activesupport 7.2.2.1 → 8.0.0.beta1
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 +4 -4
- data/CHANGELOG.md +41 -237
- data/lib/active_support/backtrace_cleaner.rb +1 -1
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/cache/file_store.rb +12 -2
- data/lib/active_support/cache/memory_store.rb +6 -2
- data/lib/active_support/cache/redis_cache_store.rb +5 -2
- data/lib/active_support/cache.rb +14 -9
- data/lib/active_support/callbacks.rb +1 -2
- data/lib/active_support/class_attribute.rb +26 -0
- data/lib/active_support/code_generator.rb +9 -0
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/core_ext/benchmark.rb +6 -9
- data/lib/active_support/core_ext/class/attribute.rb +10 -19
- data/lib/active_support/core_ext/date/conversions.rb +2 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +2 -2
- data/lib/active_support/core_ext/enumerable.rb +8 -3
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/object/json.rb +18 -14
- data/lib/active_support/core_ext/string/multibyte.rb +1 -1
- data/lib/active_support/core_ext/time/calculations.rb +14 -2
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/time/zones.rb +1 -1
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/error_reporter.rb +25 -1
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +16 -12
- data/lib/active_support/i18n_railtie.rb +19 -10
- data/lib/active_support/isolated_execution_state.rb +0 -1
- data/lib/active_support/json/encoding.rb +2 -2
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/railtie.rb +4 -0
- data/lib/active_support/tagged_logging.rb +5 -0
- data/lib/active_support/testing/assertions.rb +72 -21
- data/lib/active_support/testing/isolation.rb +0 -2
- data/lib/active_support/testing/time_helpers.rb +2 -1
- data/lib/active_support/time_with_zone.rb +22 -13
- data/lib/active_support/values/time_zone.rb +17 -15
- data/lib/active_support.rb +10 -2
- metadata +23 -7
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/module/redefine_method"
|
4
|
+
require "active_support/class_attribute"
|
4
5
|
|
5
6
|
class Class
|
6
7
|
# Declare a class-level attribute whose value is inheritable by subclasses.
|
@@ -91,24 +92,16 @@ class Class
|
|
91
92
|
raise TypeError, "#{name.inspect} is not a symbol nor a string"
|
92
93
|
end
|
93
94
|
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
RUBY
|
98
|
-
|
99
|
-
methods << <<~RUBY if instance_reader
|
100
|
-
silence_redefinition_of_method def #{name}
|
101
|
-
defined?(@#{name}) ? @#{name} : self.class.#{name}
|
102
|
-
end
|
103
|
-
RUBY
|
95
|
+
name = name.to_sym
|
96
|
+
::ActiveSupport::ClassAttribute.redefine(self, name, default)
|
104
97
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
98
|
+
unless singleton_class?
|
99
|
+
methods << <<~RUBY if instance_reader
|
100
|
+
silence_redefinition_of_method def #{name}
|
101
|
+
defined?(@#{name}) ? @#{name} : self.class.#{name}
|
102
|
+
end
|
103
|
+
RUBY
|
104
|
+
end
|
112
105
|
|
113
106
|
methods << <<~RUBY if instance_writer
|
114
107
|
silence_redefinition_of_method(:#{name}=)
|
@@ -125,7 +118,5 @@ class Class
|
|
125
118
|
|
126
119
|
location = caller_locations(1, 1).first
|
127
120
|
class_eval(["class << self", *class_methods, "end", *methods].join(";").tr("\n", ";"), location.path, location.lineno)
|
128
|
-
|
129
|
-
attrs.each { |name| public_send("#{name}=", default) }
|
130
121
|
end
|
131
122
|
end
|
@@ -17,6 +17,7 @@ class Date
|
|
17
17
|
date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007"
|
18
18
|
},
|
19
19
|
rfc822: "%d %b %Y",
|
20
|
+
rfc2822: "%d %b %Y",
|
20
21
|
iso8601: lambda { |date| date.iso8601 }
|
21
22
|
}
|
22
23
|
|
@@ -34,6 +35,7 @@ class Date
|
|
34
35
|
# date.to_fs(:long) # => "November 10, 2007"
|
35
36
|
# date.to_fs(:long_ordinal) # => "November 10th, 2007"
|
36
37
|
# date.to_fs(:rfc822) # => "10 Nov 2007"
|
38
|
+
# date.to_fs(:rfc2822) # => "10 Nov 2007"
|
37
39
|
# date.to_fs(:iso8601) # => "2007-11-10"
|
38
40
|
#
|
39
41
|
# == Adding your own date formats to to_fs
|
@@ -26,8 +26,8 @@ module DateAndTime
|
|
26
26
|
# Only warn once, the first time the value is used (which should
|
27
27
|
# be the first time #to_time is called).
|
28
28
|
ActiveSupport.deprecator.warn(
|
29
|
-
"to_time will always preserve the timezone
|
30
|
-
"To opt in to the new behavior, set `
|
29
|
+
"`to_time` will always preserve the receiver timezone rather than system local time in Rails 8.0." \
|
30
|
+
"To opt in to the new behavior, set `config.active_support.to_time_preserves_timezone = :zone`."
|
31
31
|
)
|
32
32
|
|
33
33
|
@@preserve_timezone = false
|
@@ -192,9 +192,14 @@ module Enumerable
|
|
192
192
|
# # => [ Person.find(1), Person.find(5), Person.find(3) ]
|
193
193
|
#
|
194
194
|
# If the +series+ include keys that have no corresponding element in the Enumerable, these are ignored.
|
195
|
-
# If the Enumerable has additional elements that aren't named in the +series+, these are not included in the result
|
196
|
-
|
197
|
-
|
195
|
+
# If the Enumerable has additional elements that aren't named in the +series+, these are not included in the result, unless
|
196
|
+
# the +filter+ option is set to +false+.
|
197
|
+
def in_order_of(key, series, filter: true)
|
198
|
+
if filter
|
199
|
+
group_by(&key).values_at(*series).flatten(1).compact
|
200
|
+
else
|
201
|
+
sort_by { |v| series.index(v.public_send(key)) || series.size }.compact
|
202
|
+
end
|
198
203
|
end
|
199
204
|
|
200
205
|
# Returns the sole item in the enumerable. If there are no items, or more
|
@@ -1,18 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Hash
|
4
|
-
# Returns a hash that includes everything except given keys.
|
5
|
-
# hash = { a: true, b: false, c: nil }
|
6
|
-
# hash.except(:c) # => { a: true, b: false }
|
7
|
-
# hash.except(:a, :b) # => { c: nil }
|
8
|
-
# hash # => { a: true, b: false, c: nil }
|
9
|
-
#
|
10
|
-
# This is useful for limiting a set of parameters to everything but a few known toggles:
|
11
|
-
# @person.update(params[:person].except(:admin))
|
12
|
-
def except(*keys)
|
13
|
-
slice(*self.keys - keys)
|
14
|
-
end unless method_defined?(:except)
|
15
|
-
|
16
4
|
# Removes the given keys from hash and returns it.
|
17
5
|
# hash = { a: true, b: false, c: nil }
|
18
6
|
# hash.except!(:c) # => { a: true, b: false }
|
@@ -65,11 +65,9 @@ class Object
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
to_h.as_json(options)
|
72
|
-
end
|
68
|
+
class Data # :nodoc:
|
69
|
+
def as_json(options = nil)
|
70
|
+
to_h.as_json(options)
|
73
71
|
end
|
74
72
|
end
|
75
73
|
|
@@ -105,7 +103,7 @@ end
|
|
105
103
|
|
106
104
|
class Symbol
|
107
105
|
def as_json(options = nil) # :nodoc:
|
108
|
-
|
106
|
+
name
|
109
107
|
end
|
110
108
|
end
|
111
109
|
|
@@ -164,7 +162,12 @@ end
|
|
164
162
|
|
165
163
|
class Array
|
166
164
|
def as_json(options = nil) # :nodoc:
|
167
|
-
|
165
|
+
if options
|
166
|
+
options = options.dup.freeze unless options.frozen?
|
167
|
+
map { |v| v.as_json(options) }
|
168
|
+
else
|
169
|
+
map { |v| v.as_json }
|
170
|
+
end
|
168
171
|
end
|
169
172
|
end
|
170
173
|
|
@@ -184,8 +187,11 @@ class Hash
|
|
184
187
|
end
|
185
188
|
|
186
189
|
result = {}
|
187
|
-
|
188
|
-
|
190
|
+
if options
|
191
|
+
options = options.dup.freeze unless options.frozen?
|
192
|
+
subset.each { |k, v| result[k.to_s] = v.as_json(options) }
|
193
|
+
else
|
194
|
+
subset.each { |k, v| result[k.to_s] = v.as_json }
|
189
195
|
end
|
190
196
|
result
|
191
197
|
end
|
@@ -233,11 +239,9 @@ class Pathname # :nodoc:
|
|
233
239
|
end
|
234
240
|
end
|
235
241
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
to_s
|
240
|
-
end
|
242
|
+
class IPAddr # :nodoc:
|
243
|
+
def as_json(options = nil)
|
244
|
+
to_s
|
241
245
|
end
|
242
246
|
end
|
243
247
|
|
@@ -19,7 +19,7 @@ class String
|
|
19
19
|
# >> "lj".upcase
|
20
20
|
# => "LJ"
|
21
21
|
#
|
22
|
-
# ==
|
22
|
+
# == Method chaining
|
23
23
|
#
|
24
24
|
# All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
|
25
25
|
# method chaining on the result of any of these methods.
|
@@ -147,6 +147,13 @@ class Time
|
|
147
147
|
elsif zone.respond_to?(:utc_to_local)
|
148
148
|
new_time = ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
|
149
149
|
|
150
|
+
# Some versions of Ruby have a bug where Time.new with a zone object and
|
151
|
+
# fractional seconds will end up with a broken utc_offset.
|
152
|
+
# This is fixed in Ruby 3.3.1 and 3.2.4
|
153
|
+
unless new_time.utc_offset.integer?
|
154
|
+
new_time += 0
|
155
|
+
end
|
156
|
+
|
150
157
|
# When there are two occurrences of a nominal time due to DST ending,
|
151
158
|
# `Time.new` chooses the first chronological occurrence (the one with a
|
152
159
|
# larger UTC offset). However, for `change`, we want to choose the
|
@@ -217,8 +224,13 @@ class Time
|
|
217
224
|
# Returns a new Time representing the time a number of seconds since the instance time
|
218
225
|
def since(seconds)
|
219
226
|
self + seconds
|
220
|
-
rescue
|
221
|
-
to_datetime.since(seconds)
|
227
|
+
rescue TypeError
|
228
|
+
result = to_datetime.since(seconds)
|
229
|
+
ActiveSupport.deprecator.warn(
|
230
|
+
"Passing an instance of #{seconds.class} to #{self.class}#since is deprecated. This behavior will raise " \
|
231
|
+
"a `TypeError` in Rails 8.1."
|
232
|
+
)
|
233
|
+
result
|
222
234
|
end
|
223
235
|
alias :in :since
|
224
236
|
|
@@ -22,6 +22,7 @@ class Time
|
|
22
22
|
offset_format = time.formatted_offset(false)
|
23
23
|
time.strftime("%a, %d %b %Y %H:%M:%S #{offset_format}")
|
24
24
|
},
|
25
|
+
rfc2822: lambda { |time| time.rfc2822 },
|
25
26
|
iso8601: lambda { |time| time.iso8601 }
|
26
27
|
}
|
27
28
|
|
@@ -40,6 +41,7 @@ class Time
|
|
40
41
|
# time.to_fs(:long) # => "January 18, 2007 06:10"
|
41
42
|
# time.to_fs(:long_ordinal) # => "January 18th, 2007 06:10"
|
42
43
|
# time.to_fs(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
|
44
|
+
# time.to_fs(:rfc2822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
|
43
45
|
# time.to_fs(:iso8601) # => "2007-01-18T06:10:17-06:00"
|
44
46
|
#
|
45
47
|
# == Adding your own time formats to +to_fs+
|
@@ -20,7 +20,7 @@ class Time
|
|
20
20
|
# This method accepts any of the following:
|
21
21
|
#
|
22
22
|
# * A \Rails TimeZone object.
|
23
|
-
# * An identifier for a \Rails TimeZone object (e.g., "Eastern
|
23
|
+
# * An identifier for a \Rails TimeZone object (e.g., "Eastern Time (US & Canada)", <tt>-5.hours</tt>).
|
24
24
|
# * A +TZInfo::Timezone+ object.
|
25
25
|
# * An identifier for a +TZInfo::Timezone+ object (e.g., "America/New_York").
|
26
26
|
#
|
@@ -68,7 +68,7 @@ module ActiveSupport
|
|
68
68
|
# and the second is a library name.
|
69
69
|
#
|
70
70
|
# ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
|
71
|
-
def initialize(deprecation_horizon = "8.
|
71
|
+
def initialize(deprecation_horizon = "8.1", gem_name = "Rails")
|
72
72
|
self.gem_name = gem_name
|
73
73
|
self.deprecation_horizon = deprecation_horizon
|
74
74
|
# By default, warnings are not silenced and debugging is off.
|
@@ -43,6 +43,12 @@ module ActiveSupport
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
class InvalidKeyError < RuntimeError
|
47
|
+
def initialize(content_path, key)
|
48
|
+
super "Key '#{key}' is invalid, it must respond to '#to_sym' from configuration in '#{content_path}'."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
46
52
|
delegate_missing_to :options
|
47
53
|
|
48
54
|
def initialize(config_path:, key_path:, env_key:, raise_if_missing_key:)
|
@@ -61,7 +67,11 @@ module ActiveSupport
|
|
61
67
|
end
|
62
68
|
|
63
69
|
def validate! # :nodoc:
|
64
|
-
deserialize(read)
|
70
|
+
deserialize(read).each_key do |key|
|
71
|
+
key.to_sym
|
72
|
+
rescue NoMethodError
|
73
|
+
raise InvalidKeyError.new(content_path, key)
|
74
|
+
end
|
65
75
|
end
|
66
76
|
|
67
77
|
# Returns the decrypted content as a Hash with symbolized keys.
|
@@ -73,7 +83,7 @@ module ActiveSupport
|
|
73
83
|
# # => { some_secret: 123, some_namespace: { another_secret: 789 } }
|
74
84
|
#
|
75
85
|
def config
|
76
|
-
@config ||= deserialize(read)
|
86
|
+
@config ||= deep_symbolize_keys(deserialize(read))
|
77
87
|
end
|
78
88
|
|
79
89
|
def inspect # :nodoc:
|
@@ -81,6 +91,14 @@ module ActiveSupport
|
|
81
91
|
end
|
82
92
|
|
83
93
|
private
|
94
|
+
def deep_symbolize_keys(hash)
|
95
|
+
hash.deep_transform_keys do |key|
|
96
|
+
key.to_sym
|
97
|
+
rescue NoMethodError
|
98
|
+
raise InvalidKeyError.new(content_path, key)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
84
102
|
def deep_transform(hash)
|
85
103
|
return hash unless hash.is_a?(Hash)
|
86
104
|
|
@@ -144,9 +144,9 @@ module ActiveSupport
|
|
144
144
|
#
|
145
145
|
def unexpected(error, severity: :warning, context: {}, source: DEFAULT_SOURCE)
|
146
146
|
error = RuntimeError.new(error) if error.is_a?(String)
|
147
|
-
error.set_backtrace(caller(1)) if error.backtrace.nil?
|
148
147
|
|
149
148
|
if @debug_mode
|
149
|
+
ensure_backtrace(error)
|
150
150
|
raise UnexpectedError, "#{error.class.name}: #{error.message}", error.backtrace, cause: error
|
151
151
|
else
|
152
152
|
report(error, handled: true, severity: severity, context: context, source: source)
|
@@ -209,6 +209,7 @@ module ActiveSupport
|
|
209
209
|
#
|
210
210
|
def report(error, handled: true, severity: handled ? :warning : :error, context: {}, source: DEFAULT_SOURCE)
|
211
211
|
return if error.instance_variable_defined?(:@__rails_error_reported)
|
212
|
+
ensure_backtrace(error)
|
212
213
|
|
213
214
|
unless SEVERITIES.include?(severity)
|
214
215
|
raise ArgumentError, "severity must be one of #{SEVERITIES.map(&:inspect).join(", ")}, got: #{severity.inspect}"
|
@@ -237,5 +238,28 @@ module ActiveSupport
|
|
237
238
|
|
238
239
|
nil
|
239
240
|
end
|
241
|
+
|
242
|
+
private
|
243
|
+
def ensure_backtrace(error)
|
244
|
+
return if error.frozen? # re-raising won't add a backtrace
|
245
|
+
return unless error.backtrace.nil?
|
246
|
+
|
247
|
+
begin
|
248
|
+
# We could use Exception#set_backtrace, but until Ruby 3.4
|
249
|
+
# it only support setting `Exception#backtrace` and not
|
250
|
+
# `Exception#backtrace_locations`. So raising the exception
|
251
|
+
# is a good way to build a real backtrace.
|
252
|
+
raise error
|
253
|
+
rescue error.class => error
|
254
|
+
end
|
255
|
+
|
256
|
+
count = 0
|
257
|
+
while error.backtrace_locations.first&.path == __FILE__
|
258
|
+
count += 1
|
259
|
+
error.backtrace_locations.shift
|
260
|
+
end
|
261
|
+
|
262
|
+
error.backtrace.shift(count)
|
263
|
+
end
|
240
264
|
end
|
241
265
|
end
|
@@ -378,13 +378,10 @@ module ActiveSupport
|
|
378
378
|
|
379
379
|
# Convert to a regular hash with string keys.
|
380
380
|
def to_hash
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
_new_hash[key] = convert_value(value, conversion: :to_hash)
|
386
|
-
end
|
387
|
-
_new_hash
|
381
|
+
copy = Hash[self]
|
382
|
+
copy.transform_values! { |v| convert_value_to_hash(v) }
|
383
|
+
set_defaults(copy)
|
384
|
+
copy
|
388
385
|
end
|
389
386
|
|
390
387
|
def to_proc
|
@@ -398,11 +395,7 @@ module ActiveSupport
|
|
398
395
|
|
399
396
|
def convert_value(value, conversion: nil)
|
400
397
|
if value.is_a? Hash
|
401
|
-
|
402
|
-
value.to_hash
|
403
|
-
else
|
404
|
-
value.nested_under_indifferent_access
|
405
|
-
end
|
398
|
+
value.nested_under_indifferent_access
|
406
399
|
elsif value.is_a?(Array)
|
407
400
|
if conversion != :assignment || value.frozen?
|
408
401
|
value = value.dup
|
@@ -413,6 +406,17 @@ module ActiveSupport
|
|
413
406
|
end
|
414
407
|
end
|
415
408
|
|
409
|
+
def convert_value_to_hash(value)
|
410
|
+
if value.is_a? Hash
|
411
|
+
value.to_hash
|
412
|
+
elsif value.is_a?(Array)
|
413
|
+
value.map { |e| convert_value_to_hash(e) }
|
414
|
+
else
|
415
|
+
value
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
|
416
420
|
def set_defaults(target)
|
417
421
|
if default_proc
|
418
422
|
target.default_proc = default_proc.dup
|
@@ -14,15 +14,18 @@ module I18n
|
|
14
14
|
|
15
15
|
config.eager_load_namespaces << I18n
|
16
16
|
|
17
|
-
#
|
18
|
-
#
|
19
|
-
config.
|
17
|
+
# Make sure i18n is ready before eager loading, in case any eager loaded
|
18
|
+
# code needs it.
|
19
|
+
config.before_eager_load do |app|
|
20
20
|
I18n::Railtie.initialize_i18n(app)
|
21
21
|
end
|
22
22
|
|
23
|
-
#
|
24
|
-
#
|
25
|
-
|
23
|
+
# i18n initialization needs to run after application initialization, since
|
24
|
+
# initializers may configure i18n.
|
25
|
+
#
|
26
|
+
# If the application eager loaded, this was done on before_eager_load. The
|
27
|
+
# hook is still OK, though, because initialize_i18n is idempotent.
|
28
|
+
config.after_initialize do |app|
|
26
29
|
I18n::Railtie.initialize_i18n(app)
|
27
30
|
end
|
28
31
|
|
@@ -49,7 +52,8 @@ module I18n
|
|
49
52
|
when :load_path
|
50
53
|
I18n.load_path += value
|
51
54
|
when :raise_on_missing_translations
|
52
|
-
|
55
|
+
strict = value == :strict
|
56
|
+
setup_raise_on_missing_translations_config(app, strict)
|
53
57
|
else
|
54
58
|
I18n.public_send("#{setting}=", value)
|
55
59
|
end
|
@@ -62,8 +66,9 @@ module I18n
|
|
62
66
|
|
63
67
|
if app.config.reloading_enabled?
|
64
68
|
directories = watched_dirs_with_extensions(reloadable_paths)
|
65
|
-
|
66
|
-
|
69
|
+
root_load_paths = I18n.load_path.select { |path| path.start_with?(Rails.root.to_s) }
|
70
|
+
reloader = app.config.file_watcher.new(root_load_paths, directories) do
|
71
|
+
I18n.load_path.delete_if { |p| p.start_with?(Rails.root.to_s) && !File.exist?(p) }
|
67
72
|
I18n.load_path |= reloadable_paths.flat_map(&:existent)
|
68
73
|
end
|
69
74
|
|
@@ -77,11 +82,15 @@ module I18n
|
|
77
82
|
@i18n_inited = true
|
78
83
|
end
|
79
84
|
|
80
|
-
def self.setup_raise_on_missing_translations_config(app)
|
85
|
+
def self.setup_raise_on_missing_translations_config(app, strict)
|
81
86
|
ActiveSupport.on_load(:action_view) do
|
82
87
|
ActionView::Helpers::TranslationHelper.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
|
83
88
|
end
|
84
89
|
|
90
|
+
ActiveSupport.on_load(:active_model_translation) do
|
91
|
+
ActiveModel::Translation.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations if strict
|
92
|
+
end
|
93
|
+
|
85
94
|
if app.config.i18n.raise_on_missing_translations &&
|
86
95
|
I18n.exception_handler.is_a?(I18n::ExceptionHandler) # Only override the i18n gem's default exception handler.
|
87
96
|
|
@@ -36,14 +36,14 @@ module ActiveSupport
|
|
36
36
|
# Encode the given object into a JSON string
|
37
37
|
def encode(value)
|
38
38
|
unless options.empty?
|
39
|
-
value = value.as_json(options.dup)
|
39
|
+
value = value.as_json(options.dup.freeze)
|
40
40
|
end
|
41
41
|
json = stringify(jsonify(value))
|
42
42
|
|
43
43
|
# Rails does more escaping than the JSON gem natively does (we
|
44
44
|
# escape \u2028 and \u2029 and optionally >, <, & to work around
|
45
45
|
# certain browser problems).
|
46
|
-
if Encoding.escape_html_entities_in_json
|
46
|
+
if @options.fetch(:escape_html_entities, Encoding.escape_html_entities_in_json)
|
47
47
|
json.gsub!(">", '\u003e')
|
48
48
|
json.gsub!("<", '\u003c')
|
49
49
|
json.gsub!("&", '\u0026')
|
@@ -1,6 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
|
+
# = Number Helper
|
5
|
+
#
|
6
|
+
# Provides methods for formatting numbers into currencies, percentages,
|
7
|
+
# phone numbers, and more.
|
8
|
+
#
|
9
|
+
# Example usage in a class:
|
10
|
+
# class Topic
|
11
|
+
# include ActiveSupport::NumberHelper
|
12
|
+
#
|
13
|
+
# def price
|
14
|
+
# number_to_currency(@price)
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# Example usage in a module:
|
19
|
+
# require "active_support/number_helper"
|
20
|
+
#
|
21
|
+
# module NumberFormatting
|
22
|
+
# def format_price(price)
|
23
|
+
# ActiveSupport::NumberHelper.number_to_currency(price)
|
24
|
+
# end
|
25
|
+
# end
|
4
26
|
module NumberHelper
|
5
27
|
extend ActiveSupport::Autoload
|
6
28
|
|
@@ -96,6 +96,10 @@ module ActiveSupport
|
|
96
96
|
config.eager_load_namespaces << TZInfo
|
97
97
|
end
|
98
98
|
|
99
|
+
initializer "active_support.to_time_preserves_timezone" do |app|
|
100
|
+
ActiveSupport.to_time_preserves_timezone = app.config.active_support.to_time_preserves_timezone
|
101
|
+
end
|
102
|
+
|
99
103
|
# Sets the default week start
|
100
104
|
# If assigned value is not a valid day symbol (e.g. :sunday, :monday, ...), an exception will be raised.
|
101
105
|
initializer "active_support.initialize_beginning_of_week" do |app|
|
@@ -113,6 +113,11 @@ module ActiveSupport
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
+
# Returns an `ActiveSupport::Logger` that has already been wrapped with tagged logging concern.
|
117
|
+
def self.logger(*args, **kwargs)
|
118
|
+
new ActiveSupport::Logger.new(*args, **kwargs)
|
119
|
+
end
|
120
|
+
|
116
121
|
def self.new(logger)
|
117
122
|
logger = logger.clone
|
118
123
|
|