Powiedzmy, że mam Gift
obiekt z @name = "book"
& @price = 15.95
. Jaki jest najlepszy sposób na przekonwertowanie tego na Hash {name: "book", price: 15.95}
w Ruby, a nie Railsy (chociaż możesz też udzielić odpowiedzi Railsom)?
ruby
object
hashmap
instance-variables
ma11hew28
źródło
źródło
Gift
jest dokładnie takie, jak zdefiniował @nash , z wyjątkiem 2) oczywiście , zmienne instancji mogą mieć dostęp do czytnika. 3) Wszystkie atrybuty prezentu.Odpowiedzi:
class Gift def initialize @name = "book" @price = 15.95 end end gift = Gift.new hash = {} gift.instance_variables.each {|var| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) } p hash # => {"name"=>"book", "price"=>15.95}
Alternatywnie z
each_with_object
:gift = Gift.new hash = gift.instance_variables.each_with_object({}) { |var, hash| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) } p hash # => {"name"=>"book", "price"=>15.95}
źródło
var.to_s.delete("@")
zvar[1..-1].to_sym
dostać symboli.gift.instance_variables.each_with_object({}) { |var,hash| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) }
i pozbądź się końcowego; hash
each
.map
iinject
są znacznie potężniejsze. To jedna z wad projektowych, które mam w Rubim:map
iinject
są one realizowane zeach
. To po prostu zła informatyka.hash = Hash[gift.instance_variables.map { |var| [var.to_s[1..-1], gift.instance_variable_get(var)] } ]
Po prostu powiedz (bieżący obiekt)
.attributes
.attributes
zwracahash
z anyobject
. Jest też dużo czystszy.źródło
.values
instance_values
może być użyty dla wszystkich obiektów ruby dla podobnego wyniku.Wdrożyć
#to_hash
?class Gift def to_hash hash = {} instance_variables.each { |var| hash[var.to_s.delete('@')] = instance_variable_get(var) } hash end end h = Gift.new("Book", 19).to_hash
źródło
Use :: for describing class methods, # for describing instance methods, and use . for example code
(źródło: ruby-doc.org/documentation-guidelines.html ) Ponadto oficjalna dokumentacja (taka jak ruby CHANGELOG , github.com/ruby/ruby/blob/v2_1_0/NEWS ) używa#
na przykład metod i kropki dla metod klasowych dość konsekwentnie.each_with_object
instance_variables.each_with_object(Hash.new(0)) { |element, hash| hash["#{element}".delete("@").to_sym] = instance_variable_get(element) }
Gift.new.instance_values # => {"name"=>"book", "price"=>15.95}
źródło
instance_values
. Zauważ, że Matt poprosił o sposób w Ruby, a konkretnie nie o Railsy.Możesz użyć
as_json
metody. Przekształci twój obiekt w hash.Ale ten skrót będzie wartością dla nazwy tego obiektu jako klucza. W Twoim przypadku,
{'gift' => {'name' => 'book', 'price' => 15.95 }}
Jeśli potrzebujesz skrótu przechowywanego w obiekcie, użyj
as_json(root: false)
. Myślę, że domyślnie root będzie fałszywy. Aby uzyskać więcej informacji, zapoznaj się z oficjalnym przewodnikiem po Rubimhttp://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json
źródło
Dla obiektów Active Record
module ActiveRecordExtension def to_hash hash = {}; self.attributes.each { |k,v| hash[k] = v } return hash end end class Gift < ActiveRecord::Base include ActiveRecordExtension .... end class Purchase < ActiveRecord::Base include ActiveRecordExtension .... end
a potem po prostu zadzwoń
źródło
Jeśli nie jesteś w środowisku Railsów (tj. Nie masz dostępnego ActiveRecord), może to być pomocne:
źródło
class Gift def to_hash instance_variables.map do |var| [var[1..-1].to_sym, instance_variable_get(var)] end.to_h end end
źródło
Możesz napisać bardzo eleganckie rozwiązanie używając funkcjonalnego stylu.
class Object def hashify Hash[instance_variables.map { |v| [v.to_s[1..-1].to_sym, instance_variable_get v] }] end end
źródło
Powinieneś zastąpić
inspect
metodę obiektu, aby zwrócić żądany skrót, lub po prostu zaimplementować podobną metodę bez zastępowania domyślnego zachowania obiektu.Jeśli chcesz być bardziej wyrafinowany, możesz iterować zmienne instancji obiektu za pomocą object.instance_variables
źródło
Rekurencyjnie konwertuj swoje obiekty na hash za pomocą klejnotu „hashable” ( https://rubygems.org/gems/hashable ) Przykład
class A include Hashable attr_accessor :blist def initialize @blist = [ B.new(1), { 'b' => B.new(2) } ] end end class B include Hashable attr_accessor :id def initialize(id); @id = id; end end a = A.new a.to_dh # or a.to_deep_hash # {:blist=>[{:id=>1}, {"b"=>{:id=>2}}]}
źródło
Może zechcesz spróbować
instance_values
. To zadziałało dla mnie.źródło
Tworzy płytką kopię jako obiekt skrótu tylko atrybutów modelu
Sprawdź typ wynikowego obiektu
my_hash_gift.class => Hash
źródło
Jeśli potrzebujesz również konwersji zagnieżdżonych obiektów.
# @fn to_hash obj {{{ # @brief Convert object to hash # # @return [Hash] Hash representing converted object # def to_hash obj Hash[obj.instance_variables.map { |key| variable = obj.instance_variable_get key [key.to_s[1..-1].to_sym, if variable.respond_to? <:some_method> then hashify variable else variable end ] }] end # }}}
źródło
Gift.new.attributes.symbolize_keys
źródło
Aby to zrobić bez Railsów, czystym sposobem jest przechowywanie atrybutów w stałej.
class Gift ATTRIBUTES = [:name, :price] attr_accessor(*ATTRIBUTES) end
Następnie, aby przekonwertować wystąpienie
Gift
na aHash
, możesz:class Gift ... def to_h ATTRIBUTES.each_with_object({}) do |attribute_name, memo| memo[attribute_name] = send(attribute_name) end end end
Jest to dobry sposób na zrobienie tego, ponieważ będzie obejmował tylko to, co zdefiniujesz
attr_accessor
, a nie każdą zmienną instancji.class Gift ATTRIBUTES = [:name, :price] attr_accessor(*ATTRIBUTES) def create_random_instance_variable @xyz = 123 end def to_h ATTRIBUTES.each_with_object({}) do |attribute_name, memo| memo[attribute_name] = send(attribute_name) end end end g = Gift.new g.name = "Foo" g.price = 5.25 g.to_h #=> {:name=>"Foo", :price=>5.25} g.create_random_instance_variable g.to_h #=> {:name=>"Foo", :price=>5.25}
źródło
Zacząłem używać struktur, aby ułatwić konwersje haszujące. Zamiast używać czystej struktury, tworzę własną klasę wywodzącą się z skrótu, co pozwala na tworzenie własnych funkcji i dokumentuje właściwości klasy.
require 'ostruct' BaseGift = Struct.new(:name, :price) class Gift < BaseGift def initialize(name, price) super(name, price) end # ... more user defined methods here. end g = Gift.new('pearls', 20) g.to_h # returns: {:name=>"pearls", :price=>20}
źródło