activesupport 4.2.11.3 → 5.0.0.beta1

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 (174) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +309 -485
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/active_support.rb +8 -15
  6. data/lib/active_support/array_inquirer.rb +44 -0
  7. data/lib/active_support/backtrace_cleaner.rb +1 -1
  8. data/lib/active_support/cache.rb +59 -72
  9. data/lib/active_support/cache/file_store.rb +27 -19
  10. data/lib/active_support/cache/mem_cache_store.rb +71 -60
  11. data/lib/active_support/cache/memory_store.rb +16 -21
  12. data/lib/active_support/cache/null_store.rb +1 -4
  13. data/lib/active_support/cache/strategy/local_cache.rb +31 -20
  14. data/lib/active_support/callbacks.rb +107 -111
  15. data/lib/active_support/concern.rb +1 -1
  16. data/lib/active_support/concurrency/latch.rb +7 -15
  17. data/lib/active_support/concurrency/share_lock.rb +142 -0
  18. data/lib/active_support/configurable.rb +1 -0
  19. data/lib/active_support/core_ext.rb +2 -1
  20. data/lib/active_support/core_ext/array.rb +1 -0
  21. data/lib/active_support/core_ext/array/access.rb +13 -1
  22. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  23. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  24. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  26. data/lib/active_support/core_ext/class.rb +0 -1
  27. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  28. data/lib/active_support/core_ext/class/subclasses.rb +5 -2
  29. data/lib/active_support/core_ext/date.rb +1 -1
  30. data/lib/active_support/core_ext/date/blank.rb +12 -0
  31. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  32. data/lib/active_support/core_ext/date/conversions.rb +3 -3
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +93 -27
  34. data/lib/active_support/core_ext/date_and_time/zones.rb +1 -2
  35. data/lib/active_support/core_ext/date_time.rb +1 -1
  36. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  37. data/lib/active_support/core_ext/date_time/calculations.rb +7 -23
  38. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  39. data/lib/active_support/core_ext/enumerable.rb +27 -17
  40. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  41. data/lib/active_support/core_ext/hash/compact.rb +15 -19
  42. data/lib/active_support/core_ext/hash/conversions.rb +21 -2
  43. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
  44. data/lib/active_support/core_ext/hash/except.rb +9 -8
  45. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  46. data/lib/active_support/core_ext/hash/keys.rb +22 -18
  47. data/lib/active_support/core_ext/hash/slice.rb +1 -1
  48. data/lib/active_support/core_ext/hash/transform_values.rb +13 -7
  49. data/lib/active_support/core_ext/integer/time.rb +1 -1
  50. data/lib/active_support/core_ext/kernel.rb +0 -1
  51. data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
  52. data/lib/active_support/core_ext/kernel/reporting.rb +0 -84
  53. data/lib/active_support/core_ext/load_error.rb +4 -2
  54. data/lib/active_support/core_ext/marshal.rb +8 -13
  55. data/lib/active_support/core_ext/module.rb +1 -0
  56. data/lib/active_support/core_ext/module/aliasing.rb +6 -1
  57. data/lib/active_support/core_ext/module/anonymous.rb +10 -1
  58. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  59. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -7
  60. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  61. data/lib/active_support/core_ext/module/concerning.rb +4 -4
  62. data/lib/active_support/core_ext/module/delegation.rb +7 -14
  63. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -13
  64. data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
  65. data/lib/active_support/core_ext/module/remove_method.rb +23 -0
  66. data/lib/active_support/core_ext/name_error.rb +15 -2
  67. data/lib/active_support/core_ext/numeric.rb +1 -0
  68. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  69. data/lib/active_support/core_ext/numeric/conversions.rb +12 -23
  70. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  71. data/lib/active_support/core_ext/numeric/time.rb +20 -0
  72. data/lib/active_support/core_ext/object.rb +0 -1
  73. data/lib/active_support/core_ext/object/blank.rb +11 -2
  74. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  75. data/lib/active_support/core_ext/object/duplicable.rb +39 -70
  76. data/lib/active_support/core_ext/object/inclusion.rb +2 -2
  77. data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
  78. data/lib/active_support/core_ext/object/json.rb +9 -7
  79. data/lib/active_support/core_ext/object/to_query.rb +1 -1
  80. data/lib/active_support/core_ext/object/try.rb +67 -21
  81. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  82. data/lib/active_support/core_ext/range/conversions.rb +18 -6
  83. data/lib/active_support/core_ext/range/each.rb +16 -18
  84. data/lib/active_support/core_ext/range/include_range.rb +20 -20
  85. data/lib/active_support/core_ext/securerandom.rb +23 -0
  86. data/lib/active_support/core_ext/string/access.rb +1 -1
  87. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  88. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  89. data/lib/active_support/core_ext/string/filters.rb +1 -2
  90. data/lib/active_support/core_ext/string/inflections.rb +23 -5
  91. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  92. data/lib/active_support/core_ext/string/output_safety.rb +8 -9
  93. data/lib/active_support/core_ext/string/strip.rb +3 -6
  94. data/lib/active_support/core_ext/struct.rb +3 -6
  95. data/lib/active_support/core_ext/time.rb +0 -2
  96. data/lib/active_support/core_ext/time/calculations.rb +18 -16
  97. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  98. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  99. data/lib/active_support/core_ext/time/zones.rb +19 -3
  100. data/lib/active_support/core_ext/uri.rb +1 -3
  101. data/lib/active_support/dependencies.rb +79 -44
  102. data/lib/active_support/dependencies/interlock.rb +47 -0
  103. data/lib/active_support/deprecation/behaviors.rb +12 -0
  104. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  105. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  106. data/lib/active_support/deprecation/reporting.rb +13 -2
  107. data/lib/active_support/duration.rb +5 -8
  108. data/lib/active_support/evented_file_update_checker.rb +150 -0
  109. data/lib/active_support/file_update_checker.rb +1 -1
  110. data/lib/active_support/gem_version.rb +5 -5
  111. data/lib/active_support/hash_with_indifferent_access.rb +15 -17
  112. data/lib/active_support/i18n_railtie.rb +25 -4
  113. data/lib/active_support/inflector/inflections.rb +36 -5
  114. data/lib/active_support/inflector/methods.rb +87 -89
  115. data/lib/active_support/inflector/transliterate.rb +36 -21
  116. data/lib/active_support/json/decoding.rb +2 -8
  117. data/lib/active_support/json/encoding.rb +0 -50
  118. data/lib/active_support/key_generator.rb +4 -4
  119. data/lib/active_support/log_subscriber.rb +1 -1
  120. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  121. data/lib/active_support/logger.rb +4 -52
  122. data/lib/active_support/logger_silence.rb +3 -5
  123. data/lib/active_support/message_encryptor.rb +4 -11
  124. data/lib/active_support/message_verifier.rb +64 -8
  125. data/lib/active_support/multibyte/chars.rb +12 -3
  126. data/lib/active_support/multibyte/unicode.rb +6 -8
  127. data/lib/active_support/notifications.rb +2 -2
  128. data/lib/active_support/notifications/fanout.rb +5 -5
  129. data/lib/active_support/notifications/instrumenter.rb +19 -2
  130. data/lib/active_support/number_helper.rb +21 -15
  131. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -4
  132. data/lib/active_support/number_helper/number_to_delimited_converter.rb +7 -2
  133. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  134. data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -1
  135. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  136. data/lib/active_support/number_helper/number_to_rounded_converter.rb +28 -25
  137. data/lib/active_support/ordered_options.rb +15 -1
  138. data/lib/active_support/per_thread_registry.rb +3 -0
  139. data/lib/active_support/rails.rb +2 -2
  140. data/lib/active_support/railtie.rb +6 -1
  141. data/lib/active_support/rescuable.rb +4 -4
  142. data/lib/active_support/security_utils.rb +0 -7
  143. data/lib/active_support/string_inquirer.rb +1 -1
  144. data/lib/active_support/subscriber.rb +5 -10
  145. data/lib/active_support/tagged_logging.rb +3 -1
  146. data/lib/active_support/test_case.rb +13 -25
  147. data/lib/active_support/testing/assertions.rb +15 -13
  148. data/lib/active_support/testing/autorun.rb +8 -1
  149. data/lib/active_support/testing/composite_filter.rb +54 -0
  150. data/lib/active_support/testing/deprecation.rb +9 -8
  151. data/lib/active_support/testing/file_fixtures.rb +34 -0
  152. data/lib/active_support/testing/isolation.rb +22 -8
  153. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  154. data/lib/active_support/testing/stream.rb +42 -0
  155. data/lib/active_support/testing/time_helpers.rb +6 -6
  156. data/lib/active_support/time_with_zone.rb +135 -53
  157. data/lib/active_support/values/time_zone.rb +80 -46
  158. data/lib/active_support/values/unicode_tables.dat +0 -0
  159. data/lib/active_support/xml_mini.rb +15 -30
  160. data/lib/active_support/xml_mini/jdom.rb +1 -1
  161. data/lib/active_support/xml_mini/libxml.rb +5 -3
  162. data/lib/active_support/xml_mini/libxmlsax.rb +4 -1
  163. data/lib/active_support/xml_mini/nokogiri.rb +5 -3
  164. data/lib/active_support/xml_mini/nokogirisax.rb +3 -1
  165. data/lib/active_support/xml_mini/rexml.rb +3 -1
  166. metadata +57 -21
  167. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  168. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  169. data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -15
  170. data/lib/active_support/core_ext/date_time/compatibility.rb +0 -16
  171. data/lib/active_support/core_ext/object/itself.rb +0 -15
  172. data/lib/active_support/core_ext/thread.rb +0 -86
  173. data/lib/active_support/core_ext/time/compatibility.rb +0 -14
  174. data/lib/active_support/logger_thread_safe_level.rb +0 -32
@@ -0,0 +1,34 @@
1
+ module ActiveSupport
2
+ module Testing
3
+ # Adds simple access to sample files called file fixtures.
4
+ # File fixtures are normal files stored in
5
+ # <tt>ActiveSupport::TestCase.file_fixture_path</tt>.
6
+ #
7
+ # File fixtures are represented as +Pathname+ objects.
8
+ # This makes it easy to extract specific information:
9
+ #
10
+ # file_fixture("example.txt").read # get the file's content
11
+ # file_fixture("example.mp3").size # get the file size
12
+ module FileFixtures
13
+ extend ActiveSupport::Concern
14
+
15
+ included do
16
+ class_attribute :file_fixture_path, instance_writer: false
17
+ end
18
+
19
+ # Returns a +Pathname+ to the fixture file named +fixture_name+.
20
+ #
21
+ # Raises +ArgumentError+ if +fixture_name+ can't be found.
22
+ def file_fixture(fixture_name)
23
+ path = Pathname.new(File.join(file_fixture_path, fixture_name))
24
+
25
+ if path.exist?
26
+ path
27
+ else
28
+ msg = "the directory '%s' does not contain a file named '%s'"
29
+ raise ArgumentError, msg % [file_fixture_path, fixture_name]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,5 +1,3 @@
1
- require 'rbconfig'
2
-
3
1
  module ActiveSupport
4
2
  module Testing
5
3
  module Isolation
@@ -12,7 +10,7 @@ module ActiveSupport
12
10
  end
13
11
 
14
12
  def self.forking_env?
15
- !ENV["NO_FORK"] && ((RbConfig::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/))
13
+ !ENV["NO_FORK"] && Process.respond_to?(:fork)
16
14
  end
17
15
 
18
16
  @@class_setup_mutex = Mutex.new
@@ -43,7 +41,23 @@ module ActiveSupport
43
41
  pid = fork do
44
42
  read.close
45
43
  yield
46
- write.puts [Marshal.dump(self.dup)].pack("m")
44
+ begin
45
+ if error?
46
+ failures.map! { |e|
47
+ begin
48
+ Marshal.dump e
49
+ e
50
+ rescue TypeError
51
+ ex = Exception.new e.message
52
+ ex.set_backtrace e.backtrace
53
+ Minitest::UnexpectedError.new ex
54
+ end
55
+ }
56
+ end
57
+ result = Marshal.dump(self.dup)
58
+ end
59
+
60
+ write.puts [result].pack("m")
47
61
  exit!
48
62
  end
49
63
 
@@ -71,17 +85,17 @@ module ActiveSupport
71
85
  else
72
86
  Tempfile.open("isolation") do |tmpfile|
73
87
  env = {
74
- ISOLATION_TEST: self.class.name,
75
- ISOLATION_OUTPUT: tmpfile.path
88
+ 'ISOLATION_TEST' => self.class.name,
89
+ 'ISOLATION_OUTPUT' => tmpfile.path
76
90
  }
77
91
 
78
92
  load_paths = $-I.map {|p| "-I\"#{File.expand_path(p)}\"" }.join(" ")
79
93
  orig_args = ORIG_ARGV.join(" ")
80
94
  test_opts = "-n#{self.class.name}##{self.name}"
81
- command = "#{Gem.ruby} #{load_paths} #{$0} #{orig_args} #{test_opts}"
95
+ command = "#{Gem.ruby} #{load_paths} #{$0} '#{orig_args}' #{test_opts}"
82
96
 
83
97
  # IO.popen lets us pass env in a cross-platform way
84
- child = IO.popen([env, command])
98
+ child = IO.popen(env, command)
85
99
 
86
100
  begin
87
101
  Process.wait(child.pid)
@@ -0,0 +1,41 @@
1
+ require 'minitest/mock'
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module MethodCallAssertions # :nodoc:
6
+ private
7
+ def assert_called(object, method_name, message = nil, times: 1, returns: nil)
8
+ times_called = 0
9
+
10
+ object.stub(method_name, proc { times_called += 1; returns }) { yield }
11
+
12
+ error = "Expected #{method_name} to be called #{times} times, " \
13
+ "but was called #{times_called} times"
14
+ error = "#{message}.\n#{error}" if message
15
+ assert_equal times, times_called, error
16
+ end
17
+
18
+ def assert_called_with(object, method_name, args = [], returns: nil)
19
+ mock = Minitest::Mock.new
20
+
21
+ if args.all? { |arg| arg.is_a?(Array) }
22
+ args.each { |arg| mock.expect(:call, returns, arg) }
23
+ else
24
+ mock.expect(:call, returns, args)
25
+ end
26
+
27
+ object.stub(method_name, mock) { yield }
28
+
29
+ mock.verify
30
+ end
31
+
32
+ def assert_not_called(object, method_name, message = nil, &block)
33
+ assert_called(object, method_name, message, times: 0, &block)
34
+ end
35
+
36
+ def stub_any_instance(klass, instance: klass.new)
37
+ klass.stub(:new, instance) { yield instance }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,42 @@
1
+ module ActiveSupport
2
+ module Testing
3
+ module Stream #:nodoc:
4
+ private
5
+
6
+ def silence_stream(stream)
7
+ old_stream = stream.dup
8
+ stream.reopen(IO::NULL)
9
+ stream.sync = true
10
+ yield
11
+ ensure
12
+ stream.reopen(old_stream)
13
+ old_stream.close
14
+ end
15
+
16
+ def quietly
17
+ silence_stream(STDOUT) do
18
+ silence_stream(STDERR) do
19
+ yield
20
+ end
21
+ end
22
+ end
23
+
24
+ def capture(stream)
25
+ stream = stream.to_s
26
+ captured_stream = Tempfile.new(stream)
27
+ stream_io = eval("$#{stream}")
28
+ origin_stream = stream_io.dup
29
+ stream_io.reopen(captured_stream)
30
+
31
+ yield
32
+
33
+ stream_io.rewind
34
+ return captured_stream.read
35
+ ensure
36
+ captured_stream.close
37
+ captured_stream.unlink
38
+ stream_io.reopen(origin_stream)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -7,7 +7,7 @@ module ActiveSupport
7
7
  @stubs = {}
8
8
  end
9
9
 
10
- def stub_object(object, method_name, &block)
10
+ def stub_object(object, method_name, return_value)
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, &block)
22
+ object.define_singleton_method(method_name) { return_value }
23
23
  end
24
24
 
25
25
  def unstub_all!
@@ -39,7 +39,7 @@ module ActiveSupport
39
39
  end
40
40
  end
41
41
 
42
- # Containing helpers that helps you test passage of time.
42
+ # Contains helpers that help 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
45
  # stubbing +Time.now+, +Date.today+, and +DateTime.now+.
@@ -99,9 +99,9 @@ module ActiveSupport
99
99
  now = date_or_time.to_time.change(usec: 0)
100
100
  end
101
101
 
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)) }
102
+ simple_stubs.stub_object(Time, :now, now)
103
+ simple_stubs.stub_object(Date, :today, now.to_date)
104
+ simple_stubs.stub_object(DateTime, :now, now.to_datetime)
105
105
 
106
106
  if block_given?
107
107
  begin
@@ -1,6 +1,6 @@
1
+ require 'active_support/duration'
1
2
  require 'active_support/values/time_zone'
2
3
  require 'active_support/core_ext/object/acts_like'
3
- require 'active_support/core_ext/date_and_time/compatibility'
4
4
 
5
5
  module ActiveSupport
6
6
  # A Time-like class that can represent a time in any time zone. Necessary
@@ -14,7 +14,7 @@ module ActiveSupport
14
14
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
15
15
  # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
16
16
  # Time.zone.parse('2007-02-10 15:30:45') # => Sat, 10 Feb 2007 15:30:45 EST -05:00
17
- # Time.zone.at(1170361845) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
17
+ # Time.zone.at(1171139445) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
18
18
  # Time.zone.now # => Sun, 18 May 2008 13:07:55 EDT -04:00
19
19
  # Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45 EST -05:00
20
20
  #
@@ -41,21 +41,23 @@ module ActiveSupport
41
41
  'Time'
42
42
  end
43
43
 
44
- include Comparable, DateAndTime::Compatibility
44
+ PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N".freeze }
45
+ PRECISIONS[0] = '%FT%T'.freeze
46
+
47
+ include Comparable
45
48
  attr_reader :time_zone
46
49
 
47
50
  def initialize(utc_time, time_zone, local_time = nil, period = nil)
48
- @utc = utc_time ? transfer_time_values_to_utc_constructor(utc_time) : nil
49
- @time_zone, @time = time_zone, local_time
51
+ @utc, @time_zone, @time = utc_time, time_zone, local_time
50
52
  @period = @utc ? period : get_period_and_ensure_valid_local_time(period)
51
53
  end
52
54
 
53
- # Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
55
+ # Returns a Time or DateTime instance that represents the time in +time_zone+.
54
56
  def time
55
57
  @time ||= period.to_local(@utc)
56
58
  end
57
59
 
58
- # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
60
+ # Returns a Time or DateTime instance that represents the time in UTC.
59
61
  def utc
60
62
  @utc ||= period.to_utc(@time)
61
63
  end
@@ -75,9 +77,10 @@ module ActiveSupport
75
77
  utc.in_time_zone(new_zone)
76
78
  end
77
79
 
78
- # Returns a <tt>Time</tt> instance of the simultaneous time in the system timezone.
80
+ # Returns a <tt>Time.local()</tt> instance of the simultaneous time in your
81
+ # system's <tt>ENV['TZ']</tt> zone.
79
82
  def localtime(utc_offset = nil)
80
- utc.getlocal(utc_offset)
83
+ utc.respond_to?(:getlocal) ? utc.getlocal(utc_offset) : utc.to_time.getlocal(utc_offset)
81
84
  end
82
85
  alias_method :getlocal, :localtime
83
86
 
@@ -99,7 +102,7 @@ module ActiveSupport
99
102
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
100
103
  # Time.zone.now.utc? # => false
101
104
  def utc?
102
- time_zone.name == 'UTC'
105
+ period.offset.abbreviation == :UTC || period.offset.abbreviation == :UCT
103
106
  end
104
107
  alias_method :gmt?, :utc?
105
108
 
@@ -122,22 +125,27 @@ module ActiveSupport
122
125
  utc? && alternate_utc_string || TimeZone.seconds_to_utc_offset(utc_offset, colon)
123
126
  end
124
127
 
125
- # Time uses +zone+ to display the time zone abbreviation, so we're
126
- # duck-typing it.
128
+ # Returns the time zone abbreviation.
129
+ #
130
+ # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
131
+ # Time.zone.now.zone # => "EST"
127
132
  def zone
128
133
  period.zone_identifier.to_s
129
134
  end
130
135
 
136
+ # Returns a string of the object's date, time, zone and offset from UTC.
137
+ #
138
+ # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25 EST -05:00"
131
139
  def inspect
132
140
  "#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}"
133
141
  end
134
142
 
143
+ # Returns a string of the object's date and time in the ISO 8601 standard
144
+ # format.
145
+ #
146
+ # Time.zone.now.xmlschema # => "2014-12-04T11:02:37-05:00"
135
147
  def xmlschema(fraction_digits = 0)
136
- fraction = if fraction_digits.to_i > 0
137
- (".%06i" % time.usec)[0, fraction_digits.to_i + 1]
138
- end
139
-
140
- "#{time.strftime("%Y-%m-%dT%H:%M:%S")}#{fraction}#{formatted_offset(true, 'Z')}"
148
+ "#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z'.freeze)}"
141
149
  end
142
150
  alias_method :iso8601, :xmlschema
143
151
 
@@ -166,11 +174,8 @@ module ActiveSupport
166
174
  end
167
175
 
168
176
  def encode_with(coder) #:nodoc:
169
- if coder.respond_to?(:represent_object)
170
- coder.represent_object(nil, utc)
171
- else
172
- coder.represent_scalar(nil, utc.strftime("%Y-%m-%d %H:%M:%S.%9NZ"))
173
- end
177
+ coder.tag = '!ruby/object:ActiveSupport::TimeWithZone'
178
+ coder.map = { 'utc' => utc, 'zone' => time_zone, 'time' => time }
174
179
  end
175
180
 
176
181
  # Returns a string of the object's date and time in the format used by
@@ -192,7 +197,7 @@ module ActiveSupport
192
197
 
193
198
  # Returns a string of the object's date and time.
194
199
  # Accepts an optional <tt>format</tt>:
195
- # * <tt>:default</tt> - default value, mimics Ruby 1.9 Time#to_s format.
200
+ # * <tt>:default</tt> - default value, mimics Ruby Time#to_s format.
196
201
  # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_formatted_s(:db).
197
202
  # * Any key in <tt>Time::DATE_FORMATS</tt> can be used. See active_support/core_ext/time/conversions.rb.
198
203
  def to_s(format = :default)
@@ -201,7 +206,7 @@ module ActiveSupport
201
206
  elsif formatter = ::Time::DATE_FORMATS[format]
202
207
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
203
208
  else
204
- "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby 1.9 Time#to_s format
209
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
205
210
  end
206
211
  end
207
212
  alias_method :to_formatted_s, :to_s
@@ -240,6 +245,7 @@ module ActiveSupport
240
245
  utc.future?
241
246
  end
242
247
 
248
+ # Returns +true+ if +other+ is equal to current object.
243
249
  def eql?(other)
244
250
  other.eql?(utc)
245
251
  end
@@ -248,9 +254,23 @@ module ActiveSupport
248
254
  utc.hash
249
255
  end
250
256
 
257
+ # Adds an interval of time to the current object's time and returns that
258
+ # value as a new TimeWithZone object.
259
+ #
260
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
261
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
262
+ # now + 1000 # => Sun, 02 Nov 2014 01:43:08 EDT -04:00
263
+ #
264
+ # If we're adding a Duration of variable length (i.e., years, months, days),
265
+ # move forward from #time, otherwise move forward from #utc, for accuracy
266
+ # when moving across DST boundaries.
267
+ #
268
+ # For instance, a time + 24.hours will advance exactly 24 hours, while a
269
+ # time + 1.day will advance 23-25 hours, depending on the day.
270
+ #
271
+ # now + 24.hours # => Mon, 03 Nov 2014 00:26:28 EST -05:00
272
+ # now + 1.day # => Mon, 03 Nov 2014 01:26:28 EST -05:00
251
273
  def +(other)
252
- # If we're adding a Duration of variable length (i.e., years, months, days), move forward from #time,
253
- # otherwise move forward from #utc, for accuracy when moving across DST boundaries
254
274
  if duration_of_variable_length?(other)
255
275
  method_missing(:+, other)
256
276
  else
@@ -258,10 +278,25 @@ module ActiveSupport
258
278
  result.in_time_zone(time_zone)
259
279
  end
260
280
  end
281
+ alias_method :since, :+
261
282
 
283
+ # Returns a new TimeWithZone object that represents the difference between
284
+ # the current object's time and the +other+ time.
285
+ #
286
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
287
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
288
+ # now - 1000 # => Mon, 03 Nov 2014 00:09:48 EST -05:00
289
+ #
290
+ # If subtracting a Duration of variable length (i.e., years, months, days),
291
+ # move backward from #time, otherwise move backward from #utc, for accuracy
292
+ # when moving across DST boundaries.
293
+ #
294
+ # For instance, a time - 24.hours will go subtract exactly 24 hours, while a
295
+ # time - 1.day will subtract 23-25 hours, depending on the day.
296
+ #
297
+ # now - 24.hours # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
298
+ # now - 1.day # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
262
299
  def -(other)
263
- # If we're subtracting a Duration of variable length (i.e., years, months, days), move backwards from #time,
264
- # otherwise move backwards #utc, for accuracy when moving across DST boundaries
265
300
  if other.acts_like?(:time)
266
301
  to_time - other.to_time
267
302
  elsif duration_of_variable_length?(other)
@@ -272,21 +307,48 @@ module ActiveSupport
272
307
  end
273
308
  end
274
309
 
275
- def since(other)
276
- # If we're adding a Duration of variable length (i.e., years, months, days), move forward from #time,
277
- # otherwise move forward from #utc, for accuracy when moving across DST boundaries
278
- if duration_of_variable_length?(other)
279
- method_missing(:since, other)
280
- else
281
- utc.since(other).in_time_zone(time_zone)
282
- end
283
- end
284
- alias_method :in, :since
285
-
310
+ # Subtracts an interval of time from the current object's time and returns
311
+ # the result as a new TimeWithZone object.
312
+ #
313
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
314
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
315
+ # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48 EST -05:00
316
+ #
317
+ # If we're subtracting a Duration of variable length (i.e., years, months,
318
+ # days), move backward from #time, otherwise move backward from #utc, for
319
+ # accuracy when moving across DST boundaries.
320
+ #
321
+ # For instance, <tt>time.ago(24.hours)</tt> will move back exactly 24 hours,
322
+ # while <tt>time.ago(1.day)</tt> will move back 23-25 hours, depending on
323
+ # the day.
324
+ #
325
+ # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
326
+ # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
286
327
  def ago(other)
287
328
  since(-other)
288
329
  end
289
330
 
331
+ # Uses Date to provide precise Time calculations for years, months, and days
332
+ # according to the proleptic Gregorian calendar. The result is returned as a
333
+ # new TimeWithZone object.
334
+ #
335
+ # The +options+ parameter takes a hash with any of these keys:
336
+ # <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>,
337
+ # <tt>:hours</tt>, <tt>:minutes</tt>, <tt>:seconds</tt>.
338
+ #
339
+ # If advancing by a value of variable length (i.e., years, weeks, months,
340
+ # days), move forward from #time, otherwise move forward from #utc, for
341
+ # accuracy when moving across DST boundaries.
342
+ #
343
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
344
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
345
+ # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29 EDT -04:00
346
+ # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28 EDT -04:00
347
+ # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28 EST -05:00
348
+ # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28 EST -05:00
349
+ # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28 EST -05:00
350
+ # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28 EST -05:00
351
+ # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28 EST -05:00
290
352
  def advance(options)
291
353
  # If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
292
354
  # otherwise advance from #utc, for accuracy when moving across DST boundaries
@@ -305,36 +367,51 @@ module ActiveSupport
305
367
  EOV
306
368
  end
307
369
 
370
+ # Returns Array of parts of Time in sequence of
371
+ # [seconds, minutes, hours, day, month, year, weekday, yearday, dst?, zone].
372
+ #
373
+ # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27 UTC +00:00
374
+ # now.to_a # => [27, 29, 2, 18, 8, 2015, 2, 230, false, "UTC"]
308
375
  def to_a
309
376
  [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
310
377
  end
311
378
 
379
+ # Returns the object's date and time as a floating point number of seconds
380
+ # since the Epoch (January 1, 1970 00:00 UTC).
381
+ #
382
+ # Time.zone.now.to_f # => 1417709320.285418
312
383
  def to_f
313
384
  utc.to_f
314
385
  end
315
386
 
387
+ # Returns the object's date and time as an integer number of seconds
388
+ # since the Epoch (January 1, 1970 00:00 UTC).
389
+ #
390
+ # Time.zone.now.to_i # => 1417709320
316
391
  def to_i
317
392
  utc.to_i
318
393
  end
319
394
  alias_method :tv_sec, :to_i
320
395
 
396
+ # Returns the object's date and time as a rational number of seconds
397
+ # since the Epoch (January 1, 1970 00:00 UTC).
398
+ #
399
+ # Time.zone.now.to_r # => (708854548642709/500000)
321
400
  def to_r
322
401
  utc.to_r
323
402
  end
324
403
 
325
- def to_datetime
326
- @to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
404
+ # Returns an instance of Time in the system timezone.
405
+ def to_time
406
+ utc.to_time
327
407
  end
328
408
 
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
409
+ # Returns an instance of DateTime with the timezone's UTC offset
410
+ #
411
+ # Time.zone.now.to_datetime # => Tue, 18 Aug 2015 02:32:20 +0000
412
+ # Time.current.in_time_zone('Hawaii').to_datetime # => Mon, 17 Aug 2015 16:32:20 -1000
413
+ def to_datetime
414
+ utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
338
415
  end
339
416
 
340
417
  # So that +self+ <tt>acts_like?(:time)</tt>.
@@ -348,9 +425,13 @@ module ActiveSupport
348
425
  end
349
426
  alias_method :kind_of?, :is_a?
350
427
 
428
+ # An instance of ActiveSupport::TimeWithZone is never blank
429
+ def blank?
430
+ false
431
+ end
432
+
351
433
  def freeze
352
- # preload instance variables before freezing
353
- period; utc; time; to_datetime; to_time
434
+ period; utc; time # preload instance variables before freezing
354
435
  super
355
436
  end
356
437
 
@@ -373,6 +454,7 @@ module ActiveSupport
373
454
  # Ensure proxy class responds to all methods that underlying time instance
374
455
  # responds to.
375
456
  def respond_to_missing?(sym, include_priv)
457
+ # consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime
376
458
  return false if sym.to_sym == :acts_like_date?
377
459
  time.respond_to?(sym, include_priv)
378
460
  end
@@ -400,7 +482,7 @@ module ActiveSupport
400
482
  end
401
483
 
402
484
  def transfer_time_values_to_utc_constructor(time)
403
- ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec + time.subsec)
485
+ ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec, Rational(time.nsec, 1000))
404
486
  end
405
487
 
406
488
  def duration_of_variable_length?(obj)