Class: SolidObjects::ActorDefinition
- Inherits:
-
Object
- Object
- SolidObjects::ActorDefinition
show all
- Defined in:
- lib/solid_objects/actor_definition.rb,
sig/generated/lib/solid_objects/actor_definition.rbs
Defined Under Namespace
Classes: Handler, StateMigration
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#actor_message_method_names(actor_class) ⇒ Array[Symbol]
-
#add_attribute(name, default:) ⇒ StateDefinition::Attribute
-
#add_handler(collection, name, block) ⇒ Handler
-
#add_message(name, block) ⇒ Handler
-
#add_method_message(name) ⇒ Handler
-
#add_observable(name, block = nil) ⇒ Handler
-
#add_query(name, block) ⇒ Handler
-
#add_state_migration(from, to, block) ⇒ StateMigration
-
#duplicate ⇒ ActorDefinition
-
#initialize ⇒ ActorDefinition
constructor
A new instance of ActorDefinition.
-
#migrate_state(version, data) ⇒ Hash[String, untyped]
-
#set_state_version(version) ⇒ Integer
-
#synchronize_instance_messages(actor_class) ⇒ ActorDefinition
-
#validate_attribute_methods!(attribute_method_names) ⇒ void
Constructor Details
Returns a new instance of ActorDefinition.
29
30
31
32
33
34
35
36
37
38
39
40
|
# File 'lib/solid_objects/actor_definition.rb', line 29
def initialize
@state_definition = StateDefinition.new
@messages = {}
@queries = {}
@observables = {}
@state_version = 1
@state_migrations = []
@activation_hooks = []
@deactivation_hooks = []
@attribute_queries = {}
@method_messages = {}
end
|
Instance Attribute Details
#activation_hooks ⇒ Object
19
20
21
|
# File 'lib/solid_objects/actor_definition.rb', line 19
def activation_hooks
@activation_hooks
end
|
#attribute_queries ⇒ Object
Returns the value of attribute attribute_queries.
163
164
165
|
# File 'lib/solid_objects/actor_definition.rb', line 163
def attribute_queries
@attribute_queries
end
|
#deactivation_hooks ⇒ Object
19
20
21
|
# File 'lib/solid_objects/actor_definition.rb', line 19
def deactivation_hooks
@deactivation_hooks
end
|
#messages ⇒ Object
19
20
21
|
# File 'lib/solid_objects/actor_definition.rb', line 19
def messages
@messages
end
|
#method_messages ⇒ Object
Returns the value of attribute method_messages.
163
164
165
|
# File 'lib/solid_objects/actor_definition.rb', line 163
def method_messages
@method_messages
end
|
#observables ⇒ Object
19
20
21
|
# File 'lib/solid_objects/actor_definition.rb', line 19
def observables
@observables
end
|
#queries ⇒ Object
19
20
21
|
# File 'lib/solid_objects/actor_definition.rb', line 19
def queries
@queries
end
|
#state_definition ⇒ Object
19
20
21
|
# File 'lib/solid_objects/actor_definition.rb', line 19
def state_definition
@state_definition
end
|
#state_migrations ⇒ Object
19
20
21
|
# File 'lib/solid_objects/actor_definition.rb', line 19
def state_migrations
@state_migrations
end
|
#state_version ⇒ Object
19
20
21
|
# File 'lib/solid_objects/actor_definition.rb', line 19
def state_version
@state_version
end
|
Instance Method Details
#actor_message_method_names(actor_class) ⇒ Array[Symbol]
181
182
183
184
185
186
187
188
189
190
191
192
193
|
# File 'lib/solid_objects/actor_definition.rb', line 181
def actor_message_method_names(actor_class)
actor_ancestors = actor_class.ancestors.take_while { |ancestor| ancestor != Actor }
attribute_method_names = actor_class.send(:generated_attribute_methods).keys
validate_attribute_methods!(attribute_method_names)
actor_class.public_instance_methods.filter_map do |name|
method_name = name.to_sym
next if attribute_method_names.include?(method_name)
next unless actor_ancestors.include?(actor_class.instance_method(method_name).owner)
method_name
end.uniq
end
|
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
# File 'lib/solid_objects/actor_definition.rb', line 43
def add_attribute(name, default:)
attribute_name = name.to_sym
if messages.key?(attribute_name) || queries.key?(attribute_name)
raise InvalidActor, "#{attribute_name.inspect} is already defined"
end
state_definition.attribute(attribute_name, default:).tap do
queries[attribute_name] = Handler.new(
name: attribute_name,
block: -> { state.fetch(attribute_name) }
)
attribute_queries[attribute_name] = true
end
end
|
#add_handler(collection, name, block) ⇒ Handler
207
208
209
210
211
212
|
# File 'lib/solid_objects/actor_definition.rb', line 207
def add_handler(collection, name, block)
handler_name = name.to_sym
raise InvalidActor, "#{handler_name.inspect} is already defined" if messages.key?(handler_name) || queries.key?(handler_name)
Handler.new(name: handler_name, block:).tap { |handler| collection[handler_name] = handler }
end
|
#add_message(name, block) ⇒ Handler
59
60
61
|
# File 'lib/solid_objects/actor_definition.rb', line 59
def add_message(name, block)
add_handler(messages, name, block)
end
|
#add_method_message(name) ⇒ Handler
166
167
168
169
170
171
172
173
174
175
176
177
178
|
# File 'lib/solid_objects/actor_definition.rb', line 166
def add_method_message(name)
if messages.key?(name) || queries.key?(name)
raise InvalidActor, "#{name.inspect} is already defined"
end
Handler.new(
name:,
block: ->(**arguments) { public_send(name, **arguments) }
).tap do |handler|
messages[name] = handler
method_messages[name] = true
end
end
|
#add_observable(name, block = nil) ⇒ Handler
76
77
78
79
80
81
82
83
84
|
# File 'lib/solid_objects/actor_definition.rb', line 76
def add_observable(name, block = nil)
observable_name = name.to_sym
raise InvalidActor, "#{observable_name.inspect} observable is already defined" if observables.key?(observable_name)
observable_block = block || -> { state.fetch(observable_name) }
Handler.new(name: observable_name, block: observable_block).tap do |handler|
observables[observable_name] = handler
end
end
|
#add_query(name, block) ⇒ Handler
64
65
66
67
68
69
70
71
72
73
|
# File 'lib/solid_objects/actor_definition.rb', line 64
def add_query(name, block)
query_name = name.to_sym
if attribute_queries.delete(query_name)
return Handler.new(name: query_name, block:).tap do |handler|
queries[query_name] = handler
end
end
add_handler(queries, name, block)
end
|
#add_state_migration(from, to, block) ⇒ StateMigration
107
108
109
110
111
112
113
114
115
116
117
|
# File 'lib/solid_objects/actor_definition.rb', line 107
def add_state_migration(from, to, block)
unless to == from + 1
raise InvalidActor, "state migrations must advance exactly one version"
end
if state_migrations.any? { |migration| migration.from == from }
raise InvalidActor, "state migration from version #{from} is already defined"
end
StateMigration.new(from:, to:, block:).tap { |migration| state_migrations << migration }
end
|
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
# File 'lib/solid_objects/actor_definition.rb', line 146
def duplicate
self.class.new.tap do |copy|
copy.instance_variable_set(:@state_definition, state_definition.duplicate)
copy.instance_variable_set(:@messages, messages.dup)
copy.instance_variable_set(:@queries, queries.dup)
copy.instance_variable_set(:@observables, observables.dup)
copy.instance_variable_set(:@state_version, state_version)
copy.instance_variable_set(:@state_migrations, state_migrations.dup)
copy.instance_variable_set(:@activation_hooks, activation_hooks.dup)
copy.instance_variable_set(:@deactivation_hooks, deactivation_hooks.dup)
copy.instance_variable_set(:@attribute_queries, attribute_queries.dup)
copy.instance_variable_set(:@method_messages, method_messages.dup)
end
end
|
#migrate_state(version, data) ⇒ Hash[String, untyped]
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
# File 'lib/solid_objects/actor_definition.rb', line 120
def migrate_state(version, data)
migrated = Serialization.deep_copy(data)
current_version = version
while current_version < state_version
migration = state_migrations.find { |candidate| candidate.from == current_version }
raise StateMigrationError, "missing state migration from version #{current_version}" unless migration
migrated = Serialization.dump(migration.block.call(migrated))
current_version = migration.to
end
if current_version > state_version
raise StateMigrationError, "stored state version #{current_version} is newer than code version #{state_version}"
end
migrated
rescue StateMigrationError
raise
rescue ActiveRecord::ReadOnlyError
raise
rescue => error
raise StateMigrationError, "state migration failed: #{error.message}"
end
|
#set_state_version(version) ⇒ Integer
100
101
102
103
104
|
# File 'lib/solid_objects/actor_definition.rb', line 100
def set_state_version(version)
raise InvalidActor, "state version must be positive" unless version.positive?
@state_version = version
end
|
#synchronize_instance_messages(actor_class) ⇒ ActorDefinition
87
88
89
90
91
92
93
94
95
96
97
|
# File 'lib/solid_objects/actor_definition.rb', line 87
def synchronize_instance_messages(actor_class)
names = actor_message_method_names(actor_class)
(method_messages.keys - names).each do |name|
messages.delete(name)
method_messages.delete(name)
end
names.each { |name| add_method_message(name) unless method_messages.key?(name) }
self
end
|
#validate_attribute_methods!(attribute_method_names) ⇒ void
This method returns an undefined value.
196
197
198
199
200
201
202
203
204
|
# File 'lib/solid_objects/actor_definition.rb', line 196
def validate_attribute_methods!(attribute_method_names)
state_definition.to_h.each_key do |name|
[ name, :"#{name}=" ].each do |method_name|
next if attribute_method_names.include?(method_name)
raise InvalidActor, "actor method #{method_name} overrides attribute #{name.inspect}"
end
end
end
|