我喜欢"任意属性的定义",我认为ruby中的OpenStruct有时比使用散列更清晰,但我很好奇是否有其他特定的优点或用例使OpenStruct成为比单纯使用更好的选择哈希.
我试图找出如何使它成为一个OpenStruct的子类(或任何类的东西)或哈希,如果我尝试访问尚未设置的属性将引发自定义异常.我无法得到define_method和method_missing做到这一点,所以我无能应该如何在Ruby中进行.
这是一个例子:
class Request < OpenStruct...
request = Request.new
begin
request.non_existent_attr
rescue CustomError...
Run Code Online (Sandbox Code Playgroud)
我可以想象它必须是这样的:
class Hash
# if trying to access key:
# 1) key exists, return key
# 2) key doesn't exist, raise exception
end
Run Code Online (Sandbox Code Playgroud)
编辑:存在的属性不应引发异常.我正在寻找的功能是,我可以自由访问属性,如果它不存在我的自定义异常将被引发.
我有一个包含模块的Ruby类.我希望include类的行为类似于OpenStruct.如何在不明确继承OpenStruct的情况下实现这一目标?
class Book
include MyModule
end
module MyModule
def self.included(klass)
# Make including class behave like OpenStruct
end
end
Run Code Online (Sandbox Code Playgroud)
代替
class Book < OpenStruct
include MyModule
end
Run Code Online (Sandbox Code Playgroud) 我对红宝石完全陌生。我必须解析一个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
Run Code Online (Sandbox Code Playgroud)
我想从此YAML创建一个对象,为此我在Ruby中编写了以下代码
require 'yaml'
object = YAML.load(File.read('./file.yaml'))
Run Code Online (Sandbox Code Playgroud)
我可以使用[]成功访问该对象的属性,例如
puts object[projects].first[developers].last[certifications].first[name]
# prints ABC
Run Code Online (Sandbox Code Playgroud)
但是,我想通过方法调用访问属性
例如
puts object.projects.first.developers.last.certifications.first.name
# should print ABC
Run Code Online (Sandbox Code Playgroud)
有什么方法可以构造可以通过上述(点)方式访问其属性的对象?我已经读过有关OpenStruct和hashugar的文章。我也想避免使用第三方宝石
我必须模仿 Google API 响应并创建一个可通过.如下方式遍历的 2 级深层数据结构:
=> user.names.first_name
Run Code Online (Sandbox Code Playgroud)
鲍勃
有没有比这更聪明/更好的方法:
user = OpenStruct.new(names: OpenStruct.new(first_name: 'Bob'))
Run Code Online (Sandbox Code Playgroud) 我有一个 OpenStruct 对象,需要转换为 JSON 数据。
样本哈希(来自 RSPEC 助手):
def test_order
{
"id": 505311428702,
"email": "test@gmail.com",
"closed_at": "",
"discount_codes": {
"id": 507328175,
"text": "test"
}
}
end
Run Code Online (Sandbox Code Playgroud)
我正在使用以下函数进行递归:
def to_recursive_ostruct(hash)
OpenStruct.new(hash.each_with_object({}) do |(key, val), memo|
memo[key] = val.is_a?(Hash) ? to_recursive_ostruct(val) : val
end)
end
Run Code Online (Sandbox Code Playgroud)
对于前 to_recursive_ostruct(test_order),将返回:
<OpenStruct id=505311428702, email="test@gmail.com", closed_at="", ...>
Run Code Online (Sandbox Code Playgroud)
转换后,使用OpenStructObject.marshal_dump:
{
:id=>505311428702, :email=>"test@gmail.com", :closed_at=>"",
discount_codes=>#<OpenStruct id=507328175, text= "test">}
}
Run Code Online (Sandbox Code Playgroud)
OpenStructObject.marshal_dump在第一级给了我正确的数据,
我还希望转换嵌套数据。
我真正需要的是:
{:id=>505311428702, :email=>"test@gmail.com", :closed_at=>"", :discount_codes=>{:id=>507328175, :text=> "test"} }
Run Code Online (Sandbox Code Playgroud)
请帮忙,提前致谢。
在创建一个新的Ruby OpenStruct对象之后,我能够存储属性但不能检索它们(我得到一个空行而是返回nil):
obj = OpenStruct.new # => #<OpenStruct>
obj.x = 10
obj.y = 20
obj # => #<OpenStruct x=10, y=20>
obj.x # => 10
obj.y #
# => nil
Run Code Online (Sandbox Code Playgroud)
如果我尝试使用不同的名称存储其他属性,一切都按预期工作.这个问题似乎只有在我存储一个名为的属性时才会发生y.我使用以下版本:
ruby 1.9.2p320 (2012-04-20 revision 35421) [i686-linux]
有没有人知道发生了什么?
如何使用OpenStruct的marshal_load实用程序?它似乎没有按预期工作.
文档提供了这个示例,但它似乎不起作用.
require 'ostruct'
event = OpenStruct.new
hash = { 'time' => Time.now, 'title' => 'Birthday Party' }
event.marshal_load(hash)
event.title # => nil
Run Code Online (Sandbox Code Playgroud)
如果不是这样,我如何将哈希加载到OpenStruct(不使用构造函数)?
对于上下文:我正在从YAML文件加载哈希并将其加载到OpenStruct子类的现有实例中.
在Ruby 2.1.5和2.2.4中,创建一个新的收集器会返回正确的结果.
require 'ostruct'
module ResourceResponses
class Collector < OpenStruct
def initialize
super
@table = Hash.new {|h,k| h[k] = Response.new }
end
end
class Response
attr_reader :publish_formats, :publish_block, :blocks, :block_order
def initialize
@publish_formats = []
@blocks = {}
@block_order = []
end
end
end
> Collector.new
=> #<ResourceResponses::Collector>
Collector.new.responses
=> #<ResourceResponses::Response:0x007fb3f409ae98 @block_order=[], @blocks= {}, @publish_formats=[]>
Run Code Online (Sandbox Code Playgroud)
当我升级到Ruby 2.3.1时,它开始返回nil而不是.
> Collector.new
=> #<ResourceResponses::Collector>
> Collector.new.responses
=> nil
Run Code Online (Sandbox Code Playgroud)
我已经做了很多关于OpenStruct如何在2.3中快10倍的阅读但是我没有看到会破坏收集器和响应之间关系的改变.非常感谢任何帮助.Rails的版本是4.2.7.1.
我试图解析这样一个简单的 JSON:
JSON.parse({"pong": "ok"})
Run Code Online (Sandbox Code Playgroud)
它失败了
2.4.0 :014 > JSON.parse({"pong": "ok"})
TypeError: no implicit conversion of Hash into String
from (irb):14
Run Code Online (Sandbox Code Playgroud)
这里有什么问题?为什么要转换为 String ?
另一个尝试,这次使用OpenStruct:
2.4.0 :001 > pong = OpenStruct.new(pong: 'OK')
=> #<OpenStruct pong="OK">
2.4.0 :002 > JSON.parse(pong)
TypeError: no implicit conversion of OpenStruct into String
from (irb):2
Run Code Online (Sandbox Code Playgroud)
相同 ?谢谢
我有一个哈希数组,我宁愿把它变成一个对象数组,其中的属性以编程方式添加到这些对象中.
我现在正试试这个
obj = OpenStruct.new
resulthash["users"].collect { |u|
u.each do |k,v|
obj.send("#{k}=#{v}");
end
}
Run Code Online (Sandbox Code Playgroud)
回顾一下我正在尝试做的事
obj.foo = "bar"
obj.hello = "world"
Run Code Online (Sandbox Code Playgroud)
但是以编程方式,例如对于数组/哈希看起来喜欢这个
{"users"=>[{"foo"=>"bar","hello"=>"world"}]}
Run Code Online (Sandbox Code Playgroud) openstruct ×11
ruby ×10
json ×2
hashmap ×1
mixins ×1
module ×1
null ×1
parsing ×1
ruby-1.9.3 ×1
ruby-2.3.1 ×1
yaml ×1