activesupport 4.2.0 → 4.2.10
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 +280 -0
- data/lib/active_support/cache/mem_cache_store.rb +1 -1
- data/lib/active_support/cache.rb +3 -3
- data/lib/active_support/callbacks.rb +126 -82
- data/lib/active_support/concern.rb +1 -1
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +2 -0
- data/lib/active_support/core_ext/class/subclasses.rb +0 -2
- data/lib/active_support/core_ext/date/conversions.rb +6 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +11 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +23 -3
- data/lib/active_support/core_ext/date_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/enumerable.rb +16 -0
- data/lib/active_support/core_ext/hash/compact.rb +19 -15
- data/lib/active_support/core_ext/hash/conversions.rb +1 -2
- data/lib/active_support/core_ext/hash/transform_values.rb +2 -2
- data/lib/active_support/core_ext/integer/time.rb +0 -15
- data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +1 -0
- data/lib/active_support/core_ext/marshal.rb +8 -5
- data/lib/active_support/core_ext/module/delegation.rb +24 -12
- data/lib/active_support/core_ext/module/method_transplanting.rb +3 -1
- data/lib/active_support/core_ext/numeric/conversions.rb +11 -3
- data/lib/active_support/core_ext/numeric/time.rb +0 -15
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/duplicable.rb +58 -32
- data/lib/active_support/core_ext/object/json.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/string/access.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +4 -3
- data/lib/active_support/core_ext/string/output_safety.rb +6 -2
- data/lib/active_support/core_ext/time/calculations.rb +18 -2
- data/lib/active_support/core_ext/time/compatibility.rb +14 -0
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/deprecation/behaviors.rb +1 -1
- data/lib/active_support/duration.rb +25 -1
- data/lib/active_support/gem_version.rb +1 -1
- data/lib/active_support/hash_with_indifferent_access.rb +22 -3
- data/lib/active_support/inflector/methods.rb +1 -1
- data/lib/active_support/json/encoding.rb +5 -0
- data/lib/active_support/logger.rb +50 -0
- data/lib/active_support/logger_silence.rb +7 -4
- data/lib/active_support/logger_thread_safe_level.rb +32 -0
- data/lib/active_support/message_encryptor.rb +8 -1
- data/lib/active_support/message_verifier.rb +1 -1
- data/lib/active_support/multibyte/chars.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +1 -1
- data/lib/active_support/per_thread_registry.rb +5 -3
- data/lib/active_support/security_utils.rb +7 -0
- data/lib/active_support/testing/time_helpers.rb +16 -13
- data/lib/active_support/time_with_zone.rb +29 -17
- data/lib/active_support/values/time_zone.rb +10 -5
- data/lib/active_support/xml_mini/jdom.rb +6 -5
- data/lib/active_support/xml_mini/libxml.rb +1 -3
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
- data/lib/active_support/xml_mini/nokogiri.rb +1 -3
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
- data/lib/active_support/xml_mini/rexml.rb +7 -8
- data/lib/active_support/xml_mini.rb +33 -15
- data/lib/active_support.rb +9 -0
- metadata +7 -23
@@ -17,21 +17,6 @@ class Integer
|
|
17
17
|
#
|
18
18
|
# # equivalent to Time.now.advance(months: 4, years: 5)
|
19
19
|
# (4.months + 5.years).from_now
|
20
|
-
#
|
21
|
-
# While these methods provide precise calculation when used as in the examples
|
22
|
-
# above, care should be taken to note that this is not true if the result of
|
23
|
-
# +months+, +years+, etc is converted before use:
|
24
|
-
#
|
25
|
-
# # equivalent to 30.days.to_i.from_now
|
26
|
-
# 1.month.to_i.from_now
|
27
|
-
#
|
28
|
-
# # equivalent to 365.25.days.to_f.from_now
|
29
|
-
# 1.year.to_f.from_now
|
30
|
-
#
|
31
|
-
# In such cases, Ruby's core
|
32
|
-
# Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
|
33
|
-
# Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
|
34
|
-
# date and time arithmetic.
|
35
20
|
def months
|
36
21
|
ActiveSupport::Duration.new(self * 30.days, [[:months, self]])
|
37
22
|
end
|
@@ -3,7 +3,7 @@ module Kernel
|
|
3
3
|
# Starts a debugging session if the +debugger+ gem has been loaded (call rails server --debugger to do load it).
|
4
4
|
def debugger
|
5
5
|
message = "\n***** Debugger requested, but was not available (ensure the debugger gem is listed in Gemfile/installed as gem): Start server with --debugger to enable *****\n"
|
6
|
-
defined?(Rails) ? Rails.logger.info(message) : $stderr.puts(message)
|
6
|
+
defined?(Rails.logger) ? Rails.logger.info(message) : $stderr.puts(message)
|
7
7
|
end
|
8
8
|
alias breakpoint debugger unless respond_to?(:breakpoint)
|
9
9
|
end
|
@@ -2,13 +2,16 @@ require 'active_support/core_ext/module/aliasing'
|
|
2
2
|
|
3
3
|
module Marshal
|
4
4
|
class << self
|
5
|
-
def load_with_autoloading(source)
|
6
|
-
load_without_autoloading(source)
|
5
|
+
def load_with_autoloading(source, proc = nil)
|
6
|
+
load_without_autoloading(source, proc)
|
7
7
|
rescue ArgumentError, NameError => exc
|
8
|
-
if exc.message.match(%r|undefined class/module (
|
8
|
+
if exc.message.match(%r|undefined class/module (.+?)(::)?\z|)
|
9
9
|
# try loading the class/module
|
10
|
-
$1.constantize
|
11
|
-
|
10
|
+
loaded = $1.constantize
|
11
|
+
|
12
|
+
raise unless $1 == loaded.name
|
13
|
+
|
14
|
+
# if it is an IO we need to go back to read the object
|
12
15
|
source.rewind if source.respond_to?(:rewind)
|
13
16
|
retry
|
14
17
|
else
|
@@ -185,19 +185,31 @@ class Module
|
|
185
185
|
# On the other hand it could be that the target has side-effects,
|
186
186
|
# whereas conceptually, from the user point of view, the delegator should
|
187
187
|
# be doing one call.
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
" _.#{method}(#{definition})",
|
196
|
-
" else",
|
197
|
-
" #{exception unless allow_nil}",
|
198
|
-
" end",
|
188
|
+
if allow_nil
|
189
|
+
method_def = [
|
190
|
+
"def #{method_prefix}#{method}(#{definition})",
|
191
|
+
"_ = #{to}",
|
192
|
+
"if !_.nil? || nil.respond_to?(:#{method})",
|
193
|
+
" _.#{method}(#{definition})",
|
194
|
+
"end",
|
199
195
|
"end"
|
200
|
-
|
196
|
+
].join ';'
|
197
|
+
else
|
198
|
+
exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
|
199
|
+
|
200
|
+
method_def = [
|
201
|
+
"def #{method_prefix}#{method}(#{definition})",
|
202
|
+
" _ = #{to}",
|
203
|
+
" _.#{method}(#{definition})",
|
204
|
+
"rescue NoMethodError => e",
|
205
|
+
" if _.nil? && e.name == :#{method}",
|
206
|
+
" #{exception}",
|
207
|
+
" else",
|
208
|
+
" raise",
|
209
|
+
" end",
|
210
|
+
"end"
|
211
|
+
].join ';'
|
212
|
+
end
|
201
213
|
|
202
214
|
module_eval(method_def, file, line)
|
203
215
|
end
|
@@ -2,7 +2,9 @@ class Module
|
|
2
2
|
###
|
3
3
|
# TODO: remove this after 1.9 support is dropped
|
4
4
|
def methods_transplantable? # :nodoc:
|
5
|
-
x = Module.new {
|
5
|
+
x = Module.new {
|
6
|
+
def foo; end # :nodoc:
|
7
|
+
}
|
6
8
|
Module.new { define_method :bar, x.instance_method(:foo) }
|
7
9
|
true
|
8
10
|
rescue TypeError
|
@@ -41,7 +41,7 @@ class Numeric
|
|
41
41
|
# 1000.to_s(:percentage, delimiter: '.', separator: ',') # => 1.000,000%
|
42
42
|
# 302.24398923423.to_s(:percentage, precision: 5) # => 302.24399%
|
43
43
|
# 1000.to_s(:percentage, locale: :fr) # => 1 000,000%
|
44
|
-
# 100.to_s(:percentage, format: '%n %') # => 100 %
|
44
|
+
# 100.to_s(:percentage, format: '%n %') # => 100.000 %
|
45
45
|
#
|
46
46
|
# Delimited:
|
47
47
|
# 12345678.to_s(:delimited) # => 12,345,678
|
@@ -78,7 +78,7 @@ class Numeric
|
|
78
78
|
# 1234567.to_s(:human_size, precision: 2) # => 1.2 MB
|
79
79
|
# 483989.to_s(:human_size, precision: 2) # => 470 KB
|
80
80
|
# 1234567.to_s(:human_size, precision: 2, separator: ',') # => 1,2 MB
|
81
|
-
# 1234567890123.to_s(:human_size, precision: 5) # => "1.
|
81
|
+
# 1234567890123.to_s(:human_size, precision: 5) # => "1.1228 TB"
|
82
82
|
# 524288000.to_s(:human_size, precision: 5) # => "500 MB"
|
83
83
|
#
|
84
84
|
# Human-friendly format:
|
@@ -118,7 +118,15 @@ class Numeric
|
|
118
118
|
end
|
119
119
|
end
|
120
120
|
|
121
|
-
[Float,
|
121
|
+
klasses = [Float, BigDecimal]
|
122
|
+
# Ruby 2.4+ unifies Fixnum & Bignum into Integer.
|
123
|
+
if 0.class == Integer
|
124
|
+
klasses << Integer
|
125
|
+
else
|
126
|
+
klasses << Fixnum << Bignum
|
127
|
+
end
|
128
|
+
|
129
|
+
klasses.each do |klass|
|
122
130
|
klass.send(:alias_method, :to_default_s, :to_s)
|
123
131
|
|
124
132
|
klass.send(:define_method, :to_s) do |*args|
|
@@ -16,21 +16,6 @@ class Numeric
|
|
16
16
|
#
|
17
17
|
# # equivalent to Time.current.advance(months: 4, years: 5)
|
18
18
|
# (4.months + 5.years).from_now
|
19
|
-
#
|
20
|
-
# While these methods provide precise calculation when used as in the examples above, care
|
21
|
-
# should be taken to note that this is not true if the result of `months', `years', etc is
|
22
|
-
# converted before use:
|
23
|
-
#
|
24
|
-
# # equivalent to 30.days.to_i.from_now
|
25
|
-
# 1.month.to_i.from_now
|
26
|
-
#
|
27
|
-
# # equivalent to 365.25.days.to_f.from_now
|
28
|
-
# 1.year.to_f.from_now
|
29
|
-
#
|
30
|
-
# In such cases, Ruby's core
|
31
|
-
# Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
|
32
|
-
# Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
|
33
|
-
# date and time arithmetic.
|
34
19
|
def seconds
|
35
20
|
ActiveSupport::Duration.new(self, [[:seconds, self]])
|
36
21
|
end
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
class Object
|
4
4
|
# An object is blank if it's false, empty, or a whitespace string.
|
5
|
-
# For example, '', ' ', +nil+, [], and {} are all blank.
|
5
|
+
# For example, +false+, '', ' ', +nil+, [], and {} are all blank.
|
6
6
|
#
|
7
7
|
# This simplifies
|
8
8
|
#
|
9
|
-
# address
|
9
|
+
# !address || address.empty?
|
10
10
|
#
|
11
11
|
# to
|
12
12
|
#
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#--
|
2
|
-
# Most objects are cloneable, but not all. For example you can't dup
|
2
|
+
# Most objects are cloneable, but not all. For example you can't dup methods:
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# method(:puts).dup # => TypeError: allocator undefined for Method
|
5
5
|
#
|
6
6
|
# Classes may signal their instances are not duplicable removing +dup+/+clone+
|
7
7
|
# or raising exceptions from them. So, to dup an arbitrary object you normally
|
@@ -27,52 +27,78 @@ class Object
|
|
27
27
|
end
|
28
28
|
|
29
29
|
class NilClass
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
begin
|
31
|
+
nil.dup
|
32
|
+
rescue TypeError
|
33
|
+
|
34
|
+
# +nil+ is not duplicable:
|
35
|
+
#
|
36
|
+
# nil.duplicable? # => false
|
37
|
+
# nil.dup # => TypeError: can't dup NilClass
|
38
|
+
def duplicable?
|
39
|
+
false
|
40
|
+
end
|
36
41
|
end
|
37
42
|
end
|
38
43
|
|
39
44
|
class FalseClass
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
45
|
+
begin
|
46
|
+
false.dup
|
47
|
+
rescue TypeError
|
48
|
+
|
49
|
+
# +false+ is not duplicable:
|
50
|
+
#
|
51
|
+
# false.duplicable? # => false
|
52
|
+
# false.dup # => TypeError: can't dup FalseClass
|
53
|
+
def duplicable?
|
54
|
+
false
|
55
|
+
end
|
46
56
|
end
|
47
57
|
end
|
48
58
|
|
49
59
|
class TrueClass
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
60
|
+
begin
|
61
|
+
true.dup
|
62
|
+
rescue TypeError
|
63
|
+
|
64
|
+
# +true+ is not duplicable:
|
65
|
+
#
|
66
|
+
# true.duplicable? # => false
|
67
|
+
# true.dup # => TypeError: can't dup TrueClass
|
68
|
+
def duplicable?
|
69
|
+
false
|
70
|
+
end
|
56
71
|
end
|
57
72
|
end
|
58
73
|
|
59
74
|
class Symbol
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
75
|
+
begin
|
76
|
+
:symbol.dup # Ruby 2.4.x.
|
77
|
+
'symbol_from_string'.to_sym.dup # Some symbols can't `dup` in Ruby 2.4.0.
|
78
|
+
rescue TypeError
|
79
|
+
|
80
|
+
# Symbols are not duplicable:
|
81
|
+
#
|
82
|
+
# :my_symbol.duplicable? # => false
|
83
|
+
# :my_symbol.dup # => TypeError: can't dup Symbol
|
84
|
+
def duplicable?
|
85
|
+
false
|
86
|
+
end
|
66
87
|
end
|
67
88
|
end
|
68
89
|
|
69
90
|
class Numeric
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
91
|
+
begin
|
92
|
+
1.dup
|
93
|
+
rescue TypeError
|
94
|
+
|
95
|
+
# Numbers are not duplicable:
|
96
|
+
#
|
97
|
+
# 3.duplicable? # => false
|
98
|
+
# 3.dup # => TypeError: can't dup Integer
|
99
|
+
def duplicable?
|
100
|
+
false
|
101
|
+
end
|
76
102
|
end
|
77
103
|
end
|
78
104
|
|
@@ -26,9 +26,9 @@ require 'active_support/core_ext/module/aliasing'
|
|
26
26
|
# bypassed completely. This means that as_json won't be invoked and the JSON gem will simply
|
27
27
|
# ignore any options it does not natively understand. This also means that ::JSON.{generate,dump}
|
28
28
|
# should give exactly the same results with or without active support.
|
29
|
-
[Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass
|
29
|
+
[Enumerable, Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].each do |klass|
|
30
30
|
klass.class_eval do
|
31
|
-
def to_json_with_active_support_encoder(options = nil)
|
31
|
+
def to_json_with_active_support_encoder(options = nil) # :nodoc:
|
32
32
|
if options.is_a?(::JSON::State)
|
33
33
|
# Called from JSON.{generate,dump}, forward it to JSON gem's to_json
|
34
34
|
self.to_json_without_active_support_encoder(options)
|
@@ -65,10 +65,10 @@ class Object
|
|
65
65
|
|
66
66
|
# Same as #try, but will raise a NoMethodError exception if the receiver is not +nil+ and
|
67
67
|
# does not implement the tried method.
|
68
|
-
|
68
|
+
|
69
69
|
def try!(*a, &b)
|
70
70
|
if a.empty? && block_given?
|
71
|
-
if b.arity
|
71
|
+
if b.arity == 0
|
72
72
|
instance_eval(&b)
|
73
73
|
else
|
74
74
|
yield self
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class String
|
2
|
-
# If you pass a single
|
2
|
+
# If you pass a single integer, returns a substring of one character at that
|
3
3
|
# position. The first character of the string is at position 0, the next at
|
4
4
|
# position 1, and so on. If a range is supplied, a substring containing
|
5
5
|
# characters at offsets given by the range is returned. In both cases, if an
|
@@ -26,6 +26,7 @@ class String
|
|
26
26
|
# Returns a new string with all occurrences of the patterns removed.
|
27
27
|
# str = "foo bar test"
|
28
28
|
# str.remove(" test") # => "foo bar"
|
29
|
+
# str.remove(" test", /bar/) # => "foo "
|
29
30
|
# str # => "foo bar test"
|
30
31
|
def remove(*patterns)
|
31
32
|
dup.remove!(*patterns)
|
@@ -33,8 +34,8 @@ class String
|
|
33
34
|
|
34
35
|
# Alters the string by removing all occurrences of the patterns.
|
35
36
|
# str = "foo bar test"
|
36
|
-
# str.remove!(" test")
|
37
|
-
# str
|
37
|
+
# str.remove!(" test", /bar/) # => "foo "
|
38
|
+
# str # => "foo "
|
38
39
|
def remove!(*patterns)
|
39
40
|
patterns.each do |pattern|
|
40
41
|
gsub! pattern, ""
|
@@ -93,7 +94,7 @@ class String
|
|
93
94
|
def truncate_words(words_count, options = {})
|
94
95
|
sep = options[:separator] || /\s+/
|
95
96
|
sep = Regexp.escape(sep.to_s) unless Regexp === sep
|
96
|
-
if self =~ /\A((
|
97
|
+
if self =~ /\A((?>.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m
|
97
98
|
$1 + (options[:omission] || '...')
|
98
99
|
else
|
99
100
|
dup
|
@@ -150,7 +150,11 @@ module ActiveSupport #:nodoc:
|
|
150
150
|
else
|
151
151
|
if html_safe?
|
152
152
|
new_safe_buffer = super
|
153
|
-
|
153
|
+
|
154
|
+
if new_safe_buffer
|
155
|
+
new_safe_buffer.instance_variable_set :@html_safe, true
|
156
|
+
end
|
157
|
+
|
154
158
|
new_safe_buffer
|
155
159
|
else
|
156
160
|
to_str[*args]
|
@@ -219,7 +223,7 @@ module ActiveSupport #:nodoc:
|
|
219
223
|
end
|
220
224
|
|
221
225
|
def encode_with(coder)
|
222
|
-
coder.
|
226
|
+
coder.represent_object nil, to_str
|
223
227
|
end
|
224
228
|
|
225
229
|
UNSAFE_STRING_METHODS.each do |unsafe_method|
|
@@ -3,6 +3,7 @@ require 'active_support/core_ext/time/conversions'
|
|
3
3
|
require 'active_support/time_with_zone'
|
4
4
|
require 'active_support/core_ext/time/zones'
|
5
5
|
require 'active_support/core_ext/date_and_time/calculations'
|
6
|
+
require 'active_support/core_ext/date/calculations'
|
6
7
|
|
7
8
|
class Time
|
8
9
|
include DateAndTime::Calculations
|
@@ -62,6 +63,13 @@ class Time
|
|
62
63
|
end_of_day.to_i - to_i
|
63
64
|
end
|
64
65
|
|
66
|
+
# Returns the fraction of a second as a +Rational+
|
67
|
+
#
|
68
|
+
# Time.new(2012, 8, 29, 0, 0, 0.5).sec_fraction # => (1/2)
|
69
|
+
def sec_fraction
|
70
|
+
subsec
|
71
|
+
end
|
72
|
+
|
65
73
|
# Returns a new Time where one or more of the elements have been changed according
|
66
74
|
# to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
|
67
75
|
# <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
|
@@ -94,7 +102,7 @@ class Time
|
|
94
102
|
elsif zone
|
95
103
|
::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
|
96
104
|
else
|
97
|
-
raise ArgumentError, 'argument out of range' if new_usec
|
105
|
+
raise ArgumentError, 'argument out of range' if new_usec >= 1000000
|
98
106
|
::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset)
|
99
107
|
end
|
100
108
|
end
|
@@ -104,6 +112,12 @@ class Time
|
|
104
112
|
# takes a hash with any of these keys: <tt>:years</tt>, <tt>:months</tt>,
|
105
113
|
# <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>, <tt>:minutes</tt>,
|
106
114
|
# <tt>:seconds</tt>.
|
115
|
+
#
|
116
|
+
# Time.new(2015, 8, 1, 14, 35, 0).advance(seconds: 1) # => 2015-08-01 14:35:01 -0700
|
117
|
+
# Time.new(2015, 8, 1, 14, 35, 0).advance(minutes: 1) # => 2015-08-01 14:36:00 -0700
|
118
|
+
# Time.new(2015, 8, 1, 14, 35, 0).advance(hours: 1) # => 2015-08-01 15:35:00 -0700
|
119
|
+
# Time.new(2015, 8, 1, 14, 35, 0).advance(days: 1) # => 2015-08-02 14:35:00 -0700
|
120
|
+
# Time.new(2015, 8, 1, 14, 35, 0).advance(weeks: 1) # => 2015-08-08 14:35:00 -0700
|
107
121
|
def advance(options)
|
108
122
|
unless options[:weeks].nil?
|
109
123
|
options[:weeks], partial_weeks = options[:weeks].divmod(1)
|
@@ -243,7 +257,9 @@ class Time
|
|
243
257
|
# can be chronologically compared with a Time
|
244
258
|
def compare_with_coercion(other)
|
245
259
|
# we're avoiding Time#to_datetime cause it's expensive
|
246
|
-
if other.
|
260
|
+
if other.class == Time
|
261
|
+
compare_without_coercion(other)
|
262
|
+
elsif other.is_a?(Time)
|
247
263
|
compare_without_coercion(other.to_time)
|
248
264
|
else
|
249
265
|
to_datetime <=> other
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "active_support/core_ext/date_and_time/compatibility"
|
2
|
+
require "active_support/core_ext/module/remove_method"
|
3
|
+
|
4
|
+
class Time
|
5
|
+
include DateAndTime::Compatibility
|
6
|
+
|
7
|
+
remove_possible_method :to_time
|
8
|
+
|
9
|
+
# Either return +self+ or the time in the local system timezone depending
|
10
|
+
# on the setting of +ActiveSupport.to_time_preserves_timezone+.
|
11
|
+
def to_time
|
12
|
+
preserve_timezone ? self : getlocal
|
13
|
+
end
|
14
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/time/acts_like'
|
2
2
|
require 'active_support/core_ext/time/calculations'
|
3
|
+
require 'active_support/core_ext/time/compatibility'
|
3
4
|
require 'active_support/core_ext/time/conversions'
|
4
5
|
require 'active_support/core_ext/time/marshal'
|
5
6
|
require 'active_support/core_ext/time/zones'
|
@@ -56,6 +56,30 @@ module ActiveSupport
|
|
56
56
|
@value.to_s
|
57
57
|
end
|
58
58
|
|
59
|
+
# Returns the number of seconds that this Duration represents.
|
60
|
+
#
|
61
|
+
# 1.minute.to_i # => 60
|
62
|
+
# 1.hour.to_i # => 3600
|
63
|
+
# 1.day.to_i # => 86400
|
64
|
+
#
|
65
|
+
# Note that this conversion makes some assumptions about the
|
66
|
+
# duration of some periods, e.g. months are always 30 days
|
67
|
+
# and years are 365.25 days:
|
68
|
+
#
|
69
|
+
# # equivalent to 30.days.to_i
|
70
|
+
# 1.month.to_i # => 2592000
|
71
|
+
#
|
72
|
+
# # equivalent to 365.25.days.to_i
|
73
|
+
# 1.year.to_i # => 31557600
|
74
|
+
#
|
75
|
+
# In such cases, Ruby's core
|
76
|
+
# Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
|
77
|
+
# Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
|
78
|
+
# date and time arithmetic.
|
79
|
+
def to_i
|
80
|
+
@value.to_i
|
81
|
+
end
|
82
|
+
|
59
83
|
# Returns +true+ if +other+ is also a Duration instance, which has the
|
60
84
|
# same parts as this one.
|
61
85
|
def eql?(other)
|
@@ -91,7 +115,7 @@ module ActiveSupport
|
|
91
115
|
reduce(::Hash.new(0)) { |h,(l,r)| h[l] += r; h }.
|
92
116
|
sort_by {|unit, _ | [:years, :months, :days, :minutes, :seconds].index(unit)}.
|
93
117
|
map {|unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}"}.
|
94
|
-
to_sentence(:
|
118
|
+
to_sentence(locale: ::I18n.default_locale)
|
95
119
|
end
|
96
120
|
|
97
121
|
def as_json(options = nil) #:nodoc:
|
@@ -188,7 +188,7 @@ module ActiveSupport
|
|
188
188
|
# dup[:a][:c] # => "c"
|
189
189
|
def dup
|
190
190
|
self.class.new(self).tap do |new_hash|
|
191
|
-
new_hash
|
191
|
+
set_defaults(new_hash)
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|
@@ -245,9 +245,20 @@ module ActiveSupport
|
|
245
245
|
dup.tap { |hash| hash.reject!(*args, &block) }
|
246
246
|
end
|
247
247
|
|
248
|
+
def transform_values(*args, &block)
|
249
|
+
return to_enum(:transform_values) unless block_given?
|
250
|
+
dup.tap { |hash| hash.transform_values!(*args, &block) }
|
251
|
+
end
|
252
|
+
|
253
|
+
def compact
|
254
|
+
dup.tap(&:compact!)
|
255
|
+
end
|
256
|
+
|
248
257
|
# Convert to a regular hash with string keys.
|
249
258
|
def to_hash
|
250
|
-
_new_hash = Hash.new
|
259
|
+
_new_hash = Hash.new
|
260
|
+
set_defaults(_new_hash)
|
261
|
+
|
251
262
|
each do |key, value|
|
252
263
|
_new_hash[key] = convert_value(value, for: :to_hash)
|
253
264
|
end
|
@@ -267,7 +278,7 @@ module ActiveSupport
|
|
267
278
|
value.nested_under_indifferent_access
|
268
279
|
end
|
269
280
|
elsif value.is_a?(Array)
|
270
|
-
|
281
|
+
if options[:for] != :assignment || value.frozen?
|
271
282
|
value = value.dup
|
272
283
|
end
|
273
284
|
value.map! { |e| convert_value(e, options) }
|
@@ -275,6 +286,14 @@ module ActiveSupport
|
|
275
286
|
value
|
276
287
|
end
|
277
288
|
end
|
289
|
+
|
290
|
+
def set_defaults(target)
|
291
|
+
if default_proc
|
292
|
+
target.default_proc = default_proc.dup
|
293
|
+
else
|
294
|
+
target.default = default
|
295
|
+
end
|
296
|
+
end
|
278
297
|
end
|
279
298
|
end
|
280
299
|
|
@@ -153,7 +153,7 @@ module ActiveSupport
|
|
153
153
|
# 'TheManWithoutAPast'.titleize # => "The Man Without A Past"
|
154
154
|
# 'raiders_of_the_lost_ark'.titleize # => "Raiders Of The Lost Ark"
|
155
155
|
def titleize(word)
|
156
|
-
humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) {
|
156
|
+
humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) { |match| match.capitalize }
|
157
157
|
end
|
158
158
|
|
159
159
|
# Create the name of a table like Rails does for models to table names. This
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/object/json'
|
2
2
|
require 'active_support/core_ext/module/delegation'
|
3
|
+
require 'active_support/deprecation'
|
3
4
|
|
4
5
|
module ActiveSupport
|
5
6
|
class << self
|
@@ -58,6 +59,10 @@ module ActiveSupport
|
|
58
59
|
super.gsub ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, ESCAPED_CHARS
|
59
60
|
end
|
60
61
|
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
self
|
65
|
+
end
|
61
66
|
end
|
62
67
|
|
63
68
|
# Mark these as private so we don't leak encoding-specific constructs
|