自动为符号生成'attr_reader'

时间:2017-11-10 13:58:37

标签: ruby

我有以下代码,我手动设置attr_readerattr_writer

class Pairs
  attr_reader :pair, :asks, :bids, :isFrozen, :seq, :main_currency, :sub_currency
  attr_writer :pair, :asks, :bids, :isFrozen, :seq

  def initialize (key, args)
    @pair = key
    @main_currency, @sub_currency = key.split('_')
    args.each {|k,v| 
      if numeric?(v) then v=v.to_f end
      self.instance_variable_set("@#{k}".to_sym, v)
    }
  end

  private

  def numeric?(string)
    Float(string) != nil rescue false
  end
end

有没有办法根据参数的键自动设置它们,比如我自动用@k填充v?我可以为每个attr_reader设置@k吗?

我想这样的事情:

self.attr_reader("@#{k}")
对于班级的所有对象,

甚至更好,例如:

Pairs << attr_reader("@#{k}")

3 个答案:

答案 0 :(得分:1)

我怀疑我理解了这个问题,但是从我得到的内容来看,你希望在运行时使用属性读取器动态扩展你的类。

这种方法可以:

def extend_self_with_reader name
  self.class.send :attr_reader, name
end

测试:

class C
  def extend_self_with_reader name
    self.class.send :attr_reader, name
  end

  def initialize *keys
    puts keys.inspect
    keys.each(&method(:extend_self_with_reader))
  end
end
cc = C.new(*%i|a b c|)
cc.a #⇒ nil

答案 1 :(得分:1)

我将假设您可能正在使用针对不同keys的许多Hash来创建此项,如果是这种情况,则不要使用不需要的读者将各个实例混为一起,以便存在不存在的键#&# 39;为此使用singleton_class

所以你的最终Pairs课程看起来像

class Pairs
  attr_reader :main_currency, :sub_currency
  attr_accessor :pair, :asks, :bids, :isFrozen, :seq

  def initialize (key, args)
    @pair = key
    @main_currency, @sub_currency = key.split('_')
    args.each do |k,v| 
      singleton_class.send(:attr_reader,k)
      instance_variable_set("@#{k}", convert_numeric(v))
    end
    # Alternatively:
    # args.each do |k,v| 
    #   val = convert_numeric(v)
    #   define_singleton_method(k) {val}
    # end
  end

  private

    def convert_numeric(val)
      Float(Rational(val)) rescue val
    end
end

<强> TL; DR

例如:(使用@ mudasobwa&#39; s方法)

class C
  def extend_self_with_reader name
    self.class.send :attr_reader, name
  end

  def initialize *keys
    keys.each(&method(:extend_self_with_reader))
  end
end

这会导致后续读者混淆实例并在实例之间出血:

a = C.new(:a,:b)
a.a #=> nil
b = C.new
b.a #=> nil 
c = C.new(:r) 
c.a #=> nil
c.r #=> nil
a.methods.sort - Object.methods
#=> [:a, :b, :extend_self_with_reader, :r]
a.r #=> nil (hmmmmm) 

而是使用实例的singleton_class来本地化这些读者,例如:

class C 
  def initialize *keys 
    singleton_class.send(:attr_reader, *keys)
  end
end 

然后

a = C.new(:a,:b)
a.a #=> nil
b = C.new
b.a #=> NoMethodError: undefined method `a'
c = C.new(:r) 
c.a #=> NoMethodError: undefined method `a'
c.r #=> nil
a.r #=> NoMethodError: undefined method `r'
a.methods.sort - Object.methods
#=> [:a,:b] 
b.methods.sort - Object.methods
#=> []

使用singleton_class将这些读者本地化为对象的实例,而不是将它们放入Class定义中。如果attr_reader不是必需条件,那么这也足够了:

keys.each {|k| define_singleton_method(k) {}}

答案 2 :(得分:0)

或许关注define_method

我不是100%确定我理解这个问题,但请检查一下:

hash = { a: 1, b: 2, c: 3 }

hash.keys.each do |key|
  define_method(key) do
    hash[key]
  end
end

现在有a,b和c的方法:

a => 1
b => 2
c => 3

这实际上为哈希中的所有键创建了attr_reader。您可以为attr_writer执行类似操作。