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
。なぜスーパー@count
になっているのかわかりませんか?nil: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
実行しますか?