activesupport 7.0.8 → 7.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +142 -428
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +3 -1
  7. data/lib/active_support/backtrace_cleaner.rb +39 -7
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +251 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +49 -17
  14. data/lib/active_support/cache/mem_cache_store.rb +94 -128
  15. data/lib/active_support/cache/memory_store.rb +80 -25
  16. data/lib/active_support/cache/null_store.rb +6 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +165 -152
  18. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +29 -14
  20. data/lib/active_support/cache.rb +363 -291
  21. data/lib/active_support/callbacks.rb +118 -134
  22. data/lib/active_support/code_generator.rb +15 -10
  23. data/lib/active_support/concern.rb +4 -2
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/configurable.rb +10 -0
  27. data/lib/active_support/core_ext/array/conversions.rb +1 -2
  28. data/lib/active_support/core_ext/array.rb +0 -1
  29. data/lib/active_support/core_ext/class/subclasses.rb +17 -34
  30. data/lib/active_support/core_ext/date/blank.rb +4 -0
  31. data/lib/active_support/core_ext/date/conversions.rb +1 -2
  32. data/lib/active_support/core_ext/date.rb +0 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  35. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  36. data/lib/active_support/core_ext/date_time/conversions.rb +2 -2
  37. data/lib/active_support/core_ext/date_time.rb +0 -1
  38. data/lib/active_support/core_ext/digest/uuid.rb +7 -10
  39. data/lib/active_support/core_ext/enumerable.rb +3 -75
  40. data/lib/active_support/core_ext/erb/util.rb +201 -0
  41. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  42. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  43. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  44. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  45. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  46. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  47. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  48. data/lib/active_support/core_ext/module/delegation.rb +20 -119
  49. data/lib/active_support/core_ext/module/deprecation.rb +12 -12
  50. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  51. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  52. data/lib/active_support/core_ext/numeric/conversions.rb +5 -3
  53. data/lib/active_support/core_ext/numeric.rb +0 -1
  54. data/lib/active_support/core_ext/object/blank.rb +45 -1
  55. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  56. data/lib/active_support/core_ext/object/duplicable.rb +24 -15
  57. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  58. data/lib/active_support/core_ext/object/instance_variables.rb +4 -2
  59. data/lib/active_support/core_ext/object/json.rb +17 -7
  60. data/lib/active_support/core_ext/object/with.rb +46 -0
  61. data/lib/active_support/core_ext/object/with_options.rb +4 -4
  62. data/lib/active_support/core_ext/object.rb +1 -0
  63. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  64. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  65. data/lib/active_support/core_ext/pathname.rb +1 -0
  66. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  67. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  68. data/lib/active_support/core_ext/range.rb +1 -2
  69. data/lib/active_support/core_ext/securerandom.rb +1 -5
  70. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  71. data/lib/active_support/core_ext/string/filters.rb +21 -15
  72. data/lib/active_support/core_ext/string/indent.rb +1 -1
  73. data/lib/active_support/core_ext/string/inflections.rb +16 -5
  74. data/lib/active_support/core_ext/string/multibyte.rb +1 -1
  75. data/lib/active_support/core_ext/string/output_safety.rb +34 -177
  76. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  77. data/lib/active_support/core_ext/time/calculations.rb +36 -30
  78. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  79. data/lib/active_support/core_ext/time/conversions.rb +1 -3
  80. data/lib/active_support/core_ext/time/zones.rb +4 -4
  81. data/lib/active_support/core_ext/time.rb +0 -1
  82. data/lib/active_support/core_ext.rb +0 -1
  83. data/lib/active_support/current_attributes.rb +53 -46
  84. data/lib/active_support/deep_mergeable.rb +53 -0
  85. data/lib/active_support/delegation.rb +202 -0
  86. data/lib/active_support/dependencies/autoload.rb +9 -16
  87. data/lib/active_support/deprecation/behaviors.rb +65 -42
  88. data/lib/active_support/deprecation/constant_accessor.rb +47 -25
  89. data/lib/active_support/deprecation/deprecators.rb +104 -0
  90. data/lib/active_support/deprecation/disallowed.rb +3 -5
  91. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  92. data/lib/active_support/deprecation/proxy_wrappers.rb +34 -22
  93. data/lib/active_support/deprecation/reporting.rb +49 -27
  94. data/lib/active_support/deprecation.rb +39 -9
  95. data/lib/active_support/deprecator.rb +7 -0
  96. data/lib/active_support/descendants_tracker.rb +66 -172
  97. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  98. data/lib/active_support/duration/iso8601_serializer.rb +1 -4
  99. data/lib/active_support/duration.rb +13 -7
  100. data/lib/active_support/encrypted_configuration.rb +30 -9
  101. data/lib/active_support/encrypted_file.rb +9 -4
  102. data/lib/active_support/environment_inquirer.rb +22 -2
  103. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  104. data/lib/active_support/error_reporter.rb +160 -36
  105. data/lib/active_support/evented_file_update_checker.rb +0 -1
  106. data/lib/active_support/execution_wrapper.rb +4 -5
  107. data/lib/active_support/file_update_checker.rb +5 -3
  108. data/lib/active_support/fork_tracker.rb +4 -32
  109. data/lib/active_support/gem_version.rb +3 -3
  110. data/lib/active_support/gzip.rb +2 -0
  111. data/lib/active_support/hash_with_indifferent_access.rb +41 -25
  112. data/lib/active_support/html_safe_translation.rb +19 -6
  113. data/lib/active_support/i18n.rb +1 -1
  114. data/lib/active_support/i18n_railtie.rb +20 -13
  115. data/lib/active_support/inflector/inflections.rb +2 -0
  116. data/lib/active_support/inflector/methods.rb +23 -11
  117. data/lib/active_support/inflector/transliterate.rb +3 -1
  118. data/lib/active_support/isolated_execution_state.rb +26 -22
  119. data/lib/active_support/json/decoding.rb +2 -1
  120. data/lib/active_support/json/encoding.rb +25 -43
  121. data/lib/active_support/key_generator.rb +9 -1
  122. data/lib/active_support/lazy_load_hooks.rb +6 -4
  123. data/lib/active_support/locale/en.yml +2 -0
  124. data/lib/active_support/log_subscriber.rb +74 -34
  125. data/lib/active_support/logger.rb +22 -60
  126. data/lib/active_support/logger_thread_safe_level.rb +10 -32
  127. data/lib/active_support/message_encryptor.rb +197 -53
  128. data/lib/active_support/message_encryptors.rb +141 -0
  129. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  130. data/lib/active_support/message_pack/extensions.rb +305 -0
  131. data/lib/active_support/message_pack/serializer.rb +63 -0
  132. data/lib/active_support/message_pack.rb +50 -0
  133. data/lib/active_support/message_verifier.rb +220 -89
  134. data/lib/active_support/message_verifiers.rb +135 -0
  135. data/lib/active_support/messages/codec.rb +65 -0
  136. data/lib/active_support/messages/metadata.rb +111 -45
  137. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  138. data/lib/active_support/messages/rotator.rb +34 -32
  139. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  140. data/lib/active_support/multibyte/chars.rb +4 -2
  141. data/lib/active_support/multibyte/unicode.rb +9 -37
  142. data/lib/active_support/notifications/fanout.rb +248 -87
  143. data/lib/active_support/notifications/instrumenter.rb +93 -25
  144. data/lib/active_support/notifications.rb +29 -28
  145. data/lib/active_support/number_helper/number_converter.rb +16 -7
  146. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  147. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
  148. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  149. data/lib/active_support/number_helper.rb +379 -318
  150. data/lib/active_support/option_merger.rb +2 -2
  151. data/lib/active_support/ordered_hash.rb +3 -3
  152. data/lib/active_support/ordered_options.rb +67 -15
  153. data/lib/active_support/parameter_filter.rb +84 -69
  154. data/lib/active_support/proxy_object.rb +8 -3
  155. data/lib/active_support/railtie.rb +25 -20
  156. data/lib/active_support/reloader.rb +12 -4
  157. data/lib/active_support/rescuable.rb +2 -0
  158. data/lib/active_support/secure_compare_rotator.rb +16 -9
  159. data/lib/active_support/string_inquirer.rb +4 -2
  160. data/lib/active_support/subscriber.rb +10 -27
  161. data/lib/active_support/syntax_error_proxy.rb +60 -0
  162. data/lib/active_support/tagged_logging.rb +64 -25
  163. data/lib/active_support/test_case.rb +156 -7
  164. data/lib/active_support/testing/assertions.rb +28 -12
  165. data/lib/active_support/testing/autorun.rb +0 -2
  166. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  167. data/lib/active_support/testing/deprecation.rb +20 -27
  168. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  169. data/lib/active_support/testing/isolation.rb +21 -9
  170. data/lib/active_support/testing/method_call_assertions.rb +7 -8
  171. data/lib/active_support/testing/parallelization/server.rb +3 -0
  172. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  173. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  174. data/lib/active_support/testing/stream.rb +1 -1
  175. data/lib/active_support/testing/strict_warnings.rb +43 -0
  176. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  177. data/lib/active_support/testing/time_helpers.rb +38 -16
  178. data/lib/active_support/time_with_zone.rb +12 -18
  179. data/lib/active_support/values/time_zone.rb +25 -14
  180. data/lib/active_support/version.rb +1 -1
  181. data/lib/active_support/xml_mini/jdom.rb +3 -10
  182. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  183. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  184. data/lib/active_support/xml_mini/rexml.rb +1 -1
  185. data/lib/active_support/xml_mini.rb +12 -3
  186. data/lib/active_support.rb +15 -3
  187. metadata +145 -24
  188. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  189. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
  190. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
  191. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  192. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
  193. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
  194. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  195. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
  196. data/lib/active_support/core_ext/uri.rb +0 -5
  197. data/lib/active_support/deprecation/instance_delegator.rb +0 -38
  198. data/lib/active_support/per_thread_registry.rb +0 -65
  199. 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 `name` because we want it
46
- # to work with inheritance via polymorphism.
47
- class_eval(<<-EOS, __FILE__, __LINE__ + 1)
48
- def self.#{sym}
49
- @__thread_mattr_#{sym} ||= "attr_\#{name}_#{sym}"
50
- ::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}]
51
- end
52
- EOS
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, default: nil) # :nodoc:
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 `name` because we want it
90
- # to work with inheritance via polymorphism.
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_\#{name}_#{sym}"
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
- # = Bite-sized separation of concerns
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
- # = Dissatisfying ways to separate small concerns
21
+ # == Dissatisfying ways to separate small concerns
22
22
  #
23
- # == Using comments:
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
- # == With an inline module:
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
- # == Mix-in noise exiled to its own file:
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
- # = Introducing Module#concerning
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
- # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
7
- # option is not used.
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 +Module::DelegationError+
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
- # +Module::DelegationError+ is raised. If you wish to instead return +nil+,
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
- # # => Module::DelegationError: User#age delegated to profile.age, but profile is nil
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
- unless to
173
- raise ArgumentError, "Delegation needs a target. Supply a keyword argument 'to' (e.g. delegate :hello, to: :greeter)."
174
- end
175
-
176
- if prefix == true && /^[^a-z_]/.match?(to)
177
- raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
178
- end
179
-
180
- method_prefix = \
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
- target = target.to_s
291
- target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
292
-
293
- module_eval <<-RUBY, __FILE__, __LINE__ + 1
294
- def respond_to_missing?(name, include_private = false)
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: 'message'
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
- # You can also use custom deprecator instance:
9
- #
10
- # deprecate :foo, deprecator: MyLib::Deprecator.new
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.deprecate_methods(self, *method_names)
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
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/string/filters"
4
3
  require "active_support/inflector"
5
4
 
6
5
  class Module
@@ -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.prepend ActiveSupport::NumericWithFormat
142
- Float.prepend ActiveSupport::NumericWithFormat
143
- BigDecimal.prepend ActiveSupport::NumericWithFormat
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? : !self
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
@@ -28,23 +28,32 @@ class Object
28
28
  end
29
29
  end
30
30
 
31
- class Method
32
- # Methods are not duplicable:
33
- #
34
- # method(:puts).duplicable? # => false
35
- # method(:puts).dup # => TypeError: allocator undefined for Method
36
- def duplicable?
37
- false
38
- end
31
+ methods_are_duplicable = begin
32
+ Object.instance_method(:duplicable?).dup
33
+ true
34
+ rescue TypeError
35
+ false
39
36
  end
40
37
 
41
- class UnboundMethod
42
- # Unbound methods are not duplicable:
43
- #
44
- # method(:puts).unbind.duplicable? # => false
45
- # method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
46
- def duplicable?
47
- false
38
+ unless methods_are_duplicable
39
+ class Method
40
+ # Methods are not duplicable:
41
+ #
42
+ # method(:puts).duplicable? # => false
43
+ # method(:puts).dup # => TypeError: allocator undefined for Method
44
+ def duplicable?
45
+ false
46
+ end
47
+ end
48
+
49
+ class UnboundMethod
50
+ # Unbound methods are not duplicable:
51
+ #
52
+ # method(:puts).unbind.duplicable? # => false
53
+ # method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
54
+ def duplicable?
55
+ false
56
+ end
48
57
  end
49
58
  end
50
59
 
@@ -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. Argument must be
5
- # any object which responds to +#include?+. Usage:
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
- # This will throw an +ArgumentError+ if the argument doesn't respond
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.include?(self)
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
- Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
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(&:to_s)
30
+ instance_variables.map(&:name)
29
31
  end
30
32
  end