从任意哈希初始化Ruby类,但只有具有匹配访问器的键

JP.*_*JP. 5 ruby class

有没有一种简单的方法来列出已在Ruby类中设置的访问器/阅读器?

class Test
  attr_reader :one, :two

  def initialize
    # Do something
  end

  def three
  end
end

Test.new
=> [one,two]
Run Code Online (Sandbox Code Playgroud)

我真正想要做的是允许初始化接受具有任意数量属性的哈希,但只提交已经定义了读者的哈希.就像是:

def initialize(opts)
  opts.delete_if{|opt,val| not the_list_of_readers.include?(opt)}.each do |opt,val|
    eval("@#{opt} = \"#{val}\"")
  end
end
Run Code Online (Sandbox Code Playgroud)

还有其他建议吗?

Jul*_*lik 9

这是我使用的(我称之为idiom hash-init).

 def initialize(object_attribute_hash = {})
  object_attribute_hash.map { |(k, v)| send("#{k}=", v) }
 end
Run Code Online (Sandbox Code Playgroud)

如果你使用的是Ruby 1.9,你可以做得更干净(发送允许私有方法):

 def initialize(object_attribute_hash = {})
  object_attribute_hash.map { |(k, v)| public_send("#{k}=", v) }
 end
Run Code Online (Sandbox Code Playgroud)

如果您尝试分配给foo并且方法"foo ="不存在,这将引发NoMethodError.如果你想干净(指定存在作者的attrs)你应该做一个检查

 def initialize(object_attribute_hash = {})
  object_attribute_hash.map do |(k, v)| 
    writer_m = "#{k}="
    send(writer_m, v) if respond_to?(writer_m) }
  end
 end
Run Code Online (Sandbox Code Playgroud)

然而,这可能会导致您向对象提供错误的键(例如从表单中)而不是大声失败而只是吞下它们的情况 - 前方的痛苦调试.所以在我的书中,NoMethodError是一个更好的选择(它表示合同违规).

如果你只想要一份所有作家的名单(没有办法为读者做到这一点),那你就做了

 some_object.methods.grep(/\w=$/)
Run Code Online (Sandbox Code Playgroud)

这是"获取一个方法名称数组,并为条目字符后面的单个等号结束的条目grep".

如果你这样做

  eval("@#{opt} = \"#{val}\"")
Run Code Online (Sandbox Code Playgroud)

val来自网络表单 - 恭喜你,你刚刚为你的应用程序配备了一个开放的漏洞.