動的に追加アクセサ譲渡しない場合、呼び出しをブロックをinstance_eval Ruby
-
25-09-2019 - |
質問
いクラスを追加する属性accessors動的に行います。このクラスの一環で、DSLをブロックの取得に渡される構成の方法を使って起動instance_eval.このDSLを削除参照"自己"の場合参照法のクラスです。
しかし、私見できたらいいのに参考に属性を取得する値が割り当てることができませんしない限り、explicityを参考自己、以下のコード例を示す.
class Bar
def add_dynamic_attribute_to_class(name)
Bar.add_dynamic_attribute(name)
end
def invoke_block(&block)
instance_eval &block
end
def self.add_dynamic_attribute(name)
attr_accessor name
end
end
b = Bar.new
b.add_dynamic_attribute_to_class 'dyn_attr'
b.dyn_attr = 'Hello World!'
# dyn_attr behaves like a local variable in this case
b.invoke_block do
dyn_attr = 'Goodbye!'
end
# unchanged!
puts "#{b.dyn_attr} but should be 'Goodbye!'"
# works if explicitly reference self
b.invoke_block do
self.dyn_attr = 'Goodbye!'
end
# changed...
puts "#{b.dyn_attr} = 'Goodbye!"
# using send works
b.invoke_block do
send 'dyn_attr=', 'Hello Again'
end
# changed...
puts "#{b.dyn_attr} = 'Hello Again!"
# explain this... local variable or instance method?
b.invoke_block do
puts "Retrieving... '#{dyn_attr}'"
# doesn't fail... but no effect
dyn_attr = 'Cheers'
end
# unchanged
puts "#{b.dyn_attr} should be 'Cheers'"
誰でもできるのでその理由を説明ではないで行動するか?
解決
Rubyはインスタンス変数とローカル変数を扱うような方法で問題をarrises。何が起こっていることは、あなたのinstance_evalをブロック内のローカル変数を設定するのではなく、ルビーアクセサを使用していることである。
このかもしれないヘルプは、それを説明する:
class Foo
attr_accessor :bar
def input_local
bar = "local"
[bar, self.bar, @bar, bar()]
end
def input_instance
self.bar = "instance"
[bar, self.bar, @bar, bar()]
end
def input_both
bar = "local"
self.bar = "instance"
[bar, self.bar, @bar, bar()]
end
end
foo = Foo.new
foo.input_local #["local", nil, nil, nil]
foo.input_instance #["instance", "instance", "instance", "instance"]
foo.input_both #["local", "instance", "instance", "instance"]
の方法bocks仕事は、私の中input_instanceへの呼び出しの場合のように、彼らは(インスタンス変数にクラスのデフォルト設定、ローカルおよびインスタンス変数を区別し、それのリーダーが呼び出されたときに、ローカル変数が定義されていない場合ということです一例)。
あなたが望む動作を取得する方法は3つあります。
使用インスタンス変数ます:
class Foo attr_accessor :bar def evaluate(&block) instance_eval &block end end foo = Foo.new foo.evaluate do @bar = "instance" end foo.bar #"instance"
セルフ変数を使用します:
class Foo attr_accessor :bar def evaluate(&block) block.call(self) end end foo = Foo.new foo.evaluate do |c| c.bar = "instance" end foo.bar #"instance"
使用セッター機能:
class Foo attr_reader :bar def set_bar value @bar = value end def evaluate(&block) instance_eval &block end end foo = Foo.new foo.evaluate do set_bar "instance" end foo.bar #"instance"
これらの例のすべては、 "インスタンス" にfoo.barを設定します。
所属していません StackOverflow