activesupport 6.0.6.1 → 7.1.3.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 +4 -4
- data/CHANGELOG.md +865 -438
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -6
- data/lib/active_support/actionable_error.rb +4 -2
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +30 -10
- data/lib/active_support/benchmarkable.rb +4 -3
- data/lib/active_support/broadcast_logger.rb +250 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +53 -20
- data/lib/active_support/cache/mem_cache_store.rb +208 -63
- data/lib/active_support/cache/memory_store.rb +120 -38
- data/lib/active_support/cache/null_store.rb +16 -2
- data/lib/active_support/cache/redis_cache_store.rb +201 -208
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +73 -66
- data/lib/active_support/cache.rb +539 -261
- data/lib/active_support/callbacks.rb +273 -142
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +53 -7
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +19 -6
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +15 -13
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +19 -29
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +24 -9
- data/lib/active_support/core_ext/date/conversions.rb +18 -16
- data/lib/active_support/core_ext/date_and_time/calculations.rb +27 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
- data/lib/active_support/core_ext/digest/uuid.rb +30 -13
- data/lib/active_support/core_ext/enumerable.rb +146 -72
- data/lib/active_support/core_ext/erb/util.rb +196 -0
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +3 -4
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +4 -4
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +5 -5
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +31 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +51 -20
- data/lib/active_support/core_ext/module/concerning.rb +14 -8
- data/lib/active_support/core_ext/module/delegation.rb +75 -42
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +1 -26
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +82 -73
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
- data/lib/active_support/core_ext/object/duplicable.rb +15 -4
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
- data/lib/active_support/core_ext/object/json.rb +52 -28
- data/lib/active_support/core_ext/object/to_query.rb +2 -4
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +25 -6
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +16 -0
- data/lib/active_support/core_ext/pathname/existence.rb +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +6 -25
- data/lib/active_support/core_ext/range/conversions.rb +34 -13
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/securerandom.rb +25 -13
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +3 -2
- data/lib/active_support/core_ext/string/filters.rb +21 -15
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +51 -10
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +85 -194
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +46 -8
- data/lib/active_support/core_ext/time/conversions.rb +16 -13
- data/lib/active_support/core_ext/time/zones.rb +12 -28
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +54 -22
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- 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 -769
- data/lib/active_support/deprecation/behaviors.rb +77 -38
- data/lib/active_support/deprecation/constant_accessor.rb +5 -4
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +54 -0
- data/lib/active_support/deprecation/instance_delegator.rb +31 -5
- data/lib/active_support/deprecation/method_wrappers.rb +12 -28
- data/lib/active_support/deprecation/proxy_wrappers.rb +40 -25
- data/lib/active_support/deprecation/reporting.rb +76 -16
- data/lib/active_support/deprecation.rb +36 -4
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +150 -68
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +24 -12
- data/lib/active_support/duration.rb +136 -56
- data/lib/active_support/encrypted_configuration.rb +72 -9
- data/lib/active_support/encrypted_file.rb +46 -13
- data/lib/active_support/environment_inquirer.rb +40 -0
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +203 -0
- data/lib/active_support/evented_file_update_checker.rb +86 -137
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +31 -12
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +79 -0
- data/lib/active_support/gem_version.rb +5 -5
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +86 -42
- data/lib/active_support/html_safe_translation.rb +53 -0
- data/lib/active_support/i18n.rb +2 -1
- data/lib/active_support/i18n_railtie.rb +29 -27
- data/lib/active_support/inflector/inflections.rb +26 -9
- data/lib/active_support/inflector/methods.rb +54 -64
- data/lib/active_support/inflector/transliterate.rb +7 -5
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +6 -5
- data/lib/active_support/json/encoding.rb +31 -45
- data/lib/active_support/key_generator.rb +32 -7
- data/lib/active_support/lazy_load_hooks.rb +33 -7
- data/lib/active_support/locale/en.yml +10 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +101 -32
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +24 -25
- data/lib/active_support/message_encryptor.rb +205 -58
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +292 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +237 -86
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +112 -46
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +35 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +15 -52
- data/lib/active_support/multibyte/unicode.rb +8 -122
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +310 -105
- data/lib/active_support/notifications/instrumenter.rb +113 -48
- data/lib/active_support/notifications.rb +56 -29
- data/lib/active_support/number_helper/number_converter.rb +15 -8
- 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_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -5
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +379 -304
- data/lib/active_support/option_merger.rb +11 -18
- data/lib/active_support/ordered_hash.rb +4 -4
- data/lib/active_support/ordered_options.rb +23 -3
- data/lib/active_support/parameter_filter.rb +104 -75
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +90 -6
- data/lib/active_support/reloader.rb +12 -4
- data/lib/active_support/rescuable.rb +18 -16
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +58 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +5 -3
- data/lib/active_support/subscriber.rb +23 -47
- data/lib/active_support/syntax_error_proxy.rb +70 -0
- data/lib/active_support/tagged_logging.rb +84 -23
- data/lib/active_support/test_case.rb +166 -27
- data/lib/active_support/testing/assertions.rb +73 -20
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +32 -0
- data/lib/active_support/testing/deprecation.rb +53 -2
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +30 -29
- data/lib/active_support/testing/method_call_assertions.rb +24 -11
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +16 -95
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/stream.rb +4 -6
- data/lib/active_support/testing/strict_warnings.rb +39 -0
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +89 -19
- data/lib/active_support/time_with_zone.rb +105 -70
- data/lib/active_support/values/time_zone.rb +59 -26
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +4 -11
- 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 +5 -5
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
- data/lib/active_support/xml_mini/rexml.rb +9 -2
- data/lib/active_support/xml_mini.rb +7 -6
- data/lib/active_support.rb +40 -1
- metadata +127 -40
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -23
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/uri.rb +0 -25
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
- data/lib/active_support/per_thread_registry.rb +0 -60
@@ -3,12 +3,14 @@
|
|
3
3
|
require "active_support/inflections"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
|
+
# = Active Support \Inflector
|
7
|
+
#
|
6
8
|
# The Inflector transforms words from singular to plural, class names to table
|
7
9
|
# names, modularized class names to ones without, and class names to foreign
|
8
10
|
# keys. The default inflections for pluralization, singularization, and
|
9
11
|
# uncountable words are kept in inflections.rb.
|
10
12
|
#
|
11
|
-
# The Rails core team has stated patches for the inflections library will not
|
13
|
+
# The \Rails core team has stated patches for the inflections library will not
|
12
14
|
# be accepted in order to avoid breaking legacy applications which may be
|
13
15
|
# relying on errant inflections. If you discover an incorrect inflection and
|
14
16
|
# require it for your application or wish to define rules for languages other
|
@@ -67,13 +69,19 @@ module ActiveSupport
|
|
67
69
|
# camelize(underscore('SSLError')) # => "SslError"
|
68
70
|
def camelize(term, uppercase_first_letter = true)
|
69
71
|
string = term.to_s
|
70
|
-
|
71
|
-
|
72
|
+
# String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent.
|
73
|
+
if !uppercase_first_letter || uppercase_first_letter == :lower
|
74
|
+
string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase! || match }
|
75
|
+
elsif string.match?(/\A[a-z\d]*\z/)
|
76
|
+
return inflections.acronyms[string]&.dup || string.capitalize
|
72
77
|
else
|
73
|
-
string = string.sub(
|
78
|
+
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize! || match }
|
79
|
+
end
|
80
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) do
|
81
|
+
word = $2
|
82
|
+
substituted = inflections.acronyms[word] || word.capitalize! || word
|
83
|
+
$1 ? "::#{substituted}" : substituted
|
74
84
|
end
|
75
|
-
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
|
76
|
-
string.gsub!("/", "::")
|
77
85
|
string
|
78
86
|
end
|
79
87
|
|
@@ -89,11 +97,10 @@ module ActiveSupport
|
|
89
97
|
#
|
90
98
|
# camelize(underscore('SSLError')) # => "SslError"
|
91
99
|
def underscore(camel_cased_word)
|
92
|
-
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
|
100
|
+
return camel_cased_word.to_s.dup unless /[A-Z-]|::/.match?(camel_cased_word)
|
93
101
|
word = camel_cased_word.to_s.gsub("::", "/")
|
94
102
|
word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
|
95
|
-
word.gsub!(/([A-Z
|
96
|
-
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
103
|
+
word.gsub!(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_")
|
97
104
|
word.tr!("-", "_")
|
98
105
|
word.downcase!
|
99
106
|
word
|
@@ -105,7 +112,7 @@ module ActiveSupport
|
|
105
112
|
#
|
106
113
|
# * Applies human inflection rules to the argument.
|
107
114
|
# * Deletes leading underscores, if any.
|
108
|
-
# * Removes
|
115
|
+
# * Removes an "_id" suffix if present.
|
109
116
|
# * Replaces underscores with spaces, if any.
|
110
117
|
# * Downcases all words except acronyms.
|
111
118
|
# * Capitalizes the first word.
|
@@ -119,7 +126,7 @@ module ActiveSupport
|
|
119
126
|
# humanize('author_id') # => "Author"
|
120
127
|
# humanize('author_id', capitalize: false) # => "author"
|
121
128
|
# humanize('_id') # => "Id"
|
122
|
-
# humanize('author_id', keep_id_suffix: true) # => "Author
|
129
|
+
# humanize('author_id', keep_id_suffix: true) # => "Author id"
|
123
130
|
#
|
124
131
|
# If "SSL" was defined to be an acronym:
|
125
132
|
#
|
@@ -130,54 +137,65 @@ module ActiveSupport
|
|
130
137
|
|
131
138
|
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
132
139
|
|
133
|
-
result.sub!(/\A_+/, "")
|
134
|
-
unless keep_id_suffix
|
135
|
-
result.sub!(/_id\z/, "")
|
136
|
-
end
|
137
140
|
result.tr!("_", " ")
|
141
|
+
result.lstrip!
|
142
|
+
if !keep_id_suffix && lower_case_and_underscored_word&.end_with?("_id")
|
143
|
+
result.delete_suffix!(" id")
|
144
|
+
end
|
138
145
|
|
139
|
-
result.gsub!(/([a-z\d]
|
140
|
-
|
146
|
+
result.gsub!(/([a-z\d]+)/i) do |match|
|
147
|
+
match.downcase!
|
148
|
+
inflections.acronyms[match] || match
|
141
149
|
end
|
142
150
|
|
143
151
|
if capitalize
|
144
|
-
result.sub!(/\A\w/)
|
152
|
+
result.sub!(/\A\w/) do |match|
|
153
|
+
match.upcase!
|
154
|
+
match
|
155
|
+
end
|
145
156
|
end
|
146
157
|
|
147
158
|
result
|
148
159
|
end
|
149
160
|
|
150
|
-
# Converts
|
161
|
+
# Converts the first character in the string to uppercase.
|
151
162
|
#
|
152
163
|
# upcase_first('what a Lovely Day') # => "What a Lovely Day"
|
153
164
|
# upcase_first('w') # => "W"
|
154
165
|
# upcase_first('') # => ""
|
155
166
|
def upcase_first(string)
|
156
|
-
string.length > 0 ? string[0].upcase.concat(string[1..-1]) : ""
|
167
|
+
string.length > 0 ? string[0].upcase.concat(string[1..-1]) : +""
|
168
|
+
end
|
169
|
+
|
170
|
+
# Converts the first character in the string to lowercase.
|
171
|
+
#
|
172
|
+
# downcase_first('If they enjoyed The Matrix') # => "if they enjoyed The Matrix"
|
173
|
+
# downcase_first('I') # => "i"
|
174
|
+
# downcase_first('') # => ""
|
175
|
+
def downcase_first(string)
|
176
|
+
string.length > 0 ? string[0].downcase.concat(string[1..-1]) : +""
|
157
177
|
end
|
158
178
|
|
159
179
|
# Capitalizes all the words and replaces some characters in the string to
|
160
180
|
# create a nicer looking title. +titleize+ is meant for creating pretty
|
161
|
-
# output. It is not used in the Rails internals.
|
181
|
+
# output. It is not used in the \Rails internals.
|
162
182
|
#
|
163
183
|
# The trailing '_id','Id'.. can be kept and capitalized by setting the
|
164
184
|
# optional parameter +keep_id_suffix+ to true.
|
165
185
|
# By default, this parameter is false.
|
166
186
|
#
|
167
|
-
# +titleize+ is also aliased as +titlecase+.
|
168
|
-
#
|
169
187
|
# titleize('man from the boondocks') # => "Man From The Boondocks"
|
170
188
|
# titleize('x-men: the last stand') # => "X Men: The Last Stand"
|
171
189
|
# titleize('TheManWithoutAPast') # => "The Man Without A Past"
|
172
190
|
# titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
|
173
191
|
# titleize('string_ending_with_id', keep_id_suffix: true) # => "String Ending With Id"
|
174
192
|
def titleize(word, keep_id_suffix: false)
|
175
|
-
humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`])[a-z]/) do |match|
|
193
|
+
humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`()])[a-z]/) do |match|
|
176
194
|
match.capitalize
|
177
195
|
end
|
178
196
|
end
|
179
197
|
|
180
|
-
# Creates the name of a table like Rails does for models to table names.
|
198
|
+
# Creates the name of a table like \Rails does for models to table names.
|
181
199
|
# This method uses the #pluralize method on the last word in the string.
|
182
200
|
#
|
183
201
|
# tableize('RawScaledScorer') # => "raw_scaled_scorers"
|
@@ -187,9 +205,9 @@ module ActiveSupport
|
|
187
205
|
pluralize(underscore(class_name))
|
188
206
|
end
|
189
207
|
|
190
|
-
# Creates a class name from a plural table name like Rails does for table
|
191
|
-
# names to models. Note that this returns a string and not a Class (To
|
192
|
-
# convert to an actual class follow +classify+ with #constantize)
|
208
|
+
# Creates a class name from a plural table name like \Rails does for table
|
209
|
+
# names to models. Note that this returns a string and not a Class. (To
|
210
|
+
# convert to an actual class follow +classify+ with #constantize.)
|
193
211
|
#
|
194
212
|
# classify('ham_and_eggs') # => "HamAndEgg"
|
195
213
|
# classify('posts') # => "Post"
|
@@ -220,7 +238,7 @@ module ActiveSupport
|
|
220
238
|
def demodulize(path)
|
221
239
|
path = path.to_s
|
222
240
|
if i = path.rindex("::")
|
223
|
-
path[(i + 2)
|
241
|
+
path[(i + 2), path.length]
|
224
242
|
else
|
225
243
|
path
|
226
244
|
end
|
@@ -269,34 +287,7 @@ module ActiveSupport
|
|
269
287
|
# NameError is raised when the name is not in CamelCase or the constant is
|
270
288
|
# unknown.
|
271
289
|
def constantize(camel_cased_word)
|
272
|
-
|
273
|
-
|
274
|
-
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
275
|
-
Object.const_get(camel_cased_word) if names.empty?
|
276
|
-
|
277
|
-
# Remove the first blank element in case of '::ClassName' notation.
|
278
|
-
names.shift if names.size > 1 && names.first.empty?
|
279
|
-
|
280
|
-
names.inject(Object) do |constant, name|
|
281
|
-
if constant == Object
|
282
|
-
constant.const_get(name)
|
283
|
-
else
|
284
|
-
candidate = constant.const_get(name)
|
285
|
-
next candidate if constant.const_defined?(name, false)
|
286
|
-
next candidate unless Object.const_defined?(name)
|
287
|
-
|
288
|
-
# Go down the ancestors to check if it is owned directly. The check
|
289
|
-
# stops when we reach Object or the end of ancestors tree.
|
290
|
-
constant = constant.ancestors.inject(constant) do |const, ancestor|
|
291
|
-
break const if ancestor == Object
|
292
|
-
break ancestor if ancestor.const_defined?(name, false)
|
293
|
-
const
|
294
|
-
end
|
295
|
-
|
296
|
-
# owner is in Object, so raise
|
297
|
-
constant.const_get(name, false)
|
298
|
-
end
|
299
|
-
end
|
290
|
+
Object.const_get(camel_cased_word)
|
300
291
|
end
|
301
292
|
|
302
293
|
# Tries to find a constant with the name specified in the argument string.
|
@@ -326,10 +317,9 @@ module ActiveSupport
|
|
326
317
|
rescue NameError => e
|
327
318
|
raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
|
328
319
|
e.name.to_s == camel_cased_word.to_s)
|
329
|
-
rescue ArgumentError => e
|
330
|
-
raise unless /not missing constant #{const_regexp(camel_cased_word)}!$/.match?(e.message)
|
331
320
|
rescue LoadError => e
|
332
|
-
|
321
|
+
message = e.respond_to?(:original_message) ? e.original_message : e.message
|
322
|
+
raise unless /Unable to autoload constant #{const_regexp(camel_cased_word)}/.match?(message)
|
333
323
|
end
|
334
324
|
|
335
325
|
# Returns the suffix that should be added to a number to denote the position
|
@@ -367,11 +357,11 @@ module ActiveSupport
|
|
367
357
|
def const_regexp(camel_cased_word)
|
368
358
|
parts = camel_cased_word.split("::")
|
369
359
|
|
370
|
-
return Regexp.escape(camel_cased_word) if parts.
|
360
|
+
return Regexp.escape(camel_cased_word) if parts.empty?
|
371
361
|
|
372
362
|
last = parts.pop
|
373
363
|
|
374
|
-
parts.reverse
|
364
|
+
parts.reverse!.inject(last) do |acc, part|
|
375
365
|
part.empty? ? acc : "#{part}(::#{acc})?"
|
376
366
|
end
|
377
367
|
end
|
@@ -381,8 +371,8 @@ module ActiveSupport
|
|
381
371
|
# If passed an optional +locale+ parameter, the uncountables will be
|
382
372
|
# found for that locale.
|
383
373
|
#
|
384
|
-
#
|
385
|
-
#
|
374
|
+
# apply_inflections('post', inflections.plurals, :en) # => "posts"
|
375
|
+
# apply_inflections('posts', inflections.singulars, :en) # => "post"
|
386
376
|
def apply_inflections(word, rules, locale = :en)
|
387
377
|
result = word.to_s.dup
|
388
378
|
|
@@ -5,6 +5,8 @@ require "active_support/i18n"
|
|
5
5
|
|
6
6
|
module ActiveSupport
|
7
7
|
module Inflector
|
8
|
+
ALLOWED_ENCODINGS_FOR_TRANSLITERATE = [Encoding::UTF_8, Encoding::US_ASCII, Encoding::GB18030].freeze
|
9
|
+
|
8
10
|
# Replaces non-ASCII characters with an ASCII approximation, or if none
|
9
11
|
# exists, a replacement character which defaults to "?".
|
10
12
|
#
|
@@ -57,14 +59,14 @@ module ActiveSupport
|
|
57
59
|
# transliterate('Jürgen', locale: :de)
|
58
60
|
# # => "Juergen"
|
59
61
|
#
|
60
|
-
# Transliteration is restricted to UTF-8, US-ASCII and GB18030 strings
|
62
|
+
# Transliteration is restricted to UTF-8, US-ASCII, and GB18030 strings.
|
61
63
|
# Other encodings will raise an ArgumentError.
|
62
64
|
def transliterate(string, replacement = "?", locale: nil)
|
63
|
-
string = string.dup if string.frozen?
|
64
65
|
raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
|
66
|
+
raise ArgumentError, "Cannot transliterate strings with #{string.encoding} encoding" unless ALLOWED_ENCODINGS_FOR_TRANSLITERATE.include?(string.encoding)
|
65
67
|
|
66
|
-
|
67
|
-
|
68
|
+
return string.dup if string.ascii_only?
|
69
|
+
string = string.dup if string.frozen?
|
68
70
|
|
69
71
|
input_encoding = string.encoding
|
70
72
|
|
@@ -117,7 +119,7 @@ module ActiveSupport
|
|
117
119
|
# If the optional parameter +locale+ is specified,
|
118
120
|
# the word will be parameterized as a word of that language.
|
119
121
|
# By default, this parameter is set to <tt>nil</tt> and it will use
|
120
|
-
# the configured <tt>I18n.locale
|
122
|
+
# the configured <tt>I18n.locale</tt>.
|
121
123
|
def parameterize(string, separator: "-", preserve_case: false, locale: nil)
|
122
124
|
# Replace accented chars with their ASCII equivalents.
|
123
125
|
parameterized_string = transliterate(string, locale: locale)
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fiber"
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
module IsolatedExecutionState # :nodoc:
|
7
|
+
@isolation_level = nil
|
8
|
+
|
9
|
+
Thread.attr_accessor :active_support_execution_state
|
10
|
+
Fiber.attr_accessor :active_support_execution_state
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_reader :isolation_level, :scope
|
14
|
+
|
15
|
+
def isolation_level=(level)
|
16
|
+
return if level == @isolation_level
|
17
|
+
|
18
|
+
unless %i(thread fiber).include?(level)
|
19
|
+
raise ArgumentError, "isolation_level must be `:thread` or `:fiber`, got: `#{level.inspect}`"
|
20
|
+
end
|
21
|
+
|
22
|
+
clear if @isolation_level
|
23
|
+
|
24
|
+
@scope =
|
25
|
+
case level
|
26
|
+
when :thread; Thread
|
27
|
+
when :fiber; Fiber
|
28
|
+
end
|
29
|
+
|
30
|
+
@isolation_level = level
|
31
|
+
end
|
32
|
+
|
33
|
+
def unique_id
|
34
|
+
self[:__id__] ||= Object.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def [](key)
|
38
|
+
state[key]
|
39
|
+
end
|
40
|
+
|
41
|
+
def []=(key, value)
|
42
|
+
state[key] = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def key?(key)
|
46
|
+
state.key?(key)
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete(key)
|
50
|
+
state.delete(key)
|
51
|
+
end
|
52
|
+
|
53
|
+
def clear
|
54
|
+
state.clear
|
55
|
+
end
|
56
|
+
|
57
|
+
def context
|
58
|
+
scope.current
|
59
|
+
end
|
60
|
+
|
61
|
+
def share_with(other)
|
62
|
+
# Action Controller streaming spawns a new thread and copy thread locals.
|
63
|
+
# We do the same here for backward compatibility, but this is very much a hack
|
64
|
+
# and streaming should be rethought.
|
65
|
+
context.active_support_execution_state = other.active_support_execution_state.dup
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def state
|
70
|
+
context.active_support_execution_state ||= {}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
self.isolation_level = :thread
|
75
|
+
end
|
76
|
+
end
|
@@ -5,13 +5,13 @@ require "active_support/core_ext/module/delegation"
|
|
5
5
|
require "json"
|
6
6
|
|
7
7
|
module ActiveSupport
|
8
|
-
# Look for and parse
|
8
|
+
# Look for and parse JSON strings that look like ISO 8601 times.
|
9
9
|
mattr_accessor :parse_json_times
|
10
10
|
|
11
11
|
module JSON
|
12
12
|
# matches YAML-formatted dates
|
13
|
-
DATE_REGEX =
|
14
|
-
DATETIME_REGEX =
|
13
|
+
DATE_REGEX = /\A\d{4}-\d{2}-\d{2}\z/
|
14
|
+
DATETIME_REGEX = /\A(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)\z/
|
15
15
|
|
16
16
|
class << self
|
17
17
|
# Parses a JSON string (JavaScript Object Notation) into a hash.
|
@@ -28,6 +28,7 @@ module ActiveSupport
|
|
28
28
|
data
|
29
29
|
end
|
30
30
|
end
|
31
|
+
alias_method :load, :decode
|
31
32
|
|
32
33
|
# Returns the class of the error that will be raised when there is an
|
33
34
|
# error in decoding JSON. Using this method means you won't directly
|
@@ -63,8 +64,8 @@ module ActiveSupport
|
|
63
64
|
when Array
|
64
65
|
data.map! { |d| convert_dates_from(d) }
|
65
66
|
when Hash
|
66
|
-
data.
|
67
|
-
|
67
|
+
data.transform_values! do |value|
|
68
|
+
convert_dates_from(value)
|
68
69
|
end
|
69
70
|
else
|
70
71
|
data
|
@@ -18,12 +18,15 @@ module ActiveSupport
|
|
18
18
|
#
|
19
19
|
# ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
|
20
20
|
# # => "{\"team\":\"rails\",\"players\":\"36\"}"
|
21
|
-
|
22
|
-
|
21
|
+
class << self
|
22
|
+
def encode(value, options = nil)
|
23
|
+
Encoding.json_encoder.new(options).encode(value)
|
24
|
+
end
|
25
|
+
alias_method :dump, :encode
|
23
26
|
end
|
24
27
|
|
25
|
-
module Encoding
|
26
|
-
class JSONGemEncoder
|
28
|
+
module Encoding # :nodoc:
|
29
|
+
class JSONGemEncoder # :nodoc:
|
27
30
|
attr_reader :options
|
28
31
|
|
29
32
|
def initialize(options = nil)
|
@@ -32,49 +35,27 @@ module ActiveSupport
|
|
32
35
|
|
33
36
|
# Encode the given object into a JSON string
|
34
37
|
def encode(value)
|
35
|
-
|
36
|
-
|
38
|
+
unless options.empty?
|
39
|
+
value = value.as_json(options.dup)
|
40
|
+
end
|
41
|
+
json = stringify(jsonify(value))
|
37
42
|
|
38
|
-
private
|
39
43
|
# Rails does more escaping than the JSON gem natively does (we
|
40
44
|
# escape \u2028 and \u2029 and optionally >, <, & to work around
|
41
45
|
# certain browser problems).
|
42
|
-
|
43
|
-
"
|
44
|
-
"
|
45
|
-
"
|
46
|
-
"<" => '\u003c',
|
47
|
-
"&" => '\u0026',
|
48
|
-
}
|
49
|
-
|
50
|
-
ESCAPE_REGEX_WITH_HTML_ENTITIES = /[\u2028\u2029><&]/u
|
51
|
-
ESCAPE_REGEX_WITHOUT_HTML_ENTITIES = /[\u2028\u2029]/u
|
52
|
-
|
53
|
-
# This class wraps all the strings we see and does the extra escaping
|
54
|
-
class EscapedString < String #:nodoc:
|
55
|
-
def to_json(*)
|
56
|
-
if Encoding.escape_html_entities_in_json
|
57
|
-
s = super
|
58
|
-
s.gsub! ESCAPE_REGEX_WITH_HTML_ENTITIES, ESCAPED_CHARS
|
59
|
-
s
|
60
|
-
else
|
61
|
-
s = super
|
62
|
-
s.gsub! ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, ESCAPED_CHARS
|
63
|
-
s
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def to_s
|
68
|
-
self
|
69
|
-
end
|
46
|
+
if Encoding.escape_html_entities_in_json
|
47
|
+
json.gsub!(">", '\u003e')
|
48
|
+
json.gsub!("<", '\u003c')
|
49
|
+
json.gsub!("&", '\u0026')
|
70
50
|
end
|
51
|
+
json.gsub!("\u2028", '\u2028')
|
52
|
+
json.gsub!("\u2029", '\u2029')
|
53
|
+
json
|
54
|
+
end
|
71
55
|
|
72
|
-
|
73
|
-
private_constant :ESCAPED_CHARS, :ESCAPE_REGEX_WITH_HTML_ENTITIES,
|
74
|
-
:ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, :EscapedString
|
75
|
-
|
56
|
+
private
|
76
57
|
# Convert an object into a "JSON-ready" representation composed of
|
77
|
-
# primitives like Hash, Array, String, Numeric,
|
58
|
+
# primitives like Hash, Array, String, Symbol, Numeric,
|
78
59
|
# and +true+/+false+/+nil+.
|
79
60
|
# Recursively calls #as_json to the object to recursively build a
|
80
61
|
# fully JSON-ready object.
|
@@ -88,12 +69,17 @@ module ActiveSupport
|
|
88
69
|
# calls.
|
89
70
|
def jsonify(value)
|
90
71
|
case value
|
91
|
-
when String
|
92
|
-
|
93
|
-
when Numeric
|
72
|
+
when String, Integer, Symbol, nil, true, false
|
73
|
+
value
|
74
|
+
when Numeric
|
94
75
|
value.as_json
|
95
76
|
when Hash
|
96
|
-
|
77
|
+
result = {}
|
78
|
+
value.each do |k, v|
|
79
|
+
k = k.to_s unless String === k
|
80
|
+
result[k] = jsonify(v)
|
81
|
+
end
|
82
|
+
result
|
97
83
|
when Array
|
98
84
|
value.map { |v| jsonify(v) }
|
99
85
|
else
|
@@ -120,7 +106,7 @@ module ActiveSupport
|
|
120
106
|
# Defaults to 3 (equivalent to millisecond precision)
|
121
107
|
attr_accessor :time_precision
|
122
108
|
|
123
|
-
# Sets the encoder used by Rails to encode Ruby objects into JSON strings
|
109
|
+
# Sets the encoder used by \Rails to encode Ruby objects into JSON strings
|
124
110
|
# in +Object#to_json+ and +ActiveSupport::JSON.encode+.
|
125
111
|
attr_accessor :json_encoder
|
126
112
|
end
|
@@ -4,29 +4,54 @@ require "concurrent/map"
|
|
4
4
|
require "openssl"
|
5
5
|
|
6
6
|
module ActiveSupport
|
7
|
+
# = Key Generator
|
8
|
+
#
|
7
9
|
# KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2.
|
8
10
|
# It can be used to derive a number of keys for various purposes from a given secret.
|
9
|
-
# This lets Rails applications have a single secure secret, but avoid reusing that
|
11
|
+
# This lets \Rails applications have a single secure secret, but avoid reusing that
|
10
12
|
# key in multiple incompatible contexts.
|
11
13
|
class KeyGenerator
|
14
|
+
class << self
|
15
|
+
def hash_digest_class=(klass)
|
16
|
+
if klass.kind_of?(Class) && klass < OpenSSL::Digest
|
17
|
+
@hash_digest_class = klass
|
18
|
+
else
|
19
|
+
raise ArgumentError, "#{klass} is expected to be an OpenSSL::Digest subclass"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def hash_digest_class
|
24
|
+
@hash_digest_class ||= OpenSSL::Digest::SHA1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
12
28
|
def initialize(secret, options = {})
|
13
29
|
@secret = secret
|
14
30
|
# The default iterations are higher than required for our key derivation uses
|
15
31
|
# on the off chance someone uses this for password storage
|
16
32
|
@iterations = options[:iterations] || 2**16
|
33
|
+
# Also allow configuration here so people can use this to build a rotation
|
34
|
+
# scheme when switching the digest class.
|
35
|
+
@hash_digest_class = options[:hash_digest_class] || self.class.hash_digest_class
|
17
36
|
end
|
18
37
|
|
19
|
-
# Returns a derived key suitable for use. The default key_size is chosen
|
38
|
+
# Returns a derived key suitable for use. The default +key_size+ is chosen
|
20
39
|
# to be compatible with the default settings of ActiveSupport::MessageVerifier.
|
21
|
-
# i.e. OpenSSL::Digest::SHA1#block_length
|
40
|
+
# i.e. <tt>OpenSSL::Digest::SHA1#block_length</tt>
|
22
41
|
def generate_key(salt, key_size = 64)
|
23
|
-
OpenSSL::PKCS5.
|
42
|
+
OpenSSL::PKCS5.pbkdf2_hmac(@secret, salt, @iterations, key_size, @hash_digest_class.new)
|
43
|
+
end
|
44
|
+
|
45
|
+
def inspect # :nodoc:
|
46
|
+
"#<#{self.class.name}:#{'%#016x' % (object_id << 1)}>"
|
24
47
|
end
|
25
48
|
end
|
26
49
|
|
50
|
+
# = Caching Key Generator
|
51
|
+
#
|
27
52
|
# CachingKeyGenerator is a wrapper around KeyGenerator which allows users to avoid
|
28
|
-
# re-executing the key generation process when it's called using the same salt and
|
29
|
-
# key_size
|
53
|
+
# re-executing the key generation process when it's called using the same +salt+ and
|
54
|
+
# +key_size+.
|
30
55
|
class CachingKeyGenerator
|
31
56
|
def initialize(key_generator)
|
32
57
|
@key_generator = key_generator
|
@@ -35,7 +60,7 @@ module ActiveSupport
|
|
35
60
|
|
36
61
|
# Returns a derived key suitable for use.
|
37
62
|
def generate_key(*args)
|
38
|
-
@cache_keys[args.join] ||= @key_generator.generate_key(*args)
|
63
|
+
@cache_keys[args.join("|")] ||= @key_generator.generate_key(*args)
|
39
64
|
end
|
40
65
|
end
|
41
66
|
end
|
@@ -1,14 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
|
-
#
|
4
|
+
# = Lazy Load Hooks
|
5
|
+
#
|
6
|
+
# LazyLoadHooks allows \Rails to lazily load a lot of components and thus
|
5
7
|
# making the app boot faster. Because of this feature now there is no need to
|
6
|
-
# require
|
8
|
+
# require +ActiveRecord::Base+ at boot time purely to apply
|
7
9
|
# configuration. Instead a hook is registered that applies configuration once
|
8
|
-
#
|
10
|
+
# +ActiveRecord::Base+ is loaded. Here +ActiveRecord::Base+ is
|
9
11
|
# used as example but this feature can be applied elsewhere too.
|
10
12
|
#
|
11
|
-
# Here is an example where
|
13
|
+
# Here is an example where on_load method is called to register a hook.
|
12
14
|
#
|
13
15
|
# initializer 'active_record.initialize_timezone' do
|
14
16
|
# ActiveSupport.on_load(:active_record) do
|
@@ -18,10 +20,26 @@ module ActiveSupport
|
|
18
20
|
# end
|
19
21
|
#
|
20
22
|
# When the entirety of +ActiveRecord::Base+ has been
|
21
|
-
# evaluated then
|
23
|
+
# evaluated then run_load_hooks is invoked. The very last line of
|
22
24
|
# +ActiveRecord::Base+ is:
|
23
25
|
#
|
24
26
|
# ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
|
27
|
+
#
|
28
|
+
# run_load_hooks will then execute all the hooks that were registered
|
29
|
+
# with the on_load method. In the case of the above example, it will
|
30
|
+
# execute the block of code that is in the +initializer+.
|
31
|
+
#
|
32
|
+
# Registering a hook that has already run results in that hook executing
|
33
|
+
# immediately. This allows hooks to be nested for code that relies on
|
34
|
+
# multiple lazily loaded components:
|
35
|
+
#
|
36
|
+
# initializer "action_text.renderer" do
|
37
|
+
# ActiveSupport.on_load(:action_controller_base) do
|
38
|
+
# ActiveSupport.on_load(:action_text_content) do
|
39
|
+
# self.default_renderer = Class.new(ActionController::Base).renderer
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# end
|
25
43
|
module LazyLoadHooks
|
26
44
|
def self.extended(base) # :nodoc:
|
27
45
|
base.class_eval do
|
@@ -31,8 +49,9 @@ module ActiveSupport
|
|
31
49
|
end
|
32
50
|
end
|
33
51
|
|
34
|
-
# Declares a block that will be executed when a Rails component is fully
|
35
|
-
# loaded.
|
52
|
+
# Declares a block that will be executed when a \Rails component is fully
|
53
|
+
# loaded. If the component has already loaded, the block is executed
|
54
|
+
# immediately.
|
36
55
|
#
|
37
56
|
# Options:
|
38
57
|
#
|
@@ -46,6 +65,13 @@ module ActiveSupport
|
|
46
65
|
@load_hooks[name] << [block, options]
|
47
66
|
end
|
48
67
|
|
68
|
+
# Executes all blocks registered to +name+ via on_load, using +base+ as the
|
69
|
+
# evaluation context.
|
70
|
+
#
|
71
|
+
# ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
|
72
|
+
#
|
73
|
+
# In the case of the above example, it will execute all hooks registered
|
74
|
+
# for +:active_record+ within the class +ActiveRecord::Base+.
|
49
75
|
def run_load_hooks(name, base = Object)
|
50
76
|
@loaded[name] << base
|
51
77
|
@load_hooks[name].each do |hook, options|
|