module RubyImmutableStruct
Public Class Methods
new(*attributes, &block)
click to toggle source
# File lib/ruby-immutable-struct.rb, line 2 def self.new(*attributes, &block) attributes = attributes.map(&:to_sym) if !attributes.all? { |a| a.to_s =~ /^[_a-z][_a-zA-Z0-9_]*/ } raise "ImmutableStruct only allows attributes that look like Ruby variables: /[_a-z][a-zA-Z0-9_]*/. That keeps things fast and simple." end klass = Class.new do attr_reader(*attributes) class_eval <<-EOT def initialize(*args) # args.length == 1 is faster than args[0].is_a?(Hash). So check it # first -- speed demons won't be using hashes, so let's save them the # is_a? call. if args.length == 1 && args[0].is_a?(Hash) hash = args[0] #{attributes.map{ |a| "@#{a} = hash[:#{a}]" }.join(';')} else #{attributes.map.with_index{ |a, i| "@#{a} = args[#{i}]" }.join(';')} end after_initialize freeze end def after_initialize # Implementations may override this end def merge(hash) merged_hash = to_h.merge!(hash) self.class.new(merged_hash) end def to_h { #{attributes.map{ |a| "#{a}: @#{a}" }.join(',')} } end def to_a [ #{attributes.map{ |a| "@#{a}" }.join(',')} ] end def ==(other) #{attributes.map{ |a| "@#{a} == other.#{a}" }.join(' && ')} end alias :eql? :== def hash to_a.hash end def inspect "#<#\{self.class.name} #\{to_a.map(&:inspect).join(',')}>" end def to_s inspect end EOT end klass.class_exec(&block) if !block.nil? klass end