将 Ruby 对象的实例变量作为映射传递给另一个 class 的初始化器
Pass Ruby object's instance variables to another class's initializer as a map
我正在使用 xml-mapping
gem 读取一些 XML,我想将映射对象提供给一些现有域 classes 的初始化器.所以给定 XML 比如:
<foo bar="baz"><qux>quux</qux></foo>
我得到一个像这样的对象:
#<Foo @bar="baz", @qux="quux">
然后我想将它提供给域 class,例如:
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" }
有没有一种方法可以将实例变量名称转换为符号 而无需 @
符号?
或者,有没有更简单的说法"initialize yourself from all the attributes in this object"?
Andrey 的评论很好,但我不喜欢直接依赖实例变量。我建议将自定义 to_h
方法添加到您的 Foo
class。您甚至可以通过以下方式将其与 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
class 中,或者:
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
class.
之前
我正在使用 xml-mapping
gem 读取一些 XML,我想将映射对象提供给一些现有域 classes 的初始化器.所以给定 XML 比如:
<foo bar="baz"><qux>quux</qux></foo>
我得到一个像这样的对象:
#<Foo @bar="baz", @qux="quux">
然后我想将它提供给域 class,例如:
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" }
有没有一种方法可以将实例变量名称转换为符号 而无需 @
符号?
或者,有没有更简单的说法"initialize yourself from all the attributes in this object"?
Andrey 的评论很好,但我不喜欢直接依赖实例变量。我建议将自定义 to_h
方法添加到您的 Foo
class。您甚至可以通过以下方式将其与 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
class 中,或者:
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
class.