activesupport 4.2.11.1 → 6.0.3.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 (263) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +399 -411
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +5 -3
  7. data/lib/active_support/array_inquirer.rb +48 -0
  8. data/lib/active_support/backtrace_cleaner.rb +34 -6
  9. data/lib/active_support/benchmarkable.rb +6 -4
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +58 -53
  12. data/lib/active_support/cache/mem_cache_store.rb +95 -91
  13. data/lib/active_support/cache/memory_store.rb +39 -36
  14. data/lib/active_support/cache/null_store.rb +11 -7
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +75 -42
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +331 -217
  19. data/lib/active_support/callbacks.rb +650 -592
  20. data/lib/active_support/concern.rb +35 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +226 -0
  23. data/lib/active_support/configurable.rb +13 -14
  24. data/lib/active_support/core_ext/array/access.rb +41 -1
  25. data/lib/active_support/core_ext/array/conversions.rb +24 -20
  26. data/lib/active_support/core_ext/array/extract.rb +21 -0
  27. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  28. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  29. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  30. data/lib/active_support/core_ext/array/prepend_and_append.rb +4 -6
  31. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  32. data/lib/active_support/core_ext/array.rb +9 -6
  33. data/lib/active_support/core_ext/benchmark.rb +3 -1
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +45 -31
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +20 -6
  39. data/lib/active_support/core_ext/class.rb +4 -3
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +14 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +17 -14
  43. data/lib/active_support/core_ext/date/conversions.rb +25 -23
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +6 -4
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +154 -65
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -13
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  50. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +37 -19
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
  53. data/lib/active_support/core_ext/date_time/conversions.rb +16 -13
  54. data/lib/active_support/core_ext/date_time.rb +7 -5
  55. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +114 -22
  58. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/compact.rb +4 -23
  61. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  62. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  63. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  64. data/lib/active_support/core_ext/hash/except.rb +12 -9
  65. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  66. data/lib/active_support/core_ext/hash/keys.rb +19 -42
  67. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  68. data/lib/active_support/core_ext/hash/slice.rb +5 -27
  69. data/lib/active_support/core_ext/hash/transform_values.rb +4 -22
  70. data/lib/active_support/core_ext/hash.rb +10 -9
  71. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  72. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  73. data/lib/active_support/core_ext/integer/time.rb +11 -18
  74. data/lib/active_support/core_ext/integer.rb +5 -3
  75. data/lib/active_support/core_ext/kernel/concern.rb +5 -1
  76. data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
  77. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  78. data/lib/active_support/core_ext/kernel.rb +5 -5
  79. data/lib/active_support/core_ext/load_error.rb +3 -22
  80. data/lib/active_support/core_ext/marshal.rb +8 -8
  81. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  82. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  83. data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
  84. data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -46
  85. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  86. data/lib/active_support/core_ext/module/concerning.rb +11 -12
  87. data/lib/active_support/core_ext/module/delegation.rb +133 -30
  88. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  89. data/lib/active_support/core_ext/module/introspection.rb +44 -19
  90. data/lib/active_support/core_ext/module/reachable.rb +5 -7
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  93. data/lib/active_support/core_ext/module.rb +13 -11
  94. data/lib/active_support/core_ext/name_error.rb +22 -2
  95. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +129 -136
  97. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  99. data/lib/active_support/core_ext/numeric.rb +5 -3
  100. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  101. data/lib/active_support/core_ext/object/blank.rb +27 -3
  102. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  103. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  104. data/lib/active_support/core_ext/object/duplicable.rb +13 -93
  105. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  106. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  107. data/lib/active_support/core_ext/object/json.rb +51 -20
  108. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  109. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  110. data/lib/active_support/core_ext/object/try.rb +81 -23
  111. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  112. data/lib/active_support/core_ext/object.rb +14 -13
  113. data/lib/active_support/core_ext/range/compare_range.rb +76 -0
  114. data/lib/active_support/core_ext/range/conversions.rb +37 -15
  115. data/lib/active_support/core_ext/range/each.rb +18 -17
  116. data/lib/active_support/core_ext/range/include_range.rb +7 -21
  117. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  118. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  119. data/lib/active_support/core_ext/range.rb +7 -4
  120. data/lib/active_support/core_ext/regexp.rb +2 -0
  121. data/lib/active_support/core_ext/securerandom.rb +45 -0
  122. data/lib/active_support/core_ext/string/access.rb +16 -6
  123. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  124. data/lib/active_support/core_ext/string/conversions.rb +7 -4
  125. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  126. data/lib/active_support/core_ext/string/filters.rb +48 -6
  127. data/lib/active_support/core_ext/string/indent.rb +6 -4
  128. data/lib/active_support/core_ext/string/inflections.rb +66 -24
  129. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  130. data/lib/active_support/core_ext/string/multibyte.rb +16 -7
  131. data/lib/active_support/core_ext/string/output_safety.rb +93 -40
  132. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  133. data/lib/active_support/core_ext/string/strip.rb +6 -5
  134. data/lib/active_support/core_ext/string/zones.rb +4 -2
  135. data/lib/active_support/core_ext/string.rb +15 -13
  136. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  137. data/lib/active_support/core_ext/time/calculations.rb +115 -52
  138. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  139. data/lib/active_support/core_ext/time/conversions.rb +20 -13
  140. data/lib/active_support/core_ext/time/zones.rb +41 -7
  141. data/lib/active_support/core_ext/time.rb +7 -6
  142. data/lib/active_support/core_ext/uri.rb +6 -7
  143. data/lib/active_support/core_ext.rb +3 -1
  144. data/lib/active_support/current_attributes.rb +203 -0
  145. data/lib/active_support/dependencies/autoload.rb +2 -0
  146. data/lib/active_support/dependencies/interlock.rb +57 -0
  147. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  148. data/lib/active_support/dependencies.rb +208 -166
  149. data/lib/active_support/deprecation/behaviors.rb +44 -11
  150. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  151. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  152. data/lib/active_support/deprecation/method_wrappers.rb +61 -21
  153. data/lib/active_support/deprecation/proxy_wrappers.rb +81 -30
  154. data/lib/active_support/deprecation/reporting.rb +32 -12
  155. data/lib/active_support/deprecation.rb +12 -9
  156. data/lib/active_support/descendants_tracker.rb +57 -9
  157. data/lib/active_support/digest.rb +20 -0
  158. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  159. data/lib/active_support/duration/iso8601_serializer.rb +53 -0
  160. data/lib/active_support/duration.rb +315 -40
  161. data/lib/active_support/encrypted_configuration.rb +45 -0
  162. data/lib/active_support/encrypted_file.rb +100 -0
  163. data/lib/active_support/evented_file_update_checker.rb +234 -0
  164. data/lib/active_support/execution_wrapper.rb +129 -0
  165. data/lib/active_support/executor.rb +8 -0
  166. data/lib/active_support/file_update_checker.rb +62 -37
  167. data/lib/active_support/gem_version.rb +6 -4
  168. data/lib/active_support/gzip.rb +7 -5
  169. data/lib/active_support/hash_with_indifferent_access.rb +129 -30
  170. data/lib/active_support/i18n.rb +9 -6
  171. data/lib/active_support/i18n_railtie.rb +50 -14
  172. data/lib/active_support/inflections.rb +13 -11
  173. data/lib/active_support/inflector/inflections.rb +58 -13
  174. data/lib/active_support/inflector/methods.rb +159 -145
  175. data/lib/active_support/inflector/transliterate.rb +84 -34
  176. data/lib/active_support/inflector.rb +7 -5
  177. data/lib/active_support/json/decoding.rb +32 -30
  178. data/lib/active_support/json/encoding.rb +17 -60
  179. data/lib/active_support/json.rb +4 -2
  180. data/lib/active_support/key_generator.rb +11 -43
  181. data/lib/active_support/lazy_load_hooks.rb +53 -20
  182. data/lib/active_support/locale/en.rb +33 -0
  183. data/lib/active_support/locale/en.yml +2 -0
  184. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  185. data/lib/active_support/log_subscriber.rb +44 -19
  186. data/lib/active_support/logger.rb +9 -23
  187. data/lib/active_support/logger_silence.rb +32 -14
  188. data/lib/active_support/logger_thread_safe_level.rb +32 -8
  189. data/lib/active_support/message_encryptor.rb +166 -53
  190. data/lib/active_support/message_verifier.rb +149 -16
  191. data/lib/active_support/messages/metadata.rb +72 -0
  192. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  193. data/lib/active_support/messages/rotator.rb +56 -0
  194. data/lib/active_support/multibyte/chars.rb +56 -63
  195. data/lib/active_support/multibyte/unicode.rb +56 -290
  196. data/lib/active_support/multibyte.rb +4 -2
  197. data/lib/active_support/notifications/fanout.rb +109 -22
  198. data/lib/active_support/notifications/instrumenter.rb +107 -16
  199. data/lib/active_support/notifications.rb +51 -10
  200. data/lib/active_support/number_helper/number_converter.rb +16 -15
  201. data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -15
  202. data/lib/active_support/number_helper/number_to_delimited_converter.rb +11 -4
  203. data/lib/active_support/number_helper/number_to_human_converter.rb +13 -10
  204. data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -9
  205. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  206. data/lib/active_support/number_helper/number_to_phone_converter.rb +15 -5
  207. data/lib/active_support/number_helper/number_to_rounded_converter.rb +25 -57
  208. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  209. data/lib/active_support/number_helper.rb +105 -68
  210. data/lib/active_support/option_merger.rb +24 -4
  211. data/lib/active_support/ordered_hash.rb +7 -5
  212. data/lib/active_support/ordered_options.rb +27 -5
  213. data/lib/active_support/parameter_filter.rb +128 -0
  214. data/lib/active_support/per_thread_registry.rb +9 -4
  215. data/lib/active_support/proxy_object.rb +2 -0
  216. data/lib/active_support/rails.rb +10 -8
  217. data/lib/active_support/railtie.rb +43 -9
  218. data/lib/active_support/reloader.rb +130 -0
  219. data/lib/active_support/rescuable.rb +108 -53
  220. data/lib/active_support/security_utils.rb +15 -11
  221. data/lib/active_support/string_inquirer.rb +11 -4
  222. data/lib/active_support/subscriber.rb +74 -30
  223. data/lib/active_support/tagged_logging.rb +25 -13
  224. data/lib/active_support/test_case.rb +107 -44
  225. data/lib/active_support/testing/assertions.rb +151 -20
  226. data/lib/active_support/testing/autorun.rb +4 -2
  227. data/lib/active_support/testing/constant_lookup.rb +2 -1
  228. data/lib/active_support/testing/declarative.rb +3 -1
  229. data/lib/active_support/testing/deprecation.rb +13 -10
  230. data/lib/active_support/testing/file_fixtures.rb +38 -0
  231. data/lib/active_support/testing/isolation.rb +35 -26
  232. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  233. data/lib/active_support/testing/parallelization.rb +134 -0
  234. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  235. data/lib/active_support/testing/stream.rb +43 -0
  236. data/lib/active_support/testing/tagged_logging.rb +3 -1
  237. data/lib/active_support/testing/time_helpers.rb +84 -20
  238. data/lib/active_support/time.rb +14 -12
  239. data/lib/active_support/time_with_zone.rb +179 -39
  240. data/lib/active_support/values/time_zone.rb +203 -63
  241. data/lib/active_support/version.rb +3 -1
  242. data/lib/active_support/xml_mini/jdom.rb +116 -115
  243. data/lib/active_support/xml_mini/libxml.rb +16 -13
  244. data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
  245. data/lib/active_support/xml_mini/nokogiri.rb +14 -12
  246. data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
  247. data/lib/active_support/xml_mini/rexml.rb +11 -9
  248. data/lib/active_support/xml_mini.rb +38 -46
  249. data/lib/active_support.rb +13 -11
  250. metadata +84 -26
  251. data/lib/active_support/concurrency/latch.rb +0 -27
  252. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  253. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  254. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  255. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  256. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  257. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  258. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  259. data/lib/active_support/core_ext/object/itself.rb +0 -15
  260. data/lib/active_support/core_ext/struct.rb +0 -6
  261. data/lib/active_support/core_ext/thread.rb +0 -86
  262. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  263. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,23 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/try"
4
+
1
5
  module DateAndTime
2
6
  module Calculations
3
7
  DAYS_INTO_WEEK = {
4
- :monday => 0,
5
- :tuesday => 1,
6
- :wednesday => 2,
7
- :thursday => 3,
8
- :friday => 4,
9
- :saturday => 5,
10
- :sunday => 6
8
+ sunday: 0,
9
+ monday: 1,
10
+ tuesday: 2,
11
+ wednesday: 3,
12
+ thursday: 4,
13
+ friday: 5,
14
+ saturday: 6
11
15
  }
16
+ WEEKEND_DAYS = [ 6, 0 ]
12
17
 
13
18
  # Returns a new date/time representing yesterday.
14
19
  def yesterday
15
- advance(:days => -1)
20
+ advance(days: -1)
16
21
  end
17
22
 
18
23
  # Returns a new date/time representing tomorrow.
19
24
  def tomorrow
20
- advance(:days => 1)
25
+ advance(days: 1)
21
26
  end
22
27
 
23
28
  # Returns true if the date/time is today.
@@ -35,76 +40,121 @@ module DateAndTime
35
40
  self > self.class.current
36
41
  end
37
42
 
43
+ # Returns true if the date/time falls on a Saturday or Sunday.
44
+ def on_weekend?
45
+ WEEKEND_DAYS.include?(wday)
46
+ end
47
+
48
+ # Returns true if the date/time does not fall on a Saturday or Sunday.
49
+ def on_weekday?
50
+ !WEEKEND_DAYS.include?(wday)
51
+ end
52
+
53
+ # Returns true if the date/time falls before <tt>date_or_time</tt>.
54
+ def before?(date_or_time)
55
+ self < date_or_time
56
+ end
57
+
58
+ # Returns true if the date/time falls after <tt>date_or_time</tt>.
59
+ def after?(date_or_time)
60
+ self > date_or_time
61
+ end
62
+
38
63
  # Returns a new date/time the specified number of days ago.
39
64
  def days_ago(days)
40
- advance(:days => -days)
65
+ advance(days: -days)
41
66
  end
42
67
 
43
68
  # Returns a new date/time the specified number of days in the future.
44
69
  def days_since(days)
45
- advance(:days => days)
70
+ advance(days: days)
46
71
  end
47
72
 
48
73
  # Returns a new date/time the specified number of weeks ago.
49
74
  def weeks_ago(weeks)
50
- advance(:weeks => -weeks)
75
+ advance(weeks: -weeks)
51
76
  end
52
77
 
53
78
  # Returns a new date/time the specified number of weeks in the future.
54
79
  def weeks_since(weeks)
55
- advance(:weeks => weeks)
80
+ advance(weeks: weeks)
56
81
  end
57
82
 
58
83
  # Returns a new date/time the specified number of months ago.
59
84
  def months_ago(months)
60
- advance(:months => -months)
85
+ advance(months: -months)
61
86
  end
62
87
 
63
88
  # Returns a new date/time the specified number of months in the future.
64
89
  def months_since(months)
65
- advance(:months => months)
90
+ advance(months: months)
66
91
  end
67
92
 
68
93
  # Returns a new date/time the specified number of years ago.
69
94
  def years_ago(years)
70
- advance(:years => -years)
95
+ advance(years: -years)
71
96
  end
72
97
 
73
98
  # Returns a new date/time the specified number of years in the future.
74
99
  def years_since(years)
75
- advance(:years => years)
100
+ advance(years: years)
76
101
  end
77
102
 
78
103
  # Returns a new date/time at the start of the month.
79
- # DateTime objects will have a time set to 0:00.
104
+ #
105
+ # today = Date.today # => Thu, 18 Jun 2015
106
+ # today.beginning_of_month # => Mon, 01 Jun 2015
107
+ #
108
+ # +DateTime+ objects will have a time set to 0:00.
109
+ #
110
+ # now = DateTime.current # => Thu, 18 Jun 2015 15:23:13 +0000
111
+ # now.beginning_of_month # => Mon, 01 Jun 2015 00:00:00 +0000
80
112
  def beginning_of_month
81
- first_hour(change(:day => 1))
113
+ first_hour(change(day: 1))
82
114
  end
83
115
  alias :at_beginning_of_month :beginning_of_month
84
116
 
85
117
  # Returns a new date/time at the start of the quarter.
86
- # Example: 1st January, 1st July, 1st October.
87
- # DateTime objects will have a time set to 0:00.
118
+ #
119
+ # today = Date.today # => Fri, 10 Jul 2015
120
+ # today.beginning_of_quarter # => Wed, 01 Jul 2015
121
+ #
122
+ # +DateTime+ objects will have a time set to 0:00.
123
+ #
124
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
125
+ # now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000
88
126
  def beginning_of_quarter
89
- first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month }
90
- beginning_of_month.change(:month => first_quarter_month)
127
+ first_quarter_month = month - (2 + month) % 3
128
+ beginning_of_month.change(month: first_quarter_month)
91
129
  end
92
130
  alias :at_beginning_of_quarter :beginning_of_quarter
93
131
 
94
132
  # Returns a new date/time at the end of the quarter.
95
- # Example: 31st March, 30th June, 30th September.
96
- # DateTime objects will have a time set to 23:59:59.
133
+ #
134
+ # today = Date.today # => Fri, 10 Jul 2015
135
+ # today.end_of_quarter # => Wed, 30 Sep 2015
136
+ #
137
+ # +DateTime+ objects will have a time set to 23:59:59.
138
+ #
139
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
140
+ # now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000
97
141
  def end_of_quarter
98
- last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month }
99
- beginning_of_month.change(:month => last_quarter_month).end_of_month
142
+ last_quarter_month = month + (12 - month) % 3
143
+ beginning_of_month.change(month: last_quarter_month).end_of_month
100
144
  end
101
145
  alias :at_end_of_quarter :end_of_quarter
102
146
 
103
- # Return a new date/time at the beginning of the year.
104
- # Example: 1st January.
105
- # DateTime objects will have a time set to 0:00.
147
+ # Returns a new date/time at the beginning of the year.
148
+ #
149
+ # today = Date.today # => Fri, 10 Jul 2015
150
+ # today.beginning_of_year # => Thu, 01 Jan 2015
151
+ #
152
+ # +DateTime+ objects will have a time set to 0:00.
153
+ #
154
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
155
+ # now.beginning_of_year # => Thu, 01 Jan 2015 00:00:00 +0000
106
156
  def beginning_of_year
107
- change(:month => 1).beginning_of_month
157
+ change(month: 1).beginning_of_month
108
158
  end
109
159
  alias :at_beginning_of_year :beginning_of_year
110
160
 
@@ -115,21 +165,27 @@ module DateAndTime
115
165
  #
116
166
  # The +given_day_in_next_week+ defaults to the beginning of the week
117
167
  # which is determined by +Date.beginning_of_week+ or +config.beginning_of_week+
168
+ # when set.
118
169
  #
119
170
  # today = Date.today # => Thu, 07 May 2015
120
171
  # today.next_week(:friday) # => Fri, 15 May 2015
121
172
  #
122
- # when set. +DateTime+ objects have their time set to 0:00.
173
+ # +DateTime+ objects have their time set to 0:00 unless +same_time+ is true.
123
174
  #
124
- # now = Time.current # => Thu, 07 May 2015 13:31:16 UTC +00:00
125
- # now.next_week # => Mon, 11 May 2015 00:00:00 UTC +00:00
126
- def next_week(given_day_in_next_week = Date.beginning_of_week)
127
- first_hour(weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week)))
175
+ # now = DateTime.current # => Thu, 07 May 2015 13:31:16 +0000
176
+ # now.next_week # => Mon, 11 May 2015 00:00:00 +0000
177
+ def next_week(given_day_in_next_week = Date.beginning_of_week, same_time: false)
178
+ result = first_hour(weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week)))
179
+ same_time ? copy_time_to(result) : result
128
180
  end
129
181
 
130
- # Short-hand for months_since(1).
131
- def next_month
132
- months_since(1)
182
+ # Returns a new date/time representing the next weekday.
183
+ def next_weekday
184
+ if next_day.on_weekend?
185
+ next_week(:monday, same_time: true)
186
+ else
187
+ next_day
188
+ end
133
189
  end
134
190
 
135
191
  # Short-hand for months_since(3)
@@ -137,25 +193,30 @@ module DateAndTime
137
193
  months_since(3)
138
194
  end
139
195
 
140
- # Short-hand for years_since(1).
141
- def next_year
142
- years_since(1)
143
- end
144
-
145
196
  # Returns a new date/time representing the given day in the previous week.
146
197
  # Week is assumed to start on +start_day+, default is
147
198
  # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
148
- # DateTime objects have their time set to 0:00.
149
- def prev_week(start_day = Date.beginning_of_week)
150
- first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day)))
199
+ # DateTime objects have their time set to 0:00 unless +same_time+ is true.
200
+ def prev_week(start_day = Date.beginning_of_week, same_time: false)
201
+ result = first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day)))
202
+ same_time ? copy_time_to(result) : result
151
203
  end
152
204
  alias_method :last_week, :prev_week
153
205
 
206
+ # Returns a new date/time representing the previous weekday.
207
+ def prev_weekday
208
+ if prev_day.on_weekend?
209
+ copy_time_to(beginning_of_week(:friday))
210
+ else
211
+ prev_day
212
+ end
213
+ end
214
+ alias_method :last_weekday, :prev_weekday
215
+
154
216
  # Short-hand for months_ago(1).
155
- def prev_month
217
+ def last_month
156
218
  months_ago(1)
157
219
  end
158
- alias_method :last_month, :prev_month
159
220
 
160
221
  # Short-hand for months_ago(3).
161
222
  def prev_quarter
@@ -164,18 +225,16 @@ module DateAndTime
164
225
  alias_method :last_quarter, :prev_quarter
165
226
 
166
227
  # Short-hand for years_ago(1).
167
- def prev_year
228
+ def last_year
168
229
  years_ago(1)
169
230
  end
170
- alias_method :last_year, :prev_year
171
231
 
172
232
  # Returns the number of days to the start of the week on the given day.
173
233
  # Week is assumed to start on +start_day+, default is
174
234
  # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
175
235
  def days_to_week_start(start_day = Date.beginning_of_week)
176
- start_day_number = DAYS_INTO_WEEK[start_day]
177
- current_day_number = wday != 0 ? wday - 1 : 6
178
- (current_day_number - start_day_number) % 7
236
+ start_day_number = DAYS_INTO_WEEK.fetch(start_day)
237
+ (wday - start_day_number) % 7
179
238
  end
180
239
 
181
240
  # Returns a new date/time representing the start of this week on the given day.
@@ -220,12 +279,17 @@ module DateAndTime
220
279
  # Returns a new date/time representing the end of the year.
221
280
  # DateTime objects will have a time set to 23:59:59.
222
281
  def end_of_year
223
- change(:month => 12).end_of_month
282
+ change(month: 12).end_of_month
224
283
  end
225
284
  alias :at_end_of_year :end_of_year
226
285
 
286
+ # Returns a Range representing the whole day of the current date/time.
287
+ def all_day
288
+ beginning_of_day..end_of_day
289
+ end
290
+
227
291
  # Returns a Range representing the whole week of the current date/time.
228
- # Week starts on start_day, default is <tt>Date.week_start</tt> or <tt>config.week_start</tt> when set.
292
+ # Week starts on start_day, default is <tt>Date.beginning_of_week</tt> or <tt>config.beginning_of_week</tt> when set.
229
293
  def all_week(start_day = Date.beginning_of_week)
230
294
  beginning_of_week(start_day)..end_of_week(start_day)
231
295
  end
@@ -245,18 +309,43 @@ module DateAndTime
245
309
  beginning_of_year..end_of_year
246
310
  end
247
311
 
248
- private
249
-
250
- def first_hour(date_or_time)
251
- date_or_time.acts_like?(:time) ? date_or_time.beginning_of_day : date_or_time
312
+ # Returns a new date/time representing the next occurrence of the specified day of week.
313
+ #
314
+ # today = Date.today # => Thu, 14 Dec 2017
315
+ # today.next_occurring(:monday) # => Mon, 18 Dec 2017
316
+ # today.next_occurring(:thursday) # => Thu, 21 Dec 2017
317
+ def next_occurring(day_of_week)
318
+ from_now = DAYS_INTO_WEEK.fetch(day_of_week) - wday
319
+ from_now += 7 unless from_now > 0
320
+ advance(days: from_now)
252
321
  end
253
322
 
254
- def last_hour(date_or_time)
255
- date_or_time.acts_like?(:time) ? date_or_time.end_of_day : date_or_time
323
+ # Returns a new date/time representing the previous occurrence of the specified day of week.
324
+ #
325
+ # today = Date.today # => Thu, 14 Dec 2017
326
+ # today.prev_occurring(:monday) # => Mon, 11 Dec 2017
327
+ # today.prev_occurring(:thursday) # => Thu, 07 Dec 2017
328
+ def prev_occurring(day_of_week)
329
+ ago = wday - DAYS_INTO_WEEK.fetch(day_of_week)
330
+ ago += 7 unless ago > 0
331
+ advance(days: -ago)
256
332
  end
257
333
 
258
- def days_span(day)
259
- (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7
260
- end
334
+ private
335
+ def first_hour(date_or_time)
336
+ date_or_time.acts_like?(:time) ? date_or_time.beginning_of_day : date_or_time
337
+ end
338
+
339
+ def last_hour(date_or_time)
340
+ date_or_time.acts_like?(:time) ? date_or_time.end_of_day : date_or_time
341
+ end
342
+
343
+ def days_span(day)
344
+ (DAYS_INTO_WEEK.fetch(day) - DAYS_INTO_WEEK.fetch(Date.beginning_of_week)) % 7
345
+ end
346
+
347
+ def copy_time_to(other)
348
+ other.change(hour: hour, min: min, sec: sec, nsec: try(:nsec))
349
+ end
261
350
  end
262
351
  end
@@ -1,5 +1,6 @@
1
- require 'active_support/core_ext/module/attribute_accessors'
2
- require 'active_support/core_ext/module/remove_method'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/attribute_accessors"
3
4
 
4
5
  module DateAndTime
5
6
  module Compatibility
@@ -10,6 +11,6 @@ module DateAndTime
10
11
  # of the receiver. For backwards compatibility we're overriding
11
12
  # this behavior, but new apps will have an initializer that sets
12
13
  # this to true, because the new behavior is preferred.
13
- mattr_accessor(:preserve_timezone, instance_writer: false) { false }
14
+ mattr_accessor :preserve_timezone, instance_writer: false, default: false
14
15
  end
15
16
  end
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DateAndTime
2
4
  module Zones
3
5
  # Returns the simultaneous time in <tt>Time.zone</tt> if a zone is given or
4
6
  # if Time.zone_default is set. Otherwise, it returns the current time.
5
7
  #
6
8
  # Time.zone = 'Hawaii' # => 'Hawaii'
7
- # DateTime.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
8
- # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00
9
+ # Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
10
+ # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00
9
11
  #
10
12
  # This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone
11
13
  # instead of the operating system's time zone.
@@ -14,8 +16,7 @@ module DateAndTime
14
16
  # and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
15
17
  #
16
18
  # Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
17
- # DateTime.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
18
- # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00
19
+ # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00
19
20
  def in_time_zone(zone = ::Time.zone)
20
21
  time_zone = ::Time.find_zone! zone
21
22
  time = acts_like?(:time) ? self : nil
@@ -23,19 +24,17 @@ module DateAndTime
23
24
  if time_zone
24
25
  time_with_zone(time, time_zone)
25
26
  else
26
- time || self.to_time
27
+ time || to_time
27
28
  end
28
29
  end
29
30
 
30
31
  private
31
-
32
- def time_with_zone(time, zone)
33
- if time
34
- ActiveSupport::TimeWithZone.new(time.utc? ? time : time.getutc, zone)
35
- else
36
- ActiveSupport::TimeWithZone.new(nil, zone, to_time(:utc))
32
+ def time_with_zone(time, zone)
33
+ if time
34
+ ActiveSupport::TimeWithZone.new(time.utc? ? time : time.getutc, zone)
35
+ else
36
+ ActiveSupport::TimeWithZone.new(nil, zone, to_time(:utc))
37
+ end
37
38
  end
38
- end
39
39
  end
40
40
  end
41
-
@@ -1,5 +1,7 @@
1
- require 'date'
2
- require 'active_support/core_ext/object/acts_like'
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "active_support/core_ext/object/acts_like"
3
5
 
4
6
  class DateTime
5
7
  # Duck-types as a Date-like class. See Object#acts_like?.
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+
5
+ class DateTime #:nodoc:
6
+ # No DateTime is ever blank:
7
+ #
8
+ # DateTime.now.blank? # => false
9
+ #
10
+ # @return [false]
11
+ def blank?
12
+ false
13
+ end
14
+ end
@@ -1,4 +1,6 @@
1
- require 'date'
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
2
4
 
3
5
  class DateTime
4
6
  class << self
@@ -10,7 +12,11 @@ class DateTime
10
12
  end
11
13
  end
12
14
 
13
- # Seconds since midnight: DateTime.now.seconds_since_midnight.
15
+ # Returns the number of seconds since 00:00:00.
16
+ #
17
+ # DateTime.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0
18
+ # DateTime.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296
19
+ # DateTime.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399
14
20
  def seconds_since_midnight
15
21
  sec + (min * 60) + (hour * 3600)
16
22
  end
@@ -43,13 +49,23 @@ class DateTime
43
49
  # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => DateTime.new(1981, 8, 1, 22, 35, 0)
44
50
  # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => DateTime.new(1981, 8, 29, 0, 0, 0)
45
51
  def change(options)
52
+ if new_nsec = options[:nsec]
53
+ raise ArgumentError, "Can't change both :nsec and :usec at the same time: #{options.inspect}" if options[:usec]
54
+ new_fraction = Rational(new_nsec, 1000000000)
55
+ else
56
+ new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
57
+ new_fraction = Rational(new_usec, 1000000)
58
+ end
59
+
60
+ raise ArgumentError, "argument out of range" if new_fraction >= 1
61
+
46
62
  ::DateTime.civil(
47
63
  options.fetch(:year, year),
48
64
  options.fetch(:month, month),
49
65
  options.fetch(:day, day),
50
66
  options.fetch(:hour, hour),
51
67
  options.fetch(:min, options[:hour] ? 0 : min),
52
- options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec + sec_fraction),
68
+ options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec) + new_fraction,
53
69
  options.fetch(:offset, offset),
54
70
  options.fetch(:start, start)
55
71
  )
@@ -71,7 +87,7 @@ class DateTime
71
87
  end
72
88
 
73
89
  d = to_date.advance(options)
74
- datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
90
+ datetime_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
75
91
  seconds_to_advance = \
76
92
  options.fetch(:seconds, 0) +
77
93
  options.fetch(:minutes, 0) * 60 +
@@ -94,13 +110,13 @@ class DateTime
94
110
  # instance time. Do not use this method in combination with x.months, use
95
111
  # months_since instead!
96
112
  def since(seconds)
97
- self + Rational(seconds.round, 86400)
113
+ self + Rational(seconds, 86400)
98
114
  end
99
115
  alias :in :since
100
116
 
101
117
  # Returns a new DateTime representing the start of the day (0:00).
102
118
  def beginning_of_day
103
- change(:hour => 0)
119
+ change(hour: 0)
104
120
  end
105
121
  alias :midnight :beginning_of_day
106
122
  alias :at_midnight :beginning_of_day
@@ -108,7 +124,7 @@ class DateTime
108
124
 
109
125
  # Returns a new DateTime representing the middle of the day (12:00)
110
126
  def middle_of_day
111
- change(:hour => 12)
127
+ change(hour: 12)
112
128
  end
113
129
  alias :midday :middle_of_day
114
130
  alias :noon :middle_of_day
@@ -118,31 +134,31 @@ class DateTime
118
134
 
119
135
  # Returns a new DateTime representing the end of the day (23:59:59).
120
136
  def end_of_day
121
- change(:hour => 23, :min => 59, :sec => 59)
137
+ change(hour: 23, min: 59, sec: 59, usec: Rational(999999999, 1000))
122
138
  end
123
139
  alias :at_end_of_day :end_of_day
124
140
 
125
141
  # Returns a new DateTime representing the start of the hour (hh:00:00).
126
142
  def beginning_of_hour
127
- change(:min => 0)
143
+ change(min: 0)
128
144
  end
129
145
  alias :at_beginning_of_hour :beginning_of_hour
130
146
 
131
147
  # Returns a new DateTime representing the end of the hour (hh:59:59).
132
148
  def end_of_hour
133
- change(:min => 59, :sec => 59)
149
+ change(min: 59, sec: 59, usec: Rational(999999999, 1000))
134
150
  end
135
151
  alias :at_end_of_hour :end_of_hour
136
152
 
137
153
  # Returns a new DateTime representing the start of the minute (hh:mm:00).
138
154
  def beginning_of_minute
139
- change(:sec => 0)
155
+ change(sec: 0)
140
156
  end
141
157
  alias :at_beginning_of_minute :beginning_of_minute
142
158
 
143
159
  # Returns a new DateTime representing the end of the minute (hh:mm:59).
144
160
  def end_of_minute
145
- change(:sec => 59)
161
+ change(sec: 59, usec: Rational(999999999, 1000))
146
162
  end
147
163
  alias :at_end_of_minute :end_of_minute
148
164
 
@@ -157,12 +173,17 @@ class DateTime
157
173
  end
158
174
  alias_method :getlocal, :localtime
159
175
 
160
- # Returns a <tt>DateTime</tt> instance of the simultaneous time in the UTC timezone.
176
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
161
177
  #
162
178
  # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
163
179
  # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 UTC
164
180
  def utc
165
- new_offset(0)
181
+ utc = new_offset(0)
182
+
183
+ Time.utc(
184
+ utc.year, utc.month, utc.day,
185
+ utc.hour, utc.min, utc.sec + utc.sec_fraction
186
+ )
166
187
  end
167
188
  alias_method :getgm, :utc
168
189
  alias_method :getutc, :utc
@@ -181,13 +202,10 @@ class DateTime
181
202
  # Layers additional behavior on DateTime#<=> so that Time and
182
203
  # ActiveSupport::TimeWithZone instances can be compared with a DateTime.
183
204
  def <=>(other)
184
- if other.kind_of?(Infinity)
185
- super
186
- elsif other.respond_to? :to_datetime
205
+ if other.respond_to? :to_datetime
187
206
  super other.to_datetime rescue nil
188
207
  else
189
- nil
208
+ super
190
209
  end
191
210
  end
192
-
193
211
  end
@@ -1,14 +1,16 @@
1
- require 'active_support/core_ext/date_and_time/compatibility'
2
- require 'active_support/core_ext/module/remove_method'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/date_and_time/compatibility"
4
+ require "active_support/core_ext/module/redefine_method"
3
5
 
4
6
  class DateTime
5
7
  include DateAndTime::Compatibility
6
8
 
7
- remove_possible_method :to_time
9
+ silence_redefinition_of_method :to_time
8
10
 
9
- # Either return an instance of `Time` with the same UTC offset
10
- # as +self+ or an instance of `Time` representing the same time
11
- # in the the local system timezone depending on the setting of
11
+ # Either return an instance of +Time+ with the same UTC offset
12
+ # as +self+ or an instance of +Time+ representing the same time
13
+ # in the local system timezone depending on the setting of
12
14
  # on the setting of +ActiveSupport.to_time_preserves_timezone+.
13
15
  def to_time
14
16
  preserve_timezone ? getlocal(utc_offset) : getlocal
@@ -1,8 +1,10 @@
1
- require 'date'
2
- require 'active_support/inflector/methods'
3
- require 'active_support/core_ext/time/conversions'
4
- require 'active_support/core_ext/date_time/calculations'
5
- require 'active_support/values/time_zone'
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "active_support/inflector/methods"
5
+ require "active_support/core_ext/time/conversions"
6
+ require "active_support/core_ext/date_time/calculations"
7
+ require "active_support/values/time_zone"
6
8
 
7
9
  class DateTime
8
10
  # Convert to a formatted string. See Time::DATE_FORMATS for predefined formats.
@@ -40,6 +42,8 @@ class DateTime
40
42
  alias_method :to_default_s, :to_s if instance_methods(false).include?(:to_s)
41
43
  alias_method :to_s, :to_formatted_s
42
44
 
45
+ # Returns a formatted string of the offset from UTC, or an alternative
46
+ # string if the time zone is already UTC.
43
47
  #
44
48
  # datetime = DateTime.civil(2000, 1, 1, 0, 0, 0, Rational(-6, 24))
45
49
  # datetime.formatted_offset # => "-06:00"
@@ -62,7 +66,7 @@ class DateTime
62
66
  # # => Sun, 01 Jan 2012 00:00:00 +0300
63
67
  # DateTime.civil_from_format :local, 2012, 12, 17
64
68
  # # => Mon, 17 Dec 2012 00:00:00 +0000
65
- def self.civil_from_format(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0)
69
+ def self.civil_from_format(utc_or_local, year, month = 1, day = 1, hour = 0, min = 0, sec = 0)
66
70
  if utc_or_local.to_sym == :local
67
71
  offset = ::Time.local(year, month, day).utc_offset.to_r / 86400
68
72
  else
@@ -92,12 +96,11 @@ class DateTime
92
96
  end
93
97
 
94
98
  private
99
+ def offset_in_seconds
100
+ (offset * 86400).to_i
101
+ end
95
102
 
96
- def offset_in_seconds
97
- (offset * 86400).to_i
98
- end
99
-
100
- def seconds_since_unix_epoch
101
- (jd - 2440588) * 86400 - offset_in_seconds + seconds_since_midnight
102
- end
103
+ def seconds_since_unix_epoch
104
+ (jd - 2440588) * 86400 - offset_in_seconds + seconds_since_midnight
105
+ end
103
106
  end