activesupport 6.0.6.1 → 6.1.7.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +441 -455
- data/MIT-LICENSE +1 -1
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +3 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache/file_store.rb +3 -3
- data/lib/active_support/cache/mem_cache_store.rb +28 -18
- data/lib/active_support/cache/memory_store.rb +46 -26
- data/lib/active_support/cache/redis_cache_store.rb +25 -25
- data/lib/active_support/cache/strategy/local_cache.rb +20 -5
- data/lib/active_support/cache.rb +87 -40
- data/lib/active_support/callbacks.rb +65 -56
- data/lib/active_support/concern.rb +46 -2
- data/lib/active_support/configurable.rb +3 -3
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/digest/uuid.rb +1 -0
- data/lib/active_support/core_ext/enumerable.rb +76 -4
- data/lib/active_support/core_ext/hash/conversions.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- 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 +23 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +38 -28
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +12 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/compare_range.rb +9 -3
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/inflections.rb +38 -4
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +7 -4
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- 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 +19 -0
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +5 -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 +9 -2
- data/lib/active_support/dependencies/zeitwerk_integration.rb +4 -1
- data/lib/active_support/dependencies.rb +37 -18
- data/lib/active_support/deprecation/behaviors.rb +15 -2
- 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 +3 -2
- data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +6 -2
- data/lib/active_support/digest.rb +2 -0
- data/lib/active_support/duration/iso8601_serializer.rb +15 -9
- data/lib/active_support/duration.rb +75 -25
- data/lib/active_support/encrypted_file.rb +27 -11
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +69 -133
- data/lib/active_support/fork_tracker.rb +64 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +48 -24
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +1 -2
- data/lib/active_support/inflector/methods.rb +36 -33
- data/lib/active_support/inflector/transliterate.rb +4 -4
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +5 -1
- data/lib/active_support/key_generator.rb +1 -1
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +8 -0
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -12
- data/lib/active_support/message_encryptor.rb +4 -7
- data/lib/active_support/message_verifier.rb +5 -5
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +4 -42
- data/lib/active_support/multibyte/unicode.rb +9 -83
- data/lib/active_support/notifications/fanout.rb +23 -8
- data/lib/active_support/notifications/instrumenter.rb +6 -15
- data/lib/active_support/notifications.rb +32 -5
- data/lib/active_support/number_helper/number_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 +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/number_helper.rb +29 -14
- data/lib/active_support/option_merger.rb +2 -1
- data/lib/active_support/ordered_options.rb +8 -2
- data/lib/active_support/parameter_filter.rb +16 -11
- data/lib/active_support/per_thread_registry.rb +2 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +23 -1
- 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 -2
- data/lib/active_support/subscriber.rb +12 -7
- data/lib/active_support/tagged_logging.rb +30 -5
- data/lib/active_support/testing/assertions.rb +18 -11
- 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 +12 -95
- data/lib/active_support/testing/time_helpers.rb +40 -3
- data/lib/active_support/time_with_zone.rb +67 -43
- data/lib/active_support/values/time_zone.rb +22 -10
- data/lib/active_support/xml_mini/rexml.rb +8 -1
- data/lib/active_support.rb +13 -1
- metadata +34 -36
- 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/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
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/kernel/singleton_class"
|
4
3
|
require "active_support/core_ext/module/redefine_method"
|
5
|
-
require "active_support/core_ext/array/extract_options"
|
6
4
|
|
7
5
|
class Class
|
8
6
|
# Declare a class-level attribute whose value is inheritable by subclasses.
|
@@ -84,58 +82,50 @@ class Class
|
|
84
82
|
# To set a default value for the attribute, pass <tt>default:</tt>, like so:
|
85
83
|
#
|
86
84
|
# class_attribute :settings, default: {}
|
87
|
-
def class_attribute(
|
88
|
-
|
89
|
-
instance_accessor: true,
|
90
|
-
instance_reader: instance_accessor,
|
91
|
-
instance_writer: instance_accessor,
|
92
|
-
instance_predicate: true,
|
93
|
-
default: nil
|
94
|
-
)
|
95
|
-
attrs.each do |name|
|
96
|
-
singleton_class.silence_redefinition_of_method(name)
|
97
|
-
define_singleton_method(name) { default }
|
98
|
-
|
99
|
-
singleton_class.silence_redefinition_of_method("#{name}?")
|
100
|
-
define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
|
85
|
+
def class_attribute(*attrs, instance_accessor: true,
|
86
|
+
instance_reader: instance_accessor, instance_writer: instance_accessor, instance_predicate: true, default: nil)
|
101
87
|
|
102
|
-
|
88
|
+
class_methods, methods = [], []
|
89
|
+
attrs.each do |name|
|
90
|
+
unless name.is_a?(Symbol) || name.is_a?(String)
|
91
|
+
raise TypeError, "#{name.inspect} is not a symbol nor a string"
|
92
|
+
end
|
103
93
|
|
104
|
-
|
105
|
-
|
106
|
-
|
94
|
+
class_methods << <<~RUBY # In case the method exists and is not public
|
95
|
+
silence_redefinition_of_method def #{name}
|
96
|
+
end
|
97
|
+
RUBY
|
107
98
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
if instance_variable_defined? ivar
|
112
|
-
instance_variable_get ivar
|
113
|
-
else
|
114
|
-
singleton_class.send name
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
99
|
+
methods << <<~RUBY if instance_reader
|
100
|
+
silence_redefinition_of_method def #{name}
|
101
|
+
defined?(@#{name}) ? @#{name} : self.class.#{name}
|
118
102
|
end
|
119
|
-
|
120
|
-
end
|
103
|
+
RUBY
|
121
104
|
|
122
|
-
|
123
|
-
|
124
|
-
if
|
125
|
-
|
126
|
-
|
127
|
-
self.class.public_send name
|
128
|
-
end
|
105
|
+
class_methods << <<~RUBY
|
106
|
+
silence_redefinition_of_method def #{name}=(value)
|
107
|
+
redefine_method(:#{name}) { value } if singleton_class?
|
108
|
+
redefine_singleton_method(:#{name}) { value }
|
109
|
+
value
|
129
110
|
end
|
111
|
+
RUBY
|
130
112
|
|
131
|
-
|
132
|
-
|
113
|
+
methods << <<~RUBY if instance_writer
|
114
|
+
silence_redefinition_of_method(:#{name}=)
|
115
|
+
attr_writer :#{name}
|
116
|
+
RUBY
|
133
117
|
|
134
|
-
if
|
135
|
-
|
136
|
-
|
118
|
+
if instance_predicate
|
119
|
+
class_methods << "silence_redefinition_of_method def #{name}?; !!self.#{name}; end"
|
120
|
+
if instance_reader
|
121
|
+
methods << "silence_redefinition_of_method def #{name}?; !!self.#{name}; end"
|
137
122
|
end
|
138
123
|
end
|
139
124
|
end
|
125
|
+
|
126
|
+
location = caller_locations(1, 1).first
|
127
|
+
class_eval(["class << self", *class_methods, "end", *methods].join(";").tr("\n", ";"), location.path, location.lineno)
|
128
|
+
|
129
|
+
attrs.each { |name| public_send("#{name}=", default) }
|
140
130
|
end
|
141
131
|
end
|
@@ -1,39 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Class
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# C.descendants # => [B, A, D]
|
21
|
-
def descendants
|
22
|
-
descendants = []
|
23
|
-
ObjectSpace.each_object(singleton_class) do |k|
|
24
|
-
next if k.singleton_class?
|
25
|
-
descendants.unshift k unless k == self
|
26
|
-
end
|
27
|
-
descendants
|
28
|
-
end
|
29
|
-
rescue StandardError # JRuby 9.0.4.0 and earlier
|
30
|
-
def descendants
|
31
|
-
descendants = []
|
32
|
-
ObjectSpace.each_object(Class) do |k|
|
33
|
-
descendants.unshift k if k < self
|
34
|
-
end
|
35
|
-
descendants.uniq!
|
36
|
-
descendants
|
4
|
+
# Returns an array with all classes that are < than its receiver.
|
5
|
+
#
|
6
|
+
# class C; end
|
7
|
+
# C.descendants # => []
|
8
|
+
#
|
9
|
+
# class B < C; end
|
10
|
+
# C.descendants # => [B]
|
11
|
+
#
|
12
|
+
# class A < B; end
|
13
|
+
# C.descendants # => [B, A]
|
14
|
+
#
|
15
|
+
# class D < C; end
|
16
|
+
# C.descendants # => [B, A, D]
|
17
|
+
def descendants
|
18
|
+
ObjectSpace.each_object(singleton_class).reject do |k|
|
19
|
+
k.singleton_class? || k == self
|
37
20
|
end
|
38
21
|
end
|
39
22
|
|
@@ -45,10 +28,6 @@ class Class
|
|
45
28
|
#
|
46
29
|
# Foo.subclasses # => [Bar]
|
47
30
|
def subclasses
|
48
|
-
|
49
|
-
chain.each do |k|
|
50
|
-
subclasses << k unless chain.any? { |c| c > k }
|
51
|
-
end
|
52
|
-
subclasses
|
31
|
+
descendants.select { |descendant| descendant.superclass == self }
|
53
32
|
end
|
54
33
|
end
|
@@ -10,6 +10,7 @@ class Date
|
|
10
10
|
short: "%d %b",
|
11
11
|
long: "%B %d, %Y",
|
12
12
|
db: "%Y-%m-%d",
|
13
|
+
inspect: "%Y-%m-%d",
|
13
14
|
number: "%Y%m%d",
|
14
15
|
long_ordinal: lambda { |date|
|
15
16
|
day_format = ActiveSupport::Inflector.ordinalize(date.day)
|
@@ -80,7 +81,7 @@ class Date
|
|
80
81
|
# If the *application's* timezone is needed, then use +in_time_zone+ instead.
|
81
82
|
def to_time(form = :local)
|
82
83
|
raise ArgumentError, "Expected :local or :utc, got #{form.inspect}." unless [:local, :utc].include?(form)
|
83
|
-
::Time.
|
84
|
+
::Time.public_send(form, year, month, day)
|
84
85
|
end
|
85
86
|
|
86
87
|
silence_redefinition_of_method :xmlschema
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/object/try"
|
4
|
+
require "active_support/core_ext/date_time/conversions"
|
4
5
|
|
5
6
|
module DateAndTime
|
6
7
|
module Calculations
|
@@ -30,6 +31,18 @@ module DateAndTime
|
|
30
31
|
to_date == ::Date.current
|
31
32
|
end
|
32
33
|
|
34
|
+
# Returns true if the date/time is tomorrow.
|
35
|
+
def tomorrow?
|
36
|
+
to_date == ::Date.current.tomorrow
|
37
|
+
end
|
38
|
+
alias :next_day? :tomorrow?
|
39
|
+
|
40
|
+
# Returns true if the date/time is yesterday.
|
41
|
+
def yesterday?
|
42
|
+
to_date == ::Date.current.yesterday
|
43
|
+
end
|
44
|
+
alias :prev_day? :yesterday?
|
45
|
+
|
33
46
|
# Returns true if the date/time is in the past.
|
34
47
|
def past?
|
35
48
|
self < self.class.current
|
@@ -12,5 +12,20 @@ module DateAndTime
|
|
12
12
|
# this behavior, but new apps will have an initializer that sets
|
13
13
|
# this to true, because the new behavior is preferred.
|
14
14
|
mattr_accessor :preserve_timezone, instance_writer: false, default: false
|
15
|
+
|
16
|
+
# Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
|
17
|
+
#
|
18
|
+
# When `true`, it returns local times with an UTC offset, with `false` local
|
19
|
+
# times are returned as UTC.
|
20
|
+
#
|
21
|
+
# # Given this zone:
|
22
|
+
# zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
|
23
|
+
#
|
24
|
+
# # With `utc_to_local_returns_utc_offset_times = false`, local time is converted to UTC:
|
25
|
+
# zone.utc_to_local(Time.utc(2000, 1)) # => 1999-12-31 19:00:00 UTC
|
26
|
+
#
|
27
|
+
# # With `utc_to_local_returns_utc_offset_times = true`, local time is returned with UTC offset:
|
28
|
+
# zone.utc_to_local(Time.utc(2000, 1)) # => 1999-12-31 19:00:00 -0500
|
29
|
+
mattr_accessor :utc_to_local_returns_utc_offset_times, instance_writer: false, default: false
|
15
30
|
end
|
16
31
|
end
|
@@ -44,7 +44,8 @@ module Enumerable
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
# Convert an enumerable to a hash
|
47
|
+
# Convert an enumerable to a hash, using the block result as the key and the
|
48
|
+
# element as the value.
|
48
49
|
#
|
49
50
|
# people.index_by(&:login)
|
50
51
|
# # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
|
@@ -61,12 +62,19 @@ module Enumerable
|
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
64
|
-
# Convert an enumerable to a hash
|
65
|
+
# Convert an enumerable to a hash, using the element as the key and the block
|
66
|
+
# result as the value.
|
65
67
|
#
|
66
68
|
# post = Post.new(title: "hey there", body: "what's up?")
|
67
69
|
#
|
68
70
|
# %i( title body ).index_with { |attr_name| post.public_send(attr_name) }
|
69
71
|
# # => { title: "hey there", body: "what's up?" }
|
72
|
+
#
|
73
|
+
# If an argument is passed instead of a block, it will be used as the value
|
74
|
+
# for all elements:
|
75
|
+
#
|
76
|
+
# %i( created_at updated_at ).index_with(Time.now)
|
77
|
+
# # => { created_at: 2020-03-09 22:31:47, updated_at: 2020-03-09 22:31:47 }
|
70
78
|
def index_with(default = INDEX_WITH_DEFAULT)
|
71
79
|
if block_given?
|
72
80
|
result = {}
|
@@ -134,7 +142,7 @@ module Enumerable
|
|
134
142
|
excluding(*elements)
|
135
143
|
end
|
136
144
|
|
137
|
-
#
|
145
|
+
# Extract the given key from each element in the enumerable.
|
138
146
|
#
|
139
147
|
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
|
140
148
|
# # => ["David", "Rafael", "Aaron"]
|
@@ -145,9 +153,62 @@ module Enumerable
|
|
145
153
|
if keys.many?
|
146
154
|
map { |element| keys.map { |key| element[key] } }
|
147
155
|
else
|
148
|
-
|
156
|
+
key = keys.first
|
157
|
+
map { |element| element[key] }
|
149
158
|
end
|
150
159
|
end
|
160
|
+
|
161
|
+
# Extract the given key from the first element in the enumerable.
|
162
|
+
#
|
163
|
+
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pick(:name)
|
164
|
+
# # => "David"
|
165
|
+
#
|
166
|
+
# [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pick(:id, :name)
|
167
|
+
# # => [1, "David"]
|
168
|
+
def pick(*keys)
|
169
|
+
return if none?
|
170
|
+
|
171
|
+
if keys.many?
|
172
|
+
keys.map { |key| first[key] }
|
173
|
+
else
|
174
|
+
first[keys.first]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns a new +Array+ without the blank items.
|
179
|
+
# Uses Object#blank? for determining if an item is blank.
|
180
|
+
#
|
181
|
+
# [1, "", nil, 2, " ", [], {}, false, true].compact_blank
|
182
|
+
# # => [1, 2, true]
|
183
|
+
#
|
184
|
+
# Set.new([nil, "", 1, 2])
|
185
|
+
# # => [2, 1] (or [1, 2])
|
186
|
+
#
|
187
|
+
# When called on a +Hash+, returns a new +Hash+ without the blank values.
|
188
|
+
#
|
189
|
+
# { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
|
190
|
+
# #=> { b: 1, f: true }
|
191
|
+
def compact_blank
|
192
|
+
reject(&:blank?)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
class Hash
|
197
|
+
# Hash#reject has its own definition, so this needs one too.
|
198
|
+
def compact_blank #:nodoc:
|
199
|
+
reject { |_k, v| v.blank? }
|
200
|
+
end
|
201
|
+
|
202
|
+
# Removes all blank values from the +Hash+ in place and returns self.
|
203
|
+
# Uses Object#blank? for determining if a value is blank.
|
204
|
+
#
|
205
|
+
# h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
|
206
|
+
# h.compact_blank!
|
207
|
+
# # => { b: 1, f: true }
|
208
|
+
def compact_blank!
|
209
|
+
# use delete_if rather than reject! because it always returns self even if nothing changed
|
210
|
+
delete_if { |_k, v| v.blank? }
|
211
|
+
end
|
151
212
|
end
|
152
213
|
|
153
214
|
class Range #:nodoc:
|
@@ -185,4 +246,15 @@ class Array #:nodoc:
|
|
185
246
|
super
|
186
247
|
end
|
187
248
|
end
|
249
|
+
|
250
|
+
# Removes all blank elements from the +Array+ in place and returns self.
|
251
|
+
# Uses Object#blank? for determining if an item is blank.
|
252
|
+
#
|
253
|
+
# a = [1, "", nil, 2, " ", [], {}, false, true]
|
254
|
+
# a.compact_blank!
|
255
|
+
# # => [1, 2, true]
|
256
|
+
def compact_blank!
|
257
|
+
# use delete_if rather than reject! because it always returns self even if nothing changed
|
258
|
+
delete_if(&:blank?)
|
259
|
+
end
|
188
260
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/xml_mini"
|
4
|
-
require "active_support/time"
|
5
4
|
require "active_support/core_ext/object/blank"
|
6
5
|
require "active_support/core_ext/object/to_param"
|
7
6
|
require "active_support/core_ext/object/to_query"
|
7
|
+
require "active_support/core_ext/object/try"
|
8
8
|
require "active_support/core_ext/array/wrap"
|
9
9
|
require "active_support/core_ext/hash/reverse_merge"
|
10
10
|
require "active_support/core_ext/string/inflections"
|
@@ -208,7 +208,7 @@ module ActiveSupport
|
|
208
208
|
elsif become_empty_string?(value)
|
209
209
|
""
|
210
210
|
elsif become_hash?(value)
|
211
|
-
xml_value =
|
211
|
+
xml_value = value.transform_values { |v| deep_to_h(v) }
|
212
212
|
|
213
213
|
# Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
|
214
214
|
# how multipart uploaded files from HTML appear
|
@@ -112,7 +112,7 @@ class Hash
|
|
112
112
|
end
|
113
113
|
|
114
114
|
private
|
115
|
-
#
|
115
|
+
# Support methods for deep transforming nested hashes and arrays.
|
116
116
|
def _deep_transform_keys_in_object(object, &block)
|
117
117
|
case object
|
118
118
|
when Hash
|
@@ -18,8 +18,9 @@ class Hash
|
|
18
18
|
|
19
19
|
# Removes and returns the key/value pairs matching the given keys.
|
20
20
|
#
|
21
|
-
# { a: 1, b: 2, c: 3, d: 4 }
|
22
|
-
#
|
21
|
+
# hash = { a: 1, b: 2, c: 3, d: 4 }
|
22
|
+
# hash.extract!(:a, :b) # => {:a=>1, :b=>2}
|
23
|
+
# hash # => {:c=>3, :d=>4}
|
23
24
|
def extract!(*keys)
|
24
25
|
keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
|
25
26
|
end
|
@@ -4,6 +4,6 @@ class LoadError
|
|
4
4
|
# Returns true if the given path name (except perhaps for the ".rb"
|
5
5
|
# extension) is the missing file which caused the exception to be raised.
|
6
6
|
def is_missing?(location)
|
7
|
-
location.
|
7
|
+
location.delete_suffix(".rb") == path.to_s.delete_suffix(".rb")
|
8
8
|
end
|
9
9
|
end
|
@@ -28,9 +28,9 @@ class Module
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def attr_internal_define(attr_name, type)
|
31
|
-
internal_name = attr_internal_ivar_name(attr_name).
|
31
|
+
internal_name = attr_internal_ivar_name(attr_name).delete_prefix("@")
|
32
32
|
# use native attr_* methods as they are faster on some Ruby implementations
|
33
|
-
|
33
|
+
public_send("attr_#{type}", internal_name)
|
34
34
|
attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
|
35
35
|
alias_method attr_name, internal_name
|
36
36
|
remove_method internal_name
|
@@ -48,28 +48,25 @@ class Module
|
|
48
48
|
# end
|
49
49
|
#
|
50
50
|
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
|
51
|
-
def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil)
|
51
|
+
def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil, location: nil)
|
52
|
+
raise TypeError, "module attributes should be defined directly on class, not singleton" if singleton_class?
|
53
|
+
location ||= caller_locations(1, 1).first
|
54
|
+
|
55
|
+
definition = []
|
52
56
|
syms.each do |sym|
|
53
57
|
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
|
54
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
55
|
-
@@#{sym} = nil unless defined? @@#{sym}
|
56
58
|
|
57
|
-
|
58
|
-
@@#{sym}
|
59
|
-
end
|
60
|
-
EOS
|
59
|
+
definition << "def self.#{sym}; @@#{sym}; end"
|
61
60
|
|
62
61
|
if instance_reader && instance_accessor
|
63
|
-
|
64
|
-
def #{sym}
|
65
|
-
@@#{sym}
|
66
|
-
end
|
67
|
-
EOS
|
62
|
+
definition << "def #{sym}; @@#{sym}; end"
|
68
63
|
end
|
69
64
|
|
70
65
|
sym_default_value = (block_given? && default.nil?) ? yield : default
|
71
|
-
class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil?
|
66
|
+
class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil? && class_variable_defined?("@@#{sym}")
|
72
67
|
end
|
68
|
+
|
69
|
+
module_eval(definition.join(";"), location.path, location.lineno)
|
73
70
|
end
|
74
71
|
alias :cattr_reader :mattr_reader
|
75
72
|
|
@@ -115,28 +112,24 @@ class Module
|
|
115
112
|
# end
|
116
113
|
#
|
117
114
|
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
118
|
-
def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil)
|
115
|
+
def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil, location: nil)
|
116
|
+
raise TypeError, "module attributes should be defined directly on class, not singleton" if singleton_class?
|
117
|
+
location ||= caller_locations(1, 1).first
|
118
|
+
|
119
|
+
definition = []
|
119
120
|
syms.each do |sym|
|
120
121
|
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
|
121
|
-
|
122
|
-
@@#{sym} = nil unless defined? @@#{sym}
|
123
|
-
|
124
|
-
def self.#{sym}=(obj)
|
125
|
-
@@#{sym} = obj
|
126
|
-
end
|
127
|
-
EOS
|
122
|
+
definition << "def self.#{sym}=(val); @@#{sym} = val; end"
|
128
123
|
|
129
124
|
if instance_writer && instance_accessor
|
130
|
-
|
131
|
-
def #{sym}=(obj)
|
132
|
-
@@#{sym} = obj
|
133
|
-
end
|
134
|
-
EOS
|
125
|
+
definition << "def #{sym}=(val); @@#{sym} = val; end"
|
135
126
|
end
|
136
127
|
|
137
128
|
sym_default_value = (block_given? && default.nil?) ? yield : default
|
138
|
-
|
129
|
+
class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil? && class_variable_defined?("@@#{sym}")
|
139
130
|
end
|
131
|
+
|
132
|
+
module_eval(definition.join(";"), location.path, location.lineno)
|
140
133
|
end
|
141
134
|
alias :cattr_writer :mattr_writer
|
142
135
|
|
@@ -205,8 +198,9 @@ class Module
|
|
205
198
|
#
|
206
199
|
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
207
200
|
def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk)
|
208
|
-
|
209
|
-
|
201
|
+
location = caller_locations(1, 1).first
|
202
|
+
mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, location: location, &blk)
|
203
|
+
mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default, location: location)
|
210
204
|
end
|
211
205
|
alias :cattr_accessor :mattr_accessor
|
212
206
|
end
|
@@ -33,7 +33,7 @@ class Module
|
|
33
33
|
# end
|
34
34
|
#
|
35
35
|
# Current.new.user # => NoMethodError
|
36
|
-
def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true) # :nodoc:
|
36
|
+
def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil) # :nodoc:
|
37
37
|
syms.each do |sym|
|
38
38
|
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
|
39
39
|
|
@@ -52,6 +52,8 @@ class Module
|
|
52
52
|
end
|
53
53
|
EOS
|
54
54
|
end
|
55
|
+
|
56
|
+
Thread.current["attr_" + name + "_#{sym}"] = default unless default.nil?
|
55
57
|
end
|
56
58
|
end
|
57
59
|
alias :thread_cattr_reader :thread_mattr_reader
|
@@ -74,7 +76,7 @@ class Module
|
|
74
76
|
# end
|
75
77
|
#
|
76
78
|
# Current.new.user = "DHH" # => NoMethodError
|
77
|
-
def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true) # :nodoc:
|
79
|
+
def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil) # :nodoc:
|
78
80
|
syms.each do |sym|
|
79
81
|
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
|
80
82
|
|
@@ -93,6 +95,8 @@ class Module
|
|
93
95
|
end
|
94
96
|
EOS
|
95
97
|
end
|
98
|
+
|
99
|
+
public_send("#{sym}=", default) unless default.nil?
|
96
100
|
end
|
97
101
|
end
|
98
102
|
alias :thread_cattr_writer :thread_mattr_writer
|
@@ -136,8 +140,8 @@ class Module
|
|
136
140
|
#
|
137
141
|
# Current.new.user = "DHH" # => NoMethodError
|
138
142
|
# Current.new.user # => NoMethodError
|
139
|
-
def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true)
|
140
|
-
thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor)
|
143
|
+
def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil)
|
144
|
+
thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default)
|
141
145
|
thread_mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor)
|
142
146
|
end
|
143
147
|
alias :thread_cattr_accessor :thread_mattr_accessor
|
@@ -104,10 +104,16 @@ class Module
|
|
104
104
|
# * grok the behavior of our class in one glance,
|
105
105
|
# * clean up monolithic junk-drawer classes by separating their concerns, and
|
106
106
|
# * stop leaning on protected/private for crude "this is internal stuff" modularity.
|
107
|
+
#
|
108
|
+
# === Prepending concerning
|
109
|
+
#
|
110
|
+
# <tt>concerning</tt> supports a <tt>prepend: true</tt> argument which will <tt>prepend</tt> the
|
111
|
+
# concern instead of using <tt>include</tt> for it.
|
107
112
|
module Concerning
|
108
113
|
# Define a new concern and mix it in.
|
109
|
-
def concerning(topic, &block)
|
110
|
-
|
114
|
+
def concerning(topic, prepend: false, &block)
|
115
|
+
method = prepend ? :prepend : :include
|
116
|
+
__send__(method, concern(topic, &block))
|
111
117
|
end
|
112
118
|
|
113
119
|
# A low-cruft shortcut to define a concern.
|