Class: Tina4::Middleware
- Inherits:
-
Object
- Object
- Tina4::Middleware
- Defined in:
- lib/tina4/middleware.rb
Class Method Summary collapse
- .after(pattern = nil, &block) ⇒ Object
- .after_handlers ⇒ Object
- .before(pattern = nil, &block) ⇒ Object
- .before_handlers ⇒ Object
- .clear! ⇒ Object
-
.get_global ⇒ Object
Parity alias matching Python/PHP/Node orchestrators.
-
.global_middleware ⇒ Object
Registry of class-based middleware (registered via Router.use).
-
.middleware_500(response, label, error) ⇒ Object
Deterministic clean 500 for a middleware that threw.
-
.run_after(middleware_classes, request, response) ⇒ Object
Run all “after” hooks: block-based handlers, then class-based after_* methods (in definition order).
-
.run_before(middleware_classes, request, response) ⇒ Object
Run all “before” hooks: block-based handlers, then class-based before_* methods (in definition order).
-
.use(klass) ⇒ Object
Register a class-based middleware globally.
Class Method Details
.after(pattern = nil, &block) ⇒ Object
28 29 30 |
# File 'lib/tina4/middleware.rb', line 28 def after(pattern = nil, &block) after_handlers << { pattern: pattern, handler: block } end |
.after_handlers ⇒ Object
10 11 12 |
# File 'lib/tina4/middleware.rb', line 10 def after_handlers @after_handlers ||= [] end |
.before(pattern = nil, &block) ⇒ Object
24 25 26 |
# File 'lib/tina4/middleware.rb', line 24 def before(pattern = nil, &block) before_handlers << { pattern: pattern, handler: block } end |
.before_handlers ⇒ Object
6 7 8 |
# File 'lib/tina4/middleware.rb', line 6 def before_handlers @before_handlers ||= [] end |
.clear! ⇒ Object
38 39 40 41 42 |
# File 'lib/tina4/middleware.rb', line 38 def clear! @before_handlers = [] @after_handlers = [] @global_middleware = [] end |
.get_global ⇒ Object
Parity alias matching Python/PHP/Node orchestrators.
20 21 22 |
# File 'lib/tina4/middleware.rb', line 20 def get_global global_middleware.dup end |
.global_middleware ⇒ Object
Registry of class-based middleware (registered via Router.use)
15 16 17 |
# File 'lib/tina4/middleware.rb', line 15 def global_middleware @global_middleware ||= [] end |
.middleware_500(response, label, error) ⇒ Object
Deterministic clean 500 for a middleware that threw. Logs the cause (NEVER silent) then sets the response to the canonical error shape —byte-identical to the Python master (Server Error”, “status”:500 + status 500). Returns the response for chaining.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/tina4/middleware.rb', line 143 def middleware_500(response, label, error) begin Tina4::Log.error( "Middleware #{label} raised #{error.class.name}: #{error.}" ) rescue StandardError begin $stderr.puts("Middleware #{label} raised #{error.class.name}: #{error.}") $stderr.flush rescue StandardError # never let logging break the worker end end response.json({ error: "Internal Server Error", status: 500 }, 500) end |
.run_after(middleware_classes, request, response) ⇒ Object
Run all “after” hooks: block-based handlers, then class-based after_* methods (in definition order).
Signature matches Python/PHP/Node orchestrators: pass the list of middleware classes explicitly.
AFTER-ON-4xx RULE (M2, documented + consistent across all 4 frameworks): after_* ALWAYS run even when a before_* short-circuited with status >= 400 and the handler was skipped — so they can still add headers / logging. The dispatcher calls #run_after unconditionally after the before/handler block (including on the 4xx / throw halt path).
M2 — every after_* call is wrapped: a THROW is LOGGED and turns the response into a clean 500, then the REMAINING after_* still run (they may add headers/logging). Never an unhandled crash.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/tina4/middleware.rb', line 111 def run_after(middleware_classes, request, response) # 1. Block-based after handlers (pattern-matched) after_handlers.each do |entry| next unless matches_pattern?(request.path, entry[:pattern]) begin entry[:handler].call(request, response) rescue StandardError, ScriptError => error middleware_500(response, "after handler", error) end end # 2. Class-based middleware: call every after_* method (definition order) middleware_classes.each do |klass| after_methods_for(klass).each do |method_name| begin result = klass.send(method_name, request, response) rescue StandardError, ScriptError => error middleware_500(response, "#{class_label(klass)}.#{method_name}", error) next end if result.is_a?(Array) && result.length == 2 request, response = result end end end end |
.run_before(middleware_classes, request, response) ⇒ Object
Run all “before” hooks: block-based handlers, then class-based before_* methods (in definition order).
Signature matches Python/PHP/Node orchestrators: pass the list of middleware classes explicitly.
M2 — visible-but-resilient: every before_* call is wrapped so a THROW never crashes the worker. On a throw the error is LOGGED and the response becomes a clean 500 (Server Error”, “status”:500), then processing halts (handler skipped) — deterministic, never an unhandled exception. A before_* that sets status >= 400 also halts (the existing 4xx short-circuit). after_* still run on either halt path (see the dispatcher / #run_after docstring).
Returns true on success, or false to halt the request (handler skipped).
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/tina4/middleware.rb', line 59 def run_before(middleware_classes, request, response) # 1. Block-based before handlers (pattern-matched) before_handlers.each do |entry| next unless matches_pattern?(request.path, entry[:pattern]) begin result = entry[:handler].call(request, response) rescue StandardError, ScriptError => error middleware_500(response, "before handler", error) return false end return false if result == false end # 2. Class-based middleware: call every before_* method (definition order) middleware_classes.each do |klass| before_methods_for(klass).each do |method_name| begin result = klass.send(method_name, request, response) rescue StandardError, ScriptError => error middleware_500(response, "#{class_label(klass)}.#{method_name}", error) return false end # Support returning [request, response] (Python convention) or false to halt if result == false return false elsif result.is_a?(Array) && result.length == 2 request, response = result # If response already has a non-2xx status, halt processing return false if response.status_code >= 400 end end end true end |
.use(klass) ⇒ Object
Register a class-based middleware globally. The class should define static before_* and/or after_* methods.
34 35 36 |
# File 'lib/tina4/middleware.rb', line 34 def use(klass) global_middleware << klass unless global_middleware.include?(klass) end |