2013-06-03 48 views
9

我想弄清楚如何使OpenStruct的子類(或任何類的問題)或散列會引發自定義異常if我嘗試訪問尚未設置的屬性。我無法獲得define_methodmethod_missing來做到這一點,所以我不知道它應該如何在Ruby中完成。訪問OpenStruct中不存在的屬性時引發異常

下面是一個例子:

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

我用這個解決方案,它不正是我需要去:

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 
+1

您可以在這裏使用'fetch'方法而不是覆蓋'[]'。 http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-fetch –

1

在ruby中,無論您何時寫object.horray消息horray被髮送到對象object,這將返回一個值。由於每個horray是一條消息。如果對象不響應此消息,則無法區分該對象沒有該名稱的屬性,或者它沒有具有該名稱的方法。

所以,除非你認爲沒有方法可以有拼寫錯誤,否則你不可能做你想做的事情。

+0

如果你做到這一點上OpenStruct除了初始化之外,您將不能再創建新成員。 – dbenhur

+0

@dbenhur你是對的,ty,刪除那個例子 – fotanus

6

當您設置新成員時,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 
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) 
+0

@Serialize想要在讀取一個不存在的屬性時產生錯誤。 –

6

如果您需要嚴格的散列,只需:

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>' 
+1

我在找的是「點訪問」,而不是哈希訪問。 +1儘管如此,優雅。 – Seralize

1

我使用類似

hash = { a: 2, b: 3 } 

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

得到一個不可變對象,這將提高NoMethodError,以防意外的方法被調用

相關問題