Skip to content

Commit ee11a9c

Browse files
Remove Utopia context state
Assisted-By: devx/166ed168-1c4d-4c63-a5f6-8d0d9cbff13f
1 parent 9ab5abf commit ee11a9c

20 files changed

Lines changed: 154 additions & 185 deletions

File tree

‎lib/utopia/application.rb‎

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@
66
require "protocol/http/middleware"
77
require "protocol/http/middleware/builder"
88

9-
require_relative "context"
109
require_relative "request"
1110
require_relative "response"
1211

1312
module Utopia
1413
# The protocol-facing entrypoint for a Utopia application.
1514
#
16-
# This object accepts {Protocol::HTTP::Request} instances, installs the
17-
# request-scoped Utopia fiber state, dispatches to the Utopia application
18-
# stack, and normalizes the result back to a {Protocol::HTTP::Response}.
15+
# This object accepts {Protocol::HTTP::Request} instances, dispatches to the
16+
# Utopia application stack, and normalizes the result back to a
17+
# {Protocol::HTTP::Response}.
1918
class Application < Protocol::HTTP::Middleware
2019
CONFIGURATION_PATH = "config/application.rb".freeze
2120

@@ -82,13 +81,7 @@ def initialize(delegate)
8281
# @parameter http_request [Protocol::HTTP::Request] The incoming protocol request.
8382
# @returns [Protocol::HTTP::Response] The normalized protocol response.
8483
def call(http_request)
85-
Context.clear
86-
87-
Context.with(request: http_request, request_path: http_request.path_info) do
88-
return Response.wrap(super(http_request))
89-
end
90-
ensure
91-
Context.clear
84+
return Response.wrap(super(http_request))
9285
end
9386
end
9487
end

‎lib/utopia/content/document.rb‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
require_relative "response"
88
require_relative "markup"
99
require_relative "builder"
10-
require_relative "../context"
1110

1211
module Utopia
1312
module Content
@@ -42,7 +41,7 @@ def initialize(request, attributes = {})
4241

4342
# @returns [Path] The original request path, if known.
4443
def request_path
45-
Path[Context.request_path || request.path_info]
44+
Path[request.request_path]
4645
end
4746

4847
protected def current_base_uri_path

‎lib/utopia/content/middleware.rb‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
# Copyright, 2025-2026, by Samuel Williams.
55

66
require_relative "../middleware"
7-
require_relative "../context"
87
require_relative "../localization"
98
require_relative "../response"
9+
require_relative "../controller/variables"
1010

1111
require_relative "links"
1212
require_relative "node"
@@ -94,7 +94,7 @@ def resolve_link(link)
9494

9595
def respond(link, request)
9696
if node = resolve_link(link)
97-
attributes = Context.variables&.to_hash || {}
97+
attributes = Controller.current&.to_hash || {}
9898

9999
return node.process!(request, attributes)
100100
elsif redirect_uri = link[:uri]
@@ -116,7 +116,7 @@ def call(request)
116116
return Utopia::Response[307, {HTTP::LOCATION => path.dirname.join(index_path).to_s}, []]
117117
end
118118

119-
locale = Context.current_locale
119+
locale = Localization.current_locale
120120
if link = @links.for(path, locale)
121121
if response = self.respond(link, request)
122122
return response

‎lib/utopia/context.rb‎

Lines changed: 0 additions & 70 deletions
This file was deleted.

‎lib/utopia/controller/middleware.rb‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
require_relative "../path"
77
require_relative "../middleware"
8-
require_relative "../context"
98

109
require_relative "variables"
1110
require_relative "base"
@@ -92,7 +91,7 @@ def invoke_controllers(request)
9291
controller_path = Path.new
9392

9493
# Controller instance variables which eventually get processed by the view:
95-
variables = Context.variables
94+
variables = Controller.current
9695

9796
while request_path.components.any?
9897
# We copy one path component from the relative path to the controller path at a time. The controller, when invoked, can modify the relative path (by assigning to relative_path.components). This allows for controller-relative rewrites, but only the remaining path postfix can be modified.
@@ -119,13 +118,17 @@ def invoke_controllers(request)
119118
end
120119

121120
def call(request)
122-
Context.variables ||= Variables.new
121+
previous_variables = Controller.current
122+
123+
Controller.current ||= Variables.new
123124

124125
if result = invoke_controllers(request)
125126
return result
126127
end
127128

128129
return @app.call(request)
130+
ensure
131+
Controller.current = previous_variables
129132
end
130133
end
131134
end

‎lib/utopia/controller/variables.rb‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
# Copyright, 2014-2025, by Samuel Williams.
55

66
require_relative "../middleware"
7-
require_relative "../context"
87

98
module Utopia
109
module Controller
10+
CURRENT_KEY = :utopia_variables
11+
1112
# Provides a stack-based instance variable lookup mechanism. It can flatten a stack of controllers into a single hash.
1213
class Variables
1314
def initialize
@@ -66,7 +67,11 @@ def [] key
6667
end
6768

6869
def self.current
69-
Context.variables
70+
Fiber[CURRENT_KEY]
71+
end
72+
73+
def self.current= variables
74+
Fiber[CURRENT_KEY] = variables
7075
end
7176

7277
def self.[] request = nil

‎lib/utopia/exceptions/handler.rb‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,23 @@
66

77
require "console"
88

9-
require_relative "../context"
109
require_relative "../middleware"
1110
require_relative "../response"
1211

1312
module Utopia
1413
module Exceptions
14+
CURRENT_KEY = :utopia_exception
15+
16+
# The exception currently being handled.
17+
def self.current
18+
Fiber[CURRENT_KEY]
19+
end
20+
21+
# Assign the exception currently being handled.
22+
def self.current= exception
23+
Fiber[CURRENT_KEY] = exception
24+
end
25+
1526
# A middleware which catches exceptions and performs an internal redirect.
1627
class Handler
1728
# @param location [String] Peform an internal redirect to this location when an exception is raised.
@@ -42,8 +53,14 @@ def call(request)
4253
path_info: @location
4354
)
4455

45-
error_response = Context.with(request: error_request, exception: exception) do
46-
Response.wrap(@app.call(error_request))
56+
previous_exception = Exceptions.current
57+
58+
begin
59+
Exceptions.current = exception
60+
61+
error_response = Response.wrap(@app.call(error_request))
62+
ensure
63+
Exceptions.current = previous_exception
4764
end
4865
error_response.status = 500
4966

‎lib/utopia/exceptions/mailer.rb‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
require "net/smtp"
77
require "mail"
88

9-
require_relative "../context"
109
require_relative "../middleware"
10+
require_relative "../session"
11+
require_relative "../controller/variables"
12+
require_relative "../localization"
13+
require_relative "handler"
1114

1215
module Utopia
1316
module Exceptions
@@ -130,8 +133,8 @@ def generate_body(exception, request)
130133
io.puts "header[#{key.inspect}]: #{value.inspect}"
131134
end
132135

133-
Context.to_hash.each do |key, value|
134-
io.puts "context.#{key}: #{value.inspect}"
136+
self.current_state.each do |key, value|
137+
io.puts "state.#{key}: #{value.inspect}"
135138
end
136139

137140
io.puts
@@ -164,7 +167,7 @@ def generate_mail(exception, request)
164167
end
165168

166169
if @dump_environment
167-
mail.attachments["context.yaml"] = YAML.dump(Context.to_hash)
170+
mail.attachments["state.yaml"] = YAML.dump(self.current_state)
168171
end
169172

170173
return mail
@@ -181,6 +184,16 @@ def send_notification(exception, request)
181184
$stderr.puts mail_exception.backtrace
182185
end
183186

187+
def current_state
188+
{
189+
session: Session.current,
190+
variables: Controller.current,
191+
localization: Localization.current,
192+
current_locale: Localization.current_locale,
193+
exception: Exceptions.current,
194+
}
195+
end
196+
184197
def extract_body(request)
185198
request.body&.read
186199
end

‎lib/utopia/localization/middleware.rb‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# Copyright, 2025-2026, by Samuel Williams.
55

66
require_relative "wrapper"
7-
require_relative "../context"
87
require_relative "../middleware"
98
require_relative "../response"
109

@@ -143,7 +142,7 @@ def vary(request, response)
143142
headers.add("vary", "Accept-Language")
144143

145144
# Althought this header is generally not supported, we supply it anyway as it is useful for debugging:
146-
if locale = Context.current_locale
145+
if locale = Localization.current_locale
147146
# Set the Content-Location to point to the localized URI as requested:
148147
headers["content-location"] = "/#{locale}" + request.path_info
149148
end
@@ -161,8 +160,17 @@ def call(request)
161160
preferred_locales(request) do |localized_request, locale|
162161
# puts "Trying locale: #{locale}: #{localized_request.path_info}..."
163162

164-
response = Context.with(request: localized_request, localization: self, current_locale: locale) do
165-
Response.wrap(@app.call(localized_request))
163+
previous_localization = Localization.current
164+
previous_locale = Localization.current_locale
165+
166+
begin
167+
Localization.current = self
168+
Localization.current_locale = locale
169+
170+
response = Response.wrap(@app.call(localized_request))
171+
ensure
172+
Localization.current = previous_localization
173+
Localization.current_locale = previous_locale
166174
end
167175

168176
break unless response.status >= 400

0 commit comments

Comments
 (0)