activesupport 4.1.15 → 4.2.11.3

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 (111) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +395 -574
  3. data/README.rdoc +7 -2
  4. data/lib/active_support.rb +19 -0
  5. data/lib/active_support/backtrace_cleaner.rb +4 -4
  6. data/lib/active_support/cache.rb +17 -19
  7. data/lib/active_support/cache/file_store.rb +5 -0
  8. data/lib/active_support/cache/mem_cache_store.rb +1 -1
  9. data/lib/active_support/cache/strategy/local_cache.rb +5 -4
  10. data/lib/active_support/cache/strategy/local_cache_middleware.rb +5 -0
  11. data/lib/active_support/callbacks.rb +41 -33
  12. data/lib/active_support/concern.rb +10 -2
  13. data/lib/active_support/core_ext/array/access.rb +9 -1
  14. data/lib/active_support/core_ext/array/grouping.rb +5 -0
  15. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +2 -0
  16. data/lib/active_support/core_ext/class/delegating_attributes.rb +4 -0
  17. data/lib/active_support/core_ext/class/subclasses.rb +0 -2
  18. data/lib/active_support/core_ext/date/conversions.rb +6 -0
  19. data/lib/active_support/core_ext/date_and_time/calculations.rb +11 -0
  20. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  21. data/lib/active_support/core_ext/date_time.rb +1 -0
  22. data/lib/active_support/core_ext/date_time/calculations.rb +34 -4
  23. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  24. data/lib/active_support/core_ext/date_time/conversions.rb +2 -2
  25. data/lib/active_support/core_ext/digest/uuid.rb +51 -0
  26. data/lib/active_support/core_ext/enumerable.rb +16 -0
  27. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  28. data/lib/active_support/core_ext/hash.rb +1 -0
  29. data/lib/active_support/core_ext/hash/compact.rb +20 -16
  30. data/lib/active_support/core_ext/hash/conversions.rb +3 -5
  31. data/lib/active_support/core_ext/hash/except.rb +8 -2
  32. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  33. data/lib/active_support/core_ext/hash/keys.rb +10 -6
  34. data/lib/active_support/core_ext/hash/slice.rb +8 -2
  35. data/lib/active_support/core_ext/hash/transform_values.rb +23 -0
  36. data/lib/active_support/core_ext/integer/time.rb +0 -15
  37. data/lib/active_support/core_ext/kernel.rb +3 -2
  38. data/lib/active_support/core_ext/kernel/concern.rb +10 -0
  39. data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
  40. data/lib/active_support/core_ext/kernel/reporting.rb +15 -0
  41. data/lib/active_support/core_ext/load_error.rb +4 -1
  42. data/lib/active_support/core_ext/marshal.rb +8 -5
  43. data/lib/active_support/core_ext/module/aliasing.rb +2 -2
  44. data/lib/active_support/core_ext/module/delegation.rb +34 -18
  45. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -1
  46. data/lib/active_support/core_ext/numeric/conversions.rb +11 -3
  47. data/lib/active_support/core_ext/numeric/time.rb +1 -34
  48. data/lib/active_support/core_ext/object.rb +1 -0
  49. data/lib/active_support/core_ext/object/blank.rb +2 -2
  50. data/lib/active_support/core_ext/object/duplicable.rb +62 -33
  51. data/lib/active_support/core_ext/object/itself.rb +15 -0
  52. data/lib/active_support/core_ext/object/json.rb +2 -2
  53. data/lib/active_support/core_ext/object/to_query.rb +2 -1
  54. data/lib/active_support/core_ext/object/try.rb +35 -13
  55. data/lib/active_support/core_ext/object/with_options.rb +30 -3
  56. data/lib/active_support/core_ext/string/access.rb +5 -5
  57. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  58. data/lib/active_support/core_ext/string/filters.rb +44 -6
  59. data/lib/active_support/core_ext/string/inflections.rb +4 -1
  60. data/lib/active_support/core_ext/string/output_safety.rb +33 -14
  61. data/lib/active_support/core_ext/thread.rb +7 -0
  62. data/lib/active_support/core_ext/time.rb +1 -0
  63. data/lib/active_support/core_ext/time/calculations.rb +31 -7
  64. data/lib/active_support/core_ext/time/compatibility.rb +14 -0
  65. data/lib/active_support/core_ext/time/conversions.rb +1 -1
  66. data/lib/active_support/dependencies.rb +32 -18
  67. data/lib/active_support/dependencies/autoload.rb +1 -1
  68. data/lib/active_support/deprecation.rb +1 -1
  69. data/lib/active_support/deprecation/behaviors.rb +1 -1
  70. data/lib/active_support/duration.rb +47 -5
  71. data/lib/active_support/gem_version.rb +4 -4
  72. data/lib/active_support/hash_with_indifferent_access.rb +35 -7
  73. data/lib/active_support/i18n_railtie.rb +1 -7
  74. data/lib/active_support/inflector/inflections.rb +2 -2
  75. data/lib/active_support/inflector/methods.rb +43 -19
  76. data/lib/active_support/json/decoding.rb +1 -1
  77. data/lib/active_support/json/encoding.rb +3 -2
  78. data/lib/active_support/logger.rb +36 -0
  79. data/lib/active_support/logger_silence.rb +4 -22
  80. data/lib/active_support/logger_thread_safe_level.rb +32 -0
  81. data/lib/active_support/message_encryptor.rb +10 -2
  82. data/lib/active_support/message_verifier.rb +11 -12
  83. data/lib/active_support/multibyte/chars.rb +1 -1
  84. data/lib/active_support/multibyte/unicode.rb +5 -4
  85. data/lib/active_support/notifications.rb +8 -3
  86. data/lib/active_support/notifications/fanout.rb +12 -7
  87. data/lib/active_support/number_helper.rb +12 -13
  88. data/lib/active_support/number_helper/number_to_currency_converter.rb +1 -1
  89. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  90. data/lib/active_support/number_helper/number_to_rounded_converter.rb +1 -1
  91. data/lib/active_support/per_thread_registry.rb +5 -3
  92. data/lib/active_support/test_case.rb +46 -12
  93. data/lib/active_support/testing/assertions.rb +1 -1
  94. data/lib/active_support/testing/constant_lookup.rb +1 -5
  95. data/lib/active_support/testing/declarative.rb +1 -25
  96. data/lib/active_support/testing/isolation.rb +16 -6
  97. data/lib/active_support/testing/tagged_logging.rb +1 -1
  98. data/lib/active_support/testing/time_helpers.rb +23 -16
  99. data/lib/active_support/time.rb +0 -2
  100. data/lib/active_support/time_with_zone.rb +48 -29
  101. data/lib/active_support/values/time_zone.rb +81 -75
  102. data/lib/active_support/values/unicode_tables.dat +0 -0
  103. data/lib/active_support/xml_mini.rb +30 -15
  104. data/lib/active_support/xml_mini/libxml.rb +1 -3
  105. data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
  106. data/lib/active_support/xml_mini/nokogiri.rb +1 -3
  107. data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
  108. data/lib/active_support/xml_mini/rexml.rb +1 -3
  109. metadata +21 -36
  110. data/lib/active_support/core_ext/object/to_json.rb +0 -5
  111. data/lib/active_support/file_watcher.rb +0 -36
@@ -1,5 +1,6 @@
1
1
  require 'erb'
2
2
  require 'active_support/core_ext/kernel/singleton_class'
3
+ require 'active_support/deprecation'
3
4
 
4
5
  class ERB
5
6
  module Util
@@ -18,12 +19,7 @@ class ERB
18
19
  # puts html_escape('is a > 0 & a < 10?')
19
20
  # # => is a &gt; 0 &amp; a &lt; 10?
20
21
  def html_escape(s)
21
- s = s.to_s
22
- if s.html_safe?
23
- s
24
- else
25
- s.gsub(HTML_ESCAPE_REGEXP, HTML_ESCAPE).html_safe
26
- end
22
+ unwrapped_html_escape(s).html_safe
27
23
  end
28
24
 
29
25
  # Aliasing twice issues a warning "discarding old...". Remove first to avoid it.
@@ -35,6 +31,18 @@ class ERB
35
31
  singleton_class.send(:remove_method, :html_escape)
36
32
  module_function :html_escape
37
33
 
34
+ # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
35
+ # This method is not for public consumption! Seriously!
36
+ def unwrapped_html_escape(s) # :nodoc:
37
+ s = s.to_s
38
+ if s.html_safe?
39
+ s
40
+ else
41
+ s.gsub(HTML_ESCAPE_REGEXP, HTML_ESCAPE)
42
+ end
43
+ end
44
+ module_function :unwrapped_html_escape
45
+
38
46
  # A utility method for escaping HTML without affecting existing escaped entities.
39
47
  #
40
48
  # html_escape_once('1 < 2 &amp; 3')
@@ -124,7 +132,7 @@ module ActiveSupport #:nodoc:
124
132
  class SafeBuffer < String
125
133
  UNSAFE_STRING_METHODS = %w(
126
134
  capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
127
- slice squeeze strip sub succ swapcase tr tr_s upcase prepend
135
+ slice squeeze strip sub succ swapcase tr tr_s upcase
128
136
  )
129
137
 
130
138
  alias_method :original_concat, :concat
@@ -144,7 +152,7 @@ module ActiveSupport #:nodoc:
144
152
  new_safe_buffer = super
145
153
 
146
154
  if new_safe_buffer
147
- new_safe_buffer.instance_eval { @html_safe = true }
155
+ new_safe_buffer.instance_variable_set :@html_safe, true
148
156
  end
149
157
 
150
158
  new_safe_buffer
@@ -174,14 +182,19 @@ module ActiveSupport #:nodoc:
174
182
  end
175
183
 
176
184
  def concat(value)
177
- if !html_safe? || value.html_safe?
178
- super(value)
179
- else
180
- super(ERB::Util.h(value))
181
- end
185
+ super(html_escape_interpolated_argument(value))
182
186
  end
183
187
  alias << concat
184
188
 
189
+ def prepend(value)
190
+ super(html_escape_interpolated_argument(value))
191
+ end
192
+
193
+ def prepend!(value)
194
+ ActiveSupport::Deprecation.deprecation_warning "ActiveSupport::SafeBuffer#prepend!", :prepend
195
+ prepend value
196
+ end
197
+
185
198
  def +(other)
186
199
  dup.concat(other)
187
200
  end
@@ -231,12 +244,18 @@ module ActiveSupport #:nodoc:
231
244
  private
232
245
 
233
246
  def html_escape_interpolated_argument(arg)
234
- (!html_safe? || arg.html_safe?) ? arg : ERB::Util.h(arg)
247
+ (!html_safe? || arg.html_safe?) ? arg :
248
+ arg.to_s.gsub(ERB::Util::HTML_ESCAPE_REGEXP, ERB::Util::HTML_ESCAPE)
235
249
  end
236
250
  end
237
251
  end
238
252
 
239
253
  class String
254
+ # Marks a string as trusted safe. It will be inserted into HTML with no
255
+ # additional escaping performed. It is your responsibilty to ensure that the
256
+ # string contains no malicious content. This method is equivalent to the
257
+ # `raw` helper in views. It is recommended that you use `sanitize` instead of
258
+ # this method. It should never be called on user input.
240
259
  def html_safe
241
260
  ActiveSupport::SafeBuffer.new(self)
242
261
  end
@@ -62,6 +62,13 @@ class Thread
62
62
  _locals.has_key?(key.to_sym)
63
63
  end
64
64
 
65
+ # Freezes the thread so that thread local variables cannot be set via
66
+ # Thread#thread_variable_set, nor can fiber local variables be set.
67
+ #
68
+ # me = Thread.current
69
+ # me.freeze
70
+ # me.thread_variable_set(:oliver, "a") #=> RuntimeError: can't modify frozen thread locals
71
+ # me[:oliver] = "a" #=> RuntimeError: can't modify frozen thread locals
65
72
  def freeze
66
73
  _locals.freeze
67
74
  super
@@ -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'
@@ -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,13 +63,21 @@ 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
- # <tt>:sec</tt>, <tt>:usec</tt>) reset cascadingly, so if only the hour is passed,
68
- # then minute, sec, and usec is set to 0. If the hour and minute is passed, then
69
- # sec and usec is set to 0. The +options+ parameter takes a hash with any of these
70
- # keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>,
71
- # <tt>:sec</tt>, <tt>:usec</tt>.
75
+ # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
76
+ # the hour is passed, then minute, sec, usec and nsec is set to 0. If the hour
77
+ # and minute is passed, then sec, usec and nsec is set to 0. The +options+
78
+ # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
79
+ # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>
80
+ # <tt>:nsec</tt>. Path either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
72
81
  #
73
82
  # Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0)
74
83
  # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0)
@@ -80,13 +89,20 @@ class Time
80
89
  new_hour = options.fetch(:hour, hour)
81
90
  new_min = options.fetch(:min, options[:hour] ? 0 : min)
82
91
  new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
83
- new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
92
+
93
+ if new_nsec = options[:nsec]
94
+ raise ArgumentError, "Can't change both :nsec and :usec at the same time: #{options.inspect}" if options[:usec]
95
+ new_usec = Rational(new_nsec, 1000)
96
+ else
97
+ new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
98
+ end
84
99
 
85
100
  if utc?
86
101
  ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
87
102
  elsif zone
88
103
  ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
89
104
  else
105
+ raise ArgumentError, 'argument out of range' if new_usec >= 1000000
90
106
  ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset)
91
107
  end
92
108
  end
@@ -96,6 +112,12 @@ class Time
96
112
  # takes a hash with any of these keys: <tt>:years</tt>, <tt>:months</tt>,
97
113
  # <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>, <tt>:minutes</tt>,
98
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
99
121
  def advance(options)
100
122
  unless options[:weeks].nil?
101
123
  options[:weeks], partial_weeks = options[:weeks].divmod(1)
@@ -235,7 +257,9 @@ class Time
235
257
  # can be chronologically compared with a Time
236
258
  def compare_with_coercion(other)
237
259
  # we're avoiding Time#to_datetime cause it's expensive
238
- if other.is_a?(Time)
260
+ if other.class == Time
261
+ compare_without_coercion(other)
262
+ elsif other.is_a?(Time)
239
263
  compare_without_coercion(other.to_time)
240
264
  else
241
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
@@ -20,7 +20,7 @@ class Time
20
20
  :iso8601 => lambda { |time| time.iso8601 }
21
21
  }
22
22
 
23
- # Converts to a formatted string. See DATE_FORMATS for builtin formats.
23
+ # Converts to a formatted string. See DATE_FORMATS for built-in formats.
24
24
  #
25
25
  # This method is aliased to <tt>to_s</tt>.
26
26
  #
@@ -30,6 +30,10 @@ module ActiveSupport #:nodoc:
30
30
  mattr_accessor :loaded
31
31
  self.loaded = Set.new
32
32
 
33
+ # Stack of files being loaded.
34
+ mattr_accessor :loading
35
+ self.loading = []
36
+
33
37
  # Should we load files or require them?
34
38
  mattr_accessor :mechanism
35
39
  self.mechanism = ENV['NO_RELOAD'] ? :require : :load
@@ -180,10 +184,11 @@ module ActiveSupport #:nodoc:
180
184
  Dependencies.load_missing_constant(from_mod, const_name)
181
185
  end
182
186
 
183
- # Dependencies assumes the name of the module reflects the nesting (unless
184
- # it can be proven that is not the case), and the path to the file that
185
- # defines the constant. Anonymous modules cannot follow these conventions
186
- # and we assume therefore the user wants to refer to a top-level constant.
187
+ # We assume that the name of the module reflects the nesting
188
+ # (unless it can be proven that is not the case) and the path to the file
189
+ # that defines the constant. Anonymous modules cannot follow these
190
+ # conventions and therefore we assume that the user wants to refer to a
191
+ # top-level constant.
187
192
  def guess_for_anonymous(const_name)
188
193
  if Object.const_defined?(const_name)
189
194
  raise NameError.new "#{const_name} cannot be autoloaded from an anonymous class or module", const_name
@@ -200,7 +205,10 @@ module ActiveSupport #:nodoc:
200
205
  # Object includes this module.
201
206
  module Loadable #:nodoc:
202
207
  def self.exclude_from(base)
203
- base.class_eval { define_method(:load, Kernel.instance_method(:load)) }
208
+ base.class_eval do
209
+ define_method(:load, Kernel.instance_method(:load))
210
+ private :load
211
+ end
204
212
  end
205
213
 
206
214
  def require_or_load(file_name)
@@ -236,18 +244,6 @@ module ActiveSupport #:nodoc:
236
244
  raise
237
245
  end
238
246
 
239
- def load(file, wrap = false)
240
- result = false
241
- load_dependency(file) { result = super }
242
- result
243
- end
244
-
245
- def require(file)
246
- result = false
247
- load_dependency(file) { result = super }
248
- result
249
- end
250
-
251
247
  # Mark the given constant as unloadable. Unloadable constants are removed
252
248
  # each time dependencies are cleared.
253
249
  #
@@ -264,6 +260,20 @@ module ActiveSupport #:nodoc:
264
260
  def unloadable(const_desc)
265
261
  Dependencies.mark_for_unload const_desc
266
262
  end
263
+
264
+ private
265
+
266
+ def load(file, wrap = false)
267
+ result = false
268
+ load_dependency(file) { result = super }
269
+ result
270
+ end
271
+
272
+ def require(file)
273
+ result = false
274
+ load_dependency(file) { result = super }
275
+ result
276
+ end
267
277
  end
268
278
 
269
279
  # Exception file-blaming.
@@ -316,6 +326,7 @@ module ActiveSupport #:nodoc:
316
326
  def clear
317
327
  log_call
318
328
  loaded.clear
329
+ loading.clear
319
330
  remove_unloadable_constants!
320
331
  end
321
332
 
@@ -328,6 +339,7 @@ module ActiveSupport #:nodoc:
328
339
  # Record that we've seen this file *before* loading it to avoid an
329
340
  # infinite loop with mutual dependencies.
330
341
  loaded << expanded
342
+ loading << expanded
331
343
 
332
344
  begin
333
345
  if load?
@@ -350,6 +362,8 @@ module ActiveSupport #:nodoc:
350
362
  rescue Exception
351
363
  loaded.delete expanded
352
364
  raise
365
+ ensure
366
+ loading.pop
353
367
  end
354
368
 
355
369
  # Record history *after* loading so first load gets warnings.
@@ -474,7 +488,7 @@ module ActiveSupport #:nodoc:
474
488
  expanded = File.expand_path(file_path)
475
489
  expanded.sub!(/\.rb\z/, '')
476
490
 
477
- if loaded.include?(expanded)
491
+ if loading.include?(expanded)
478
492
  raise "Circular dependency detected while autoloading constant #{qualified_name}"
479
493
  else
480
494
  require_or_load(expanded, qualified_name)
@@ -67,7 +67,7 @@ module ActiveSupport
67
67
  end
68
68
 
69
69
  def eager_load!
70
- @_autoloads.values.each { |file| require file }
70
+ @_autoloads.each_value { |file| require file }
71
71
  end
72
72
 
73
73
  def autoloads
@@ -32,7 +32,7 @@ module ActiveSupport
32
32
  # and the second is a library name
33
33
  #
34
34
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
35
- def initialize(deprecation_horizon = '4.2', gem_name = 'Rails')
35
+ def initialize(deprecation_horizon = '5.0', gem_name = 'Rails')
36
36
  self.gem_name = gem_name
37
37
  self.deprecation_horizon = deprecation_horizon
38
38
  # By default, warnings are not silenced and debugging is off.
@@ -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'
@@ -1,4 +1,3 @@
1
- require 'active_support/proxy_object'
2
1
  require 'active_support/core_ext/array/conversions'
3
2
  require 'active_support/core_ext/object/acts_like'
4
3
 
@@ -7,7 +6,7 @@ module ActiveSupport
7
6
  # Time#advance, respectively. It mainly supports the methods on Numeric.
8
7
  #
9
8
  # 1.month.ago # equivalent to Time.now.advance(months: -1)
10
- class Duration < ProxyObject
9
+ class Duration
11
10
  attr_accessor :value, :parts
12
11
 
13
12
  def initialize(value, parts) #:nodoc:
@@ -39,6 +38,10 @@ module ActiveSupport
39
38
  end
40
39
  alias :kind_of? :is_a?
41
40
 
41
+ def instance_of?(klass) # :nodoc:
42
+ Duration == klass || value.instance_of?(klass)
43
+ end
44
+
42
45
  # Returns +true+ if +other+ is also a Duration instance with the
43
46
  # same +value+, or if <tt>other == value</tt>.
44
47
  def ==(other)
@@ -49,8 +52,42 @@ module ActiveSupport
49
52
  end
50
53
  end
51
54
 
55
+ def to_s
56
+ @value.to_s
57
+ end
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
+
83
+ # Returns +true+ if +other+ is also a Duration instance, which has the
84
+ # same parts as this one.
52
85
  def eql?(other)
53
- other.is_a?(Duration) && self == other
86
+ Duration === other && other.value.eql?(value)
87
+ end
88
+
89
+ def hash
90
+ @value.hash
54
91
  end
55
92
 
56
93
  def self.===(other) #:nodoc:
@@ -85,6 +122,12 @@ module ActiveSupport
85
122
  to_i
86
123
  end
87
124
 
125
+ def respond_to_missing?(method, include_private=false) #:nodoc
126
+ @value.respond_to?(method, include_private)
127
+ end
128
+
129
+ delegate :<=>, to: :value
130
+
88
131
  protected
89
132
 
90
133
  def sum(sign, time = ::Time.current) #:nodoc:
@@ -105,8 +148,7 @@ module ActiveSupport
105
148
 
106
149
  # We define it as a workaround to Ruby 2.0.0-p353 bug.
107
150
  # For more information, check rails/rails#13055.
108
- # It should be dropped once a new Ruby patch-level
109
- # release after 2.0.0-p353 happens.
151
+ # Remove it when we drop support for 2.0.0-p353.
110
152
  def ===(other) #:nodoc:
111
153
  value === other
112
154
  end