activesupport 7.0.8.7 → 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 +143 -459
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- 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 +39 -7
- 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 +94 -128
- data/lib/active_support/cache/memory_store.rb +80 -25
- data/lib/active_support/cache/null_store.rb +6 -0
- data/lib/active_support/cache/redis_cache_store.rb +165 -152
- data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
- data/lib/active_support/cache/strategy/local_cache.rb +29 -14
- data/lib/active_support/cache.rb +363 -291
- data/lib/active_support/callbacks.rb +118 -134
- 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 +10 -0
- data/lib/active_support/core_ext/array/conversions.rb +1 -2
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/class/subclasses.rb +17 -34
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +1 -2
- data/lib/active_support/core_ext/date.rb +0 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -2
- 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 +3 -75
- data/lib/active_support/core_ext/erb/util.rb +201 -0
- data/lib/active_support/core_ext/hash/conversions.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- 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 +34 -16
- 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 +5 -3
- data/lib/active_support/core_ext/numeric.rb +0 -1
- 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/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/with.rb +46 -0
- data/lib/active_support/core_ext/object/with_options.rb +4 -4
- 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 +28 -7
- 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 +1 -5
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- 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 -5
- data/lib/active_support/core_ext/string/multibyte.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +34 -177
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +36 -30
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +1 -3
- data/lib/active_support/core_ext/time/zones.rb +4 -4
- 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 +3 -5
- 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 -172
- 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 +30 -9
- data/lib/active_support/encrypted_file.rb +9 -4
- 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 +0 -1
- data/lib/active_support/execution_wrapper.rb +4 -5
- 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 +23 -11
- data/lib/active_support/inflector/transliterate.rb +3 -1
- data/lib/active_support/isolated_execution_state.rb +26 -22
- 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 +9 -1
- data/lib/active_support/lazy_load_hooks.rb +6 -4
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber.rb +74 -34
- 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 +197 -53
- 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 +29 -28
- 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 -318
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_hash.rb +3 -3
- data/lib/active_support/ordered_options.rb +67 -15
- data/lib/active_support/parameter_filter.rb +84 -69
- data/lib/active_support/proxy_object.rb +8 -3
- data/lib/active_support/railtie.rb +25 -20
- data/lib/active_support/reloader.rb +12 -4
- data/lib/active_support/rescuable.rb +2 -0
- data/lib/active_support/secure_compare_rotator.rb +16 -9
- 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 +156 -7
- data/lib/active_support/testing/assertions.rb +28 -12
- 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 +21 -9
- 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 +12 -18
- data/lib/active_support/values/time_zone.rb +25 -14
- 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 +12 -3
- data/lib/active_support.rb +15 -3
- metadata +140 -19
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
- 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
@@ -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)
|
@@ -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
|
@@ -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
|
@@ -5,6 +5,8 @@ require "active_support/number_helper"
|
|
5
5
|
|
6
6
|
module ActiveSupport
|
7
7
|
module NumericWithFormat
|
8
|
+
# \Numeric With Format
|
9
|
+
#
|
8
10
|
# Provides options for converting numbers into formatted strings.
|
9
11
|
# Options are provided for phone numbers, currency, percentage,
|
10
12
|
# precision, positional notation, file size, and pretty printing.
|
@@ -138,6 +140,6 @@ module ActiveSupport
|
|
138
140
|
end
|
139
141
|
end
|
140
142
|
|
141
|
-
Integer.
|
142
|
-
Float.
|
143
|
-
BigDecimal.
|
143
|
+
Integer.include ActiveSupport::NumericWithFormat
|
144
|
+
Float.include ActiveSupport::NumericWithFormat
|
145
|
+
BigDecimal.include ActiveSupport::NumericWithFormat
|
@@ -3,4 +3,3 @@
|
|
3
3
|
require "active_support/core_ext/numeric/bytes"
|
4
4
|
require "active_support/core_ext/numeric/time"
|
5
5
|
require "active_support/core_ext/numeric/conversions"
|
6
|
-
require "active_support/core_ext/numeric/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
@@ -16,7 +16,7 @@ class Object
|
|
16
16
|
#
|
17
17
|
# @return [true, false]
|
18
18
|
def blank?
|
19
|
-
respond_to?(:empty?) ? !!empty? :
|
19
|
+
respond_to?(:empty?) ? !!empty? : false
|
20
20
|
end
|
21
21
|
|
22
22
|
# An object is present if it's not blank.
|
@@ -56,6 +56,10 @@ class NilClass
|
|
56
56
|
def blank?
|
57
57
|
true
|
58
58
|
end
|
59
|
+
|
60
|
+
def present? # :nodoc:
|
61
|
+
false
|
62
|
+
end
|
59
63
|
end
|
60
64
|
|
61
65
|
class FalseClass
|
@@ -67,6 +71,10 @@ class FalseClass
|
|
67
71
|
def blank?
|
68
72
|
true
|
69
73
|
end
|
74
|
+
|
75
|
+
def present? # :nodoc:
|
76
|
+
false
|
77
|
+
end
|
70
78
|
end
|
71
79
|
|
72
80
|
class TrueClass
|
@@ -78,6 +86,10 @@ class TrueClass
|
|
78
86
|
def blank?
|
79
87
|
false
|
80
88
|
end
|
89
|
+
|
90
|
+
def present? # :nodoc:
|
91
|
+
true
|
92
|
+
end
|
81
93
|
end
|
82
94
|
|
83
95
|
class Array
|
@@ -88,6 +100,10 @@ class Array
|
|
88
100
|
#
|
89
101
|
# @return [true, false]
|
90
102
|
alias_method :blank?, :empty?
|
103
|
+
|
104
|
+
def present? # :nodoc:
|
105
|
+
!empty?
|
106
|
+
end
|
91
107
|
end
|
92
108
|
|
93
109
|
class Hash
|
@@ -98,6 +114,22 @@ class Hash
|
|
98
114
|
#
|
99
115
|
# @return [true, false]
|
100
116
|
alias_method :blank?, :empty?
|
117
|
+
|
118
|
+
def present? # :nodoc:
|
119
|
+
!empty?
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class Symbol
|
124
|
+
# A Symbol is blank if it's empty:
|
125
|
+
#
|
126
|
+
# :''.blank? # => true
|
127
|
+
# :symbol.blank? # => false
|
128
|
+
alias_method :blank?, :empty?
|
129
|
+
|
130
|
+
def present? # :nodoc:
|
131
|
+
!empty?
|
132
|
+
end
|
101
133
|
end
|
102
134
|
|
103
135
|
class String
|
@@ -129,6 +161,10 @@ class String
|
|
129
161
|
ENCODED_BLANKS[self.encoding].match?(self)
|
130
162
|
end
|
131
163
|
end
|
164
|
+
|
165
|
+
def present? # :nodoc:
|
166
|
+
!blank?
|
167
|
+
end
|
132
168
|
end
|
133
169
|
|
134
170
|
class Numeric # :nodoc:
|
@@ -141,6 +177,10 @@ class Numeric # :nodoc:
|
|
141
177
|
def blank?
|
142
178
|
false
|
143
179
|
end
|
180
|
+
|
181
|
+
def present?
|
182
|
+
true
|
183
|
+
end
|
144
184
|
end
|
145
185
|
|
146
186
|
class Time # :nodoc:
|
@@ -152,4 +192,8 @@ class Time # :nodoc:
|
|
152
192
|
def blank?
|
153
193
|
false
|
154
194
|
end
|
195
|
+
|
196
|
+
def present?
|
197
|
+
true
|
198
|
+
end
|
155
199
|
end
|
@@ -53,3 +53,19 @@ class Hash
|
|
53
53
|
hash
|
54
54
|
end
|
55
55
|
end
|
56
|
+
|
57
|
+
class Module
|
58
|
+
# Returns a copy of module or class if it's anonymous. If it's
|
59
|
+
# named, returns +self+.
|
60
|
+
#
|
61
|
+
# Object.deep_dup == Object # => true
|
62
|
+
# klass = Class.new
|
63
|
+
# klass.deep_dup == klass # => false
|
64
|
+
def deep_dup
|
65
|
+
if name.nil?
|
66
|
+
super
|
67
|
+
else
|
68
|
+
self
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -1,16 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Object
|
4
|
-
# Returns true if this object is included in the argument.
|
5
|
-
#
|
4
|
+
# Returns true if this object is included in the argument.
|
5
|
+
#
|
6
|
+
# When argument is a +Range+, +#cover?+ is used to properly handle inclusion
|
7
|
+
# check within open ranges. Otherwise, argument must be any object which responds
|
8
|
+
# to +#include?+. Usage:
|
6
9
|
#
|
7
10
|
# characters = ["Konata", "Kagami", "Tsukasa"]
|
8
11
|
# "Konata".in?(characters) # => true
|
9
12
|
#
|
10
|
-
#
|
11
|
-
# to +#include?+.
|
13
|
+
# For non +Range+ arguments, this will throw an +ArgumentError+ if the argument
|
14
|
+
# doesn't respond to +#include?+.
|
12
15
|
def in?(another_object)
|
13
|
-
another_object
|
16
|
+
case another_object
|
17
|
+
when Range
|
18
|
+
another_object.cover?(self)
|
19
|
+
else
|
20
|
+
another_object.include?(self)
|
21
|
+
end
|
14
22
|
rescue NoMethodError
|
15
23
|
raise ArgumentError.new("The parameter passed to #in? must respond to #include?")
|
16
24
|
end
|
@@ -12,7 +12,9 @@ class Object
|
|
12
12
|
#
|
13
13
|
# C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
|
14
14
|
def instance_values
|
15
|
-
|
15
|
+
instance_variables.to_h do |ivar|
|
16
|
+
[ivar[1..-1].freeze, instance_variable_get(ivar)]
|
17
|
+
end
|
16
18
|
end
|
17
19
|
|
18
20
|
# Returns an array of instance variable names as strings including "@".
|
@@ -25,6 +27,6 @@ class Object
|
|
25
27
|
#
|
26
28
|
# C.new(0, 1).instance_variable_names # => ["@y", "@x"]
|
27
29
|
def instance_variable_names
|
28
|
-
instance_variables.map(&:
|
30
|
+
instance_variables.map(&:name)
|
29
31
|
end
|
30
32
|
end
|