activesupport 5.2.7 → 6.0.0.beta1

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 (127) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +182 -566
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support/backtrace_cleaner.rb +23 -0
  6. data/lib/active_support/cache/file_store.rb +19 -12
  7. data/lib/active_support/cache/mem_cache_store.rb +16 -2
  8. data/lib/active_support/cache/memory_store.rb +5 -0
  9. data/lib/active_support/cache/null_store.rb +5 -0
  10. data/lib/active_support/cache/redis_cache_store.rb +39 -20
  11. data/lib/active_support/cache.rb +40 -18
  12. data/lib/active_support/callbacks.rb +16 -5
  13. data/lib/active_support/configurable.rb +4 -8
  14. data/lib/active_support/core_ext/array/extract.rb +21 -0
  15. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  16. data/lib/active_support/core_ext/array.rb +1 -1
  17. data/lib/active_support/core_ext/class/attribute.rb +1 -1
  18. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  19. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  20. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -17
  21. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  22. data/lib/active_support/core_ext/enumerable.rb +71 -67
  23. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  24. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  25. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  26. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  27. data/lib/active_support/core_ext/hash.rb +0 -2
  28. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  29. data/lib/active_support/core_ext/load_error.rb +1 -1
  30. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -5
  31. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -14
  32. data/lib/active_support/core_ext/module/delegation.rb +27 -7
  33. data/lib/active_support/core_ext/module/introspection.rb +37 -13
  34. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  35. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  36. data/lib/active_support/core_ext/module.rb +0 -1
  37. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  38. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  39. data/lib/active_support/core_ext/numeric.rb +0 -1
  40. data/lib/active_support/core_ext/object/blank.rb +1 -2
  41. data/lib/active_support/core_ext/object/duplicable.rb +5 -2
  42. data/lib/active_support/core_ext/object/json.rb +1 -0
  43. data/lib/active_support/core_ext/object/try.rb +15 -7
  44. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  45. data/lib/active_support/core_ext/range/compare_range.rb +1 -1
  46. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  47. data/lib/active_support/core_ext/range/include_range.rb +6 -0
  48. data/lib/active_support/core_ext/regexp.rb +0 -4
  49. data/lib/active_support/core_ext/securerandom.rb +23 -3
  50. data/lib/active_support/core_ext/string/access.rb +8 -0
  51. data/lib/active_support/core_ext/string/filters.rb +41 -0
  52. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  53. data/lib/active_support/core_ext/string/output_safety.rb +16 -5
  54. data/lib/active_support/core_ext/string/strip.rb +3 -1
  55. data/lib/active_support/core_ext/uri.rb +1 -0
  56. data/lib/active_support/current_attributes.rb +2 -0
  57. data/lib/active_support/dependencies.rb +28 -11
  58. data/lib/active_support/deprecation/behaviors.rb +1 -1
  59. data/lib/active_support/deprecation/method_wrappers.rb +4 -5
  60. data/lib/active_support/deprecation/proxy_wrappers.rb +0 -2
  61. data/lib/active_support/deprecation.rb +1 -1
  62. data/lib/active_support/descendants_tracker.rb +6 -5
  63. data/lib/active_support/duration/iso8601_parser.rb +2 -3
  64. data/lib/active_support/duration/iso8601_serializer.rb +3 -4
  65. data/lib/active_support/duration.rb +12 -14
  66. data/lib/active_support/encrypted_configuration.rb +0 -4
  67. data/lib/active_support/evented_file_update_checker.rb +25 -7
  68. data/lib/active_support/execution_wrapper.rb +14 -16
  69. data/lib/active_support/gem_version.rb +4 -4
  70. data/lib/active_support/hash_with_indifferent_access.rb +16 -28
  71. data/lib/active_support/i18n.rb +1 -0
  72. data/lib/active_support/i18n_railtie.rb +8 -1
  73. data/lib/active_support/inflector/inflections.rb +1 -4
  74. data/lib/active_support/inflector/methods.rb +15 -27
  75. data/lib/active_support/inflector/transliterate.rb +6 -6
  76. data/lib/active_support/json/decoding.rb +23 -23
  77. data/lib/active_support/json/encoding.rb +6 -2
  78. data/lib/active_support/key_generator.rb +0 -32
  79. data/lib/active_support/lazy_load_hooks.rb +5 -1
  80. data/lib/active_support/locale/en.rb +31 -0
  81. data/lib/active_support/log_subscriber.rb +31 -8
  82. data/lib/active_support/logger.rb +0 -15
  83. data/lib/active_support/logger_silence.rb +28 -12
  84. data/lib/active_support/logger_thread_safe_level.rb +27 -6
  85. data/lib/active_support/message_encryptor.rb +2 -4
  86. data/lib/active_support/message_verifier.rb +2 -2
  87. data/lib/active_support/multibyte/chars.rb +29 -48
  88. data/lib/active_support/multibyte/unicode.rb +44 -281
  89. data/lib/active_support/notifications/fanout.rb +42 -4
  90. data/lib/active_support/notifications/instrumenter.rb +73 -2
  91. data/lib/active_support/notifications.rb +32 -4
  92. data/lib/active_support/number_helper/number_to_currency_converter.rb +2 -2
  93. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -1
  94. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -1
  95. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -1
  96. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  97. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -0
  98. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -3
  99. data/lib/active_support/number_helper.rb +7 -0
  100. data/lib/active_support/ordered_options.rb +1 -1
  101. data/lib/active_support/parameter_filter.rb +124 -0
  102. data/lib/active_support/rails.rb +0 -6
  103. data/lib/active_support/reloader.rb +5 -6
  104. data/lib/active_support/subscriber.rb +16 -26
  105. data/lib/active_support/tagged_logging.rb +13 -4
  106. data/lib/active_support/test_case.rb +91 -0
  107. data/lib/active_support/testing/assertions.rb +15 -1
  108. data/lib/active_support/testing/deprecation.rb +0 -1
  109. data/lib/active_support/testing/file_fixtures.rb +2 -0
  110. data/lib/active_support/testing/isolation.rb +2 -2
  111. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  112. data/lib/active_support/testing/parallelization.rb +109 -0
  113. data/lib/active_support/testing/stream.rb +1 -1
  114. data/lib/active_support/testing/time_helpers.rb +7 -7
  115. data/lib/active_support/time_with_zone.rb +15 -5
  116. data/lib/active_support/values/time_zone.rb +12 -7
  117. data/lib/active_support/xml_mini/jdom.rb +2 -2
  118. data/lib/active_support/xml_mini/libxml.rb +2 -2
  119. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  120. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  121. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  122. data/lib/active_support/xml_mini/rexml.rb +2 -2
  123. data/lib/active_support/xml_mini.rb +2 -9
  124. data/lib/active_support.rb +1 -1
  125. metadata +12 -10
  126. data/lib/active_support/core_ext/digest.rb +0 -3
  127. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -5,13 +5,13 @@ require "active_support/core_ext/object/try"
5
5
  module DateAndTime
6
6
  module Calculations
7
7
  DAYS_INTO_WEEK = {
8
- monday: 0,
9
- tuesday: 1,
10
- wednesday: 2,
11
- thursday: 3,
12
- friday: 4,
13
- saturday: 5,
14
- sunday: 6
8
+ sunday: 0,
9
+ monday: 1,
10
+ tuesday: 2,
11
+ wednesday: 3,
12
+ thursday: 4,
13
+ friday: 5,
14
+ saturday: 6
15
15
  }
16
16
  WEEKEND_DAYS = [ 6, 0 ]
17
17
 
@@ -60,6 +60,16 @@ module DateAndTime
60
60
  !WEEKEND_DAYS.include?(wday)
61
61
  end
62
62
 
63
+ # Returns true if the date/time falls before <tt>date_or_time</tt>.
64
+ def before?(date_or_time)
65
+ self < date_or_time
66
+ end
67
+
68
+ # Returns true if the date/time falls after <tt>date_or_time</tt>.
69
+ def after?(date_or_time)
70
+ self > date_or_time
71
+ end
72
+
63
73
  # Returns a new date/time the specified number of days ago.
64
74
  def days_ago(days)
65
75
  advance(days: -days)
@@ -124,7 +134,7 @@ module DateAndTime
124
134
  # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
125
135
  # now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000
126
136
  def beginning_of_quarter
127
- first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month }
137
+ first_quarter_month = month - (2 + month) % 3
128
138
  beginning_of_month.change(month: first_quarter_month)
129
139
  end
130
140
  alias :at_beginning_of_quarter :beginning_of_quarter
@@ -139,7 +149,7 @@ module DateAndTime
139
149
  # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
140
150
  # now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000
141
151
  def end_of_quarter
142
- last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month }
152
+ last_quarter_month = month + (12 - month) % 3
143
153
  beginning_of_month.change(month: last_quarter_month).end_of_month
144
154
  end
145
155
  alias :at_end_of_quarter :end_of_quarter
@@ -253,9 +263,8 @@ module DateAndTime
253
263
  # Week is assumed to start on +start_day+, default is
254
264
  # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
255
265
  def days_to_week_start(start_day = Date.beginning_of_week)
256
- start_day_number = DAYS_INTO_WEEK[start_day]
257
- current_day_number = wday != 0 ? wday - 1 : 6
258
- (current_day_number - start_day_number) % 7
266
+ start_day_number = DAYS_INTO_WEEK.fetch(start_day)
267
+ (wday - start_day_number) % 7
259
268
  end
260
269
 
261
270
  # Returns a new date/time representing the start of this week on the given day.
@@ -336,8 +345,7 @@ module DateAndTime
336
345
  # today.next_occurring(:monday) # => Mon, 18 Dec 2017
337
346
  # today.next_occurring(:thursday) # => Thu, 21 Dec 2017
338
347
  def next_occurring(day_of_week)
339
- current_day_number = wday != 0 ? wday - 1 : 6
340
- from_now = DAYS_INTO_WEEK.fetch(day_of_week) - current_day_number
348
+ from_now = DAYS_INTO_WEEK.fetch(day_of_week) - wday
341
349
  from_now += 7 unless from_now > 0
342
350
  advance(days: from_now)
343
351
  end
@@ -348,8 +356,7 @@ module DateAndTime
348
356
  # today.prev_occurring(:monday) # => Mon, 11 Dec 2017
349
357
  # today.prev_occurring(:thursday) # => Thu, 07 Dec 2017
350
358
  def prev_occurring(day_of_week)
351
- current_day_number = wday != 0 ? wday - 1 : 6
352
- ago = current_day_number - DAYS_INTO_WEEK.fetch(day_of_week)
359
+ ago = wday - DAYS_INTO_WEEK.fetch(day_of_week)
353
360
  ago += 7 unless ago > 0
354
361
  advance(days: -ago)
355
362
  end
@@ -364,7 +371,7 @@ module DateAndTime
364
371
  end
365
372
 
366
373
  def days_span(day)
367
- (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7
374
+ (DAYS_INTO_WEEK.fetch(day) - DAYS_INTO_WEEK.fetch(Date.beginning_of_week)) % 7
368
375
  end
369
376
 
370
377
  def copy_time_to(other)
@@ -110,7 +110,7 @@ class DateTime
110
110
  # instance time. Do not use this method in combination with x.months, use
111
111
  # months_since instead!
112
112
  def since(seconds)
113
- self + Rational(seconds.round, 86400)
113
+ self + Rational(seconds, 86400)
114
114
  end
115
115
  alias :in :since
116
116
 
@@ -1,64 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enumerable
4
+ INDEX_WITH_DEFAULT = Object.new
5
+ private_constant :INDEX_WITH_DEFAULT
6
+
4
7
  # Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
5
8
  # when we omit an identity.
6
- #
7
- # We tried shimming it to attempt the fast native method, rescue TypeError,
8
- # and fall back to the compatible implementation, but that's much slower than
9
- # just calling the compat method in the first place.
10
- if Enumerable.instance_methods(false).include?(:sum) && !((?a..?b).sum rescue false)
11
- # :stopdoc:
12
9
 
13
- # We can't use Refinements here because Refinements with Module which will be prepended
14
- # doesn't work well https://bugs.ruby-lang.org/issues/13446
15
- alias :_original_sum_with_required_identity :sum
16
- private :_original_sum_with_required_identity
10
+ # :stopdoc:
17
11
 
18
- # :startdoc:
12
+ # We can't use Refinements here because Refinements with Module which will be prepended
13
+ # doesn't work well https://bugs.ruby-lang.org/issues/13446
14
+ alias :_original_sum_with_required_identity :sum
15
+ private :_original_sum_with_required_identity
19
16
 
20
- # Calculates a sum from the elements.
21
- #
22
- # payments.sum { |p| p.price * p.tax_rate }
23
- # payments.sum(&:price)
24
- #
25
- # The latter is a shortcut for:
26
- #
27
- # payments.inject(0) { |sum, p| sum + p.price }
28
- #
29
- # It can also calculate the sum without the use of a block.
30
- #
31
- # [5, 15, 10].sum # => 30
32
- # ['foo', 'bar'].sum # => "foobar"
33
- # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
34
- #
35
- # The default sum of an empty list is zero. You can override this default:
36
- #
37
- # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
38
- def sum(identity = nil, &block)
39
- if identity
40
- _original_sum_with_required_identity(identity, &block)
41
- elsif block_given?
42
- map(&block).sum(identity)
43
- else
44
- inject(:+) || 0
45
- end
46
- end
47
- else
48
- def sum(identity = nil, &block)
49
- if block_given?
50
- map(&block).sum(identity)
51
- else
52
- sum = identity ? inject(identity, :+) : inject(:+)
53
- sum || identity || 0
54
- end
17
+ # :startdoc:
18
+
19
+ # Calculates a sum from the elements.
20
+ #
21
+ # payments.sum { |p| p.price * p.tax_rate }
22
+ # payments.sum(&:price)
23
+ #
24
+ # The latter is a shortcut for:
25
+ #
26
+ # payments.inject(0) { |sum, p| sum + p.price }
27
+ #
28
+ # It can also calculate the sum without the use of a block.
29
+ #
30
+ # [5, 15, 10].sum # => 30
31
+ # ['foo', 'bar'].sum # => "foobar"
32
+ # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
33
+ #
34
+ # The default sum of an empty list is zero. You can override this default:
35
+ #
36
+ # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
37
+ def sum(identity = nil, &block)
38
+ if identity
39
+ _original_sum_with_required_identity(identity, &block)
40
+ elsif block_given?
41
+ map(&block).sum(identity)
42
+ else
43
+ inject(:+) || 0
55
44
  end
56
45
  end
57
46
 
58
- # Convert an enumerable to a hash.
47
+ # Convert an enumerable to a hash keying it by the block return value.
59
48
  #
60
49
  # people.index_by(&:login)
61
50
  # # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
51
+ #
62
52
  # people.index_by { |person| "#{person.first_name} #{person.last_name}" }
63
53
  # # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
64
54
  def index_by
@@ -71,6 +61,26 @@ module Enumerable
71
61
  end
72
62
  end
73
63
 
64
+ # Convert an enumerable to a hash keying it with the enumerable items and with the values returned in the block.
65
+ #
66
+ # post = Post.new(title: "hey there", body: "what's up?")
67
+ #
68
+ # %i( title body ).index_with { |attr_name| post.public_send(attr_name) }
69
+ # # => { title: "hey there", body: "what's up?" }
70
+ def index_with(default = INDEX_WITH_DEFAULT)
71
+ if block_given?
72
+ result = {}
73
+ each { |elem| result[elem] = yield(elem) }
74
+ result
75
+ elsif default != INDEX_WITH_DEFAULT
76
+ result = {}
77
+ each { |elem| result[elem] = default }
78
+ result
79
+ else
80
+ to_enum(:index_with) { size if respond_to?(:size) }
81
+ end
82
+ end
83
+
74
84
  # Returns +true+ if the enumerable has more than 1 element. Functionally
75
85
  # equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
76
86
  # much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
@@ -138,27 +148,21 @@ class Range #:nodoc:
138
148
  end
139
149
  end
140
150
 
141
- # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
142
- #
143
- # We tried shimming it to attempt the fast native method, rescue TypeError,
144
- # and fall back to the compatible implementation, but that's much slower than
145
- # just calling the compat method in the first place.
146
- if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
147
- # Using Refinements here in order not to expose our internal method
148
- using Module.new {
149
- refine Array do
150
- alias :orig_sum :sum
151
- end
152
- }
151
+ # Using Refinements here in order not to expose our internal method
152
+ using Module.new {
153
+ refine Array do
154
+ alias :orig_sum :sum
155
+ end
156
+ }
153
157
 
154
- class Array
155
- def sum(init = nil, &block) #:nodoc:
156
- if init.is_a?(Numeric) || first.is_a?(Numeric)
157
- init ||= 0
158
- orig_sum(init, &block)
159
- else
160
- super
161
- end
158
+ class Array #:nodoc:
159
+ # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
160
+ def sum(init = nil, &block)
161
+ if init.is_a?(Numeric) || first.is_a?(Numeric)
162
+ init ||= 0
163
+ orig_sum(init, &block)
164
+ else
165
+ super
162
166
  end
163
167
  end
164
168
  end
@@ -1,29 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Hash
4
- unless Hash.instance_methods(false).include?(:compact)
5
- # Returns a hash with non +nil+ values.
6
- #
7
- # hash = { a: true, b: false, c: nil }
8
- # hash.compact # => { a: true, b: false }
9
- # hash # => { a: true, b: false, c: nil }
10
- # { c: nil }.compact # => {}
11
- # { c: true }.compact # => { c: true }
12
- def compact
13
- select { |_, value| !value.nil? }
14
- end
15
- end
3
+ require "active_support/deprecation"
16
4
 
17
- unless Hash.instance_methods(false).include?(:compact!)
18
- # Replaces current hash with non +nil+ values.
19
- # Returns +nil+ if no changes were made, otherwise returns the hash.
20
- #
21
- # hash = { a: true, b: false, c: nil }
22
- # hash.compact! # => { a: true, b: false }
23
- # hash # => { a: true, b: false }
24
- # { c: true }.compact! # => nil
25
- def compact!
26
- reject! { |_, value| value.nil? }
27
- end
28
- end
29
- end
5
+ ActiveSupport::Deprecation.warn "Ruby 2.5+ (required by Rails 6) provides Hash#compact and Hash#compact! natively, so requiring active_support/core_ext/hash/compact is no longer necessary. Requiring it will raise LoadError in Rails 6.1."
@@ -1,35 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Hash
4
- # Returns a new hash with all keys converted using the +block+ operation.
5
- #
6
- # hash = { name: 'Rob', age: '28' }
7
- #
8
- # hash.transform_keys { |key| key.to_s.upcase } # => {"NAME"=>"Rob", "AGE"=>"28"}
9
- #
10
- # If you do not provide a +block+, it will return an Enumerator
11
- # for chaining with other methods:
12
- #
13
- # hash.transform_keys.with_index { |k, i| [k, i].join } # => {"name0"=>"Rob", "age1"=>"28"}
14
- def transform_keys
15
- return enum_for(:transform_keys) { size } unless block_given?
16
- result = {}
17
- each_key do |key|
18
- result[yield(key)] = self[key]
19
- end
20
- result
21
- end unless method_defined? :transform_keys
22
-
23
- # Destructively converts all keys using the +block+ operations.
24
- # Same as +transform_keys+ but modifies +self+.
25
- def transform_keys!
26
- return enum_for(:transform_keys!) { size } unless block_given?
27
- keys.each do |key|
28
- self[yield(key)] = delete(key)
29
- end
30
- self
31
- end unless method_defined? :transform_keys!
32
-
33
4
  # Returns a new hash with all keys converted to strings.
34
5
  #
35
6
  # hash = { name: 'Rob', age: '28' }
@@ -1,34 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Hash
4
- # Slices a hash to include only the given keys. Returns a hash containing
5
- # the given keys.
6
- #
7
- # { a: 1, b: 2, c: 3, d: 4 }.slice(:a, :b)
8
- # # => {:a=>1, :b=>2}
9
- #
10
- # This is useful for limiting an options hash to valid keys before
11
- # passing to a method:
12
- #
13
- # def search(criteria = {})
14
- # criteria.assert_valid_keys(:mass, :velocity, :time)
15
- # end
16
- #
17
- # search(options.slice(:mass, :velocity, :time))
18
- #
19
- # If you have an array of keys you want to limit to, you should splat them:
20
- #
21
- # valid_keys = [:mass, :velocity, :time]
22
- # search(options.slice(*valid_keys))
23
- def slice(*keys)
24
- keys.each_with_object(Hash.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
25
- end unless method_defined?(:slice)
26
-
27
4
  # Replaces the hash with only the given keys.
28
5
  # Returns a hash containing the removed key/value pairs.
29
6
  #
30
- # { a: 1, b: 2, c: 3, d: 4 }.slice!(:a, :b)
31
- # # => {:c=>3, :d=>4}
7
+ # hash = { a: 1, b: 2, c: 3, d: 4 }
8
+ # hash.slice!(:a, :b) # => {:c=>3, :d=>4}
9
+ # hash # => {:a=>1, :b=>2}
32
10
  def slice!(*keys)
33
11
  omit = slice(*self.keys - keys)
34
12
  hash = slice(*keys)
@@ -1,32 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Hash
4
- # Returns a new hash with the results of running +block+ once for every value.
5
- # The keys are unchanged.
6
- #
7
- # { a: 1, b: 2, c: 3 }.transform_values { |x| x * 2 } # => { a: 2, b: 4, c: 6 }
8
- #
9
- # If you do not provide a +block+, it will return an Enumerator
10
- # for chaining with other methods:
11
- #
12
- # { a: 1, b: 2 }.transform_values.with_index { |v, i| [v, i].join.to_i } # => { a: 10, b: 21 }
13
- def transform_values
14
- return enum_for(:transform_values) { size } unless block_given?
15
- return {} if empty?
16
- result = self.class.new
17
- each do |key, value|
18
- result[key] = yield(value)
19
- end
20
- result
21
- end unless method_defined? :transform_values
3
+ require "active_support/deprecation"
22
4
 
23
- # Destructively converts all values using the +block+ operations.
24
- # Same as +transform_values+ but modifies +self+.
25
- def transform_values!
26
- return enum_for(:transform_values!) { size } unless block_given?
27
- each do |key, value|
28
- self[key] = yield(value)
29
- end
30
- end unless method_defined? :transform_values!
31
- # TODO: Remove this file when supporting only Ruby 2.4+.
32
- end
5
+ ActiveSupport::Deprecation.warn "Ruby 2.5+ (required by Rails 6) provides Hash#transform_values natively, so requiring active_support/core_ext/hash/transform_values is no longer necessary. Requiring it will raise LoadError in Rails 6.1."
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/hash/compact"
4
3
  require "active_support/core_ext/hash/conversions"
5
4
  require "active_support/core_ext/hash/deep_merge"
6
5
  require "active_support/core_ext/hash/except"
@@ -8,4 +7,3 @@ require "active_support/core_ext/hash/indifferent_access"
8
7
  require "active_support/core_ext/hash/keys"
9
8
  require "active_support/core_ext/hash/reverse_merge"
10
9
  require "active_support/core_ext/hash/slice"
11
- require "active_support/core_ext/hash/transform_values"
@@ -7,6 +7,6 @@ class Integer
7
7
  # 6.multiple_of?(5) # => false
8
8
  # 10.multiple_of?(2) # => true
9
9
  def multiple_of?(number)
10
- number != 0 ? self % number == 0 : zero?
10
+ number == 0 ? self == 0 : self % number == 0
11
11
  end
12
12
  end
@@ -4,6 +4,6 @@ class LoadError
4
4
  # Returns true if the given path name (except perhaps for the ".rb"
5
5
  # extension) is the missing file which caused the exception to be raised.
6
6
  def is_missing?(location)
7
- location.sub(/\.rb$/, "".freeze) == path.sub(/\.rb$/, "".freeze)
7
+ location.sub(/\.rb$/, "") == path.to_s.sub(/\.rb$/, "")
8
8
  end
9
9
  end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/array/extract_options"
4
- require "active_support/core_ext/regexp"
5
-
6
3
  # Extends the module object with class/module and instance accessors for
7
4
  # class/module attributes, just like the native attr* accessors for instance
8
5
  # attributes.
@@ -163,10 +160,10 @@ class Module
163
160
  # parent class. Similarly if parent class changes the value then that would
164
161
  # change the value of subclasses too.
165
162
  #
166
- # class Male < Person
163
+ # class Citizen < Person
167
164
  # end
168
165
  #
169
- # Male.new.hair_colors << :blue
166
+ # Citizen.new.hair_colors << :blue
170
167
  # Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
171
168
  #
172
169
  # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/array/extract_options"
4
- require "active_support/core_ext/regexp"
5
-
6
3
  # Extends the module object with class/module and instance accessors for
7
4
  # class/module attributes, just like the native attr* accessors for instance
8
5
  # attributes, but does so on a per-thread basis.
@@ -36,9 +33,7 @@ class Module
36
33
  # end
37
34
  #
38
35
  # Current.new.user # => NoMethodError
39
- def thread_mattr_reader(*syms) # :nodoc:
40
- options = syms.extract_options!
41
-
36
+ def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true) # :nodoc:
42
37
  syms.each do |sym|
43
38
  raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
44
39
 
@@ -50,7 +45,7 @@ class Module
50
45
  end
51
46
  EOS
52
47
 
53
- unless options[:instance_reader] == false || options[:instance_accessor] == false
48
+ if instance_reader && instance_accessor
54
49
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
55
50
  def #{sym}
56
51
  self.class.#{sym}
@@ -79,8 +74,7 @@ class Module
79
74
  # end
80
75
  #
81
76
  # Current.new.user = "DHH" # => NoMethodError
82
- def thread_mattr_writer(*syms) # :nodoc:
83
- options = syms.extract_options!
77
+ def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true) # :nodoc:
84
78
  syms.each do |sym|
85
79
  raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
86
80
 
@@ -92,7 +86,7 @@ class Module
92
86
  end
93
87
  EOS
94
88
 
95
- unless options[:instance_writer] == false || options[:instance_accessor] == false
89
+ if instance_writer && instance_accessor
96
90
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
97
91
  def #{sym}=(obj)
98
92
  self.class.#{sym} = obj
@@ -137,14 +131,14 @@ class Module
137
131
  # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
138
132
  #
139
133
  # class Current
140
- # mattr_accessor :user, instance_accessor: false
134
+ # thread_mattr_accessor :user, instance_accessor: false
141
135
  # end
142
136
  #
143
137
  # Current.new.user = "DHH" # => NoMethodError
144
138
  # Current.new.user # => NoMethodError
145
- def thread_mattr_accessor(*syms)
146
- thread_mattr_reader(*syms)
147
- thread_mattr_writer(*syms)
139
+ def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true)
140
+ thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor)
141
+ thread_mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor)
148
142
  end
149
143
  alias :thread_cattr_accessor :thread_mattr_accessor
150
144
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "set"
4
- require "active_support/core_ext/regexp"
5
4
 
6
5
  class Module
7
6
  # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
@@ -20,10 +19,11 @@ class Module
20
19
  # public methods as your own.
21
20
  #
22
21
  # ==== Options
23
- # * <tt>:to</tt> - Specifies the target object
22
+ # * <tt>:to</tt> - Specifies the target object name as a symbol or string
24
23
  # * <tt>:prefix</tt> - Prefixes the new method with the target name or a custom prefix
25
- # * <tt>:allow_nil</tt> - if set to true, prevents a +Module::DelegationError+
24
+ # * <tt>:allow_nil</tt> - If set to true, prevents a +Module::DelegationError+
26
25
  # from being raised
26
+ # * <tt>:private</tt> - If set to true, changes method visibility to private
27
27
  #
28
28
  # The macro receives one or more method names (specified as symbols or
29
29
  # strings) and the name of the target object via the <tt>:to</tt> option
@@ -114,6 +114,23 @@ class Module
114
114
  # invoice.customer_name # => 'John Doe'
115
115
  # invoice.customer_address # => 'Vimmersvej 13'
116
116
  #
117
+ # The delegated methods are public by default.
118
+ # Pass <tt>private: true</tt> to change that.
119
+ #
120
+ # class User < ActiveRecord::Base
121
+ # has_one :profile
122
+ # delegate :first_name, to: :profile
123
+ # delegate :date_of_birth, to: :profile, private: true
124
+ #
125
+ # def age
126
+ # Date.today.year - date_of_birth.year
127
+ # end
128
+ # end
129
+ #
130
+ # User.new.first_name # => "Tomas"
131
+ # User.new.date_of_birth # => NoMethodError: private method `date_of_birth' called for #<User:0x00000008221340>
132
+ # User.new.age # => 2
133
+ #
117
134
  # If the target is +nil+ and does not respond to the delegated method a
118
135
  # +Module::DelegationError+ is raised. If you wish to instead return +nil+,
119
136
  # use the <tt>:allow_nil</tt> option.
@@ -151,7 +168,7 @@ class Module
151
168
  # Foo.new("Bar").name # raises NoMethodError: undefined method `name'
152
169
  #
153
170
  # The target method must be public, otherwise it will raise +NoMethodError+.
154
- def delegate(*methods, to: nil, prefix: nil, allow_nil: nil)
171
+ def delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil)
155
172
  unless to
156
173
  raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter)."
157
174
  end
@@ -173,7 +190,7 @@ class Module
173
190
  to = to.to_s
174
191
  to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to)
175
192
 
176
- methods.map do |method|
193
+ method_names = methods.map do |method|
177
194
  # Attribute writer methods only accept one argument. Makes sure []=
178
195
  # methods still accept two arguments.
179
196
  definition = /[^\]]=$/.match?(method) ? "arg" : "*args, &block"
@@ -213,6 +230,9 @@ class Module
213
230
 
214
231
  module_eval(method_def, file, line)
215
232
  end
233
+
234
+ private(*method_names) if private
235
+ method_names
216
236
  end
217
237
 
218
238
  # When building decorators, a common pattern may emerge:
@@ -223,7 +243,7 @@ class Module
223
243
  # end
224
244
  #
225
245
  # def person
226
- # @event.detail.person || @event.creator
246
+ # detail.person || creator
227
247
  # end
228
248
  #
229
249
  # private
@@ -246,7 +266,7 @@ class Module
246
266
  # end
247
267
  #
248
268
  # def person
249
- # @event.detail.person || @event.creator
269
+ # detail.person || creator
250
270
  # end
251
271
  # end
252
272
  #