How to define a Ruby Struct which accepts its initialization arguments as a hash?
If you don't care about performance, you can use an OpenStruct
.
require 'ostruct'
user = OpenStruct.new(id: 1, username: 'joe', first_name: 'Joe', ...)
user.first_name
=> "Joe"
See this for more details.
It's entirely possible to make it a class and define methods on it:
class Customer < Openstruct
def hello
"world"
end
end
joe = Customer.new(id: 1, username: 'joe', first_name: 'Joe', ...)
joe.hello
=> "world"
But again, because OpenStructs are implemented using method_missing
and define_method
, they are pretty slow. I would go with BroiSatse's answer. If you care about required parameters, you should so something along the lines of
def initialize(params = {})
if missing_required_param?(params)
raise ArgumentError.new("Missing required parameter")
end
params.each do |k,v|
send("#{k}=", v)
end
end
def missing_required_params?(params)
...
end
Cant you just do:
def initialize(hash)
hash.each do |key, value|
send("#{key}=", value)
end
end
UPDATE:
To specify default values you can do:
def initialize(hash)
default_values = {
first_name: ''
}
default_values.merge(hash).each do |key, value|
send("#{key}=", value)
end
end
If you want to specify that given attribute is required, but has no default value you can do:
def initialize(hash)
requried_keys = [:id, :username]
default_values = {
first_name: ''
}
raise 'Required param missing' unless (required_keys - hash.keys).empty?
default_values.merge(hash).each do |key, value|
send("#{key}=", value)
end
end
In ruby 2.5 you can do the following:
Customer = Struct.new(
:id,
:username,
:first_name,
keyword_init: true
)
Customer.new(username: "al1ce", first_name: "alice", id: 123)
=> #<struct Customer id=123, username="al1ce", first_name="alice">
references:
- https://ruby-doc.org/core-2.5.0/Struct.html