从 YAML 创建嵌套对象以通过 Ruby 中的方法调用访问属性
Create nested object from YAML to access attributes via method calls in Ruby
我对 ruby 完全陌生。
我必须解析一个 YAML 文件来构造一个对象
YAML 文件
projects:
- name: Project1
developers:
- name: Dev1
certifications:
- name: cert1
- name: Dev2
certifications:
- name: cert2
- name: Project2
developers:
- name: Dev1
certifications:
- name: cert3
- name: Dev2
certifications:
- name: cert4
我想从这个 YAML 创建一个对象,我在 Ruby
中为此编写了以下代码
require 'yaml'
object = YAML.load(File.read('./file.yaml'))
我可以通过[]成功访问这个对象的属性
例如
puts object[projects].first[developers].last[certifications].first[name]
# prints ABC
但是,我想通过方法调用访问属性
例如
puts object.projects.first.developers.last.certifications.first.name
# should print ABC
有没有办法构造这样一个对象,其属性可以通过上面提到的(点)方式访问?
我读过 OpenStruct and hashugar。
我也想避免使用第三方 gems
如果您只是在试验,可以使用一种快速但肮脏的方法:
class Hash
def method_missing(name, *args)
send(:[], name.to_s, *args)
end
end
虽然我不会在生产代码中使用它,因为 method_missing
和猴子补丁通常都是在路上遇到麻烦的方法。
更好的解决方案是递归遍历数据结构并用 openstructs 替换散列。
require 'ostruct'
def to_ostruct(object)
case object
when Hash
OpenStruct.new(Hash[object.map {|k, v| [k, to_ostruct(v)] }])
when Array
object.map {|x| to_ostruct(x) }
else
object
end
end
puts to_ostruct(object).projects.first.developers.last.certifications.first.name
请注意,如果您经常使用这两种方法,这两种方法都可能存在性能问题 - 如果您的应用程序对时间敏感,请确保对它们进行基准测试!不过这可能与您无关。
Xavier 的回答很好,但它可以更短,只需要 yaml,json 并构造并解析你的 YAML,将其转换为 JSON,在 Openstruct 中解析它(一个 Struct 会也可以)像这样
object = JSON.parse(YAML.load(yaml).to_json, object_class: OpenStruct)
要从文件加载 YAML,它是
object = JSON.parse(YAML::load_file("./test.yaml").to_json, object_class: OpenStruct)
这给了
object
=>#<OpenStruct projects=[#<OpenStruct name="Project1", developers=[#<OpenStruct name="Dev1", certifications=[#<OpenStruct name="cert1">]>, #<OpenStruct name="Dev2", certifications=[#<OpenStruct name="cert2">]>]>, #<OpenStruct name="Project2", developers=[#<OpenStruct name="Dev1", certifications=[#<OpenStruct name="cert3">]>, #<OpenStruct name="Dev2", certifications=[#<OpenStruct name="cert4">]>]>]>
object.projects.first.developers.last.certifications.first.name
=>cert2
我用它来从文件加载配置,Yaml 很容易维护,而且在你的代码中它比 Hash 中的配置更容易使用。
不要为重复性任务执行此操作。
我对 ruby 完全陌生。 我必须解析一个 YAML 文件来构造一个对象
YAML 文件
projects:
- name: Project1
developers:
- name: Dev1
certifications:
- name: cert1
- name: Dev2
certifications:
- name: cert2
- name: Project2
developers:
- name: Dev1
certifications:
- name: cert3
- name: Dev2
certifications:
- name: cert4
我想从这个 YAML 创建一个对象,我在 Ruby
中为此编写了以下代码require 'yaml'
object = YAML.load(File.read('./file.yaml'))
我可以通过[]成功访问这个对象的属性 例如
puts object[projects].first[developers].last[certifications].first[name]
# prints ABC
但是,我想通过方法调用访问属性
例如
puts object.projects.first.developers.last.certifications.first.name
# should print ABC
有没有办法构造这样一个对象,其属性可以通过上面提到的(点)方式访问? 我读过 OpenStruct and hashugar。 我也想避免使用第三方 gems
如果您只是在试验,可以使用一种快速但肮脏的方法:
class Hash
def method_missing(name, *args)
send(:[], name.to_s, *args)
end
end
虽然我不会在生产代码中使用它,因为 method_missing
和猴子补丁通常都是在路上遇到麻烦的方法。
更好的解决方案是递归遍历数据结构并用 openstructs 替换散列。
require 'ostruct'
def to_ostruct(object)
case object
when Hash
OpenStruct.new(Hash[object.map {|k, v| [k, to_ostruct(v)] }])
when Array
object.map {|x| to_ostruct(x) }
else
object
end
end
puts to_ostruct(object).projects.first.developers.last.certifications.first.name
请注意,如果您经常使用这两种方法,这两种方法都可能存在性能问题 - 如果您的应用程序对时间敏感,请确保对它们进行基准测试!不过这可能与您无关。
Xavier 的回答很好,但它可以更短,只需要 yaml,json 并构造并解析你的 YAML,将其转换为 JSON,在 Openstruct 中解析它(一个 Struct 会也可以)像这样
object = JSON.parse(YAML.load(yaml).to_json, object_class: OpenStruct)
要从文件加载 YAML,它是
object = JSON.parse(YAML::load_file("./test.yaml").to_json, object_class: OpenStruct)
这给了
object
=>#<OpenStruct projects=[#<OpenStruct name="Project1", developers=[#<OpenStruct name="Dev1", certifications=[#<OpenStruct name="cert1">]>, #<OpenStruct name="Dev2", certifications=[#<OpenStruct name="cert2">]>]>, #<OpenStruct name="Project2", developers=[#<OpenStruct name="Dev1", certifications=[#<OpenStruct name="cert3">]>, #<OpenStruct name="Dev2", certifications=[#<OpenStruct name="cert4">]>]>]>
object.projects.first.developers.last.certifications.first.name
=>cert2
我用它来从文件加载配置,Yaml 很容易维护,而且在你的代码中它比 Hash 中的配置更容易使用。
不要为重复性任务执行此操作。