activesupport 4.0.12 → 7.0.2.4

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 (295) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +249 -501
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -5
  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 +41 -13
  9. data/lib/active_support/benchmarkable.rb +7 -15
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +96 -74
  12. data/lib/active_support/cache/mem_cache_store.rb +211 -103
  13. data/lib/active_support/cache/memory_store.rb +90 -58
  14. data/lib/active_support/cache/null_store.rb +19 -7
  15. data/lib/active_support/cache/redis_cache_store.rb +468 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +86 -83
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  18. data/lib/active_support/cache.rb +580 -241
  19. data/lib/active_support/callbacks.rb +812 -425
  20. data/lib/active_support/code_generator.rb +65 -0
  21. data/lib/active_support/concern.rb +103 -14
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +33 -0
  23. data/lib/active_support/concurrency/share_lock.rb +226 -0
  24. data/lib/active_support/configurable.rb +21 -19
  25. data/lib/active_support/configuration_file.rb +51 -0
  26. data/lib/active_support/core_ext/array/access.rb +47 -1
  27. data/lib/active_support/core_ext/array/conversions.rb +35 -44
  28. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +26 -16
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  34. data/lib/active_support/core_ext/array.rb +10 -7
  35. data/lib/active_support/core_ext/benchmark.rb +5 -3
  36. data/lib/active_support/core_ext/big_decimal/conversions.rb +9 -26
  37. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  38. data/lib/active_support/core_ext/class/attribute.rb +52 -49
  39. data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
  40. data/lib/active_support/core_ext/class/subclasses.rb +25 -26
  41. data/lib/active_support/core_ext/class.rb +4 -4
  42. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  43. data/lib/active_support/core_ext/date/blank.rb +14 -0
  44. data/lib/active_support/core_ext/date/calculations.rb +31 -18
  45. data/lib/active_support/core_ext/date/conversions.rb +43 -32
  46. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  47. data/lib/active_support/core_ext/date/zones.rb +5 -34
  48. data/lib/active_support/core_ext/date.rb +7 -4
  49. data/lib/active_support/core_ext/date_and_time/calculations.rb +198 -66
  50. data/lib/active_support/core_ext/date_and_time/compatibility.rb +31 -0
  51. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +79 -38
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +31 -26
  57. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  58. data/lib/active_support/core_ext/date_time.rb +8 -4
  59. data/lib/active_support/core_ext/digest/uuid.rb +79 -0
  60. data/lib/active_support/core_ext/digest.rb +3 -0
  61. data/lib/active_support/core_ext/enumerable.rb +249 -17
  62. data/lib/active_support/core_ext/file/atomic.rb +41 -32
  63. data/lib/active_support/core_ext/file.rb +3 -1
  64. data/lib/active_support/core_ext/hash/conversions.rb +71 -49
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +14 -5
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
  69. data/lib/active_support/core_ext/hash/keys.rb +39 -56
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  71. data/lib/active_support/core_ext/hash/slice.rb +8 -23
  72. data/lib/active_support/core_ext/hash.rb +10 -8
  73. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  74. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  75. data/lib/active_support/core_ext/integer/time.rb +11 -33
  76. data/lib/active_support/core_ext/integer.rb +5 -3
  77. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  78. data/lib/active_support/core_ext/kernel/reporting.rb +9 -78
  79. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  80. data/lib/active_support/core_ext/kernel.rb +5 -4
  81. data/lib/active_support/core_ext/load_error.rb +5 -21
  82. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  83. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  84. data/lib/active_support/core_ext/module/attr_internal.rb +8 -8
  85. data/lib/active_support/core_ext/module/attribute_accessors.rb +186 -44
  86. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +157 -0
  87. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  88. data/lib/active_support/core_ext/module/delegation.rb +172 -45
  89. data/lib/active_support/core_ext/module/deprecation.rb +3 -3
  90. data/lib/active_support/core_ext/module/introspection.rb +23 -38
  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 -10
  94. data/lib/active_support/core_ext/name_error.rb +45 -4
  95. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +135 -127
  97. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +37 -50
  99. data/lib/active_support/core_ext/numeric.rb +6 -3
  100. data/lib/active_support/core_ext/object/acts_like.rb +41 -6
  101. data/lib/active_support/core_ext/object/blank.rb +70 -20
  102. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  103. data/lib/active_support/core_ext/object/deep_dup.rb +19 -10
  104. data/lib/active_support/core_ext/object/duplicable.rb +17 -47
  105. data/lib/active_support/core_ext/object/inclusion.rb +18 -15
  106. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  107. data/lib/active_support/core_ext/object/json.rb +244 -0
  108. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  109. data/lib/active_support/core_ext/object/to_query.rb +21 -8
  110. data/lib/active_support/core_ext/object/try.rb +106 -26
  111. data/lib/active_support/core_ext/object/with_options.rb +64 -5
  112. data/lib/active_support/core_ext/object.rb +14 -12
  113. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  114. data/lib/active_support/core_ext/pathname.rb +3 -0
  115. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  116. data/lib/active_support/core_ext/range/conversions.rb +37 -15
  117. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  118. data/lib/active_support/core_ext/range/each.rb +18 -17
  119. data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
  120. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  121. data/lib/active_support/core_ext/range.rb +7 -4
  122. data/lib/active_support/core_ext/regexp.rb +10 -1
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string/access.rb +42 -51
  125. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  126. data/lib/active_support/core_ext/string/conversions.rb +18 -13
  127. data/lib/active_support/core_ext/string/exclude.rb +5 -3
  128. data/lib/active_support/core_ext/string/filters.rb +97 -7
  129. data/lib/active_support/core_ext/string/indent.rb +6 -4
  130. data/lib/active_support/core_ext/string/inflections.rb +106 -25
  131. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  132. data/lib/active_support/core_ext/string/multibyte.rb +18 -9
  133. data/lib/active_support/core_ext/string/output_safety.rb +227 -54
  134. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  135. data/lib/active_support/core_ext/string/strip.rb +6 -5
  136. data/lib/active_support/core_ext/string/zones.rb +4 -1
  137. data/lib/active_support/core_ext/string.rb +15 -13
  138. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  139. data/lib/active_support/core_ext/symbol.rb +3 -0
  140. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  141. data/lib/active_support/core_ext/time/calculations.rb +178 -116
  142. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  143. data/lib/active_support/core_ext/time/conversions.rb +37 -25
  144. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  145. data/lib/active_support/core_ext/time/zones.rb +44 -42
  146. data/lib/active_support/core_ext/time.rb +8 -5
  147. data/lib/active_support/core_ext/uri.rb +4 -25
  148. data/lib/active_support/core_ext.rb +4 -2
  149. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  150. data/lib/active_support/current_attributes.rb +226 -0
  151. data/lib/active_support/dependencies/autoload.rb +3 -1
  152. data/lib/active_support/dependencies/interlock.rb +49 -0
  153. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  154. data/lib/active_support/dependencies.rb +71 -696
  155. data/lib/active_support/deprecation/behaviors.rb +65 -16
  156. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  157. data/lib/active_support/deprecation/disallowed.rb +56 -0
  158. data/lib/active_support/deprecation/instance_delegator.rb +16 -2
  159. data/lib/active_support/deprecation/method_wrappers.rb +62 -21
  160. data/lib/active_support/deprecation/proxy_wrappers.rb +82 -31
  161. data/lib/active_support/deprecation/reporting.rb +81 -18
  162. data/lib/active_support/deprecation.rb +19 -11
  163. data/lib/active_support/descendants_tracker.rb +192 -34
  164. data/lib/active_support/digest.rb +22 -0
  165. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  166. data/lib/active_support/duration/iso8601_serializer.rb +67 -0
  167. data/lib/active_support/duration.rb +437 -39
  168. data/lib/active_support/encrypted_configuration.rb +56 -0
  169. data/lib/active_support/encrypted_file.rb +117 -0
  170. data/lib/active_support/environment_inquirer.rb +20 -0
  171. data/lib/active_support/error_reporter.rb +117 -0
  172. data/lib/active_support/evented_file_update_checker.rb +170 -0
  173. data/lib/active_support/execution_context/test_helper.rb +13 -0
  174. data/lib/active_support/execution_context.rb +53 -0
  175. data/lib/active_support/execution_wrapper.rb +151 -0
  176. data/lib/active_support/executor/test_helper.rb +7 -0
  177. data/lib/active_support/executor.rb +8 -0
  178. data/lib/active_support/file_update_checker.rb +62 -37
  179. data/lib/active_support/fork_tracker.rb +71 -0
  180. data/lib/active_support/gem_version.rb +17 -0
  181. data/lib/active_support/gzip.rb +7 -5
  182. data/lib/active_support/hash_with_indifferent_access.rb +207 -54
  183. data/lib/active_support/html_safe_translation.rb +43 -0
  184. data/lib/active_support/i18n.rb +10 -6
  185. data/lib/active_support/i18n_railtie.rb +48 -19
  186. data/lib/active_support/inflections.rb +19 -12
  187. data/lib/active_support/inflector/inflections.rb +97 -37
  188. data/lib/active_support/inflector/methods.rb +192 -157
  189. data/lib/active_support/inflector/transliterate.rb +83 -33
  190. data/lib/active_support/inflector.rb +7 -5
  191. data/lib/active_support/isolated_execution_state.rb +64 -0
  192. data/lib/active_support/json/decoding.rb +37 -42
  193. data/lib/active_support/json/encoding.rb +93 -293
  194. data/lib/active_support/json.rb +4 -2
  195. data/lib/active_support/key_generator.rb +30 -47
  196. data/lib/active_support/lazy_load_hooks.rb +54 -21
  197. data/lib/active_support/locale/en.rb +33 -0
  198. data/lib/active_support/locale/en.yml +10 -4
  199. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  200. data/lib/active_support/log_subscriber.rb +61 -18
  201. data/lib/active_support/logger.rb +40 -4
  202. data/lib/active_support/logger_silence.rb +17 -20
  203. data/lib/active_support/logger_thread_safe_level.rb +69 -0
  204. data/lib/active_support/message_encryptor.rb +178 -55
  205. data/lib/active_support/message_verifier.rb +195 -26
  206. data/lib/active_support/messages/metadata.rb +80 -0
  207. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  208. data/lib/active_support/messages/rotator.rb +57 -0
  209. data/lib/active_support/multibyte/chars.rb +45 -92
  210. data/lib/active_support/multibyte/unicode.rb +44 -377
  211. data/lib/active_support/multibyte.rb +5 -3
  212. data/lib/active_support/notifications/fanout.rb +177 -44
  213. data/lib/active_support/notifications/instrumenter.rb +117 -17
  214. data/lib/active_support/notifications.rb +106 -39
  215. data/lib/active_support/number_helper/number_converter.rb +181 -0
  216. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  217. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  218. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  219. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  220. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  221. data/lib/active_support/number_helper/number_to_phone_converter.rb +59 -0
  222. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  223. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  224. data/lib/active_support/number_helper.rb +152 -394
  225. data/lib/active_support/option_merger.rb +18 -5
  226. data/lib/active_support/ordered_hash.rb +8 -6
  227. data/lib/active_support/ordered_options.rb +43 -7
  228. data/lib/active_support/parameter_filter.rb +138 -0
  229. data/lib/active_support/per_thread_registry.rb +24 -11
  230. data/lib/active_support/proxy_object.rb +2 -0
  231. data/lib/active_support/rails.rb +10 -11
  232. data/lib/active_support/railtie.rb +118 -12
  233. data/lib/active_support/reloader.rb +130 -0
  234. data/lib/active_support/rescuable.rb +112 -57
  235. data/lib/active_support/ruby_features.rb +7 -0
  236. data/lib/active_support/secure_compare_rotator.rb +51 -0
  237. data/lib/active_support/security_utils.rb +38 -0
  238. data/lib/active_support/string_inquirer.rb +11 -4
  239. data/lib/active_support/subscriber.rb +109 -39
  240. data/lib/active_support/tagged_logging.rb +54 -17
  241. data/lib/active_support/test_case.rb +121 -37
  242. data/lib/active_support/testing/assertions.rb +177 -39
  243. data/lib/active_support/testing/autorun.rb +5 -3
  244. data/lib/active_support/testing/constant_lookup.rb +3 -6
  245. data/lib/active_support/testing/declarative.rb +10 -22
  246. data/lib/active_support/testing/deprecation.rb +65 -11
  247. data/lib/active_support/testing/file_fixtures.rb +38 -0
  248. data/lib/active_support/testing/isolation.rb +56 -87
  249. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  250. data/lib/active_support/testing/parallelization/server.rb +82 -0
  251. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  252. data/lib/active_support/testing/parallelization.rb +55 -0
  253. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  254. data/lib/active_support/testing/setup_and_teardown.rb +30 -10
  255. data/lib/active_support/testing/stream.rb +41 -0
  256. data/lib/active_support/testing/tagged_logging.rb +6 -4
  257. data/lib/active_support/testing/time_helpers.rb +246 -0
  258. data/lib/active_support/time.rb +13 -13
  259. data/lib/active_support/time_with_zone.rb +315 -90
  260. data/lib/active_support/values/time_zone.rb +306 -135
  261. data/lib/active_support/version.rb +6 -7
  262. data/lib/active_support/xml_mini/jdom.rb +117 -115
  263. data/lib/active_support/xml_mini/libxml.rb +22 -21
  264. data/lib/active_support/xml_mini/libxmlsax.rb +17 -19
  265. data/lib/active_support/xml_mini/nokogiri.rb +19 -19
  266. data/lib/active_support/xml_mini/nokogirisax.rb +16 -17
  267. data/lib/active_support/xml_mini/rexml.rb +25 -17
  268. data/lib/active_support/xml_mini.rb +67 -56
  269. data/lib/active_support.rb +58 -3
  270. metadata +125 -66
  271. data/lib/active_support/basic_object.rb +0 -11
  272. data/lib/active_support/buffered_logger.rb +0 -21
  273. data/lib/active_support/concurrency/latch.rb +0 -27
  274. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  275. data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
  276. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -40
  277. data/lib/active_support/core_ext/date_time/zones.rb +0 -24
  278. data/lib/active_support/core_ext/hash/diff.rb +0 -14
  279. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  280. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  281. data/lib/active_support/core_ext/logger.rb +0 -67
  282. data/lib/active_support/core_ext/marshal.rb +0 -21
  283. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  284. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  285. data/lib/active_support/core_ext/object/to_json.rb +0 -27
  286. data/lib/active_support/core_ext/proc.rb +0 -17
  287. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  288. data/lib/active_support/core_ext/string/encoding.rb +0 -8
  289. data/lib/active_support/core_ext/struct.rb +0 -6
  290. data/lib/active_support/core_ext/thread.rb +0 -79
  291. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  292. data/lib/active_support/file_watcher.rb +0 -36
  293. data/lib/active_support/json/variable.rb +0 -18
  294. data/lib/active_support/testing/pending.rb +0 -14
  295. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,26 +1,273 @@
1
- require 'active_support/proxy_object'
2
- require 'active_support/core_ext/array/conversions'
3
- require 'active_support/core_ext/object/acts_like'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/conversions"
4
+ require "active_support/core_ext/module/delegation"
5
+ require "active_support/core_ext/object/acts_like"
6
+ require "active_support/core_ext/string/filters"
4
7
 
5
8
  module ActiveSupport
6
9
  # Provides accurate date and time measurements using Date#advance and
7
10
  # Time#advance, respectively. It mainly supports the methods on Numeric.
8
11
  #
9
12
  # 1.month.ago # equivalent to Time.now.advance(months: -1)
10
- class Duration < ProxyObject
11
- attr_accessor :value, :parts
13
+ class Duration
14
+ class Scalar < Numeric # :nodoc:
15
+ attr_reader :value
16
+ delegate :to_i, :to_f, :to_s, to: :value
17
+
18
+ def initialize(value)
19
+ @value = value
20
+ end
21
+
22
+ def coerce(other)
23
+ [Scalar.new(other), self]
24
+ end
25
+
26
+ def -@
27
+ Scalar.new(-value)
28
+ end
29
+
30
+ def <=>(other)
31
+ if Scalar === other || Duration === other
32
+ value <=> other.value
33
+ elsif Numeric === other
34
+ value <=> other
35
+ else
36
+ nil
37
+ end
38
+ end
39
+
40
+ def +(other)
41
+ if Duration === other
42
+ seconds = value + other._parts.fetch(:seconds, 0)
43
+ new_parts = other._parts.merge(seconds: seconds)
44
+ new_value = value + other.value
45
+
46
+ Duration.new(new_value, new_parts, other.variable?)
47
+ else
48
+ calculate(:+, other)
49
+ end
50
+ end
51
+
52
+ def -(other)
53
+ if Duration === other
54
+ seconds = value - other._parts.fetch(:seconds, 0)
55
+ new_parts = other._parts.transform_values(&:-@)
56
+ new_parts = new_parts.merge(seconds: seconds)
57
+ new_value = value - other.value
58
+
59
+ Duration.new(new_value, new_parts, other.variable?)
60
+ else
61
+ calculate(:-, other)
62
+ end
63
+ end
12
64
 
13
- def initialize(value, parts) #:nodoc:
65
+ def *(other)
66
+ if Duration === other
67
+ new_parts = other._parts.transform_values { |other_value| value * other_value }
68
+ new_value = value * other.value
69
+
70
+ Duration.new(new_value, new_parts, other.variable?)
71
+ else
72
+ calculate(:*, other)
73
+ end
74
+ end
75
+
76
+ def /(other)
77
+ if Duration === other
78
+ value / other.value
79
+ else
80
+ calculate(:/, other)
81
+ end
82
+ end
83
+
84
+ def %(other)
85
+ if Duration === other
86
+ Duration.build(value % other.value)
87
+ else
88
+ calculate(:%, other)
89
+ end
90
+ end
91
+
92
+ def variable? # :nodoc:
93
+ false
94
+ end
95
+
96
+ private
97
+ def calculate(op, other)
98
+ if Scalar === other
99
+ Scalar.new(value.public_send(op, other.value))
100
+ elsif Numeric === other
101
+ Scalar.new(value.public_send(op, other))
102
+ else
103
+ raise_type_error(other)
104
+ end
105
+ end
106
+
107
+ def raise_type_error(other)
108
+ raise TypeError, "no implicit conversion of #{other.class} into #{self.class}"
109
+ end
110
+ end
111
+
112
+ SECONDS_PER_MINUTE = 60
113
+ SECONDS_PER_HOUR = 3600
114
+ SECONDS_PER_DAY = 86400
115
+ SECONDS_PER_WEEK = 604800
116
+ SECONDS_PER_MONTH = 2629746 # 1/12 of a gregorian year
117
+ SECONDS_PER_YEAR = 31556952 # length of a gregorian year (365.2425 days)
118
+
119
+ PARTS_IN_SECONDS = {
120
+ seconds: 1,
121
+ minutes: SECONDS_PER_MINUTE,
122
+ hours: SECONDS_PER_HOUR,
123
+ days: SECONDS_PER_DAY,
124
+ weeks: SECONDS_PER_WEEK,
125
+ months: SECONDS_PER_MONTH,
126
+ years: SECONDS_PER_YEAR
127
+ }.freeze
128
+
129
+ PARTS = [:years, :months, :weeks, :days, :hours, :minutes, :seconds].freeze
130
+ VARIABLE_PARTS = [:years, :months, :weeks, :days].freeze
131
+
132
+ attr_reader :value
133
+
134
+ autoload :ISO8601Parser, "active_support/duration/iso8601_parser"
135
+ autoload :ISO8601Serializer, "active_support/duration/iso8601_serializer"
136
+
137
+ class << self
138
+ # Creates a new Duration from string formatted according to ISO 8601 Duration.
139
+ #
140
+ # See {ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601#Durations] for more information.
141
+ # This method allows negative parts to be present in pattern.
142
+ # If invalid string is provided, it will raise +ActiveSupport::Duration::ISO8601Parser::ParsingError+.
143
+ def parse(iso8601duration)
144
+ parts = ISO8601Parser.new(iso8601duration).parse!
145
+ new(calculate_total_seconds(parts), parts)
146
+ end
147
+
148
+ def ===(other) # :nodoc:
149
+ other.is_a?(Duration)
150
+ rescue ::NoMethodError
151
+ false
152
+ end
153
+
154
+ def seconds(value) # :nodoc:
155
+ new(value, { seconds: value }, false)
156
+ end
157
+
158
+ def minutes(value) # :nodoc:
159
+ new(value * SECONDS_PER_MINUTE, { minutes: value }, false)
160
+ end
161
+
162
+ def hours(value) # :nodoc:
163
+ new(value * SECONDS_PER_HOUR, { hours: value }, false)
164
+ end
165
+
166
+ def days(value) # :nodoc:
167
+ new(value * SECONDS_PER_DAY, { days: value }, true)
168
+ end
169
+
170
+ def weeks(value) # :nodoc:
171
+ new(value * SECONDS_PER_WEEK, { weeks: value }, true)
172
+ end
173
+
174
+ def months(value) # :nodoc:
175
+ new(value * SECONDS_PER_MONTH, { months: value }, true)
176
+ end
177
+
178
+ def years(value) # :nodoc:
179
+ new(value * SECONDS_PER_YEAR, { years: value }, true)
180
+ end
181
+
182
+ # Creates a new Duration from a seconds value that is converted
183
+ # to the individual parts:
184
+ #
185
+ # ActiveSupport::Duration.build(31556952).parts # => {:years=>1}
186
+ # ActiveSupport::Duration.build(2716146).parts # => {:months=>1, :days=>1}
187
+ #
188
+ def build(value)
189
+ unless value.is_a?(::Numeric)
190
+ raise TypeError, "can't build an #{self.name} from a #{value.class.name}"
191
+ end
192
+
193
+ parts = {}
194
+ remainder_sign = value <=> 0
195
+ remainder = value.round(9).abs
196
+ variable = false
197
+
198
+ PARTS.each do |part|
199
+ unless part == :seconds
200
+ part_in_seconds = PARTS_IN_SECONDS[part]
201
+ parts[part] = remainder.div(part_in_seconds) * remainder_sign
202
+ remainder %= part_in_seconds
203
+
204
+ unless parts[part].zero?
205
+ variable ||= VARIABLE_PARTS.include?(part)
206
+ end
207
+ end
208
+ end unless value == 0
209
+
210
+ parts[:seconds] = remainder * remainder_sign
211
+
212
+ new(value, parts, variable)
213
+ end
214
+
215
+ private
216
+ def calculate_total_seconds(parts)
217
+ parts.inject(0) do |total, (part, value)|
218
+ total + value * PARTS_IN_SECONDS[part]
219
+ end
220
+ end
221
+ end
222
+
223
+ def initialize(value, parts, variable = nil) # :nodoc:
14
224
  @value, @parts = value, parts
225
+ @parts.reject! { |k, v| v.zero? } unless value == 0
226
+ @parts.freeze
227
+ @variable = variable
228
+
229
+ if @variable.nil?
230
+ @variable = @parts.any? { |part, _| VARIABLE_PARTS.include?(part) }
231
+ end
232
+ end
233
+
234
+ # Returns a copy of the parts hash that defines the duration
235
+ def parts
236
+ @parts.dup
237
+ end
238
+
239
+ def coerce(other) # :nodoc:
240
+ case other
241
+ when Scalar
242
+ [other, self]
243
+ when Duration
244
+ [Scalar.new(other.value), self]
245
+ else
246
+ [Scalar.new(other), self]
247
+ end
248
+ end
249
+
250
+ # Compares one Duration with another or a Numeric to this Duration.
251
+ # Numeric values are treated as seconds.
252
+ def <=>(other)
253
+ if Duration === other
254
+ value <=> other.value
255
+ elsif Numeric === other
256
+ value <=> other
257
+ end
15
258
  end
16
259
 
17
260
  # Adds another Duration or a Numeric to this Duration. Numeric values
18
261
  # are treated as seconds.
19
262
  def +(other)
20
263
  if Duration === other
21
- Duration.new(value + other.value, @parts + other.parts)
264
+ parts = @parts.merge(other._parts) do |_key, value, other_value|
265
+ value + other_value
266
+ end
267
+ Duration.new(value + other.value, parts, @variable || other.variable?)
22
268
  else
23
- Duration.new(value + other, @parts + [[:seconds, other]])
269
+ seconds = @parts.fetch(:seconds, 0) + other
270
+ Duration.new(value + other, @parts.merge(seconds: seconds), @variable)
24
271
  end
25
272
  end
26
273
 
@@ -30,15 +277,59 @@ module ActiveSupport
30
277
  self + (-other)
31
278
  end
32
279
 
33
- def -@ #:nodoc:
34
- Duration.new(-value, parts.map { |type,number| [type, -number] })
280
+ # Multiplies this Duration by a Numeric and returns a new Duration.
281
+ def *(other)
282
+ if Scalar === other || Duration === other
283
+ Duration.new(value * other.value, @parts.transform_values { |number| number * other.value }, @variable || other.variable?)
284
+ elsif Numeric === other
285
+ Duration.new(value * other, @parts.transform_values { |number| number * other }, @variable)
286
+ else
287
+ raise_type_error(other)
288
+ end
35
289
  end
36
290
 
37
- def is_a?(klass) #:nodoc:
291
+ # Divides this Duration by a Numeric and returns a new Duration.
292
+ def /(other)
293
+ if Scalar === other
294
+ Duration.new(value / other.value, @parts.transform_values { |number| number / other.value }, @variable)
295
+ elsif Duration === other
296
+ value / other.value
297
+ elsif Numeric === other
298
+ Duration.new(value / other, @parts.transform_values { |number| number / other }, @variable)
299
+ else
300
+ raise_type_error(other)
301
+ end
302
+ end
303
+
304
+ # Returns the modulo of this Duration by another Duration or Numeric.
305
+ # Numeric values are treated as seconds.
306
+ def %(other)
307
+ if Duration === other || Scalar === other
308
+ Duration.build(value % other.value)
309
+ elsif Numeric === other
310
+ Duration.build(value % other)
311
+ else
312
+ raise_type_error(other)
313
+ end
314
+ end
315
+
316
+ def -@ # :nodoc:
317
+ Duration.new(-value, @parts.transform_values(&:-@), @variable)
318
+ end
319
+
320
+ def +@ # :nodoc:
321
+ self
322
+ end
323
+
324
+ def is_a?(klass) # :nodoc:
38
325
  Duration == klass || value.is_a?(klass)
39
326
  end
40
327
  alias :kind_of? :is_a?
41
328
 
329
+ def instance_of?(klass) # :nodoc:
330
+ Duration == klass || value.instance_of?(klass)
331
+ end
332
+
42
333
  # Returns +true+ if +other+ is also a Duration instance with the
43
334
  # same +value+, or if <tt>other == value</tt>.
44
335
  def ==(other)
@@ -49,10 +340,89 @@ module ActiveSupport
49
340
  end
50
341
  end
51
342
 
52
- def self.===(other) #:nodoc:
53
- other.is_a?(Duration)
54
- rescue ::NoMethodError
55
- false
343
+ # Returns the amount of seconds a duration covers as a string.
344
+ # For more information check to_i method.
345
+ #
346
+ # 1.day.to_s # => "86400"
347
+ def to_s
348
+ @value.to_s
349
+ end
350
+
351
+ # Returns the number of seconds that this Duration represents.
352
+ #
353
+ # 1.minute.to_i # => 60
354
+ # 1.hour.to_i # => 3600
355
+ # 1.day.to_i # => 86400
356
+ #
357
+ # Note that this conversion makes some assumptions about the
358
+ # duration of some periods, e.g. months are always 1/12 of year
359
+ # and years are 365.2425 days:
360
+ #
361
+ # # equivalent to (1.year / 12).to_i
362
+ # 1.month.to_i # => 2629746
363
+ #
364
+ # # equivalent to 365.2425.days.to_i
365
+ # 1.year.to_i # => 31556952
366
+ #
367
+ # In such cases, Ruby's core
368
+ # Date[https://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
369
+ # Time[https://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
370
+ # date and time arithmetic.
371
+ def to_i
372
+ @value.to_i
373
+ end
374
+ alias :in_seconds :to_i
375
+
376
+ # Returns the amount of minutes a duration covers as a float
377
+ #
378
+ # 1.day.in_minutes # => 1440.0
379
+ def in_minutes
380
+ in_seconds / SECONDS_PER_MINUTE.to_f
381
+ end
382
+
383
+ # Returns the amount of hours a duration covers as a float
384
+ #
385
+ # 1.day.in_hours # => 24.0
386
+ def in_hours
387
+ in_seconds / SECONDS_PER_HOUR.to_f
388
+ end
389
+
390
+ # Returns the amount of days a duration covers as a float
391
+ #
392
+ # 12.hours.in_days # => 0.5
393
+ def in_days
394
+ in_seconds / SECONDS_PER_DAY.to_f
395
+ end
396
+
397
+ # Returns the amount of weeks a duration covers as a float
398
+ #
399
+ # 2.months.in_weeks # => 8.696
400
+ def in_weeks
401
+ in_seconds / SECONDS_PER_WEEK.to_f
402
+ end
403
+
404
+ # Returns the amount of months a duration covers as a float
405
+ #
406
+ # 9.weeks.in_months # => 2.07
407
+ def in_months
408
+ in_seconds / SECONDS_PER_MONTH.to_f
409
+ end
410
+
411
+ # Returns the amount of years a duration covers as a float
412
+ #
413
+ # 30.days.in_years # => 0.082
414
+ def in_years
415
+ in_seconds / SECONDS_PER_YEAR.to_f
416
+ end
417
+
418
+ # Returns +true+ if +other+ is also a Duration instance, which has the
419
+ # same parts as this one.
420
+ def eql?(other)
421
+ Duration === other && other.value.eql?(value)
422
+ end
423
+
424
+ def hash
425
+ @value.hash
56
426
  end
57
427
 
58
428
  # Calculates a new Time or Date that is as far in the future
@@ -61,6 +431,7 @@ module ActiveSupport
61
431
  sum(1, time)
62
432
  end
63
433
  alias :from_now :since
434
+ alias :after :since
64
435
 
65
436
  # Calculates a new Time or Date that is as far in the past
66
437
  # as this Duration represents.
@@ -68,49 +439,76 @@ module ActiveSupport
68
439
  sum(-1, time)
69
440
  end
70
441
  alias :until :ago
442
+ alias :before :ago
443
+
444
+ def inspect # :nodoc:
445
+ return "#{value} seconds" if @parts.empty?
71
446
 
72
- def inspect #:nodoc:
73
- consolidated = parts.inject(::Hash.new(0)) { |h,(l,r)| h[l] += r; h }
74
- parts = [:years, :months, :days, :minutes, :seconds].map do |length|
75
- n = consolidated[length]
76
- "#{n} #{n == 1 ? length.to_s.singularize : length.to_s}" if n.nonzero?
77
- end.compact
78
- parts = ["0 seconds"] if parts.empty?
79
- parts.to_sentence(:locale => :en)
447
+ @parts.
448
+ sort_by { |unit, _ | PARTS.index(unit) }.
449
+ map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }.
450
+ to_sentence(locale: false)
80
451
  end
81
452
 
82
- def as_json(options = nil) #:nodoc:
453
+ def as_json(options = nil) # :nodoc:
83
454
  to_i
84
455
  end
85
456
 
86
- protected
457
+ def init_with(coder) # :nodoc:
458
+ initialize(coder["value"], coder["parts"])
459
+ end
460
+
461
+ def encode_with(coder) # :nodoc:
462
+ coder.map = { "value" => @value, "parts" => @parts }
463
+ end
464
+
465
+ # Build ISO 8601 Duration string for this duration.
466
+ # The +precision+ parameter can be used to limit seconds' precision of duration.
467
+ def iso8601(precision: nil)
468
+ ISO8601Serializer.new(self, precision: precision).serialize
469
+ end
470
+
471
+ def variable? # :nodoc:
472
+ @variable
473
+ end
87
474
 
88
- def sum(sign, time = ::Time.current) #:nodoc:
89
- parts.inject(time) do |t,(type,number)|
90
- if t.acts_like?(:time) || t.acts_like?(:date)
475
+ def _parts # :nodoc:
476
+ @parts
477
+ end
478
+
479
+ private
480
+ def sum(sign, time = ::Time.current)
481
+ unless time.acts_like?(:time) || time.acts_like?(:date)
482
+ raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
483
+ end
484
+
485
+ if @parts.empty?
486
+ time.since(sign * value)
487
+ else
488
+ @parts.inject(time) do |t, (type, number)|
91
489
  if type == :seconds
92
490
  t.since(sign * number)
491
+ elsif type == :minutes
492
+ t.since(sign * number * 60)
493
+ elsif type == :hours
494
+ t.since(sign * number * 3600)
93
495
  else
94
496
  t.advance(type => sign * number)
95
497
  end
96
- else
97
- raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
98
498
  end
99
499
  end
100
500
  end
101
501
 
102
- private
502
+ def respond_to_missing?(method, _)
503
+ value.respond_to?(method)
504
+ end
103
505
 
104
- # We define it as a workaround to Ruby 2.0.0-p353 bug.
105
- # For more information, check rails/rails#13055.
106
- # It should be dropped once a new Ruby patch-level
107
- # release after 2.0.0-p353 happens.
108
- def ===(other) #:nodoc:
109
- value === other
506
+ def method_missing(method, *args, &block)
507
+ value.public_send(method, *args, &block)
110
508
  end
111
509
 
112
- def method_missing(method, *args, &block) #:nodoc:
113
- value.send(method, *args, &block)
510
+ def raise_type_error(other)
511
+ raise TypeError, "no implicit conversion of #{other.class} into #{self.class}"
114
512
  end
115
513
  end
116
514
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "active_support/encrypted_file"
5
+ require "active_support/ordered_options"
6
+ require "active_support/core_ext/object/inclusion"
7
+ require "active_support/core_ext/module/delegation"
8
+
9
+ module ActiveSupport
10
+ class EncryptedConfiguration < EncryptedFile
11
+ delegate :[], :fetch, to: :config
12
+ delegate_missing_to :options
13
+
14
+ def initialize(config_path:, key_path:, env_key:, raise_if_missing_key:)
15
+ super content_path: config_path, key_path: key_path,
16
+ env_key: env_key, raise_if_missing_key: raise_if_missing_key
17
+ end
18
+
19
+ # Allow a config to be started without a file present
20
+ def read
21
+ super
22
+ rescue ActiveSupport::EncryptedFile::MissingContentError
23
+ ""
24
+ end
25
+
26
+ def write(contents)
27
+ deserialize(contents)
28
+
29
+ super
30
+ end
31
+
32
+ def config
33
+ @config ||= deserialize(read).deep_symbolize_keys
34
+ end
35
+
36
+ private
37
+ def deep_transform(hash)
38
+ return hash unless hash.is_a?(Hash)
39
+
40
+ h = ActiveSupport::InheritableOptions.new
41
+ hash.each do |k, v|
42
+ h[k] = deep_transform(v)
43
+ end
44
+ h
45
+ end
46
+
47
+ def options
48
+ @options ||= ActiveSupport::InheritableOptions.new(deep_transform(config))
49
+ end
50
+
51
+ def deserialize(config)
52
+ doc = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(config) : YAML.load(config)
53
+ doc.presence || {}
54
+ end
55
+ end
56
+ end