Class: Hecks::Runtime::Instance
- Inherits:
-
Object
- Object
- Hecks::Runtime::Instance
show all
- Defined in:
- lib/hecks/runtime/instance.rb
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(aggregate:, id:, state: nil) ⇒ Instance
Returns a new instance of Instance.
9
10
11
12
13
14
|
# File 'lib/hecks/runtime/instance.rb', line 9
def initialize(aggregate:, id:, state: nil)
@aggregate = aggregate
@id = id
@state = state ? self.class.hydrate_with_defaults(aggregate, state) : self.class.defaults(aggregate)
materialize_identity!
end
|
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
62
63
64
65
66
|
# File 'lib/hecks/runtime/instance.rb', line 62
def method_missing(name, *args)
return @state[name] if @state.key?(name)
super
end
|
Instance Attribute Details
#aggregate ⇒ Object
Returns the value of attribute aggregate.
6
7
8
|
# File 'lib/hecks/runtime/instance.rb', line 6
def aggregate
@aggregate
end
|
#id ⇒ Object
Returns the value of attribute id.
6
7
8
|
# File 'lib/hecks/runtime/instance.rb', line 6
def id
@id
end
|
#state ⇒ Object
Returns the value of attribute state.
7
8
9
|
# File 'lib/hecks/runtime/instance.rb', line 7
def state
@state
end
|
Class Method Details
.default_for(aggregate, attribute) ⇒ Object
42
43
44
45
46
47
48
49
50
51
52
|
# File 'lib/hecks/runtime/instance.rb', line 42
def self.default_for(aggregate, attribute)
return Value.for_attribute(aggregate, attribute, attribute.default) unless attribute.default.nil?
return nil unless aggregate.respond_to?(:value_object)
value_object = aggregate.value_object(attribute.type)
return nil unless value_object && value_object.attributes.all? { |field| !field.default.nil? }
Value.build(value_object, {}, aggregate)
end
|
.defaults(aggregate) ⇒ Object
30
31
32
33
34
35
36
37
38
39
40
|
# File 'lib/hecks/runtime/instance.rb', line 30
def self.defaults(aggregate)
state = aggregate.attributes.each_with_object({}) do |attr, acc|
acc[attr.name] = attr.list? ? Freezer.deep([]) : default_for(aggregate, attr)
end
state[aggregate.lifecycle.field.to_sym] = aggregate.lifecycle.default if aggregate.lifecycle
state
end
|
.hydrate_with_defaults(aggregate, state) ⇒ Object
Loading existing state runs the same default-fill a fresh instance
gets: an attribute the record predates — a newly-required field
with a declared default:, a list added since the record was
written — arrives filled instead of nil. Only declared defaults
fill in; an attribute with no default stays absent, exactly as
stored.
22
23
24
25
26
27
28
|
# File 'lib/hecks/runtime/instance.rb', line 22
def self.hydrate_with_defaults(aggregate, state)
hydrated = Value.hydrate(aggregate, state)
defaults(aggregate).each do |name, value|
hydrated[name] = value unless value.nil? || hydrated.key?(name)
end
hydrated
end
|
Instance Method Details
#[](name) ⇒ Object
54
|
# File 'lib/hecks/runtime/instance.rb', line 54
def [](name) = @state[name.to_sym]
|
#[]=(name, value) ⇒ Object
58
59
60
|
# File 'lib/hecks/runtime/instance.rb', line 58
def []=(name, value)
@state[name.to_sym] = value
end
|
#dup ⇒ Object
A COPY A MUTATION MAY TOUCH. Every adapter but Memory hands find
a freshly-decoded Instance already; Memory's holds the record it
eventually saves — the SAME state Hash, aliased. Before ensures
existed, nothing could refuse between apply_mutations and save, so
that aliasing was invisible: a dispatch either ran to completion or
raised before touching state at all. ensures is the first refusal
to sit AFTER mutation, and it found the bug the moment it did — an
in-memory record left half-mutated by a dispatch that then refused.
command_interpreter/entity_interpreter hydrate an EXISTING
record through this, never through the adapter's own return value
directly, so a refused ensures leaves the stored record untouched
regardless of which adapter is holding it.
93
94
95
96
97
|
# File 'lib/hecks/runtime/instance.rb', line 93
def dup
copy = super
copy.state = @state.dup
copy
end
|
#inspect ⇒ Object
99
100
101
102
|
# File 'lib/hecks/runtime/instance.rb', line 99
def inspect
fields = @state.map { |k, v| "#{k}=#{v.inspect}" }.join(" ")
"#<#{@aggregate.hecks_name} #{@id} #{fields}>"
end
|
#key?(name) ⇒ Boolean
56
|
# File 'lib/hecks/runtime/instance.rb', line 56
def key?(name) = @state.key?(name.to_sym)
|
#respond_to_missing?(name, include_private = false) ⇒ Boolean
68
69
70
|
# File 'lib/hecks/runtime/instance.rb', line 68
def respond_to_missing?(name, include_private = false)
@state.key?(name) || super
end
|
#to_h ⇒ Object
id: @id LAST, not first — see Facade::Handle#to_h's own comment
for the full story (the same fix, landed there first): an
aggregate free to declare its own attribute literally named id
(BurningManPrep's Item, attribute :id, ItemId) has that
attribute's own wrapped value object sitting in @state[:id] —
merging @state on top of { id: @id } let it silently clobber
the correct bare identity. @id merged last always wins.
79
|
# File 'lib/hecks/runtime/instance.rb', line 79
def to_h = @state.merge(id: @id)
|