2013-02-05 8 views
10

Voglio generare dinamicamente un metodo di classe in un Mixin, in base al nome della classe che include questo Mixin.: definire dinamicamente il metodo di classe basato sul nome della classe genitore all'interno del modulo/preoccupazione

Ecco il mio codice corrente:

module MyModule 
    extend ActiveSupport::Concern 

    # def some_methods 
    # ... 
    # end 

    module ClassMethods 

    # Here is where I'm stuck... 
    define_method "#{self.name.downcase}_status" do 
     # do something... 
    end 

    end 
end 

class MyClass < ActiveRecord::Base 
    include MyModule 
end 

# What I'm trying to achieve: 
MyClass.myclass_status 

Ma questo mi danno il seguente nome del metodo:

MyClass.mymodule::classmethods_status 

Ottenere il nome della classe di base all'interno delle opere metodo di definizione (auto, self.name. ..), ma non riesco a fare funziona per il nome del metodo ...

Finora, ho provato

define_method "#{self}" 
define_method "#{self.name" 
define_method "#{self.class}" 
define_method "#{self.class.name}" 
define_method "#{self.model_name}" 
define_method "#{self.parent.name}" 

Ma niente di tutto questo sembra fare il trucco:/

C'è un modo per recuperare il nome della classe di base (non so cosa per chiamare la classe che includono il mio modulo). Ho lottato con questo problema per ore e che io non riesco a capire una soluzione pulita :(

Grazie

risposta

5

Non si può fare così! - a questo punto non è ancora noto quale classe (o classi) include il modulo

Se si definisce un metodo self.included, verrà chiamato ogni volta che il modulo è incluso e la cosa che fa l'inclusione verrà passata come argomento. utilizzando AS :: Concern si può fare

included do 
    #code here is executed in the context of the including class 
end 
+1

Grazie per la spiegazione. Ho usato 'define_singleton_method' all'interno del blocco' include do # ... end': 'define_singleton_method" # {self.name} _status "do # ... end' ' – cl3m

1

Si può fare qualcosa di simile:

module MyModule 
    def self.included(base) 
    (class << base; self; end).send(:define_method, "#{base.name.downcase}_status") do 
     puts "Hey!" 
    end 

    base.extend(ClassMethods) 
end 

    module ClassMethods 
    def other_method 
     puts "Hi!" 
    end 
    end 
end 

class MyClass 
    include MyModule 
end 

MyClass.myclass_status 
MyClass.other_method 
1

Lavori per la extend:

module MyModule 
    def self.extended who 
    define_method "#{who.name.downcase}_status" do 
     p "Inside" 
    end 
    end 
end 

class MyClass 
    extend MyModule 
end 

MyClass.myclass_status 
5

ho trovato una soluzione pulita: usando define_singleton_method (disponibile in rosso rubino v1.9.3)

module MyModule 
    extend ActiveSupport::Concern 

    included do 
    define_singleton_method "#{self.name}_status" do 
     # do stuff 
    end 
    end 

    # def some_methods 
    # ... 
    # end 

    module ClassMethods 
    # Not needed anymore! 
    end 
end