Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

ruby

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?

like image 361
Andrew Avatar asked May 17 '14 21:05

Andrew


2 Answers

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
like image 65
schpet Avatar answered Nov 04 '22 23:11

schpet


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
like image 14
BroiSatse Avatar answered Nov 04 '22 22:11

BroiSatse