2012-08-14 19 views

Respuesta

49

Si no lo hace específicamente h AVE a ser un Struct y en su lugar puede ser una OpenStruct:

pry(main)> require 'ostruct' 
pry(main)> s = OpenStruct.new(h) 
=> #<OpenStruct a=1, b=2> 
pry(main)> puts s.a, s.b 
1 
2 
+0

Nunca había oído hablar de 'OpenStruct' antes. ¡Eso es genial! ¡Gracias! – alf

+5

Tenga en cuenta que OpenStructs puede ser increíblemente lento de usar. Está bien para una pequeña cantidad de objetos pequeños, pero se escalan mal. Más información aquí: http://stackoverflow.com/questions/1177594/ruby-struct-vs-openstruct –

+0

@AFaderDarkly Creo que sus problemas de velocidad están bien documentados, pero gracias. –

8

A continuación se crea una estructura de un hash de una manera fiable (ya fin de hash no está garantizada en rubí) :

s = Struct.new(*(k = h.keys)).new(*h.values_at(*k)) 
45

Desde un orden clave hash está garantizada en Ruby 1.9+:

Struct.new(*h.keys).new(*h.values) 
+0

Es bueno saberlo.Pensé que lo había leído en alguna parte pero no recordaba dónde. ¡Gracias! – alf

+0

Esto no parece funcionar (al menos en Ruby 2.2.0): 'Struct.new (* h.keys)' plantea: 'NameError: identifier my_key necesita ser constante' – Joe

+2

@Joe funciona bien. Creo que usaste llaves de cadena para tu hash, que es la causa del error. El error le indica que necesita un valor constante, es decir, un símbolo en lugar de una cadena. Puedo reproducir el error en 2.1.5, desaparece si cambio al símbolo. – ehsanul

1

He aquí un ejemplo para asignar los valores a la orden de la struct:

require 'securerandom' 

Message = Struct.new(:to, :from, :message, :invitee) 

message_params = {from: "[email protected]", to: "[email protected]", 
     invitee: SecureRandom.uuid, message: "hello"} 

if Message.members.sort == message_params.keys.sort 
    # Do something with the return struct object here 
    Message.new *Message.members.map {|k| message_params[k] } 
else 
    raise "Invalid keys for Message" 
end 
52

Si ya ha definido una estructura, y que desea crear una instancia con un hash:

Person = Struct.new(:first_name, :last_name, :age) 

person_hash = { first_name: "Foo", last_name: "Bar", age: 29 } 

person = Person.new(*person_hash.values_at(*Person.members)) 

=> #<struct Person first_name="Foo", last_name="Bar", age=29> 
+0

Esta debería ser la respuesta aceptada :). ¡Gracias! – Ven

+0

¡Gracias! Estoy diseñando una gema que se puede invocar desde un comando o desde un código externo, cada una de las opciones de suministro (utilizando OptionParser o Hash, respectivamente). Esto permite un fácil filtrado de opciones durante la inicialización de mi gema. Y el Struct también ayuda a auto-documentar las opciones permitidas. – Excalibur

-1
require 'ds_hash' 

data = {a: {b: 123 }}.to_struct 

data.a.b == 123  # true 
data.a == {b: 123 } # true 
2

Habiendo Hash#to_struct es bastante práctico:

class Hash 
    def to_struct 
    Struct.new(*keys).new(*values) 
    end 
end 

Y algunos ejemplos:

>> { a: 1, b: 2 }.to_struct 
=> #<struct a=1, b=2> 
>> { a: 1, b: 2 }.to_struct.a 
=> 1 
>> { a: 1, b: 2 }.to_struct.b 
=> 2 
>> { a: 1, b: 2 }.to_struct.c 
NoMethodError: undefined method `c` for #<struct a=1, b=2> 

profundo to_struct que trabaja con matrices:

class Array 
    def to_struct 
    map { |value| value.respond_to?(:to_struct) ? value.to_struct : value } 
    end 
end 

class Hash 
    def to_struct 
    Struct.new(*keys).new(*values.to_struct) 
    end 
end 
+0

Es bueno, pero si su hash json '['name']', necesita simbolizar las teclas. – 7urkm3n

Cuestiones relacionadas