2013-07-03 14 views
5

Załóżmy, że mam dwa moduły:Ruby moduł dynamiczny 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 

Teraz chcę warunkowo mieszać tych modułów do klasy. To co próbowałem:

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 

To zachowanie widzę:

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

także @a jest nil w metodach instancji w obrębie klasy. Czuję, że nie rozumiem tutaj czegoś ważnego. Chciałbym zrozumieć, dlaczego to, co robię, nie działa, a także, jaki jest właściwy sposób osiągnięcia pożądanej funkcjonalności.

Odpowiedz

9

Takie zachowanie występuje, ponieważ te zmienne instancji ustawione w modułach należą do samych modułów, a nie do instancji MyClass. Rozważmy następujący kod:

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

Aby rozwiązać ten problem, można użyć extend zamiast 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 

A w swojej klasie:

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

Doskonały, dokładnie tego właśnie szukałem. Dzięki! –

2

myślałem o drodze do pracy wokół tego problemu, więc pomyślałem, że go podzielę. Nadal chciałbym sprawdzić, czy ktoś wie o lepszym sposobie osiągnięcia tego, co próbowałem.

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 
Powiązane problemy