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.

Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +280 -0
  3. data/lib/active_support/cache/mem_cache_store.rb +1 -1
  4. data/lib/active_support/cache.rb +3 -3
  5. data/lib/active_support/callbacks.rb +126 -82
  6. data/lib/active_support/concern.rb +1 -1
  7. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +2 -0
  8. data/lib/active_support/core_ext/class/subclasses.rb +0 -2
  9. data/lib/active_support/core_ext/date/conversions.rb +6 -0
  10. data/lib/active_support/core_ext/date_and_time/calculations.rb +11 -0
  11. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  12. data/lib/active_support/core_ext/date_time/calculations.rb +23 -3
  13. data/lib/active_support/core_ext/date_time/compatibility.rb +15 -0
  14. data/lib/active_support/core_ext/date_time.rb +1 -0
  15. data/lib/active_support/core_ext/enumerable.rb +16 -0
  16. data/lib/active_support/core_ext/hash/compact.rb +19 -15
  17. data/lib/active_support/core_ext/hash/conversions.rb +1 -2
  18. data/lib/active_support/core_ext/hash/transform_values.rb +2 -2
  19. data/lib/active_support/core_ext/integer/time.rb +0 -15
  20. data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
  21. data/lib/active_support/core_ext/kernel/reporting.rb +1 -0
  22. data/lib/active_support/core_ext/marshal.rb +8 -5
  23. data/lib/active_support/core_ext/module/delegation.rb +24 -12
  24. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -1
  25. data/lib/active_support/core_ext/numeric/conversions.rb +11 -3
  26. data/lib/active_support/core_ext/numeric/time.rb +0 -15
  27. data/lib/active_support/core_ext/object/blank.rb +2 -2
  28. data/lib/active_support/core_ext/object/duplicable.rb +58 -32
  29. data/lib/active_support/core_ext/object/json.rb +2 -2
  30. data/lib/active_support/core_ext/object/try.rb +2 -2
  31. data/lib/active_support/core_ext/string/access.rb +1 -1
  32. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  33. data/lib/active_support/core_ext/string/filters.rb +4 -3
  34. data/lib/active_support/core_ext/string/output_safety.rb +6 -2
  35. data/lib/active_support/core_ext/time/calculations.rb +18 -2
  36. data/lib/active_support/core_ext/time/compatibility.rb +14 -0
  37. data/lib/active_support/core_ext/time.rb +1 -0
  38. data/lib/active_support/deprecation/behaviors.rb +1 -1
  39. data/lib/active_support/duration.rb +25 -1
  40. data/lib/active_support/gem_version.rb +1 -1
  41. data/lib/active_support/hash_with_indifferent_access.rb +22 -3
  42. data/lib/active_support/inflector/methods.rb +1 -1
  43. data/lib/active_support/json/encoding.rb +5 -0
  44. data/lib/active_support/logger.rb +50 -0
  45. data/lib/active_support/logger_silence.rb +7 -4
  46. data/lib/active_support/logger_thread_safe_level.rb +32 -0
  47. data/lib/active_support/message_encryptor.rb +8 -1
  48. data/lib/active_support/message_verifier.rb +1 -1
  49. data/lib/active_support/multibyte/chars.rb +1 -1
  50. data/lib/active_support/notifications/fanout.rb +1 -1
  51. data/lib/active_support/number_helper/number_to_rounded_converter.rb +1 -1
  52. data/lib/active_support/per_thread_registry.rb +5 -3
  53. data/lib/active_support/security_utils.rb +7 -0
  54. data/lib/active_support/testing/time_helpers.rb +16 -13
  55. data/lib/active_support/time_with_zone.rb +29 -17
  56. data/lib/active_support/values/time_zone.rb +10 -5
  57. data/lib/active_support/xml_mini/jdom.rb +6 -5
  58. data/lib/active_support/xml_mini/libxml.rb +1 -3
  59. data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
  60. data/lib/active_support/xml_mini/nokogiri.rb +1 -3
  61. data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
  62. data/lib/active_support/xml_mini/rexml.rb +7 -8
  63. data/lib/active_support/xml_mini.rb +33 -15
  64. data/lib/active_support.rb +9 -0
  65. 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
@@ -1,5 +1,6 @@
1
1
  require 'rbconfig'
2
2
  require 'tempfile'
3
+ require 'active_support/deprecation'
3
4
 
4
5
  module Kernel
5
6
  # Sets $VERBOSE to nil for the duration of the block and back to its original
@@ -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
- # if it is a IO we need to go back to read the object
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
- exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
190
-
191
- method_def = [
192
- "def #{method_prefix}#{method}(#{definition})",
193
- " _ = #{to}",
194
- " if !_.nil? || nil.respond_to?(:#{method})",
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
- ].join ';'
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 { def foo; end }
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.1229 TB"
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, Fixnum, Bignum, BigDecimal].each do |klass|
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.nil? || address.empty?
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 +nil+:
2
+ # Most objects are cloneable, but not all. For example you can't dup methods:
3
3
  #
4
- # nil.dup # => TypeError: can't dup NilClass
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
- # +nil+ is not duplicable:
31
- #
32
- # nil.duplicable? # => false
33
- # nil.dup # => TypeError: can't dup NilClass
34
- def duplicable?
35
- false
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
- # +false+ is not duplicable:
41
- #
42
- # false.duplicable? # => false
43
- # false.dup # => TypeError: can't dup FalseClass
44
- def duplicable?
45
- false
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
- # +true+ is not duplicable:
51
- #
52
- # true.duplicable? # => false
53
- # true.dup # => TypeError: can't dup TrueClass
54
- def duplicable?
55
- false
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
- # Symbols are not duplicable:
61
- #
62
- # :my_symbol.duplicable? # => false
63
- # :my_symbol.dup # => TypeError: can't dup Symbol
64
- def duplicable?
65
- false
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
- # Numbers are not duplicable:
71
- #
72
- # 3.duplicable? # => false
73
- # 3.dup # => TypeError: can't dup Fixnum
74
- def duplicable?
75
- false
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, Enumerable].each do |klass|
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.zero?
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 Fixnum, returns a substring of one character at that
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
@@ -31,7 +31,7 @@ class String
31
31
  parts.fetch(:offset, form == :utc ? 0 : nil)
32
32
  )
33
33
 
34
- form == :utc ? time.utc : time.getlocal
34
+ form == :utc ? time.utc : time.to_time
35
35
  end
36
36
 
37
37
  # Converts a string to a Date value.
@@ -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") # => "foo bar"
37
- # str # => "foo bar"
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((?:.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m
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
- new_safe_buffer.instance_variable_set :@html_safe, true
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.represent_scalar nil, to_str
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 > 999999
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.is_a?(Time)
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'
@@ -20,7 +20,7 @@ module ActiveSupport
20
20
 
21
21
  log: ->(message, callstack) {
22
22
  logger =
23
- if defined?(Rails) && Rails.logger
23
+ if defined?(Rails.logger) && Rails.logger
24
24
  Rails.logger
25
25
  else
26
26
  require 'active_support/logger'
@@ -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(:locale => :en)
118
+ to_sentence(locale: ::I18n.default_locale)
95
119
  end
96
120
 
97
121
  def as_json(options = nil) #:nodoc:
@@ -7,7 +7,7 @@ module ActiveSupport
7
7
  module VERSION
8
8
  MAJOR = 4
9
9
  MINOR = 2
10
- TINY = 0
10
+ TINY = 10
11
11
  PRE = nil
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -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.default = default
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(default)
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
- unless options[:for] == :assignment
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]/) { $&.capitalize }
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