activesupport 6.0.0
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 +7 -0
- data/CHANGELOG.md +572 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +40 -0
- data/lib/active_support.rb +96 -0
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -0
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +132 -0
- data/lib/active_support/benchmarkable.rb +51 -0
- data/lib/active_support/builder.rb +8 -0
- data/lib/active_support/cache.rb +830 -0
- data/lib/active_support/cache/file_store.rb +196 -0
- data/lib/active_support/cache/mem_cache_store.rb +212 -0
- data/lib/active_support/cache/memory_store.rb +174 -0
- data/lib/active_support/cache/null_store.rb +48 -0
- data/lib/active_support/cache/redis_cache_store.rb +488 -0
- data/lib/active_support/cache/strategy/local_cache.rb +194 -0
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/callbacks.rb +856 -0
- data/lib/active_support/concern.rb +171 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
- data/lib/active_support/concurrency/share_lock.rb +227 -0
- data/lib/active_support/configurable.rb +146 -0
- data/lib/active_support/core_ext.rb +5 -0
- data/lib/active_support/core_ext/array.rb +9 -0
- data/lib/active_support/core_ext/array/access.rb +104 -0
- data/lib/active_support/core_ext/array/conversions.rb +213 -0
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +31 -0
- data/lib/active_support/core_ext/array/grouping.rb +109 -0
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
- data/lib/active_support/core_ext/array/wrap.rb +48 -0
- data/lib/active_support/core_ext/benchmark.rb +16 -0
- data/lib/active_support/core_ext/big_decimal.rb +3 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
- data/lib/active_support/core_ext/class.rb +4 -0
- data/lib/active_support/core_ext/class/attribute.rb +141 -0
- data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/class/subclasses.rb +54 -0
- data/lib/active_support/core_ext/date.rb +7 -0
- data/lib/active_support/core_ext/date/acts_like.rb +10 -0
- data/lib/active_support/core_ext/date/blank.rb +14 -0
- data/lib/active_support/core_ext/date/calculations.rb +146 -0
- data/lib/active_support/core_ext/date/conversions.rb +96 -0
- data/lib/active_support/core_ext/date/zones.rb +8 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
- data/lib/active_support/core_ext/date_time.rb +7 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
- data/lib/active_support/core_ext/date_time/blank.rb +14 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/digest/uuid.rb +53 -0
- data/lib/active_support/core_ext/enumerable.rb +188 -0
- data/lib/active_support/core_ext/file.rb +3 -0
- data/lib/active_support/core_ext/file/atomic.rb +70 -0
- data/lib/active_support/core_ext/hash.rb +10 -0
- data/lib/active_support/core_ext/hash/compact.rb +5 -0
- data/lib/active_support/core_ext/hash/conversions.rb +263 -0
- data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +24 -0
- data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
- data/lib/active_support/core_ext/hash/keys.rb +143 -0
- data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
- data/lib/active_support/core_ext/hash/slice.rb +26 -0
- data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
- data/lib/active_support/core_ext/integer.rb +5 -0
- data/lib/active_support/core_ext/integer/inflections.rb +31 -0
- data/lib/active_support/core_ext/integer/multiple.rb +12 -0
- data/lib/active_support/core_ext/integer/time.rb +22 -0
- data/lib/active_support/core_ext/kernel.rb +5 -0
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
- data/lib/active_support/core_ext/load_error.rb +9 -0
- data/lib/active_support/core_ext/marshal.rb +24 -0
- data/lib/active_support/core_ext/module.rb +13 -0
- data/lib/active_support/core_ext/module/aliasing.rb +31 -0
- data/lib/active_support/core_ext/module/anonymous.rb +30 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
- data/lib/active_support/core_ext/module/concerning.rb +134 -0
- data/lib/active_support/core_ext/module/delegation.rb +313 -0
- data/lib/active_support/core_ext/module/deprecation.rb +25 -0
- data/lib/active_support/core_ext/module/introspection.rb +86 -0
- data/lib/active_support/core_ext/module/reachable.rb +6 -0
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +17 -0
- data/lib/active_support/core_ext/name_error.rb +38 -0
- data/lib/active_support/core_ext/numeric.rb +5 -0
- data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
- data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
- data/lib/active_support/core_ext/numeric/time.rb +66 -0
- data/lib/active_support/core_ext/object.rb +16 -0
- data/lib/active_support/core_ext/object/acts_like.rb +21 -0
- data/lib/active_support/core_ext/object/blank.rb +155 -0
- data/lib/active_support/core_ext/object/conversions.rb +6 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
- data/lib/active_support/core_ext/object/duplicable.rb +49 -0
- data/lib/active_support/core_ext/object/inclusion.rb +29 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
- data/lib/active_support/core_ext/object/json.rb +228 -0
- data/lib/active_support/core_ext/object/to_param.rb +3 -0
- data/lib/active_support/core_ext/object/to_query.rb +89 -0
- data/lib/active_support/core_ext/object/try.rb +156 -0
- data/lib/active_support/core_ext/object/with_options.rb +82 -0
- data/lib/active_support/core_ext/range.rb +7 -0
- data/lib/active_support/core_ext/range/compare_range.rb +70 -0
- data/lib/active_support/core_ext/range/conversions.rb +41 -0
- data/lib/active_support/core_ext/range/each.rb +25 -0
- data/lib/active_support/core_ext/range/include_range.rb +9 -0
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
- data/lib/active_support/core_ext/range/overlaps.rb +10 -0
- data/lib/active_support/core_ext/regexp.rb +7 -0
- data/lib/active_support/core_ext/securerandom.rb +45 -0
- data/lib/active_support/core_ext/string.rb +15 -0
- data/lib/active_support/core_ext/string/access.rb +114 -0
- data/lib/active_support/core_ext/string/behavior.rb +8 -0
- data/lib/active_support/core_ext/string/conversions.rb +59 -0
- data/lib/active_support/core_ext/string/exclude.rb +13 -0
- data/lib/active_support/core_ext/string/filters.rb +145 -0
- data/lib/active_support/core_ext/string/indent.rb +45 -0
- data/lib/active_support/core_ext/string/inflections.rb +259 -0
- data/lib/active_support/core_ext/string/inquiry.rb +15 -0
- data/lib/active_support/core_ext/string/multibyte.rb +58 -0
- data/lib/active_support/core_ext/string/output_safety.rb +314 -0
- data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/string/strip.rb +27 -0
- data/lib/active_support/core_ext/string/zones.rb +16 -0
- data/lib/active_support/core_ext/time.rb +7 -0
- data/lib/active_support/core_ext/time/acts_like.rb +10 -0
- data/lib/active_support/core_ext/time/calculations.rb +344 -0
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +72 -0
- data/lib/active_support/core_ext/time/zones.rb +113 -0
- data/lib/active_support/core_ext/uri.rb +25 -0
- data/lib/active_support/current_attributes.rb +203 -0
- data/lib/active_support/dependencies.rb +806 -0
- data/lib/active_support/dependencies/autoload.rb +79 -0
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
- data/lib/active_support/deprecation.rb +46 -0
- data/lib/active_support/deprecation/behaviors.rb +109 -0
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/instance_delegator.rb +39 -0
- data/lib/active_support/deprecation/method_wrappers.rb +78 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
- data/lib/active_support/deprecation/reporting.rb +114 -0
- data/lib/active_support/descendants_tracker.rb +109 -0
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration.rb +433 -0
- data/lib/active_support/duration/iso8601_parser.rb +124 -0
- data/lib/active_support/duration/iso8601_serializer.rb +54 -0
- data/lib/active_support/encrypted_configuration.rb +45 -0
- data/lib/active_support/encrypted_file.rb +100 -0
- data/lib/active_support/evented_file_update_checker.rb +235 -0
- data/lib/active_support/execution_wrapper.rb +129 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +163 -0
- data/lib/active_support/gem_version.rb +17 -0
- data/lib/active_support/gzip.rb +38 -0
- data/lib/active_support/hash_with_indifferent_access.rb +399 -0
- data/lib/active_support/i18n.rb +16 -0
- data/lib/active_support/i18n_railtie.rb +126 -0
- data/lib/active_support/inflections.rb +72 -0
- data/lib/active_support/inflector.rb +9 -0
- data/lib/active_support/inflector/inflections.rb +257 -0
- data/lib/active_support/inflector/methods.rb +398 -0
- data/lib/active_support/inflector/transliterate.rb +147 -0
- data/lib/active_support/json.rb +4 -0
- data/lib/active_support/json/decoding.rb +76 -0
- data/lib/active_support/json/encoding.rb +134 -0
- data/lib/active_support/key_generator.rb +41 -0
- data/lib/active_support/lazy_load_hooks.rb +82 -0
- data/lib/active_support/locale/en.rb +31 -0
- data/lib/active_support/locale/en.yml +135 -0
- data/lib/active_support/log_subscriber.rb +135 -0
- data/lib/active_support/log_subscriber/test_helper.rb +106 -0
- data/lib/active_support/logger.rb +93 -0
- data/lib/active_support/logger_silence.rb +45 -0
- data/lib/active_support/logger_thread_safe_level.rb +56 -0
- data/lib/active_support/message_encryptor.rb +227 -0
- data/lib/active_support/message_verifier.rb +205 -0
- data/lib/active_support/messages/metadata.rb +71 -0
- data/lib/active_support/messages/rotation_configuration.rb +22 -0
- data/lib/active_support/messages/rotator.rb +56 -0
- data/lib/active_support/multibyte.rb +23 -0
- data/lib/active_support/multibyte/chars.rb +216 -0
- data/lib/active_support/multibyte/unicode.rb +157 -0
- data/lib/active_support/notifications.rb +253 -0
- data/lib/active_support/notifications/fanout.rb +244 -0
- data/lib/active_support/notifications/instrumenter.rb +164 -0
- data/lib/active_support/number_helper.rb +378 -0
- data/lib/active_support/number_helper/number_converter.rb +184 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
- data/lib/active_support/number_helper/rounding_helper.rb +66 -0
- data/lib/active_support/option_merger.rb +27 -0
- data/lib/active_support/ordered_hash.rb +50 -0
- data/lib/active_support/ordered_options.rb +85 -0
- data/lib/active_support/parameter_filter.rb +129 -0
- data/lib/active_support/per_thread_registry.rb +60 -0
- data/lib/active_support/proxy_object.rb +15 -0
- data/lib/active_support/rails.rb +29 -0
- data/lib/active_support/railtie.rb +80 -0
- data/lib/active_support/reloader.rb +130 -0
- data/lib/active_support/rescuable.rb +174 -0
- data/lib/active_support/security_utils.rb +31 -0
- data/lib/active_support/string_inquirer.rb +34 -0
- data/lib/active_support/subscriber.rb +169 -0
- data/lib/active_support/tagged_logging.rb +88 -0
- data/lib/active_support/test_case.rb +163 -0
- data/lib/active_support/testing/assertions.rb +228 -0
- data/lib/active_support/testing/autorun.rb +7 -0
- data/lib/active_support/testing/constant_lookup.rb +51 -0
- data/lib/active_support/testing/declarative.rb +28 -0
- data/lib/active_support/testing/deprecation.rb +38 -0
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +110 -0
- data/lib/active_support/testing/method_call_assertions.rb +70 -0
- data/lib/active_support/testing/parallelization.rb +128 -0
- data/lib/active_support/testing/setup_and_teardown.rb +55 -0
- data/lib/active_support/testing/stream.rb +44 -0
- data/lib/active_support/testing/tagged_logging.rb +27 -0
- data/lib/active_support/testing/time_helpers.rb +200 -0
- data/lib/active_support/time.rb +20 -0
- data/lib/active_support/time_with_zone.rb +561 -0
- data/lib/active_support/values/time_zone.rb +570 -0
- data/lib/active_support/version.rb +10 -0
- data/lib/active_support/xml_mini.rb +202 -0
- data/lib/active_support/xml_mini/jdom.rb +183 -0
- data/lib/active_support/xml_mini/libxml.rb +80 -0
- data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
- data/lib/active_support/xml_mini/nokogiri.rb +83 -0
- data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
- data/lib/active_support/xml_mini/rexml.rb +130 -0
- metadata +385 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/callbacks"
|
|
4
|
+
require "concurrent/hash"
|
|
5
|
+
|
|
6
|
+
module ActiveSupport
|
|
7
|
+
class ExecutionWrapper
|
|
8
|
+
include ActiveSupport::Callbacks
|
|
9
|
+
|
|
10
|
+
Null = Object.new # :nodoc:
|
|
11
|
+
def Null.complete! # :nodoc:
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
define_callbacks :run
|
|
15
|
+
define_callbacks :complete
|
|
16
|
+
|
|
17
|
+
def self.to_run(*args, &block)
|
|
18
|
+
set_callback(:run, *args, &block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.to_complete(*args, &block)
|
|
22
|
+
set_callback(:complete, *args, &block)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
RunHook = Struct.new(:hook) do # :nodoc:
|
|
26
|
+
def before(target)
|
|
27
|
+
hook_state = target.send(:hook_state)
|
|
28
|
+
hook_state[hook] = hook.run
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
CompleteHook = Struct.new(:hook) do # :nodoc:
|
|
33
|
+
def before(target)
|
|
34
|
+
hook_state = target.send(:hook_state)
|
|
35
|
+
if hook_state.key?(hook)
|
|
36
|
+
hook.complete hook_state[hook]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
alias after before
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Register an object to be invoked during both the +run+ and
|
|
43
|
+
# +complete+ steps.
|
|
44
|
+
#
|
|
45
|
+
# +hook.complete+ will be passed the value returned from +hook.run+,
|
|
46
|
+
# and will only be invoked if +run+ has previously been called.
|
|
47
|
+
# (Mostly, this means it won't be invoked if an exception occurs in
|
|
48
|
+
# a preceding +to_run+ block; all ordinary +to_complete+ blocks are
|
|
49
|
+
# invoked in that situation.)
|
|
50
|
+
def self.register_hook(hook, outer: false)
|
|
51
|
+
if outer
|
|
52
|
+
to_run RunHook.new(hook), prepend: true
|
|
53
|
+
to_complete :after, CompleteHook.new(hook)
|
|
54
|
+
else
|
|
55
|
+
to_run RunHook.new(hook)
|
|
56
|
+
to_complete CompleteHook.new(hook)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Run this execution.
|
|
61
|
+
#
|
|
62
|
+
# Returns an instance, whose +complete!+ method *must* be invoked
|
|
63
|
+
# after the work has been performed.
|
|
64
|
+
#
|
|
65
|
+
# Where possible, prefer +wrap+.
|
|
66
|
+
def self.run!
|
|
67
|
+
if active?
|
|
68
|
+
Null
|
|
69
|
+
else
|
|
70
|
+
new.tap do |instance|
|
|
71
|
+
success = nil
|
|
72
|
+
begin
|
|
73
|
+
instance.run!
|
|
74
|
+
success = true
|
|
75
|
+
ensure
|
|
76
|
+
instance.complete! unless success
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Perform the work in the supplied block as an execution.
|
|
83
|
+
def self.wrap
|
|
84
|
+
return yield if active?
|
|
85
|
+
|
|
86
|
+
instance = run!
|
|
87
|
+
begin
|
|
88
|
+
yield
|
|
89
|
+
ensure
|
|
90
|
+
instance.complete!
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
class << self # :nodoc:
|
|
95
|
+
attr_accessor :active
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def self.inherited(other) # :nodoc:
|
|
99
|
+
super
|
|
100
|
+
other.active = Concurrent::Hash.new
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
self.active = Concurrent::Hash.new
|
|
104
|
+
|
|
105
|
+
def self.active? # :nodoc:
|
|
106
|
+
@active[Thread.current]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def run! # :nodoc:
|
|
110
|
+
self.class.active[Thread.current] = true
|
|
111
|
+
run_callbacks(:run)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Complete this in-flight execution. This method *must* be called
|
|
115
|
+
# exactly once on the result of any call to +run!+.
|
|
116
|
+
#
|
|
117
|
+
# Where possible, prefer +wrap+.
|
|
118
|
+
def complete!
|
|
119
|
+
run_callbacks(:complete)
|
|
120
|
+
ensure
|
|
121
|
+
self.class.active.delete Thread.current
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
def hook_state
|
|
126
|
+
@_hook_state ||= {}
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/time/calculations"
|
|
4
|
+
|
|
5
|
+
module ActiveSupport
|
|
6
|
+
# FileUpdateChecker specifies the API used by Rails to watch files
|
|
7
|
+
# and control reloading. The API depends on four methods:
|
|
8
|
+
#
|
|
9
|
+
# * +initialize+ which expects two parameters and one block as
|
|
10
|
+
# described below.
|
|
11
|
+
#
|
|
12
|
+
# * +updated?+ which returns a boolean if there were updates in
|
|
13
|
+
# the filesystem or not.
|
|
14
|
+
#
|
|
15
|
+
# * +execute+ which executes the given block on initialization
|
|
16
|
+
# and updates the latest watched files and timestamp.
|
|
17
|
+
#
|
|
18
|
+
# * +execute_if_updated+ which just executes the block if it was updated.
|
|
19
|
+
#
|
|
20
|
+
# After initialization, a call to +execute_if_updated+ must execute
|
|
21
|
+
# the block only if there was really a change in the filesystem.
|
|
22
|
+
#
|
|
23
|
+
# This class is used by Rails to reload the I18n framework whenever
|
|
24
|
+
# they are changed upon a new request.
|
|
25
|
+
#
|
|
26
|
+
# i18n_reloader = ActiveSupport::FileUpdateChecker.new(paths) do
|
|
27
|
+
# I18n.reload!
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# ActiveSupport::Reloader.to_prepare do
|
|
31
|
+
# i18n_reloader.execute_if_updated
|
|
32
|
+
# end
|
|
33
|
+
class FileUpdateChecker
|
|
34
|
+
# It accepts two parameters on initialization. The first is an array
|
|
35
|
+
# of files and the second is an optional hash of directories. The hash must
|
|
36
|
+
# have directories as keys and the value is an array of extensions to be
|
|
37
|
+
# watched under that directory.
|
|
38
|
+
#
|
|
39
|
+
# This method must also receive a block that will be called once a path
|
|
40
|
+
# changes. The array of files and list of directories cannot be changed
|
|
41
|
+
# after FileUpdateChecker has been initialized.
|
|
42
|
+
def initialize(files, dirs = {}, &block)
|
|
43
|
+
unless block
|
|
44
|
+
raise ArgumentError, "A block is required to initialize a FileUpdateChecker"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
@files = files.freeze
|
|
48
|
+
@glob = compile_glob(dirs)
|
|
49
|
+
@block = block
|
|
50
|
+
|
|
51
|
+
@watched = nil
|
|
52
|
+
@updated_at = nil
|
|
53
|
+
|
|
54
|
+
@last_watched = watched
|
|
55
|
+
@last_update_at = updated_at(@last_watched)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Check if any of the entries were updated. If so, the watched and/or
|
|
59
|
+
# updated_at values are cached until the block is executed via +execute+
|
|
60
|
+
# or +execute_if_updated+.
|
|
61
|
+
def updated?
|
|
62
|
+
current_watched = watched
|
|
63
|
+
if @last_watched.size != current_watched.size
|
|
64
|
+
@watched = current_watched
|
|
65
|
+
true
|
|
66
|
+
else
|
|
67
|
+
current_updated_at = updated_at(current_watched)
|
|
68
|
+
if @last_update_at < current_updated_at
|
|
69
|
+
@watched = current_watched
|
|
70
|
+
@updated_at = current_updated_at
|
|
71
|
+
true
|
|
72
|
+
else
|
|
73
|
+
false
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Executes the given block and updates the latest watched files and
|
|
79
|
+
# timestamp.
|
|
80
|
+
def execute
|
|
81
|
+
@last_watched = watched
|
|
82
|
+
@last_update_at = updated_at(@last_watched)
|
|
83
|
+
@block.call
|
|
84
|
+
ensure
|
|
85
|
+
@watched = nil
|
|
86
|
+
@updated_at = nil
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Execute the block given if updated.
|
|
90
|
+
def execute_if_updated
|
|
91
|
+
if updated?
|
|
92
|
+
yield if block_given?
|
|
93
|
+
execute
|
|
94
|
+
true
|
|
95
|
+
else
|
|
96
|
+
false
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def watched
|
|
103
|
+
@watched || begin
|
|
104
|
+
all = @files.select { |f| File.exist?(f) }
|
|
105
|
+
all.concat(Dir[@glob]) if @glob
|
|
106
|
+
all
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def updated_at(paths)
|
|
111
|
+
@updated_at || max_mtime(paths) || Time.at(0)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# This method returns the maximum mtime of the files in +paths+, or +nil+
|
|
115
|
+
# if the array is empty.
|
|
116
|
+
#
|
|
117
|
+
# Files with a mtime in the future are ignored. Such abnormal situation
|
|
118
|
+
# can happen for example if the user changes the clock by hand. It is
|
|
119
|
+
# healthy to consider this edge case because with mtimes in the future
|
|
120
|
+
# reloading is not triggered.
|
|
121
|
+
def max_mtime(paths)
|
|
122
|
+
time_now = Time.now
|
|
123
|
+
max_mtime = nil
|
|
124
|
+
|
|
125
|
+
# Time comparisons are performed with #compare_without_coercion because
|
|
126
|
+
# AS redefines these operators in a way that is much slower and does not
|
|
127
|
+
# bring any benefit in this particular code.
|
|
128
|
+
#
|
|
129
|
+
# Read t1.compare_without_coercion(t2) < 0 as t1 < t2.
|
|
130
|
+
paths.each do |path|
|
|
131
|
+
mtime = File.mtime(path)
|
|
132
|
+
|
|
133
|
+
next if time_now.compare_without_coercion(mtime) < 0
|
|
134
|
+
|
|
135
|
+
if max_mtime.nil? || max_mtime.compare_without_coercion(mtime) < 0
|
|
136
|
+
max_mtime = mtime
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
max_mtime
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def compile_glob(hash)
|
|
144
|
+
hash.freeze # Freeze so changes aren't accidentally pushed
|
|
145
|
+
return if hash.empty?
|
|
146
|
+
|
|
147
|
+
globs = hash.map do |key, value|
|
|
148
|
+
"#{escape(key)}/**/*#{compile_ext(value)}"
|
|
149
|
+
end
|
|
150
|
+
"{#{globs.join(",")}}"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def escape(key)
|
|
154
|
+
key.gsub(",", '\,')
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def compile_ext(array)
|
|
158
|
+
array = Array(array)
|
|
159
|
+
return if array.empty?
|
|
160
|
+
".{#{array.join(",")}}"
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
# Returns the version of the currently loaded Active Support as a <tt>Gem::Version</tt>.
|
|
5
|
+
def self.gem_version
|
|
6
|
+
Gem::Version.new VERSION::STRING
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module VERSION
|
|
10
|
+
MAJOR = 6
|
|
11
|
+
MINOR = 0
|
|
12
|
+
TINY = 0
|
|
13
|
+
PRE = nil
|
|
14
|
+
|
|
15
|
+
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zlib"
|
|
4
|
+
require "stringio"
|
|
5
|
+
|
|
6
|
+
module ActiveSupport
|
|
7
|
+
# A convenient wrapper for the zlib standard library that allows
|
|
8
|
+
# compression/decompression of strings with gzip.
|
|
9
|
+
#
|
|
10
|
+
# gzip = ActiveSupport::Gzip.compress('compress me!')
|
|
11
|
+
# # => "\x1F\x8B\b\x00o\x8D\xCDO\x00\x03K\xCE\xCF-(J-.V\xC8MU\x04\x00R>n\x83\f\x00\x00\x00"
|
|
12
|
+
#
|
|
13
|
+
# ActiveSupport::Gzip.decompress(gzip)
|
|
14
|
+
# # => "compress me!"
|
|
15
|
+
module Gzip
|
|
16
|
+
class Stream < StringIO
|
|
17
|
+
def initialize(*)
|
|
18
|
+
super
|
|
19
|
+
set_encoding "BINARY"
|
|
20
|
+
end
|
|
21
|
+
def close; rewind; end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Decompresses a gzipped string.
|
|
25
|
+
def self.decompress(source)
|
|
26
|
+
Zlib::GzipReader.wrap(StringIO.new(source), &:read)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Compresses a string using gzip.
|
|
30
|
+
def self.compress(source, level = Zlib::DEFAULT_COMPRESSION, strategy = Zlib::DEFAULT_STRATEGY)
|
|
31
|
+
output = Stream.new
|
|
32
|
+
gz = Zlib::GzipWriter.new(output, level, strategy)
|
|
33
|
+
gz.write(source)
|
|
34
|
+
gz.close
|
|
35
|
+
output.string
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/hash/keys"
|
|
4
|
+
require "active_support/core_ext/hash/reverse_merge"
|
|
5
|
+
require "active_support/core_ext/hash/except"
|
|
6
|
+
|
|
7
|
+
module ActiveSupport
|
|
8
|
+
# Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
|
|
9
|
+
# to be the same.
|
|
10
|
+
#
|
|
11
|
+
# rgb = ActiveSupport::HashWithIndifferentAccess.new
|
|
12
|
+
#
|
|
13
|
+
# rgb[:black] = '#000000'
|
|
14
|
+
# rgb[:black] # => '#000000'
|
|
15
|
+
# rgb['black'] # => '#000000'
|
|
16
|
+
#
|
|
17
|
+
# rgb['white'] = '#FFFFFF'
|
|
18
|
+
# rgb[:white] # => '#FFFFFF'
|
|
19
|
+
# rgb['white'] # => '#FFFFFF'
|
|
20
|
+
#
|
|
21
|
+
# Internally symbols are mapped to strings when used as keys in the entire
|
|
22
|
+
# writing interface (calling <tt>[]=</tt>, <tt>merge</tt>, etc). This
|
|
23
|
+
# mapping belongs to the public interface. For example, given:
|
|
24
|
+
#
|
|
25
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
|
|
26
|
+
#
|
|
27
|
+
# You are guaranteed that the key is returned as a string:
|
|
28
|
+
#
|
|
29
|
+
# hash.keys # => ["a"]
|
|
30
|
+
#
|
|
31
|
+
# Technically other types of keys are accepted:
|
|
32
|
+
#
|
|
33
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
|
|
34
|
+
# hash[0] = 0
|
|
35
|
+
# hash # => {"a"=>1, 0=>0}
|
|
36
|
+
#
|
|
37
|
+
# but this class is intended for use cases where strings or symbols are the
|
|
38
|
+
# expected keys and it is convenient to understand both as the same. For
|
|
39
|
+
# example the +params+ hash in Ruby on Rails.
|
|
40
|
+
#
|
|
41
|
+
# Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
|
|
42
|
+
#
|
|
43
|
+
# rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access
|
|
44
|
+
#
|
|
45
|
+
# which may be handy.
|
|
46
|
+
#
|
|
47
|
+
# To access this class outside of Rails, require the core extension with:
|
|
48
|
+
#
|
|
49
|
+
# require "active_support/core_ext/hash/indifferent_access"
|
|
50
|
+
#
|
|
51
|
+
# which will, in turn, require this file.
|
|
52
|
+
class HashWithIndifferentAccess < Hash
|
|
53
|
+
# Returns +true+ so that <tt>Array#extract_options!</tt> finds members of
|
|
54
|
+
# this class.
|
|
55
|
+
def extractable_options?
|
|
56
|
+
true
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def with_indifferent_access
|
|
60
|
+
dup
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def nested_under_indifferent_access
|
|
64
|
+
self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def initialize(constructor = {})
|
|
68
|
+
if constructor.respond_to?(:to_hash)
|
|
69
|
+
super()
|
|
70
|
+
update(constructor)
|
|
71
|
+
|
|
72
|
+
hash = constructor.to_hash
|
|
73
|
+
self.default = hash.default if hash.default
|
|
74
|
+
self.default_proc = hash.default_proc if hash.default_proc
|
|
75
|
+
else
|
|
76
|
+
super(constructor)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.[](*args)
|
|
81
|
+
new.merge!(Hash[*args])
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
|
85
|
+
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
|
86
|
+
|
|
87
|
+
# Assigns a new value to the hash:
|
|
88
|
+
#
|
|
89
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
90
|
+
# hash[:key] = 'value'
|
|
91
|
+
#
|
|
92
|
+
# This value can be later fetched using either +:key+ or <tt>'key'</tt>.
|
|
93
|
+
def []=(key, value)
|
|
94
|
+
regular_writer(convert_key(key), convert_value(value, for: :assignment))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
alias_method :store, :[]=
|
|
98
|
+
|
|
99
|
+
# Updates the receiver in-place, merging in the hash passed as argument:
|
|
100
|
+
#
|
|
101
|
+
# hash_1 = ActiveSupport::HashWithIndifferentAccess.new
|
|
102
|
+
# hash_1[:key] = 'value'
|
|
103
|
+
#
|
|
104
|
+
# hash_2 = ActiveSupport::HashWithIndifferentAccess.new
|
|
105
|
+
# hash_2[:key] = 'New Value!'
|
|
106
|
+
#
|
|
107
|
+
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
|
|
108
|
+
#
|
|
109
|
+
# The argument can be either an
|
|
110
|
+
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
|
|
111
|
+
# In either case the merge respects the semantics of indifferent access.
|
|
112
|
+
#
|
|
113
|
+
# If the argument is a regular hash with keys +:key+ and +"key"+ only one
|
|
114
|
+
# of the values end up in the receiver, but which one is unspecified.
|
|
115
|
+
#
|
|
116
|
+
# When given a block, the value for duplicated keys will be determined
|
|
117
|
+
# by the result of invoking the block with the duplicated key, the value
|
|
118
|
+
# in the receiver, and the value in +other_hash+. The rules for duplicated
|
|
119
|
+
# keys follow the semantics of indifferent access:
|
|
120
|
+
#
|
|
121
|
+
# hash_1[:key] = 10
|
|
122
|
+
# hash_2['key'] = 12
|
|
123
|
+
# hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
|
|
124
|
+
def update(other_hash)
|
|
125
|
+
if other_hash.is_a? HashWithIndifferentAccess
|
|
126
|
+
super(other_hash)
|
|
127
|
+
else
|
|
128
|
+
other_hash.to_hash.each_pair do |key, value|
|
|
129
|
+
if block_given? && key?(key)
|
|
130
|
+
value = yield(convert_key(key), self[key], value)
|
|
131
|
+
end
|
|
132
|
+
regular_writer(convert_key(key), convert_value(value))
|
|
133
|
+
end
|
|
134
|
+
self
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
alias_method :merge!, :update
|
|
139
|
+
|
|
140
|
+
# Checks the hash for a key matching the argument passed in:
|
|
141
|
+
#
|
|
142
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
143
|
+
# hash['key'] = 'value'
|
|
144
|
+
# hash.key?(:key) # => true
|
|
145
|
+
# hash.key?('key') # => true
|
|
146
|
+
def key?(key)
|
|
147
|
+
super(convert_key(key))
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
alias_method :include?, :key?
|
|
151
|
+
alias_method :has_key?, :key?
|
|
152
|
+
alias_method :member?, :key?
|
|
153
|
+
|
|
154
|
+
# Same as <tt>Hash#[]</tt> where the key passed as argument can be
|
|
155
|
+
# either a string or a symbol:
|
|
156
|
+
#
|
|
157
|
+
# counters = ActiveSupport::HashWithIndifferentAccess.new
|
|
158
|
+
# counters[:foo] = 1
|
|
159
|
+
#
|
|
160
|
+
# counters['foo'] # => 1
|
|
161
|
+
# counters[:foo] # => 1
|
|
162
|
+
# counters[:zoo] # => nil
|
|
163
|
+
def [](key)
|
|
164
|
+
super(convert_key(key))
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Same as <tt>Hash#assoc</tt> where the key passed as argument can be
|
|
168
|
+
# either a string or a symbol:
|
|
169
|
+
#
|
|
170
|
+
# counters = ActiveSupport::HashWithIndifferentAccess.new
|
|
171
|
+
# counters[:foo] = 1
|
|
172
|
+
#
|
|
173
|
+
# counters.assoc('foo') # => ["foo", 1]
|
|
174
|
+
# counters.assoc(:foo) # => ["foo", 1]
|
|
175
|
+
# counters.assoc(:zoo) # => nil
|
|
176
|
+
def assoc(key)
|
|
177
|
+
super(convert_key(key))
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Same as <tt>Hash#fetch</tt> where the key passed as argument can be
|
|
181
|
+
# either a string or a symbol:
|
|
182
|
+
#
|
|
183
|
+
# counters = ActiveSupport::HashWithIndifferentAccess.new
|
|
184
|
+
# counters[:foo] = 1
|
|
185
|
+
#
|
|
186
|
+
# counters.fetch('foo') # => 1
|
|
187
|
+
# counters.fetch(:bar, 0) # => 0
|
|
188
|
+
# counters.fetch(:bar) { |key| 0 } # => 0
|
|
189
|
+
# counters.fetch(:zoo) # => KeyError: key not found: "zoo"
|
|
190
|
+
def fetch(key, *extras)
|
|
191
|
+
super(convert_key(key), *extras)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Same as <tt>Hash#dig</tt> where the key passed as argument can be
|
|
195
|
+
# either a string or a symbol:
|
|
196
|
+
#
|
|
197
|
+
# counters = ActiveSupport::HashWithIndifferentAccess.new
|
|
198
|
+
# counters[:foo] = { bar: 1 }
|
|
199
|
+
#
|
|
200
|
+
# counters.dig('foo', 'bar') # => 1
|
|
201
|
+
# counters.dig(:foo, :bar) # => 1
|
|
202
|
+
# counters.dig(:zoo) # => nil
|
|
203
|
+
def dig(*args)
|
|
204
|
+
args[0] = convert_key(args[0]) if args.size > 0
|
|
205
|
+
super(*args)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Same as <tt>Hash#default</tt> where the key passed as argument can be
|
|
209
|
+
# either a string or a symbol:
|
|
210
|
+
#
|
|
211
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new(1)
|
|
212
|
+
# hash.default # => 1
|
|
213
|
+
#
|
|
214
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new { |hash, key| key }
|
|
215
|
+
# hash.default # => nil
|
|
216
|
+
# hash.default('foo') # => 'foo'
|
|
217
|
+
# hash.default(:foo) # => 'foo'
|
|
218
|
+
def default(*args)
|
|
219
|
+
super(*args.map { |arg| convert_key(arg) })
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Returns an array of the values at the specified indices:
|
|
223
|
+
#
|
|
224
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
225
|
+
# hash[:a] = 'x'
|
|
226
|
+
# hash[:b] = 'y'
|
|
227
|
+
# hash.values_at('a', 'b') # => ["x", "y"]
|
|
228
|
+
def values_at(*keys)
|
|
229
|
+
super(*keys.map { |key| convert_key(key) })
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Returns an array of the values at the specified indices, but also
|
|
233
|
+
# raises an exception when one of the keys can't be found.
|
|
234
|
+
#
|
|
235
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
236
|
+
# hash[:a] = 'x'
|
|
237
|
+
# hash[:b] = 'y'
|
|
238
|
+
# hash.fetch_values('a', 'b') # => ["x", "y"]
|
|
239
|
+
# hash.fetch_values('a', 'c') { |key| 'z' } # => ["x", "z"]
|
|
240
|
+
# hash.fetch_values('a', 'c') # => KeyError: key not found: "c"
|
|
241
|
+
def fetch_values(*indices, &block)
|
|
242
|
+
super(*indices.map { |key| convert_key(key) }, &block)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Returns a shallow copy of the hash.
|
|
246
|
+
#
|
|
247
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new({ a: { b: 'b' } })
|
|
248
|
+
# dup = hash.dup
|
|
249
|
+
# dup[:a][:c] = 'c'
|
|
250
|
+
#
|
|
251
|
+
# hash[:a][:c] # => "c"
|
|
252
|
+
# dup[:a][:c] # => "c"
|
|
253
|
+
def dup
|
|
254
|
+
self.class.new(self).tap do |new_hash|
|
|
255
|
+
set_defaults(new_hash)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# This method has the same semantics of +update+, except it does not
|
|
260
|
+
# modify the receiver but rather returns a new hash with indifferent
|
|
261
|
+
# access with the result of the merge.
|
|
262
|
+
def merge(hash, &block)
|
|
263
|
+
dup.update(hash, &block)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Like +merge+ but the other way around: Merges the receiver into the
|
|
267
|
+
# argument and returns a new hash with indifferent access as result:
|
|
268
|
+
#
|
|
269
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
270
|
+
# hash['a'] = nil
|
|
271
|
+
# hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
|
|
272
|
+
def reverse_merge(other_hash)
|
|
273
|
+
super(self.class.new(other_hash))
|
|
274
|
+
end
|
|
275
|
+
alias_method :with_defaults, :reverse_merge
|
|
276
|
+
|
|
277
|
+
# Same semantics as +reverse_merge+ but modifies the receiver in-place.
|
|
278
|
+
def reverse_merge!(other_hash)
|
|
279
|
+
super(self.class.new(other_hash))
|
|
280
|
+
end
|
|
281
|
+
alias_method :with_defaults!, :reverse_merge!
|
|
282
|
+
|
|
283
|
+
# Replaces the contents of this hash with other_hash.
|
|
284
|
+
#
|
|
285
|
+
# h = { "a" => 100, "b" => 200 }
|
|
286
|
+
# h.replace({ "c" => 300, "d" => 400 }) # => {"c"=>300, "d"=>400}
|
|
287
|
+
def replace(other_hash)
|
|
288
|
+
super(self.class.new(other_hash))
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Removes the specified key from the hash.
|
|
292
|
+
def delete(key)
|
|
293
|
+
super(convert_key(key))
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def except(*keys)
|
|
297
|
+
slice(*self.keys - keys.map { |key| convert_key(key) })
|
|
298
|
+
end
|
|
299
|
+
alias_method :without, :except
|
|
300
|
+
|
|
301
|
+
def stringify_keys!; self end
|
|
302
|
+
def deep_stringify_keys!; self end
|
|
303
|
+
def stringify_keys; dup end
|
|
304
|
+
def deep_stringify_keys; dup end
|
|
305
|
+
undef :symbolize_keys!
|
|
306
|
+
undef :deep_symbolize_keys!
|
|
307
|
+
def symbolize_keys; to_hash.symbolize_keys! end
|
|
308
|
+
alias_method :to_options, :symbolize_keys
|
|
309
|
+
def deep_symbolize_keys; to_hash.deep_symbolize_keys! end
|
|
310
|
+
def to_options!; self end
|
|
311
|
+
|
|
312
|
+
def select(*args, &block)
|
|
313
|
+
return to_enum(:select) unless block_given?
|
|
314
|
+
dup.tap { |hash| hash.select!(*args, &block) }
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def reject(*args, &block)
|
|
318
|
+
return to_enum(:reject) unless block_given?
|
|
319
|
+
dup.tap { |hash| hash.reject!(*args, &block) }
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def transform_values(*args, &block)
|
|
323
|
+
return to_enum(:transform_values) unless block_given?
|
|
324
|
+
dup.tap { |hash| hash.transform_values!(*args, &block) }
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def transform_keys(*args, &block)
|
|
328
|
+
return to_enum(:transform_keys) unless block_given?
|
|
329
|
+
dup.tap { |hash| hash.transform_keys!(*args, &block) }
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def transform_keys!
|
|
333
|
+
return enum_for(:transform_keys!) { size } unless block_given?
|
|
334
|
+
keys.each do |key|
|
|
335
|
+
self[yield(key)] = delete(key)
|
|
336
|
+
end
|
|
337
|
+
self
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def slice(*keys)
|
|
341
|
+
keys.map! { |key| convert_key(key) }
|
|
342
|
+
self.class.new(super)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def slice!(*keys)
|
|
346
|
+
keys.map! { |key| convert_key(key) }
|
|
347
|
+
super
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def compact
|
|
351
|
+
dup.tap(&:compact!)
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# Convert to a regular hash with string keys.
|
|
355
|
+
def to_hash
|
|
356
|
+
_new_hash = Hash.new
|
|
357
|
+
set_defaults(_new_hash)
|
|
358
|
+
|
|
359
|
+
each do |key, value|
|
|
360
|
+
_new_hash[key] = convert_value(value, for: :to_hash)
|
|
361
|
+
end
|
|
362
|
+
_new_hash
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
private
|
|
366
|
+
def convert_key(key) # :doc:
|
|
367
|
+
key.kind_of?(Symbol) ? key.to_s : key
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def convert_value(value, options = {}) # :doc:
|
|
371
|
+
if value.is_a? Hash
|
|
372
|
+
if options[:for] == :to_hash
|
|
373
|
+
value.to_hash
|
|
374
|
+
else
|
|
375
|
+
value.nested_under_indifferent_access
|
|
376
|
+
end
|
|
377
|
+
elsif value.is_a?(Array)
|
|
378
|
+
if options[:for] != :assignment || value.frozen?
|
|
379
|
+
value = value.dup
|
|
380
|
+
end
|
|
381
|
+
value.map! { |e| convert_value(e, options) }
|
|
382
|
+
else
|
|
383
|
+
value
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def set_defaults(target) # :doc:
|
|
388
|
+
if default_proc
|
|
389
|
+
target.default_proc = default_proc.dup
|
|
390
|
+
else
|
|
391
|
+
target.default = default
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# :stopdoc:
|
|
398
|
+
|
|
399
|
+
HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess
|