11

我试图弄清楚如何做到这一点,以便在我尝试访问尚未设置的属性时,OpenStruct 的子类(或与此相关的任何类)或哈希将引发自定义异常。我无法做到这一点define_methodmethod_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

编辑:存在的属性不应引发异常。我正在寻找的功能是让我可以自由地访问属性,如果它碰巧不存在,我的自定义异常将被引发。

4

6 回答 6

10

如果您需要严格的哈希,只需:

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>'
于 2015-06-16T14:59:59.497 回答
9

当您设置新成员时,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
于 2013-06-03T21:01:13.350 回答
4

我使用类似的东西

hash = { a: 2, b: 3 }

Struct.new(*hash.keys).new(*hash.values).freeze

获取一个不可变对象,NoMethodError如果调用了意外的方法,该对象将引发

于 2017-03-23T12:52:18.610 回答
1

在 ruby​​ 中,每当您编写 object.horray消息horray发送到 objectobject时,它都会返回一个值。因为每一个horray都是一个消息。如果对象不响应此消息,则您无法区分对象没有具有此名称的属性还是没有具有此名称的方法。

因此,除非您假设没有任何方法可以有错字,否则不可能做您想做的事。

于 2013-06-03T20:55:01.130 回答
1

我选择了这个解决方案,它完全符合我的需要:

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
于 2013-06-04T16:39:22.587 回答
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)
于 2013-06-03T21:27:19.607 回答