2012-02-27 61 views
16

我正在使用class_eval编写要在当前类的上下文中执行的代码。在下面的代码中,我想添加一个计数器来更改属性值。`class_eval`字符串中的变量作用域是什么?

class Class 
    def attr_count(attr_name) 
    attr_name = attr_name.to_s 
    attr_reader attr_name # create the attribute's getter 
    class_eval %Q{ 
     @count = 0 
     def #{attr_name}= (attr_name) 
     @attr_name = attr_name 
     @count += 1 
     end 

     def #{attr_name} 
     @attr_name 
     end 
    } 
    end 
    end 
class Foo 
    attr_count :bar 
end 

f = Foo.new 
f.bar = 1 

我的class_eval的理解是,它的计算结果在运行时类的背景下,块- 在我的情况,class Foo下。我希望上面的代码运行类似

class Foo 
    attr_count :bar 
    @count = 0 
    def bar= (attr_name) 
    @attr_name = attr_name 
    @count += 1 
    end 

    def bar 
    @attr_name 
    end 
end 

但是上面的代码导致错误的说法,错误是由@count += 1造成的。我想不通为什么@countnil:NilClass作为它的超级?

(eval):5:in `bar=': undefined method `+' for nil:NilClass (NoMethodError) 

在另一方面,@selman给了一个解决方案把实例方法中@count分配和它的作品。

class Class 
    def attr_count(attr_name) 
    #... 
    class_eval %Q{ 
     def #{attr_name}= (attr_name) 
     @attr_name = attr_name 
     if @count 
      @count += 1 
     else 
      @count = 1 
     end 
     end 
     #... 
    } 
    end 
end 

为什么要改变变量作用域? class_eval如何执行其以下字符串?

+0

你是如何喜欢CS169课程的? :) – 2012-10-17 01:36:52

回答

12

它不是约class_eval它是关于@count。如果您在类别级别定义此变量,则它将是class instance variable而不是instance variable

class Class 
    def attr_count(attr_name) 
    attr_name = attr_name.to_s 
    attr_reader attr_name # create the attribute's getter 
    class_eval %Q{ 
     def #{attr_name}= (attr_name) 
     @attr_name = attr_name 
     if @count 
      @count += 1 
     else 
      @count = 1 
     end 
     end 

     def #{attr_name} 
     @attr_name 
     end 
    } 
    end 
end 

class Foo 
    attr_count :bar 
end 

f = Foo.new 
f.bar = 1 
+0

它的工作。我仍然对'class_eval'方法中'@ count'和'@@ count'之间的区别感到困惑。我的理解是1.传递给'class_eval'的字符串将在运行时进行评估 - 当调用'class Foo'时。 2.“@ count”应该是'Foo'所有实例的一个实例变量。为什么使用类变量'@@ count'使其表现得像**实例变量**?我知道这个话题很复杂,你有一些我可以读的参考吗? – steveyang 2012-02-27 15:31:36

+0

这[博客文章](http://martinfowler.com/bliki/ClassInstanceVariable.html) – 2012-02-27 15:37:27

+0

嗨,@selmen。我发现'@@ count'实际上并不是一个实例变量。它表现为类变量。这不是我期望的 – steveyang 2012-02-27 16:35:40