Module: Phronomy::WorkflowContext
- Defined in:
- lib/phronomy/workflow_context.rb
Overview
Module for defining workflow context (the data that travels through a workflow). Include in a class and use the field DSL to declare context fields.
In StateChart terminology this is the "extended state" or "context" — data associated with the current execution that does not affect transitions directly, as opposed to the current phase (which is the machine's state).
Field update policies: :replace (default) -- overwrites with the new value :append -- appends to an Array :merge -- shallow-merges into a Hash (top-level keys are merged; nested objects are replaced)
Defined Under Namespace
Modules: ClassMethods
Instance Attribute Summary collapse
-
#thread_id ⇒ Object
readonly
Internal workflow metadata accessors (not user-defined fields).
Class Method Summary collapse
Instance Method Summary collapse
-
#halted? ⇒ Boolean
Returns true if the workflow is paused mid-execution (not yet completed).
-
#initialize(**attrs) ⇒ Object
mutant:disable - multiple genuine equivalent mutations: is_a?(Proc) vs instance_of?(Proc) (Proc has no subclasses in practice), config[]/fetch() for always-present :default key, @thread_id=nil removal (unset ivar is already nil), @phase=:end → nil or removal (phase method returns :end via @phase||:end fallback), raise message #inspect vs #{} (spec checks exception class not message text).
-
#merge(updates) ⇒ self.class
Returns a new context instance with the specified field updates applied.
-
#phase ⇒ Symbol
Returns the current execution phase of the workflow.
-
#set_graph_metadata(thread_id: nil, phase: nil) ⇒ Object
Sets internal workflow metadata.
-
#to_h ⇒ Hash
Converts user-defined fields to a Hash (excludes internal workflow metadata).
Instance Attribute Details
#thread_id ⇒ Object (readonly)
Internal workflow metadata accessors (not user-defined fields). These are preserved through merge but excluded from to_h.
64 65 66 |
# File 'lib/phronomy/workflow_context.rb', line 64 def thread_id @thread_id end |
Class Method Details
.included(base) ⇒ Object
24 25 26 27 |
# File 'lib/phronomy/workflow_context.rb', line 24 def self.included(base) base.extend(ClassMethods) base.instance_variable_set(:@fields, {}) end |
Instance Method Details
#halted? ⇒ Boolean
Returns true if the workflow is paused mid-execution (not yet completed). mutant:disable - phase != :end vs !phase.eql?(:end) vs !phase.equal?(:end) are genuine equivalents for Symbol (Symbols are interned so == / eql? / equal? all behave identically)
82 83 84 |
# File 'lib/phronomy/workflow_context.rb', line 82 def halted? phase != :__end__ end |
#initialize(**attrs) ⇒ Object
mutant:disable - multiple genuine equivalent mutations: is_a?(Proc) vs instance_of?(Proc) (Proc has no subclasses in practice), config[]/fetch() for always-present :default key, @thread_id=nil removal (unset ivar is already nil), @phase=:end → nil or removal (phase method returns :end via @phase||:end fallback), raise message #inspect vs #{} (spec checks exception class not message text)
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/phronomy/workflow_context.rb', line 98 def initialize(**attrs) unknown = attrs.keys - self.class.fields.keys raise ArgumentError, "Unknown WorkflowContext field(s): #{unknown.inspect}" unless unknown.empty? self.class.fields.each do |name, config| default = config[:default].is_a?(Proc) ? config[:default].call : config[:default] # Bypass the write guard in initialize — ownership enforcement begins # after construction is complete. instance_variable_set(:"@#{name}", attrs.fetch(name, default)) end @thread_id = nil @phase = :__end__ end |
#merge(updates) ⇒ self.class
Returns a new context instance with the specified field updates applied. Updated fields follow the field's declared +:type+ semantics (:replace, :append, or :merge). Unchanged fields are deep-copied on a best-effort basis — objects that do not support +#dup+ (e.g. integers, frozen objects) are carried over by reference. Internal workflow metadata (thread_id, phase) is preserved. mutant:disable - multiple genuine equivalent mutations: send/public_send/send are identical (all field accessors are public), fields[]/fetch() and field_config[]/fetch() for always-present keys, updates[]/fetch() when updates.key?(name) is already true, Array() wrapping for append fields that always hold Arrays, (send||{})/send equivalence for merge fields that always hold Hashes, deep_dup_value(send) vs send are equivalent under killfork (coverage selection does not trace the deep_dup_value call site across the fork boundary), raise message inspect vs to_s (spec checks exception class only)
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/phronomy/workflow_context.rb', line 122 def merge(updates) unknown = updates.keys - self.class.fields.keys raise ArgumentError, "Unknown WorkflowContext field(s): #{unknown.inspect}" unless unknown.empty? new_attrs = {} self.class.fields.each_key do |name| field_config = self.class.fields[name] new_attrs[name] = if updates.key?(name) case field_config[:type] when :append Array(send(name)) + Array(updates[name]) when :merge (send(name) || {}).merge(updates[name]) else updates[name] end else deep_dup_value(send(name)) end end new_context = self.class.new(**new_attrs) new_context.( thread_id: @thread_id, phase: @phase ) new_context end |
#phase ⇒ Symbol
Returns the current execution phase of the workflow.
Encoding:
:end — workflow completed (or not yet started)
:awaiting_
74 75 76 |
# File 'lib/phronomy/workflow_context.rb', line 74 def phase @phase || :__end__ end |
#set_graph_metadata(thread_id: nil, phase: nil) ⇒ Object
Sets internal workflow metadata. Returns self.
mutant:disable - mutations replacing return value self with nil or removing the last line are genuine equivalents: callers chain on the return value only in merge which immediately discards it
91 92 93 94 95 |
# File 'lib/phronomy/workflow_context.rb', line 91 def (thread_id: nil, phase: nil) @thread_id = thread_id unless thread_id.nil? @phase = phase unless phase.nil? self end |
#to_h ⇒ Hash
Converts user-defined fields to a Hash (excludes internal workflow metadata). mutant:disable - send/public_send/send are genuine equivalents (all field accessors are public methods)
154 155 156 157 158 |
# File 'lib/phronomy/workflow_context.rb', line 154 def to_h self.class.fields.keys.each_with_object({}) do |name, h| h[name] = send(name) end end |