activesupport 7.0.0 → 7.2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +156 -255
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -6
- data/lib/active_support/actionable_error.rb +3 -1
- data/lib/active_support/array_inquirer.rb +3 -1
- data/lib/active_support/backtrace_cleaner.rb +41 -9
- data/lib/active_support/benchmarkable.rb +1 -0
- data/lib/active_support/broadcast_logger.rb +251 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +49 -17
- data/lib/active_support/cache/mem_cache_store.rb +111 -129
- data/lib/active_support/cache/memory_store.rb +81 -26
- data/lib/active_support/cache/null_store.rb +6 -0
- data/lib/active_support/cache/redis_cache_store.rb +175 -154
- data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
- data/lib/active_support/cache/strategy/local_cache.rb +31 -13
- data/lib/active_support/cache.rb +457 -377
- data/lib/active_support/callbacks.rb +123 -139
- data/lib/active_support/code_generator.rb +15 -10
- data/lib/active_support/concern.rb +4 -2
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/configurable.rb +12 -2
- data/lib/active_support/core_ext/array/conversions.rb +7 -9
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/class/subclasses.rb +4 -15
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/calculations.rb +20 -5
- data/lib/active_support/core_ext/date/conversions.rb +15 -16
- data/lib/active_support/core_ext/date.rb +0 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +14 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +29 -2
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +15 -15
- data/lib/active_support/core_ext/date_time.rb +0 -1
- data/lib/active_support/core_ext/digest/uuid.rb +7 -10
- data/lib/active_support/core_ext/enumerable.rb +51 -101
- data/lib/active_support/core_ext/erb/util.rb +201 -0
- data/lib/active_support/core_ext/file/atomic.rb +2 -0
- data/lib/active_support/core_ext/hash/conversions.rb +1 -2
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +7 -7
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
- data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +38 -20
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -119
- data/lib/active_support/core_ext/module/deprecation.rb +12 -12
- data/lib/active_support/core_ext/module/introspection.rb +0 -1
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +77 -75
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
- data/lib/active_support/core_ext/object/duplicable.rb +25 -16
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +4 -2
- data/lib/active_support/core_ext/object/json.rb +17 -7
- data/lib/active_support/core_ext/object/to_query.rb +0 -2
- data/lib/active_support/core_ext/object/with.rb +46 -0
- data/lib/active_support/core_ext/object/with_options.rb +9 -9
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +20 -0
- data/lib/active_support/core_ext/pathname/existence.rb +2 -0
- data/lib/active_support/core_ext/pathname.rb +1 -0
- data/lib/active_support/core_ext/range/conversions.rb +32 -11
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +2 -6
- data/lib/active_support/core_ext/string/conversions.rb +3 -3
- data/lib/active_support/core_ext/string/filters.rb +21 -15
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +16 -9
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +39 -150
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +42 -32
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +13 -15
- data/lib/active_support/core_ext/time/zones.rb +8 -9
- data/lib/active_support/core_ext/time.rb +0 -1
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/current_attributes.rb +53 -46
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/delegation.rb +202 -0
- data/lib/active_support/dependencies/autoload.rb +9 -16
- data/lib/active_support/deprecation/behaviors.rb +65 -42
- data/lib/active_support/deprecation/constant_accessor.rb +47 -25
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +6 -8
- data/lib/active_support/deprecation/method_wrappers.rb +6 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +34 -22
- data/lib/active_support/deprecation/reporting.rb +49 -27
- data/lib/active_support/deprecation.rb +39 -9
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +66 -175
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -4
- data/lib/active_support/duration.rb +13 -7
- data/lib/active_support/encrypted_configuration.rb +63 -10
- data/lib/active_support/encrypted_file.rb +29 -13
- data/lib/active_support/environment_inquirer.rb +22 -2
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +160 -36
- data/lib/active_support/evented_file_update_checker.rb +19 -7
- data/lib/active_support/execution_wrapper.rb +23 -28
- data/lib/active_support/file_update_checker.rb +5 -3
- data/lib/active_support/fork_tracker.rb +4 -32
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +41 -25
- data/lib/active_support/html_safe_translation.rb +19 -6
- data/lib/active_support/i18n.rb +1 -1
- data/lib/active_support/i18n_railtie.rb +20 -13
- data/lib/active_support/inflector/inflections.rb +2 -0
- data/lib/active_support/inflector/methods.rb +28 -18
- data/lib/active_support/inflector/transliterate.rb +4 -2
- data/lib/active_support/isolated_execution_state.rb +39 -19
- data/lib/active_support/json/decoding.rb +2 -1
- data/lib/active_support/json/encoding.rb +25 -43
- data/lib/active_support/key_generator.rb +13 -5
- data/lib/active_support/lazy_load_hooks.rb +33 -7
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +76 -36
- data/lib/active_support/logger.rb +22 -60
- data/lib/active_support/logger_thread_safe_level.rb +10 -32
- data/lib/active_support/message_encryptor.rb +200 -55
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +305 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +220 -89
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +111 -45
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +34 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +4 -2
- data/lib/active_support/multibyte/unicode.rb +9 -37
- data/lib/active_support/notifications/fanout.rb +248 -87
- data/lib/active_support/notifications/instrumenter.rb +93 -25
- data/lib/active_support/notifications.rb +38 -31
- data/lib/active_support/number_helper/number_converter.rb +16 -7
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
- data/lib/active_support/number_helper.rb +379 -317
- data/lib/active_support/option_merger.rb +4 -4
- data/lib/active_support/ordered_hash.rb +3 -3
- data/lib/active_support/ordered_options.rb +68 -16
- data/lib/active_support/parameter_filter.rb +103 -84
- data/lib/active_support/proxy_object.rb +8 -3
- data/lib/active_support/railtie.rb +30 -25
- data/lib/active_support/reloader.rb +13 -5
- data/lib/active_support/rescuable.rb +12 -10
- data/lib/active_support/secure_compare_rotator.rb +17 -10
- data/lib/active_support/string_inquirer.rb +4 -2
- data/lib/active_support/subscriber.rb +10 -27
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +64 -25
- data/lib/active_support/test_case.rb +160 -7
- data/lib/active_support/testing/assertions.rb +29 -13
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +54 -0
- data/lib/active_support/testing/deprecation.rb +20 -27
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +46 -33
- data/lib/active_support/testing/method_call_assertions.rb +7 -8
- data/lib/active_support/testing/parallelization/server.rb +3 -0
- data/lib/active_support/testing/parallelize_executor.rb +8 -3
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/stream.rb +1 -1
- data/lib/active_support/testing/strict_warnings.rb +43 -0
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +38 -16
- data/lib/active_support/time_with_zone.rb +28 -54
- data/lib/active_support/values/time_zone.rb +26 -15
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +3 -10
- data/lib/active_support/xml_mini/nokogiri.rb +1 -1
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +13 -4
- data/lib/active_support.rb +15 -3
- metadata +142 -21
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -7
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
- data/lib/active_support/core_ext/uri.rb +0 -5
- data/lib/active_support/deprecation/instance_delegator.rb +0 -38
- data/lib/active_support/per_thread_registry.rb +0 -65
- data/lib/active_support/ruby_features.rb +0 -7
@@ -19,16 +19,27 @@ class Module
|
|
19
19
|
end
|
20
20
|
alias_method :attr_internal, :attr_internal_accessor
|
21
21
|
|
22
|
-
class << self
|
23
|
-
|
22
|
+
class << self
|
23
|
+
attr_reader :attr_internal_naming_format
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def attr_internal_naming_format=(format)
|
26
|
+
if format.start_with?("@")
|
27
|
+
ActiveSupport.deprecator.warn <<~MESSAGE
|
28
|
+
Setting `attr_internal_naming_format` with a `@` prefix is deprecated and will be removed in Rails 8.0.
|
29
|
+
|
30
|
+
You can simply replace #{format.inspect} by #{format.delete_prefix("@").inspect}.
|
31
|
+
MESSAGE
|
32
|
+
|
33
|
+
format = format.delete_prefix("@")
|
34
|
+
end
|
35
|
+
@attr_internal_naming_format = format
|
28
36
|
end
|
37
|
+
end
|
38
|
+
self.attr_internal_naming_format = "_%s"
|
29
39
|
|
40
|
+
private
|
30
41
|
def attr_internal_define(attr_name, type)
|
31
|
-
internal_name =
|
42
|
+
internal_name = Module.attr_internal_naming_format % attr_name
|
32
43
|
# use native attr_* methods as they are faster on some Ruby implementations
|
33
44
|
public_send("attr_#{type}", internal_name)
|
34
45
|
attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
|
@@ -43,6 +43,7 @@ class Module
|
|
43
43
|
#
|
44
44
|
# module HairColors
|
45
45
|
# mattr_reader :hair_colors, default: [:brown, :black, :blonde, :red]
|
46
|
+
# mattr_reader(:hair_styles) { [:long, :short] }
|
46
47
|
# end
|
47
48
|
#
|
48
49
|
# class Person
|
@@ -50,6 +51,7 @@ class Module
|
|
50
51
|
# end
|
51
52
|
#
|
52
53
|
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
|
54
|
+
# Person.new.hair_styles # => [:long, :short]
|
53
55
|
def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil, location: nil)
|
54
56
|
raise TypeError, "module attributes should be defined directly on class, not singleton" if singleton_class?
|
55
57
|
location ||= caller_locations(1, 1).first
|
@@ -107,6 +109,7 @@ class Module
|
|
107
109
|
#
|
108
110
|
# module HairColors
|
109
111
|
# mattr_writer :hair_colors, default: [:brown, :black, :blonde, :red]
|
112
|
+
# mattr_writer(:hair_styles) { [:long, :short] }
|
110
113
|
# end
|
111
114
|
#
|
112
115
|
# class Person
|
@@ -114,6 +117,7 @@ class Module
|
|
114
117
|
# end
|
115
118
|
#
|
116
119
|
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
120
|
+
# Person.class_variable_get("@@hair_styles") # => [:long, :short]
|
117
121
|
def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil, location: nil)
|
118
122
|
raise TypeError, "module attributes should be defined directly on class, not singleton" if singleton_class?
|
119
123
|
location ||= caller_locations(1, 1).first
|
@@ -192,6 +196,7 @@ class Module
|
|
192
196
|
#
|
193
197
|
# module HairColors
|
194
198
|
# mattr_accessor :hair_colors, default: [:brown, :black, :blonde, :red]
|
199
|
+
# mattr_accessor(:hair_styles) { [:long, :short] }
|
195
200
|
# end
|
196
201
|
#
|
197
202
|
# class Person
|
@@ -199,6 +204,7 @@ class Module
|
|
199
204
|
# end
|
200
205
|
#
|
201
206
|
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
207
|
+
# Person.class_variable_get("@@hair_styles") # => [:long, :short]
|
202
208
|
def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk)
|
203
209
|
location = caller_locations(1, 1).first
|
204
210
|
mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, location: location, &blk)
|
@@ -9,8 +9,8 @@
|
|
9
9
|
# So the values are scoped within the Thread.current space under the class name
|
10
10
|
# of the module.
|
11
11
|
#
|
12
|
-
# Note that it can also be scoped per-fiber if Rails.application.config.active_support.isolation_level
|
13
|
-
# is set to
|
12
|
+
# Note that it can also be scoped per-fiber if +Rails.application.config.active_support.isolation_level+
|
13
|
+
# is set to +:fiber+.
|
14
14
|
class Module
|
15
15
|
# Defines a per-thread class attribute and creates class and instance reader methods.
|
16
16
|
# The underlying per-thread class variable is set to +nil+, if it is not previously defined.
|
@@ -21,7 +21,7 @@ class Module
|
|
21
21
|
#
|
22
22
|
# Current.user = "DHH"
|
23
23
|
# Current.user # => "DHH"
|
24
|
-
# Thread.new { Current.user }.
|
24
|
+
# Thread.new { Current.user }.value # => nil
|
25
25
|
#
|
26
26
|
# The attribute name must be a valid method name in Ruby.
|
27
27
|
#
|
@@ -42,14 +42,32 @@ class Module
|
|
42
42
|
syms.each do |sym|
|
43
43
|
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
|
44
44
|
|
45
|
-
# The following generated method concatenates `
|
46
|
-
# to
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
45
|
+
# The following generated method concatenates `object_id` because we want
|
46
|
+
# subclasses to maintain independent values.
|
47
|
+
if default.nil?
|
48
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
49
|
+
def self.#{sym}
|
50
|
+
@__thread_mattr_#{sym} ||= "attr_#{sym}_\#{object_id}"
|
51
|
+
::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}]
|
52
|
+
end
|
53
|
+
EOS
|
54
|
+
else
|
55
|
+
default = default.dup.freeze unless default.frozen?
|
56
|
+
singleton_class.define_method("#{sym}_default_value") { default }
|
57
|
+
|
58
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
59
|
+
def self.#{sym}
|
60
|
+
@__thread_mattr_#{sym} ||= "attr_#{sym}_\#{object_id}"
|
61
|
+
value = ::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}]
|
62
|
+
|
63
|
+
if value.nil? && !::ActiveSupport::IsolatedExecutionState.key?(@__thread_mattr_#{sym})
|
64
|
+
::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}] = #{sym}_default_value
|
65
|
+
else
|
66
|
+
value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
EOS
|
70
|
+
end
|
53
71
|
|
54
72
|
if instance_reader && instance_accessor
|
55
73
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
@@ -58,8 +76,6 @@ class Module
|
|
58
76
|
end
|
59
77
|
EOS
|
60
78
|
end
|
61
|
-
|
62
|
-
::ActiveSupport::IsolatedExecutionState["attr_#{name}_#{sym}"] = default unless default.nil?
|
63
79
|
end
|
64
80
|
end
|
65
81
|
alias :thread_cattr_reader :thread_mattr_reader
|
@@ -82,15 +98,15 @@ class Module
|
|
82
98
|
# end
|
83
99
|
#
|
84
100
|
# Current.new.user = "DHH" # => NoMethodError
|
85
|
-
def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true
|
101
|
+
def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true) # :nodoc:
|
86
102
|
syms.each do |sym|
|
87
103
|
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
|
88
104
|
|
89
|
-
# The following generated method concatenates `
|
90
|
-
# to
|
105
|
+
# The following generated method concatenates `object_id` because we want
|
106
|
+
# subclasses to maintain independent values.
|
91
107
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
92
108
|
def self.#{sym}=(obj)
|
93
|
-
@__thread_mattr_#{sym} ||= "attr_
|
109
|
+
@__thread_mattr_#{sym} ||= "attr_#{sym}_\#{object_id}"
|
94
110
|
::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}] = obj
|
95
111
|
end
|
96
112
|
EOS
|
@@ -102,8 +118,6 @@ class Module
|
|
102
118
|
end
|
103
119
|
EOS
|
104
120
|
end
|
105
|
-
|
106
|
-
public_send("#{sym}=", default) unless default.nil?
|
107
121
|
end
|
108
122
|
end
|
109
123
|
alias :thread_cattr_writer :thread_mattr_writer
|
@@ -118,7 +132,7 @@ class Module
|
|
118
132
|
# Account.user # => "DHH"
|
119
133
|
# Account.new.user # => "DHH"
|
120
134
|
#
|
121
|
-
# Unlike
|
135
|
+
# Unlike +mattr_accessor+, values are *not* shared with subclasses or parent classes.
|
122
136
|
# If a subclass changes the value, the parent class' value is not changed.
|
123
137
|
# If the parent class changes the value, the value of subclasses is not changed.
|
124
138
|
#
|
@@ -149,6 +163,10 @@ class Module
|
|
149
163
|
#
|
150
164
|
# Current.new.user = "DHH" # => NoMethodError
|
151
165
|
# Current.new.user # => NoMethodError
|
166
|
+
#
|
167
|
+
# A default value may be specified using the +:default+ option. Because
|
168
|
+
# multiple threads can access the default value, non-frozen default values
|
169
|
+
# will be <tt>dup</tt>ed and frozen.
|
152
170
|
def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil)
|
153
171
|
thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default)
|
154
172
|
thread_mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_support/concern"
|
4
4
|
|
5
5
|
class Module
|
6
|
-
#
|
6
|
+
# == Bite-sized separation of concerns
|
7
7
|
#
|
8
8
|
# We often find ourselves with a medium-sized chunk of behavior that we'd
|
9
9
|
# like to extract, but only mix in to a single class.
|
@@ -18,9 +18,9 @@ class Module
|
|
18
18
|
# with a comment, as a least-bad alternative. Using modules in separate files
|
19
19
|
# means tedious sifting to get a big-picture view.
|
20
20
|
#
|
21
|
-
#
|
21
|
+
# == Dissatisfying ways to separate small concerns
|
22
22
|
#
|
23
|
-
#
|
23
|
+
# === Using comments:
|
24
24
|
#
|
25
25
|
# class Todo < ApplicationRecord
|
26
26
|
# # Other todo implementation
|
@@ -37,7 +37,7 @@ class Module
|
|
37
37
|
# end
|
38
38
|
# end
|
39
39
|
#
|
40
|
-
#
|
40
|
+
# === With an inline module:
|
41
41
|
#
|
42
42
|
# Noisy syntax.
|
43
43
|
#
|
@@ -61,7 +61,7 @@ class Module
|
|
61
61
|
# include EventTracking
|
62
62
|
# end
|
63
63
|
#
|
64
|
-
#
|
64
|
+
# === Mix-in noise exiled to its own file:
|
65
65
|
#
|
66
66
|
# Once our chunk of behavior starts pushing the scroll-to-understand-it
|
67
67
|
# boundary, we give in and move it to a separate file. At this size, the
|
@@ -75,7 +75,7 @@ class Module
|
|
75
75
|
# include TodoEventTracking
|
76
76
|
# end
|
77
77
|
#
|
78
|
-
#
|
78
|
+
# == Introducing Module#concerning
|
79
79
|
#
|
80
80
|
# By quieting the mix-in noise, we arrive at a natural, low-ceremony way to
|
81
81
|
# separate bite-sized concerns.
|
@@ -1,19 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "set"
|
4
|
-
|
5
3
|
class Module
|
6
|
-
|
7
|
-
|
8
|
-
class DelegationError < NoMethodError; end
|
9
|
-
|
10
|
-
RUBY_RESERVED_KEYWORDS = %w(alias and BEGIN begin break case class def defined? do
|
11
|
-
else elsif END end ensure false for if in module next nil not or redo rescue retry
|
12
|
-
return self super then true undef unless until when while yield)
|
13
|
-
DELEGATION_RESERVED_KEYWORDS = %w(_ arg args block)
|
14
|
-
DELEGATION_RESERVED_METHOD_NAMES = Set.new(
|
15
|
-
RUBY_RESERVED_KEYWORDS + DELEGATION_RESERVED_KEYWORDS
|
16
|
-
).freeze
|
4
|
+
require "active_support/delegation"
|
5
|
+
DelegationError = ActiveSupport::DelegationError # :nodoc:
|
17
6
|
|
18
7
|
# Provides a +delegate+ class method to easily expose contained objects'
|
19
8
|
# public methods as your own.
|
@@ -21,7 +10,7 @@ class Module
|
|
21
10
|
# ==== Options
|
22
11
|
# * <tt>:to</tt> - Specifies the target object name as a symbol or string
|
23
12
|
# * <tt>:prefix</tt> - Prefixes the new method with the target name or a custom prefix
|
24
|
-
# * <tt>:allow_nil</tt> - If set to true, prevents a +
|
13
|
+
# * <tt>:allow_nil</tt> - If set to true, prevents a +ActiveSupport::DelegationError+
|
25
14
|
# from being raised
|
26
15
|
# * <tt>:private</tt> - If set to true, changes method visibility to private
|
27
16
|
#
|
@@ -132,7 +121,7 @@ class Module
|
|
132
121
|
# User.new.age # => 2
|
133
122
|
#
|
134
123
|
# If the target is +nil+ and does not respond to the delegated method a
|
135
|
-
# +
|
124
|
+
# +ActiveSupport::DelegationError+ is raised. If you wish to instead return +nil+,
|
136
125
|
# use the <tt>:allow_nil</tt> option.
|
137
126
|
#
|
138
127
|
# class User < ActiveRecord::Base
|
@@ -141,7 +130,7 @@ class Module
|
|
141
130
|
# end
|
142
131
|
#
|
143
132
|
# User.new.age
|
144
|
-
# # =>
|
133
|
+
# # => ActiveSupport::DelegationError: User#age delegated to profile.age, but profile is nil
|
145
134
|
#
|
146
135
|
# But if not having a profile yet is fine and should not be an error
|
147
136
|
# condition:
|
@@ -169,75 +158,15 @@ class Module
|
|
169
158
|
#
|
170
159
|
# The target method must be public, otherwise it will raise +NoMethodError+.
|
171
160
|
def delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil)
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
if prefix
|
182
|
-
"#{prefix == true ? to : prefix}_"
|
183
|
-
else
|
184
|
-
""
|
185
|
-
end
|
186
|
-
|
187
|
-
location = caller_locations(1, 1).first
|
188
|
-
file, line = location.path, location.lineno
|
189
|
-
|
190
|
-
to = to.to_s
|
191
|
-
to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to)
|
192
|
-
|
193
|
-
method_def = []
|
194
|
-
method_names = []
|
195
|
-
|
196
|
-
methods.map do |method|
|
197
|
-
method_name = prefix ? "#{method_prefix}#{method}" : method
|
198
|
-
method_names << method_name.to_sym
|
199
|
-
|
200
|
-
# Attribute writer methods only accept one argument. Makes sure []=
|
201
|
-
# methods still accept two arguments.
|
202
|
-
definition = /[^\]]=\z/.match?(method) ? "arg" : "..."
|
203
|
-
|
204
|
-
# The following generated method calls the target exactly once, storing
|
205
|
-
# the returned value in a dummy variable.
|
206
|
-
#
|
207
|
-
# Reason is twofold: On one hand doing less calls is in general better.
|
208
|
-
# On the other hand it could be that the target has side-effects,
|
209
|
-
# whereas conceptually, from the user point of view, the delegator should
|
210
|
-
# be doing one call.
|
211
|
-
if allow_nil
|
212
|
-
method = method.to_s
|
213
|
-
|
214
|
-
method_def <<
|
215
|
-
"def #{method_name}(#{definition})" <<
|
216
|
-
" _ = #{to}" <<
|
217
|
-
" if !_.nil? || nil.respond_to?(:#{method})" <<
|
218
|
-
" _.#{method}(#{definition})" <<
|
219
|
-
" end" <<
|
220
|
-
"end"
|
221
|
-
else
|
222
|
-
method = method.to_s
|
223
|
-
method_name = method_name.to_s
|
224
|
-
|
225
|
-
method_def <<
|
226
|
-
"def #{method_name}(#{definition})" <<
|
227
|
-
" _ = #{to}" <<
|
228
|
-
" _.#{method}(#{definition})" <<
|
229
|
-
"rescue NoMethodError => e" <<
|
230
|
-
" if _.nil? && e.name == :#{method}" <<
|
231
|
-
%( raise DelegationError, "#{self}##{method_name} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") <<
|
232
|
-
" else" <<
|
233
|
-
" raise" <<
|
234
|
-
" end" <<
|
235
|
-
"end"
|
236
|
-
end
|
237
|
-
end
|
238
|
-
module_eval(method_def.join(";"), file, line)
|
239
|
-
private(*method_names) if private
|
240
|
-
method_names
|
161
|
+
::ActiveSupport::Delegation.generate(
|
162
|
+
self,
|
163
|
+
methods,
|
164
|
+
location: caller_locations(1, 1).first,
|
165
|
+
to: to,
|
166
|
+
prefix: prefix,
|
167
|
+
allow_nil: allow_nil,
|
168
|
+
private: private,
|
169
|
+
)
|
241
170
|
end
|
242
171
|
|
243
172
|
# When building decorators, a common pattern may emerge:
|
@@ -279,7 +208,7 @@ class Module
|
|
279
208
|
# variables, methods, constants, etc.
|
280
209
|
#
|
281
210
|
# The delegated method must be public on the target, otherwise it will
|
282
|
-
# raise +DelegationError+. If you wish to instead return +nil+,
|
211
|
+
# raise +ActiveSupport::DelegationError+. If you wish to instead return +nil+,
|
283
212
|
# use the <tt>:allow_nil</tt> option.
|
284
213
|
#
|
285
214
|
# The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
|
@@ -287,38 +216,10 @@ class Module
|
|
287
216
|
# <tt>Marshal.dump(object)</tt>, should the delegation target method
|
288
217
|
# of <tt>object</tt> add or remove instance variables.
|
289
218
|
def delegate_missing_to(target, allow_nil: nil)
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
# It may look like an oversight, but we deliberately do not pass
|
296
|
-
# +include_private+, because they do not get delegated.
|
297
|
-
|
298
|
-
return false if name == :marshal_dump || name == :_dump
|
299
|
-
#{target}.respond_to?(name) || super
|
300
|
-
end
|
301
|
-
|
302
|
-
def method_missing(method, *args, &block)
|
303
|
-
if #{target}.respond_to?(method)
|
304
|
-
#{target}.public_send(method, *args, &block)
|
305
|
-
else
|
306
|
-
begin
|
307
|
-
super
|
308
|
-
rescue NoMethodError
|
309
|
-
if #{target}.nil?
|
310
|
-
if #{allow_nil == true}
|
311
|
-
nil
|
312
|
-
else
|
313
|
-
raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
|
314
|
-
end
|
315
|
-
else
|
316
|
-
raise
|
317
|
-
end
|
318
|
-
end
|
319
|
-
end
|
320
|
-
end
|
321
|
-
ruby2_keywords(:method_missing)
|
322
|
-
RUBY
|
219
|
+
::ActiveSupport::Delegation.generate_method_missing(
|
220
|
+
self,
|
221
|
+
target,
|
222
|
+
allow_nil: allow_nil,
|
223
|
+
)
|
323
224
|
end
|
324
225
|
end
|
@@ -1,17 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Module
|
4
|
-
# deprecate :foo
|
5
|
-
# deprecate bar:
|
6
|
-
# deprecate :foo, :bar, baz: 'warning!', qux: 'gone!'
|
4
|
+
# deprecate :foo, deprecator: MyLib.deprecator
|
5
|
+
# deprecate :foo, bar: "warning!", deprecator: MyLib.deprecator
|
7
6
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# deprecate :foo, bar: "warning!", deprecator: MyLib::Deprecator.new
|
12
|
-
#
|
13
|
-
# \Custom deprecators must respond to <tt>deprecation_warning(deprecated_method_name, message, caller_backtrace)</tt>
|
14
|
-
# method where you can implement your custom warning behavior.
|
7
|
+
# A deprecator is typically an instance of ActiveSupport::Deprecation, but you can also pass any object that responds
|
8
|
+
# to <tt>deprecation_warning(deprecated_method_name, message, caller_backtrace)</tt> where you can implement your
|
9
|
+
# custom warning behavior.
|
15
10
|
#
|
16
11
|
# class MyLib::Deprecator
|
17
12
|
# def deprecation_warning(deprecated_method_name, message, caller_backtrace = nil)
|
@@ -19,7 +14,12 @@ class Module
|
|
19
14
|
# Kernel.warn message
|
20
15
|
# end
|
21
16
|
# end
|
22
|
-
def deprecate(*method_names)
|
23
|
-
ActiveSupport::Deprecation
|
17
|
+
def deprecate(*method_names, deprecator:, **options)
|
18
|
+
if deprecator.is_a?(ActiveSupport::Deprecation)
|
19
|
+
deprecator.deprecate_methods(self, *method_names, **options)
|
20
|
+
elsif deprecator
|
21
|
+
# we just need any instance to call deprecate_methods, but the deprecation will be emitted by deprecator
|
22
|
+
ActiveSupport.deprecator.deprecate_methods(self, *method_names, **options, deprecator: deprecator)
|
23
|
+
end
|
24
24
|
end
|
25
25
|
end
|
@@ -7,6 +7,7 @@ class Numeric
|
|
7
7
|
TERABYTE = GIGABYTE * 1024
|
8
8
|
PETABYTE = TERABYTE * 1024
|
9
9
|
EXABYTE = PETABYTE * 1024
|
10
|
+
ZETTABYTE = EXABYTE * 1024
|
10
11
|
|
11
12
|
# Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes
|
12
13
|
#
|
@@ -63,4 +64,12 @@ class Numeric
|
|
63
64
|
self * EXABYTE
|
64
65
|
end
|
65
66
|
alias :exabyte :exabytes
|
67
|
+
|
68
|
+
# Returns the number of bytes equivalent to the zettabytes provided.
|
69
|
+
#
|
70
|
+
# 2.zettabytes # => 2_361_183_241_434_822_606_848
|
71
|
+
def zettabytes
|
72
|
+
self * ZETTABYTE
|
73
|
+
end
|
74
|
+
alias :zettabyte :zettabytes
|
66
75
|
end
|