activesupport 5.2.0 → 6.0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +479 -330
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support.rb +2 -1
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +27 -1
- data/lib/active_support/cache.rb +104 -84
- data/lib/active_support/cache/file_store.rb +29 -30
- data/lib/active_support/cache/mem_cache_store.rb +14 -19
- data/lib/active_support/cache/memory_store.rb +15 -9
- data/lib/active_support/cache/null_store.rb +8 -3
- data/lib/active_support/cache/redis_cache_store.rb +73 -34
- data/lib/active_support/cache/strategy/local_cache.rb +23 -23
- data/lib/active_support/callbacks.rb +16 -8
- data/lib/active_support/concern.rb +31 -4
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configurable.rb +7 -11
- data/lib/active_support/core_ext/array.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +18 -6
- data/lib/active_support/core_ext/array/conversions.rb +5 -5
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
- data/lib/active_support/core_ext/class/attribute.rb +11 -16
- data/lib/active_support/core_ext/class/subclasses.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +6 -5
- data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -47
- data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +97 -68
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash.rb +1 -2
- data/lib/active_support/core_ext/hash/compact.rb +2 -26
- data/lib/active_support/core_ext/hash/conversions.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +0 -29
- data/lib/active_support/core_ext/hash/slice.rb +3 -25
- data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
- data/lib/active_support/core_ext/integer/multiple.rb +1 -1
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module.rb +0 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -10
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +13 -19
- data/lib/active_support/core_ext/module/delegation.rb +41 -8
- data/lib/active_support/core_ext/module/introspection.rb +38 -13
- data/lib/active_support/core_ext/module/reachable.rb +1 -6
- data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
- data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
- data/lib/active_support/core_ext/object/blank.rb +1 -2
- data/lib/active_support/core_ext/object/duplicable.rb +7 -114
- data/lib/active_support/core_ext/object/json.rb +1 -0
- data/lib/active_support/core_ext/object/to_query.rb +5 -2
- data/lib/active_support/core_ext/object/try.rb +17 -7
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/range/compare_range.rb +76 -0
- data/lib/active_support/core_ext/range/conversions.rb +31 -29
- data/lib/active_support/core_ext/range/each.rb +0 -1
- data/lib/active_support/core_ext/range/include_range.rb +6 -22
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
- data/lib/active_support/core_ext/regexp.rb +0 -4
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +8 -0
- data/lib/active_support/core_ext/string/filters.rb +42 -1
- data/lib/active_support/core_ext/string/inflections.rb +7 -2
- data/lib/active_support/core_ext/string/multibyte.rb +4 -3
- data/lib/active_support/core_ext/string/output_safety.rb +63 -6
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +31 -2
- data/lib/active_support/core_ext/uri.rb +2 -4
- data/lib/active_support/current_attributes.rb +8 -0
- data/lib/active_support/dependencies.rb +77 -18
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/deprecation/behaviors.rb +5 -1
- data/lib/active_support/deprecation/method_wrappers.rb +20 -13
- data/lib/active_support/deprecation/proxy_wrappers.rb +28 -5
- data/lib/active_support/deprecation/reporting.rb +1 -1
- data/lib/active_support/descendants_tracker.rb +55 -9
- data/lib/active_support/duration.rb +19 -16
- data/lib/active_support/duration/iso8601_parser.rb +2 -4
- data/lib/active_support/duration/iso8601_serializer.rb +3 -5
- data/lib/active_support/encrypted_configuration.rb +1 -5
- data/lib/active_support/encrypted_file.rb +4 -3
- data/lib/active_support/evented_file_update_checker.rb +39 -10
- data/lib/active_support/execution_wrapper.rb +1 -0
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +36 -18
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +18 -2
- data/lib/active_support/inflector/inflections.rb +1 -5
- data/lib/active_support/inflector/methods.rb +18 -29
- data/lib/active_support/inflector/transliterate.rb +47 -18
- data/lib/active_support/json/decoding.rb +23 -24
- data/lib/active_support/json/encoding.rb +6 -2
- data/lib/active_support/key_generator.rb +0 -32
- data/lib/active_support/lazy_load_hooks.rb +5 -2
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/log_subscriber.rb +31 -9
- data/lib/active_support/logger.rb +1 -16
- data/lib/active_support/logger_silence.rb +28 -12
- data/lib/active_support/logger_thread_safe_level.rb +28 -5
- data/lib/active_support/message_encryptor.rb +4 -6
- data/lib/active_support/message_verifier.rb +5 -5
- data/lib/active_support/messages/metadata.rb +3 -2
- data/lib/active_support/messages/rotator.rb +4 -4
- data/lib/active_support/multibyte/chars.rb +29 -49
- data/lib/active_support/multibyte/unicode.rb +44 -282
- data/lib/active_support/notifications.rb +41 -4
- data/lib/active_support/notifications/fanout.rb +100 -15
- data/lib/active_support/notifications/instrumenter.rb +80 -9
- data/lib/active_support/number_helper.rb +11 -0
- data/lib/active_support/number_helper/number_converter.rb +4 -5
- data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -10
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -4
- data/lib/active_support/option_merger.rb +21 -3
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +5 -1
- data/lib/active_support/parameter_filter.rb +128 -0
- data/lib/active_support/rails.rb +0 -6
- data/lib/active_support/reloader.rb +4 -5
- data/lib/active_support/security_utils.rb +1 -1
- data/lib/active_support/string_inquirer.rb +0 -1
- data/lib/active_support/subscriber.rb +65 -22
- data/lib/active_support/tagged_logging.rb +13 -4
- data/lib/active_support/test_case.rb +92 -1
- data/lib/active_support/testing/assertions.rb +15 -1
- data/lib/active_support/testing/deprecation.rb +0 -1
- data/lib/active_support/testing/file_fixtures.rb +2 -0
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +28 -1
- data/lib/active_support/testing/parallelization.rb +134 -0
- data/lib/active_support/testing/setup_and_teardown.rb +5 -9
- data/lib/active_support/testing/stream.rb +1 -2
- data/lib/active_support/testing/time_helpers.rb +7 -9
- data/lib/active_support/time_with_zone.rb +15 -5
- data/lib/active_support/values/time_zone.rb +14 -8
- data/lib/active_support/xml_mini.rb +2 -10
- data/lib/active_support/xml_mini/jdom.rb +2 -3
- data/lib/active_support/xml_mini/libxml.rb +2 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
- data/lib/active_support/xml_mini/nokogiri.rb +2 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
- data/lib/active_support/xml_mini/rexml.rb +2 -2
- metadata +42 -13
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -84,27 +84,26 @@ class Class
|
|
84
84
|
# To set a default value for the attribute, pass <tt>default:</tt>, like so:
|
85
85
|
#
|
86
86
|
# class_attribute :settings, default: {}
|
87
|
-
def class_attribute(
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
87
|
+
def class_attribute(
|
88
|
+
*attrs,
|
89
|
+
instance_accessor: true,
|
90
|
+
instance_reader: instance_accessor,
|
91
|
+
instance_writer: instance_accessor,
|
92
|
+
instance_predicate: true,
|
93
|
+
default: nil
|
94
|
+
)
|
94
95
|
attrs.each do |name|
|
95
96
|
singleton_class.silence_redefinition_of_method(name)
|
96
|
-
define_singleton_method(name) {
|
97
|
+
define_singleton_method(name) { default }
|
97
98
|
|
98
99
|
singleton_class.silence_redefinition_of_method("#{name}?")
|
99
100
|
define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
|
100
101
|
|
101
|
-
ivar = "@#{name}"
|
102
|
+
ivar = "@#{name}".to_sym
|
102
103
|
|
103
104
|
singleton_class.silence_redefinition_of_method("#{name}=")
|
104
105
|
define_singleton_method("#{name}=") do |val|
|
105
|
-
|
106
|
-
redefine_method(name) { val }
|
107
|
-
end
|
106
|
+
redefine_singleton_method(name) { val }
|
108
107
|
|
109
108
|
if singleton_class?
|
110
109
|
class_eval do
|
@@ -137,10 +136,6 @@ class Class
|
|
137
136
|
instance_variable_set ivar, val
|
138
137
|
end
|
139
138
|
end
|
140
|
-
|
141
|
-
unless default_value.nil?
|
142
|
-
self.send("#{name}=", default_value)
|
143
|
-
end
|
144
139
|
end
|
145
140
|
end
|
146
141
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
class Class
|
4
4
|
begin
|
5
5
|
# Test if this Ruby supports each_object against singleton_class
|
6
|
-
ObjectSpace.each_object(Numeric.singleton_class) {}
|
6
|
+
ObjectSpace.each_object(Numeric.singleton_class) { }
|
7
7
|
|
8
8
|
# Returns an array with all classes that are < than its receiver.
|
9
9
|
#
|
@@ -110,12 +110,13 @@ class Date
|
|
110
110
|
# Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with
|
111
111
|
# any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>.
|
112
112
|
def advance(options)
|
113
|
-
options = options.dup
|
114
113
|
d = self
|
115
|
-
|
116
|
-
d = d >> options
|
117
|
-
d = d
|
118
|
-
d = d +
|
114
|
+
|
115
|
+
d = d >> options[:years] * 12 if options[:years]
|
116
|
+
d = d >> options[:months] if options[:months]
|
117
|
+
d = d + options[:weeks] * 7 if options[:weeks]
|
118
|
+
d = d + options[:days] if options[:days]
|
119
|
+
|
119
120
|
d
|
120
121
|
end
|
121
122
|
|
@@ -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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
|
@@ -20,21 +20,11 @@ module DateAndTime
|
|
20
20
|
advance(days: -1)
|
21
21
|
end
|
22
22
|
|
23
|
-
# Returns a new date/time the specified number of days ago.
|
24
|
-
def prev_day(days = 1)
|
25
|
-
advance(days: -days)
|
26
|
-
end
|
27
|
-
|
28
23
|
# Returns a new date/time representing tomorrow.
|
29
24
|
def tomorrow
|
30
25
|
advance(days: 1)
|
31
26
|
end
|
32
27
|
|
33
|
-
# Returns a new date/time the specified number of days in the future.
|
34
|
-
def next_day(days = 1)
|
35
|
-
advance(days: days)
|
36
|
-
end
|
37
|
-
|
38
28
|
# Returns true if the date/time is today.
|
39
29
|
def today?
|
40
30
|
to_date == ::Date.current
|
@@ -60,6 +50,16 @@ module DateAndTime
|
|
60
50
|
!WEEKEND_DAYS.include?(wday)
|
61
51
|
end
|
62
52
|
|
53
|
+
# Returns true if the date/time falls before <tt>date_or_time</tt>.
|
54
|
+
def before?(date_or_time)
|
55
|
+
self < date_or_time
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns true if the date/time falls after <tt>date_or_time</tt>.
|
59
|
+
def after?(date_or_time)
|
60
|
+
self > date_or_time
|
61
|
+
end
|
62
|
+
|
63
63
|
# Returns a new date/time the specified number of days ago.
|
64
64
|
def days_ago(days)
|
65
65
|
advance(days: -days)
|
@@ -124,7 +124,7 @@ module DateAndTime
|
|
124
124
|
# now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
|
125
125
|
# now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000
|
126
126
|
def beginning_of_quarter
|
127
|
-
first_quarter_month =
|
127
|
+
first_quarter_month = month - (2 + month) % 3
|
128
128
|
beginning_of_month.change(month: first_quarter_month)
|
129
129
|
end
|
130
130
|
alias :at_beginning_of_quarter :beginning_of_quarter
|
@@ -139,7 +139,7 @@ module DateAndTime
|
|
139
139
|
# now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
|
140
140
|
# now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000
|
141
141
|
def end_of_quarter
|
142
|
-
last_quarter_month =
|
142
|
+
last_quarter_month = month + (12 - month) % 3
|
143
143
|
beginning_of_month.change(month: last_quarter_month).end_of_month
|
144
144
|
end
|
145
145
|
alias :at_end_of_quarter :end_of_quarter
|
@@ -188,21 +188,11 @@ module DateAndTime
|
|
188
188
|
end
|
189
189
|
end
|
190
190
|
|
191
|
-
# Returns a new date/time the specified number of months in the future.
|
192
|
-
def next_month(months = 1)
|
193
|
-
advance(months: months)
|
194
|
-
end
|
195
|
-
|
196
191
|
# Short-hand for months_since(3)
|
197
192
|
def next_quarter
|
198
193
|
months_since(3)
|
199
194
|
end
|
200
195
|
|
201
|
-
# Returns a new date/time the specified number of years in the future.
|
202
|
-
def next_year(years = 1)
|
203
|
-
advance(years: years)
|
204
|
-
end
|
205
|
-
|
206
196
|
# Returns a new date/time representing the given day in the previous week.
|
207
197
|
# Week is assumed to start on +start_day+, default is
|
208
198
|
# +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
|
@@ -223,11 +213,6 @@ module DateAndTime
|
|
223
213
|
end
|
224
214
|
alias_method :last_weekday, :prev_weekday
|
225
215
|
|
226
|
-
# Returns a new date/time the specified number of months ago.
|
227
|
-
def prev_month(months = 1)
|
228
|
-
advance(months: -months)
|
229
|
-
end
|
230
|
-
|
231
216
|
# Short-hand for months_ago(1).
|
232
217
|
def last_month
|
233
218
|
months_ago(1)
|
@@ -239,11 +224,6 @@ module DateAndTime
|
|
239
224
|
end
|
240
225
|
alias_method :last_quarter, :prev_quarter
|
241
226
|
|
242
|
-
# Returns a new date/time the specified number of years ago.
|
243
|
-
def prev_year(years = 1)
|
244
|
-
advance(years: -years)
|
245
|
-
end
|
246
|
-
|
247
227
|
# Short-hand for years_ago(1).
|
248
228
|
def last_year
|
249
229
|
years_ago(1)
|
@@ -253,9 +233,8 @@ module DateAndTime
|
|
253
233
|
# Week is assumed to start on +start_day+, default is
|
254
234
|
# +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
|
255
235
|
def days_to_week_start(start_day = Date.beginning_of_week)
|
256
|
-
start_day_number = DAYS_INTO_WEEK
|
257
|
-
|
258
|
-
(current_day_number - start_day_number) % 7
|
236
|
+
start_day_number = DAYS_INTO_WEEK.fetch(start_day)
|
237
|
+
(wday - start_day_number) % 7
|
259
238
|
end
|
260
239
|
|
261
240
|
# Returns a new date/time representing the start of this week on the given day.
|
@@ -336,8 +315,7 @@ module DateAndTime
|
|
336
315
|
# today.next_occurring(:monday) # => Mon, 18 Dec 2017
|
337
316
|
# today.next_occurring(:thursday) # => Thu, 21 Dec 2017
|
338
317
|
def next_occurring(day_of_week)
|
339
|
-
|
340
|
-
from_now = DAYS_INTO_WEEK.fetch(day_of_week) - current_day_number
|
318
|
+
from_now = DAYS_INTO_WEEK.fetch(day_of_week) - wday
|
341
319
|
from_now += 7 unless from_now > 0
|
342
320
|
advance(days: from_now)
|
343
321
|
end
|
@@ -348,8 +326,7 @@ module DateAndTime
|
|
348
326
|
# today.prev_occurring(:monday) # => Mon, 11 Dec 2017
|
349
327
|
# today.prev_occurring(:thursday) # => Thu, 07 Dec 2017
|
350
328
|
def prev_occurring(day_of_week)
|
351
|
-
|
352
|
-
ago = current_day_number - DAYS_INTO_WEEK.fetch(day_of_week)
|
329
|
+
ago = wday - DAYS_INTO_WEEK.fetch(day_of_week)
|
353
330
|
ago += 7 unless ago > 0
|
354
331
|
advance(days: -ago)
|
355
332
|
end
|
@@ -364,7 +341,7 @@ module DateAndTime
|
|
364
341
|
end
|
365
342
|
|
366
343
|
def days_span(day)
|
367
|
-
(DAYS_INTO_WEEK
|
344
|
+
(DAYS_INTO_WEEK.fetch(day) - DAYS_INTO_WEEK.fetch(Date.beginning_of_week)) % 7
|
368
345
|
end
|
369
346
|
|
370
347
|
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
|
113
|
+
self + Rational(seconds, 86400)
|
114
114
|
end
|
115
115
|
alias :in :since
|
116
116
|
|
@@ -1,59 +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.
|
9
|
+
|
10
|
+
# :stopdoc:
|
11
|
+
|
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
|
16
|
+
|
17
|
+
# :startdoc:
|
18
|
+
|
19
|
+
# Calculates a sum from the elements.
|
6
20
|
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
# The default sum of an empty list is zero. You can override this default:
|
31
|
-
#
|
32
|
-
# [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
|
33
|
-
def sum(identity = nil, &block)
|
34
|
-
if identity
|
35
|
-
_original_sum_with_required_identity(identity, &block)
|
36
|
-
elsif block_given?
|
37
|
-
map(&block).sum(identity)
|
38
|
-
else
|
39
|
-
inject(:+) || 0
|
40
|
-
end
|
41
|
-
end
|
42
|
-
else
|
43
|
-
def sum(identity = nil, &block)
|
44
|
-
if block_given?
|
45
|
-
map(&block).sum(identity)
|
46
|
-
else
|
47
|
-
sum = identity ? inject(identity, :+) : inject(:+)
|
48
|
-
sum || identity || 0
|
49
|
-
end
|
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
|
50
44
|
end
|
51
45
|
end
|
52
46
|
|
53
|
-
# Convert an enumerable to a hash.
|
47
|
+
# Convert an enumerable to a hash keying it by the block return value.
|
54
48
|
#
|
55
49
|
# people.index_by(&:login)
|
56
50
|
# # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
|
51
|
+
#
|
57
52
|
# people.index_by { |person| "#{person.first_name} #{person.last_name}" }
|
58
53
|
# # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
|
59
54
|
def index_by
|
@@ -66,6 +61,26 @@ module Enumerable
|
|
66
61
|
end
|
67
62
|
end
|
68
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
|
+
|
69
84
|
# Returns +true+ if the enumerable has more than 1 element. Functionally
|
70
85
|
# equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
|
71
86
|
# much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
|
@@ -82,23 +97,43 @@ module Enumerable
|
|
82
97
|
end
|
83
98
|
end
|
84
99
|
|
100
|
+
# Returns a new array that includes the passed elements.
|
101
|
+
#
|
102
|
+
# [ 1, 2, 3 ].including(4, 5)
|
103
|
+
# # => [ 1, 2, 3, 4, 5 ]
|
104
|
+
#
|
105
|
+
# ["David", "Rafael"].including %w[ Aaron Todd ]
|
106
|
+
# # => ["David", "Rafael", "Aaron", "Todd"]
|
107
|
+
def including(*elements)
|
108
|
+
to_a.including(*elements)
|
109
|
+
end
|
110
|
+
|
85
111
|
# The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
|
86
112
|
# collection does not include the object.
|
87
113
|
def exclude?(object)
|
88
114
|
!include?(object)
|
89
115
|
end
|
90
116
|
|
91
|
-
# Returns a copy of the enumerable
|
117
|
+
# Returns a copy of the enumerable excluding the specified elements.
|
118
|
+
#
|
119
|
+
# ["David", "Rafael", "Aaron", "Todd"].excluding "Aaron", "Todd"
|
120
|
+
# # => ["David", "Rafael"]
|
92
121
|
#
|
93
|
-
# ["David", "Rafael", "Aaron", "Todd"].
|
122
|
+
# ["David", "Rafael", "Aaron", "Todd"].excluding %w[ Aaron Todd ]
|
94
123
|
# # => ["David", "Rafael"]
|
95
124
|
#
|
96
|
-
# {foo: 1, bar: 2, baz: 3}.
|
125
|
+
# {foo: 1, bar: 2, baz: 3}.excluding :bar
|
97
126
|
# # => {foo: 1, baz: 3}
|
98
|
-
def
|
127
|
+
def excluding(*elements)
|
128
|
+
elements.flatten!(1)
|
99
129
|
reject { |element| elements.include?(element) }
|
100
130
|
end
|
101
131
|
|
132
|
+
# Alias for #excluding.
|
133
|
+
def without(*elements)
|
134
|
+
excluding(*elements)
|
135
|
+
end
|
136
|
+
|
102
137
|
# Convert an enumerable to an array based on the given key.
|
103
138
|
#
|
104
139
|
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
|
@@ -133,27 +168,21 @@ class Range #:nodoc:
|
|
133
168
|
end
|
134
169
|
end
|
135
170
|
|
136
|
-
#
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
# Using Refinements here in order not to expose our internal method
|
143
|
-
using Module.new {
|
144
|
-
refine Array do
|
145
|
-
alias :orig_sum :sum
|
146
|
-
end
|
147
|
-
}
|
171
|
+
# Using Refinements here in order not to expose our internal method
|
172
|
+
using Module.new {
|
173
|
+
refine Array do
|
174
|
+
alias :orig_sum :sum
|
175
|
+
end
|
176
|
+
}
|
148
177
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
178
|
+
class Array #:nodoc:
|
179
|
+
# Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
|
180
|
+
def sum(init = nil, &block)
|
181
|
+
if init.is_a?(Numeric) || first.is_a?(Numeric)
|
182
|
+
init ||= 0
|
183
|
+
orig_sum(init, &block)
|
184
|
+
else
|
185
|
+
super
|
157
186
|
end
|
158
187
|
end
|
159
188
|
end
|