activesupport 5.2.7.1 → 6.1.4.6
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 +399 -434
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +29 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache/file_store.rb +34 -34
- data/lib/active_support/cache/mem_cache_store.rb +39 -24
- data/lib/active_support/cache/memory_store.rb +59 -33
- data/lib/active_support/cache/null_store.rb +8 -3
- data/lib/active_support/cache/redis_cache_store.rb +72 -45
- data/lib/active_support/cache/strategy/local_cache.rb +41 -26
- data/lib/active_support/cache.rb +148 -78
- data/lib/active_support/callbacks.rb +81 -64
- data/lib/active_support/concern.rb +70 -3
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configurable.rb +10 -14
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +18 -6
- data/lib/active_support/core_ext/array/conversions.rb +5 -5
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array.rb +1 -1
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +32 -47
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/calculations.rb +6 -5
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
- data/lib/active_support/core_ext/enumerable.rb +171 -75
- data/lib/active_support/core_ext/hash/conversions.rb +3 -3
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +2 -2
- data/lib/active_support/core_ext/hash/keys.rb +1 -30
- data/lib/active_support/core_ext/hash/slice.rb +6 -27
- data/lib/active_support/core_ext/hash.rb +1 -2
- data/lib/active_support/core_ext/integer/multiple.rb +1 -1
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/marshal.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +76 -33
- data/lib/active_support/core_ext/module/introspection.rb +16 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
- data/lib/active_support/core_ext/module.rb +0 -1
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/blank.rb +1 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +7 -114
- data/lib/active_support/core_ext/object/json.rb +14 -2
- data/lib/active_support/core_ext/object/try.rb +17 -7
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/range/compare_range.rb +34 -13
- data/lib/active_support/core_ext/range/conversions.rb +31 -29
- data/lib/active_support/core_ext/range/each.rb +0 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/regexp.rb +8 -5
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +5 -16
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/filters.rb +42 -1
- data/lib/active_support/core_ext/string/inflections.rb +45 -6
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +6 -5
- data/lib/active_support/core_ext/string/output_safety.rb +70 -41
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +51 -3
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +6 -1
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +16 -2
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +109 -34
- data/lib/active_support/deprecation/behaviors.rb +16 -3
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +18 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +59 -9
- data/lib/active_support/duration/iso8601_parser.rb +2 -4
- data/lib/active_support/duration/iso8601_serializer.rb +18 -14
- data/lib/active_support/duration.rb +78 -30
- data/lib/active_support/encrypted_configuration.rb +0 -4
- data/lib/active_support/encrypted_file.rb +22 -4
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +82 -117
- data/lib/active_support/execution_wrapper.rb +2 -1
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/fork_tracker.rb +64 -0
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +70 -42
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +15 -8
- data/lib/active_support/inflector/inflections.rb +2 -7
- data/lib/active_support/inflector/methods.rb +49 -58
- data/lib/active_support/inflector/transliterate.rb +47 -18
- data/lib/active_support/json/decoding.rb +25 -26
- data/lib/active_support/json/encoding.rb +11 -3
- data/lib/active_support/key_generator.rb +1 -33
- data/lib/active_support/lazy_load_hooks.rb +5 -2
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +39 -9
- data/lib/active_support/logger.rb +2 -17
- data/lib/active_support/logger_silence.rb +11 -19
- data/lib/active_support/logger_thread_safe_level.rb +50 -6
- data/lib/active_support/message_encryptor.rb +8 -13
- data/lib/active_support/message_verifier.rb +10 -10
- data/lib/active_support/messages/metadata.rb +11 -2
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +10 -9
- data/lib/active_support/multibyte/chars.rb +10 -68
- data/lib/active_support/multibyte/unicode.rb +15 -327
- data/lib/active_support/notifications/fanout.rb +116 -16
- data/lib/active_support/notifications/instrumenter.rb +71 -9
- data/lib/active_support/notifications.rb +72 -8
- data/lib/active_support/number_helper/number_converter.rb +5 -6
- data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +12 -7
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/number_helper.rb +38 -12
- data/lib/active_support/option_merger.rb +22 -3
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +13 -3
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/rails.rb +1 -10
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/reloader.rb +4 -5
- data/lib/active_support/rescuable.rb +4 -4
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +4 -3
- data/lib/active_support/subscriber.rb +72 -28
- data/lib/active_support/tagged_logging.rb +42 -8
- data/lib/active_support/test_case.rb +91 -0
- data/lib/active_support/testing/assertions.rb +30 -9
- data/lib/active_support/testing/deprecation.rb +0 -1
- data/lib/active_support/testing/file_fixtures.rb +2 -0
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +28 -1
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +51 -0
- data/lib/active_support/testing/stream.rb +1 -2
- data/lib/active_support/testing/time_helpers.rb +47 -12
- data/lib/active_support/time_with_zone.rb +81 -47
- data/lib/active_support/values/time_zone.rb +32 -17
- data/lib/active_support/xml_mini/jdom.rb +2 -3
- data/lib/active_support/xml_mini/libxml.rb +2 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
- data/lib/active_support/xml_mini/nokogiri.rb +2 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
- data/lib/active_support/xml_mini/rexml.rb +10 -3
- data/lib/active_support/xml_mini.rb +2 -10
- data/lib/active_support.rb +14 -1
- metadata +55 -29
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
- data/lib/active_support/core_ext/hash/compact.rb +0 -29
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
- data/lib/active_support/core_ext/module/reachable.rb +0 -11
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
- data/lib/active_support/core_ext/range/include_range.rb +0 -3
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -3,6 +3,8 @@
|
|
3
3
|
require "set"
|
4
4
|
require "pathname"
|
5
5
|
require "concurrent/atomic/atomic_boolean"
|
6
|
+
require "listen"
|
7
|
+
require "active_support/fork_tracker"
|
6
8
|
|
7
9
|
module ActiveSupport
|
8
10
|
# Allows you to "listen" to changes in a file system.
|
@@ -38,48 +40,22 @@ module ActiveSupport
|
|
38
40
|
raise ArgumentError, "A block is required to initialize an EventedFileUpdateChecker"
|
39
41
|
end
|
40
42
|
|
41
|
-
@
|
42
|
-
@
|
43
|
-
|
44
|
-
@dirs = {}
|
45
|
-
dirs.each do |dir, exts|
|
46
|
-
@dirs[@ph.xpath(dir)] = Array(exts).map { |ext| @ph.normalize_extension(ext) }
|
47
|
-
end
|
48
|
-
|
49
|
-
@block = block
|
50
|
-
@updated = Concurrent::AtomicBoolean.new(false)
|
51
|
-
@lcsp = @ph.longest_common_subpath(@dirs.keys)
|
52
|
-
@pid = Process.pid
|
53
|
-
@boot_mutex = Mutex.new
|
54
|
-
|
55
|
-
if (@dtw = directories_to_watch).any?
|
56
|
-
# Loading listen triggers warnings. These are originated by a legit
|
57
|
-
# usage of attr_* macros for private attributes, but adds a lot of noise
|
58
|
-
# to our test suite. Thus, we lazy load it and disable warnings locally.
|
59
|
-
silence_warnings do
|
60
|
-
begin
|
61
|
-
require "listen"
|
62
|
-
rescue LoadError => e
|
63
|
-
raise LoadError, "Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile", e.backtrace
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
boot!
|
43
|
+
@block = block
|
44
|
+
@core = Core.new(files, dirs)
|
45
|
+
ObjectSpace.define_finalizer(self, @core.finalizer)
|
68
46
|
end
|
69
47
|
|
70
48
|
def updated?
|
71
|
-
@
|
72
|
-
|
73
|
-
|
74
|
-
@pid = Process.pid
|
75
|
-
@updated.make_true
|
76
|
-
end
|
49
|
+
if @core.restart?
|
50
|
+
@core.thread_safely(&:restart)
|
51
|
+
@core.updated.make_true
|
77
52
|
end
|
78
|
-
|
53
|
+
|
54
|
+
@core.updated.true?
|
79
55
|
end
|
80
56
|
|
81
57
|
def execute
|
82
|
-
@updated.make_false
|
58
|
+
@core.updated.make_false
|
83
59
|
@block.call
|
84
60
|
end
|
85
61
|
|
@@ -91,115 +67,104 @@ module ActiveSupport
|
|
91
67
|
end
|
92
68
|
end
|
93
69
|
|
94
|
-
|
95
|
-
|
96
|
-
Listen.to(*@dtw, &method(:changed)).start
|
97
|
-
end
|
70
|
+
class Core
|
71
|
+
attr_reader :updated
|
98
72
|
|
99
|
-
def
|
100
|
-
|
101
|
-
|
73
|
+
def initialize(files, dirs)
|
74
|
+
@files = files.map { |file| Pathname(file).expand_path }.to_set
|
75
|
+
|
76
|
+
@dirs = dirs.each_with_object({}) do |(dir, exts), hash|
|
77
|
+
hash[Pathname(dir).expand_path] = Array(exts).map { |ext| ext.to_s.sub(/\A\.?/, ".") }.to_set
|
102
78
|
end
|
103
|
-
end
|
104
79
|
|
105
|
-
|
106
|
-
file = @ph.xpath(file)
|
80
|
+
@common_path = common_path(@dirs.keys)
|
107
81
|
|
108
|
-
|
109
|
-
|
110
|
-
elsif file.directory?
|
111
|
-
false
|
112
|
-
else
|
113
|
-
ext = @ph.normalize_extension(file.extname)
|
82
|
+
@dtw = directories_to_watch
|
83
|
+
@missing = []
|
114
84
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
85
|
+
@updated = Concurrent::AtomicBoolean.new(false)
|
86
|
+
@mutex = Mutex.new
|
87
|
+
|
88
|
+
start
|
89
|
+
@after_fork = ActiveSupport::ForkTracker.after_fork { start }
|
123
90
|
end
|
124
91
|
|
125
|
-
def
|
126
|
-
|
127
|
-
|
128
|
-
|
92
|
+
def finalizer
|
93
|
+
proc do
|
94
|
+
stop
|
95
|
+
ActiveSupport::ForkTracker.unregister(@after_fork)
|
96
|
+
end
|
97
|
+
end
|
129
98
|
|
130
|
-
|
131
|
-
|
132
|
-
|
99
|
+
def thread_safely
|
100
|
+
@mutex.synchronize do
|
101
|
+
yield self
|
133
102
|
end
|
103
|
+
end
|
134
104
|
|
135
|
-
|
105
|
+
def start
|
106
|
+
normalize_dirs!
|
107
|
+
@dtw, @missing = [*@dtw, *@missing].partition(&:exist?)
|
108
|
+
@listener = @dtw.any? ? Listen.to(*@dtw, &method(:changed)) : nil
|
109
|
+
@listener&.start
|
136
110
|
end
|
137
111
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
end
|
112
|
+
def stop
|
113
|
+
@listener&.stop
|
114
|
+
end
|
142
115
|
|
143
|
-
|
144
|
-
|
145
|
-
|
116
|
+
def restart
|
117
|
+
stop
|
118
|
+
start
|
119
|
+
end
|
146
120
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
return if paths.empty?
|
151
|
-
|
152
|
-
lcsp = Pathname.new(paths[0])
|
153
|
-
|
154
|
-
paths[1..-1].each do |path|
|
155
|
-
until ascendant_of?(lcsp, path)
|
156
|
-
if lcsp.root?
|
157
|
-
# If we get here a root directory is not an ascendant of path.
|
158
|
-
# This may happen if there are paths in different drives on
|
159
|
-
# Windows.
|
160
|
-
return
|
161
|
-
else
|
162
|
-
lcsp = lcsp.parent
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
121
|
+
def restart?
|
122
|
+
@missing.any?(&:exist?)
|
123
|
+
end
|
166
124
|
|
167
|
-
|
125
|
+
def normalize_dirs!
|
126
|
+
@dirs.transform_keys! do |dir|
|
127
|
+
dir.exist? ? dir.realpath : dir
|
168
128
|
end
|
129
|
+
end
|
169
130
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
break ascendant if ascendant.directory?
|
174
|
-
end
|
131
|
+
def changed(modified, added, removed)
|
132
|
+
unless @updated.true?
|
133
|
+
@updated.make_true if (modified + added + removed).any? { |f| watching?(f) }
|
175
134
|
end
|
135
|
+
end
|
176
136
|
|
177
|
-
|
178
|
-
|
179
|
-
return dirs if dirs.length < 2
|
137
|
+
def watching?(file)
|
138
|
+
file = Pathname(file)
|
180
139
|
|
181
|
-
|
182
|
-
|
140
|
+
if @files.member?(file)
|
141
|
+
true
|
142
|
+
elsif file.directory?
|
143
|
+
false
|
144
|
+
else
|
145
|
+
ext = file.extname
|
183
146
|
|
184
|
-
|
185
|
-
|
147
|
+
file.dirname.ascend do |dir|
|
148
|
+
matching = @dirs[dir]
|
186
149
|
|
187
|
-
|
188
|
-
|
150
|
+
if matching && (matching.empty? || matching.include?(ext))
|
151
|
+
break true
|
152
|
+
elsif dir == @common_path || dir.root?
|
153
|
+
break false
|
189
154
|
end
|
190
155
|
end
|
191
|
-
|
192
|
-
# Array#- preserves order.
|
193
|
-
dirs - descendants
|
194
156
|
end
|
157
|
+
end
|
195
158
|
|
196
|
-
|
159
|
+
def directories_to_watch
|
160
|
+
dtw = @dirs.keys | @files.map(&:dirname)
|
161
|
+
accounted_for = dtw.to_set + Gem.path.map { |path| Pathname(path) }
|
162
|
+
dtw.reject { |dir| dir.ascend.drop(1).any? { |parent| accounted_for.include?(parent) } }
|
163
|
+
end
|
197
164
|
|
198
|
-
|
199
|
-
|
200
|
-
break true if base == ascendant
|
201
|
-
end
|
202
|
-
end
|
165
|
+
def common_path(paths)
|
166
|
+
paths.map { |path| path.ascend.to_a }.reduce(&:&)&.first
|
203
167
|
end
|
168
|
+
end
|
204
169
|
end
|
205
170
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/callbacks"
|
4
|
+
require "concurrent/hash"
|
4
5
|
|
5
6
|
module ActiveSupport
|
6
7
|
class ExecutionWrapper
|
@@ -65,7 +66,7 @@ module ActiveSupport
|
|
65
66
|
def self.run!(reset: false)
|
66
67
|
if reset
|
67
68
|
lost_instance = active.delete(Thread.current)
|
68
|
-
lost_instance
|
69
|
+
lost_instance&.complete!
|
69
70
|
else
|
70
71
|
return Null if active?
|
71
72
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module ForkTracker # :nodoc:
|
5
|
+
module CoreExt
|
6
|
+
def fork(*)
|
7
|
+
if block_given?
|
8
|
+
super do
|
9
|
+
ForkTracker.check!
|
10
|
+
yield
|
11
|
+
end
|
12
|
+
else
|
13
|
+
unless pid = super
|
14
|
+
ForkTracker.check!
|
15
|
+
end
|
16
|
+
pid
|
17
|
+
end
|
18
|
+
end
|
19
|
+
ruby2_keywords(:fork) if respond_to?(:ruby2_keywords, true)
|
20
|
+
end
|
21
|
+
|
22
|
+
module CoreExtPrivate
|
23
|
+
include CoreExt
|
24
|
+
|
25
|
+
private
|
26
|
+
def fork(*)
|
27
|
+
super
|
28
|
+
end
|
29
|
+
ruby2_keywords(:fork) if respond_to?(:ruby2_keywords, true)
|
30
|
+
end
|
31
|
+
|
32
|
+
@pid = Process.pid
|
33
|
+
@callbacks = []
|
34
|
+
|
35
|
+
class << self
|
36
|
+
def check!
|
37
|
+
if @pid != Process.pid
|
38
|
+
@callbacks.each(&:call)
|
39
|
+
@pid = Process.pid
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def hook!
|
44
|
+
if Process.respond_to?(:fork)
|
45
|
+
::Object.prepend(CoreExtPrivate)
|
46
|
+
::Kernel.prepend(CoreExtPrivate)
|
47
|
+
::Kernel.singleton_class.prepend(CoreExt)
|
48
|
+
::Process.singleton_class.prepend(CoreExt)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def after_fork(&block)
|
53
|
+
@callbacks << block
|
54
|
+
block
|
55
|
+
end
|
56
|
+
|
57
|
+
def unregister(callback)
|
58
|
+
@callbacks.delete(callback)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
ActiveSupport::ForkTracker.hook!
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/hash/keys"
|
4
4
|
require "active_support/core_ext/hash/reverse_merge"
|
5
|
+
require "active_support/core_ext/hash/except"
|
6
|
+
require "active_support/core_ext/hash/slice"
|
5
7
|
|
6
8
|
module ActiveSupport
|
7
9
|
# Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
|
@@ -68,7 +70,7 @@ module ActiveSupport
|
|
68
70
|
super()
|
69
71
|
update(constructor)
|
70
72
|
|
71
|
-
hash = constructor.to_hash
|
73
|
+
hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
|
72
74
|
self.default = hash.default if hash.default
|
73
75
|
self.default_proc = hash.default_proc if hash.default_proc
|
74
76
|
else
|
@@ -90,12 +92,12 @@ module ActiveSupport
|
|
90
92
|
#
|
91
93
|
# This value can be later fetched using either +:key+ or <tt>'key'</tt>.
|
92
94
|
def []=(key, value)
|
93
|
-
regular_writer(convert_key(key), convert_value(value,
|
95
|
+
regular_writer(convert_key(key), convert_value(value, conversion: :assignment))
|
94
96
|
end
|
95
97
|
|
96
98
|
alias_method :store, :[]=
|
97
99
|
|
98
|
-
# Updates the receiver in-place, merging in the
|
100
|
+
# Updates the receiver in-place, merging in the hashes passed as arguments:
|
99
101
|
#
|
100
102
|
# hash_1 = ActiveSupport::HashWithIndifferentAccess.new
|
101
103
|
# hash_1[:key] = 'value'
|
@@ -105,11 +107,14 @@ module ActiveSupport
|
|
105
107
|
#
|
106
108
|
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
|
107
109
|
#
|
108
|
-
#
|
110
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
111
|
+
# hash.update({ "a" => 1 }, { "b" => 2 }) # => { "a" => 1, "b" => 2 }
|
112
|
+
#
|
113
|
+
# The arguments can be either an
|
109
114
|
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
|
110
115
|
# In either case the merge respects the semantics of indifferent access.
|
111
116
|
#
|
112
|
-
# If the argument is a regular hash with keys +:key+ and
|
117
|
+
# If the argument is a regular hash with keys +:key+ and <tt>"key"</tt> only one
|
113
118
|
# of the values end up in the receiver, but which one is unspecified.
|
114
119
|
#
|
115
120
|
# When given a block, the value for duplicated keys will be determined
|
@@ -120,18 +125,15 @@ module ActiveSupport
|
|
120
125
|
# hash_1[:key] = 10
|
121
126
|
# hash_2['key'] = 12
|
122
127
|
# hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
|
123
|
-
def update(
|
124
|
-
if
|
125
|
-
|
128
|
+
def update(*other_hashes, &block)
|
129
|
+
if other_hashes.size == 1
|
130
|
+
update_with_single_argument(other_hashes.first, block)
|
126
131
|
else
|
127
|
-
|
128
|
-
|
129
|
-
value = yield(convert_key(key), self[key], value)
|
130
|
-
end
|
131
|
-
regular_writer(convert_key(key), convert_value(value))
|
132
|
+
other_hashes.each do |other_hash|
|
133
|
+
update_with_single_argument(other_hash, block)
|
132
134
|
end
|
133
|
-
self
|
134
135
|
end
|
136
|
+
self
|
135
137
|
end
|
136
138
|
|
137
139
|
alias_method :merge!, :update
|
@@ -190,20 +192,18 @@ module ActiveSupport
|
|
190
192
|
super(convert_key(key), *extras)
|
191
193
|
end
|
192
194
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
super(*args)
|
206
|
-
end
|
195
|
+
# Same as <tt>Hash#dig</tt> where the key passed as argument can be
|
196
|
+
# either a string or a symbol:
|
197
|
+
#
|
198
|
+
# counters = ActiveSupport::HashWithIndifferentAccess.new
|
199
|
+
# counters[:foo] = { bar: 1 }
|
200
|
+
#
|
201
|
+
# counters.dig('foo', 'bar') # => 1
|
202
|
+
# counters.dig(:foo, :bar) # => 1
|
203
|
+
# counters.dig(:zoo) # => nil
|
204
|
+
def dig(*args)
|
205
|
+
args[0] = convert_key(args[0]) if args.size > 0
|
206
|
+
super(*args)
|
207
207
|
end
|
208
208
|
|
209
209
|
# Same as <tt>Hash#default</tt> where the key passed as argument can be
|
@@ -226,8 +226,8 @@ module ActiveSupport
|
|
226
226
|
# hash[:a] = 'x'
|
227
227
|
# hash[:b] = 'y'
|
228
228
|
# hash.values_at('a', 'b') # => ["x", "y"]
|
229
|
-
def values_at(*
|
230
|
-
|
229
|
+
def values_at(*keys)
|
230
|
+
super(*keys.map { |key| convert_key(key) })
|
231
231
|
end
|
232
232
|
|
233
233
|
# Returns an array of the values at the specified indices, but also
|
@@ -240,8 +240,8 @@ module ActiveSupport
|
|
240
240
|
# hash.fetch_values('a', 'c') { |key| 'z' } # => ["x", "z"]
|
241
241
|
# hash.fetch_values('a', 'c') # => KeyError: key not found: "c"
|
242
242
|
def fetch_values(*indices, &block)
|
243
|
-
indices.
|
244
|
-
end
|
243
|
+
super(*indices.map { |key| convert_key(key) }, &block)
|
244
|
+
end
|
245
245
|
|
246
246
|
# Returns a shallow copy of the hash.
|
247
247
|
#
|
@@ -260,8 +260,8 @@ module ActiveSupport
|
|
260
260
|
# This method has the same semantics of +update+, except it does not
|
261
261
|
# modify the receiver but rather returns a new hash with indifferent
|
262
262
|
# access with the result of the merge.
|
263
|
-
def merge(
|
264
|
-
dup.update(
|
263
|
+
def merge(*hashes, &block)
|
264
|
+
dup.update(*hashes, &block)
|
265
265
|
end
|
266
266
|
|
267
267
|
# Like +merge+ but the other way around: Merges the receiver into the
|
@@ -294,6 +294,15 @@ module ActiveSupport
|
|
294
294
|
super(convert_key(key))
|
295
295
|
end
|
296
296
|
|
297
|
+
# Returns a hash with indifferent access that includes everything except given keys.
|
298
|
+
# hash = { a: "x", b: "y", c: 10 }.with_indifferent_access
|
299
|
+
# hash.except(:a, "b") # => {c: 10}.with_indifferent_access
|
300
|
+
# hash # => { a: "x", b: "y", c: 10 }.with_indifferent_access
|
301
|
+
def except(*keys)
|
302
|
+
slice(*self.keys - keys.map { |key| convert_key(key) })
|
303
|
+
end
|
304
|
+
alias_method :without, :except
|
305
|
+
|
297
306
|
def stringify_keys!; self end
|
298
307
|
def deep_stringify_keys!; self end
|
299
308
|
def stringify_keys; dup end
|
@@ -353,40 +362,59 @@ module ActiveSupport
|
|
353
362
|
set_defaults(_new_hash)
|
354
363
|
|
355
364
|
each do |key, value|
|
356
|
-
_new_hash[key] = convert_value(value,
|
365
|
+
_new_hash[key] = convert_value(value, conversion: :to_hash)
|
357
366
|
end
|
358
367
|
_new_hash
|
359
368
|
end
|
360
369
|
|
361
370
|
private
|
362
|
-
|
363
|
-
key
|
371
|
+
if Symbol.method_defined?(:name)
|
372
|
+
def convert_key(key)
|
373
|
+
key.kind_of?(Symbol) ? key.name : key
|
374
|
+
end
|
375
|
+
else
|
376
|
+
def convert_key(key)
|
377
|
+
key.kind_of?(Symbol) ? key.to_s : key
|
378
|
+
end
|
364
379
|
end
|
365
380
|
|
366
|
-
def convert_value(value,
|
381
|
+
def convert_value(value, conversion: nil)
|
367
382
|
if value.is_a? Hash
|
368
|
-
if
|
383
|
+
if conversion == :to_hash
|
369
384
|
value.to_hash
|
370
385
|
else
|
371
386
|
value.nested_under_indifferent_access
|
372
387
|
end
|
373
388
|
elsif value.is_a?(Array)
|
374
|
-
if
|
389
|
+
if conversion != :assignment || value.frozen?
|
375
390
|
value = value.dup
|
376
391
|
end
|
377
|
-
value.map! { |e| convert_value(e,
|
392
|
+
value.map! { |e| convert_value(e, conversion: conversion) }
|
378
393
|
else
|
379
394
|
value
|
380
395
|
end
|
381
396
|
end
|
382
397
|
|
383
|
-
def set_defaults(target)
|
398
|
+
def set_defaults(target)
|
384
399
|
if default_proc
|
385
400
|
target.default_proc = default_proc.dup
|
386
401
|
else
|
387
402
|
target.default = default
|
388
403
|
end
|
389
404
|
end
|
405
|
+
|
406
|
+
def update_with_single_argument(other_hash, block)
|
407
|
+
if other_hash.is_a? HashWithIndifferentAccess
|
408
|
+
regular_update(other_hash, &block)
|
409
|
+
else
|
410
|
+
other_hash.to_hash.each_pair do |key, value|
|
411
|
+
if block && key?(key)
|
412
|
+
value = block.call(convert_key(key), self[key], value)
|
413
|
+
end
|
414
|
+
regular_writer(convert_key(key), convert_value(value))
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
390
418
|
end
|
391
419
|
end
|
392
420
|
|
data/lib/active_support/i18n.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support"
|
4
|
-
require "active_support/file_update_checker"
|
5
4
|
require "active_support/core_ext/array/wrap"
|
6
5
|
|
7
6
|
# :enddoc:
|
@@ -13,6 +12,8 @@ module I18n
|
|
13
12
|
config.i18n.load_path = []
|
14
13
|
config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
|
15
14
|
|
15
|
+
config.eager_load_namespaces << I18n
|
16
|
+
|
16
17
|
# Set the i18n configuration after initialization since a lot of
|
17
18
|
# configuration is still usually done in application initializers.
|
18
19
|
config.after_initialize do |app|
|
@@ -47,8 +48,10 @@ module I18n
|
|
47
48
|
app.config.i18n.load_path.unshift(*value.flat_map(&:existent))
|
48
49
|
when :load_path
|
49
50
|
I18n.load_path += value
|
51
|
+
when :raise_on_missing_translations
|
52
|
+
forward_raise_on_missing_translations_config(app)
|
50
53
|
else
|
51
|
-
I18n.
|
54
|
+
I18n.public_send("#{setting}=", value)
|
52
55
|
end
|
53
56
|
end
|
54
57
|
|
@@ -61,8 +64,6 @@ module I18n
|
|
61
64
|
reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
|
62
65
|
I18n.load_path.keep_if { |p| File.exist?(p) }
|
63
66
|
I18n.load_path |= reloadable_paths.flat_map(&:existent)
|
64
|
-
|
65
|
-
I18n.reload!
|
66
67
|
end
|
67
68
|
|
68
69
|
app.reloaders << reloader
|
@@ -74,6 +75,16 @@ module I18n
|
|
74
75
|
@i18n_inited = true
|
75
76
|
end
|
76
77
|
|
78
|
+
def self.forward_raise_on_missing_translations_config(app)
|
79
|
+
ActiveSupport.on_load(:action_view) do
|
80
|
+
self.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
|
81
|
+
end
|
82
|
+
|
83
|
+
ActiveSupport.on_load(:action_controller) do
|
84
|
+
AbstractController::Translation.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
77
88
|
def self.include_fallbacks_module
|
78
89
|
I18n.backend.class.include(I18n::Backend::Fallbacks)
|
79
90
|
end
|
@@ -91,10 +102,6 @@ module I18n
|
|
91
102
|
[I18n.default_locale]
|
92
103
|
end
|
93
104
|
|
94
|
-
if args.empty? || args.first.is_a?(Hash)
|
95
|
-
args.unshift I18n.default_locale
|
96
|
-
end
|
97
|
-
|
98
105
|
I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
|
99
106
|
end
|
100
107
|
|