activesupport 5.2.4.4 → 6.1.1
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 +353 -435
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support.rb +14 -1
- 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.rb +142 -78
- data/lib/active_support/cache/file_store.rb +33 -33
- data/lib/active_support/cache/mem_cache_store.rb +32 -20
- 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 +70 -43
- data/lib/active_support/cache/strategy/local_cache.rb +41 -26
- 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 +46 -0
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/core_ext/array.rb +1 -1
- 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/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.rb +1 -2
- 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/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.rb +0 -1
- 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/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
- 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 -13
- 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.rb +3 -0
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/time/calculations.rb +50 -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/current_attributes.rb +15 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/dependencies.rb +109 -34
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/deprecation.rb +6 -1
- 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/descendants_tracker.rb +59 -9
- data/lib/active_support/duration.rb +90 -38
- data/lib/active_support/duration/iso8601_parser.rb +2 -4
- data/lib/active_support/duration/iso8601_serializer.rb +18 -14
- 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 +1 -0
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +64 -41
- 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.rb +72 -8
- data/lib/active_support/notifications/fanout.rb +116 -16
- data/lib/active_support/notifications/instrumenter.rb +71 -9
- data/lib/active_support/number_helper.rb +38 -12
- 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 +8 -7
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- 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.rb +51 -0
- 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/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.rb +2 -10
- 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
- metadata +58 -32
- 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
@@ -1,11 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/hash/compact"
|
4
3
|
require "active_support/core_ext/hash/conversions"
|
5
4
|
require "active_support/core_ext/hash/deep_merge"
|
5
|
+
require "active_support/core_ext/hash/deep_transform_values"
|
6
6
|
require "active_support/core_ext/hash/except"
|
7
7
|
require "active_support/core_ext/hash/indifferent_access"
|
8
8
|
require "active_support/core_ext/hash/keys"
|
9
9
|
require "active_support/core_ext/hash/reverse_merge"
|
10
10
|
require "active_support/core_ext/hash/slice"
|
11
|
-
require "active_support/core_ext/hash/transform_values"
|
@@ -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"
|
@@ -73,7 +73,7 @@ class Hash
|
|
73
73
|
# configure your own builder with the <tt>:builder</tt> option. The method also accepts
|
74
74
|
# options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
|
75
75
|
def to_xml(options = {})
|
76
|
-
require "active_support/builder" unless defined?(Builder)
|
76
|
+
require "active_support/builder" unless defined?(Builder::XmlMarkup)
|
77
77
|
|
78
78
|
options = options.dup
|
79
79
|
options[:indent] ||= 2
|
@@ -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
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
# Returns a new hash with all values converted by the block operation.
|
5
|
+
# This includes the values from the root hash and from all
|
6
|
+
# nested hashes and arrays.
|
7
|
+
#
|
8
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
9
|
+
#
|
10
|
+
# hash.deep_transform_values{ |value| value.to_s.upcase }
|
11
|
+
# # => {person: {name: "ROB", age: "28"}}
|
12
|
+
def deep_transform_values(&block)
|
13
|
+
_deep_transform_values_in_object(self, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Destructively converts all values by using the block operation.
|
17
|
+
# This includes the values from the root hash and from all
|
18
|
+
# nested hashes and arrays.
|
19
|
+
def deep_transform_values!(&block)
|
20
|
+
_deep_transform_values_in_object!(self, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
# Support methods for deep transforming nested hashes and arrays.
|
25
|
+
def _deep_transform_values_in_object(object, &block)
|
26
|
+
case object
|
27
|
+
when Hash
|
28
|
+
object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
|
29
|
+
when Array
|
30
|
+
object.map { |e| _deep_transform_values_in_object(e, &block) }
|
31
|
+
else
|
32
|
+
yield(object)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def _deep_transform_values_in_object!(object, &block)
|
37
|
+
case object
|
38
|
+
when Hash
|
39
|
+
object.transform_values! { |value| _deep_transform_values_in_object!(value, &block) }
|
40
|
+
when Array
|
41
|
+
object.map! { |e| _deep_transform_values_in_object!(e, &block) }
|
42
|
+
else
|
43
|
+
yield(object)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -10,8 +10,8 @@ class Hash
|
|
10
10
|
# This is useful for limiting a set of parameters to everything but a few known toggles:
|
11
11
|
# @person.update(params[:person].except(:admin))
|
12
12
|
def except(*keys)
|
13
|
-
|
14
|
-
end
|
13
|
+
slice(*self.keys - keys)
|
14
|
+
end unless method_defined?(:except)
|
15
15
|
|
16
16
|
# Removes the given keys from hash and returns it.
|
17
17
|
# hash = { a: true, b: false, c: nil }
|
@@ -1,35 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Hash
|
4
|
-
# Returns a new hash with all keys converted using the +block+ operation.
|
5
|
-
#
|
6
|
-
# hash = { name: 'Rob', age: '28' }
|
7
|
-
#
|
8
|
-
# hash.transform_keys { |key| key.to_s.upcase } # => {"NAME"=>"Rob", "AGE"=>"28"}
|
9
|
-
#
|
10
|
-
# If you do not provide a +block+, it will return an Enumerator
|
11
|
-
# for chaining with other methods:
|
12
|
-
#
|
13
|
-
# hash.transform_keys.with_index { |k, i| [k, i].join } # => {"name0"=>"Rob", "age1"=>"28"}
|
14
|
-
def transform_keys
|
15
|
-
return enum_for(:transform_keys) { size } unless block_given?
|
16
|
-
result = {}
|
17
|
-
each_key do |key|
|
18
|
-
result[yield(key)] = self[key]
|
19
|
-
end
|
20
|
-
result
|
21
|
-
end unless method_defined? :transform_keys
|
22
|
-
|
23
|
-
# Destructively converts all keys using the +block+ operations.
|
24
|
-
# Same as +transform_keys+ but modifies +self+.
|
25
|
-
def transform_keys!
|
26
|
-
return enum_for(:transform_keys!) { size } unless block_given?
|
27
|
-
keys.each do |key|
|
28
|
-
self[yield(key)] = delete(key)
|
29
|
-
end
|
30
|
-
self
|
31
|
-
end unless method_defined? :transform_keys!
|
32
|
-
|
33
4
|
# Returns a new hash with all keys converted to strings.
|
34
5
|
#
|
35
6
|
# hash = { name: 'Rob', age: '28' }
|
@@ -141,7 +112,7 @@ class Hash
|
|
141
112
|
end
|
142
113
|
|
143
114
|
private
|
144
|
-
#
|
115
|
+
# Support methods for deep transforming nested hashes and arrays.
|
145
116
|
def _deep_transform_keys_in_object(object, &block)
|
146
117
|
case object
|
147
118
|
when Hash
|
@@ -1,34 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Hash
|
4
|
-
# Slices a hash to include only the given keys. Returns a hash containing
|
5
|
-
# the given keys.
|
6
|
-
#
|
7
|
-
# { a: 1, b: 2, c: 3, d: 4 }.slice(:a, :b)
|
8
|
-
# # => {:a=>1, :b=>2}
|
9
|
-
#
|
10
|
-
# This is useful for limiting an options hash to valid keys before
|
11
|
-
# passing to a method:
|
12
|
-
#
|
13
|
-
# def search(criteria = {})
|
14
|
-
# criteria.assert_valid_keys(:mass, :velocity, :time)
|
15
|
-
# end
|
16
|
-
#
|
17
|
-
# search(options.slice(:mass, :velocity, :time))
|
18
|
-
#
|
19
|
-
# If you have an array of keys you want to limit to, you should splat them:
|
20
|
-
#
|
21
|
-
# valid_keys = [:mass, :velocity, :time]
|
22
|
-
# search(options.slice(*valid_keys))
|
23
|
-
def slice(*keys)
|
24
|
-
keys.each_with_object(Hash.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
|
25
|
-
end unless method_defined?(:slice)
|
26
|
-
|
27
4
|
# Replaces the hash with only the given keys.
|
28
5
|
# Returns a hash containing the removed key/value pairs.
|
29
6
|
#
|
30
|
-
# { a: 1, b: 2, c: 3, d: 4 }
|
31
|
-
# # => {:c=>3, :d=>4}
|
7
|
+
# hash = { a: 1, b: 2, c: 3, d: 4 }
|
8
|
+
# hash.slice!(:a, :b) # => {:c=>3, :d=>4}
|
9
|
+
# hash # => {:a=>1, :b=>2}
|
32
10
|
def slice!(*keys)
|
33
11
|
omit = slice(*self.keys - keys)
|
34
12
|
hash = slice(*keys)
|
@@ -40,8 +18,9 @@ class Hash
|
|
40
18
|
|
41
19
|
# Removes and returns the key/value pairs matching the given keys.
|
42
20
|
#
|
43
|
-
# { a: 1, b: 2, c: 3, d: 4 }
|
44
|
-
#
|
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}
|
45
24
|
def extract!(*keys)
|
46
25
|
keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
|
47
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
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require "active_support/core_ext/module/aliasing"
|
4
4
|
require "active_support/core_ext/module/introspection"
|
5
5
|
require "active_support/core_ext/module/anonymous"
|
6
|
-
require "active_support/core_ext/module/reachable"
|
7
6
|
require "active_support/core_ext/module/attribute_accessors"
|
8
7
|
require "active_support/core_ext/module/attribute_accessors_per_thread"
|
9
8
|
require "active_support/core_ext/module/attr_internal"
|
@@ -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
|
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/array/extract_options"
|
4
|
-
require "active_support/core_ext/regexp"
|
5
|
-
|
6
3
|
# Extends the module object with class/module and instance accessors for
|
7
4
|
# class/module attributes, just like the native attr* accessors for instance
|
8
5
|
# attributes.
|
@@ -27,7 +24,7 @@ class Module
|
|
27
24
|
# end
|
28
25
|
# # => NameError: invalid attribute name: 1_Badname
|
29
26
|
#
|
30
|
-
#
|
27
|
+
# To omit the instance reader method, pass
|
31
28
|
# <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
|
32
29
|
#
|
33
30
|
# module HairColors
|
@@ -51,28 +48,25 @@ class Module
|
|
51
48
|
# end
|
52
49
|
#
|
53
50
|
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
|
54
|
-
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 = []
|
55
56
|
syms.each do |sym|
|
56
57
|
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
|
57
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
58
|
-
@@#{sym} = nil unless defined? @@#{sym}
|
59
58
|
|
60
|
-
|
61
|
-
@@#{sym}
|
62
|
-
end
|
63
|
-
EOS
|
59
|
+
definition << "def self.#{sym}; @@#{sym}; end"
|
64
60
|
|
65
61
|
if instance_reader && instance_accessor
|
66
|
-
|
67
|
-
def #{sym}
|
68
|
-
@@#{sym}
|
69
|
-
end
|
70
|
-
EOS
|
62
|
+
definition << "def #{sym}; @@#{sym}; end"
|
71
63
|
end
|
72
64
|
|
73
65
|
sym_default_value = (block_given? && default.nil?) ? yield : default
|
74
|
-
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}")
|
75
67
|
end
|
68
|
+
|
69
|
+
module_eval(definition.join(";"), location.path, location.lineno)
|
76
70
|
end
|
77
71
|
alias :cattr_reader :mattr_reader
|
78
72
|
|
@@ -94,7 +88,7 @@ class Module
|
|
94
88
|
# Person.new.hair_colors = [:blonde, :red]
|
95
89
|
# HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red]
|
96
90
|
#
|
97
|
-
#
|
91
|
+
# To omit the instance writer method, pass
|
98
92
|
# <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
|
99
93
|
#
|
100
94
|
# module HairColors
|
@@ -118,28 +112,24 @@ class Module
|
|
118
112
|
# end
|
119
113
|
#
|
120
114
|
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
121
|
-
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 = []
|
122
120
|
syms.each do |sym|
|
123
121
|
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
|
124
|
-
|
125
|
-
@@#{sym} = nil unless defined? @@#{sym}
|
126
|
-
|
127
|
-
def self.#{sym}=(obj)
|
128
|
-
@@#{sym} = obj
|
129
|
-
end
|
130
|
-
EOS
|
122
|
+
definition << "def self.#{sym}=(val); @@#{sym} = val; end"
|
131
123
|
|
132
124
|
if instance_writer && instance_accessor
|
133
|
-
|
134
|
-
def #{sym}=(obj)
|
135
|
-
@@#{sym} = obj
|
136
|
-
end
|
137
|
-
EOS
|
125
|
+
definition << "def #{sym}=(val); @@#{sym} = val; end"
|
138
126
|
end
|
139
127
|
|
140
128
|
sym_default_value = (block_given? && default.nil?) ? yield : default
|
141
|
-
|
129
|
+
class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil? && class_variable_defined?("@@#{sym}")
|
142
130
|
end
|
131
|
+
|
132
|
+
module_eval(definition.join(";"), location.path, location.lineno)
|
143
133
|
end
|
144
134
|
alias :cattr_writer :mattr_writer
|
145
135
|
|
@@ -163,14 +153,14 @@ class Module
|
|
163
153
|
# parent class. Similarly if parent class changes the value then that would
|
164
154
|
# change the value of subclasses too.
|
165
155
|
#
|
166
|
-
# class
|
156
|
+
# class Citizen < Person
|
167
157
|
# end
|
168
158
|
#
|
169
|
-
#
|
159
|
+
# Citizen.new.hair_colors << :blue
|
170
160
|
# Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
|
171
161
|
#
|
172
|
-
# To
|
173
|
-
# To
|
162
|
+
# To omit the instance writer method, pass <tt>instance_writer: false</tt>.
|
163
|
+
# To omit the instance reader method, pass <tt>instance_reader: false</tt>.
|
174
164
|
#
|
175
165
|
# module HairColors
|
176
166
|
# mattr_accessor :hair_colors, instance_writer: false, instance_reader: false
|
@@ -183,7 +173,7 @@ class Module
|
|
183
173
|
# Person.new.hair_colors = [:brown] # => NoMethodError
|
184
174
|
# Person.new.hair_colors # => NoMethodError
|
185
175
|
#
|
186
|
-
# Or pass <tt>instance_accessor: false</tt>, to
|
176
|
+
# Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
|
187
177
|
#
|
188
178
|
# module HairColors
|
189
179
|
# mattr_accessor :hair_colors, instance_accessor: false
|
@@ -208,8 +198,9 @@ class Module
|
|
208
198
|
#
|
209
199
|
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
210
200
|
def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk)
|
211
|
-
|
212
|
-
|
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)
|
213
204
|
end
|
214
205
|
alias :cattr_accessor :mattr_accessor
|
215
206
|
end
|
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/array/extract_options"
|
4
|
-
require "active_support/core_ext/regexp"
|
5
|
-
|
6
3
|
# Extends the module object with class/module and instance accessors for
|
7
4
|
# class/module attributes, just like the native attr* accessors for instance
|
8
5
|
# attributes, but does so on a per-thread basis.
|
@@ -28,7 +25,7 @@ class Module
|
|
28
25
|
# end
|
29
26
|
# # => NameError: invalid attribute name: 1_Badname
|
30
27
|
#
|
31
|
-
#
|
28
|
+
# To omit the instance reader method, pass
|
32
29
|
# <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
|
33
30
|
#
|
34
31
|
# class Current
|
@@ -36,9 +33,7 @@ class Module
|
|
36
33
|
# end
|
37
34
|
#
|
38
35
|
# Current.new.user # => NoMethodError
|
39
|
-
def thread_mattr_reader(*syms) # :nodoc:
|
40
|
-
options = syms.extract_options!
|
41
|
-
|
36
|
+
def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil) # :nodoc:
|
42
37
|
syms.each do |sym|
|
43
38
|
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
|
44
39
|
|
@@ -50,13 +45,15 @@ class Module
|
|
50
45
|
end
|
51
46
|
EOS
|
52
47
|
|
53
|
-
|
48
|
+
if instance_reader && instance_accessor
|
54
49
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
55
50
|
def #{sym}
|
56
51
|
self.class.#{sym}
|
57
52
|
end
|
58
53
|
EOS
|
59
54
|
end
|
55
|
+
|
56
|
+
Thread.current["attr_" + name + "_#{sym}"] = default unless default.nil?
|
60
57
|
end
|
61
58
|
end
|
62
59
|
alias :thread_cattr_reader :thread_mattr_reader
|
@@ -71,7 +68,7 @@ class Module
|
|
71
68
|
# Current.user = "DHH"
|
72
69
|
# Thread.current[:attr_Current_user] # => "DHH"
|
73
70
|
#
|
74
|
-
#
|
71
|
+
# To omit the instance writer method, pass
|
75
72
|
# <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
|
76
73
|
#
|
77
74
|
# class Current
|
@@ -79,8 +76,7 @@ class Module
|
|
79
76
|
# end
|
80
77
|
#
|
81
78
|
# Current.new.user = "DHH" # => NoMethodError
|
82
|
-
def thread_mattr_writer(*syms) # :nodoc:
|
83
|
-
options = syms.extract_options!
|
79
|
+
def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil) # :nodoc:
|
84
80
|
syms.each do |sym|
|
85
81
|
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
|
86
82
|
|
@@ -92,13 +88,15 @@ class Module
|
|
92
88
|
end
|
93
89
|
EOS
|
94
90
|
|
95
|
-
|
91
|
+
if instance_writer && instance_accessor
|
96
92
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
97
93
|
def #{sym}=(obj)
|
98
94
|
self.class.#{sym} = obj
|
99
95
|
end
|
100
96
|
EOS
|
101
97
|
end
|
98
|
+
|
99
|
+
public_send("#{sym}=", default) unless default.nil?
|
102
100
|
end
|
103
101
|
end
|
104
102
|
alias :thread_cattr_writer :thread_mattr_writer
|
@@ -124,8 +122,8 @@ class Module
|
|
124
122
|
# Customer.user # => "Rafael"
|
125
123
|
# Account.user # => "DHH"
|
126
124
|
#
|
127
|
-
# To
|
128
|
-
# To
|
125
|
+
# To omit the instance writer method, pass <tt>instance_writer: false</tt>.
|
126
|
+
# To omit the instance reader method, pass <tt>instance_reader: false</tt>.
|
129
127
|
#
|
130
128
|
# class Current
|
131
129
|
# thread_mattr_accessor :user, instance_writer: false, instance_reader: false
|
@@ -134,17 +132,17 @@ class Module
|
|
134
132
|
# Current.new.user = "DHH" # => NoMethodError
|
135
133
|
# Current.new.user # => NoMethodError
|
136
134
|
#
|
137
|
-
# Or pass <tt>instance_accessor: false</tt>, to
|
135
|
+
# Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
|
138
136
|
#
|
139
137
|
# class Current
|
140
|
-
#
|
138
|
+
# thread_mattr_accessor :user, instance_accessor: false
|
141
139
|
# end
|
142
140
|
#
|
143
141
|
# Current.new.user = "DHH" # => NoMethodError
|
144
142
|
# Current.new.user # => NoMethodError
|
145
|
-
def thread_mattr_accessor(*syms)
|
146
|
-
thread_mattr_reader(*syms)
|
147
|
-
thread_mattr_writer(*syms)
|
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)
|
145
|
+
thread_mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor)
|
148
146
|
end
|
149
147
|
alias :thread_cattr_accessor :thread_mattr_accessor
|
150
148
|
end
|