activesupport 5.2.4.4 → 6.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +353 -435
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support.rb +14 -1
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/array_inquirer.rb +4 -2
  8. data/lib/active_support/backtrace_cleaner.rb +29 -3
  9. data/lib/active_support/benchmarkable.rb +1 -1
  10. data/lib/active_support/cache.rb +142 -78
  11. data/lib/active_support/cache/file_store.rb +33 -33
  12. data/lib/active_support/cache/mem_cache_store.rb +32 -20
  13. data/lib/active_support/cache/memory_store.rb +59 -33
  14. data/lib/active_support/cache/null_store.rb +8 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +70 -43
  16. data/lib/active_support/cache/strategy/local_cache.rb +41 -26
  17. data/lib/active_support/callbacks.rb +81 -64
  18. data/lib/active_support/concern.rb +70 -3
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  20. data/lib/active_support/concurrency/share_lock.rb +0 -1
  21. data/lib/active_support/configurable.rb +10 -14
  22. data/lib/active_support/configuration_file.rb +46 -0
  23. data/lib/active_support/core_ext.rb +1 -1
  24. data/lib/active_support/core_ext/array.rb +1 -1
  25. data/lib/active_support/core_ext/array/access.rb +18 -6
  26. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/benchmark.rb +2 -2
  29. data/lib/active_support/core_ext/class/attribute.rb +32 -47
  30. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  31. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  32. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  36. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  37. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  38. data/lib/active_support/core_ext/enumerable.rb +171 -75
  39. data/lib/active_support/core_ext/hash.rb +1 -2
  40. data/lib/active_support/core_ext/hash/conversions.rb +3 -3
  41. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  42. data/lib/active_support/core_ext/hash/except.rb +2 -2
  43. data/lib/active_support/core_ext/hash/keys.rb +1 -30
  44. data/lib/active_support/core_ext/hash/slice.rb +6 -27
  45. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  46. data/lib/active_support/core_ext/kernel.rb +0 -1
  47. data/lib/active_support/core_ext/load_error.rb +1 -1
  48. data/lib/active_support/core_ext/marshal.rb +2 -0
  49. data/lib/active_support/core_ext/module.rb +0 -1
  50. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  51. data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
  52. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
  53. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  54. data/lib/active_support/core_ext/module/delegation.rb +76 -33
  55. data/lib/active_support/core_ext/module/introspection.rb +16 -15
  56. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  57. data/lib/active_support/core_ext/name_error.rb +29 -2
  58. data/lib/active_support/core_ext/numeric.rb +0 -1
  59. data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
  60. data/lib/active_support/core_ext/object/blank.rb +1 -2
  61. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  62. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  63. data/lib/active_support/core_ext/object/json.rb +14 -2
  64. data/lib/active_support/core_ext/object/try.rb +17 -7
  65. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  66. data/lib/active_support/core_ext/range/compare_range.rb +34 -13
  67. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  68. data/lib/active_support/core_ext/range/each.rb +0 -1
  69. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  70. data/lib/active_support/core_ext/regexp.rb +8 -5
  71. data/lib/active_support/core_ext/securerandom.rb +23 -3
  72. data/lib/active_support/core_ext/string/access.rb +5 -16
  73. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  74. data/lib/active_support/core_ext/string/filters.rb +42 -1
  75. data/lib/active_support/core_ext/string/inflections.rb +45 -6
  76. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  77. data/lib/active_support/core_ext/string/multibyte.rb +6 -5
  78. data/lib/active_support/core_ext/string/output_safety.rb +70 -13
  79. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  80. data/lib/active_support/core_ext/string/strip.rb +3 -1
  81. data/lib/active_support/core_ext/symbol.rb +3 -0
  82. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  83. data/lib/active_support/core_ext/time/calculations.rb +50 -3
  84. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  85. data/lib/active_support/core_ext/uri.rb +6 -1
  86. data/lib/active_support/current_attributes.rb +15 -2
  87. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  88. data/lib/active_support/dependencies.rb +109 -34
  89. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  90. data/lib/active_support/deprecation.rb +6 -1
  91. data/lib/active_support/deprecation/behaviors.rb +16 -3
  92. data/lib/active_support/deprecation/disallowed.rb +56 -0
  93. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  94. data/lib/active_support/deprecation/method_wrappers.rb +18 -23
  95. data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
  96. data/lib/active_support/deprecation/reporting.rb +50 -7
  97. data/lib/active_support/descendants_tracker.rb +59 -9
  98. data/lib/active_support/duration.rb +90 -38
  99. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  100. data/lib/active_support/duration/iso8601_serializer.rb +18 -14
  101. data/lib/active_support/encrypted_configuration.rb +0 -4
  102. data/lib/active_support/encrypted_file.rb +22 -4
  103. data/lib/active_support/environment_inquirer.rb +20 -0
  104. data/lib/active_support/evented_file_update_checker.rb +82 -117
  105. data/lib/active_support/execution_wrapper.rb +1 -0
  106. data/lib/active_support/file_update_checker.rb +0 -1
  107. data/lib/active_support/fork_tracker.rb +62 -0
  108. data/lib/active_support/gem_version.rb +4 -4
  109. data/lib/active_support/hash_with_indifferent_access.rb +64 -41
  110. data/lib/active_support/i18n.rb +1 -0
  111. data/lib/active_support/i18n_railtie.rb +15 -8
  112. data/lib/active_support/inflector/inflections.rb +2 -7
  113. data/lib/active_support/inflector/methods.rb +49 -58
  114. data/lib/active_support/inflector/transliterate.rb +47 -18
  115. data/lib/active_support/json/decoding.rb +25 -26
  116. data/lib/active_support/json/encoding.rb +11 -3
  117. data/lib/active_support/key_generator.rb +1 -33
  118. data/lib/active_support/lazy_load_hooks.rb +5 -2
  119. data/lib/active_support/locale/en.rb +33 -0
  120. data/lib/active_support/locale/en.yml +7 -3
  121. data/lib/active_support/log_subscriber.rb +39 -9
  122. data/lib/active_support/logger.rb +2 -17
  123. data/lib/active_support/logger_silence.rb +11 -19
  124. data/lib/active_support/logger_thread_safe_level.rb +50 -6
  125. data/lib/active_support/message_encryptor.rb +8 -13
  126. data/lib/active_support/message_verifier.rb +10 -10
  127. data/lib/active_support/messages/metadata.rb +11 -2
  128. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  129. data/lib/active_support/messages/rotator.rb +10 -9
  130. data/lib/active_support/multibyte/chars.rb +10 -68
  131. data/lib/active_support/multibyte/unicode.rb +15 -327
  132. data/lib/active_support/notifications.rb +72 -8
  133. data/lib/active_support/notifications/fanout.rb +116 -16
  134. data/lib/active_support/notifications/instrumenter.rb +71 -9
  135. data/lib/active_support/number_helper.rb +38 -12
  136. data/lib/active_support/number_helper/number_converter.rb +5 -6
  137. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
  138. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  139. data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
  140. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
  141. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  142. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  143. data/lib/active_support/number_helper/number_to_rounded_converter.rb +8 -7
  144. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  145. data/lib/active_support/option_merger.rb +22 -3
  146. data/lib/active_support/ordered_hash.rb +1 -1
  147. data/lib/active_support/ordered_options.rb +13 -3
  148. data/lib/active_support/parameter_filter.rb +133 -0
  149. data/lib/active_support/per_thread_registry.rb +1 -1
  150. data/lib/active_support/rails.rb +1 -10
  151. data/lib/active_support/railtie.rb +23 -1
  152. data/lib/active_support/reloader.rb +4 -5
  153. data/lib/active_support/rescuable.rb +4 -4
  154. data/lib/active_support/secure_compare_rotator.rb +51 -0
  155. data/lib/active_support/security_utils.rb +19 -12
  156. data/lib/active_support/string_inquirer.rb +4 -3
  157. data/lib/active_support/subscriber.rb +72 -28
  158. data/lib/active_support/tagged_logging.rb +42 -8
  159. data/lib/active_support/test_case.rb +91 -0
  160. data/lib/active_support/testing/assertions.rb +30 -9
  161. data/lib/active_support/testing/deprecation.rb +0 -1
  162. data/lib/active_support/testing/file_fixtures.rb +2 -0
  163. data/lib/active_support/testing/isolation.rb +2 -2
  164. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  165. data/lib/active_support/testing/parallelization.rb +51 -0
  166. data/lib/active_support/testing/parallelization/server.rb +78 -0
  167. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  168. data/lib/active_support/testing/stream.rb +1 -2
  169. data/lib/active_support/testing/time_helpers.rb +47 -12
  170. data/lib/active_support/time_with_zone.rb +81 -47
  171. data/lib/active_support/values/time_zone.rb +32 -17
  172. data/lib/active_support/xml_mini.rb +2 -10
  173. data/lib/active_support/xml_mini/jdom.rb +2 -3
  174. data/lib/active_support/xml_mini/libxml.rb +2 -2
  175. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  178. data/lib/active_support/xml_mini/rexml.rb +10 -3
  179. metadata +58 -32
  180. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
  181. data/lib/active_support/core_ext/hash/compact.rb +0 -29
  182. data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
  183. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  184. data/lib/active_support/core_ext/module/reachable.rb +0 -11
  185. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
  186. data/lib/active_support/core_ext/range/include_range.rb +0 -3
  187. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/regexp"
4
3
  require "concurrent/map"
5
4
 
6
5
  class Object
7
6
  # An object is blank if it's false, empty, or a whitespace string.
8
- # For example, +false+, '', ' ', +nil+, [], and {} are all blank.
7
+ # For example, +nil+, '', ' ', [], {}, and +false+ are all blank.
9
8
  #
10
9
  # This simplifies
11
10
  #
@@ -43,7 +43,7 @@ class Hash
43
43
  def deep_dup
44
44
  hash = dup
45
45
  each_pair do |key, value|
46
- if key.frozen? && ::String === key
46
+ if (::String === key && key.frozen?) || ::Symbol === key
47
47
  hash[key] = value.deep_dup
48
48
  else
49
49
  hash.delete(key)
@@ -28,93 +28,6 @@ class Object
28
28
  end
29
29
  end
30
30
 
31
- class NilClass
32
- begin
33
- nil.dup
34
- rescue TypeError
35
-
36
- # +nil+ is not duplicable:
37
- #
38
- # nil.duplicable? # => false
39
- # nil.dup # => TypeError: can't dup NilClass
40
- def duplicable?
41
- false
42
- end
43
- end
44
- end
45
-
46
- class FalseClass
47
- begin
48
- false.dup
49
- rescue TypeError
50
-
51
- # +false+ is not duplicable:
52
- #
53
- # false.duplicable? # => false
54
- # false.dup # => TypeError: can't dup FalseClass
55
- def duplicable?
56
- false
57
- end
58
- end
59
- end
60
-
61
- class TrueClass
62
- begin
63
- true.dup
64
- rescue TypeError
65
-
66
- # +true+ is not duplicable:
67
- #
68
- # true.duplicable? # => false
69
- # true.dup # => TypeError: can't dup TrueClass
70
- def duplicable?
71
- false
72
- end
73
- end
74
- end
75
-
76
- class Symbol
77
- begin
78
- :symbol.dup # Ruby 2.4.x.
79
- "symbol_from_string".to_sym.dup # Some symbols can't `dup` in Ruby 2.4.0.
80
- rescue TypeError
81
-
82
- # Symbols are not duplicable:
83
- #
84
- # :my_symbol.duplicable? # => false
85
- # :my_symbol.dup # => TypeError: can't dup Symbol
86
- def duplicable?
87
- false
88
- end
89
- end
90
- end
91
-
92
- class Numeric
93
- begin
94
- 1.dup
95
- rescue TypeError
96
-
97
- # Numbers are not duplicable:
98
- #
99
- # 3.duplicable? # => false
100
- # 3.dup # => TypeError: can't dup Integer
101
- def duplicable?
102
- false
103
- end
104
- end
105
- end
106
-
107
- require "bigdecimal"
108
- class BigDecimal
109
- # BigDecimals are duplicable:
110
- #
111
- # BigDecimal("1.2").duplicable? # => true
112
- # BigDecimal("1.2").dup # => #<BigDecimal:...,'0.12E1',18(18)>
113
- def duplicable?
114
- true
115
- end
116
- end
117
-
118
31
  class Method
119
32
  # Methods are not duplicable:
120
33
  #
@@ -125,32 +38,12 @@ class Method
125
38
  end
126
39
  end
127
40
 
128
- class Complex
129
- begin
130
- Complex(1).dup
131
- rescue TypeError
132
-
133
- # Complexes are not duplicable:
134
- #
135
- # Complex(1).duplicable? # => false
136
- # Complex(1).dup # => TypeError: can't copy Complex
137
- def duplicable?
138
- false
139
- end
140
- end
141
- end
142
-
143
- class Rational
144
- begin
145
- Rational(1).dup
146
- rescue TypeError
147
-
148
- # Rationals are not duplicable:
149
- #
150
- # Rational(1).duplicable? # => false
151
- # Rational(1).dup # => TypeError: can't copy Rational
152
- def duplicable?
153
- false
154
- end
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
155
48
  end
156
49
  end
@@ -3,6 +3,7 @@
3
3
  # Hack to load json gem first so we can overwrite its to_json.
4
4
  require "json"
5
5
  require "bigdecimal"
6
+ require "ipaddr"
6
7
  require "uri/generic"
7
8
  require "pathname"
8
9
  require "active_support/core_ext/big_decimal/conversions" # for #to_s
@@ -14,6 +15,7 @@ require "active_support/core_ext/time/conversions"
14
15
  require "active_support/core_ext/date_time/conversions"
15
16
  require "active_support/core_ext/date/conversions"
16
17
 
18
+ #--
17
19
  # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
18
20
  # their default behavior. That said, we need to define the basic to_json method in all of them,
19
21
  # otherwise they will always use to_json gem implementation, which is backwards incompatible in
@@ -44,7 +46,7 @@ module ActiveSupport
44
46
  end
45
47
  end
46
48
 
47
- [Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].reverse_each do |klass|
49
+ [Enumerable, Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].reverse_each do |klass|
48
50
  klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder)
49
51
  end
50
52
 
@@ -168,7 +170,11 @@ class Hash
168
170
  self
169
171
  end
170
172
 
171
- Hash[subset.map { |k, v| [k.to_s, options ? v.as_json(options.dup) : v.as_json] }]
173
+ result = {}
174
+ subset.each do |k, v|
175
+ result[k.to_s] = options ? v.as_json(options.dup) : v.as_json
176
+ end
177
+ result
172
178
  end
173
179
  end
174
180
 
@@ -214,6 +220,12 @@ class Pathname #:nodoc:
214
220
  end
215
221
  end
216
222
 
223
+ class IPAddr # :nodoc:
224
+ def as_json(options = nil)
225
+ to_s
226
+ end
227
+ end
228
+
217
229
  class Process::Status #:nodoc:
218
230
  def as_json(options = nil)
219
231
  { exitstatus: exitstatus, pid: pid }
@@ -4,21 +4,31 @@ require "delegate"
4
4
 
5
5
  module ActiveSupport
6
6
  module Tryable #:nodoc:
7
- def try(*a, &b)
8
- try!(*a, &b) if a.empty? || respond_to?(a.first)
7
+ def try(method_name = nil, *args, &b)
8
+ if method_name.nil? && block_given?
9
+ if b.arity == 0
10
+ instance_eval(&b)
11
+ else
12
+ yield self
13
+ end
14
+ elsif respond_to?(method_name)
15
+ public_send(method_name, *args, &b)
16
+ end
9
17
  end
18
+ ruby2_keywords(:try) if respond_to?(:ruby2_keywords, true)
10
19
 
11
- def try!(*a, &b)
12
- if a.empty? && block_given?
20
+ def try!(method_name = nil, *args, &b)
21
+ if method_name.nil? && block_given?
13
22
  if b.arity == 0
14
23
  instance_eval(&b)
15
24
  else
16
25
  yield self
17
26
  end
18
27
  else
19
- public_send(*a, &b)
28
+ public_send(method_name, *args, &b)
20
29
  end
21
30
  end
31
+ ruby2_keywords(:try!) if respond_to?(:ruby2_keywords, true)
22
32
  end
23
33
  end
24
34
 
@@ -135,14 +145,14 @@ class NilClass
135
145
  #
136
146
  # With +try+
137
147
  # @person.try(:children).try(:first).try(:name)
138
- def try(*args)
148
+ def try(_method_name = nil, *)
139
149
  nil
140
150
  end
141
151
 
142
152
  # Calling +try!+ on +nil+ always returns +nil+.
143
153
  #
144
154
  # nil.try!(:name) # => nil
145
- def try!(*args)
155
+ def try!(_method_name = nil, *)
146
156
  nil
147
157
  end
148
158
  end
@@ -68,7 +68,7 @@ class Object
68
68
  # You can access these methods using the class name instead:
69
69
  #
70
70
  # class Phone < ActiveRecord::Base
71
- # enum phone_number_type: [home: 0, office: 1, mobile: 2]
71
+ # enum phone_number_type: { home: 0, office: 1, mobile: 2 }
72
72
  #
73
73
  # with_options presence: true do
74
74
  # validates :phone_number_type, inclusion: { in: Phone.phone_number_types.keys }
@@ -1,56 +1,77 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
- module CompareWithRange #:nodoc:
4
+ module CompareWithRange
5
5
  # Extends the default Range#=== to support range comparisons.
6
- # (1..5) === (1..5) # => true
7
- # (1..5) === (2..3) # => true
8
- # (1..5) === (2..6) # => false
6
+ # (1..5) === (1..5) # => true
7
+ # (1..5) === (2..3) # => true
8
+ # (1..5) === (1...6) # => true
9
+ # (1..5) === (2..6) # => false
9
10
  #
10
11
  # The native Range#=== behavior is untouched.
11
12
  # ('a'..'f') === ('c') # => true
12
13
  # (5..9) === (11) # => false
14
+ #
15
+ # The given range must be fully bounded, with both start and end.
13
16
  def ===(value)
14
17
  if value.is_a?(::Range)
18
+ is_backwards_op = value.exclude_end? ? :>= : :>
19
+ return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
15
20
  # 1...10 includes 1..9 but it does not include 1..10.
21
+ # 1..10 includes 1...11 but it does not include 1...12.
16
22
  operator = exclude_end? && !value.exclude_end? ? :< : :<=
17
- super(value.first) && value.last.send(operator, last)
23
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
24
+ super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
18
25
  else
19
26
  super
20
27
  end
21
28
  end
22
29
 
23
30
  # Extends the default Range#include? to support range comparisons.
24
- # (1..5).include?(1..5) # => true
25
- # (1..5).include?(2..3) # => true
26
- # (1..5).include?(2..6) # => false
31
+ # (1..5).include?(1..5) # => true
32
+ # (1..5).include?(2..3) # => true
33
+ # (1..5).include?(1...6) # => true
34
+ # (1..5).include?(2..6) # => false
27
35
  #
28
36
  # The native Range#include? behavior is untouched.
29
37
  # ('a'..'f').include?('c') # => true
30
38
  # (5..9).include?(11) # => false
39
+ #
40
+ # The given range must be fully bounded, with both start and end.
31
41
  def include?(value)
32
42
  if value.is_a?(::Range)
43
+ is_backwards_op = value.exclude_end? ? :>= : :>
44
+ return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
33
45
  # 1...10 includes 1..9 but it does not include 1..10.
46
+ # 1..10 includes 1...11 but it does not include 1...12.
34
47
  operator = exclude_end? && !value.exclude_end? ? :< : :<=
35
- super(value.first) && value.last.send(operator, last)
48
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
49
+ super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
36
50
  else
37
51
  super
38
52
  end
39
53
  end
40
54
 
41
55
  # Extends the default Range#cover? to support range comparisons.
42
- # (1..5).cover?(1..5) # => true
43
- # (1..5).cover?(2..3) # => true
44
- # (1..5).cover?(2..6) # => false
56
+ # (1..5).cover?(1..5) # => true
57
+ # (1..5).cover?(2..3) # => true
58
+ # (1..5).cover?(1...6) # => true
59
+ # (1..5).cover?(2..6) # => false
45
60
  #
46
61
  # The native Range#cover? behavior is untouched.
47
62
  # ('a'..'f').cover?('c') # => true
48
63
  # (5..9).cover?(11) # => false
64
+ #
65
+ # The given range must be fully bounded, with both start and end.
49
66
  def cover?(value)
50
67
  if value.is_a?(::Range)
68
+ is_backwards_op = value.exclude_end? ? :>= : :>
69
+ return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
51
70
  # 1...10 covers 1..9 but it does not cover 1..10.
71
+ # 1..10 covers 1...11 but it does not cover 1...12.
52
72
  operator = exclude_end? && !value.exclude_end? ? :< : :<=
53
- super(value.first) && value.last.send(operator, last)
73
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
74
+ super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
54
75
  else
55
76
  super
56
77
  end
@@ -1,39 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ActiveSupport::RangeWithFormat
4
- RANGE_FORMATS = {
5
- db: -> (start, stop) do
6
- case start
7
- when String then "BETWEEN '#{start}' AND '#{stop}'"
3
+ module ActiveSupport
4
+ module RangeWithFormat
5
+ RANGE_FORMATS = {
6
+ db: -> (start, stop) do
7
+ case start
8
+ when String then "BETWEEN '#{start}' AND '#{stop}'"
9
+ else
10
+ "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'"
11
+ end
12
+ end
13
+ }
14
+
15
+ # Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
16
+ #
17
+ # range = (1..100) # => 1..100
18
+ #
19
+ # range.to_s # => "1..100"
20
+ # range.to_s(:db) # => "BETWEEN '1' AND '100'"
21
+ #
22
+ # == Adding your own range formats to to_s
23
+ # You can add your own formats to the Range::RANGE_FORMATS hash.
24
+ # Use the format name as the hash key and a Proc instance.
25
+ #
26
+ # # config/initializers/range_formats.rb
27
+ # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
28
+ def to_s(format = :default)
29
+ if formatter = RANGE_FORMATS[format]
30
+ formatter.call(first, last)
8
31
  else
9
- "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'"
32
+ super()
10
33
  end
11
34
  end
12
- }
13
35
 
14
- # Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
15
- #
16
- # range = (1..100) # => 1..100
17
- #
18
- # range.to_s # => "1..100"
19
- # range.to_s(:db) # => "BETWEEN '1' AND '100'"
20
- #
21
- # == Adding your own range formats to to_s
22
- # You can add your own formats to the Range::RANGE_FORMATS hash.
23
- # Use the format name as the hash key and a Proc instance.
24
- #
25
- # # config/initializers/range_formats.rb
26
- # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
27
- def to_s(format = :default)
28
- if formatter = RANGE_FORMATS[format]
29
- formatter.call(first, last)
30
- else
31
- super()
32
- end
36
+ alias_method :to_default_s, :to_s
37
+ alias_method :to_formatted_s, :to_s
33
38
  end
34
-
35
- alias_method :to_default_s, :to_s
36
- alias_method :to_formatted_s, :to_s
37
39
  end
38
40
 
39
41
  Range.prepend(ActiveSupport::RangeWithFormat)
@@ -15,7 +15,6 @@ module ActiveSupport
15
15
  end
16
16
 
17
17
  private
18
-
19
18
  def ensure_iteration_allowed
20
19
  raise TypeError, "can't iterate from #{first.class}" if first.is_a?(TimeWithZone)
21
20
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/time_with_zone"
4
+ require "active_support/deprecation"
4
5
 
5
6
  module ActiveSupport
6
7
  module IncludeTimeWithZone #:nodoc:
@@ -9,9 +10,13 @@ module ActiveSupport
9
10
  # (1.hour.ago..1.hour.from_now).include?(Time.current) # => true
10
11
  #
11
12
  def include?(value)
12
- if first.is_a?(TimeWithZone)
13
- cover?(value)
14
- elsif last.is_a?(TimeWithZone)
13
+ if self.begin.is_a?(TimeWithZone) || self.end.is_a?(TimeWithZone)
14
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
15
+ Using `Range#include?` to check the inclusion of a value in
16
+ a date time range is deprecated.
17
+ It is recommended to use `Range#cover?` instead of `Range#include?` to
18
+ check the inclusion of a value in a date time range.
19
+ MSG
15
20
  cover?(value)
16
21
  else
17
22
  super