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
@@ -7,7 +7,7 @@ module ActiveSupport
7
7
  @stubs = {}
8
8
  end
9
9
 
10
- def stub_object(object, method_name, return_value)
10
+ def stub_object(object, method_name, &block)
11
11
  key = [object.object_id, method_name]
12
12
 
13
13
  if stub = @stubs[key]
@@ -19,7 +19,7 @@ module ActiveSupport
19
19
  @stubs[key] = Stub.new(object, method_name, new_name)
20
20
 
21
21
  object.singleton_class.send :alias_method, new_name, method_name
22
- object.define_singleton_method(method_name) { return_value }
22
+ object.define_singleton_method(method_name, &block)
23
23
  end
24
24
 
25
25
  def unstub_all!
@@ -42,12 +42,13 @@ module ActiveSupport
42
42
  # Containing helpers that helps you test passage of time.
43
43
  module TimeHelpers
44
44
  # Changes current time to the time in the future or in the past by a given time difference by
45
- # stubbing +Time.now+ and +Date.today+.
45
+ # stubbing +Time.now+, +Date.today+, and +DateTime.now+.
46
46
  #
47
- # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
47
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
48
48
  # travel 1.day
49
- # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
50
- # Date.current # => Sun, 10 Nov 2013
49
+ # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
50
+ # Date.current # => Sun, 10 Nov 2013
51
+ # DateTime.current # => Sun, 10 Nov 2013 15:34:49 -0500
51
52
  #
52
53
  # This method also accepts a block, which will return the current time back to its original
53
54
  # state at the end of the block:
@@ -61,13 +62,14 @@ module ActiveSupport
61
62
  travel_to Time.now + duration, &block
62
63
  end
63
64
 
64
- # Changes current time to the given time by stubbing +Time.now+ and
65
- # +Date.today+ to return the time or date passed into this method.
65
+ # Changes current time to the given time by stubbing +Time.now+,
66
+ # +Date.today+, and +DateTime.now+ to return the time or date passed into this method.
66
67
  #
67
- # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
68
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
68
69
  # travel_to Time.new(2004, 11, 24, 01, 04, 44)
69
- # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
70
- # Date.current # => Wed, 24 Nov 2004
70
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
71
+ # Date.current # => Wed, 24 Nov 2004
72
+ # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
71
73
  #
72
74
  # Dates are taken as their timestamp at the beginning of the day in the
73
75
  # application time zone. <tt>Time.current</tt> returns said timestamp,
@@ -78,6 +80,10 @@ module ActiveSupport
78
80
  # or <tt>Date.today</tt>, in order to honor the application time zone
79
81
  # please always use <tt>Time.current</tt> and <tt>Date.current</tt>.)
80
82
  #
83
+ # Note that the usec for the time passed will be set to 0 to prevent rounding
84
+ # errors with external services, like MySQL (which will round instead of floor,
85
+ # leading to off-by-one-second errors).
86
+ #
81
87
  # This method also accepts a block, which will return the current time back to its original
82
88
  # state at the end of the block:
83
89
  #
@@ -86,19 +92,20 @@ module ActiveSupport
86
92
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
87
93
  # end
88
94
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
89
- def travel_to(date_or_time, &block)
95
+ def travel_to(date_or_time)
90
96
  if date_or_time.is_a?(Date) && !date_or_time.is_a?(DateTime)
91
97
  now = date_or_time.midnight.to_time
92
98
  else
93
- now = date_or_time.to_time
99
+ now = date_or_time.to_time.change(usec: 0)
94
100
  end
95
101
 
96
- simple_stubs.stub_object(Time, :now, now)
97
- simple_stubs.stub_object(Date, :today, now.to_date)
102
+ simple_stubs.stub_object(Time, :now) { at(now.to_i) }
103
+ simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
104
+ simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
98
105
 
99
106
  if block_given?
100
107
  begin
101
- block.call
108
+ yield
102
109
  ensure
103
110
  travel_back
104
111
  end
@@ -1,5 +1,3 @@
1
- require 'active_support'
2
-
3
1
  module ActiveSupport
4
2
  autoload :Duration, 'active_support/duration'
5
3
  autoload :TimeWithZone, 'active_support/time_with_zone'
@@ -1,5 +1,6 @@
1
1
  require 'active_support/values/time_zone'
2
2
  require 'active_support/core_ext/object/acts_like'
3
+ require 'active_support/core_ext/date_and_time/compatibility'
3
4
 
4
5
  module ActiveSupport
5
6
  # A Time-like class that can represent a time in any time zone. Necessary
@@ -40,20 +41,21 @@ module ActiveSupport
40
41
  'Time'
41
42
  end
42
43
 
43
- include Comparable
44
+ include Comparable, DateAndTime::Compatibility
44
45
  attr_reader :time_zone
45
46
 
46
47
  def initialize(utc_time, time_zone, local_time = nil, period = nil)
47
- @utc, @time_zone, @time = utc_time, time_zone, local_time
48
+ @utc = utc_time ? transfer_time_values_to_utc_constructor(utc_time) : nil
49
+ @time_zone, @time = time_zone, local_time
48
50
  @period = @utc ? period : get_period_and_ensure_valid_local_time(period)
49
51
  end
50
52
 
51
- # Returns a Time or DateTime instance that represents the time in +time_zone+.
53
+ # Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
52
54
  def time
53
55
  @time ||= period.to_local(@utc)
54
56
  end
55
57
 
56
- # Returns a Time or DateTime instance that represents the time in UTC.
58
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
57
59
  def utc
58
60
  @utc ||= period.to_utc(@time)
59
61
  end
@@ -73,10 +75,9 @@ module ActiveSupport
73
75
  utc.in_time_zone(new_zone)
74
76
  end
75
77
 
76
- # Returns a <tt>Time.local()</tt> instance of the simultaneous time in your
77
- # system's <tt>ENV['TZ']</tt> zone.
78
- def localtime
79
- utc.respond_to?(:getlocal) ? utc.getlocal : utc.to_time.getlocal
78
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the system timezone.
79
+ def localtime(utc_offset = nil)
80
+ utc.getlocal(utc_offset)
80
81
  end
81
82
  alias_method :getlocal, :localtime
82
83
 
@@ -160,7 +161,11 @@ module ActiveSupport
160
161
  end
161
162
  end
162
163
 
163
- def encode_with(coder)
164
+ def init_with(coder) #:nodoc:
165
+ initialize(coder['utc'], coder['zone'], coder['time'])
166
+ end
167
+
168
+ def encode_with(coder) #:nodoc:
164
169
  if coder.respond_to?(:represent_object)
165
170
  coder.represent_object(nil, utc)
166
171
  else
@@ -185,8 +190,11 @@ module ActiveSupport
185
190
  end
186
191
  alias_method :rfc822, :rfc2822
187
192
 
188
- # <tt>:db</tt> format outputs time in UTC; all others output time in local.
189
- # Uses TimeWithZone's +strftime+, so <tt>%Z</tt> and <tt>%z</tt> work correctly.
193
+ # Returns a string of the object's date and time.
194
+ # Accepts an optional <tt>format</tt>:
195
+ # * <tt>:default</tt> - default value, mimics Ruby 1.9 Time#to_s format.
196
+ # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_formatted_s(:db).
197
+ # * Any key in <tt>Time::DATE_FORMATS</tt> can be used. See active_support/core_ext/time/conversions.rb.
190
198
  def to_s(format = :default)
191
199
  if format == :db
192
200
  utc.to_s(format)
@@ -198,15 +206,11 @@ module ActiveSupport
198
206
  end
199
207
  alias_method :to_formatted_s, :to_s
200
208
 
201
- # Replaces <tt>%Z</tt> and <tt>%z</tt> directives with +zone+ and
202
- # +formatted_offset+, respectively, before passing to Time#strftime, so
203
- # that zone information is correct
209
+ # Replaces <tt>%Z</tt> directive with +zone before passing to Time#strftime,
210
+ # so that zone information is correct.
204
211
  def strftime(format)
205
- format = format.gsub('%Z', zone)
206
- .gsub('%z', formatted_offset(false))
207
- .gsub('%:z', formatted_offset(true))
208
- .gsub('%::z', formatted_offset(true) + ":00")
209
- time.strftime(format)
212
+ format = format.gsub(/((?:\A|[^%])(?:%%)*)%Z/, "\\1#{zone}")
213
+ getlocal(utc_offset).strftime(format)
210
214
  end
211
215
 
212
216
  # Use the time in UTC for comparisons.
@@ -237,7 +241,7 @@ module ActiveSupport
237
241
  end
238
242
 
239
243
  def eql?(other)
240
- utc.eql?(other)
244
+ other.eql?(utc)
241
245
  end
242
246
 
243
247
  def hash
@@ -259,7 +263,7 @@ module ActiveSupport
259
263
  # If we're subtracting a Duration of variable length (i.e., years, months, days), move backwards from #time,
260
264
  # otherwise move backwards #utc, for accuracy when moving across DST boundaries
261
265
  if other.acts_like?(:time)
262
- utc.to_f - other.to_f
266
+ to_time - other.to_time
263
267
  elsif duration_of_variable_length?(other)
264
268
  method_missing(:-, other)
265
269
  else
@@ -277,6 +281,7 @@ module ActiveSupport
277
281
  utc.since(other).in_time_zone(time_zone)
278
282
  end
279
283
  end
284
+ alias_method :in, :since
280
285
 
281
286
  def ago(other)
282
287
  since(-other)
@@ -317,13 +322,19 @@ module ActiveSupport
317
322
  utc.to_r
318
323
  end
319
324
 
320
- # Return an instance of Time in the system timezone.
321
- def to_time
322
- utc.to_time
325
+ def to_datetime
326
+ @to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
323
327
  end
324
328
 
325
- def to_datetime
326
- utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
329
+ # Returns an instance of +Time+, either with the same UTC offset
330
+ # as +self+ or in the local system timezone depending on the setting
331
+ # of +ActiveSupport.to_time_preserves_timezone+.
332
+ def to_time
333
+ if preserve_timezone
334
+ @to_time_with_instance_offset ||= getlocal(utc_offset)
335
+ else
336
+ @to_time_with_system_offset ||= getlocal
337
+ end
327
338
  end
328
339
 
329
340
  # So that +self+ <tt>acts_like?(:time)</tt>.
@@ -338,7 +349,8 @@ module ActiveSupport
338
349
  alias_method :kind_of?, :is_a?
339
350
 
340
351
  def freeze
341
- period; utc; time # preload instance variables before freezing
352
+ # preload instance variables before freezing
353
+ period; utc; time; to_datetime; to_time
342
354
  super
343
355
  end
344
356
 
@@ -350,10 +362,17 @@ module ActiveSupport
350
362
  initialize(variables[0].utc, ::Time.find_zone(variables[1]), variables[2].utc)
351
363
  end
352
364
 
365
+ # respond_to_missing? is not called in some cases, such as when type conversion is
366
+ # performed with Kernel#String
367
+ def respond_to?(sym, include_priv = false)
368
+ # ensure that we're not going to throw and rescue from NoMethodError in method_missing which is slow
369
+ return false if sym.to_sym == :to_str
370
+ super
371
+ end
372
+
353
373
  # Ensure proxy class responds to all methods that underlying time instance
354
374
  # responds to.
355
375
  def respond_to_missing?(sym, include_priv)
356
- # consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime
357
376
  return false if sym.to_sym == :acts_like_date?
358
377
  time.respond_to?(sym, include_priv)
359
378
  end
@@ -381,7 +400,7 @@ module ActiveSupport
381
400
  end
382
401
 
383
402
  def transfer_time_values_to_utc_constructor(time)
384
- ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec, Rational(time.nsec, 1000))
403
+ ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec + time.subsec)
385
404
  end
386
405
 
387
406
  def duration_of_variable_length?(obj)
@@ -187,20 +187,76 @@ module ActiveSupport
187
187
  }
188
188
 
189
189
  UTC_OFFSET_WITH_COLON = '%s%02d:%02d'
190
- UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.sub(':', '')
190
+ UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(':', '')
191
191
 
192
192
  @lazy_zones_map = ThreadSafe::Cache.new
193
193
 
194
- # Assumes self represents an offset from UTC in seconds (as returned from
195
- # Time#utc_offset) and turns this into an +HH:MM formatted string.
196
- #
197
- # TimeZone.seconds_to_utc_offset(-21_600) # => "-06:00"
198
- def self.seconds_to_utc_offset(seconds, colon = true)
199
- format = colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON
200
- sign = (seconds < 0 ? '-' : '+')
201
- hours = seconds.abs / 3600
202
- minutes = (seconds.abs % 3600) / 60
203
- format % [sign, hours, minutes]
194
+ class << self
195
+ # Assumes self represents an offset from UTC in seconds (as returned from
196
+ # Time#utc_offset) and turns this into an +HH:MM formatted string.
197
+ #
198
+ # TimeZone.seconds_to_utc_offset(-21_600) # => "-06:00"
199
+ def seconds_to_utc_offset(seconds, colon = true)
200
+ format = colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON
201
+ sign = (seconds < 0 ? '-' : '+')
202
+ hours = seconds.abs / 3600
203
+ minutes = (seconds.abs % 3600) / 60
204
+ format % [sign, hours, minutes]
205
+ end
206
+
207
+ def find_tzinfo(name)
208
+ TZInfo::TimezoneProxy.new(MAPPING[name] || name)
209
+ end
210
+
211
+ alias_method :create, :new
212
+
213
+ # Returns a TimeZone instance with the given name, or +nil+ if no
214
+ # such TimeZone instance exists. (This exists to support the use of
215
+ # this class with the +composed_of+ macro.)
216
+ def new(name)
217
+ self[name]
218
+ end
219
+
220
+ # Returns an array of all TimeZone objects. There are multiple
221
+ # TimeZone objects per time zone, in many cases, to make it easier
222
+ # for users to find their own time zone.
223
+ def all
224
+ @zones ||= zones_map.values.sort
225
+ end
226
+
227
+ def zones_map #:nodoc:
228
+ @zones_map ||= begin
229
+ MAPPING.each_key {|place| self[place]} # load all the zones
230
+ @lazy_zones_map
231
+ end
232
+ end
233
+
234
+ # Locate a specific time zone object. If the argument is a string, it
235
+ # is interpreted to mean the name of the timezone to locate. If it is a
236
+ # numeric value it is either the hour offset, or the second offset, of the
237
+ # timezone to find. (The first one with that offset will be returned.)
238
+ # Returns +nil+ if no such time zone is known to the system.
239
+ def [](arg)
240
+ case arg
241
+ when String
242
+ begin
243
+ @lazy_zones_map[arg] ||= create(arg).tap { |tz| tz.utc_offset }
244
+ rescue TZInfo::InvalidTimezoneIdentifier
245
+ nil
246
+ end
247
+ when Numeric, ActiveSupport::Duration
248
+ arg *= 3600 if arg.abs <= 13
249
+ all.find { |z| z.utc_offset == arg.to_i }
250
+ else
251
+ raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}"
252
+ end
253
+ end
254
+
255
+ # A convenience method for returning a collection of TimeZone objects
256
+ # for time zones in the USA.
257
+ def us_zones
258
+ @us_zones ||= all.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ }
259
+ end
204
260
  end
205
261
 
206
262
  include Comparable
@@ -215,7 +271,10 @@ module ActiveSupport
215
271
  @name = name
216
272
  @utc_offset = utc_offset
217
273
  @tzinfo = tzinfo || TimeZone.find_tzinfo(name)
218
- @current_period = nil
274
+ end
275
+
276
+ def init_with(coder) #:nodoc:
277
+ initialize(coder['name'])
219
278
  end
220
279
 
221
280
  # Returns the offset of this time zone from UTC in seconds.
@@ -223,8 +282,7 @@ module ActiveSupport
223
282
  if @utc_offset
224
283
  @utc_offset
225
284
  else
226
- @current_period ||= tzinfo.try(:current_period)
227
- @current_period.try(:utc_offset)
285
+ tzinfo.current_period.utc_offset if tzinfo && tzinfo.current_period
228
286
  end
229
287
  end
230
288
 
@@ -285,6 +343,11 @@ module ActiveSupport
285
343
  #
286
344
  # Time.zone.now # => Fri, 31 Dec 1999 14:00:00 HST -10:00
287
345
  # Time.zone.parse('22:30:00') # => Fri, 31 Dec 1999 22:30:00 HST -10:00
346
+ #
347
+ # However, if the date component is not provided, but any other upper
348
+ # components are supplied, then the day of the month defaults to 1:
349
+ #
350
+ # Time.zone.parse('Mar 2000') # => Wed, 01 Mar 2000 00:00:00 HST -10:00
288
351
  def parse(str, now=now())
289
352
  parts = Date._parse(str, false)
290
353
  return if parts.empty?
@@ -292,7 +355,7 @@ module ActiveSupport
292
355
  time = Time.new(
293
356
  parts.fetch(:year, now.year),
294
357
  parts.fetch(:mon, now.month),
295
- parts.fetch(:mday, now.day),
358
+ parts.fetch(:mday, parts[:year] || parts[:mon] ? 1 : now.day),
296
359
  parts.fetch(:hour, 0),
297
360
  parts.fetch(:min, 0),
298
361
  parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
@@ -359,66 +422,9 @@ module ActiveSupport
359
422
  tzinfo.periods_for_local(time)
360
423
  end
361
424
 
362
- def self.find_tzinfo(name)
363
- TZInfo::TimezoneProxy.new(MAPPING[name] || name)
364
- end
365
-
366
- class << self
367
- alias_method :create, :new
368
-
369
- # Returns a TimeZone instance with the given name, or +nil+ if no
370
- # such TimeZone instance exists. (This exists to support the use of
371
- # this class with the +composed_of+ macro.)
372
- def new(name)
373
- self[name]
374
- end
375
-
376
- # Returns an array of all TimeZone objects. There are multiple
377
- # TimeZone objects per time zone, in many cases, to make it easier
378
- # for users to find their own time zone.
379
- def all
380
- @zones ||= zones_map.values.sort
381
- end
382
-
383
- def zones_map
384
- @zones_map ||= begin
385
- MAPPING.each_key {|place| self[place]} # load all the zones
386
- @lazy_zones_map
387
- end
388
- end
389
-
390
- # Locate a specific time zone object. If the argument is a string, it
391
- # is interpreted to mean the name of the timezone to locate. If it is a
392
- # numeric value it is either the hour offset, or the second offset, of the
393
- # timezone to find. (The first one with that offset will be returned.)
394
- # Returns +nil+ if no such time zone is known to the system.
395
- def [](arg)
396
- case arg
397
- when String
398
- begin
399
- @lazy_zones_map[arg] ||= create(arg).tap { |tz| tz.utc_offset }
400
- rescue TZInfo::InvalidTimezoneIdentifier
401
- nil
402
- end
403
- when Numeric, ActiveSupport::Duration
404
- arg *= 3600 if arg.abs <= 13
405
- all.find { |z| z.utc_offset == arg.to_i }
406
- else
407
- raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}"
408
- end
409
- end
410
-
411
- # A convenience method for returning a collection of TimeZone objects
412
- # for time zones in the USA.
413
- def us_zones
414
- @us_zones ||= all.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ }
415
- end
416
- end
417
-
418
425
  private
419
-
420
- def time_now
421
- Time.now
422
- end
426
+ def time_now
427
+ Time.now
428
+ end
423
429
  end
424
430
  end