Class: SolidObjects::Actor

Inherits:
Object
  • Object
show all
Defined in:
lib/solid_objects/actor.rb,
sig/generated/lib/solid_objects/actor.rbs

Defined Under Namespace

Classes: EffectIntent, OutboundMessageIntent, ReminderIntent

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(actor_id:, state:) ⇒ Actor

Returns a new instance of Actor.

RBS:

  • (actor_id: String, state: State) -> void

Parameters:

  • actor_id: (String)
  • state: (State)


140
141
142
143
144
145
146
# File 'lib/solid_objects/actor.rb', line 140

def initialize(actor_id:, state:)
  @actor_id = actor_id
  @state = state
  @effect_intents = []
  @reminder_intents = []
  @outbound_message_intents = []
end

Instance Attribute Details

#actor_idObject (readonly)

RBS:

  • @actor_id: String

  • @state: State

  • @effect_intents: Array[EffectIntent]

  • @reminder_intents: Array[ReminderIntent]

  • @outbound_message_intents: Array[OutboundMessageIntent]

Returns:

  • (Object)


137
138
139
# File 'lib/solid_objects/actor.rb', line 137

def actor_id
  @actor_id
end

#effect_intentsObject (readonly)

Returns the value of attribute effect_intents.

Returns:

  • (Object)


269
270
271
# File 'lib/solid_objects/actor.rb', line 269

def effect_intents
  @effect_intents
end

#outbound_message_intentsObject (readonly)

Returns the value of attribute outbound_message_intents.

Returns:

  • (Object)


269
270
271
# File 'lib/solid_objects/actor.rb', line 269

def outbound_message_intents
  @outbound_message_intents
end

#reminder_intentsObject (readonly)

Returns the value of attribute reminder_intents.

Returns:

  • (Object)


269
270
271
# File 'lib/solid_objects/actor.rb', line 269

def reminder_intents
  @reminder_intents
end

#stateObject (readonly)

RBS:

  • @actor_id: String

  • @state: State

  • @effect_intents: Array[EffectIntent]

  • @reminder_intents: Array[ReminderIntent]

  • @outbound_message_intents: Array[OutboundMessageIntent]

Returns:

  • (Object)


137
138
139
# File 'lib/solid_objects/actor.rb', line 137

def state
  @state
end

Class Method Details

.actor_type(value = nil) ⇒ String

RBS:

  • (?String | Symbol) -> String

Parameters:

  • (String, Symbol)

Returns:

  • (String)


18
19
20
21
22
23
24
25
# File 'lib/solid_objects/actor.rb', line 18

def actor_type(value = nil)
  if value
    @actor_type = value.to_s
    SolidObjects.register_actor(@actor_type, self)
  end

  @actor_type ||= default_actor_type
end

.attribute(name, default: nil) ⇒ StateDefinition::Attribute

RBS:

  • (Symbol | String, ?default: untyped) -> StateDefinition::Attribute

Parameters:

  • (Symbol, String)
  • default: (Object) (defaults to: nil)

Returns:



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/solid_objects/actor.rb', line 28

def attribute(name, default: nil)
  attribute_name = name.to_sym
  ensure_attribute_methods_available!(attribute_name)
  attribute = definition.add_attribute(attribute_name, default:)
  @defining_attribute_methods = true
  begin
    define_method(attribute_name) { state.fetch(attribute_name) }
    define_method(:"#{attribute_name}=") { |value| state.write(attribute_name, value) }
    generated_attribute_methods[attribute_name] = true
    generated_attribute_methods[:"#{attribute_name}="] = true
  ensure
    @defining_attribute_methods = false
  end
  attribute
end

.definitionActorDefinition

RBS:

  • () -> ActorDefinition

Returns:



89
90
91
# File 'lib/solid_objects/actor.rb', line 89

def definition
  (@definition ||= ActorDefinition.new).synchronize_instance_messages(self)
end

.ensure_registered!Class

RBS:

  • () -> Class

Returns:

  • (Class)


94
95
96
# File 'lib/solid_objects/actor.rb', line 94

def ensure_registered!
  SolidObjects.register_actor(actor_type, self)
end

.inherited(subclass) ⇒ void

This method returns an undefined value.

RBS:

  • (Class) -> void

Parameters:

  • (Class)


11
12
13
14
15
# File 'lib/solid_objects/actor.rb', line 11

def inherited(subclass)
  super
  subclass.instance_variable_set(:@definition, definition.duplicate)
  subclass.instance_variable_set(:@generated_attribute_methods, generated_attribute_methods.dup)
end

.message(name) {|arg0, arg1| ... } ⇒ ActorDefinition::Handler

RBS:

  • (Symbol | String) { (*untyped, **untyped) -> untyped } -> ActorDefinition::Handler

Parameters:

  • (Symbol, String)

Yields:

Yield Parameters:

  • arg0 (Object)
  • arg1 (Object)

Yield Returns:

  • (Object)

Returns:



45
46
47
# File 'lib/solid_objects/actor.rb', line 45

def message(name, &block)
  definition.add_message(name, block)
end

.migrate_state(from:, to:) {|arg0| ... } ⇒ ActorDefinition::StateMigration

RBS:

  • (from: Integer, to: Integer) { (Hash[String, untyped]) -> Hash[String, untyped] } -> ActorDefinition::StateMigration

Parameters:

  • from: (Integer)
  • to: (Integer)

Yields:

Yield Parameters:

  • arg0 (Hash[String, untyped])

Yield Returns:

  • (Hash[String, untyped])

Returns:



66
67
68
# File 'lib/solid_objects/actor.rb', line 66

def migrate_state(from:, to:, &block)
  definition.add_state_migration(from, to, block)
end

.observable(name, &block) ⇒ void

This method returns an undefined value.

RBS:

  • (Symbol | String) ?{ () -> untyped } -> ActorDefinition::Handler

Parameters:

  • (Symbol, String)


55
56
57
# File 'lib/solid_objects/actor.rb', line 55

def observable(name, &block)
  definition.add_observable(name, block)
end

.on_activate { ... } ⇒ Proc

RBS:

  • () { () -> untyped } -> Proc

Yields:

Yield Returns:

  • (Object)

Returns:

  • (Proc)


71
72
73
74
# File 'lib/solid_objects/actor.rb', line 71

def on_activate(&block)
  definition.activation_hooks << block
  block
end

.on_deactivate { ... } ⇒ Proc

RBS:

  • () { () -> untyped } -> Proc

Yields:

Yield Returns:

  • (Object)

Returns:

  • (Proc)


77
78
79
80
# File 'lib/solid_objects/actor.rb', line 77

def on_deactivate(&block)
  definition.deactivation_hooks << block
  block
end

.query(name) {|arg0, arg1| ... } ⇒ ActorDefinition::Handler

RBS:

  • (Symbol | String) { (*untyped, **untyped) -> untyped } -> ActorDefinition::Handler

Parameters:

  • (Symbol, String)

Yields:

Yield Parameters:

  • arg0 (Object)
  • arg1 (Object)

Yield Returns:

  • (Object)

Returns:



50
51
52
# File 'lib/solid_objects/actor.rb', line 50

def query(name, &block)
  definition.add_query(name, block)
end

.ref(actor_id) ⇒ Reference

RBS:

  • (String | Integer) -> Reference

Parameters:

  • (String, Integer)

Returns:



83
84
85
86
# File 'lib/solid_objects/actor.rb', line 83

def ref(actor_id)
  ensure_registered!
  Reference.new(actor_type:, actor_id: actor_id.to_s)
end

.state_version(version = nil) ⇒ Integer

RBS:

  • (?Integer) -> Integer

Parameters:

  • (Integer)

Returns:

  • (Integer)


60
61
62
63
# File 'lib/solid_objects/actor.rb', line 60

def state_version(version = nil)
  definition.set_state_version(version) if version
  definition.state_version
end

Instance Method Details

#activatevoid

This method returns an undefined value.

RBS:

  • () -> void



224
225
226
# File 'lib/solid_objects/actor.rb', line 224

def activate
  self.class.definition.activation_hooks.each { |hook| instance_exec(&hook) }
end

#current_messageMessageContext?

RBS:

  • () -> MessageContext?

Returns:



149
150
151
# File 'lib/solid_objects/actor.rb', line 149

def current_message
  Context.current_message
end

#deactivatevoid

This method returns an undefined value.

RBS:

  • () -> void



229
230
231
# File 'lib/solid_objects/actor.rb', line 229

def deactivate
  self.class.definition.deactivation_hooks.each { |hook| instance_exec(&hook) }
end

#discard_intentsvoid

This method returns an undefined value.

RBS:

  • () -> void



261
262
263
264
265
# File 'lib/solid_objects/actor.rb', line 261

def discard_intents
  effect_intents.clear
  reminder_intents.clear
  outbound_message_intents.clear
end

#drain_effect_intentsArray[EffectIntent]

RBS:

  • () -> Array[EffectIntent]

Returns:



246
247
248
# File 'lib/solid_objects/actor.rb', line 246

def drain_effect_intents
  effect_intents.shift(effect_intents.length)
end

#drain_outbound_message_intentsArray[OutboundMessageIntent]

RBS:

  • () -> Array[OutboundMessageIntent]

Returns:



256
257
258
# File 'lib/solid_objects/actor.rb', line 256

def drain_outbound_message_intents
  outbound_message_intents.shift(outbound_message_intents.length)
end

#drain_reminder_intentsArray[ReminderIntent]

RBS:

  • () -> Array[ReminderIntent]

Returns:



251
252
253
# File 'lib/solid_objects/actor.rb', line 251

def drain_reminder_intents
  reminder_intents.shift(reminder_intents.length)
end

#emit(name, on_success: nil, on_failure: nil, **arguments) ⇒ nil

RBS:

  • (Symbol | String, ?on_success: Symbol | String?, ?on_failure: Symbol | String?, **untyped) -> nil

Parameters:

  • (Symbol, String)
  • on_success: (Symbol, String, nil) (defaults to: nil)
  • on_failure: (Symbol, String, nil) (defaults to: nil)
  • (Object)

Returns:

  • (nil)


164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/solid_objects/actor.rb', line 164

def emit(name, on_success: nil, on_failure: nil, **arguments)
  validate_effect_callback!(on_success)
  validate_effect_callback!(on_failure)
  EffectIntent.new(
    name: name.to_s,
    arguments: Serialization.dump(arguments),
    success_message_name: on_success&.to_s,
    failure_message_name: on_failure&.to_s
  ).tap do |intent|
    effect_intents << intent
  end
  nil
end

#invoke(message_name, arguments) ⇒ Object

RBS:

  • (Symbol | String, Hash[String, untyped]) -> untyped

Parameters:

  • (Symbol, String)
  • (Hash[String, untyped])

Returns:

  • (Object)


208
209
210
211
212
213
214
# File 'lib/solid_objects/actor.rb', line 208

def invoke(message_name, arguments)
  handler = self.class.definition.messages[message_name.to_sym] ||
    self.class.definition.queries[message_name.to_sym]
  raise UnknownMessage, "unknown message #{message_name.inspect} for #{self.class.actor_type}" unless handler

  instance_exec(**keyword_arguments(arguments), &handler.block)
end

#keyword_arguments(arguments) ⇒ Hash[Symbol, untyped]

RBS:

  • (Hash[String, untyped]) -> Hash[Symbol, untyped]

Parameters:

  • (Hash[String, untyped])

Returns:

  • (Hash[Symbol, untyped])


272
273
274
# File 'lib/solid_objects/actor.rb', line 272

def keyword_arguments(arguments)
  arguments.each_with_object({}) { |(key, value), converted| converted[key.to_sym] = value }
end

#observable_valuesHash[String, untyped]

RBS:

  • () -> Hash[String, untyped]

Returns:

  • (Hash[String, untyped])


217
218
219
220
221
# File 'lib/solid_objects/actor.rb', line 217

def observable_values
  self.class.definition.observables.each_with_object({}) do |(name, handler), values|
    values[name.to_s] = Serialization.dump(instance_exec(&handler.block))
  end
end

#reject(code, message, details: {}) ⇒ bot

RBS:

  • (Symbol | String, String, ?details: Hash[String | Symbol, untyped]) -> bot

Parameters:

  • (Symbol, String)
  • (String)
  • details: (Hash[String | Symbol, untyped]) (defaults to: {})

Returns:

  • (bot)


154
155
156
157
158
159
160
161
# File 'lib/solid_objects/actor.rb', line 154

def reject(code, message, details: {})
  rejection_code = code.to_s
  unless rejection_code.match?(/\A[a-z][a-z0-9_]*\z/)
    raise ArgumentError, "rejection code must contain lowercase letters, digits, and underscores"
  end

  raise Rejected.new(code: rejection_code, message:, details:)
end

#schedule(name, at:, every: nil, missed: :latest, arguments: {}) ⇒ nil

RBS:

  • (Symbol | String, at: Time, ?every: Numeric?, ?missed: Symbol | String, arguments: Hash[Symbol | String, untyped]) -> nil

Parameters:

  • (Symbol, String)
  • at: (Time)
  • arguments: (Hash[Symbol | String, untyped]) (defaults to: {})
  • every: (Numeric, nil) (defaults to: nil)
  • missed: (Symbol, String) (defaults to: :latest)

Returns:

  • (nil)


179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/solid_objects/actor.rb', line 179

def schedule(name, at:, every: nil, missed: :latest, arguments: {})
  interval_seconds = every&.to_f
  if interval_seconds && !interval_seconds.positive?
    raise ArgumentError, "reminder interval must be positive"
  end
  missed_policy = missed.to_s
  unless %w[all latest].include?(missed_policy)
    raise ArgumentError, "missed reminder policy must be all or latest"
  end

  ReminderIntent.new(
    name: name.to_s,
    at:,
    arguments: Serialization.dump(arguments),
    interval_seconds:,
    missed_policy:
  ).tap do |intent|
    reminder_intents << intent
  end
  nil
end

#send_to(reference, message_name, available_at: nil, idempotency_key: nil, **arguments) ⇒ nil

RBS:

  • (Reference, Symbol | String, ?available_at: Time?, ?idempotency_key: String?, **untyped) -> nil

Parameters:

  • (Reference)
  • (Symbol, String)
  • available_at: (Time, nil) (defaults to: nil)
  • idempotency_key: (String, nil) (defaults to: nil)
  • (Object)

Returns:

  • (nil)


202
203
204
205
# File 'lib/solid_objects/actor.rb', line 202

def send_to(reference, message_name, available_at: nil, idempotency_key: nil, **arguments)
  stage_outbound_message(reference, message_name, arguments, available_at:, idempotency_key:)
  nil
end

#stage_outbound_message(reference, message_name, arguments, available_at: nil, idempotency_key: nil) ⇒ OutboundMessageIntent

RBS:

  • (Reference, Symbol | String, Hash[Symbol | String, untyped], ?available_at: Time?, idempotency_key: String?) -> OutboundMessageIntent

Parameters:

  • (Reference)
  • (Symbol, String)
  • (Hash[Symbol | String, untyped])
  • idempotency_key: (String, nil) (defaults to: nil)
  • available_at: (Time, nil) (defaults to: nil)

Returns:



234
235
236
237
238
239
240
241
242
243
# File 'lib/solid_objects/actor.rb', line 234

def stage_outbound_message(reference, message_name, arguments, available_at: nil, idempotency_key: nil)
  OutboundMessageIntent.new(
    actor_type: reference.actor_type,
    actor_id: reference.actor_id,
    message_name: message_name.to_s,
    arguments: Serialization.dump(arguments),
    available_at:,
    idempotency_key:
  ).tap { |intent| outbound_message_intents << intent }
end

#validate_effect_callback!(message_name) ⇒ void

This method returns an undefined value.

RBS:

  • (Symbol | String?) -> void

Parameters:

  • (Symbol, String, nil)


277
278
279
280
281
282
# File 'lib/solid_objects/actor.rb', line 277

def validate_effect_callback!(message_name)
  return unless message_name
  return if self.class.definition.messages.key?(message_name.to_sym)

  raise UnknownMessage, "unknown effect callback message #{message_name.inspect}"
end