activesupport 6.1.7.3 → 7.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +151 -627
- data/MIT-LICENSE +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +0 -2
- data/lib/active_support/benchmarkable.rb +2 -2
- data/lib/active_support/cache/file_store.rb +15 -9
- data/lib/active_support/cache/mem_cache_store.rb +119 -28
- data/lib/active_support/cache/memory_store.rb +21 -13
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +39 -59
- data/lib/active_support/cache/strategy/local_cache.rb +29 -49
- data/lib/active_support/cache.rb +189 -45
- data/lib/active_support/callbacks.rb +35 -31
- data/lib/active_support/concern.rb +5 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +6 -3
- data/lib/active_support/configuration_file.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +6 -6
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +2 -2
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/digest/uuid.rb +13 -13
- data/lib/active_support/core_ext/enumerable.rb +64 -12
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/module/delegation.rb +2 -8
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/conversions.rb +2 -2
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +29 -24
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +60 -68
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +4 -5
- data/lib/active_support/core_ext/time/zones.rb +2 -17
- data/lib/active_support/core_ext/uri.rb +0 -14
- data/lib/active_support/current_attributes.rb +17 -2
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -788
- data/lib/active_support/deprecation/behaviors.rb +4 -1
- data/lib/active_support/deprecation/method_wrappers.rb +3 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/descendants_tracker.rb +12 -9
- data/lib/active_support/digest.rb +4 -4
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +9 -1
- data/lib/active_support/duration.rb +80 -52
- data/lib/active_support/encrypted_configuration.rb +11 -1
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/environment_inquirer.rb +1 -1
- data/lib/active_support/evented_file_update_checker.rb +1 -1
- data/lib/active_support/execution_wrapper.rb +13 -16
- data/lib/active_support/fork_tracker.rb +2 -4
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +3 -1
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/inflector/inflections.rb +11 -4
- data/lib/active_support/inflector/methods.rb +23 -46
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/key_generator.rb +18 -1
- data/lib/active_support/locale/en.yml +1 -1
- data/lib/active_support/log_subscriber.rb +13 -3
- data/lib/active_support/logger_thread_safe_level.rb +5 -13
- data/lib/active_support/message_encryptor.rb +3 -3
- data/lib/active_support/message_verifier.rb +4 -4
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +10 -11
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +31 -11
- data/lib/active_support/notifications/instrumenter.rb +17 -0
- data/lib/active_support/notifications.rb +10 -0
- data/lib/active_support/number_helper/number_converter.rb +1 -3
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/rounding_helper.rb +1 -5
- data/lib/active_support/number_helper.rb +0 -2
- data/lib/active_support/option_merger.rb +4 -16
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/parameter_filter.rb +5 -0
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/railtie.rb +33 -10
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +2 -2
- data/lib/active_support/secure_compare_rotator.rb +1 -1
- data/lib/active_support/string_inquirer.rb +0 -2
- data/lib/active_support/subscriber.rb +5 -0
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +34 -4
- data/lib/active_support/testing/deprecation.rb +1 -1
- data/lib/active_support/testing/isolation.rb +1 -1
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +13 -2
- data/lib/active_support/time_with_zone.rb +19 -6
- data/lib/active_support/values/time_zone.rb +25 -11
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +2 -1
- data/lib/active_support.rb +14 -1
- metadata +14 -29
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
@@ -68,13 +68,17 @@ module ActiveSupport
|
|
68
68
|
# camelize(underscore('SSLError')) # => "SslError"
|
69
69
|
def camelize(term, uppercase_first_letter = true)
|
70
70
|
string = term.to_s
|
71
|
-
|
72
|
-
|
71
|
+
# String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent.
|
72
|
+
if !uppercase_first_letter || uppercase_first_letter == :lower
|
73
|
+
string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase! || match }
|
73
74
|
else
|
74
|
-
string = string.sub(
|
75
|
+
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize! || match }
|
76
|
+
end
|
77
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) do
|
78
|
+
word = $2
|
79
|
+
substituted = inflections.acronyms[word] || word.capitalize! || word
|
80
|
+
$1 ? "::#{substituted}" : substituted
|
75
81
|
end
|
76
|
-
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
|
77
|
-
string.gsub!("/", "::")
|
78
82
|
string
|
79
83
|
end
|
80
84
|
|
@@ -90,10 +94,10 @@ module ActiveSupport
|
|
90
94
|
#
|
91
95
|
# camelize(underscore('SSLError')) # => "SslError"
|
92
96
|
def underscore(camel_cased_word)
|
93
|
-
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
|
97
|
+
return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
|
94
98
|
word = camel_cased_word.to_s.gsub("::", "/")
|
95
99
|
word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
|
96
|
-
word.gsub!(/([A-Z])(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
|
100
|
+
word.gsub!(/([A-Z\d]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
|
97
101
|
word.tr!("-", "_")
|
98
102
|
word.downcase!
|
99
103
|
word
|
@@ -119,7 +123,7 @@ module ActiveSupport
|
|
119
123
|
# humanize('author_id') # => "Author"
|
120
124
|
# humanize('author_id', capitalize: false) # => "author"
|
121
125
|
# humanize('_id') # => "Id"
|
122
|
-
# humanize('author_id', keep_id_suffix: true) # => "Author
|
126
|
+
# humanize('author_id', keep_id_suffix: true) # => "Author id"
|
123
127
|
#
|
124
128
|
# If "SSL" was defined to be an acronym:
|
125
129
|
#
|
@@ -130,18 +134,22 @@ module ActiveSupport
|
|
130
134
|
|
131
135
|
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
132
136
|
|
133
|
-
result.
|
137
|
+
result.tr!("_", " ")
|
138
|
+
result.lstrip!
|
134
139
|
unless keep_id_suffix
|
135
|
-
result.delete_suffix!("
|
140
|
+
result.delete_suffix!(" id")
|
136
141
|
end
|
137
|
-
result.tr!("_", " ")
|
138
142
|
|
139
|
-
result.gsub!(/([a-z\d]
|
140
|
-
|
143
|
+
result.gsub!(/([a-z\d]+)/i) do |match|
|
144
|
+
match.downcase!
|
145
|
+
inflections.acronyms[match] || match
|
141
146
|
end
|
142
147
|
|
143
148
|
if capitalize
|
144
|
-
result.sub!(/\A\w/)
|
149
|
+
result.sub!(/\A\w/) do |match|
|
150
|
+
match.upcase!
|
151
|
+
match
|
152
|
+
end
|
145
153
|
end
|
146
154
|
|
147
155
|
result
|
@@ -269,38 +277,7 @@ module ActiveSupport
|
|
269
277
|
# NameError is raised when the name is not in CamelCase or the constant is
|
270
278
|
# unknown.
|
271
279
|
def constantize(camel_cased_word)
|
272
|
-
|
273
|
-
Object.const_get(camel_cased_word)
|
274
|
-
else
|
275
|
-
names = camel_cased_word.split("::")
|
276
|
-
|
277
|
-
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
278
|
-
Object.const_get(camel_cased_word) if names.empty?
|
279
|
-
|
280
|
-
# Remove the first blank element in case of '::ClassName' notation.
|
281
|
-
names.shift if names.size > 1 && names.first.empty?
|
282
|
-
|
283
|
-
names.inject(Object) do |constant, name|
|
284
|
-
if constant == Object
|
285
|
-
constant.const_get(name)
|
286
|
-
else
|
287
|
-
candidate = constant.const_get(name)
|
288
|
-
next candidate if constant.const_defined?(name, false)
|
289
|
-
next candidate unless Object.const_defined?(name)
|
290
|
-
|
291
|
-
# Go down the ancestors to check if it is owned directly. The check
|
292
|
-
# stops when we reach Object or the end of ancestors tree.
|
293
|
-
constant = constant.ancestors.inject(constant) do |const, ancestor|
|
294
|
-
break const if ancestor == Object
|
295
|
-
break ancestor if ancestor.const_defined?(name, false)
|
296
|
-
const
|
297
|
-
end
|
298
|
-
|
299
|
-
# owner is in Object, so raise
|
300
|
-
constant.const_get(name, false)
|
301
|
-
end
|
302
|
-
end
|
303
|
-
end
|
280
|
+
Object.const_get(camel_cased_word)
|
304
281
|
end
|
305
282
|
|
306
283
|
# Tries to find a constant with the name specified in the argument string.
|
@@ -22,8 +22,8 @@ module ActiveSupport
|
|
22
22
|
Encoding.json_encoder.new(options).encode(value)
|
23
23
|
end
|
24
24
|
|
25
|
-
module Encoding
|
26
|
-
class JSONGemEncoder
|
25
|
+
module Encoding # :nodoc:
|
26
|
+
class JSONGemEncoder # :nodoc:
|
27
27
|
attr_reader :options
|
28
28
|
|
29
29
|
def initialize(options = nil)
|
@@ -51,7 +51,7 @@ module ActiveSupport
|
|
51
51
|
ESCAPE_REGEX_WITHOUT_HTML_ENTITIES = /[\u2028\u2029]/u
|
52
52
|
|
53
53
|
# This class wraps all the strings we see and does the extra escaping
|
54
|
-
class EscapedString < String
|
54
|
+
class EscapedString < String # :nodoc:
|
55
55
|
def to_json(*)
|
56
56
|
if Encoding.escape_html_entities_in_json
|
57
57
|
s = super
|
@@ -9,18 +9,35 @@ module ActiveSupport
|
|
9
9
|
# This lets Rails applications have a single secure secret, but avoid reusing that
|
10
10
|
# key in multiple incompatible contexts.
|
11
11
|
class KeyGenerator
|
12
|
+
class << self
|
13
|
+
def hash_digest_class=(klass)
|
14
|
+
if klass.kind_of?(Class) && klass < OpenSSL::Digest
|
15
|
+
@hash_digest_class = klass
|
16
|
+
else
|
17
|
+
raise ArgumentError, "#{klass} is expected to be an OpenSSL::Digest subclass"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def hash_digest_class
|
22
|
+
@hash_digest_class ||= OpenSSL::Digest::SHA1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
12
26
|
def initialize(secret, options = {})
|
13
27
|
@secret = secret
|
14
28
|
# The default iterations are higher than required for our key derivation uses
|
15
29
|
# on the off chance someone uses this for password storage
|
16
30
|
@iterations = options[:iterations] || 2**16
|
31
|
+
# Also allow configuration here so people can use this to build a rotation
|
32
|
+
# scheme when switching the digest class.
|
33
|
+
@hash_digest_class = options[:hash_digest_class] || self.class.hash_digest_class
|
17
34
|
end
|
18
35
|
|
19
36
|
# Returns a derived key suitable for use. The default key_size is chosen
|
20
37
|
# to be compatible with the default settings of ActiveSupport::MessageVerifier.
|
21
38
|
# i.e. OpenSSL::Digest::SHA1#block_length
|
22
39
|
def generate_key(salt, key_size = 64)
|
23
|
-
OpenSSL::PKCS5.
|
40
|
+
OpenSSL::PKCS5.pbkdf2_hmac(@secret, salt, @iterations, key_size, @hash_digest_class.new)
|
24
41
|
end
|
25
42
|
end
|
26
43
|
|
@@ -55,7 +55,7 @@ en:
|
|
55
55
|
# Used in NumberHelper.number_to_currency()
|
56
56
|
currency:
|
57
57
|
format:
|
58
|
-
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
58
|
+
# Where is the currency sign? %u is the currency unit, %n is the number (default: $5.00)
|
59
59
|
format: "%u%n"
|
60
60
|
unit: "$"
|
61
61
|
# These six are to override number.format and are optional
|
@@ -114,9 +114,13 @@ module ActiveSupport
|
|
114
114
|
def finish(name, id, payload)
|
115
115
|
super if logger
|
116
116
|
rescue => e
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
log_exception(name, e)
|
118
|
+
end
|
119
|
+
|
120
|
+
def publish_event(event)
|
121
|
+
super if logger
|
122
|
+
rescue => e
|
123
|
+
log_exception(event.name, e)
|
120
124
|
end
|
121
125
|
|
122
126
|
private
|
@@ -138,5 +142,11 @@ module ActiveSupport
|
|
138
142
|
bold = bold ? BOLD : ""
|
139
143
|
"#{bold}#{color}#{text}#{CLEAR}"
|
140
144
|
end
|
145
|
+
|
146
|
+
def log_exception(name, e)
|
147
|
+
if logger
|
148
|
+
logger.error "Could not log #{name.inspect} event. #{e.class}: #{e.message} #{e.backtrace}"
|
149
|
+
end
|
150
|
+
end
|
141
151
|
end
|
142
152
|
end
|
@@ -9,10 +9,6 @@ module ActiveSupport
|
|
9
9
|
module LoggerThreadSafeLevel # :nodoc:
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
|
-
included do
|
13
|
-
cattr_accessor :local_levels, default: Concurrent::Map.new(initial_capacity: 2), instance_accessor: false
|
14
|
-
end
|
15
|
-
|
16
12
|
Logger::Severity.constants.each do |severity|
|
17
13
|
class_eval(<<-EOT, __FILE__, __LINE__ + 1)
|
18
14
|
def #{severity.downcase}? # def debug?
|
@@ -21,25 +17,21 @@ module ActiveSupport
|
|
21
17
|
EOT
|
22
18
|
end
|
23
19
|
|
24
|
-
def local_log_id
|
25
|
-
Fiber.current.__id__
|
26
|
-
end
|
27
|
-
|
28
20
|
def local_level
|
29
|
-
|
21
|
+
# Note: Thread#[] is fiber-local
|
22
|
+
Thread.current[:logger_thread_safe_level]
|
30
23
|
end
|
31
24
|
|
32
25
|
def local_level=(level)
|
33
26
|
case level
|
34
27
|
when Integer
|
35
|
-
self.class.local_levels[local_log_id] = level
|
36
28
|
when Symbol
|
37
|
-
|
29
|
+
level = Logger::Severity.const_get(level.to_s.upcase)
|
38
30
|
when nil
|
39
|
-
self.class.local_levels.delete(local_log_id)
|
40
31
|
else
|
41
32
|
raise ArgumentError, "Invalid log level: #{level.inspect}"
|
42
33
|
end
|
34
|
+
Thread.current[:logger_thread_safe_level] = level
|
43
35
|
end
|
44
36
|
|
45
37
|
def level
|
@@ -56,7 +48,7 @@ module ActiveSupport
|
|
56
48
|
|
57
49
|
# Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
|
58
50
|
# FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
|
59
|
-
def add(severity, message = nil, progname = nil, &block)
|
51
|
+
def add(severity, message = nil, progname = nil, &block) # :nodoc:
|
60
52
|
severity ||= UNKNOWN
|
61
53
|
progname ||= @progname
|
62
54
|
|
@@ -84,7 +84,7 @@ module ActiveSupport
|
|
84
84
|
cattr_accessor :use_authenticated_message_encryption, instance_accessor: false, default: false
|
85
85
|
|
86
86
|
class << self
|
87
|
-
def default_cipher
|
87
|
+
def default_cipher # :nodoc:
|
88
88
|
if use_authenticated_message_encryption
|
89
89
|
"aes-256-gcm"
|
90
90
|
else
|
@@ -93,7 +93,7 @@ module ActiveSupport
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
module NullSerializer
|
96
|
+
module NullSerializer # :nodoc:
|
97
97
|
def self.load(value)
|
98
98
|
value
|
99
99
|
end
|
@@ -103,7 +103,7 @@ module ActiveSupport
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
-
module NullVerifier
|
106
|
+
module NullVerifier # :nodoc:
|
107
107
|
def self.verify(value)
|
108
108
|
value
|
109
109
|
end
|
@@ -68,8 +68,8 @@ module ActiveSupport
|
|
68
68
|
# return the original value. But messages can be set to expire at a given
|
69
69
|
# time with +:expires_in+ or +:expires_at+.
|
70
70
|
#
|
71
|
-
# @verifier.generate(parcel, expires_in: 1.month)
|
72
|
-
# @verifier.generate(doowad, expires_at: Time.now.end_of_year)
|
71
|
+
# @verifier.generate("parcel", expires_in: 1.month)
|
72
|
+
# @verifier.generate("doowad", expires_at: Time.now.end_of_year)
|
73
73
|
#
|
74
74
|
# Then the messages can be verified and returned up to the expire time.
|
75
75
|
# Thereafter, the +verified+ method returns +nil+ while +verify+ raises
|
@@ -78,8 +78,8 @@ module ActiveSupport
|
|
78
78
|
# === Rotating keys
|
79
79
|
#
|
80
80
|
# MessageVerifier also supports rotating out old configurations by falling
|
81
|
-
# back to a stack of verifiers. Call +rotate+ to build and add a verifier
|
82
|
-
#
|
81
|
+
# back to a stack of verifiers. Call +rotate+ to build and add a verifier so
|
82
|
+
# either +verified+ or +verify+ will also try verifying with the fallback.
|
83
83
|
#
|
84
84
|
# By default any rotated verifiers use the values of the primary
|
85
85
|
# verifier unless specified otherwise.
|
@@ -3,8 +3,8 @@
|
|
3
3
|
require "time"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
|
-
module Messages
|
7
|
-
class Metadata
|
6
|
+
module Messages # :nodoc:
|
7
|
+
class Metadata # :nodoc:
|
8
8
|
def initialize(message, expires_at = nil, purpose = nil)
|
9
9
|
@message, @purpose = message, purpose
|
10
10
|
@expires_at = expires_at.is_a?(String) ? parse_expires_at(expires_at) : expires_at
|
@@ -3,11 +3,10 @@
|
|
3
3
|
require "active_support/json"
|
4
4
|
require "active_support/core_ext/string/access"
|
5
5
|
require "active_support/core_ext/string/behavior"
|
6
|
-
require "active_support/core_ext/symbol/starts_ends_with"
|
7
6
|
require "active_support/core_ext/module/delegation"
|
8
7
|
|
9
|
-
module ActiveSupport
|
10
|
-
module Multibyte
|
8
|
+
module ActiveSupport # :nodoc:
|
9
|
+
module Multibyte # :nodoc:
|
11
10
|
# Chars enables you to work transparently with UTF-8 encoding in the Ruby
|
12
11
|
# String class without having extensive knowledge about the encoding. A
|
13
12
|
# Chars object accepts a string upon initialization and proxies String
|
@@ -103,7 +102,7 @@ module ActiveSupport #:nodoc:
|
|
103
102
|
#
|
104
103
|
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
|
105
104
|
def reverse
|
106
|
-
chars(@wrapped_string.
|
105
|
+
chars(@wrapped_string.grapheme_clusters.reverse.join)
|
107
106
|
end
|
108
107
|
|
109
108
|
# Limits the byte size of the string to a number of bytes without breaking
|
@@ -126,16 +125,16 @@ module ActiveSupport #:nodoc:
|
|
126
125
|
|
127
126
|
# Performs canonical decomposition on all the characters.
|
128
127
|
#
|
129
|
-
# 'é'.length # =>
|
130
|
-
# 'é'.mb_chars.decompose.to_s.length # =>
|
128
|
+
# 'é'.length # => 1
|
129
|
+
# 'é'.mb_chars.decompose.to_s.length # => 2
|
131
130
|
def decompose
|
132
131
|
chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack("U*"))
|
133
132
|
end
|
134
133
|
|
135
134
|
# Performs composition on all the characters.
|
136
135
|
#
|
137
|
-
# 'é'.length # =>
|
138
|
-
# 'é'.mb_chars.compose.to_s.length # =>
|
136
|
+
# 'é'.length # => 1
|
137
|
+
# 'é'.mb_chars.compose.to_s.length # => 1
|
139
138
|
def compose
|
140
139
|
chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack("U*"))
|
141
140
|
end
|
@@ -143,9 +142,9 @@ module ActiveSupport #:nodoc:
|
|
143
142
|
# Returns the number of grapheme clusters in the string.
|
144
143
|
#
|
145
144
|
# 'क्षि'.mb_chars.length # => 4
|
146
|
-
# 'क्षि'.mb_chars.grapheme_length # =>
|
145
|
+
# 'क्षि'.mb_chars.grapheme_length # => 2
|
147
146
|
def grapheme_length
|
148
|
-
@wrapped_string.
|
147
|
+
@wrapped_string.grapheme_clusters.length
|
149
148
|
end
|
150
149
|
|
151
150
|
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
@@ -157,7 +156,7 @@ module ActiveSupport #:nodoc:
|
|
157
156
|
chars(Unicode.tidy_bytes(@wrapped_string, force))
|
158
157
|
end
|
159
158
|
|
160
|
-
def as_json(options = nil)
|
159
|
+
def as_json(options = nil) # :nodoc:
|
161
160
|
to_s.as_json(options)
|
162
161
|
end
|
163
162
|
|
@@ -24,12 +24,15 @@ module ActiveSupport
|
|
24
24
|
def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
|
25
25
|
subscriber = Subscribers.new(pattern, callable || block, monotonic)
|
26
26
|
synchronize do
|
27
|
-
|
27
|
+
case pattern
|
28
|
+
when String
|
28
29
|
@string_subscribers[pattern] << subscriber
|
29
30
|
@listeners_for.delete(pattern)
|
30
|
-
|
31
|
+
when NilClass, Regexp
|
31
32
|
@other_subscribers << subscriber
|
32
33
|
@listeners_for.clear
|
34
|
+
else
|
35
|
+
raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
|
33
36
|
end
|
34
37
|
end
|
35
38
|
subscriber
|
@@ -67,6 +70,10 @@ module ActiveSupport
|
|
67
70
|
listeners_for(name).each { |s| s.publish(name, *args) }
|
68
71
|
end
|
69
72
|
|
73
|
+
def publish_event(event)
|
74
|
+
listeners_for(event.name).each { |s| s.publish_event(event) }
|
75
|
+
end
|
76
|
+
|
70
77
|
def listeners_for(name)
|
71
78
|
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
|
72
79
|
@listeners_for[name] || synchronize do
|
@@ -91,13 +98,13 @@ module ActiveSupport
|
|
91
98
|
if listener.respond_to?(:start) && listener.respond_to?(:finish)
|
92
99
|
subscriber_class = Evented
|
93
100
|
else
|
94
|
-
# Doing
|
95
|
-
# `proc {
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
+
# Doing this to detect a single argument block or callable
|
102
|
+
# like `proc { |x| }` vs `proc { |*x| }`, `proc { |**x| }`,
|
103
|
+
# or `proc { |x, **y| }`
|
104
|
+
procish = listener.respond_to?(:parameters) ? listener : listener.method(:call)
|
105
|
+
|
106
|
+
if procish.arity == 1 && procish.parameters.length == 1
|
107
|
+
subscriber_class = EventObject
|
101
108
|
end
|
102
109
|
end
|
103
110
|
|
@@ -112,7 +119,7 @@ module ActiveSupport
|
|
112
119
|
end
|
113
120
|
end
|
114
121
|
|
115
|
-
class Matcher
|
122
|
+
class Matcher # :nodoc:
|
116
123
|
attr_reader :pattern, :exclusions
|
117
124
|
|
118
125
|
def self.wrap(pattern)
|
@@ -134,13 +141,14 @@ module ActiveSupport
|
|
134
141
|
end
|
135
142
|
end
|
136
143
|
|
137
|
-
class Evented
|
144
|
+
class Evented # :nodoc:
|
138
145
|
attr_reader :pattern
|
139
146
|
|
140
147
|
def initialize(pattern, delegate)
|
141
148
|
@pattern = Matcher.wrap(pattern)
|
142
149
|
@delegate = delegate
|
143
150
|
@can_publish = delegate.respond_to?(:publish)
|
151
|
+
@can_publish_event = delegate.respond_to?(:publish_event)
|
144
152
|
end
|
145
153
|
|
146
154
|
def publish(name, *args)
|
@@ -149,6 +157,14 @@ module ActiveSupport
|
|
149
157
|
end
|
150
158
|
end
|
151
159
|
|
160
|
+
def publish_event(event)
|
161
|
+
if @can_publish_event
|
162
|
+
@delegate.publish_event event
|
163
|
+
else
|
164
|
+
publish(event.name, event.time, event.end, event.transaction_id, event.payload)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
152
168
|
def start(name, id, payload)
|
153
169
|
@delegate.start name, id, payload
|
154
170
|
end
|
@@ -220,6 +236,10 @@ module ActiveSupport
|
|
220
236
|
@delegate.call event
|
221
237
|
end
|
222
238
|
|
239
|
+
def publish_event(event)
|
240
|
+
@delegate.call event
|
241
|
+
end
|
242
|
+
|
223
243
|
private
|
224
244
|
def build_event(name, id, payload)
|
225
245
|
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
@@ -31,6 +31,10 @@ module ActiveSupport
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
def new_event(name, payload = {}) # :nodoc:
|
35
|
+
Event.new(name, nil, nil, @id, payload)
|
36
|
+
end
|
37
|
+
|
34
38
|
# Send a start notification with +name+ and +payload+.
|
35
39
|
def start(name, payload)
|
36
40
|
@notifier.start name, @id, payload
|
@@ -68,6 +72,19 @@ module ActiveSupport
|
|
68
72
|
@allocation_count_finish = 0
|
69
73
|
end
|
70
74
|
|
75
|
+
def record
|
76
|
+
start!
|
77
|
+
begin
|
78
|
+
yield payload if block_given?
|
79
|
+
rescue Exception => e
|
80
|
+
payload[:exception] = [e.class.name, e.message]
|
81
|
+
payload[:exception_object] = e
|
82
|
+
raise e
|
83
|
+
ensure
|
84
|
+
finish!
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
71
88
|
# Record information at the time this event starts
|
72
89
|
def start!
|
73
90
|
@time = now
|
@@ -198,6 +198,10 @@ module ActiveSupport
|
|
198
198
|
notifier.publish(name, *args)
|
199
199
|
end
|
200
200
|
|
201
|
+
def publish_event(event) # :nodoc:
|
202
|
+
notifier.publish_event(event)
|
203
|
+
end
|
204
|
+
|
201
205
|
def instrument(name, payload = {})
|
202
206
|
if notifier.listening?(name)
|
203
207
|
instrumenter.instrument(name, payload) { yield payload if block_given? }
|
@@ -231,6 +235,12 @@ module ActiveSupport
|
|
231
235
|
# ActiveSupport::Notifications.subscribe(/render/) do |event|
|
232
236
|
# @event = event
|
233
237
|
# end
|
238
|
+
#
|
239
|
+
# Raises an error if invalid event name type is passed:
|
240
|
+
#
|
241
|
+
# ActiveSupport::Notifications.subscribe(:render) {|*args| ...}
|
242
|
+
# #=> ArgumentError (pattern must be specified as a String, Regexp or empty)
|
243
|
+
#
|
234
244
|
def subscribe(pattern = nil, callback = nil, &block)
|
235
245
|
notifier.subscribe(pattern, callback, monotonic: false, &block)
|
236
246
|
end
|
@@ -8,16 +8,21 @@ module ActiveSupport
|
|
8
8
|
self.namespace = :currency
|
9
9
|
|
10
10
|
def convert
|
11
|
-
number = self.number.to_s.strip
|
12
11
|
format = options[:format]
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
number_f = valid_float?
|
14
|
+
if number_f
|
15
|
+
if number_f.negative?
|
16
|
+
number_f = number_f.abs
|
17
|
+
format = options[:negative_format] if (number_f * 10**options[:precision]) >= 0.5
|
18
|
+
end
|
19
|
+
number_s = NumberToRoundedConverter.convert(number_f, options)
|
20
|
+
else
|
21
|
+
number_s = number.to_s.strip
|
22
|
+
format = options[:negative_format] if number_s.sub!(/^-/, "")
|
17
23
|
end
|
18
24
|
|
19
|
-
|
20
|
-
format.gsub("%n", rounded_number).gsub("%u", options[:unit])
|
25
|
+
format.gsub("%n", number_s).gsub("%u", options[:unit])
|
21
26
|
end
|
22
27
|
|
23
28
|
private
|
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
|
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
module NumberHelper
|
7
|
-
class NumberToDelimitedConverter < NumberConverter
|
7
|
+
class NumberToDelimitedConverter < NumberConverter # :nodoc:
|
8
8
|
self.validate_float = true
|
9
9
|
|
10
10
|
DEFAULT_DELIMITER_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
|
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
|
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
module NumberHelper
|
7
|
-
class NumberToHumanSizeConverter < NumberConverter
|
7
|
+
class NumberToHumanSizeConverter < NumberConverter # :nodoc:
|
8
8
|
STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb]
|
9
9
|
|
10
10
|
self.namespace = :human
|
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
|
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
module NumberHelper
|
7
|
-
class NumberToPhoneConverter < NumberConverter
|
7
|
+
class NumberToPhoneConverter < NumberConverter # :nodoc:
|
8
8
|
def convert
|
9
9
|
str = country_code(opts[:country_code]).dup
|
10
10
|
str << convert_to_phone_number(number.to_s.strip)
|
@@ -35,16 +35,12 @@ module ActiveSupport
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def absolute_precision(number)
|
38
|
-
if significant && options[:precision] > 0
|
38
|
+
if options[:significant] && options[:precision] > 0
|
39
39
|
options[:precision] - digit_count(convert_to_decimal(number))
|
40
40
|
else
|
41
41
|
options[:precision]
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
45
|
-
def significant
|
46
|
-
options[:significant]
|
47
|
-
end
|
48
44
|
end
|
49
45
|
end
|
50
46
|
end
|
@@ -99,8 +99,6 @@ module ActiveSupport
|
|
99
99
|
# number_to_currency(1234567890.506, locale: :fr) # => "1 234 567 890,51 €"
|
100
100
|
# number_to_currency('123a456') # => "$123a456"
|
101
101
|
#
|
102
|
-
# number_to_currency("123a456", raise: true) # => InvalidNumberError
|
103
|
-
#
|
104
102
|
# number_to_currency(-0.456789, precision: 0)
|
105
103
|
# # => "$0"
|
106
104
|
# number_to_currency(-1234567890.50, negative_format: '(%u%n)')
|