1
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
module ActiveRecord
class AttributeSet # :nodoc:
class Builder # :nodoc:
attr_reader :types, :always_initialized
def initialize(types, always_initialized = nil)
@types = types
@always_initialized = always_initialized
end
def build_from_database(values = {}, additional_types = {})
if always_initialized && !values.key?(always_initialized)
values[always_initialized] = nil
end
attributes = LazyAttributeHash.new(types, values, additional_types)
AttributeSet.new(attributes)
end
private
end
end
class LazyAttributeHash
delegate :select, :transform_values, to: :materialize
def initialize(types, values, additional_types)
@types = types
@values = values
@additional_types = additional_types
@materialized = false
@delegate_hash = {}
end
def key?(key)
delegate_hash.key?(key) || values.key?(key) || types.key?(key)
end
def [](key)
if delegate_hash.key?(key)
delegate_hash[key]
else
assign_default_value(key)
end
end
def []=(key, value)
if frozen?
raise RuntimeError, "Can't modify frozen hash"
end
delegate_hash[key] = value
end
def initialized_keys
delegate_hash.keys | values.keys
end
def initialize_dup(_)
@delegate_hash = delegate_hash.transform_values(&:dup)
super
end
protected
attr_reader :types, :values, :additional_types, :delegate_hash
private
def assign_default_value(name)
type = additional_types.fetch(name, types[name])
if values.key?(name)
delegate_hash[name] = Attribute.from_database(name, values[name], type)
elsif types.key?(name)
delegate_hash[name] = Attribute.uninitialized(name, type)
end
end
def materialize
unless @materialized
values.each_key { |key| self[key] }
types.each_key { |key| self[key] }
@materialized = true
end
delegate_hash
end
end
end
|