Class: CMDx::Middlewares
- Inherits:
-
Object
- Object
- CMDx::Middlewares
- Defined in:
- lib/cmdx/middlewares.rb
Overview
Ordered list of middlewares wrapping a task’s lifecycle. Each middleware is a callable with the signature ‘call(task) { next_link.call }`; Runtime builds a nested chain and requires each middleware to yield to the next.
Instance Attribute Summary collapse
-
#registry ⇒ Object
readonly
Returns the value of attribute registry.
Instance Method Summary collapse
-
#deregister(middleware = nil, at: nil) ⇒ Middlewares
Removes a middleware by reference or by index.
- #empty? ⇒ Boolean
-
#initialize ⇒ Middlewares
constructor
A new instance of Middlewares.
- #initialize_copy(source) ⇒ void
-
#process(task) { ... } ⇒ void
Walks the middleware chain around ‘task`’s lifecycle.
-
#register(callable = nil, **options, &block) { ... } ⇒ Middlewares
Inserts a middleware.
- #size ⇒ Integer
Constructor Details
#initialize ⇒ Middlewares
Returns a new instance of Middlewares.
11 12 13 |
# File 'lib/cmdx/middlewares.rb', line 11 def initialize @registry = [] end |
Instance Attribute Details
#registry ⇒ Object (readonly)
Returns the value of attribute registry.
9 10 11 |
# File 'lib/cmdx/middlewares.rb', line 9 def registry @registry end |
Instance Method Details
#deregister(middleware = nil, at: nil) ⇒ Middlewares
Removes a middleware by reference or by index.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/cmdx/middlewares.rb', line 71 def deregister(middleware = nil, at: nil) if at.nil? && middleware.nil? raise ArgumentError, "middleware: provide either a middleware or an at: index" elsif !at.nil? && !middleware.nil? raise ArgumentError, "middleware: provide either a middleware or an at: index, not both" elsif !at.nil? && !at.is_a?(Integer) raise ArgumentError, <<~MSG.chomp middleware :at must be an Integer (got #{at.class}). See https://drexed.github.io/cmdx/middlewares/#ordering MSG end if at.nil? registry.reject! { |mw, _opts| mw == middleware } else registry.delete_at(at) end self end |
#empty? ⇒ Boolean
93 94 95 |
# File 'lib/cmdx/middlewares.rb', line 93 def empty? registry.empty? end |
#initialize_copy(source) ⇒ void
This method returns an undefined value.
17 18 19 |
# File 'lib/cmdx/middlewares.rb', line 17 def initialize_copy(source) @registry = source.registry.dup end |
#process(task) { ... } ⇒ void
This method returns an undefined value.
Walks the middleware chain around ‘task`’s lifecycle. The final link yields to ‘block`, which is expected to run the actual lifecycle.
Built as an iterative reverse-reduce (matching Callbacks#around), avoiding the per-link recursive lambda invocation of the previous implementation while preserving identical semantics.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/cmdx/middlewares.rb', line 114 def process(task) processed = false last_invoked = nil innermost = lambda do processed = true yield end chain = registry.reverse_each.reduce(innermost) do |succ, (mw, opts)| lambda do next succ.call unless Util.satisfied?(opts[:if], opts[:unless], task) last_invoked = mw mw.call(task) { succ.call } end end chain.call processed || begin offender = last_invoked.is_a?(Class) ? last_invoked : last_invoked.class raise MiddlewareError, <<~MSG.chomp middleware #{offender} did not yield to next_link. See https://drexed.github.io/cmdx/middlewares/#safety MSG end end |
#register(callable = nil, **options, &block) { ... } ⇒ Middlewares
Inserts a middleware. With no ‘:at`, appends. With `:at`, inserts at the given (clamped) index — supports negative indexing. `:if`/`:unless` gates evaluated against the task at process time.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/cmdx/middlewares.rb', line 35 def register(callable = nil, **, &block) middleware = callable || block at = .delete(:at) if callable && block raise ArgumentError, "middleware: provide either a callable or a block, not both" elsif !middleware.respond_to?(:call) raise ArgumentError, <<~MSG.chomp middleware must respond to #call (got #{middleware.class}). See https://drexed.github.io/cmdx/middlewares/#signature MSG elsif !at.nil? && !at.is_a?(Integer) raise ArgumentError, <<~MSG.chomp middleware :at must be an Integer (got #{at.class}). See https://drexed.github.io/cmdx/middlewares/#ordering MSG end entry = [middleware, .freeze] if at.nil? registry << entry else registry.insert(at.clamp(-registry.size - 1, registry.size), entry) end self end |
#size ⇒ Integer
98 99 100 |
# File 'lib/cmdx/middlewares.rb', line 98 def size registry.size end |