2013-11-03 82 views
1

我正在尝试为包含我的模块的任何类创建DSL。它正在处理股票。如何在包含模块的类中设置实例变量

这里是我的测试:

context 'when price is provided' do 
     let(:stock_with_price) { 
      class Stock 
       include StopLimit 
       stock_attributes price: 3.33 
      end 

      Stock.new 
     } 
     it 'sets the price to given value' do 
      stock_with_price.price.should eq(3.33) 
     end 
    end 

这是迄今为止我的模块:

module StopLimit 
     DEFAULT_STOCK_PRICE = 0 
     def self.included(base) 
     attr_accessor :price 
     def base.stock_attributes(options = {}) 
      define_method('price') do 
       instance_variable_get("@price") ? instance_variable_get("@price") : DEFAULT_STOCK_PRICE 
      end 
      options.each_pair do |attribute, value| 
       if self.method_defined?(attribute) 
         instance_variable_set("@#{attribute.to_s}", value) 
         # raise instance_variable_get("@price").inspect <-- This prints out 3.33! 
        end 
      end 
     end 
     end 
    end 

我的测试似乎被打破。 stock.price正在返回0。为什么实例变量打印正确的东西,但是我的测试失败了?

UPDATE:

这工作:

options.each_pair do |attribute, value| 
     if self.method_defined?(attribute) 
      @price = value 
      end 
    end 

然而,这是硬编码。我将如何动态创建和设置实例变量值,以便我可以遍历所有属性和值对,并为每个值创建@ [[attribute]] =值?

回答

0

由于在类方法中调用instance_variable_set,所以self被设置为该类,而@price被设置为Stock上的类实例变量。

然而,你price方法是实例的方法,所以它试图找到实例@price,没有找到它,并返回默认值。

编辑: 如何:

define_method('price') do 
    @price ||= self.class.instance_variable_get(:@price) || DEFAULT_STOCK_PRICE 
end 
+0

所以,实际上,我怎么设置类实例的默认实例变量? – Edmund

+0

@Edmund为什么你希望它是一个实例变量,如果它是类的属性?或者相反,如果它定义了一个实例属性,为什么要在类定义中调用'stock_attributes'? – micahbf

+0

@埃德蒙我也许我明白。我已经用一个工作解决方案更新了我的答案。 – micahbf