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,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ alias_method :starts_with?, :start_with?
5
+ alias_method :ends_with?, :end_with?
6
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ # Strips indentation in heredocs.
5
+ #
6
+ # For example in
7
+ #
8
+ # if options[:usage]
9
+ # puts <<-USAGE.strip_heredoc
10
+ # This command does such and such.
11
+ #
12
+ # Supported options are:
13
+ # -h This message
14
+ # ...
15
+ # USAGE
16
+ # end
17
+ #
18
+ # the user would see the usage message aligned against the left margin.
19
+ #
20
+ # Technically, it looks for the least indented non-empty line
21
+ # in the whole string, and removes that amount of leading whitespace.
22
+ def strip_heredoc
23
+ gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "").tap do |stripped|
24
+ stripped.freeze if frozen?
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/conversions"
4
+ require "active_support/core_ext/time/zones"
5
+
6
+ class String
7
+ # Converts String to a TimeWithZone in the current zone if Time.zone or Time.zone_default
8
+ # is set, otherwise converts String to a Time via String#to_time
9
+ def in_time_zone(zone = ::Time.zone)
10
+ if zone
11
+ ::Time.find_zone!(zone).parse(self)
12
+ else
13
+ to_time
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/time/acts_like"
4
+ require "active_support/core_ext/time/calculations"
5
+ require "active_support/core_ext/time/compatibility"
6
+ require "active_support/core_ext/time/conversions"
7
+ require "active_support/core_ext/time/zones"
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/acts_like"
4
+
5
+ class Time
6
+ # Duck-types as a Time-like class. See Object#acts_like?.
7
+ def acts_like_time?
8
+ true
9
+ end
10
+ end
@@ -0,0 +1,344 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/duration"
4
+ require "active_support/core_ext/time/conversions"
5
+ require "active_support/time_with_zone"
6
+ require "active_support/core_ext/time/zones"
7
+ require "active_support/core_ext/date_and_time/calculations"
8
+ require "active_support/core_ext/date/calculations"
9
+
10
+ class Time
11
+ include DateAndTime::Calculations
12
+
13
+ COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
14
+
15
+ class << self
16
+ # Overriding case equality method so that it returns true for ActiveSupport::TimeWithZone instances
17
+ def ===(other)
18
+ super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone))
19
+ end
20
+
21
+ # Returns the number of days in the given month.
22
+ # If no year is specified, it will use the current year.
23
+ def days_in_month(month, year = current.year)
24
+ if month == 2 && ::Date.gregorian_leap?(year)
25
+ 29
26
+ else
27
+ COMMON_YEAR_DAYS_IN_MONTH[month]
28
+ end
29
+ end
30
+
31
+ # Returns the number of days in the given year.
32
+ # If no year is specified, it will use the current year.
33
+ def days_in_year(year = current.year)
34
+ days_in_month(2, year) + 337
35
+ end
36
+
37
+ # Returns <tt>Time.zone.now</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns <tt>Time.now</tt>.
38
+ def current
39
+ ::Time.zone ? ::Time.zone.now : ::Time.now
40
+ end
41
+
42
+ # Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
43
+ # instances can be used when called with a single argument
44
+ def at_with_coercion(*args)
45
+ return at_without_coercion(*args) if args.size != 1
46
+
47
+ # Time.at can be called with a time or numerical value
48
+ time_or_number = args.first
49
+
50
+ if time_or_number.is_a?(ActiveSupport::TimeWithZone) || time_or_number.is_a?(DateTime)
51
+ at_without_coercion(time_or_number.to_f).getlocal
52
+ else
53
+ at_without_coercion(time_or_number)
54
+ end
55
+ end
56
+ alias_method :at_without_coercion, :at
57
+ alias_method :at, :at_with_coercion
58
+
59
+ # Creates a +Time+ instance from an RFC 3339 string.
60
+ #
61
+ # Time.rfc3339('1999-12-31T14:00:00-10:00') # => 2000-01-01 00:00:00 -1000
62
+ #
63
+ # If the time or offset components are missing then an +ArgumentError+ will be raised.
64
+ #
65
+ # Time.rfc3339('1999-12-31') # => ArgumentError: invalid date
66
+ def rfc3339(str)
67
+ parts = Date._rfc3339(str)
68
+
69
+ raise ArgumentError, "invalid date" if parts.empty?
70
+
71
+ Time.new(
72
+ parts.fetch(:year),
73
+ parts.fetch(:mon),
74
+ parts.fetch(:mday),
75
+ parts.fetch(:hour),
76
+ parts.fetch(:min),
77
+ parts.fetch(:sec) + parts.fetch(:sec_fraction, 0),
78
+ parts.fetch(:offset)
79
+ )
80
+ end
81
+ end
82
+
83
+ # Returns the number of seconds since 00:00:00.
84
+ #
85
+ # Time.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0.0
86
+ # Time.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296.0
87
+ # Time.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399.0
88
+ def seconds_since_midnight
89
+ to_i - change(hour: 0).to_i + (usec / 1.0e+6)
90
+ end
91
+
92
+ # Returns the number of seconds until 23:59:59.
93
+ #
94
+ # Time.new(2012, 8, 29, 0, 0, 0).seconds_until_end_of_day # => 86399
95
+ # Time.new(2012, 8, 29, 12, 34, 56).seconds_until_end_of_day # => 41103
96
+ # Time.new(2012, 8, 29, 23, 59, 59).seconds_until_end_of_day # => 0
97
+ def seconds_until_end_of_day
98
+ end_of_day.to_i - to_i
99
+ end
100
+
101
+ # Returns the fraction of a second as a +Rational+
102
+ #
103
+ # Time.new(2012, 8, 29, 0, 0, 0.5).sec_fraction # => (1/2)
104
+ def sec_fraction
105
+ subsec
106
+ end
107
+
108
+ # Returns a new Time where one or more of the elements have been changed according
109
+ # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
110
+ # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
111
+ # the hour is passed, then minute, sec, usec and nsec is set to 0. If the hour
112
+ # and minute is passed, then sec, usec and nsec is set to 0. The +options+ parameter
113
+ # takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
114
+ # <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>,
115
+ # <tt>:offset</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
116
+ #
117
+ # Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0)
118
+ # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0)
119
+ # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => Time.new(1981, 8, 29, 0, 0, 0)
120
+ def change(options)
121
+ new_year = options.fetch(:year, year)
122
+ new_month = options.fetch(:month, month)
123
+ new_day = options.fetch(:day, day)
124
+ new_hour = options.fetch(:hour, hour)
125
+ new_min = options.fetch(:min, options[:hour] ? 0 : min)
126
+ new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
127
+ new_offset = options.fetch(:offset, nil)
128
+
129
+ if new_nsec = options[:nsec]
130
+ raise ArgumentError, "Can't change both :nsec and :usec at the same time: #{options.inspect}" if options[:usec]
131
+ new_usec = Rational(new_nsec, 1000)
132
+ else
133
+ new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
134
+ end
135
+
136
+ raise ArgumentError, "argument out of range" if new_usec >= 1000000
137
+
138
+ new_sec += Rational(new_usec, 1000000)
139
+
140
+ if new_offset
141
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
142
+ elsif utc?
143
+ ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
144
+ elsif zone
145
+ ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
146
+ else
147
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
148
+ end
149
+ end
150
+
151
+ # Uses Date to provide precise Time calculations for years, months, and days
152
+ # according to the proleptic Gregorian calendar. The +options+ parameter
153
+ # takes a hash with any of these keys: <tt>:years</tt>, <tt>:months</tt>,
154
+ # <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>, <tt>:minutes</tt>,
155
+ # <tt>:seconds</tt>.
156
+ #
157
+ # Time.new(2015, 8, 1, 14, 35, 0).advance(seconds: 1) # => 2015-08-01 14:35:01 -0700
158
+ # Time.new(2015, 8, 1, 14, 35, 0).advance(minutes: 1) # => 2015-08-01 14:36:00 -0700
159
+ # Time.new(2015, 8, 1, 14, 35, 0).advance(hours: 1) # => 2015-08-01 15:35:00 -0700
160
+ # Time.new(2015, 8, 1, 14, 35, 0).advance(days: 1) # => 2015-08-02 14:35:00 -0700
161
+ # Time.new(2015, 8, 1, 14, 35, 0).advance(weeks: 1) # => 2015-08-08 14:35:00 -0700
162
+ def advance(options)
163
+ unless options[:weeks].nil?
164
+ options[:weeks], partial_weeks = options[:weeks].divmod(1)
165
+ options[:days] = options.fetch(:days, 0) + 7 * partial_weeks
166
+ end
167
+
168
+ unless options[:days].nil?
169
+ options[:days], partial_days = options[:days].divmod(1)
170
+ options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
171
+ end
172
+
173
+ d = to_date.gregorian.advance(options)
174
+ time_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
175
+ seconds_to_advance = \
176
+ options.fetch(:seconds, 0) +
177
+ options.fetch(:minutes, 0) * 60 +
178
+ options.fetch(:hours, 0) * 3600
179
+
180
+ if seconds_to_advance.zero?
181
+ time_advanced_by_date
182
+ else
183
+ time_advanced_by_date.since(seconds_to_advance)
184
+ end
185
+ end
186
+
187
+ # Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension
188
+ def ago(seconds)
189
+ since(-seconds)
190
+ end
191
+
192
+ # Returns a new Time representing the time a number of seconds since the instance time
193
+ def since(seconds)
194
+ self + seconds
195
+ rescue
196
+ to_datetime.since(seconds)
197
+ end
198
+ alias :in :since
199
+
200
+ # Returns a new Time representing the start of the day (0:00)
201
+ def beginning_of_day
202
+ change(hour: 0)
203
+ end
204
+ alias :midnight :beginning_of_day
205
+ alias :at_midnight :beginning_of_day
206
+ alias :at_beginning_of_day :beginning_of_day
207
+
208
+ # Returns a new Time representing the middle of the day (12:00)
209
+ def middle_of_day
210
+ change(hour: 12)
211
+ end
212
+ alias :midday :middle_of_day
213
+ alias :noon :middle_of_day
214
+ alias :at_midday :middle_of_day
215
+ alias :at_noon :middle_of_day
216
+ alias :at_middle_of_day :middle_of_day
217
+
218
+ # Returns a new Time representing the end of the day, 23:59:59.999999
219
+ def end_of_day
220
+ change(
221
+ hour: 23,
222
+ min: 59,
223
+ sec: 59,
224
+ usec: Rational(999999999, 1000)
225
+ )
226
+ end
227
+ alias :at_end_of_day :end_of_day
228
+
229
+ # Returns a new Time representing the start of the hour (x:00)
230
+ def beginning_of_hour
231
+ change(min: 0)
232
+ end
233
+ alias :at_beginning_of_hour :beginning_of_hour
234
+
235
+ # Returns a new Time representing the end of the hour, x:59:59.999999
236
+ def end_of_hour
237
+ change(
238
+ min: 59,
239
+ sec: 59,
240
+ usec: Rational(999999999, 1000)
241
+ )
242
+ end
243
+ alias :at_end_of_hour :end_of_hour
244
+
245
+ # Returns a new Time representing the start of the minute (x:xx:00)
246
+ def beginning_of_minute
247
+ change(sec: 0)
248
+ end
249
+ alias :at_beginning_of_minute :beginning_of_minute
250
+
251
+ # Returns a new Time representing the end of the minute, x:xx:59.999999
252
+ def end_of_minute
253
+ change(
254
+ sec: 59,
255
+ usec: Rational(999999999, 1000)
256
+ )
257
+ end
258
+ alias :at_end_of_minute :end_of_minute
259
+
260
+ def plus_with_duration(other) #:nodoc:
261
+ if ActiveSupport::Duration === other
262
+ other.since(self)
263
+ else
264
+ plus_without_duration(other)
265
+ end
266
+ end
267
+ alias_method :plus_without_duration, :+
268
+ alias_method :+, :plus_with_duration
269
+
270
+ def minus_with_duration(other) #:nodoc:
271
+ if ActiveSupport::Duration === other
272
+ other.until(self)
273
+ else
274
+ minus_without_duration(other)
275
+ end
276
+ end
277
+ alias_method :minus_without_duration, :-
278
+ alias_method :-, :minus_with_duration
279
+
280
+ # Time#- can also be used to determine the number of seconds between two Time instances.
281
+ # We're layering on additional behavior so that ActiveSupport::TimeWithZone instances
282
+ # are coerced into values that Time#- will recognize
283
+ def minus_with_coercion(other)
284
+ other = other.comparable_time if other.respond_to?(:comparable_time)
285
+ other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
286
+ end
287
+ alias_method :minus_without_coercion, :-
288
+ alias_method :-, :minus_with_coercion
289
+
290
+ # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
291
+ # can be chronologically compared with a Time
292
+ def compare_with_coercion(other)
293
+ # we're avoiding Time#to_datetime and Time#to_time because they're expensive
294
+ if other.class == Time
295
+ compare_without_coercion(other)
296
+ elsif other.is_a?(Time)
297
+ compare_without_coercion(other.to_time)
298
+ else
299
+ to_datetime <=> other
300
+ end
301
+ end
302
+ alias_method :compare_without_coercion, :<=>
303
+ alias_method :<=>, :compare_with_coercion
304
+
305
+ # Layers additional behavior on Time#eql? so that ActiveSupport::TimeWithZone instances
306
+ # can be eql? to an equivalent Time
307
+ def eql_with_coercion(other)
308
+ # if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do eql? comparison
309
+ other = other.comparable_time if other.respond_to?(:comparable_time)
310
+ eql_without_coercion(other)
311
+ end
312
+ alias_method :eql_without_coercion, :eql?
313
+ alias_method :eql?, :eql_with_coercion
314
+
315
+ # Returns a new time the specified number of days ago.
316
+ def prev_day(days = 1)
317
+ advance(days: -days)
318
+ end
319
+
320
+ # Returns a new time the specified number of days in the future.
321
+ def next_day(days = 1)
322
+ advance(days: days)
323
+ end
324
+
325
+ # Returns a new time the specified number of months ago.
326
+ def prev_month(months = 1)
327
+ advance(months: -months)
328
+ end
329
+
330
+ # Returns a new time the specified number of months in the future.
331
+ def next_month(months = 1)
332
+ advance(months: months)
333
+ end
334
+
335
+ # Returns a new time the specified number of years ago.
336
+ def prev_year(years = 1)
337
+ advance(years: -years)
338
+ end
339
+
340
+ # Returns a new time the specified number of years in the future.
341
+ def next_year(years = 1)
342
+ advance(years: years)
343
+ end
344
+ end
@@ -0,0 +1,16 @@
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"
5
+
6
+ class Time
7
+ include DateAndTime::Compatibility
8
+
9
+ silence_redefinition_of_method :to_time
10
+
11
+ # Either return +self+ or the time in the local system timezone depending
12
+ # on the setting of +ActiveSupport.to_time_preserves_timezone+.
13
+ def to_time
14
+ preserve_timezone ? self : getlocal
15
+ end
16
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/inflector/methods"
4
+ require "active_support/values/time_zone"
5
+
6
+ class Time
7
+ DATE_FORMATS = {
8
+ db: "%Y-%m-%d %H:%M:%S",
9
+ number: "%Y%m%d%H%M%S",
10
+ nsec: "%Y%m%d%H%M%S%9N",
11
+ usec: "%Y%m%d%H%M%S%6N",
12
+ time: "%H:%M",
13
+ short: "%d %b %H:%M",
14
+ long: "%B %d, %Y %H:%M",
15
+ long_ordinal: lambda { |time|
16
+ day_format = ActiveSupport::Inflector.ordinalize(time.day)
17
+ time.strftime("%B #{day_format}, %Y %H:%M")
18
+ },
19
+ rfc822: lambda { |time|
20
+ offset_format = time.formatted_offset(false)
21
+ time.strftime("%a, %d %b %Y %H:%M:%S #{offset_format}")
22
+ },
23
+ iso8601: lambda { |time| time.iso8601 }
24
+ }
25
+
26
+ # Converts to a formatted string. See DATE_FORMATS for built-in formats.
27
+ #
28
+ # This method is aliased to <tt>to_s</tt>.
29
+ #
30
+ # time = Time.now # => 2007-01-18 06:10:17 -06:00
31
+ #
32
+ # time.to_formatted_s(:time) # => "06:10"
33
+ # time.to_s(:time) # => "06:10"
34
+ #
35
+ # time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
36
+ # time.to_formatted_s(:number) # => "20070118061017"
37
+ # time.to_formatted_s(:short) # => "18 Jan 06:10"
38
+ # time.to_formatted_s(:long) # => "January 18, 2007 06:10"
39
+ # time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
40
+ # time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
41
+ # time.to_formatted_s(:iso8601) # => "2007-01-18T06:10:17-06:00"
42
+ #
43
+ # == Adding your own time formats to +to_formatted_s+
44
+ # You can add your own formats to the Time::DATE_FORMATS hash.
45
+ # Use the format name as the hash key and either a strftime string
46
+ # or Proc instance that takes a time argument as the value.
47
+ #
48
+ # # config/initializers/time_formats.rb
49
+ # Time::DATE_FORMATS[:month_and_year] = '%B %Y'
50
+ # Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
51
+ def to_formatted_s(format = :default)
52
+ if formatter = DATE_FORMATS[format]
53
+ formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
54
+ else
55
+ to_default_s
56
+ end
57
+ end
58
+ alias_method :to_default_s, :to_s
59
+ alias_method :to_s, :to_formatted_s
60
+
61
+ # Returns a formatted string of the offset from UTC, or an alternative
62
+ # string if the time zone is already UTC.
63
+ #
64
+ # Time.local(2000).formatted_offset # => "-06:00"
65
+ # Time.local(2000).formatted_offset(false) # => "-0600"
66
+ def formatted_offset(colon = true, alternate_utc_string = nil)
67
+ utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon)
68
+ end
69
+
70
+ # Aliased to +xmlschema+ for compatibility with +DateTime+
71
+ alias_method :rfc3339, :xmlschema
72
+ end