web-dev-qa-db-ja.com

動的インスタンス変数にattr_accessorを設定するにはどうすればよいですか?

私はクラス内にインスタンス変数を動的に作成しました:

class Mine
  attr_accessor :some_var

  def intialize
    @some_var = true
  end

  def my_number num
    self.instance_variable_set "@my_#{num}", num
  end
end

@my_#{num}をattr値として作成するにはどうすればよいですか?

例えばこれを実行できるようにしたい:

dude = Mine.new
dude.my_number 1
dude.my_1
=> 1
31
eywu

この回答はクラス空間を汚染しません。たとえば、_mine.my_number 4_を実行すると、Mineの他のインスタンスは_my_4_メソッドを取得できません。クラスの代わりに。

_class Mine
  def my_number num
    singleton_class.class_eval { attr_accessor "my_#{num}" }
    send("my_#{num}=", num)
  end
end

a = Mine.new
b = Mine.new
a.my_number 10 #=> 10
a.my_10 #=> 10
b.my_10 #=> NoMethodError
_
27
Orlando

これは__send__。ここに:

class Mine
  attr_accessor :some_var

  def intialize
    @some_var = true
  end

  def my_number num
    self.class.__send__(:attr_accessor, "my_#{num}")
    self.__send__("my_#{num}=", num)
  end
end

dude = Mine.new
dude.my_number 1
puts dude.my_1

=> 1
24
Dorkus Prime

簡単です。 my_numberメソッド内で属性リーダーを動的に定義できます。

  def my_number num
     self.instance_variable_set "@my_#{num}", num
     self.class.class_eval do
        define_method("my_#{num}") { num }
     end
  end

それがあなたのために働くかどうか見てください

10
Gerry

ここで2つのメソッドに1つの問題があります。インスタンス変数が1つのインスタンスで設定されている場合、自分ではなくself.classでメソッドを定義しているため、そのアクセサーはすべてのインスタンスで使用できます。

dude = Mine.new
dude.my_number 1
puts dude.my_1
dudette = Mine.new
dudette.my_1 = 2    # works, but probably shouldn't
dudette.my_number 2
dude.my_2 = 3       # works, but probably shouldn't

おそらくあなたがしたいことは、インスタンス変数を持つインスタンスのみを変更することです:

class Mine
  # ...
  def my_number num
    class << self
      attr_accessor "my_#{num}"
    end
    self.send("my_#{num}=", num)
  end
end

このように、インスタンス変数は、それが作成されたオブジェクトのアクセサーのみを取得します。また、instance_variable_setを気にしませんでした。なぜなら、もしあなたがアクセサを設定しているなら、それを再利用する方が良いと思うからです。しかし、それはスタイルの呼び出しです。ここで重要なのは、class << selfではなくself.classを呼び出すことです。

5
carpeliam

OpenStructを使用することができます。

require "ostruct"

class Mine < OpenStruct
end

dude = Mine.new
dude.my_number = 1
dude.my_number # => 1

なぜあなたが欲しがるかわからないdude.my_1 1を返す-すでに持っているものを返してくれませんか?

3
Andrew Grimm

パイルに追加するさらに別のソリューション define_singleton_method

class Mine
  def my_number num
    define_singleton_method("num_#{num}") { num }
  end
end

これらすべてのソリューションの1つの副作用は、異なる番号で複数回呼び出すと、オブジェクトに多数のメソッドが作成されることです。

dude = Mine.new
dude.my_number 1
dude.my_number 5
dude.my_1
=> 1
dude.my_5
=> 5

古いメソッドを削除することでこれを修正できます:

class Mine
  def my_number num
    old_num = @num
    if @num
      # need to use `old_num` local variable
      # instance var scope is different inside `class_eval`
      singleton_class.class_eval { remove_method("num_#{old_num}") }
    end

    @num = num

    define_singleton_method("num_#{num}") { @num }
  end
end
0
lobati

古いスレッドですが、役に立ちました。ありがとうございます。これがコードDorkus Primeの答えですが、ハッシュのname\valuesからインスタンス変数も取得しています

@cookies = browser.cookies.to_a

@cookies.each do |cookie|
self.class.__send__(:attr_accessor, "#{cookie[:name]}")
self.__send__("#{cookie[:name]}=",cookie[:value])
end
0
chollaball