2013-06-03 1 views
9

J'essaie de comprendre comment faire en sorte qu'une sous-classe de OpenStruct (ou n'importe quelle classe d'ailleurs), ou hachage, déclenche une exception personnalisée si J'essaie d'accéder à un attribut qui n'a pas été défini. Je ne pouvais pas obtenir define_method et method_missing pour le faire, donc je ne sais pas comment cela devrait être fait dans Ruby.Soulevez l'exception lors de l'accès aux attributs qui n'existent pas dans OpenStruct

Voici un exemple:

class Request < OpenStruct... 

request = Request.new 

begin 
    request.non_existent_attr 
rescue CustomError... 

je pouvais l'imaginer devrait être quelque chose comme ceci:

class Hash 
    # if trying to access key: 
    # 1) key exists, return key 
    # 2) key doesn't exist, raise exception 
end 

Edit: Les attributs qui existent ne devrait pas soulever une exception. La fonctionnalité que je recherche est telle que je peux simplement accéder aux attributs librement et si cela n'arrive pas, mon exception personnalisée sera levée.

Répondre

0

Je suis allé avec cette solution qui fait exactement ce que je dois:

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

Vous pouvez utiliser la méthode 'fetch' au lieu d'écraser' [] 'ici. http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-fetch –

1

Dans ruby, chaque fois que vous écrivez object.horray le message horray est envoyé à l'objet object, qui va retourner une valeur. Puisque chaque horray est un message. Si l'objet ne répond pas à ce message, vous ne pouvez pas faire la distinction entre l'objet ne possédant pas d'attribut portant ce nom ou s'il ne possède pas de méthode portant ce nom. Donc, à moins que vous supposiez qu'aucune méthode ne peut avoir une faute de frappe, il n'est pas possible de faire ce que vous voulez. OpenStruct définit des méthodes d'accès singleton sur l'objet lorsque vous définissez un nouveau membre, vous pouvez donc utiliser respond_to? pour voir si le membre est valide.

+0

Si vous faites cela sur un OpenStruct , vous ne pourrez plus créer de nouveaux membres sauf à l'initialisation. – dbenhur

+0

@dbhur vous avez raison, ty, en supprimant cet exemple – fotanus

6

En fait, vous pouvez probablement capturer n'importe quelle méthode non définie avec method_missing et lancer l'erreur sauf s'il s'agit d'un nom de méthode setter, auquel cas vous la passerez à 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

Il est brutal, mais vous pouvez remplacer la méthode new_ostruct_member pour générer une erreur:

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 veut soulever une erreur en lisant un attribut inexistant. –

6

Si vous besoin d'un hachage strict, simplement:

class StrictHash < Hash 
    alias [] fetch 
end 

Il fonctionne comme prévu:

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

Ce que je cherchais, c'était "accès au point", pas l'accès au hachage. +1 Pour l'élégance, cependant. – Seralize

1

J'utilise quelque chose comme

hash = { a: 2, b: 3 } 

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

pour obtenir un objet immuable qui soulèvera NoMethodError en cas de méthode inattendus est invoquée

Questions connexes