2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
# 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 " def initialize(*args)\n # args.length == 1 is faster than args[0].is_a?(Hash). So check it\n # first -- speed demons won't be using hashes, so let's save them the\n # is_a? call.\n if args.length == 1 && args[0].is_a?(Hash)\n hash = args[0]\n \#{attributes.map{ |a| \"@\#{a} = hash[:\#{a}]\" }.join(';')}\n else\n \#{attributes.map.with_index{ |a, i| \"@\#{a} = args[\#{i}]\" }.join(';')}\n end\n\n after_initialize\n\n freeze\n end\n\n def after_initialize\n # Implementations may override this\n end\n\n def merge(hash)\n merged_hash = to_h.merge!(hash)\n self.class.new(merged_hash)\n end\n\n def to_h\n { \#{attributes.map{ |a| \"\#{a}: @\#{a}\" }.join(',')} }\n end\n\n def to_a\n [ \#{attributes.map{ |a| \"@\#{a}\" }.join(',')} ]\n end\n\n def ==(other)\n \#{attributes.map{ |a| \"@\#{a} == other.\#{a}\" }.join(' && ')}\n end\n alias :eql? :==\n\n def hash\n to_a.hash\n end\n\n def inspect\n \"#<#\\{self.class.name} #\\{to_a.map(&:inspect).join(',')}>\"\n end\n\n def to_s\n inspect\n end\n EOT\n end\n\n klass.class_exec(&block) if !block.nil?\n\n klass\nend\n"
|