Ruby – 动态地向类添加属性(在运行时)

我正在寻找一种方法在运行时向我已经定义的类添加属性,或者更好:

class Client attr_accessor :login, :password def initialize args = {} self.login = args[:login] self.password = args[:password] end end 

但是,我有这个哈希

 {:swift_bic=>"XXXX", :account_name=>"XXXX", :id=>"123", :iban=>"XXXX"} 

我希望这个哈希成为我的客户端实例的一部分

 client = Client.new :login => 'user', :password => 'xxxxx' 

然后带着神奇的魔力

 client @@%$%PLIM!!! {:swift_bic=>"XXXX", :account_name=>"XXXX", :id=>"123", :iban=>"XXXX"} 

我可以访问

 client.swift_bic => 'XXXX' client.account_name => 'XXXX' client.id => 123 

我还想保持一个适当的对象结构,如:

 Client.new(:login => 'user', :password => 'xxxxx').inspect # 

魔术之后

 client.inspect # '123', @iban => 'XXXX'> 

这会给我一个非常好的格式良好的json

有可能吗?

我从网络服务获取这个哈希值,所以我不知道那里是否有新的属性,然后每次他们执行服务升级时我都要更新我的应用程序。 所以,我有点想避免这种情况:/

谢谢你。

🙂

method_missing方法可以工作,但是如果你在添加它们之后要经常使用访问器,你可以将它们添加为真正的方法,如下所示:

 class Client def add_attrs(attrs) attrs.each do |var, value| class_eval { attr_accessor var } instance_variable_set "@#{var}", value end end end 

这将使它们像普通实例变量一样工作,但仅限于一个client

我认为最好的解决方案是mckeed

但这是另一个想法。 如果你想要,你可以inheritanceOpenStruct的子类:

 require 'ostruct' class Client < OpenStruct def initialize args = {} super end def add_methods( args = Hash.new ) args.each do |name,initial_value| new_ostruct_member name send "#{name}=" , initial_value end end end client = Client.new :login => 'user', :password => 'xxxxx' client.add_methods :swift_bic=>"XXXX", :account_name=>"XXXX", :iban=>"XXXX" , :to_s => 5 client # => # client.swift_bic # => "XXXX" client.account_name # => "XXXX" 

但是,此解决方案存在两个问题。 OpenStruct使用method_missing,所以如果你定义一个类似id的方法,在1.8上它会找到object_id而不是找到你的方法。

第二个问题是它使用了一些关于如何实现OpenStruct的私人知识。 所以它可以在将来改变,打破这个代码(为了记录,我检查了1.8.7 – 1.9.2,这是兼容的)

看看Object.method_missing 。 只要使用未定义的方法调用对象,就会调用此方法。 您可以定义此函数并使用它来根据其中一个哈希值的名称检查未定义的方法。 如果匹配,则返回哈希值。

您还可以定义自己的inspect函数并生成包含您希望它包含的任何内容的输出字符串。

我将建议不要使用method_missing – 它创建了许多“魔术”function,如果不通过method_missing正文,就无法轻松记录或理解。 相反,按照建议查看OpenStruct – 您甚至可以创建自己inheritance的类,例如:

 class Client < OpenStruct ... end 

并且您将能够使用您收到的任何哈希初始化客户端。