Class: Easyop::Ctx

Inherits:
Object
  • Object
show all
Defined in:
lib/easyop/ctx.rb

Overview

Easyop::Ctx is the shared data bag passed through an operation (or flow of operations). It replaces Interactor’s Context with a faster, Hash-backed implementation that avoids the deprecated OpenStruct.

It doubles as the result object returned from Operation.call — the caller inspects ctx.success? / ctx.failure? and reads output attributes directly.

Key API:

ctx.fail!                       # mark failed (raises Ctx::Failure internally)
ctx.fail!(error: "Boom!")        # set attrs AND fail
ctx.success? / ctx.ok?          # true unless fail! was called
ctx.failure? / ctx.failed?      # true after fail!
ctx.error                       # shortcut for ctx[:error]
ctx.errors                      # shortcut for ctx[:errors] ({} by default)
ctx[:key] / ctx.key             # attribute read
ctx[:key] = v / ctx.key = v     # attribute write
ctx.merge!(hash)                # bulk-set attributes
ctx.on_success { |ctx| ... }    # chainable callback
ctx.on_failure { |ctx| ... }    # chainable callback

Defined Under Namespace

Classes: Failure

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs = {}) ⇒ Ctx

Returns a new instance of Ctx.



40
41
42
43
44
45
46
# File 'lib/easyop/ctx.rb', line 40

def initialize(attrs = {})
  @attributes  = {}
  @failure     = false
  @rolled_back = false
  @called      = []   # interactors already run (for rollback)
  attrs.each { |k, v| self[k] = v }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

── Dynamic attribute access (method_missing) ─────────────────────────────



161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/easyop/ctx.rb', line 161

def method_missing(name, *args)
  key = name.to_s
  if key.end_with?("=")
    self[key.chomp("=")] = args.first
  elsif key.end_with?("?")
    base = key.chomp("?").to_sym
    return !!self[base]
  elsif @attributes.key?(name.to_sym)
    self[name]
  else
    super
  end
end

Class Method Details

.build(attrs = {}) ⇒ Object

── Construction ────────────────────────────────────────────────────────



35
36
37
38
# File 'lib/easyop/ctx.rb', line 35

def self.build(attrs = {})
  return attrs if attrs.is_a?(self)
  new(attrs)
end

Instance Method Details

#[](key) ⇒ Object

── Attribute access ─────────────────────────────────────────────────────



50
51
52
# File 'lib/easyop/ctx.rb', line 50

def [](key)
  @attributes[key.to_sym]
end

#[]=(key, val) ⇒ Object



54
55
56
# File 'lib/easyop/ctx.rb', line 54

def []=(key, val)
  @attributes[key.to_sym] = val
end

#called!(operation) ⇒ Object

Called by Flow to track which operations have run.



134
135
136
137
# File 'lib/easyop/ctx.rb', line 134

def called!(operation)
  @called << operation
  self
end

#deconstruct_keys(keys) ⇒ Object

Supports: case result; in { success: true, user: } …



152
153
154
155
156
157
# File 'lib/easyop/ctx.rb', line 152

def deconstruct_keys(keys)
  base = { success: success?, failure: failure? }
  base.merge(@attributes).then do |all|
    keys ? all.slice(*keys) : all
  end
end

#errorObject

── Error conveniences ───────────────────────────────────────────────────



103
104
105
# File 'lib/easyop/ctx.rb', line 103

def error
  self[:error]
end

#error=(msg) ⇒ Object



107
108
109
# File 'lib/easyop/ctx.rb', line 107

def error=(msg)
  self[:error] = msg
end

#errorsObject



111
112
113
# File 'lib/easyop/ctx.rb', line 111

def errors
  self[:errors] || {}
end

#errors=(hash) ⇒ Object



115
116
117
# File 'lib/easyop/ctx.rb', line 115

def errors=(hash)
  self[:errors] = hash
end

#fail!(attrs = {}) ⇒ Object

Mark the operation as failed. Accepts an optional hash of attributes to merge into ctx before raising (e.g. error:, errors:).

Raises:



95
96
97
98
99
# File 'lib/easyop/ctx.rb', line 95

def fail!(attrs = {})
  merge!(attrs)
  @failure = true
  raise Failure, self
end

#failure?Boolean Also known as: failed?

Returns:

  • (Boolean)


86
87
88
# File 'lib/easyop/ctx.rb', line 86

def failure?
  @failure
end

#inspectObject



182
183
184
185
# File 'lib/easyop/ctx.rb', line 182

def inspect
  status = @failure ? "FAILED" : "ok"
  "#<Easyop::Ctx #{@attributes.inspect} [#{status}]>"
end

#key?(key) ⇒ Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/easyop/ctx.rb', line 67

def key?(key)
  @attributes.key?(key.to_sym)
end

#merge!(attrs = {}) ⇒ Object



58
59
60
61
# File 'lib/easyop/ctx.rb', line 58

def merge!(attrs = {})
  attrs.each { |k, v| self[k] = v }
  self
end

#on_failure {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:

  • _self (Easyop::Ctx)

    the object that the method was called on



126
127
128
129
# File 'lib/easyop/ctx.rb', line 126

def on_failure
  yield self if failure?
  self
end

#on_success {|_self| ... } ⇒ Object

── Chainable result callbacks ────────────────────────────────────────────

Yields:

  • (_self)

Yield Parameters:

  • _self (Easyop::Ctx)

    the object that the method was called on



121
122
123
124
# File 'lib/easyop/ctx.rb', line 121

def on_success
  yield self if success?
  self
end

#respond_to_missing?(name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


175
176
177
178
179
180
# File 'lib/easyop/ctx.rb', line 175

def respond_to_missing?(name, include_private = false)
  key = name.to_s
  return true if key.end_with?("=")
  return true if key.end_with?("?")
  @attributes.key?(name.to_sym) || super
end

#rollback!Object

Roll back already-called operations in reverse order. Errors in individual rollbacks are swallowed to ensure all run.



141
142
143
144
145
146
147
# File 'lib/easyop/ctx.rb', line 141

def rollback!
  return if @rolled_back
  @rolled_back = true
  @called.reverse_each do |op|
    op.rollback rescue nil
  end
end

#slice(*keys) ⇒ Object

Returns a plain Hash with only the specified keys.



72
73
74
75
76
77
# File 'lib/easyop/ctx.rb', line 72

def slice(*keys)
  keys.each_with_object({}) do |k, h|
    sym = k.to_sym
    h[sym] = @attributes[sym] if @attributes.key?(sym)
  end
end

#success?Boolean Also known as: ok?

── Status ───────────────────────────────────────────────────────────────

Returns:

  • (Boolean)


81
82
83
# File 'lib/easyop/ctx.rb', line 81

def success?
  !@failure
end

#to_hObject



63
64
65
# File 'lib/easyop/ctx.rb', line 63

def to_h
  @attributes.dup
end