2013-07-03 16 views
5

Supponiamo che io ho due moduli:Rubino modulo dinamico mix-in

module Test1 

    attr_accessor :a, :b 

    @a = 0.0 
    @b = 0.0 

end 

module Test2 

    attr_accessor :c, :d 

    @c = 0.0 
    @d = 0.0 

end 

Ora, voglio mescolare condizionale questi moduli in una classe. Questo è quello che ho provato:

require './Test1.rb' 
require './Test2.rb' 

class MyClass 

    def initialize(mode) 
    if mode == 0 
     (class << self; include Test1; end) 
    elsif mode == 1 
     (class << self; include Test2; end) 
    else 
     class << self 
     include Test1 
     include Test2 
     end 
    end 
    end 

end 

questo è il comportamento che sto vedendo:

obj = MyClass.new(0) 
obj.a #=> nil 

anche @a è nil a metodi di istanza all'interno della classe. Sento che non sto capendo qualcosa di importante qui. Mi piacerebbe capire perché quello che sto facendo non funziona e anche quale sia il modo corretto per raggiungere la mia funzionalità desiderata.

risposta

9

Si ha questo comportamento perché queste variabili di istanza impostate nei moduli appartengono ai moduli stessi invece di appartenere alle istanze MyClass. Considerate questo codice:

Test1.instance_variable_get(:@a) 
# => 0.0 

Per risolvere questo problema, è possibile utilizzare extend invece di include:

module Test1 

    attr_accessor :a, :b 

    def self.extended(object) 
    object.a, object.b = 0.0, 0.0 
    end 

end 

module Test2 

    attr_accessor :c, :d 

    def self.extended(object) 
    object.c, object.d = 0.0, 0.0 
    end 

end 

E nella tua classe:

require './Test1.rb' 
require './Test2.rb' 

class MyClass 

    def initialize(mode) 
    if mode == 0 
     extend Test1 
    elsif mode == 1 
     extend Test2 
    else 
     extend Test1 
     extend Test2 
    end 
    end 

end 
+0

Perfetto, questo è esattamente quello che stavo cercando. Grazie! –

2

ho pensato a un modo di lavorare intorno a questo problema, quindi ho pensato di condividerlo. Mi piacerebbe ancora vedere se qualcuno sa di un modo migliore per ottenere ciò che stavo cercando.

Module Test1 
    attr_accessor :a, :b 

    def init1 
    @a = 0.0 
    @b = 0.0 
    end 
end 

class MyClass 
    def initialize 
    if mode == 0 
     (class << self; include Test1; end) 
     init1 
    elsif mode == 1 
     ... 
    end 
end