我使用xml-mapping
gem来读取一些XML,我想将映射对象提供给一些现有域类的初始化器。所以给出XML如:
<foo bar="baz"><qux>quux</qux></foo>
我得到一个像这样的对象:
#<Foo @bar="baz", @qux="quux">
然后我想将它提供给域类,如:
class MyFoo
def initialize(bar:, qux:)
# ... etc.
end
end
(请注意,在MyFoo
中,属性是只读的,并且初始化程序中会进行一些验证和转换,因此它不仅仅是复制实例变量的问题从一个到另一个。)
我尝试将实例变量转换为地图,因此:
foo.instance_variables.map { |name| [name, foo.instance_variable_get(name)] }.to_h
产生:
{ :@bar->"baz", :@qux->"quux" }
几乎我需要MyFoo
初始化程序,但不完全 - 我需要的是
{ :bar->"baz", :qux->"quux" }
有没有办法将实例变量名称转换为符号而不用 @
- 符号?
或者,是否有一种更简单的方式来说明&#34;从这个对象的所有属性初始化自己&#34;?
答案 0 :(得分:1)
Andrey的评论很好,但我不喜欢直接依赖实例变量。我建议您在to_h
课程中添加自定义Foo
方法。您甚至可以使用以下内容与xml-mapping
绑定:
class Foo
# ...
def self.__fields__
@__fields__ ||= all_xml_mapping_nodes.map { |r| r.instance_variable_get(:@attrname) }
end
def to_h
self.class.__fields__.each_with_object({}) do |field, acc|
acc[field] = send(field)
end
end
end
然后你可以拨打MyFoo.new(foo.to_h)
。
修改强>
作为XML::Mapping
的扩展名:
module XmlMappingExtensions
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def __fields__
@__fields__ ||= all_xml_mapping_nodes.map { |r| r.instance_variable_get(:@attrname) }
end
end
def to_h
self.class.__fields__.each_with_object({}) do |field, acc|
acc[field] = send(field)
end
end
end
然后include XmlMappingExtensions
课程中的Foo
或:
module XML::Mapping
# Note: this may break XML::Mapping if it is using this method
# and there is probably a more graceful way to do this
# but I just tried it and it seems to work fine...
def self.included(base)
base.send(:include, XmlMappingExtensions)
end
end
在您加载XML::Mapping
课程之后加载Foo
。