Andrew Andrew - 6 months ago 15
Ruby Question

How to define a Ruby Struct which accepts its initialization arguments as a hash?

I have a situation where I would like to create a class which accepts many arguments and has setters and getters in the fewest lines of code possible (for maintainability). I thought that using a Struct would be a good idea for this:

Customer = Struct.new(:id, :username, :first_name, :last_name, :address1, ...etc...)

Customer.new(123, 'joe', 'Joe', ...etc...)


However, I don't like having to know the exact order of the attributes. I prefer Ruby 2's keyword arguments feature:

class Customer
attr_accessor :id, :username, :first_name, ...etc...
def initialize(id:, username:, first_name:, last_name:, address1:, ...etc...)
@id = id
@username = username
@first_name = first_name
...etc...
end
end

Customer.new(id: 123, username: 'joe', first_name: 'Joe', ...etc...)


However, writing this all out requires a lot more code and is more tedious. Is there a way to achieve the same thing in a short-hand like the Struct?

Answer

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