activesupport 4.2.0 → 5.0.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +630 -220
- data/MIT-LICENSE +2 -2
- data/README.rdoc +2 -3
- data/lib/active_support/array_inquirer.rb +44 -0
- data/lib/active_support/backtrace_cleaner.rb +1 -1
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache/file_store.rb +36 -22
- data/lib/active_support/cache/mem_cache_store.rb +63 -54
- data/lib/active_support/cache/memory_store.rb +16 -21
- data/lib/active_support/cache/null_store.rb +1 -4
- data/lib/active_support/cache/strategy/local_cache.rb +31 -20
- data/lib/active_support/cache.rb +73 -89
- data/lib/active_support/callbacks.rb +195 -155
- data/lib/active_support/concern.rb +2 -2
- data/lib/active_support/concurrency/latch.rb +7 -15
- data/lib/active_support/concurrency/share_lock.rb +186 -0
- data/lib/active_support/configurable.rb +1 -0
- data/lib/active_support/core_ext/array/access.rb +27 -1
- data/lib/active_support/core_ext/array/conversions.rb +6 -4
- data/lib/active_support/core_ext/array/grouping.rb +9 -18
- data/lib/active_support/core_ext/array/inquiry.rb +17 -0
- data/lib/active_support/core_ext/array/wrap.rb +5 -4
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
- data/lib/active_support/core_ext/class/attribute.rb +10 -9
- data/lib/active_support/core_ext/class/subclasses.rb +3 -4
- data/lib/active_support/core_ext/class.rb +0 -1
- data/lib/active_support/core_ext/date/blank.rb +12 -0
- data/lib/active_support/core_ext/date/calculations.rb +1 -1
- data/lib/active_support/core_ext/date/conversions.rb +13 -6
- data/lib/active_support/core_ext/date.rb +1 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +109 -25
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +3 -4
- data/lib/active_support/core_ext/date_time/blank.rb +12 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +36 -10
- data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
- data/lib/active_support/core_ext/date_time.rb +2 -1
- data/lib/active_support/core_ext/enumerable.rb +49 -5
- data/lib/active_support/core_ext/file/atomic.rb +30 -25
- data/lib/active_support/core_ext/hash/conversions.rb +23 -4
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
- data/lib/active_support/core_ext/hash/except.rb +9 -8
- data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +23 -19
- data/lib/active_support/core_ext/hash/slice.rb +1 -1
- data/lib/active_support/core_ext/hash/transform_values.rb +11 -5
- data/lib/active_support/core_ext/integer/time.rb +1 -16
- data/lib/active_support/core_ext/kernel/concern.rb +2 -0
- data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
- data/lib/active_support/core_ext/kernel/reporting.rb +2 -83
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/load_error.rb +4 -2
- data/lib/active_support/core_ext/marshal.rb +12 -11
- data/lib/active_support/core_ext/module/aliasing.rb +6 -1
- data/lib/active_support/core_ext/module/anonymous.rb +10 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
- data/lib/active_support/core_ext/module/attribute_accessors.rb +15 -15
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
- data/lib/active_support/core_ext/module/concerning.rb +4 -4
- data/lib/active_support/core_ext/module/delegation.rb +35 -25
- data/lib/active_support/core_ext/module/deprecation.rb +2 -2
- data/lib/active_support/core_ext/module/introspection.rb +4 -0
- data/lib/active_support/core_ext/module/method_transplanting.rb +3 -11
- data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
- data/lib/active_support/core_ext/module/remove_method.rb +23 -0
- data/lib/active_support/core_ext/module.rb +1 -0
- data/lib/active_support/core_ext/name_error.rb +15 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +74 -64
- data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
- data/lib/active_support/core_ext/numeric/time.rb +24 -19
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/blank.rb +17 -5
- data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
- data/lib/active_support/core_ext/object/duplicable.rb +8 -13
- data/lib/active_support/core_ext/object/inclusion.rb +2 -2
- data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +15 -7
- data/lib/active_support/core_ext/object/to_query.rb +1 -1
- data/lib/active_support/core_ext/object/try.rb +68 -22
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/object.rb +0 -1
- data/lib/active_support/core_ext/range/conversions.rb +18 -6
- data/lib/active_support/core_ext/range/each.rb +16 -18
- data/lib/active_support/core_ext/range/include_range.rb +20 -20
- data/lib/active_support/core_ext/securerandom.rb +23 -0
- data/lib/active_support/core_ext/string/access.rb +1 -1
- data/lib/active_support/core_ext/string/behavior.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +4 -3
- data/lib/active_support/core_ext/string/filters.rb +5 -5
- data/lib/active_support/core_ext/string/inflections.rb +32 -5
- data/lib/active_support/core_ext/string/multibyte.rb +11 -7
- data/lib/active_support/core_ext/string/output_safety.rb +18 -16
- data/lib/active_support/core_ext/string/strip.rb +3 -6
- data/lib/active_support/core_ext/struct.rb +3 -6
- data/lib/active_support/core_ext/time/calculations.rb +36 -11
- data/lib/active_support/core_ext/time/compatibility.rb +5 -0
- data/lib/active_support/core_ext/time/conversions.rb +4 -2
- data/lib/active_support/core_ext/time/marshal.rb +2 -29
- data/lib/active_support/core_ext/time/zones.rb +36 -4
- data/lib/active_support/core_ext/time.rb +1 -1
- data/lib/active_support/core_ext/uri.rb +1 -3
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/dependencies/interlock.rb +51 -0
- data/lib/active_support/dependencies.rb +87 -95
- data/lib/active_support/deprecation/behaviors.rb +16 -2
- data/lib/active_support/deprecation/method_wrappers.rb +42 -16
- data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
- data/lib/active_support/deprecation/reporting.rb +23 -5
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/duration/iso8601_parser.rb +122 -0
- data/lib/active_support/duration/iso8601_serializer.rb +51 -0
- data/lib/active_support/duration.rb +55 -10
- data/lib/active_support/evented_file_update_checker.rb +194 -0
- data/lib/active_support/execution_wrapper.rb +117 -0
- data/lib/active_support/executor.rb +6 -0
- data/lib/active_support/file_update_checker.rb +23 -3
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +46 -13
- data/lib/active_support/i18n_railtie.rb +25 -4
- data/lib/active_support/inflector/inflections.rb +36 -5
- data/lib/active_support/inflector/methods.rb +97 -90
- data/lib/active_support/inflector/transliterate.rb +36 -21
- data/lib/active_support/json/decoding.rb +11 -10
- data/lib/active_support/json/encoding.rb +4 -49
- data/lib/active_support/key_generator.rb +7 -9
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber/test_helper.rb +3 -3
- data/lib/active_support/log_subscriber.rb +1 -1
- data/lib/active_support/logger.rb +50 -1
- data/lib/active_support/logger_silence.rb +8 -4
- data/lib/active_support/logger_thread_safe_level.rb +31 -0
- data/lib/active_support/message_encryptor.rb +4 -4
- data/lib/active_support/message_verifier.rb +70 -8
- data/lib/active_support/multibyte/chars.rb +13 -4
- data/lib/active_support/multibyte/unicode.rb +44 -21
- data/lib/active_support/notifications/fanout.rb +6 -6
- data/lib/active_support/notifications/instrumenter.rb +20 -2
- data/lib/active_support/notifications.rb +2 -2
- data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +8 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -2
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +11 -2
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +30 -25
- data/lib/active_support/number_helper.rb +90 -67
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +15 -1
- data/lib/active_support/per_thread_registry.rb +8 -3
- data/lib/active_support/rails.rb +2 -2
- data/lib/active_support/railtie.rb +6 -1
- data/lib/active_support/reloader.rb +129 -0
- data/lib/active_support/rescuable.rb +93 -47
- data/lib/active_support/security_utils.rb +7 -0
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/subscriber.rb +5 -10
- data/lib/active_support/tagged_logging.rb +3 -1
- data/lib/active_support/test_case.rb +15 -29
- data/lib/active_support/testing/assertions.rb +15 -13
- data/lib/active_support/testing/autorun.rb +8 -1
- data/lib/active_support/testing/deprecation.rb +9 -8
- data/lib/active_support/testing/file_fixtures.rb +34 -0
- data/lib/active_support/testing/isolation.rb +22 -8
- data/lib/active_support/testing/method_call_assertions.rb +41 -0
- data/lib/active_support/testing/stream.rb +42 -0
- data/lib/active_support/testing/time_helpers.rb +13 -10
- data/lib/active_support/time_with_zone.rb +135 -46
- data/lib/active_support/values/time_zone.rb +95 -47
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/xml_mini/jdom.rb +7 -6
- data/lib/active_support/xml_mini/libxml.rb +2 -2
- data/lib/active_support/xml_mini/nokogiri.rb +2 -2
- data/lib/active_support/xml_mini/rexml.rb +7 -8
- data/lib/active_support/xml_mini.rb +22 -14
- data/lib/active_support.rb +20 -6
- metadata +33 -35
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
- data/lib/active_support/core_ext/date_time/zones.rb +0 -6
- data/lib/active_support/core_ext/object/itself.rb +0 -15
- data/lib/active_support/core_ext/thread.rb +0 -86
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/object/try'
|
2
|
+
|
1
3
|
module DateAndTime
|
2
4
|
module Calculations
|
3
5
|
DAYS_INTO_WEEK = {
|
@@ -9,15 +11,26 @@ module DateAndTime
|
|
9
11
|
:saturday => 5,
|
10
12
|
:sunday => 6
|
11
13
|
}
|
14
|
+
WEEKEND_DAYS = [ 6, 0 ]
|
12
15
|
|
13
16
|
# Returns a new date/time representing yesterday.
|
14
17
|
def yesterday
|
15
|
-
advance(:
|
18
|
+
advance(days: -1)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a new date/time representing the previous day.
|
22
|
+
def prev_day
|
23
|
+
advance(days: -1)
|
16
24
|
end
|
17
25
|
|
18
26
|
# Returns a new date/time representing tomorrow.
|
19
27
|
def tomorrow
|
20
|
-
advance(:
|
28
|
+
advance(days: 1)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a new date/time representing the next day.
|
32
|
+
def next_day
|
33
|
+
advance(days: 1)
|
21
34
|
end
|
22
35
|
|
23
36
|
# Returns true if the date/time is today.
|
@@ -35,6 +48,16 @@ module DateAndTime
|
|
35
48
|
self > self.class.current
|
36
49
|
end
|
37
50
|
|
51
|
+
# Returns true if the date/time falls on a Saturday or Sunday.
|
52
|
+
def on_weekend?
|
53
|
+
WEEKEND_DAYS.include?(wday)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns true if the date/time does not fall on a Saturday or Sunday.
|
57
|
+
def on_weekday?
|
58
|
+
!WEEKEND_DAYS.include?(wday)
|
59
|
+
end
|
60
|
+
|
38
61
|
# Returns a new date/time the specified number of days ago.
|
39
62
|
def days_ago(days)
|
40
63
|
advance(:days => -days)
|
@@ -76,15 +99,28 @@ module DateAndTime
|
|
76
99
|
end
|
77
100
|
|
78
101
|
# Returns a new date/time at the start of the month.
|
79
|
-
#
|
102
|
+
#
|
103
|
+
# today = Date.today # => Thu, 18 Jun 2015
|
104
|
+
# today.beginning_of_month # => Mon, 01 Jun 2015
|
105
|
+
#
|
106
|
+
# +DateTime+ objects will have a time set to 0:00.
|
107
|
+
#
|
108
|
+
# now = DateTime.current # => Thu, 18 Jun 2015 15:23:13 +0000
|
109
|
+
# now.beginning_of_month # => Mon, 01 Jun 2015 00:00:00 +0000
|
80
110
|
def beginning_of_month
|
81
111
|
first_hour(change(:day => 1))
|
82
112
|
end
|
83
113
|
alias :at_beginning_of_month :beginning_of_month
|
84
114
|
|
85
115
|
# Returns a new date/time at the start of the quarter.
|
86
|
-
#
|
87
|
-
#
|
116
|
+
#
|
117
|
+
# today = Date.today # => Fri, 10 Jul 2015
|
118
|
+
# today.beginning_of_quarter # => Wed, 01 Jul 2015
|
119
|
+
#
|
120
|
+
# +DateTime+ objects will have a time set to 0:00.
|
121
|
+
#
|
122
|
+
# now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
|
123
|
+
# now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000
|
88
124
|
def beginning_of_quarter
|
89
125
|
first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month }
|
90
126
|
beginning_of_month.change(:month => first_quarter_month)
|
@@ -92,28 +128,62 @@ module DateAndTime
|
|
92
128
|
alias :at_beginning_of_quarter :beginning_of_quarter
|
93
129
|
|
94
130
|
# Returns a new date/time at the end of the quarter.
|
95
|
-
#
|
96
|
-
#
|
131
|
+
#
|
132
|
+
# today = Date.today # => Fri, 10 Jul 2015
|
133
|
+
# today.end_of_quarter # => Wed, 30 Sep 2015
|
134
|
+
#
|
135
|
+
# +DateTime+ objects will have a time set to 23:59:59.
|
136
|
+
#
|
137
|
+
# now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
|
138
|
+
# now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000
|
97
139
|
def end_of_quarter
|
98
140
|
last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month }
|
99
141
|
beginning_of_month.change(:month => last_quarter_month).end_of_month
|
100
142
|
end
|
101
143
|
alias :at_end_of_quarter :end_of_quarter
|
102
144
|
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
145
|
+
# Returns a new date/time at the beginning of the year.
|
146
|
+
#
|
147
|
+
# today = Date.today # => Fri, 10 Jul 2015
|
148
|
+
# today.beginning_of_year # => Thu, 01 Jan 2015
|
149
|
+
#
|
150
|
+
# +DateTime+ objects will have a time set to 0:00.
|
151
|
+
#
|
152
|
+
# now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
|
153
|
+
# now.beginning_of_year # => Thu, 01 Jan 2015 00:00:00 +0000
|
106
154
|
def beginning_of_year
|
107
155
|
change(:month => 1).beginning_of_month
|
108
156
|
end
|
109
157
|
alias :at_beginning_of_year :beginning_of_year
|
110
158
|
|
111
159
|
# Returns a new date/time representing the given day in the next week.
|
160
|
+
#
|
161
|
+
# today = Date.today # => Thu, 07 May 2015
|
162
|
+
# today.next_week # => Mon, 11 May 2015
|
163
|
+
#
|
112
164
|
# The +given_day_in_next_week+ defaults to the beginning of the week
|
113
165
|
# which is determined by +Date.beginning_of_week+ or +config.beginning_of_week+
|
114
|
-
# when set.
|
115
|
-
|
116
|
-
|
166
|
+
# when set.
|
167
|
+
#
|
168
|
+
# today = Date.today # => Thu, 07 May 2015
|
169
|
+
# today.next_week(:friday) # => Fri, 15 May 2015
|
170
|
+
#
|
171
|
+
# +DateTime+ objects have their time set to 0:00 unless +same_time+ is true.
|
172
|
+
#
|
173
|
+
# now = DateTime.current # => Thu, 07 May 2015 13:31:16 +0000
|
174
|
+
# now.next_week # => Mon, 11 May 2015 00:00:00 +0000
|
175
|
+
def next_week(given_day_in_next_week = Date.beginning_of_week, same_time: false)
|
176
|
+
result = first_hour(weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week)))
|
177
|
+
same_time ? copy_time_to(result) : result
|
178
|
+
end
|
179
|
+
|
180
|
+
# Returns a new date/time representing the next weekday.
|
181
|
+
def next_weekday
|
182
|
+
if next_day.on_weekend?
|
183
|
+
next_week(:monday, same_time: true)
|
184
|
+
else
|
185
|
+
next_day
|
186
|
+
end
|
117
187
|
end
|
118
188
|
|
119
189
|
# Short-hand for months_since(1).
|
@@ -134,12 +204,23 @@ module DateAndTime
|
|
134
204
|
# Returns a new date/time representing the given day in the previous week.
|
135
205
|
# Week is assumed to start on +start_day+, default is
|
136
206
|
# +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
|
137
|
-
# DateTime objects have their time set to 0:00.
|
138
|
-
def prev_week(start_day = Date.beginning_of_week)
|
139
|
-
first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day)))
|
207
|
+
# DateTime objects have their time set to 0:00 unless +same_time+ is true.
|
208
|
+
def prev_week(start_day = Date.beginning_of_week, same_time: false)
|
209
|
+
result = first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day)))
|
210
|
+
same_time ? copy_time_to(result) : result
|
140
211
|
end
|
141
212
|
alias_method :last_week, :prev_week
|
142
213
|
|
214
|
+
# Returns a new date/time representing the previous weekday.
|
215
|
+
def prev_weekday
|
216
|
+
if prev_day.on_weekend?
|
217
|
+
copy_time_to(beginning_of_week(:friday))
|
218
|
+
else
|
219
|
+
prev_day
|
220
|
+
end
|
221
|
+
end
|
222
|
+
alias_method :last_weekday, :prev_weekday
|
223
|
+
|
143
224
|
# Short-hand for months_ago(1).
|
144
225
|
def prev_month
|
145
226
|
months_ago(1)
|
@@ -235,17 +316,20 @@ module DateAndTime
|
|
235
316
|
end
|
236
317
|
|
237
318
|
private
|
319
|
+
def first_hour(date_or_time)
|
320
|
+
date_or_time.acts_like?(:time) ? date_or_time.beginning_of_day : date_or_time
|
321
|
+
end
|
238
322
|
|
239
|
-
|
240
|
-
|
241
|
-
|
323
|
+
def last_hour(date_or_time)
|
324
|
+
date_or_time.acts_like?(:time) ? date_or_time.end_of_day : date_or_time
|
325
|
+
end
|
242
326
|
|
243
|
-
|
244
|
-
|
245
|
-
|
327
|
+
def days_span(day)
|
328
|
+
(DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7
|
329
|
+
end
|
246
330
|
|
247
|
-
|
248
|
-
|
249
|
-
|
331
|
+
def copy_time_to(other)
|
332
|
+
other.change(hour: hour, min: min, sec: sec, usec: try(:usec))
|
333
|
+
end
|
250
334
|
end
|
251
335
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
2
|
+
|
3
|
+
module DateAndTime
|
4
|
+
module Compatibility
|
5
|
+
# If true, +to_time+ preserves the timezone offset of receiver.
|
6
|
+
#
|
7
|
+
# NOTE: With Ruby 2.4+ the default for +to_time+ changed from
|
8
|
+
# converting to the local system time, to preserving the offset
|
9
|
+
# of the receiver. For backwards compatibility we're overriding
|
10
|
+
# this behavior, but new apps will have an initializer that sets
|
11
|
+
# this to true, because the new behavior is preferred.
|
12
|
+
mattr_accessor(:preserve_timezone, instance_writer: false) { false }
|
13
|
+
|
14
|
+
def to_time
|
15
|
+
preserve_timezone ? getlocal(utc_offset) : getlocal
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -4,8 +4,8 @@ module DateAndTime
|
|
4
4
|
# if Time.zone_default is set. Otherwise, it returns the current time.
|
5
5
|
#
|
6
6
|
# Time.zone = 'Hawaii' # => 'Hawaii'
|
7
|
-
#
|
8
|
-
# Date.new(2000).in_time_zone
|
7
|
+
# Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
|
8
|
+
# Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00
|
9
9
|
#
|
10
10
|
# This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone
|
11
11
|
# instead of the operating system's time zone.
|
@@ -14,8 +14,7 @@ module DateAndTime
|
|
14
14
|
# and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
|
15
15
|
#
|
16
16
|
# Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
|
17
|
-
#
|
18
|
-
# Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00
|
17
|
+
# Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00
|
19
18
|
def in_time_zone(zone = ::Time.zone)
|
20
19
|
time_zone = ::Time.find_zone! zone
|
21
20
|
time = acts_like?(:time) ? self : nil
|
@@ -10,7 +10,11 @@ class DateTime
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
#
|
13
|
+
# Returns the number of seconds since 00:00:00.
|
14
|
+
#
|
15
|
+
# DateTime.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0
|
16
|
+
# DateTime.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296
|
17
|
+
# DateTime.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399
|
14
18
|
def seconds_since_midnight
|
15
19
|
sec + (min * 60) + (hour * 3600)
|
16
20
|
end
|
@@ -24,6 +28,13 @@ class DateTime
|
|
24
28
|
end_of_day.to_i - to_i
|
25
29
|
end
|
26
30
|
|
31
|
+
# Returns the fraction of a second as a +Rational+
|
32
|
+
#
|
33
|
+
# DateTime.new(2012, 8, 29, 0, 0, 0.5).subsec # => (1/2)
|
34
|
+
def subsec
|
35
|
+
sec_fraction
|
36
|
+
end
|
37
|
+
|
27
38
|
# Returns a new DateTime where one or more of the elements have been changed
|
28
39
|
# according to the +options+ parameter. The time options (<tt>:hour</tt>,
|
29
40
|
# <tt>:min</tt>, <tt>:sec</tt>) reset cascadingly, so if only the hour is
|
@@ -139,14 +150,32 @@ class DateTime
|
|
139
150
|
end
|
140
151
|
alias :at_end_of_minute :end_of_minute
|
141
152
|
|
142
|
-
#
|
153
|
+
# Returns a <tt>Time</tt> instance of the simultaneous time in the system timezone.
|
154
|
+
def localtime(utc_offset = nil)
|
155
|
+
utc = new_offset(0)
|
156
|
+
|
157
|
+
Time.utc(
|
158
|
+
utc.year, utc.month, utc.day,
|
159
|
+
utc.hour, utc.min, utc.sec + utc.sec_fraction
|
160
|
+
).getlocal(utc_offset)
|
161
|
+
end
|
162
|
+
alias_method :getlocal, :localtime
|
163
|
+
|
164
|
+
# Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
|
143
165
|
#
|
144
166
|
# DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
|
145
|
-
# DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12
|
167
|
+
# DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 UTC
|
146
168
|
def utc
|
147
|
-
new_offset(0)
|
169
|
+
utc = new_offset(0)
|
170
|
+
|
171
|
+
Time.utc(
|
172
|
+
utc.year, utc.month, utc.day,
|
173
|
+
utc.hour, utc.min, utc.sec + utc.sec_fraction
|
174
|
+
)
|
148
175
|
end
|
176
|
+
alias_method :getgm, :utc
|
149
177
|
alias_method :getutc, :utc
|
178
|
+
alias_method :gmtime, :utc
|
150
179
|
|
151
180
|
# Returns +true+ if <tt>offset == 0</tt>.
|
152
181
|
def utc?
|
@@ -161,13 +190,10 @@ class DateTime
|
|
161
190
|
# Layers additional behavior on DateTime#<=> so that Time and
|
162
191
|
# ActiveSupport::TimeWithZone instances can be compared with a DateTime.
|
163
192
|
def <=>(other)
|
164
|
-
if other.
|
165
|
-
super
|
166
|
-
elsif other.respond_to? :to_datetime
|
167
|
-
super other.to_datetime
|
193
|
+
if other.respond_to? :to_datetime
|
194
|
+
super other.to_datetime rescue nil
|
168
195
|
else
|
169
|
-
|
196
|
+
super
|
170
197
|
end
|
171
198
|
end
|
172
|
-
|
173
199
|
end
|
@@ -40,6 +40,8 @@ class DateTime
|
|
40
40
|
alias_method :to_default_s, :to_s if instance_methods(false).include?(:to_s)
|
41
41
|
alias_method :to_s, :to_formatted_s
|
42
42
|
|
43
|
+
# Returns a formatted string of the offset from UTC, or an alternative
|
44
|
+
# string if the time zone is already UTC.
|
43
45
|
#
|
44
46
|
# datetime = DateTime.civil(2000, 1, 1, 0, 0, 0, Rational(-6, 24))
|
45
47
|
# datetime.formatted_offset # => "-06:00"
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_support/core_ext/date_time/acts_like'
|
2
|
+
require 'active_support/core_ext/date_time/blank'
|
2
3
|
require 'active_support/core_ext/date_time/calculations'
|
4
|
+
require 'active_support/core_ext/date_time/compatibility'
|
3
5
|
require 'active_support/core_ext/date_time/conversions'
|
4
|
-
require 'active_support/core_ext/date_time/zones'
|
@@ -17,11 +17,12 @@ module Enumerable
|
|
17
17
|
# The default sum of an empty list is zero. You can override this default:
|
18
18
|
#
|
19
19
|
# [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
|
20
|
-
def sum(identity =
|
20
|
+
def sum(identity = nil, &block)
|
21
21
|
if block_given?
|
22
22
|
map(&block).sum(identity)
|
23
23
|
else
|
24
|
-
|
24
|
+
sum = identity ? inject(identity, :+) : inject(:+)
|
25
|
+
sum || identity || 0
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -60,21 +61,64 @@ module Enumerable
|
|
60
61
|
def exclude?(object)
|
61
62
|
!include?(object)
|
62
63
|
end
|
64
|
+
|
65
|
+
# Returns a copy of the enumerable without the specified elements.
|
66
|
+
#
|
67
|
+
# ["David", "Rafael", "Aaron", "Todd"].without "Aaron", "Todd"
|
68
|
+
# => ["David", "Rafael"]
|
69
|
+
#
|
70
|
+
# {foo: 1, bar: 2, baz: 3}.without :bar
|
71
|
+
# => {foo: 1, baz: 3}
|
72
|
+
def without(*elements)
|
73
|
+
reject { |element| elements.include?(element) }
|
74
|
+
end
|
75
|
+
|
76
|
+
# Convert an enumerable to an array based on the given key.
|
77
|
+
#
|
78
|
+
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
|
79
|
+
# => ["David", "Rafael", "Aaron"]
|
80
|
+
#
|
81
|
+
# [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
|
82
|
+
# => [[1, "David"], [2, "Rafael"]]
|
83
|
+
def pluck(*keys)
|
84
|
+
if keys.many?
|
85
|
+
map { |element| keys.map { |key| element[key] } }
|
86
|
+
else
|
87
|
+
map { |element| element[keys.first] }
|
88
|
+
end
|
89
|
+
end
|
63
90
|
end
|
64
91
|
|
65
92
|
class Range #:nodoc:
|
66
93
|
# Optimize range sum to use arithmetic progression if a block is not given and
|
67
94
|
# we have a range of numeric values.
|
68
|
-
def sum(identity =
|
95
|
+
def sum(identity = nil)
|
69
96
|
if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
|
70
97
|
super
|
71
98
|
else
|
72
99
|
actual_last = exclude_end? ? (last - 1) : last
|
73
100
|
if actual_last >= first
|
74
|
-
|
101
|
+
sum = identity || 0
|
102
|
+
sum + (actual_last - first + 1) * (actual_last + first) / 2
|
75
103
|
else
|
76
|
-
identity
|
104
|
+
identity || 0
|
77
105
|
end
|
78
106
|
end
|
79
107
|
end
|
80
108
|
end
|
109
|
+
|
110
|
+
# Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
|
111
|
+
#
|
112
|
+
# We tried shimming it to attempt the fast native method, rescue TypeError,
|
113
|
+
# and fall back to the compatible implementation, but that's much slower than
|
114
|
+
# just calling the compat method in the first place.
|
115
|
+
if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
|
116
|
+
class Array
|
117
|
+
remove_method :sum
|
118
|
+
|
119
|
+
def sum(*args) #:nodoc:
|
120
|
+
# Use Enumerable#sum instead.
|
121
|
+
super
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -8,40 +8,45 @@ class File
|
|
8
8
|
# file.write('hello')
|
9
9
|
# end
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# This method needs to create a temporary file. By default it will create it
|
12
|
+
# in the same directory as the destination file. If you don't like this
|
13
|
+
# behavior you can provide a different directory but it must be on the
|
14
|
+
# same physical filesystem as the file you're trying to write.
|
13
15
|
#
|
14
16
|
# File.atomic_write('/data/something.important', '/data/tmp') do |file|
|
15
17
|
# file.write('hello')
|
16
18
|
# end
|
17
|
-
def self.atomic_write(file_name, temp_dir =
|
19
|
+
def self.atomic_write(file_name, temp_dir = dirname(file_name))
|
18
20
|
require 'tempfile' unless defined?(Tempfile)
|
19
|
-
require 'fileutils' unless defined?(FileUtils)
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
|
23
|
+
temp_file.binmode
|
24
|
+
return_val = yield temp_file
|
25
|
+
temp_file.close
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
old_stat = if exist?(file_name)
|
28
|
+
# Get original file permissions
|
29
|
+
stat(file_name)
|
30
|
+
elsif temp_dir != dirname(file_name)
|
31
|
+
# If not possible, probe which are the default permissions in the
|
32
|
+
# destination directory.
|
33
|
+
probe_stat_in(dirname(file_name))
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
36
|
+
if old_stat
|
37
|
+
# Set correct permissions on new file
|
38
|
+
begin
|
39
|
+
chown(old_stat.uid, old_stat.gid, temp_file.path)
|
40
|
+
# This operation will affect filesystem ACL's
|
41
|
+
chmod(old_stat.mode, temp_file.path)
|
42
|
+
rescue Errno::EPERM, Errno::EACCES
|
43
|
+
# Changing file ownership failed, moving on.
|
44
|
+
end
|
45
|
+
end
|
37
46
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# This operation will affect filesystem ACL's
|
42
|
-
chmod(old_stat.mode, file_name)
|
43
|
-
rescue Errno::EPERM, Errno::EACCES
|
44
|
-
# Changing file ownership failed, moving on.
|
47
|
+
# Overwrite original file with temp file
|
48
|
+
rename(temp_file.path, file_name)
|
49
|
+
return_val
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
@@ -31,7 +31,7 @@ class Hash
|
|
31
31
|
# with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
|
32
32
|
# callable can add nodes by using <tt>options[:builder]</tt>.
|
33
33
|
#
|
34
|
-
#
|
34
|
+
# {foo: lambda { |options, key| options[:builder].b(key) }}.to_xml
|
35
35
|
# # => "<b>foo</b>"
|
36
36
|
#
|
37
37
|
# * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
|
@@ -55,8 +55,7 @@ class Hash
|
|
55
55
|
#
|
56
56
|
# XML_TYPE_NAMES = {
|
57
57
|
# "Symbol" => "symbol",
|
58
|
-
# "
|
59
|
-
# "Bignum" => "integer",
|
58
|
+
# "Integer" => "integer",
|
60
59
|
# "BigDecimal" => "decimal",
|
61
60
|
# "Float" => "float",
|
62
61
|
# "TrueClass" => "boolean",
|
@@ -106,7 +105,25 @@ class Hash
|
|
106
105
|
# # => {"hash"=>{"foo"=>1, "bar"=>2}}
|
107
106
|
#
|
108
107
|
# +DisallowedType+ is raised if the XML contains attributes with <tt>type="yaml"</tt> or
|
109
|
-
# <tt>type="symbol"</tt>. Use <tt>Hash.from_trusted_xml</tt> to
|
108
|
+
# <tt>type="symbol"</tt>. Use <tt>Hash.from_trusted_xml</tt> to
|
109
|
+
# parse this XML.
|
110
|
+
#
|
111
|
+
# Custom +disallowed_types+ can also be passed in the form of an
|
112
|
+
# array.
|
113
|
+
#
|
114
|
+
# xml = <<-XML
|
115
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
116
|
+
# <hash>
|
117
|
+
# <foo type="integer">1</foo>
|
118
|
+
# <bar type="string">"David"</bar>
|
119
|
+
# </hash>
|
120
|
+
# XML
|
121
|
+
#
|
122
|
+
# hash = Hash.from_xml(xml, ['integer'])
|
123
|
+
# # => ActiveSupport::XMLConverter::DisallowedType: Disallowed type attribute: "integer"
|
124
|
+
#
|
125
|
+
# Note that passing custom disallowed types will override the default types,
|
126
|
+
# which are Symbol and YAML.
|
110
127
|
def from_xml(xml, disallowed_types = nil)
|
111
128
|
ActiveSupport::XMLConverter.new(xml, disallowed_types).to_h
|
112
129
|
end
|
@@ -120,6 +137,8 @@ end
|
|
120
137
|
|
121
138
|
module ActiveSupport
|
122
139
|
class XMLConverter # :nodoc:
|
140
|
+
# Raised if the XML contains attributes with type="yaml" or
|
141
|
+
# type="symbol". Read Hash#from_xml for more details.
|
123
142
|
class DisallowedType < StandardError
|
124
143
|
def initialize(type)
|
125
144
|
super "Disallowed type attribute: #{type.inspect}"
|
@@ -4,7 +4,7 @@ class Hash
|
|
4
4
|
# h1 = { a: true, b: { c: [1, 2, 3] } }
|
5
5
|
# h2 = { a: false, b: { x: [3, 4, 5] } }
|
6
6
|
#
|
7
|
-
# h1.deep_merge(h2)
|
7
|
+
# h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
|
8
8
|
#
|
9
9
|
# Like with Hash#merge in the standard library, a block can be provided
|
10
10
|
# to merge values:
|
@@ -1,8 +1,9 @@
|
|
1
1
|
class Hash
|
2
|
-
# Returns a hash that includes everything
|
3
|
-
# hash = { a: true, b: false, c: nil}
|
4
|
-
# hash.except(:c)
|
5
|
-
# hash # => {
|
2
|
+
# Returns a hash that includes everything except given keys.
|
3
|
+
# hash = { a: true, b: false, c: nil }
|
4
|
+
# hash.except(:c) # => { a: true, b: false }
|
5
|
+
# hash.except(:a, :b) # => { c: nil }
|
6
|
+
# hash # => { a: true, b: false, c: nil }
|
6
7
|
#
|
7
8
|
# This is useful for limiting a set of parameters to everything but a few known toggles:
|
8
9
|
# @person.update(params[:person].except(:admin))
|
@@ -10,10 +11,10 @@ class Hash
|
|
10
11
|
dup.except!(*keys)
|
11
12
|
end
|
12
13
|
|
13
|
-
#
|
14
|
-
# hash = { a: true, b: false, c: nil}
|
15
|
-
# hash.except!(:c) # => { a: true, b: false}
|
16
|
-
# hash
|
14
|
+
# Removes the given keys from hash and returns it.
|
15
|
+
# hash = { a: true, b: false, c: nil }
|
16
|
+
# hash.except!(:c) # => { a: true, b: false }
|
17
|
+
# hash # => { a: true, b: false }
|
17
18
|
def except!(*keys)
|
18
19
|
keys.each { |key| delete(key) }
|
19
20
|
self
|
@@ -6,7 +6,7 @@ class Hash
|
|
6
6
|
#
|
7
7
|
# { a: 1 }.with_indifferent_access['a'] # => 1
|
8
8
|
def with_indifferent_access
|
9
|
-
ActiveSupport::HashWithIndifferentAccess.
|
9
|
+
ActiveSupport::HashWithIndifferentAccess.new(self)
|
10
10
|
end
|
11
11
|
|
12
12
|
# Called when object is nested under an object that receives
|