activesupport 4.2.11.1 → 5.2.8.1

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 (256) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +441 -399
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +4 -5
  5. data/lib/active_support/all.rb +5 -3
  6. data/lib/active_support/array_inquirer.rb +48 -0
  7. data/lib/active_support/backtrace_cleaner.rb +7 -5
  8. data/lib/active_support/benchmarkable.rb +6 -4
  9. data/lib/active_support/builder.rb +3 -1
  10. data/lib/active_support/cache/file_store.rb +41 -35
  11. data/lib/active_support/cache/mem_cache_store.rb +91 -91
  12. data/lib/active_support/cache/memory_store.rb +27 -30
  13. data/lib/active_support/cache/null_store.rb +7 -8
  14. data/lib/active_support/cache/redis_cache_store.rb +466 -0
  15. data/lib/active_support/cache/strategy/local_cache.rb +67 -34
  16. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  17. data/lib/active_support/cache.rb +287 -196
  18. data/lib/active_support/callbacks.rb +640 -590
  19. data/lib/active_support/concern.rb +11 -5
  20. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  21. data/lib/active_support/concurrency/share_lock.rb +227 -0
  22. data/lib/active_support/configurable.rb +8 -5
  23. data/lib/active_support/core_ext/array/access.rb +29 -1
  24. data/lib/active_support/core_ext/array/conversions.rb +22 -18
  25. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  26. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  27. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  28. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -3
  29. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  30. data/lib/active_support/core_ext/array.rb +9 -6
  31. data/lib/active_support/core_ext/benchmark.rb +3 -1
  32. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  33. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  34. data/lib/active_support/core_ext/class/attribute.rb +41 -22
  35. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  36. data/lib/active_support/core_ext/class/subclasses.rb +20 -6
  37. data/lib/active_support/core_ext/class.rb +4 -3
  38. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  39. data/lib/active_support/core_ext/date/blank.rb +14 -0
  40. data/lib/active_support/core_ext/date/calculations.rb +11 -9
  41. data/lib/active_support/core_ext/date/conversions.rb +25 -23
  42. data/lib/active_support/core_ext/date/zones.rb +4 -2
  43. data/lib/active_support/core_ext/date.rb +6 -4
  44. data/lib/active_support/core_ext/date_and_time/calculations.rb +170 -58
  45. data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
  46. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -12
  47. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  48. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  49. data/lib/active_support/core_ext/date_time/calculations.rb +36 -18
  50. data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
  51. data/lib/active_support/core_ext/date_time/conversions.rb +16 -12
  52. data/lib/active_support/core_ext/date_time.rb +7 -5
  53. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  54. data/lib/active_support/core_ext/digest.rb +3 -0
  55. data/lib/active_support/core_ext/enumerable.rb +101 -33
  56. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  57. data/lib/active_support/core_ext/file.rb +3 -1
  58. data/lib/active_support/core_ext/hash/compact.rb +14 -9
  59. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  60. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  61. data/lib/active_support/core_ext/hash/except.rb +11 -8
  62. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  63. data/lib/active_support/core_ext/hash/keys.rb +33 -27
  64. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  65. data/lib/active_support/core_ext/hash/slice.rb +8 -8
  66. data/lib/active_support/core_ext/hash/transform_values.rb +14 -5
  67. data/lib/active_support/core_ext/hash.rb +11 -9
  68. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  69. data/lib/active_support/core_ext/integer/multiple.rb +2 -0
  70. data/lib/active_support/core_ext/integer/time.rb +11 -18
  71. data/lib/active_support/core_ext/integer.rb +5 -3
  72. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/concern.rb +5 -1
  74. data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +6 -5
  77. data/lib/active_support/core_ext/load_error.rb +3 -22
  78. data/lib/active_support/core_ext/marshal.rb +8 -8
  79. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  80. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  81. data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +43 -40
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
  84. data/lib/active_support/core_ext/module/concerning.rb +11 -12
  85. data/lib/active_support/core_ext/module/delegation.rb +99 -29
  86. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  87. data/lib/active_support/core_ext/module/introspection.rb +9 -9
  88. data/lib/active_support/core_ext/module/reachable.rb +5 -2
  89. data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
  90. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  91. data/lib/active_support/core_ext/module.rb +14 -11
  92. data/lib/active_support/core_ext/name_error.rb +22 -2
  93. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  94. data/lib/active_support/core_ext/numeric/conversions.rb +78 -81
  95. data/lib/active_support/core_ext/numeric/inquiry.rb +28 -0
  96. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  97. data/lib/active_support/core_ext/numeric.rb +6 -3
  98. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  99. data/lib/active_support/core_ext/object/blank.rb +27 -2
  100. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  101. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  102. data/lib/active_support/core_ext/object/duplicable.rb +41 -14
  103. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  104. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  105. data/lib/active_support/core_ext/object/json.rb +49 -19
  106. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  107. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  108. data/lib/active_support/core_ext/object/try.rb +69 -21
  109. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  110. data/lib/active_support/core_ext/object.rb +14 -13
  111. data/lib/active_support/core_ext/range/compare_range.rb +61 -0
  112. data/lib/active_support/core_ext/range/conversions.rb +27 -7
  113. data/lib/active_support/core_ext/range/each.rb +19 -17
  114. data/lib/active_support/core_ext/range/include_range.rb +2 -22
  115. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  116. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  117. data/lib/active_support/core_ext/range.rb +7 -4
  118. data/lib/active_support/core_ext/regexp.rb +6 -0
  119. data/lib/active_support/core_ext/securerandom.rb +25 -0
  120. data/lib/active_support/core_ext/string/access.rb +8 -6
  121. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  122. data/lib/active_support/core_ext/string/conversions.rb +7 -4
  123. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  124. data/lib/active_support/core_ext/string/filters.rb +6 -5
  125. data/lib/active_support/core_ext/string/indent.rb +6 -4
  126. data/lib/active_support/core_ext/string/inflections.rb +61 -24
  127. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  128. data/lib/active_support/core_ext/string/multibyte.rb +15 -7
  129. data/lib/active_support/core_ext/string/output_safety.rb +62 -38
  130. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  131. data/lib/active_support/core_ext/string/strip.rb +4 -5
  132. data/lib/active_support/core_ext/string/zones.rb +4 -2
  133. data/lib/active_support/core_ext/string.rb +15 -13
  134. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  135. data/lib/active_support/core_ext/time/calculations.rb +85 -51
  136. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  137. data/lib/active_support/core_ext/time/conversions.rb +20 -13
  138. data/lib/active_support/core_ext/time/zones.rb +41 -7
  139. data/lib/active_support/core_ext/time.rb +7 -6
  140. data/lib/active_support/core_ext/uri.rb +6 -8
  141. data/lib/active_support/core_ext.rb +3 -1
  142. data/lib/active_support/current_attributes.rb +195 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +57 -0
  145. data/lib/active_support/dependencies.rb +152 -161
  146. data/lib/active_support/deprecation/behaviors.rb +44 -11
  147. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  148. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  149. data/lib/active_support/deprecation/method_wrappers.rb +66 -20
  150. data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
  151. data/lib/active_support/deprecation/reporting.rb +32 -12
  152. data/lib/active_support/deprecation.rb +12 -9
  153. data/lib/active_support/descendants_tracker.rb +2 -0
  154. data/lib/active_support/digest.rb +20 -0
  155. data/lib/active_support/duration/iso8601_parser.rb +125 -0
  156. data/lib/active_support/duration/iso8601_serializer.rb +55 -0
  157. data/lib/active_support/duration.rb +314 -38
  158. data/lib/active_support/encrypted_configuration.rb +49 -0
  159. data/lib/active_support/encrypted_file.rb +99 -0
  160. data/lib/active_support/evented_file_update_checker.rb +205 -0
  161. data/lib/active_support/execution_wrapper.rb +131 -0
  162. data/lib/active_support/executor.rb +8 -0
  163. data/lib/active_support/file_update_checker.rb +63 -37
  164. data/lib/active_support/gem_version.rb +5 -3
  165. data/lib/active_support/gzip.rb +7 -5
  166. data/lib/active_support/hash_with_indifferent_access.rb +123 -28
  167. data/lib/active_support/i18n.rb +8 -6
  168. data/lib/active_support/i18n_railtie.rb +37 -13
  169. data/lib/active_support/inflections.rb +13 -11
  170. data/lib/active_support/inflector/inflections.rb +61 -12
  171. data/lib/active_support/inflector/methods.rb +163 -136
  172. data/lib/active_support/inflector/transliterate.rb +48 -27
  173. data/lib/active_support/inflector.rb +7 -5
  174. data/lib/active_support/json/decoding.rb +16 -13
  175. data/lib/active_support/json/encoding.rb +11 -58
  176. data/lib/active_support/json.rb +4 -2
  177. data/lib/active_support/key_generator.rb +25 -25
  178. data/lib/active_support/lazy_load_hooks.rb +50 -20
  179. data/lib/active_support/locale/en.yml +2 -0
  180. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  181. data/lib/active_support/log_subscriber.rb +13 -10
  182. data/lib/active_support/logger.rb +8 -7
  183. data/lib/active_support/logger_silence.rb +6 -4
  184. data/lib/active_support/logger_thread_safe_level.rb +7 -5
  185. data/lib/active_support/message_encryptor.rb +168 -53
  186. data/lib/active_support/message_verifier.rb +150 -17
  187. data/lib/active_support/messages/metadata.rb +71 -0
  188. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  189. data/lib/active_support/messages/rotator.rb +56 -0
  190. data/lib/active_support/multibyte/chars.rb +36 -23
  191. data/lib/active_support/multibyte/unicode.rb +100 -96
  192. data/lib/active_support/multibyte.rb +4 -2
  193. data/lib/active_support/notifications/fanout.rb +11 -9
  194. data/lib/active_support/notifications/instrumenter.rb +27 -7
  195. data/lib/active_support/notifications.rb +11 -7
  196. data/lib/active_support/number_helper/number_converter.rb +13 -11
  197. data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -9
  198. data/lib/active_support/number_helper/number_to_delimited_converter.rb +9 -3
  199. data/lib/active_support/number_helper/number_to_human_converter.rb +11 -9
  200. data/lib/active_support/number_helper/number_to_human_size_converter.rb +9 -8
  201. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  202. data/lib/active_support/number_helper/number_to_phone_converter.rb +13 -4
  203. data/lib/active_support/number_helper/number_to_rounded_converter.rb +23 -56
  204. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  205. data/lib/active_support/number_helper.rb +94 -68
  206. data/lib/active_support/option_merger.rb +3 -1
  207. data/lib/active_support/ordered_hash.rb +6 -4
  208. data/lib/active_support/ordered_options.rb +23 -5
  209. data/lib/active_support/per_thread_registry.rb +9 -4
  210. data/lib/active_support/proxy_object.rb +2 -0
  211. data/lib/active_support/rails.rb +16 -8
  212. data/lib/active_support/railtie.rb +43 -9
  213. data/lib/active_support/reloader.rb +131 -0
  214. data/lib/active_support/rescuable.rb +108 -53
  215. data/lib/active_support/security_utils.rb +15 -11
  216. data/lib/active_support/string_inquirer.rb +11 -3
  217. data/lib/active_support/subscriber.rb +21 -16
  218. data/lib/active_support/tagged_logging.rb +14 -11
  219. data/lib/active_support/test_case.rb +19 -47
  220. data/lib/active_support/testing/assertions.rb +137 -20
  221. data/lib/active_support/testing/autorun.rb +4 -2
  222. data/lib/active_support/testing/constant_lookup.rb +2 -1
  223. data/lib/active_support/testing/declarative.rb +3 -1
  224. data/lib/active_support/testing/deprecation.rb +14 -10
  225. data/lib/active_support/testing/file_fixtures.rb +36 -0
  226. data/lib/active_support/testing/isolation.rb +34 -25
  227. data/lib/active_support/testing/method_call_assertions.rb +43 -0
  228. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  229. data/lib/active_support/testing/stream.rb +44 -0
  230. data/lib/active_support/testing/tagged_logging.rb +3 -1
  231. data/lib/active_support/testing/time_helpers.rb +81 -15
  232. data/lib/active_support/time.rb +14 -12
  233. data/lib/active_support/time_with_zone.rb +169 -39
  234. data/lib/active_support/values/time_zone.rb +196 -61
  235. data/lib/active_support/values/unicode_tables.dat +0 -0
  236. data/lib/active_support/version.rb +3 -1
  237. data/lib/active_support/xml_mini/jdom.rb +116 -114
  238. data/lib/active_support/xml_mini/libxml.rb +16 -13
  239. data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
  240. data/lib/active_support/xml_mini/nokogiri.rb +14 -12
  241. data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
  242. data/lib/active_support/xml_mini/rexml.rb +11 -9
  243. data/lib/active_support/xml_mini.rb +37 -37
  244. data/lib/active_support.rb +12 -11
  245. metadata +57 -27
  246. data/lib/active_support/concurrency/latch.rb +0 -27
  247. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  248. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  249. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  250. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  251. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  252. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  253. data/lib/active_support/core_ext/object/itself.rb +0 -15
  254. data/lib/active_support/core_ext/struct.rb +0 -6
  255. data/lib/active_support/core_ext/thread.rb +0 -86
  256. data/lib/active_support/core_ext/time/marshal.rb +0 -30
@@ -1,48 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/redefine_method"
4
+ require "active_support/core_ext/string/strip" # for strip_heredoc
5
+ require "active_support/core_ext/time/calculations"
6
+ require "concurrent/map"
7
+
1
8
  module ActiveSupport
2
9
  module Testing
3
10
  class SimpleStubs # :nodoc:
4
11
  Stub = Struct.new(:object, :method_name, :original_method)
5
12
 
6
13
  def initialize
7
- @stubs = {}
14
+ @stubs = Concurrent::Map.new { |h, k| h[k] = {} }
8
15
  end
9
16
 
10
17
  def stub_object(object, method_name, &block)
11
- key = [object.object_id, method_name]
12
-
13
- if stub = @stubs[key]
18
+ if stub = stubbing(object, method_name)
14
19
  unstub_object(stub)
15
20
  end
16
21
 
17
22
  new_name = "__simple_stub__#{method_name}"
18
23
 
19
- @stubs[key] = Stub.new(object, method_name, new_name)
24
+ @stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name)
20
25
 
21
26
  object.singleton_class.send :alias_method, new_name, method_name
22
27
  object.define_singleton_method(method_name, &block)
23
28
  end
24
29
 
25
30
  def unstub_all!
26
- @stubs.each_value do |stub|
27
- unstub_object(stub)
31
+ @stubs.each_value do |object_stubs|
32
+ object_stubs.each_value do |stub|
33
+ unstub_object(stub)
34
+ end
28
35
  end
29
- @stubs = {}
36
+ @stubs.clear
37
+ end
38
+
39
+ def stubbing(object, method_name)
40
+ @stubs[object.object_id][method_name]
30
41
  end
31
42
 
32
43
  private
33
44
 
34
45
  def unstub_object(stub)
35
46
  singleton_class = stub.object.singleton_class
36
- singleton_class.send :undef_method, stub.method_name
47
+ singleton_class.send :silence_redefinition_of_method, stub.method_name
37
48
  singleton_class.send :alias_method, stub.method_name, stub.original_method
38
49
  singleton_class.send :undef_method, stub.original_method
39
50
  end
40
51
  end
41
52
 
42
- # Containing helpers that helps you test passage of time.
53
+ # Contains helpers that help you test passage of time.
43
54
  module TimeHelpers
55
+ def after_teardown
56
+ travel_back
57
+ super
58
+ end
59
+
44
60
  # Changes current time to the time in the future or in the past by a given time difference by
45
- # stubbing +Time.now+, +Date.today+, and +DateTime.now+.
61
+ # stubbing +Time.now+, +Date.today+, and +DateTime.now+. The stubs are automatically removed
62
+ # at the end of the test.
46
63
  #
47
64
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
48
65
  # travel 1.day
@@ -64,9 +81,10 @@ module ActiveSupport
64
81
 
65
82
  # Changes current time to the given time by stubbing +Time.now+,
66
83
  # +Date.today+, and +DateTime.now+ to return the time or date passed into this method.
84
+ # The stubs are automatically removed at the end of the test.
67
85
  #
68
86
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
69
- # travel_to Time.new(2004, 11, 24, 01, 04, 44)
87
+ # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
70
88
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
71
89
  # Date.current # => Wed, 24 Nov 2004
72
90
  # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
@@ -88,11 +106,39 @@ module ActiveSupport
88
106
  # state at the end of the block:
89
107
  #
90
108
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
91
- # travel_to Time.new(2004, 11, 24, 01, 04, 44) do
109
+ # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) do
92
110
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
93
111
  # end
94
112
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
95
113
  def travel_to(date_or_time)
114
+ if block_given? && simple_stubs.stubbing(Time, :now)
115
+ travel_to_nested_block_call = <<-MSG.strip_heredoc
116
+
117
+ Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing.
118
+
119
+ Instead of:
120
+
121
+ travel_to 2.days.from_now do
122
+ # 2 days from today
123
+ travel_to 3.days.from_now do
124
+ # 5 days from today
125
+ end
126
+ end
127
+
128
+ preferred way to achieve above is:
129
+
130
+ travel 2.days do
131
+ # 2 days from today
132
+ end
133
+
134
+ travel 5.days do
135
+ # 5 days from today
136
+ end
137
+
138
+ MSG
139
+ raise travel_to_nested_block_call
140
+ end
141
+
96
142
  if date_or_time.is_a?(Date) && !date_or_time.is_a?(DateTime)
97
143
  now = date_or_time.midnight.to_time
98
144
  else
@@ -113,10 +159,10 @@ module ActiveSupport
113
159
  end
114
160
 
115
161
  # Returns the current time back to its original state, by removing the stubs added by
116
- # `travel` and `travel_to`.
162
+ # +travel+ and +travel_to+.
117
163
  #
118
164
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
119
- # travel_to Time.new(2004, 11, 24, 01, 04, 44)
165
+ # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
120
166
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
121
167
  # travel_back
122
168
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
@@ -124,6 +170,26 @@ module ActiveSupport
124
170
  simple_stubs.unstub_all!
125
171
  end
126
172
 
173
+ # Calls +travel_to+ with +Time.now+.
174
+ #
175
+ # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
176
+ # freeze_time
177
+ # sleep(1)
178
+ # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
179
+ #
180
+ # This method also accepts a block, which will return the current time back to its original
181
+ # state at the end of the block:
182
+ #
183
+ # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
184
+ # freeze_time do
185
+ # sleep(1)
186
+ # User.create.created_at # => Sun, 09 Jul 2017 15:34:49 EST -05:00
187
+ # end
188
+ # Time.current # => Sun, 09 Jul 2017 15:34:50 EST -05:00
189
+ def freeze_time(&block)
190
+ travel_to Time.now, &block
191
+ end
192
+
127
193
  private
128
194
 
129
195
  def simple_stubs
@@ -1,18 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
- autoload :Duration, 'active_support/duration'
3
- autoload :TimeWithZone, 'active_support/time_with_zone'
4
- autoload :TimeZone, 'active_support/values/time_zone'
4
+ autoload :Duration, "active_support/duration"
5
+ autoload :TimeWithZone, "active_support/time_with_zone"
6
+ autoload :TimeZone, "active_support/values/time_zone"
5
7
  end
6
8
 
7
- require 'date'
8
- require 'time'
9
+ require "date"
10
+ require "time"
9
11
 
10
- require 'active_support/core_ext/time'
11
- require 'active_support/core_ext/date'
12
- require 'active_support/core_ext/date_time'
12
+ require "active_support/core_ext/time"
13
+ require "active_support/core_ext/date"
14
+ require "active_support/core_ext/date_time"
13
15
 
14
- require 'active_support/core_ext/integer/time'
15
- require 'active_support/core_ext/numeric/time'
16
+ require "active_support/core_ext/integer/time"
17
+ require "active_support/core_ext/numeric/time"
16
18
 
17
- require 'active_support/core_ext/string/conversions'
18
- require 'active_support/core_ext/string/zones'
19
+ require "active_support/core_ext/string/conversions"
20
+ require "active_support/core_ext/string/zones"
@@ -1,6 +1,9 @@
1
- require 'active_support/values/time_zone'
2
- require 'active_support/core_ext/object/acts_like'
3
- require 'active_support/core_ext/date_and_time/compatibility'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/duration"
4
+ require "active_support/values/time_zone"
5
+ require "active_support/core_ext/object/acts_like"
6
+ require "active_support/core_ext/date_and_time/compatibility"
4
7
 
5
8
  module ActiveSupport
6
9
  # A Time-like class that can represent a time in any time zone. Necessary
@@ -14,7 +17,7 @@ module ActiveSupport
14
17
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
15
18
  # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
16
19
  # 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
20
+ # Time.zone.at(1171139445) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
18
21
  # Time.zone.now # => Sun, 18 May 2008 13:07:55 EDT -04:00
19
22
  # Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45 EST -05:00
20
23
  #
@@ -35,12 +38,14 @@ module ActiveSupport
35
38
  # t.is_a?(Time) # => true
36
39
  # t.is_a?(ActiveSupport::TimeWithZone) # => true
37
40
  class TimeWithZone
38
-
39
41
  # Report class name as 'Time' to thwart type checking.
40
42
  def self.name
41
- 'Time'
43
+ "Time"
42
44
  end
43
45
 
46
+ PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N".freeze }
47
+ PRECISIONS[0] = "%FT%T".freeze
48
+
44
49
  include Comparable, DateAndTime::Compatibility
45
50
  attr_reader :time_zone
46
51
 
@@ -99,7 +104,7 @@ module ActiveSupport
99
104
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
100
105
  # Time.zone.now.utc? # => false
101
106
  def utc?
102
- time_zone.name == 'UTC'
107
+ period.offset.abbreviation == :UTC || period.offset.abbreviation == :UCT
103
108
  end
104
109
  alias_method :gmt?, :utc?
105
110
 
@@ -122,24 +127,30 @@ module ActiveSupport
122
127
  utc? && alternate_utc_string || TimeZone.seconds_to_utc_offset(utc_offset, colon)
123
128
  end
124
129
 
125
- # Time uses +zone+ to display the time zone abbreviation, so we're
126
- # duck-typing it.
130
+ # Returns the time zone abbreviation.
131
+ #
132
+ # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
133
+ # Time.zone.now.zone # => "EST"
127
134
  def zone
128
135
  period.zone_identifier.to_s
129
136
  end
130
137
 
138
+ # Returns a string of the object's date, time, zone, and offset from UTC.
139
+ #
140
+ # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25 EST -05:00"
131
141
  def inspect
132
142
  "#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}"
133
143
  end
134
144
 
145
+ # Returns a string of the object's date and time in the ISO 8601 standard
146
+ # format.
147
+ #
148
+ # Time.zone.now.xmlschema # => "2014-12-04T11:02:37-05:00"
135
149
  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')}"
150
+ "#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z'.freeze)}"
141
151
  end
142
152
  alias_method :iso8601, :xmlschema
153
+ alias_method :rfc3339, :xmlschema
143
154
 
144
155
  # Coerces time to a string for JSON encoding. The default format is ISO 8601.
145
156
  # You can get %Y/%m/%d %H:%M:%S +offset style by setting
@@ -162,15 +173,12 @@ module ActiveSupport
162
173
  end
163
174
 
164
175
  def init_with(coder) #:nodoc:
165
- initialize(coder['utc'], coder['zone'], coder['time'])
176
+ initialize(coder["utc"], coder["zone"], coder["time"])
166
177
  end
167
178
 
168
179
  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
180
+ coder.tag = "!ruby/object:ActiveSupport::TimeWithZone"
181
+ coder.map = { "utc" => utc, "zone" => time_zone, "time" => time }
174
182
  end
175
183
 
176
184
  # Returns a string of the object's date and time in the format used by
@@ -192,7 +200,7 @@ module ActiveSupport
192
200
 
193
201
  # Returns a string of the object's date and time.
194
202
  # Accepts an optional <tt>format</tt>:
195
- # * <tt>:default</tt> - default value, mimics Ruby 1.9 Time#to_s format.
203
+ # * <tt>:default</tt> - default value, mimics Ruby Time#to_s format.
196
204
  # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_formatted_s(:db).
197
205
  # * Any key in <tt>Time::DATE_FORMATS</tt> can be used. See active_support/core_ext/time/conversions.rb.
198
206
  def to_s(format = :default)
@@ -201,7 +209,7 @@ module ActiveSupport
201
209
  elsif formatter = ::Time::DATE_FORMATS[format]
202
210
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
203
211
  else
204
- "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby 1.9 Time#to_s format
212
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
205
213
  end
206
214
  end
207
215
  alias_method :to_formatted_s, :to_s
@@ -240,6 +248,7 @@ module ActiveSupport
240
248
  utc.future?
241
249
  end
242
250
 
251
+ # Returns +true+ if +other+ is equal to current object.
243
252
  def eql?(other)
244
253
  other.eql?(utc)
245
254
  end
@@ -248,9 +257,23 @@ module ActiveSupport
248
257
  utc.hash
249
258
  end
250
259
 
260
+ # Adds an interval of time to the current object's time and returns that
261
+ # value as a new TimeWithZone object.
262
+ #
263
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
264
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
265
+ # now + 1000 # => Sun, 02 Nov 2014 01:43:08 EDT -04:00
266
+ #
267
+ # If we're adding a Duration of variable length (i.e., years, months, days),
268
+ # move forward from #time, otherwise move forward from #utc, for accuracy
269
+ # when moving across DST boundaries.
270
+ #
271
+ # For instance, a time + 24.hours will advance exactly 24 hours, while a
272
+ # time + 1.day will advance 23-25 hours, depending on the day.
273
+ #
274
+ # now + 24.hours # => Mon, 03 Nov 2014 00:26:28 EST -05:00
275
+ # now + 1.day # => Mon, 03 Nov 2014 01:26:28 EST -05:00
251
276
  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
277
  if duration_of_variable_length?(other)
255
278
  method_missing(:+, other)
256
279
  else
@@ -258,10 +281,26 @@ module ActiveSupport
258
281
  result.in_time_zone(time_zone)
259
282
  end
260
283
  end
284
+ alias_method :since, :+
285
+ alias_method :in, :+
261
286
 
287
+ # Returns a new TimeWithZone object that represents the difference between
288
+ # the current object's time and the +other+ time.
289
+ #
290
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
291
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
292
+ # now - 1000 # => Mon, 03 Nov 2014 00:09:48 EST -05:00
293
+ #
294
+ # If subtracting a Duration of variable length (i.e., years, months, days),
295
+ # move backward from #time, otherwise move backward from #utc, for accuracy
296
+ # when moving across DST boundaries.
297
+ #
298
+ # For instance, a time - 24.hours will go subtract exactly 24 hours, while a
299
+ # time - 1.day will subtract 23-25 hours, depending on the day.
300
+ #
301
+ # now - 24.hours # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
302
+ # now - 1.day # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
262
303
  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
304
  if other.acts_like?(:time)
266
305
  to_time - other.to_time
267
306
  elsif duration_of_variable_length?(other)
@@ -272,21 +311,84 @@ module ActiveSupport
272
311
  end
273
312
  end
274
313
 
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
-
314
+ # Subtracts an interval of time from the current object's time and returns
315
+ # the result as a new TimeWithZone object.
316
+ #
317
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
318
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
319
+ # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48 EST -05:00
320
+ #
321
+ # If we're subtracting a Duration of variable length (i.e., years, months,
322
+ # days), move backward from #time, otherwise move backward from #utc, for
323
+ # accuracy when moving across DST boundaries.
324
+ #
325
+ # For instance, <tt>time.ago(24.hours)</tt> will move back exactly 24 hours,
326
+ # while <tt>time.ago(1.day)</tt> will move back 23-25 hours, depending on
327
+ # the day.
328
+ #
329
+ # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
330
+ # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
286
331
  def ago(other)
287
332
  since(-other)
288
333
  end
289
334
 
335
+ # Returns a new +ActiveSupport::TimeWithZone+ where one or more of the elements have
336
+ # been changed according to the +options+ parameter. The time options (<tt>:hour</tt>,
337
+ # <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly,
338
+ # so if only the hour is passed, then minute, sec, usec and nsec is set to 0. If the
339
+ # hour and minute is passed, then sec, usec and nsec is set to 0. The +options+
340
+ # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
341
+ # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>,
342
+ # <tt>:nsec</tt>, <tt>:offset</tt>, <tt>:zone</tt>. Pass either <tt>:usec</tt>
343
+ # or <tt>:nsec</tt>, not both. Similarly, pass either <tt>:zone</tt> or
344
+ # <tt>:offset</tt>, not both.
345
+ #
346
+ # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15 EST -05:00
347
+ # t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15 EST -05:00
348
+ # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00 EST -05:00
349
+ # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00 EST -05:00
350
+ # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15 HST -10:00
351
+ # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15 HST -10:00
352
+ def change(options)
353
+ if options[:zone] && options[:offset]
354
+ raise ArgumentError, "Can't change both :offset and :zone at the same time: #{options.inspect}"
355
+ end
356
+
357
+ new_time = time.change(options)
358
+
359
+ if options[:zone]
360
+ new_zone = ::Time.find_zone(options[:zone])
361
+ elsif options[:offset]
362
+ new_zone = ::Time.find_zone(new_time.utc_offset)
363
+ end
364
+
365
+ new_zone ||= time_zone
366
+ periods = new_zone.periods_for_local(new_time)
367
+
368
+ self.class.new(nil, new_zone, new_time, periods.include?(period) ? period : nil)
369
+ end
370
+
371
+ # Uses Date to provide precise Time calculations for years, months, and days
372
+ # according to the proleptic Gregorian calendar. The result is returned as a
373
+ # new TimeWithZone object.
374
+ #
375
+ # The +options+ parameter takes a hash with any of these keys:
376
+ # <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>,
377
+ # <tt>:hours</tt>, <tt>:minutes</tt>, <tt>:seconds</tt>.
378
+ #
379
+ # If advancing by a value of variable length (i.e., years, weeks, months,
380
+ # days), move forward from #time, otherwise move forward from #utc, for
381
+ # accuracy when moving across DST boundaries.
382
+ #
383
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
384
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
385
+ # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29 EDT -04:00
386
+ # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28 EDT -04:00
387
+ # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28 EST -05:00
388
+ # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28 EST -05:00
389
+ # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28 EST -05:00
390
+ # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28 EST -05:00
391
+ # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28 EST -05:00
290
392
  def advance(options)
291
393
  # If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
292
394
  # otherwise advance from #utc, for accuracy when moving across DST boundaries
@@ -305,23 +407,44 @@ module ActiveSupport
305
407
  EOV
306
408
  end
307
409
 
410
+ # Returns Array of parts of Time in sequence of
411
+ # [seconds, minutes, hours, day, month, year, weekday, yearday, dst?, zone].
412
+ #
413
+ # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27 UTC +00:00
414
+ # now.to_a # => [27, 29, 2, 18, 8, 2015, 2, 230, false, "UTC"]
308
415
  def to_a
309
416
  [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
310
417
  end
311
418
 
419
+ # Returns the object's date and time as a floating point number of seconds
420
+ # since the Epoch (January 1, 1970 00:00 UTC).
421
+ #
422
+ # Time.zone.now.to_f # => 1417709320.285418
312
423
  def to_f
313
424
  utc.to_f
314
425
  end
315
426
 
427
+ # Returns the object's date and time as an integer number of seconds
428
+ # since the Epoch (January 1, 1970 00:00 UTC).
429
+ #
430
+ # Time.zone.now.to_i # => 1417709320
316
431
  def to_i
317
432
  utc.to_i
318
433
  end
319
434
  alias_method :tv_sec, :to_i
320
435
 
436
+ # Returns the object's date and time as a rational number of seconds
437
+ # since the Epoch (January 1, 1970 00:00 UTC).
438
+ #
439
+ # Time.zone.now.to_r # => (708854548642709/500000)
321
440
  def to_r
322
441
  utc.to_r
323
442
  end
324
443
 
444
+ # Returns an instance of DateTime with the timezone's UTC offset
445
+ #
446
+ # Time.zone.now.to_datetime # => Tue, 18 Aug 2015 02:32:20 +0000
447
+ # Time.current.in_time_zone('Hawaii').to_datetime # => Mon, 17 Aug 2015 16:32:20 -1000
325
448
  def to_datetime
326
449
  @to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
327
450
  end
@@ -348,6 +471,11 @@ module ActiveSupport
348
471
  end
349
472
  alias_method :kind_of?, :is_a?
350
473
 
474
+ # An instance of ActiveSupport::TimeWithZone is never blank
475
+ def blank?
476
+ false
477
+ end
478
+
351
479
  def freeze
352
480
  # preload instance variables before freezing
353
481
  period; utc; time; to_datetime; to_time
@@ -382,7 +510,7 @@ module ActiveSupport
382
510
  def method_missing(sym, *args, &block)
383
511
  wrap_with_time_zone time.__send__(sym, *args, &block)
384
512
  rescue NoMethodError => e
385
- raise e, e.message.sub(time.inspect, self.inspect), e.backtrace
513
+ raise e, e.message.sub(time.inspect, inspect), e.backtrace
386
514
  end
387
515
 
388
516
  private
@@ -400,11 +528,13 @@ module ActiveSupport
400
528
  end
401
529
 
402
530
  def transfer_time_values_to_utc_constructor(time)
531
+ # avoid creating another Time object if possible
532
+ return time if time.instance_of?(::Time) && time.utc?
403
533
  ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec + time.subsec)
404
534
  end
405
535
 
406
536
  def duration_of_variable_length?(obj)
407
- ActiveSupport::Duration === obj && obj.parts.any? {|p| [:years, :months, :days].include?(p[0]) }
537
+ ActiveSupport::Duration === obj && obj.parts.any? { |p| [:years, :months, :weeks, :days].include?(p[0]) }
408
538
  end
409
539
 
410
540
  def wrap_with_time_zone(time)