動的に追加アクセサ譲渡しない場合、呼び出しをブロックをinstance_eval Ruby

StackOverflow https://stackoverflow.com/questions/4403973

質問

いクラスを追加する属性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を設定します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top