activesupport 8.1.1 → 8.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b039f92d3ea92da9f26a0976ed2a520582423f6a4a76fc3ff876b01a752ea95c
4
- data.tar.gz: bed24bdb19b85bc7d5aaa866a91c92f7661e54d3276a7dd7f1f99724d35bee79
3
+ metadata.gz: 9c47955c56ff0cd5b61a8b4d74383c8f2f7523146088f2f1f7181049c354920c
4
+ data.tar.gz: a42c08e02aa40dafbaf38a7aff2b2d12dbb32c262bef95e10071381179aec53b
5
5
  SHA512:
6
- metadata.gz: 1988996636e1e6e8b8c7f54ec0bc0fc0be22eae66dc3048adc8bf00edcb1fc812154dc770f768d3ebffbb5d1edd9191d64b59dac81264c0e1ca3d11e9578cf60
7
- data.tar.gz: 2d785dd9295cfef86a9e390ed59f7ea1094f94410079e00a1d6cfb2fcc71bd2ec205cd1256d3ebc688c3cbfafabc5eff95715213dc09626993440816e6c33c7f
6
+ metadata.gz: 83cfdbf2e2542e39fcfbe2918d6f50eca40e3ab713176f4a0ba2085272b642596632fa13704dd5fd37ba97f8d1ec1848d4821ad6d17d3330095f1576b8c1059f
7
+ data.tar.gz: 1c8b04fd7508ae125f30d5317437258ca35b02f6092562a81aa26bd6eaccb386684367e7bc6273128c7aa9ca036451694c8c67af3784f6e68fdf4a584c5fcdcc
data/CHANGELOG.md CHANGED
@@ -1,3 +1,43 @@
1
+ ## Rails 8.1.2 (January 08, 2026) ##
2
+
3
+ * Make `delegate` and `delegate_missing_to` work in BasicObject subclasses.
4
+
5
+ *Rafael Mendonça França*
6
+
7
+ * Fix Inflectors when using a locale that fallbacks to `:en`.
8
+
9
+ *Said Kaldybaev*
10
+
11
+ * Fix `ActiveSupport::TimeWithZone#as_json` to consistently return UTF-8 strings.
12
+
13
+ Previously the returned string would sometime be encoded in US-ASCII, which in
14
+ some cases may be problematic.
15
+
16
+ Now the method consistently always return UTF-8 strings.
17
+
18
+ *Jean Boussier*
19
+
20
+ * Fix `TimeWithZone#xmlschema` when wrapping a `DateTime` instance in local time.
21
+
22
+ Previously it would return an invalid time.
23
+
24
+ *Dmytro Rymar*
25
+
26
+ * Implement LocalCache strategy on `ActiveSupport::Cache::MemoryStore`. The memory store
27
+ needs to respond to the same interface as other cache stores (e.g. `ActiveSupport::NullStore`).
28
+
29
+ *Mikey Gough*
30
+
31
+ * Fix `ActiveSupport::Inflector.humanize` with international characters.
32
+
33
+ ```ruby
34
+ ActiveSupport::Inflector.humanize("áÉÍÓÚ") # => "Áéíóú"
35
+ ActiveSupport::Inflector.humanize("аБВГДЕ") # => "Абвгде"
36
+ ```
37
+
38
+ *Jose Luis Duran*
39
+
40
+
1
41
  ## Rails 8.1.1 (October 28, 2025) ##
2
42
 
3
43
  * No changes.
@@ -59,7 +59,7 @@ module ActiveSupport
59
59
  pool_options = retrieve_pool_options(options)
60
60
 
61
61
  if pool_options
62
- ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
62
+ ConnectionPool.new(**pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
63
63
  else
64
64
  Dalli::Client.new(addresses, options)
65
65
  end
@@ -26,6 +26,8 @@ module ActiveSupport
26
26
  #
27
27
  # +MemoryStore+ is thread-safe.
28
28
  class MemoryStore < Store
29
+ prepend Strategy::LocalCache
30
+
29
31
  module DupCoder # :nodoc:
30
32
  extend self
31
33
 
@@ -160,7 +160,7 @@ module ActiveSupport
160
160
  (redis.respond_to?(:wrapped_pool) && redis.wrapped_pool.instance_of?(::ConnectionPool))
161
161
 
162
162
  if !already_pool && pool_options = self.class.send(:retrieve_pool_options, redis_options)
163
- @redis = ::ConnectionPool.new(pool_options) { self.class.build_redis(**redis_options) }
163
+ @redis = ::ConnectionPool.new(**pool_options) { self.class.build_redis(**redis_options) }
164
164
  else
165
165
  @redis = self.class.build_redis(**redis_options)
166
166
  end
@@ -4,7 +4,7 @@
4
4
  require "json"
5
5
  require "bigdecimal"
6
6
  require "ipaddr"
7
- require "uri/generic"
7
+ require "uri"
8
8
  require "pathname"
9
9
  require "active_support/core_ext/big_decimal/conversions" # for #to_s
10
10
  require "active_support/core_ext/hash/except"
@@ -134,11 +134,11 @@ module ActiveSupport
134
134
  "def #{method_name}(#{definition})" <<
135
135
  " _ = #{receiver}" <<
136
136
  " _.#{method}(#{definition})" <<
137
- "rescue NoMethodError => e" <<
137
+ "rescue ::NoMethodError => e" <<
138
138
  " if _.nil? && e.name == :#{method}" <<
139
- " raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
139
+ " ::Kernel.raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
140
140
  " else" <<
141
- " raise" <<
141
+ " ::Kernel.raise" <<
142
142
  " end" <<
143
143
  "end"
144
144
  end
@@ -151,49 +151,32 @@ module ActiveSupport
151
151
  target = target.to_s
152
152
  target = "self.#{target}" if RESERVED_METHOD_NAMES.include?(target) || target == "__target"
153
153
 
154
- if allow_nil
155
- owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
156
- def respond_to_missing?(name, include_private = false)
157
- # It may look like an oversight, but we deliberately do not pass
158
- # +include_private+, because they do not get delegated.
159
-
160
- return false if name == :marshal_dump || name == :_dump
161
- #{target}.respond_to?(name) || super
162
- end
163
-
164
- def method_missing(method, ...)
165
- __target = #{target}
166
- if __target.nil? && !nil.respond_to?(method)
167
- nil
168
- elsif __target.respond_to?(method)
169
- __target.public_send(method, ...)
170
- else
171
- super
172
- end
173
- end
174
- RUBY
154
+ nil_behavior = if allow_nil
155
+ "nil"
175
156
  else
176
- owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
177
- def respond_to_missing?(name, include_private = false)
178
- # It may look like an oversight, but we deliberately do not pass
179
- # +include_private+, because they do not get delegated.
157
+ "::Kernel.raise ::ActiveSupport::DelegationError.nil_target(method, :'#{target}')"
158
+ end
180
159
 
181
- return false if name == :marshal_dump || name == :_dump
182
- #{target}.respond_to?(name) || super
183
- end
160
+ owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
161
+ def respond_to_missing?(name, include_private = false)
162
+ # It may look like an oversight, but we deliberately do not pass
163
+ # +include_private+, because they do not get delegated.
184
164
 
185
- def method_missing(method, ...)
186
- __target = #{target}
187
- if __target.nil? && !nil.respond_to?(method)
188
- raise ::ActiveSupport::DelegationError.nil_target(method, :'#{target}')
189
- elsif __target.respond_to?(method)
190
- __target.public_send(method, ...)
191
- else
192
- super
193
- end
165
+ return false if name == :marshal_dump || name == :_dump
166
+ #{target}.respond_to?(name) || super
167
+ end
168
+
169
+ def method_missing(method, ...)
170
+ __target = #{target}
171
+ if __target.nil? && !nil.respond_to?(method)
172
+ #{nil_behavior}
173
+ elsif __target.respond_to?(method)
174
+ __target.public_send(method, ...)
175
+ else
176
+ super
194
177
  end
195
- RUBY
196
- end
178
+ end
179
+ RUBY
197
180
  end
198
181
  end
199
182
  end
@@ -9,7 +9,7 @@ module ActiveSupport
9
9
  module VERSION
10
10
  MAJOR = 8
11
11
  MINOR = 1
12
- TINY = 1
12
+ TINY = 2
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -84,6 +84,7 @@ module ActiveSupport
84
84
  return @__en_instance__ ||= new if locale == :en
85
85
 
86
86
  I18n.fallbacks[locale].each do |k|
87
+ return @__en_instance__ if k == :en && @__en_instance__
87
88
  return @__instance__[k] if @__instance__.key?(k)
88
89
  end
89
90
  instance(locale)
@@ -143,13 +143,13 @@ module ActiveSupport
143
143
  result.delete_suffix!(" id")
144
144
  end
145
145
 
146
- result.gsub!(/([a-z\d]+)/i) do |match|
146
+ result.gsub!(/([[[:alpha:]]\d]+)/i) do |match|
147
147
  match.downcase!
148
148
  inflections.acronyms[match] || match
149
149
  end
150
150
 
151
151
  if capitalize
152
- result.sub!(/\A\w/) do |match|
152
+ result.sub!(/\A[[:alpha:]]/) do |match|
153
153
  match.upcase!
154
154
  match
155
155
  end
@@ -55,11 +55,16 @@ module ActiveSupport
55
55
  scope.current
56
56
  end
57
57
 
58
- def share_with(other, &block)
58
+ def share_with(other, except: [], &block)
59
59
  # Action Controller streaming spawns a new thread and copy thread locals.
60
60
  # We do the same here for backward compatibility, but this is very much a hack
61
61
  # and streaming should be rethought.
62
- old_state, context.active_support_execution_state = context.active_support_execution_state, other.active_support_execution_state.dup
62
+ if state = other.active_support_execution_state
63
+ copied_state = state.dup
64
+ Array(except).each { |key| copied_state.delete(key) }
65
+ end
66
+
67
+ old_state, context.active_support_execution_state = context.active_support_execution_state, copied_state
63
68
  block.call
64
69
  ensure
65
70
  context.active_support_execution_state = old_state
@@ -4,7 +4,7 @@ require "bigdecimal"
4
4
  require "date"
5
5
  require "ipaddr"
6
6
  require "pathname"
7
- require "uri/generic"
7
+ require "uri"
8
8
  require "msgpack/bigint"
9
9
  require "active_support/hash_with_indifferent_access"
10
10
  require "active_support/core_ext/string/output_safety"
@@ -21,6 +21,10 @@ module ActiveSupport
21
21
 
22
22
  def base_label
23
23
  end
24
+
25
+ def absolute_path
26
+ path
27
+ end
24
28
  end
25
29
 
26
30
  class BacktraceLocationProxy < DelegateClass(Thread::Backtrace::Location) # :nodoc:
@@ -62,6 +62,12 @@ module ActiveSupport
62
62
  ActiveSupport.test_order ||= :random
63
63
  end
64
64
 
65
+ if Minitest.respond_to? :run_order # MT6 API change
66
+ def run_order # :nodoc:
67
+ test_order
68
+ end
69
+ end
70
+
65
71
  # Parallelizes the test suite.
66
72
  #
67
73
  # Takes a +workers+ argument that controls how many times the process
@@ -124,7 +124,8 @@ module ActiveSupport
124
124
  actual = exp.call
125
125
  rich_message = -> do
126
126
  code_string = code.respond_to?(:call) ? _callable_to_source_string(code) : code
127
- error = "`#{code_string}` didn't change by #{diff}, but by #{actual - before_value}"
127
+ error = "`#{code_string}` didn't change by #{diff}, but by #{actual - before_value}."
128
+ error = "#{error}\n#{diff before_value + diff, actual}" if Minitest::VERSION > "6"
128
129
  error = "#{message}.\n#{error}" if message
129
130
  error
130
131
  end
@@ -228,7 +229,7 @@ module ActiveSupport
228
229
  rich_message = -> do
229
230
  code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
230
231
  error = "`#{code_string}` didn't change"
231
- error = "#{error}. It was already #{to.inspect}" if before == to
232
+ error = "#{error}. It was already #{to.inspect}." if before == to
232
233
  error = "#{message}.\n#{error}" if message
233
234
  error
234
235
  end
@@ -296,8 +297,9 @@ module ActiveSupport
296
297
 
297
298
  rich_message = -> do
298
299
  code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
299
- error = "`#{code_string}` changed"
300
+ error = "`#{code_string}` changed."
300
301
  error = "#{message}.\n#{error}" if message
302
+ error = "#{error}\n#{diff before, after}" if Minitest::VERSION > "6"
301
303
  error
302
304
  end
303
305
 
@@ -2,4 +2,9 @@
2
2
 
3
3
  require "minitest"
4
4
 
5
+ # This respond_to check handles tests running sub-processes in an
6
+ # unbundled environment, which triggers MT5 usage. This conditional may
7
+ # be removable after the version bump, though it currently safeguards
8
+ # against issues in environments with multiple versions installed.
9
+ Minitest.load :rails if Minitest.respond_to? :load
5
10
  Minitest.autorun
@@ -46,8 +46,10 @@ module ActiveSupport
46
46
 
47
47
  set_process_title("#{klass}##{method}")
48
48
 
49
- result = klass.with_info_handler reporter do
50
- Minitest.run_one_method(klass, method)
49
+ result = if Minitest.respond_to? :run_one_method then
50
+ Minitest.run_one_method klass, method
51
+ else
52
+ klass.new(method).run
51
53
  end
52
54
 
53
55
  safe_record(reporter, result)
@@ -152,11 +152,15 @@ module ActiveSupport
152
152
  #
153
153
  # Time.zone.now.xmlschema # => "2014-12-04T11:02:37-05:00"
154
154
  def xmlschema(fraction_digits = 0)
155
+ precision = fraction_digits || 0
156
+
155
157
  if @is_utc
156
- utc.iso8601(fraction_digits || 0)
158
+ utc.iso8601(precision)
157
159
  else
158
- str = time.iso8601(fraction_digits || 0)
159
- str[-1] = formatted_offset(true, "Z")
160
+ str = time.iso8601(precision)
161
+ offset = formatted_offset(true, "Z")
162
+
163
+ str.sub!(/(Z|[+-]\d{2}:\d{2})\z/, offset)
160
164
  str
161
165
  end
162
166
  end
@@ -177,7 +181,7 @@ module ActiveSupport
177
181
  # # => "2005/02/01 05:15:10 -1000"
178
182
  def as_json(options = nil)
179
183
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
180
- xmlschema(ActiveSupport::JSON::Encoding.time_precision)
184
+ xmlschema(ActiveSupport::JSON::Encoding.time_precision).force_encoding(Encoding::UTF_8)
181
185
  else
182
186
  %(#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
183
187
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activesupport
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.1.1
4
+ version: 8.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -501,10 +501,10 @@ licenses:
501
501
  - MIT
502
502
  metadata:
503
503
  bug_tracker_uri: https://github.com/rails/rails/issues
504
- changelog_uri: https://github.com/rails/rails/blob/v8.1.1/activesupport/CHANGELOG.md
505
- documentation_uri: https://api.rubyonrails.org/v8.1.1/
504
+ changelog_uri: https://github.com/rails/rails/blob/v8.1.2/activesupport/CHANGELOG.md
505
+ documentation_uri: https://api.rubyonrails.org/v8.1.2/
506
506
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
507
- source_code_uri: https://github.com/rails/rails/tree/v8.1.1/activesupport
507
+ source_code_uri: https://github.com/rails/rails/tree/v8.1.2/activesupport
508
508
  rubygems_mfa_required: 'true'
509
509
  rdoc_options:
510
510
  - "--encoding"
@@ -522,7 +522,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
522
522
  - !ruby/object:Gem::Version
523
523
  version: '0'
524
524
  requirements: []
525
- rubygems_version: 3.6.9
525
+ rubygems_version: 4.0.3
526
526
  specification_version: 4
527
527
  summary: A toolkit of support libraries and Ruby core extensions extracted from the
528
528
  Rails framework.