activesupport 1.2.4 → 8.1.2

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