utopia 2.24.4 → 2.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/bake/utopia/environment.rb +16 -12
  4. data/bake/utopia/node.rb +5 -5
  5. data/bake/utopia/server.rb +8 -8
  6. data/bake/utopia/shell.rb +3 -3
  7. data/bake/utopia/site.rb +16 -16
  8. data/bake/utopia/static.rb +8 -8
  9. data/bake/utopia.rb +4 -4
  10. data/lib/utopia/content/document.rb +4 -4
  11. data/lib/utopia/content/link.rb +10 -10
  12. data/lib/utopia/content/links.rb +5 -5
  13. data/lib/utopia/content/markup.rb +6 -6
  14. data/lib/utopia/content/node.rb +8 -8
  15. data/lib/utopia/content/response.rb +5 -5
  16. data/lib/utopia/content/tags.rb +8 -8
  17. data/lib/utopia/content.rb +18 -18
  18. data/lib/utopia/controller/actions.rb +5 -5
  19. data/lib/utopia/controller/base.rb +2 -2
  20. data/lib/utopia/controller/respond.rb +6 -6
  21. data/lib/utopia/controller/rewrite.rb +3 -3
  22. data/lib/utopia/controller.rb +10 -10
  23. data/lib/utopia/exceptions/handler.rb +3 -3
  24. data/lib/utopia/exceptions/mailer.rb +9 -9
  25. data/lib/utopia/exceptions.rb +3 -3
  26. data/lib/utopia/extensions/date_comparisons.rb +2 -2
  27. data/lib/utopia/http.rb +36 -36
  28. data/lib/utopia/locale.rb +3 -3
  29. data/lib/utopia/localization.rb +7 -7
  30. data/lib/utopia/middleware.rb +5 -5
  31. data/lib/utopia/path/matcher.rb +2 -2
  32. data/lib/utopia/path.rb +21 -21
  33. data/lib/utopia/redirection.rb +4 -4
  34. data/lib/utopia/responder.rb +2 -2
  35. data/lib/utopia/session/serialization.rb +4 -4
  36. data/lib/utopia/session.rb +8 -8
  37. data/lib/utopia/setup.rb +7 -7
  38. data/lib/utopia/shell.rb +5 -5
  39. data/lib/utopia/static/local_file.rb +8 -8
  40. data/lib/utopia/static/mime_types.rb +2 -2
  41. data/lib/utopia/static.rb +11 -11
  42. data/lib/utopia/version.rb +1 -1
  43. data/lib/utopia.rb +7 -8
  44. data/license.md +1 -1
  45. data/readme.md +1 -1
  46. data/setup/server/git/hooks/post-receive +10 -9
  47. data/setup/site/Guardfile +3 -2
  48. data/setup/site/bake.rb +3 -3
  49. data/setup/site/config/environment.rb +3 -3
  50. data/setup/site/config/sus.rb +3 -3
  51. data/setup/site/config.ru +8 -8
  52. data/setup/site/fixtures/website.rb +6 -6
  53. data/setup/site/gems.rb +13 -13
  54. data/setup/site/test/website.rb +3 -3
  55. data.tar.gz.sig +0 -0
  56. metadata +3 -9
  57. metadata.gz.sig +0 -0
  58. data/lib/utopia/content_length.rb +0 -33
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2014-2024, by Samuel Williams.
4
+ # Copyright, 2014-2025, by Samuel Williams.
5
5
 
6
- require_relative '../http'
6
+ require_relative "../http"
7
7
 
8
8
  module Utopia
9
9
  class Controller
@@ -45,10 +45,10 @@ module Utopia
45
45
  end
46
46
 
47
47
  # Matches 0 or more path components.
48
- WILDCARD_GREEDY = '**'.freeze
48
+ WILDCARD_GREEDY = "**".freeze
49
49
 
50
50
  # Matches any 1 path component.
51
- WILDCARD = '*'.freeze
51
+ WILDCARD = "*".freeze
52
52
 
53
53
  # Given a path, iterate over all actions that match. Actions match from most specific to most general.
54
54
  # @return nil if nothing matched, or true if something matched.
@@ -121,7 +121,7 @@ module Utopia
121
121
 
122
122
  def on(first, *path, **options, &block)
123
123
  if first.is_a? Symbol
124
- first = ['**', first.to_s]
124
+ first = ["**", first.to_s]
125
125
  end
126
126
 
127
127
  actions.define(Path.split(first) + path, **options, &block)
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2014-2022, by Samuel Williams.
4
+ # Copyright, 2014-2025, by Samuel Williams.
5
5
 
6
- require_relative '../http'
6
+ require_relative "../http"
7
7
 
8
8
  module Utopia
9
9
  class Controller
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2016-2022, by Samuel Williams.
4
+ # Copyright, 2016-2025, by Samuel Williams.
5
5
 
6
- require_relative '../http'
7
- require_relative '../responder'
6
+ require_relative "../http"
7
+ require_relative "../responder"
8
8
 
9
9
  module Utopia
10
10
  class Controller
@@ -16,14 +16,14 @@ module Utopia
16
16
 
17
17
  module Handlers
18
18
  module JSON
19
- APPLICATION_JSON = HTTP::Accept::ContentType.new('application', 'json').freeze
19
+ APPLICATION_JSON = HTTP::Accept::ContentType.new("application", "json").freeze
20
20
 
21
21
  def self.split(*arguments)
22
22
  APPLICATION_JSON.split(*arguments)
23
23
  end
24
24
 
25
25
  def self.call(context, request, media_range, object, **options)
26
- if version = media_range.parameters['version']
26
+ if version = media_range.parameters["version"]
27
27
  options[:version] = version.to_s
28
28
  end
29
29
 
@@ -32,7 +32,7 @@ module Utopia
32
32
  end
33
33
 
34
34
  module Passthrough
35
- WILDCARD = HTTP::Accept::MediaTypes::MediaRange.new('*', '*').freeze
35
+ WILDCARD = HTTP::Accept::MediaTypes::MediaRange.new("*", "*").freeze
36
36
 
37
37
  def self.split(*arguments)
38
38
  WILDCARD.split(*arguments)
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2015-2022, by Samuel Williams.
4
+ # Copyright, 2015-2025, by Samuel Williams.
5
5
 
6
- require_relative '../http'
7
- require_relative '../path/matcher'
6
+ require_relative "../http"
7
+ require_relative "../path/matcher"
8
8
 
9
9
  module Utopia
10
10
  class Controller
@@ -1,25 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2009-2022, by Samuel Williams.
4
+ # Copyright, 2009-2025, by Samuel Williams.
5
5
 
6
- require_relative 'path'
6
+ require_relative "path"
7
7
 
8
- require_relative 'middleware'
9
- require_relative 'controller/variables'
10
- require_relative 'controller/base'
8
+ require_relative "middleware"
9
+ require_relative "controller/variables"
10
+ require_relative "controller/base"
11
11
 
12
- require_relative 'controller/rewrite'
13
- require_relative 'controller/respond'
14
- require_relative 'controller/actions'
12
+ require_relative "controller/rewrite"
13
+ require_relative "controller/respond"
14
+ require_relative "controller/actions"
15
15
 
16
- require 'concurrent/map'
16
+ require "concurrent/map"
17
17
 
18
18
  module Utopia
19
19
  # A middleware which loads controller classes and invokes functionality based on the requested path.
20
20
  class Controller
21
21
  # The controller filename.
22
- CONTROLLER_RB = 'controller.rb'.freeze
22
+ CONTROLLER_RB = "controller.rb".freeze
23
23
 
24
24
  def self.[] request
25
25
  request.env[VARIABLES_KEY]
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2014-2022, by Samuel Williams.
4
+ # Copyright, 2014-2025, by Samuel Williams.
5
5
 
6
6
  module Utopia
7
7
  module Exceptions
8
8
  # A middleware which catches exceptions and performs an internal redirect.
9
9
  class Handler
10
10
  # @param location [String] Peform an internal redirect to this location when an exception is raised.
11
- def initialize(app, location = '/errors/exception')
11
+ def initialize(app, location = "/errors/exception")
12
12
  @app = app
13
13
 
14
14
  @location = location
@@ -34,7 +34,7 @@ module Utopia
34
34
 
35
35
  def log_exception(env, exception)
36
36
  # An error has occurred, log it:
37
- output = env['rack.errors'] || $stderr
37
+ output = env["rack.errors"] || $stderr
38
38
  write_exception_to_stream(output, env, exception, true)
39
39
  end
40
40
 
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2016-2022, by Samuel Williams.
4
+ # Copyright, 2016-2025, by Samuel Williams.
5
5
 
6
- require 'net/smtp'
7
- require 'mail'
6
+ require "net/smtp"
7
+ require "mail"
8
8
 
9
9
  module Utopia
10
10
  module Exceptions
@@ -17,8 +17,8 @@ module Utopia
17
17
  :enable_starttls_auto => false
18
18
  }]
19
19
 
20
- DEFAULT_FROM = (ENV['USER'] || 'utopia').freeze
21
- DEFAULT_SUBJECT = '%{exception} [PID %{pid} : %{cwd}]'.freeze
20
+ DEFAULT_FROM = (ENV["USER"] || "utopia").freeze
21
+ DEFAULT_SUBJECT = "%{exception} [PID %{pid} : %{cwd}]".freeze
22
22
 
23
23
  # @param to [String] The address to email error reports to.
24
24
  # @param from [String] The from address for error reports.
@@ -104,7 +104,7 @@ module Utopia
104
104
 
105
105
  io.puts
106
106
 
107
- env.select{|key,_| key.start_with? 'HTTP_'}.each do |key, value|
107
+ env.select{|key,_| key.start_with? "HTTP_"}.each do |key, value|
108
108
  io.puts "#{key}: #{value.inspect}"
109
109
  end
110
110
 
@@ -134,11 +134,11 @@ module Utopia
134
134
  mail.text_part.body = generate_body(exception, env)
135
135
 
136
136
  if body = extract_body(env) and body.size > 0
137
- mail.attachments['body.bin'] = body
137
+ mail.attachments["body.bin"] = body
138
138
  end
139
139
 
140
140
  if @dump_environment
141
- mail.attachments['environment.yaml'] = YAML.dump(env)
141
+ mail.attachments["environment.yaml"] = YAML.dump(env)
142
142
  end
143
143
 
144
144
  return mail
@@ -156,7 +156,7 @@ module Utopia
156
156
  end
157
157
 
158
158
  def extract_body(env)
159
- if io = env['rack.input']
159
+ if io = env["rack.input"]
160
160
  io.rewind if io.respond_to?(:rewind)
161
161
  io.read
162
162
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2016-2022, by Samuel Williams.
4
+ # Copyright, 2016-2025, by Samuel Williams.
5
5
 
6
- require_relative 'exceptions/handler'
7
- require_relative 'exceptions/mailer'
6
+ require_relative "exceptions/handler"
7
+ require_relative "exceptions/mailer"
8
8
 
9
9
  module Utopia
10
10
  # Middleware for handling exceptional situations.
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2010-2022, by Samuel Williams.
4
+ # Copyright, 2010-2025, by Samuel Williams.
5
5
 
6
- require 'date'
6
+ require "date"
7
7
 
8
8
  module Utopia
9
9
  module Extensions
data/lib/utopia/http.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2010-2022, by Samuel Williams.
4
+ # Copyright, 2010-2025, by Samuel Williams.
5
5
 
6
- require 'rack'
6
+ require "rack"
7
7
 
8
- require 'http/accept'
8
+ require "http/accept"
9
9
 
10
10
  module Utopia
11
11
  # HTTP protocol implementation.
@@ -41,41 +41,41 @@ module Utopia
41
41
  # A list of human readable descriptions for a given status code.
42
42
  # For a more detailed description, see https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
43
43
  STATUS_DESCRIPTIONS = {
44
- 200 => 'OK'.freeze,
45
- 201 => 'Created'.freeze,
46
- 202 => 'Accepted'.freeze,
47
- 203 => 'Non-Authoritive Information'.freeze,
48
- 204 => 'No Content'.freeze,
49
- 205 => 'Reset Content'.freeze,
50
- 206 => 'Partial Content'.freeze,
51
- 300 => 'Multiple Choices'.freeze,
52
- 301 => 'Moved Permanently'.freeze,
53
- 302 => 'Found'.freeze,
54
- 303 => 'See Other'.freeze,
55
- 304 => 'Not Modified'.freeze,
56
- 305 => 'Use Proxy'.freeze,
57
- 307 => 'Temporary Redirect'.freeze,
58
- 308 => 'Permanent Redirect'.freeze,
59
- 400 => 'Bad Request'.freeze,
60
- 401 => 'Permission Denied'.freeze,
61
- 402 => 'Payment Required'.freeze,
62
- 403 => 'Access Forbidden'.freeze,
63
- 404 => 'Resource Not Found'.freeze,
64
- 405 => 'Unsupported Method'.freeze,
65
- 406 => 'Not Acceptable'.freeze,
66
- 408 => 'Request Timeout'.freeze,
67
- 409 => 'Request Conflict'.freeze,
68
- 410 => 'Resource Removed'.freeze,
69
- 416 => 'Byte range unsatisfiable'.freeze,
70
- 422 => 'Unprocessible Entity'.freeze,
71
- 500 => 'Internal Server Error'.freeze,
72
- 501 => 'Not Implemented'.freeze,
73
- 503 => 'Service Unavailable'.freeze
44
+ 200 => "OK".freeze,
45
+ 201 => "Created".freeze,
46
+ 202 => "Accepted".freeze,
47
+ 203 => "Non-Authoritive Information".freeze,
48
+ 204 => "No Content".freeze,
49
+ 205 => "Reset Content".freeze,
50
+ 206 => "Partial Content".freeze,
51
+ 300 => "Multiple Choices".freeze,
52
+ 301 => "Moved Permanently".freeze,
53
+ 302 => "Found".freeze,
54
+ 303 => "See Other".freeze,
55
+ 304 => "Not Modified".freeze,
56
+ 305 => "Use Proxy".freeze,
57
+ 307 => "Temporary Redirect".freeze,
58
+ 308 => "Permanent Redirect".freeze,
59
+ 400 => "Bad Request".freeze,
60
+ 401 => "Permission Denied".freeze,
61
+ 402 => "Payment Required".freeze,
62
+ 403 => "Access Forbidden".freeze,
63
+ 404 => "Resource Not Found".freeze,
64
+ 405 => "Unsupported Method".freeze,
65
+ 406 => "Not Acceptable".freeze,
66
+ 408 => "Request Timeout".freeze,
67
+ 409 => "Request Conflict".freeze,
68
+ 410 => "Resource Removed".freeze,
69
+ 416 => "Byte range unsatisfiable".freeze,
70
+ 422 => "Unprocessible Entity".freeze,
71
+ 500 => "Internal Server Error".freeze,
72
+ 501 => "Not Implemented".freeze,
73
+ 503 => "Service Unavailable".freeze
74
74
  }.merge(Rack::Utils::HTTP_STATUS_CODES)
75
75
 
76
- CONTENT_TYPE = 'content-type'.freeze
77
- LOCATION = 'location'.freeze
78
- CACHE_CONTROL = 'cache-control'.freeze
76
+ CONTENT_TYPE = "content-type".freeze
77
+ LOCATION = "location".freeze
78
+ CACHE_CONTROL = "cache-control".freeze
79
79
 
80
80
  # A small HTTP status wrapper that verifies the status code within a given range.
81
81
  class Status
data/lib/utopia/locale.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2015-2022, by Samuel Williams.
4
+ # Copyright, 2015-2025, by Samuel Williams.
5
5
 
6
6
  module Utopia
7
7
  # A structured representation of locale based on RFC3066.
8
8
  Locale = Struct.new(:language, :country, :variant) do
9
9
  def to_s
10
- to_a.compact.join('-')
10
+ to_a.compact.join("-")
11
11
  end
12
12
 
13
13
  def self.dump(instance)
@@ -18,7 +18,7 @@ module Utopia
18
18
 
19
19
  def self.load(instance)
20
20
  if instance.is_a? String
21
- self.new(*instance.split('-', 3))
21
+ self.new(*instance.split("-", 3))
22
22
  elsif instance.is_a? Array
23
23
  return self.new(*instance)
24
24
  elsif instance.is_a? self
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2009-2022, by Samuel Williams.
4
+ # Copyright, 2009-2025, by Samuel Williams.
5
5
 
6
- require_relative 'middleware'
6
+ require_relative "middleware"
7
7
 
8
8
  module Utopia
9
9
  # A middleware which attempts to find localized content.
@@ -48,9 +48,9 @@ module Utopia
48
48
 
49
49
  RESOURCE_NOT_FOUND = [400, {}, []].freeze
50
50
 
51
- HTTP_ACCEPT_LANGUAGE = 'HTTP_ACCEPT_LANGUAGE'.freeze
52
- LOCALIZATION_KEY = 'utopia.localization'.freeze
53
- CURRENT_LOCALE_KEY = 'utopia.localization.current_locale'.freeze
51
+ HTTP_ACCEPT_LANGUAGE = "HTTP_ACCEPT_LANGUAGE".freeze
52
+ LOCALIZATION_KEY = "utopia.localization".freeze
53
+ CURRENT_LOCALE_KEY = "utopia.localization.current_locale".freeze
54
54
 
55
55
  # @param locales [Array<String>] An array of all supported locales.
56
56
  # @param default_locale [String] The default locale if none is provided.
@@ -176,12 +176,12 @@ module Utopia
176
176
  headers = response[1].to_a
177
177
 
178
178
  # This response was based on the Accept-Language header:
179
- headers << ['Vary', 'Accept-Language']
179
+ headers << ["Vary", "Accept-Language"]
180
180
 
181
181
  # Althought this header is generally not supported, we supply it anyway as it is useful for debugging:
182
182
  if locale = env[CURRENT_LOCALE_KEY]
183
183
  # Set the Content-Location to point to the localized URI as requested:
184
- headers['Content-Location'] = "/#{locale}" + env[Rack::PATH_INFO]
184
+ headers["Content-Location"] = "/#{locale}" + env[Rack::PATH_INFO]
185
185
  end
186
186
 
187
187
  return response
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2009-2022, by Samuel Williams.
4
+ # Copyright, 2009-2025, by Samuel Williams.
5
5
 
6
- require_relative 'http'
7
- require_relative 'path'
6
+ require_relative "http"
7
+ require_relative "path"
8
8
 
9
9
  module Utopia
10
10
  # The default pages path for {Utopia::Content} middleware.
11
- PAGES_PATH = 'pages'.freeze
11
+ PAGES_PATH = "pages".freeze
12
12
 
13
13
  # This is used for shared controller variables which get consumed by the content middleware.
14
- VARIABLES_KEY = 'utopia.variables'.freeze
14
+ VARIABLES_KEY = "utopia.variables".freeze
15
15
 
16
16
  # The default root directory for middleware to operate within, e.g. the web-site directory. Convention over configuration.
17
17
  # @param subdirectory [String] Appended to the default root to make a more specific path.
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2015-2022, by Samuel Williams.
4
+ # Copyright, 2015-2025, by Samuel Williams.
5
5
 
6
- require_relative '../path'
6
+ require_relative "../path"
7
7
 
8
8
  module Utopia
9
9
  class Path
data/lib/utopia/path.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2009-2022, by Samuel Williams.
4
+ # Copyright, 2009-2025, by Samuel Williams.
5
5
 
6
6
  module Utopia
7
7
  # Represents a path as an array of path components. Useful for efficient URL manipulation.
8
8
  class Path
9
9
  include Comparable
10
10
 
11
- SEPARATOR = '/'
11
+ SEPARATOR = "/"
12
12
 
13
13
  def initialize(components = [])
14
14
  @components = components
@@ -29,7 +29,7 @@ module Utopia
29
29
  end
30
30
 
31
31
  def self.root
32
- self.new([''])
32
+ self.new([""])
33
33
  end
34
34
 
35
35
  # Returns the length of the prefix which is shared by two strings.
@@ -57,8 +57,8 @@ module Utopia
57
57
 
58
58
  # Converts '+' into whitespace and hex encoded characters into their equivalent characters.
59
59
  def self.unescape(string)
60
- string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) {
61
- [$1.delete('%')].pack('H*')
60
+ string.tr("+", " ").gsub(/((?:%[0-9a-fA-F]{2})+)/n) {
61
+ [$1.delete("%")].pack("H*")
62
62
  }
63
63
  end
64
64
 
@@ -116,34 +116,34 @@ module Utopia
116
116
  end
117
117
 
118
118
  def directory?
119
- return @components.last == ''
119
+ return @components.last == ""
120
120
  end
121
121
 
122
122
  def file?
123
- return @components.last != ''
123
+ return @components.last != ""
124
124
  end
125
125
 
126
126
  def to_directory
127
127
  if directory?
128
128
  return self
129
129
  else
130
- return self.class.new(@components + [''])
130
+ return self.class.new(@components + [""])
131
131
  end
132
132
  end
133
133
 
134
134
  def relative?
135
- @components.first != ''
135
+ @components.first != ""
136
136
  end
137
137
 
138
138
  def absolute?
139
- @components.first == ''
139
+ @components.first == ""
140
140
  end
141
141
 
142
142
  def to_absolute
143
143
  if absolute?
144
144
  return self
145
145
  else
146
- return self.class.new([''] + @components)
146
+ return self.class.new([""] + @components)
147
147
  end
148
148
  end
149
149
 
@@ -152,7 +152,7 @@ module Utopia
152
152
  end
153
153
 
154
154
  def to_str
155
- if @components == ['']
155
+ if @components == [""]
156
156
  SEPARATOR
157
157
  else
158
158
  @components.join(SEPARATOR)
@@ -168,7 +168,7 @@ module Utopia
168
168
  # @parameter other [Array(String)] The path components to append.
169
169
  def join(other)
170
170
  # Check whether other is an absolute path:
171
- if other.first == ''
171
+ if other.first == ""
172
172
  self.class.new(other)
173
173
  else
174
174
  self.class.new(@components + other).simplify
@@ -215,17 +215,17 @@ module Utopia
215
215
  end
216
216
 
217
217
  def simplify
218
- result = absolute? ? [''] : []
218
+ result = absolute? ? [""] : []
219
219
 
220
220
  @components.each do |bit|
221
221
  if bit == ".."
222
222
  result.pop
223
- elsif bit != "." && bit != ''
223
+ elsif bit != "." && bit != ""
224
224
  result << bit
225
225
  end
226
226
  end
227
227
 
228
- result << '' if directory?
228
+ result << "" if directory?
229
229
 
230
230
  return self.class.new(result)
231
231
  end
@@ -241,7 +241,7 @@ module Utopia
241
241
 
242
242
  # Returns the last path component.
243
243
  def last
244
- if @components != ['']
244
+ if @components != [""]
245
245
  @components.last
246
246
  end
247
247
  end
@@ -251,21 +251,21 @@ module Utopia
251
251
  # Pops the last path component.
252
252
  def pop
253
253
  # We don't want to convert an absolute path to a relative path.
254
- if @components != ['']
254
+ if @components != [""]
255
255
  @components.pop
256
256
  end
257
257
  end
258
258
 
259
259
  # @return [String] the last path component without any file extension.
260
260
  def basename
261
- basename, _ = @components.last.split('.', 2)
261
+ basename, _ = @components.last.split(".", 2)
262
262
 
263
- return basename || ''
263
+ return basename || ""
264
264
  end
265
265
 
266
266
  # @return [String] the last path component's file extension.
267
267
  def extension
268
- _, extension = @components.last.split('.', 2)
268
+ _, extension = @components.last.split(".", 2)
269
269
 
270
270
  return extension
271
271
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2009-2024, by Samuel Williams.
4
+ # Copyright, 2009-2025, by Samuel Williams.
5
5
 
6
- require_relative 'middleware'
6
+ require_relative "middleware"
7
7
 
8
8
  module Utopia
9
9
  # A middleware which assists with redirecting from one path to another.
@@ -114,7 +114,7 @@ module Utopia
114
114
 
115
115
  # Redirect urls that end with a `/`, e.g. directories.
116
116
  class DirectoryIndex < ClientRedirect
117
- def initialize(app, index: 'index')
117
+ def initialize(app, index: "index")
118
118
  @app = app
119
119
  @index = index
120
120
 
@@ -122,7 +122,7 @@ module Utopia
122
122
  end
123
123
 
124
124
  def [] path
125
- if path.end_with?('/')
125
+ if path.end_with?("/")
126
126
  return redirect(path + @index)
127
127
  end
128
128
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2022, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
 
6
- require_relative 'middleware'
6
+ require_relative "middleware"
7
7
 
8
8
  module Utopia
9
9
  class Responder
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2022, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
- require 'msgpack'
6
+ require "msgpack"
7
7
 
8
- require 'time'
9
- require 'date'
8
+ require "time"
9
+ require "date"
10
10
 
11
11
  module Utopia
12
12
  class Session