Jonah Jonah - 15 days ago 5
Ruby Question

Use another object's constructor inside your initializer?

Consider this code:

Campus = ImmutableStruct.new(:id, :name, :timezone) do
def hash; id end
end

Merchant = ImmutableStruct.new(:id, :name, :campus) do
def hash; id end
end


Notice the duplication of the
hash
method. I want to remove this duplication with a new class
ImmutableStructWithId
. That new class would allow the above 2 lines to be rewritten as follows:

Campus = ImmutableStructWithId.new(:id, :name, :timezone)
Merchant = ImmutableStructWithId.new(:id, :name, :campus)


If ruby's initializer worked like factory functions (they don't), something like the following is what I'd want:

class ImmutableStructWithId
def initialize(*args)
ImmutableStruct.new(*args) do
def hash; id end
end
end
end


I am aware the above won't work, because initializers don't return the object they are creating, they just initialize it. But if they did work like factory functions, the above is what I'd want to do.

What is the correct way to achieve the same effect in ruby?

Answer

IMO this should work for you:

require 'immutable-struct'

module ImmutableStructWithId
  def self.new(*args)
    ImmutableStruct.new(*args) do
      def hash; id; end
    end
  end
end

Campus = ImmutableStructWithId.new(:id, :name, :timezone)
campus = Campus.new(id: '1', name: 'foo', timezone: 'UTC')
#=> #<Campus:0x007f8ed581de20 @id="1", @name="foo", @timezone="UTC">
campus.hash
#=> "1"