Skip to content

Instantly share code, notes, and snippets.

@reu
Created January 20, 2020 19:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reu/d802a29b9f715c190e064d344f009b0f to your computer and use it in GitHub Desktop.
Save reu/d802a29b9f715c190e064d344f009b0f to your computer and use it in GitHub Desktop.
Person = Immutable.new(:name, :age)
p1 = Person.new(name: "Sasha", age: 30) # <Person @name="Sasha", @age=30>
p2 = p1.with_name("Tori") # <Person @name="Tori", @age=30>
p3 = p2.update(name: "Craudio", age: 10) # <Person @name="Craudio", @age=10>
Person.new(name: "Sasha").with_age(30).with_name { |name| "#{name} Grey" } # <Person @name="Sasha Grey", @age=30>
class Immutable
def self.new(*attributes)
Class.new do
attributes.each do |attribute|
attr_reader attribute
define_method(:"with_#{attribute}") do |value = nil, &block|
update(attribute => block ? block.call(send(attribute)) : value)
end
end
define_method(:initialize) do |**kwargs|
attributes.each do |attribute|
instance_variable_set("@#{attribute}", kwargs[attribute])
end
end
define_method(:to_h) do
attributes
.map { |attribute| [attribute, instance_variable_get("@#{attribute}")] }
.to_h
end
define_method(:update) do |values|
self.class.new(to_h.merge(values))
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment