activesupport 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +572 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support.rb +96 -0
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/all.rb +5 -0
  8. data/lib/active_support/array_inquirer.rb +48 -0
  9. data/lib/active_support/backtrace_cleaner.rb +132 -0
  10. data/lib/active_support/benchmarkable.rb +51 -0
  11. data/lib/active_support/builder.rb +8 -0
  12. data/lib/active_support/cache.rb +830 -0
  13. data/lib/active_support/cache/file_store.rb +196 -0
  14. data/lib/active_support/cache/mem_cache_store.rb +212 -0
  15. data/lib/active_support/cache/memory_store.rb +174 -0
  16. data/lib/active_support/cache/null_store.rb +48 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +488 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +194 -0
  19. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  20. data/lib/active_support/callbacks.rb +856 -0
  21. data/lib/active_support/concern.rb +171 -0
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  23. data/lib/active_support/concurrency/share_lock.rb +227 -0
  24. data/lib/active_support/configurable.rb +146 -0
  25. data/lib/active_support/core_ext.rb +5 -0
  26. data/lib/active_support/core_ext/array.rb +9 -0
  27. data/lib/active_support/core_ext/array/access.rb +104 -0
  28. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
  34. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  35. data/lib/active_support/core_ext/benchmark.rb +16 -0
  36. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  37. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  38. data/lib/active_support/core_ext/class.rb +4 -0
  39. data/lib/active_support/core_ext/class/attribute.rb +141 -0
  40. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  41. data/lib/active_support/core_ext/class/subclasses.rb +54 -0
  42. data/lib/active_support/core_ext/date.rb +7 -0
  43. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  44. data/lib/active_support/core_ext/date/blank.rb +14 -0
  45. data/lib/active_support/core_ext/date/calculations.rb +146 -0
  46. data/lib/active_support/core_ext/date/conversions.rb +96 -0
  47. data/lib/active_support/core_ext/date/zones.rb +8 -0
  48. data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
  49. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  50. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  51. data/lib/active_support/core_ext/date_time.rb +7 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
  57. data/lib/active_support/core_ext/digest.rb +3 -0
  58. data/lib/active_support/core_ext/digest/uuid.rb +53 -0
  59. data/lib/active_support/core_ext/enumerable.rb +188 -0
  60. data/lib/active_support/core_ext/file.rb +3 -0
  61. data/lib/active_support/core_ext/file/atomic.rb +70 -0
  62. data/lib/active_support/core_ext/hash.rb +10 -0
  63. data/lib/active_support/core_ext/hash/compact.rb +5 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +263 -0
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +24 -0
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  69. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  71. data/lib/active_support/core_ext/hash/slice.rb +26 -0
  72. data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
  73. data/lib/active_support/core_ext/integer.rb +5 -0
  74. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  75. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  76. data/lib/active_support/core_ext/integer/time.rb +22 -0
  77. data/lib/active_support/core_ext/kernel.rb +5 -0
  78. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  79. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  80. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  81. data/lib/active_support/core_ext/load_error.rb +9 -0
  82. data/lib/active_support/core_ext/marshal.rb +24 -0
  83. data/lib/active_support/core_ext/module.rb +13 -0
  84. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  85. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  86. data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
  87. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  88. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  89. data/lib/active_support/core_ext/module/concerning.rb +134 -0
  90. data/lib/active_support/core_ext/module/delegation.rb +313 -0
  91. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  92. data/lib/active_support/core_ext/module/introspection.rb +86 -0
  93. data/lib/active_support/core_ext/module/reachable.rb +6 -0
  94. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  95. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  96. data/lib/active_support/core_ext/name_error.rb +38 -0
  97. data/lib/active_support/core_ext/numeric.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
  99. data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
  100. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  101. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  102. data/lib/active_support/core_ext/object.rb +16 -0
  103. data/lib/active_support/core_ext/object/acts_like.rb +21 -0
  104. data/lib/active_support/core_ext/object/blank.rb +155 -0
  105. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  106. data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
  107. data/lib/active_support/core_ext/object/duplicable.rb +49 -0
  108. data/lib/active_support/core_ext/object/inclusion.rb +29 -0
  109. data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
  110. data/lib/active_support/core_ext/object/json.rb +228 -0
  111. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  112. data/lib/active_support/core_ext/object/to_query.rb +89 -0
  113. data/lib/active_support/core_ext/object/try.rb +156 -0
  114. data/lib/active_support/core_ext/object/with_options.rb +82 -0
  115. data/lib/active_support/core_ext/range.rb +7 -0
  116. data/lib/active_support/core_ext/range/compare_range.rb +70 -0
  117. data/lib/active_support/core_ext/range/conversions.rb +41 -0
  118. data/lib/active_support/core_ext/range/each.rb +25 -0
  119. data/lib/active_support/core_ext/range/include_range.rb +9 -0
  120. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  121. data/lib/active_support/core_ext/range/overlaps.rb +10 -0
  122. data/lib/active_support/core_ext/regexp.rb +7 -0
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string.rb +15 -0
  125. data/lib/active_support/core_ext/string/access.rb +114 -0
  126. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  127. data/lib/active_support/core_ext/string/conversions.rb +59 -0
  128. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  129. data/lib/active_support/core_ext/string/filters.rb +145 -0
  130. data/lib/active_support/core_ext/string/indent.rb +45 -0
  131. data/lib/active_support/core_ext/string/inflections.rb +259 -0
  132. data/lib/active_support/core_ext/string/inquiry.rb +15 -0
  133. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  134. data/lib/active_support/core_ext/string/output_safety.rb +314 -0
  135. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  136. data/lib/active_support/core_ext/string/strip.rb +27 -0
  137. data/lib/active_support/core_ext/string/zones.rb +16 -0
  138. data/lib/active_support/core_ext/time.rb +7 -0
  139. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  140. data/lib/active_support/core_ext/time/calculations.rb +344 -0
  141. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  142. data/lib/active_support/core_ext/time/conversions.rb +72 -0
  143. data/lib/active_support/core_ext/time/zones.rb +113 -0
  144. data/lib/active_support/core_ext/uri.rb +25 -0
  145. data/lib/active_support/current_attributes.rb +203 -0
  146. data/lib/active_support/dependencies.rb +806 -0
  147. data/lib/active_support/dependencies/autoload.rb +79 -0
  148. data/lib/active_support/dependencies/interlock.rb +57 -0
  149. data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
  150. data/lib/active_support/deprecation.rb +46 -0
  151. data/lib/active_support/deprecation/behaviors.rb +109 -0
  152. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  153. data/lib/active_support/deprecation/instance_delegator.rb +39 -0
  154. data/lib/active_support/deprecation/method_wrappers.rb +78 -0
  155. data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
  156. data/lib/active_support/deprecation/reporting.rb +114 -0
  157. data/lib/active_support/descendants_tracker.rb +109 -0
  158. data/lib/active_support/digest.rb +20 -0
  159. data/lib/active_support/duration.rb +433 -0
  160. data/lib/active_support/duration/iso8601_parser.rb +124 -0
  161. data/lib/active_support/duration/iso8601_serializer.rb +54 -0
  162. data/lib/active_support/encrypted_configuration.rb +45 -0
  163. data/lib/active_support/encrypted_file.rb +100 -0
  164. data/lib/active_support/evented_file_update_checker.rb +235 -0
  165. data/lib/active_support/execution_wrapper.rb +129 -0
  166. data/lib/active_support/executor.rb +8 -0
  167. data/lib/active_support/file_update_checker.rb +163 -0
  168. data/lib/active_support/gem_version.rb +17 -0
  169. data/lib/active_support/gzip.rb +38 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +399 -0
  171. data/lib/active_support/i18n.rb +16 -0
  172. data/lib/active_support/i18n_railtie.rb +126 -0
  173. data/lib/active_support/inflections.rb +72 -0
  174. data/lib/active_support/inflector.rb +9 -0
  175. data/lib/active_support/inflector/inflections.rb +257 -0
  176. data/lib/active_support/inflector/methods.rb +398 -0
  177. data/lib/active_support/inflector/transliterate.rb +147 -0
  178. data/lib/active_support/json.rb +4 -0
  179. data/lib/active_support/json/decoding.rb +76 -0
  180. data/lib/active_support/json/encoding.rb +134 -0
  181. data/lib/active_support/key_generator.rb +41 -0
  182. data/lib/active_support/lazy_load_hooks.rb +82 -0
  183. data/lib/active_support/locale/en.rb +31 -0
  184. data/lib/active_support/locale/en.yml +135 -0
  185. data/lib/active_support/log_subscriber.rb +135 -0
  186. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  187. data/lib/active_support/logger.rb +93 -0
  188. data/lib/active_support/logger_silence.rb +45 -0
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -0
  190. data/lib/active_support/message_encryptor.rb +227 -0
  191. data/lib/active_support/message_verifier.rb +205 -0
  192. data/lib/active_support/messages/metadata.rb +71 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  194. data/lib/active_support/messages/rotator.rb +56 -0
  195. data/lib/active_support/multibyte.rb +23 -0
  196. data/lib/active_support/multibyte/chars.rb +216 -0
  197. data/lib/active_support/multibyte/unicode.rb +157 -0
  198. data/lib/active_support/notifications.rb +253 -0
  199. data/lib/active_support/notifications/fanout.rb +244 -0
  200. data/lib/active_support/notifications/instrumenter.rb +164 -0
  201. data/lib/active_support/number_helper.rb +378 -0
  202. data/lib/active_support/number_helper/number_converter.rb +184 -0
  203. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  204. data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
  205. data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
  206. data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
  207. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  208. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  209. data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
  210. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  211. data/lib/active_support/option_merger.rb +27 -0
  212. data/lib/active_support/ordered_hash.rb +50 -0
  213. data/lib/active_support/ordered_options.rb +85 -0
  214. data/lib/active_support/parameter_filter.rb +129 -0
  215. data/lib/active_support/per_thread_registry.rb +60 -0
  216. data/lib/active_support/proxy_object.rb +15 -0
  217. data/lib/active_support/rails.rb +29 -0
  218. data/lib/active_support/railtie.rb +80 -0
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +174 -0
  221. data/lib/active_support/security_utils.rb +31 -0
  222. data/lib/active_support/string_inquirer.rb +34 -0
  223. data/lib/active_support/subscriber.rb +169 -0
  224. data/lib/active_support/tagged_logging.rb +88 -0
  225. data/lib/active_support/test_case.rb +163 -0
  226. data/lib/active_support/testing/assertions.rb +228 -0
  227. data/lib/active_support/testing/autorun.rb +7 -0
  228. data/lib/active_support/testing/constant_lookup.rb +51 -0
  229. data/lib/active_support/testing/declarative.rb +28 -0
  230. data/lib/active_support/testing/deprecation.rb +38 -0
  231. data/lib/active_support/testing/file_fixtures.rb +38 -0
  232. data/lib/active_support/testing/isolation.rb +110 -0
  233. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  234. data/lib/active_support/testing/parallelization.rb +128 -0
  235. data/lib/active_support/testing/setup_and_teardown.rb +55 -0
  236. data/lib/active_support/testing/stream.rb +44 -0
  237. data/lib/active_support/testing/tagged_logging.rb +27 -0
  238. data/lib/active_support/testing/time_helpers.rb +200 -0
  239. data/lib/active_support/time.rb +20 -0
  240. data/lib/active_support/time_with_zone.rb +561 -0
  241. data/lib/active_support/values/time_zone.rb +570 -0
  242. data/lib/active_support/version.rb +10 -0
  243. data/lib/active_support/xml_mini.rb +202 -0
  244. data/lib/active_support/xml_mini/jdom.rb +183 -0
  245. data/lib/active_support/xml_mini/libxml.rb +80 -0
  246. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  247. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  248. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  249. data/lib/active_support/xml_mini/rexml.rb +130 -0
  250. metadata +385 -0
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "active_support/inflector/methods"
5
+ require "active_support/core_ext/date/zones"
6
+ require "active_support/core_ext/module/redefine_method"
7
+
8
+ class Date
9
+ DATE_FORMATS = {
10
+ short: "%d %b",
11
+ long: "%B %d, %Y",
12
+ db: "%Y-%m-%d",
13
+ number: "%Y%m%d",
14
+ long_ordinal: lambda { |date|
15
+ day_format = ActiveSupport::Inflector.ordinalize(date.day)
16
+ date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007"
17
+ },
18
+ rfc822: "%d %b %Y",
19
+ iso8601: lambda { |date| date.iso8601 }
20
+ }
21
+
22
+ # Convert to a formatted string. See DATE_FORMATS for predefined formats.
23
+ #
24
+ # This method is aliased to <tt>to_s</tt>.
25
+ #
26
+ # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
27
+ #
28
+ # date.to_formatted_s(:db) # => "2007-11-10"
29
+ # date.to_s(:db) # => "2007-11-10"
30
+ #
31
+ # date.to_formatted_s(:short) # => "10 Nov"
32
+ # date.to_formatted_s(:number) # => "20071110"
33
+ # date.to_formatted_s(:long) # => "November 10, 2007"
34
+ # date.to_formatted_s(:long_ordinal) # => "November 10th, 2007"
35
+ # date.to_formatted_s(:rfc822) # => "10 Nov 2007"
36
+ # date.to_formatted_s(:iso8601) # => "2007-11-10"
37
+ #
38
+ # == Adding your own date formats to to_formatted_s
39
+ # You can add your own formats to the Date::DATE_FORMATS hash.
40
+ # Use the format name as the hash key and either a strftime string
41
+ # or Proc instance that takes a date argument as the value.
42
+ #
43
+ # # config/initializers/date_formats.rb
44
+ # Date::DATE_FORMATS[:month_and_year] = '%B %Y'
45
+ # Date::DATE_FORMATS[:short_ordinal] = ->(date) { date.strftime("%B #{date.day.ordinalize}") }
46
+ def to_formatted_s(format = :default)
47
+ if formatter = DATE_FORMATS[format]
48
+ if formatter.respond_to?(:call)
49
+ formatter.call(self).to_s
50
+ else
51
+ strftime(formatter)
52
+ end
53
+ else
54
+ to_default_s
55
+ end
56
+ end
57
+ alias_method :to_default_s, :to_s
58
+ alias_method :to_s, :to_formatted_s
59
+
60
+ # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
61
+ def readable_inspect
62
+ strftime("%a, %d %b %Y")
63
+ end
64
+ alias_method :default_inspect, :inspect
65
+ alias_method :inspect, :readable_inspect
66
+
67
+ silence_redefinition_of_method :to_time
68
+
69
+ # Converts a Date instance to a Time, where the time is set to the beginning of the day.
70
+ # The timezone can be either :local or :utc (default :local).
71
+ #
72
+ # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
73
+ #
74
+ # date.to_time # => 2007-11-10 00:00:00 0800
75
+ # date.to_time(:local) # => 2007-11-10 00:00:00 0800
76
+ #
77
+ # date.to_time(:utc) # => 2007-11-10 00:00:00 UTC
78
+ #
79
+ # NOTE: The :local timezone is Ruby's *process* timezone, i.e. ENV['TZ'].
80
+ # If the *application's* timezone is needed, then use +in_time_zone+ instead.
81
+ def to_time(form = :local)
82
+ raise ArgumentError, "Expected :local or :utc, got #{form.inspect}." unless [:local, :utc].include?(form)
83
+ ::Time.send(form, year, month, day)
84
+ end
85
+
86
+ silence_redefinition_of_method :xmlschema
87
+
88
+ # Returns a string which represents the time in used time zone as DateTime
89
+ # defined by XML Schema:
90
+ #
91
+ # date = Date.new(2015, 05, 23) # => Sat, 23 May 2015
92
+ # date.xmlschema # => "2015-05-23T00:00:00+04:00"
93
+ def xmlschema
94
+ in_time_zone.xmlschema
95
+ end
96
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "active_support/core_ext/date_and_time/zones"
5
+
6
+ class Date
7
+ include DateAndTime::Zones
8
+ end
@@ -0,0 +1,351 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/try"
4
+
5
+ module DateAndTime
6
+ module Calculations
7
+ DAYS_INTO_WEEK = {
8
+ sunday: 0,
9
+ monday: 1,
10
+ tuesday: 2,
11
+ wednesday: 3,
12
+ thursday: 4,
13
+ friday: 5,
14
+ saturday: 6
15
+ }
16
+ WEEKEND_DAYS = [ 6, 0 ]
17
+
18
+ # Returns a new date/time representing yesterday.
19
+ def yesterday
20
+ advance(days: -1)
21
+ end
22
+
23
+ # Returns a new date/time representing tomorrow.
24
+ def tomorrow
25
+ advance(days: 1)
26
+ end
27
+
28
+ # Returns true if the date/time is today.
29
+ def today?
30
+ to_date == ::Date.current
31
+ end
32
+
33
+ # Returns true if the date/time is in the past.
34
+ def past?
35
+ self < self.class.current
36
+ end
37
+
38
+ # Returns true if the date/time is in the future.
39
+ def future?
40
+ self > self.class.current
41
+ end
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
+
63
+ # Returns a new date/time the specified number of days ago.
64
+ def days_ago(days)
65
+ advance(days: -days)
66
+ end
67
+
68
+ # Returns a new date/time the specified number of days in the future.
69
+ def days_since(days)
70
+ advance(days: days)
71
+ end
72
+
73
+ # Returns a new date/time the specified number of weeks ago.
74
+ def weeks_ago(weeks)
75
+ advance(weeks: -weeks)
76
+ end
77
+
78
+ # Returns a new date/time the specified number of weeks in the future.
79
+ def weeks_since(weeks)
80
+ advance(weeks: weeks)
81
+ end
82
+
83
+ # Returns a new date/time the specified number of months ago.
84
+ def months_ago(months)
85
+ advance(months: -months)
86
+ end
87
+
88
+ # Returns a new date/time the specified number of months in the future.
89
+ def months_since(months)
90
+ advance(months: months)
91
+ end
92
+
93
+ # Returns a new date/time the specified number of years ago.
94
+ def years_ago(years)
95
+ advance(years: -years)
96
+ end
97
+
98
+ # Returns a new date/time the specified number of years in the future.
99
+ def years_since(years)
100
+ advance(years: years)
101
+ end
102
+
103
+ # Returns a new date/time at the start of the month.
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
112
+ def beginning_of_month
113
+ first_hour(change(day: 1))
114
+ end
115
+ alias :at_beginning_of_month :beginning_of_month
116
+
117
+ # Returns a new date/time at the start of the quarter.
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
126
+ def beginning_of_quarter
127
+ first_quarter_month = month - (2 + month) % 3
128
+ beginning_of_month.change(month: first_quarter_month)
129
+ end
130
+ alias :at_beginning_of_quarter :beginning_of_quarter
131
+
132
+ # Returns a new date/time at the end of the quarter.
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
141
+ def end_of_quarter
142
+ last_quarter_month = month + (12 - month) % 3
143
+ beginning_of_month.change(month: last_quarter_month).end_of_month
144
+ end
145
+ alias :at_end_of_quarter :end_of_quarter
146
+
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
156
+ def beginning_of_year
157
+ change(month: 1).beginning_of_month
158
+ end
159
+ alias :at_beginning_of_year :beginning_of_year
160
+
161
+ # Returns a new date/time representing the given day in the next week.
162
+ #
163
+ # today = Date.today # => Thu, 07 May 2015
164
+ # today.next_week # => Mon, 11 May 2015
165
+ #
166
+ # The +given_day_in_next_week+ defaults to the beginning of the week
167
+ # which is determined by +Date.beginning_of_week+ or +config.beginning_of_week+
168
+ # when set.
169
+ #
170
+ # today = Date.today # => Thu, 07 May 2015
171
+ # today.next_week(:friday) # => Fri, 15 May 2015
172
+ #
173
+ # +DateTime+ objects have their time set to 0:00 unless +same_time+ is true.
174
+ #
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
180
+ end
181
+
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
189
+ end
190
+
191
+ # Short-hand for months_since(3)
192
+ def next_quarter
193
+ months_since(3)
194
+ end
195
+
196
+ # Returns a new date/time representing the given day in the previous week.
197
+ # Week is assumed to start on +start_day+, default is
198
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
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
203
+ end
204
+ alias_method :last_week, :prev_week
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
+
216
+ # Short-hand for months_ago(1).
217
+ def last_month
218
+ months_ago(1)
219
+ end
220
+
221
+ # Short-hand for months_ago(3).
222
+ def prev_quarter
223
+ months_ago(3)
224
+ end
225
+ alias_method :last_quarter, :prev_quarter
226
+
227
+ # Short-hand for years_ago(1).
228
+ def last_year
229
+ years_ago(1)
230
+ end
231
+
232
+ # Returns the number of days to the start of the week on the given day.
233
+ # Week is assumed to start on +start_day+, default is
234
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
235
+ def days_to_week_start(start_day = Date.beginning_of_week)
236
+ start_day_number = DAYS_INTO_WEEK.fetch(start_day)
237
+ (wday - start_day_number) % 7
238
+ end
239
+
240
+ # Returns a new date/time representing the start of this week on the given day.
241
+ # Week is assumed to start on +start_day+, default is
242
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
243
+ # +DateTime+ objects have their time set to 0:00.
244
+ def beginning_of_week(start_day = Date.beginning_of_week)
245
+ result = days_ago(days_to_week_start(start_day))
246
+ acts_like?(:time) ? result.midnight : result
247
+ end
248
+ alias :at_beginning_of_week :beginning_of_week
249
+
250
+ # Returns Monday of this week assuming that week starts on Monday.
251
+ # +DateTime+ objects have their time set to 0:00.
252
+ def monday
253
+ beginning_of_week(:monday)
254
+ end
255
+
256
+ # Returns a new date/time representing the end of this week on the given day.
257
+ # Week is assumed to start on +start_day+, default is
258
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
259
+ # DateTime objects have their time set to 23:59:59.
260
+ def end_of_week(start_day = Date.beginning_of_week)
261
+ last_hour(days_since(6 - days_to_week_start(start_day)))
262
+ end
263
+ alias :at_end_of_week :end_of_week
264
+
265
+ # Returns Sunday of this week assuming that week starts on Monday.
266
+ # +DateTime+ objects have their time set to 23:59:59.
267
+ def sunday
268
+ end_of_week(:monday)
269
+ end
270
+
271
+ # Returns a new date/time representing the end of the month.
272
+ # DateTime objects will have a time set to 23:59:59.
273
+ def end_of_month
274
+ last_day = ::Time.days_in_month(month, year)
275
+ last_hour(days_since(last_day - day))
276
+ end
277
+ alias :at_end_of_month :end_of_month
278
+
279
+ # Returns a new date/time representing the end of the year.
280
+ # DateTime objects will have a time set to 23:59:59.
281
+ def end_of_year
282
+ change(month: 12).end_of_month
283
+ end
284
+ alias :at_end_of_year :end_of_year
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
+
291
+ # Returns a Range representing the whole week of the current date/time.
292
+ # Week starts on start_day, default is <tt>Date.beginning_of_week</tt> or <tt>config.beginning_of_week</tt> when set.
293
+ def all_week(start_day = Date.beginning_of_week)
294
+ beginning_of_week(start_day)..end_of_week(start_day)
295
+ end
296
+
297
+ # Returns a Range representing the whole month of the current date/time.
298
+ def all_month
299
+ beginning_of_month..end_of_month
300
+ end
301
+
302
+ # Returns a Range representing the whole quarter of the current date/time.
303
+ def all_quarter
304
+ beginning_of_quarter..end_of_quarter
305
+ end
306
+
307
+ # Returns a Range representing the whole year of the current date/time.
308
+ def all_year
309
+ beginning_of_year..end_of_year
310
+ end
311
+
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)
321
+ end
322
+
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)
332
+ end
333
+
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
350
+ end
351
+ end