我正在试图找出如何使它成为一个OpenStruct的子类(或任何类的那个)或哈希,如果我试图访问一个尚未设置的属性,将引发一个自定义异常。我无法让define_method
和method_missing
这样做,所以我无法在Ruby中完成它。
以下是一个例子:
class Request < OpenStruct...
request = Request.new
begin
request.non_existent_attr
rescue CustomError...
我可以想象它必须是这样的:
class Hash
# if trying to access key:
# 1) key exists, return key
# 2) key doesn't exist, raise exception
end
编辑:存在的属性不应引发异常。我正在寻找的功能是,我可以自由访问属性,如果它不存在,我的自定义异常将被引发。
答案 0 :(得分:7)
OpenStruct在您设置新成员时定义对象上的单例访问器方法,因此您可以使用respond_to?
来查看该成员是否有效。实际上你可能只是捕获任何未使用method_missing定义的方法并抛出错误,除非它是一个setter方法名称,在这种情况下你将它传递给super。
class WhinyOpenStruct < OpenStruct
def method_missing(meth, *args)
raise NoMemberError, "no #{meth} member set yet" unless meth.to_s.end_with?('=')
super
end
end
答案 1 :(得分:7)
如果您需要严格的哈希,只需:
class StrictHash < Hash
alias [] fetch
end
按预期工作:
hash = StrictHash[foo: "bar"]
hash[:foo]
# => "bar"
hash[:qux]
# stricthash.rb:7:in `fetch': key not found: :qux (KeyError)
# from stricthash.rb:7:in `<main>'
答案 2 :(得分:2)
我使用类似
的东西hash = { a: 2, b: 3 }
Struct.new(*hash.keys).new(*hash.values).freeze
获取一个不可变对象,如果调用了意外方法,它将引发NoMethodError
答案 3 :(得分:1)
在ruby中,无论何时编写object.horray
,消息horray
都会发送到对象object
,这将返回一个值。因为每个horray
都是一条消息。如果对象没有响应此消息,则无法区分对象没有具有此名称的属性,或者它没有具有此名称的方法。
因此,除非你假设没有方法可以输入拼写错误,否则不可能做你想做的事。
答案 4 :(得分:0)
这很残酷,但你可以覆盖new_ostruct_member方法来生成错误:
require 'ostruct'
class CustomError < StandardError; end
os = OpenStruct.new({:a=>1, :b=>1})
def os.new_ostruct_member(name) #just wrecking a single instance
raise CustomError, "non-existing key #{name} called"
end
p os.a=3
p os.c=4 #=>non-existing key c called (CustomError)
答案 5 :(得分:0)
我选择了这个完全符合我需要的解决方案:
class Request < Hash
class RequestError < StandardError; end
class MissingAttributeError < RequestError; end
def initialize(hash)
hash.each do |key, value|
self[key] = value
end
end
def [](key)
unless self.include?(key)
raise MissingAttributeError.new("Attribute '#{key}' not found in request")
end
super
end
end