Is it possible to create a hash with attributes?
I want to be able to take the id from another collection, and use that as the key for a hash. Then I would like to be able to apply various attributes to each. It would be something like:
@books = Hash.new
@books[key].title = "A Title"
@books[key].condition = "Poor"
@books[key].rating = "Excellent"
or something to that effect. Is this even possible with some tweaks?
Thanks for your time!
Edit: I should have added that it is undesirable to create a Class in this case, although I ma开发者_开发问答y end up having to do that.
If you want exactly that syntax you can create a hash of OpenStruct
s:
require 'ostruct'
@books = Hash.new { |h, k| h[k] = OpenStruct.new }
key = 1
@books[key].title = "A Title"
@books[key].condition = "Poor"
@books[key].rating = "Excellent"
@books #=> {1=>#<OpenStruct title="A Title", condition="Poor", rating="Excellent">}
You can use multidimensional Hash?
@books = Book.all
@books_hash = {}
@books.each do |book|
@books_hash[book.id] = {}
@books_hash[book.id][:title] = book.title
@books_hash[book.id][:rating] = book.rating
end
You probably never want to do this, but just to answer the question.
Is this even possible with some tweaks?
Yes, we can create our own class to do this pretty easily.
class MyAnonObject
attr_accessor attributes
def attributes
@attributes ||= {}
end
def method_missing method, *args, &block
if method =~ /^(\w+)=$/
@attributes[$1] = args[0]
else
@attributes[$1]
end
end
end
And then we can modify your example to use this new class.
@books = Hash.new { MyAnonObject.new }
@books[key].title = "A Title"
@books[key].condition = "Poor"
@books[key].rating = "Excellent"
That being said, I wouldn't recommend this solution. It can be very confusing to read. However, it is possible =) And really, this is just a multi-dimensional hash with strange semantics.
You can make an object of type Book.
class Book
attr_accessor :tilte, :rating, :condition
end
And then modify your example to use the new Book class.
@books = Hash.new
@books[key] = Book.new
@books[key].title = "A Title"
@books[key].condition = "Poor"
@books[key].rating = "Excellent"
Similar to diedthreetimes anser, but the Book.new is done by the Hash:
class Book
attr_accessor :title
attr_accessor :condition
attr_accessor :rating
def initialize()
@undefined_values = {}
end
def method_missing ( m, *args )
@undefined_values[m] = args
end
def inspect()
"Book #{@title} (#{@condition}, #{@rating}, #{@undefined_values.inspect})"
end
end
@books = Hash.new{ |hash,k| hash[k] = Book.new
}
key = :xx
@books[key].title = "A Title"
@books[key].condition = "Poor"
@books[key].rating = "Excellent"
@books[key].isbn = "123456"
p @books[key] #-> Book A Title (Poor, Excellent, {:isbn==>["123456"]})
edit: Added code to handle undefined values. p @books[key]
精彩评论