2014-08-20 3 views
0

Допустим, у меня есть такой код:Как инициализировать переменную класса рубин в модуле

class TestClass 
    module ClassMethods 
    attr_accessor :number 

    def initialize 
     @number = 47 
    end 
    end 

    include ClassMethods 
    extend ClassMethods 
end 

TestClass.new.number возвращает 47, который, как ожидается, но TestClass.number возвращается nil.

Как я могу инициализировать переменную number для обоих классов TestClass и TestClass экземпляров? До сих пор я сделал это так:

class TestClass 
    module ClassMethods 
    attr_accessor :number 

    def initialize 
     @number = 47 
    end 
    end 

    include ClassMethods 
    extend ClassMethods 
    @number = 47 
end 

мне не нравится этот подход, поскольку number инициализируется в двух местах.

+0

Первое число для данного экземпляра 'TestClass'; вторая - переменная экземпляра класса.Они могут сосуществовать, поскольку они отличаются от «@ night» и «@ day». –

+0

@CarySwoveland: Я это понимаю. Мой вопрос в том, почему «расширение ClassMethods» не инициализирует переменную экземпляра класса. И как я могу инициализировать переменную экземпляра экземпляра и класса без дублирования кода? – xx77aBs

+0

xx, я не забыл. Мне просто потребовалось некоторое время, чтобы найти время, чтобы дать ответ. Дайте знать, если у вас появятся вопросы. –

ответ

1

не Предположим, что у вас это:

class TestClass 
    module ClassMethods 
    attr_accessor :number  
    def initialize 
     @number = 47 
    end 
    end 
    include ClassMethods 
    extend ClassMethods 
end 

Давайте получить некоторую информацию об этом классе:

TestClass.instance_variables #=> [] 

никаких сюрпризов.

tc = TestClass.new  #=> #<TestClass:0x00000101098a10 @number=47> 
p tc.instance_variables #=> [:@number] 
tc.number    #=> 47 
tc.number = 11 

Все как ожидается. Переменная экземпляра @number была создана initialize, и мы можем проверить ее и изменить ее с помощью аксессора.

extendTestClass#initialize метод класса, но он не был вызван. Давайте вызвать его для инициализации экземпляра класса переменной @number:

TestClass.initialize 
    #=> NoMethodError: private method `initialize' called for TestClass:Class 

Ах, да, initialize является частным методом.

TestClass.methods.include?(:initialize)   #=> false 
TestClass.private_methods.include?(:initialize) #=> true 

Мы не можем использовать методы частного класса обычным способом. send, однако, работает с частными и государственными методами:

TestClass.send :initialize      #=> 47 
TestClass.instance_variables     #=> [:@number] 
TestClass.instance_variable_get(:@number)  #=> 47 

Так что теперь переменная экземпляра класса был создан устанавливается равным 47. Изменилось ли значение переменной экземпляра @number?

tc.number          #=> 11 

Это не изменено. Теперь давайте изменим значение переменного экземпляра класса, а затем увидеть, если значение переменного экземпляра зависит:

TestClass.instance_variable_set(:@number, -5) #=> -5 
tc.number          #=> 11 

Если вы хотите добавить аксессор для экземпляра класса переменной @number, добавьте эту строку в класс или модуль:

Module.instance_eval("attr_accessor :number") 

(Для объяснения см мой ответ here.)

Тогда тест:

TestClass.number  #=> -5 
TestClass.number = 107 
TestClass.number  #=> 107 
+0

Спасибо, я был на правильном пути, за исключением того, что я пытался вызвать инициализацию без использования отправки. Кто бы ни опустил - объясните? – xx77aBs

Смежные вопросы