omg-activesupport 8.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (289) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +86 -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 +163 -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 +251 -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 +290 -0
  17. data/lib/active_support/cache/memory_store.rb +262 -0
  18. data/lib/active_support/cache/null_store.rb +62 -0
  19. data/lib/active_support/cache/redis_cache_store.rb +492 -0
  20. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  21. data/lib/active_support/cache/strategy/local_cache.rb +201 -0
  22. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  23. data/lib/active_support/cache.rb +1104 -0
  24. data/lib/active_support/callbacks.rb +944 -0
  25. data/lib/active_support/class_attribute.rb +26 -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 +72 -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/configurable.rb +159 -0
  32. data/lib/active_support/configuration_file.rb +60 -0
  33. data/lib/active_support/core_ext/array/access.rb +100 -0
  34. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  35. data/lib/active_support/core_ext/array/extract.rb +21 -0
  36. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  37. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  38. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  39. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  40. data/lib/active_support/core_ext/array.rb +9 -0
  41. data/lib/active_support/core_ext/benchmark.rb +13 -0
  42. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  43. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  44. data/lib/active_support/core_ext/class/attribute.rb +122 -0
  45. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  46. data/lib/active_support/core_ext/class/subclasses.rb +24 -0
  47. data/lib/active_support/core_ext/class.rb +4 -0
  48. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  49. data/lib/active_support/core_ext/date/blank.rb +18 -0
  50. data/lib/active_support/core_ext/date/calculations.rb +161 -0
  51. data/lib/active_support/core_ext/date/conversions.rb +98 -0
  52. data/lib/active_support/core_ext/date/zones.rb +8 -0
  53. data/lib/active_support/core_ext/date.rb +7 -0
  54. data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
  55. data/lib/active_support/core_ext/date_and_time/compatibility.rb +58 -0
  56. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  57. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  58. data/lib/active_support/core_ext/date_time/blank.rb +18 -0
  59. data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
  60. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  61. data/lib/active_support/core_ext/date_time/conversions.rb +106 -0
  62. data/lib/active_support/core_ext/date_time.rb +7 -0
  63. data/lib/active_support/core_ext/digest/uuid.rb +76 -0
  64. data/lib/active_support/core_ext/digest.rb +3 -0
  65. data/lib/active_support/core_ext/enumerable.rb +267 -0
  66. data/lib/active_support/core_ext/erb/util.rb +201 -0
  67. data/lib/active_support/core_ext/file/atomic.rb +72 -0
  68. data/lib/active_support/core_ext/file.rb +3 -0
  69. data/lib/active_support/core_ext/hash/conversions.rb +262 -0
  70. data/lib/active_support/core_ext/hash/deep_merge.rb +42 -0
  71. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  72. data/lib/active_support/core_ext/hash/except.rb +12 -0
  73. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  74. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  75. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  76. data/lib/active_support/core_ext/hash/slice.rb +27 -0
  77. data/lib/active_support/core_ext/hash.rb +10 -0
  78. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  79. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  80. data/lib/active_support/core_ext/integer/time.rb +22 -0
  81. data/lib/active_support/core_ext/integer.rb +5 -0
  82. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  83. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  84. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  85. data/lib/active_support/core_ext/kernel.rb +5 -0
  86. data/lib/active_support/core_ext/load_error.rb +9 -0
  87. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  88. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  89. data/lib/active_support/core_ext/module/attr_internal.rb +49 -0
  90. data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
  91. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
  92. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  93. data/lib/active_support/core_ext/module/delegation.rb +225 -0
  94. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  95. data/lib/active_support/core_ext/module/introspection.rb +62 -0
  96. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  97. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  98. data/lib/active_support/core_ext/module.rb +13 -0
  99. data/lib/active_support/core_ext/name_error.rb +59 -0
  100. data/lib/active_support/core_ext/numeric/bytes.rb +75 -0
  101. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  102. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  103. data/lib/active_support/core_ext/numeric.rb +5 -0
  104. data/lib/active_support/core_ext/object/acts_like.rb +45 -0
  105. data/lib/active_support/core_ext/object/blank.rb +199 -0
  106. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  107. data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
  108. data/lib/active_support/core_ext/object/duplicable.rb +69 -0
  109. data/lib/active_support/core_ext/object/inclusion.rb +37 -0
  110. data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
  111. data/lib/active_support/core_ext/object/json.rb +260 -0
  112. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  113. data/lib/active_support/core_ext/object/to_query.rb +87 -0
  114. data/lib/active_support/core_ext/object/try.rb +158 -0
  115. data/lib/active_support/core_ext/object/with.rb +46 -0
  116. data/lib/active_support/core_ext/object/with_options.rb +101 -0
  117. data/lib/active_support/core_ext/object.rb +17 -0
  118. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  119. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  120. data/lib/active_support/core_ext/pathname.rb +4 -0
  121. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  122. data/lib/active_support/core_ext/range/conversions.rb +62 -0
  123. data/lib/active_support/core_ext/range/each.rb +24 -0
  124. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  125. data/lib/active_support/core_ext/range.rb +6 -0
  126. data/lib/active_support/core_ext/regexp.rb +14 -0
  127. data/lib/active_support/core_ext/securerandom.rb +41 -0
  128. data/lib/active_support/core_ext/string/access.rb +95 -0
  129. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  130. data/lib/active_support/core_ext/string/conversions.rb +60 -0
  131. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  132. data/lib/active_support/core_ext/string/filters.rb +151 -0
  133. data/lib/active_support/core_ext/string/indent.rb +45 -0
  134. data/lib/active_support/core_ext/string/inflections.rb +300 -0
  135. data/lib/active_support/core_ext/string/inquiry.rb +16 -0
  136. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  137. data/lib/active_support/core_ext/string/output_safety.rb +228 -0
  138. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  139. data/lib/active_support/core_ext/string/strip.rb +27 -0
  140. data/lib/active_support/core_ext/string/zones.rb +16 -0
  141. data/lib/active_support/core_ext/string.rb +15 -0
  142. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  143. data/lib/active_support/core_ext/symbol.rb +3 -0
  144. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  145. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  146. data/lib/active_support/core_ext/time/calculations.rb +386 -0
  147. data/lib/active_support/core_ext/time/compatibility.rb +32 -0
  148. data/lib/active_support/core_ext/time/conversions.rb +75 -0
  149. data/lib/active_support/core_ext/time/zones.rb +97 -0
  150. data/lib/active_support/core_ext/time.rb +7 -0
  151. data/lib/active_support/core_ext.rb +5 -0
  152. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  153. data/lib/active_support/current_attributes.rb +233 -0
  154. data/lib/active_support/deep_mergeable.rb +53 -0
  155. data/lib/active_support/delegation.rb +202 -0
  156. data/lib/active_support/dependencies/autoload.rb +72 -0
  157. data/lib/active_support/dependencies/interlock.rb +49 -0
  158. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  159. data/lib/active_support/dependencies.rb +98 -0
  160. data/lib/active_support/deprecation/behaviors.rb +148 -0
  161. data/lib/active_support/deprecation/constant_accessor.rb +74 -0
  162. data/lib/active_support/deprecation/deprecators.rb +104 -0
  163. data/lib/active_support/deprecation/disallowed.rb +54 -0
  164. data/lib/active_support/deprecation/method_wrappers.rb +68 -0
  165. data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
  166. data/lib/active_support/deprecation/reporting.rb +179 -0
  167. data/lib/active_support/deprecation.rb +81 -0
  168. data/lib/active_support/deprecator.rb +7 -0
  169. data/lib/active_support/descendants_tracker.rb +112 -0
  170. data/lib/active_support/digest.rb +22 -0
  171. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  172. data/lib/active_support/duration/iso8601_serializer.rb +64 -0
  173. data/lib/active_support/duration.rb +520 -0
  174. data/lib/active_support/encrypted_configuration.rb +126 -0
  175. data/lib/active_support/encrypted_file.rb +133 -0
  176. data/lib/active_support/environment_inquirer.rb +40 -0
  177. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  178. data/lib/active_support/error_reporter.rb +265 -0
  179. data/lib/active_support/evented_file_update_checker.rb +182 -0
  180. data/lib/active_support/execution_context/test_helper.rb +13 -0
  181. data/lib/active_support/execution_context.rb +53 -0
  182. data/lib/active_support/execution_wrapper.rb +150 -0
  183. data/lib/active_support/executor/test_helper.rb +7 -0
  184. data/lib/active_support/executor.rb +8 -0
  185. data/lib/active_support/file_update_checker.rb +164 -0
  186. data/lib/active_support/fork_tracker.rb +43 -0
  187. data/lib/active_support/gem_version.rb +17 -0
  188. data/lib/active_support/gzip.rb +40 -0
  189. data/lib/active_support/hash_with_indifferent_access.rb +445 -0
  190. data/lib/active_support/html_safe_translation.rb +56 -0
  191. data/lib/active_support/i18n.rb +17 -0
  192. data/lib/active_support/i18n_railtie.rb +138 -0
  193. data/lib/active_support/inflections.rb +72 -0
  194. data/lib/active_support/inflector/inflections.rb +273 -0
  195. data/lib/active_support/inflector/methods.rb +387 -0
  196. data/lib/active_support/inflector/transliterate.rb +149 -0
  197. data/lib/active_support/inflector.rb +9 -0
  198. data/lib/active_support/isolated_execution_state.rb +75 -0
  199. data/lib/active_support/json/decoding.rb +76 -0
  200. data/lib/active_support/json/encoding.rb +120 -0
  201. data/lib/active_support/json.rb +4 -0
  202. data/lib/active_support/key_generator.rb +66 -0
  203. data/lib/active_support/lazy_load_hooks.rb +107 -0
  204. data/lib/active_support/locale/en.rb +33 -0
  205. data/lib/active_support/locale/en.yml +141 -0
  206. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  207. data/lib/active_support/log_subscriber.rb +192 -0
  208. data/lib/active_support/logger.rb +55 -0
  209. data/lib/active_support/logger_silence.rb +21 -0
  210. data/lib/active_support/logger_thread_safe_level.rb +47 -0
  211. data/lib/active_support/message_encryptor.rb +374 -0
  212. data/lib/active_support/message_encryptors.rb +141 -0
  213. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  214. data/lib/active_support/message_pack/extensions.rb +305 -0
  215. data/lib/active_support/message_pack/serializer.rb +63 -0
  216. data/lib/active_support/message_pack.rb +50 -0
  217. data/lib/active_support/message_verifier.rb +368 -0
  218. data/lib/active_support/message_verifiers.rb +135 -0
  219. data/lib/active_support/messages/codec.rb +65 -0
  220. data/lib/active_support/messages/metadata.rb +146 -0
  221. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  222. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  223. data/lib/active_support/messages/rotator.rb +59 -0
  224. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  225. data/lib/active_support/multibyte/chars.rb +178 -0
  226. data/lib/active_support/multibyte/unicode.rb +42 -0
  227. data/lib/active_support/multibyte.rb +23 -0
  228. data/lib/active_support/notifications/fanout.rb +446 -0
  229. data/lib/active_support/notifications/instrumenter.rb +240 -0
  230. data/lib/active_support/notifications.rb +281 -0
  231. data/lib/active_support/number_helper/number_converter.rb +190 -0
  232. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  233. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  234. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  235. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  236. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  237. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  238. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  239. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  240. data/lib/active_support/number_helper.rb +479 -0
  241. data/lib/active_support/option_merger.rb +38 -0
  242. data/lib/active_support/ordered_hash.rb +50 -0
  243. data/lib/active_support/ordered_options.rb +147 -0
  244. data/lib/active_support/parameter_filter.rb +157 -0
  245. data/lib/active_support/proxy_object.rb +20 -0
  246. data/lib/active_support/rails.rb +26 -0
  247. data/lib/active_support/railtie.rb +161 -0
  248. data/lib/active_support/reloader.rb +138 -0
  249. data/lib/active_support/rescuable.rb +176 -0
  250. data/lib/active_support/secure_compare_rotator.rb +58 -0
  251. data/lib/active_support/security_utils.rb +38 -0
  252. data/lib/active_support/string_inquirer.rb +35 -0
  253. data/lib/active_support/subscriber.rb +146 -0
  254. data/lib/active_support/syntax_error_proxy.rb +60 -0
  255. data/lib/active_support/tagged_logging.rb +152 -0
  256. data/lib/active_support/test_case.rb +304 -0
  257. data/lib/active_support/testing/assertions.rb +332 -0
  258. data/lib/active_support/testing/autorun.rb +5 -0
  259. data/lib/active_support/testing/constant_lookup.rb +51 -0
  260. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  261. data/lib/active_support/testing/declarative.rb +28 -0
  262. data/lib/active_support/testing/deprecation.rb +82 -0
  263. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  264. data/lib/active_support/testing/file_fixtures.rb +38 -0
  265. data/lib/active_support/testing/isolation.rb +121 -0
  266. data/lib/active_support/testing/method_call_assertions.rb +69 -0
  267. data/lib/active_support/testing/parallelization/server.rb +85 -0
  268. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  269. data/lib/active_support/testing/parallelization.rb +55 -0
  270. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  271. data/lib/active_support/testing/setup_and_teardown.rb +57 -0
  272. data/lib/active_support/testing/stream.rb +41 -0
  273. data/lib/active_support/testing/strict_warnings.rb +43 -0
  274. data/lib/active_support/testing/tagged_logging.rb +27 -0
  275. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  276. data/lib/active_support/testing/time_helpers.rb +269 -0
  277. data/lib/active_support/time.rb +20 -0
  278. data/lib/active_support/time_with_zone.rb +609 -0
  279. data/lib/active_support/values/time_zone.rb +614 -0
  280. data/lib/active_support/version.rb +10 -0
  281. data/lib/active_support/xml_mini/jdom.rb +175 -0
  282. data/lib/active_support/xml_mini/libxml.rb +80 -0
  283. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  284. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  285. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  286. data/lib/active_support/xml_mini/rexml.rb +137 -0
  287. data/lib/active_support/xml_mini.rb +211 -0
  288. data/lib/active_support.rb +144 -0
  289. metadata +526 -0
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ class Pathname
6
+ # Returns the receiver if the named file exists otherwise returns +nil+.
7
+ # <tt>pathname.existence</tt> is equivalent to
8
+ #
9
+ # pathname.exist? ? pathname : nil
10
+ #
11
+ # For example, something like
12
+ #
13
+ # content = pathname.read if pathname.exist?
14
+ #
15
+ # becomes
16
+ #
17
+ # content = pathname.existence&.read
18
+ #
19
+ # @return [Pathname]
20
+ def existence
21
+ self if exist?
22
+ end
23
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/pathname/blank"
4
+ require "active_support/core_ext/pathname/existence"
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module CompareWithRange
5
+ # Extends the default Range#=== to support range comparisons.
6
+ # (1..5) === (1..5) # => true
7
+ # (1..5) === (2..3) # => true
8
+ # (1..5) === (1...6) # => true
9
+ # (1..5) === (2..6) # => false
10
+ #
11
+ # The native Range#=== behavior is untouched.
12
+ # ('a'..'f') === ('c') # => true
13
+ # (5..9) === (11) # => false
14
+ #
15
+ # The given range must be fully bounded, with both start and end.
16
+ def ===(value)
17
+ if value.is_a?(::Range)
18
+ is_backwards_op = value.exclude_end? ? :>= : :>
19
+ return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
20
+ # 1...10 includes 1..9 but it does not include 1..10.
21
+ # 1..10 includes 1...11 but it does not include 1...12.
22
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
23
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
24
+ super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ # Extends the default Range#include? to support range comparisons.
31
+ # (1..5).include?(1..5) # => true
32
+ # (1..5).include?(2..3) # => true
33
+ # (1..5).include?(1...6) # => true
34
+ # (1..5).include?(2..6) # => false
35
+ #
36
+ # The native Range#include? behavior is untouched.
37
+ # ('a'..'f').include?('c') # => true
38
+ # (5..9).include?(11) # => false
39
+ #
40
+ # The given range must be fully bounded, with both start and end.
41
+ def include?(value)
42
+ if value.is_a?(::Range)
43
+ is_backwards_op = value.exclude_end? ? :>= : :>
44
+ return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
45
+ # 1...10 includes 1..9 but it does not include 1..10.
46
+ # 1..10 includes 1...11 but it does not include 1...12.
47
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
48
+ value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
49
+ super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
50
+ else
51
+ super
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ Range.prepend(ActiveSupport::CompareWithRange)
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ # = \Range With Format
5
+ module RangeWithFormat
6
+ RANGE_FORMATS = {
7
+ db: -> (start, stop) do
8
+ if start && stop
9
+ case start
10
+ when String then "BETWEEN '#{start}' AND '#{stop}'"
11
+ else
12
+ "BETWEEN '#{start.to_fs(:db)}' AND '#{stop.to_fs(:db)}'"
13
+ end
14
+ elsif start
15
+ case start
16
+ when String then ">= '#{start}'"
17
+ else
18
+ ">= '#{start.to_fs(:db)}'"
19
+ end
20
+ elsif stop
21
+ case stop
22
+ when String then "<= '#{stop}'"
23
+ else
24
+ "<= '#{stop.to_fs(:db)}'"
25
+ end
26
+ end
27
+ end
28
+ }
29
+
30
+ # Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
31
+ #
32
+ # This method is aliased to <tt>to_formatted_s</tt>.
33
+ #
34
+ # range = (1..100) # => 1..100
35
+ #
36
+ # range.to_s # => "1..100"
37
+ # range.to_fs(:db) # => "BETWEEN '1' AND '100'"
38
+ #
39
+ # range = (1..) # => 1..
40
+ # range.to_fs(:db) # => ">= '1'"
41
+ #
42
+ # range = (..100) # => ..100
43
+ # range.to_fs(:db) # => "<= '100'"
44
+ #
45
+ # == Adding your own range formats to to_fs
46
+ # You can add your own formats to the Range::RANGE_FORMATS hash.
47
+ # Use the format name as the hash key and a Proc instance.
48
+ #
49
+ # # config/initializers/range_formats.rb
50
+ # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_fs(:db)} and #{stop.to_fs(:db)}" }
51
+ def to_fs(format = :default)
52
+ if formatter = RANGE_FORMATS[format]
53
+ formatter.call(self.begin, self.end)
54
+ else
55
+ to_s
56
+ end
57
+ end
58
+ alias_method :to_formatted_s, :to_fs
59
+ end
60
+ end
61
+
62
+ Range.prepend(ActiveSupport::RangeWithFormat)
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/time_with_zone"
4
+
5
+ module ActiveSupport
6
+ module EachTimeWithZone # :nodoc:
7
+ def each(&block)
8
+ ensure_iteration_allowed
9
+ super
10
+ end
11
+
12
+ def step(n = 1, &block)
13
+ ensure_iteration_allowed
14
+ super
15
+ end
16
+
17
+ private
18
+ def ensure_iteration_allowed
19
+ raise TypeError, "can't iterate from #{first.class}" if first.is_a?(TimeWithZone)
20
+ end
21
+ end
22
+ end
23
+
24
+ Range.prepend(ActiveSupport::EachTimeWithZone)
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Range
4
+ # Compare two ranges and see if they overlap each other
5
+ # (1..5).overlap?(4..6) # => true
6
+ # (1..5).overlap?(7..9) # => false
7
+ unless Range.method_defined?(:overlap?) # Ruby 3.3+
8
+ def overlap?(other)
9
+ raise TypeError unless other.is_a? Range
10
+
11
+ self_begin = self.begin
12
+ other_end = other.end
13
+ other_excl = other.exclude_end?
14
+
15
+ return false if _empty_range?(self_begin, other_end, other_excl)
16
+
17
+ other_begin = other.begin
18
+ self_end = self.end
19
+ self_excl = self.exclude_end?
20
+
21
+ return false if _empty_range?(other_begin, self_end, self_excl)
22
+ return true if self_begin == other_begin
23
+
24
+ return false if _empty_range?(self_begin, self_end, self_excl)
25
+ return false if _empty_range?(other_begin, other_end, other_excl)
26
+
27
+ true
28
+ end
29
+
30
+ private
31
+ def _empty_range?(b, e, excl)
32
+ return false if b.nil? || e.nil?
33
+
34
+ comp = b <=> e
35
+ comp.nil? || comp > 0 || (comp == 0 && excl)
36
+ end
37
+ end
38
+
39
+ alias :overlaps? :overlap?
40
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/range/conversions"
4
+ require "active_support/core_ext/range/compare_range"
5
+ require "active_support/core_ext/range/overlap"
6
+ require "active_support/core_ext/range/each"
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Regexp
4
+ # Returns +true+ if the regexp has the multiline flag set.
5
+ #
6
+ # (/./).multiline? # => false
7
+ # (/./m).multiline? # => true
8
+ #
9
+ # Regexp.new(".").multiline? # => false
10
+ # Regexp.new(".", Regexp::MULTILINE).multiline? # => true
11
+ def multiline?
12
+ options & MULTILINE == MULTILINE
13
+ end
14
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
5
+ module SecureRandom
6
+ BASE58_ALPHABET = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a - ["0", "O", "I", "l"]
7
+ BASE36_ALPHABET = ("0".."9").to_a + ("a".."z").to_a
8
+
9
+ # SecureRandom.base58 generates a random base58 string.
10
+ #
11
+ # The argument _n_ specifies the length of the random string to be generated.
12
+ #
13
+ # If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
14
+ #
15
+ # The result may contain alphanumeric characters except 0, O, I, and l.
16
+ #
17
+ # p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
18
+ # p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
19
+ def self.base58(n = 16)
20
+ SecureRandom.alphanumeric(n, chars: BASE58_ALPHABET)
21
+ end
22
+
23
+ # SecureRandom.base36 generates a random base36 string in lowercase.
24
+ #
25
+ # The argument _n_ specifies the length of the random string to be generated.
26
+ #
27
+ # If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
28
+ # This method can be used over +base58+ if a deterministic case key is necessary.
29
+ #
30
+ # The result will contain alphanumeric characters in lowercase.
31
+ #
32
+ # p SecureRandom.base36 # => "4kugl2pdqmscqtje"
33
+ # p SecureRandom.base36(24) # => "77tmhrhjfvfdwodq8w7ev2m7"
34
+ def self.base36(n = 16)
35
+ SecureRandom.random_bytes(n).unpack("C*").map do |byte|
36
+ idx = byte % 64
37
+ idx = SecureRandom.random_number(36) if idx >= 36
38
+ BASE36_ALPHABET[idx]
39
+ end.join
40
+ end
41
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ # If you pass a single integer, returns a substring of one character at that
5
+ # position. The first character of the string is at position 0, the next at
6
+ # position 1, and so on. If a range is supplied, a substring containing
7
+ # characters at offsets given by the range is returned. In both cases, if an
8
+ # offset is negative, it is counted from the end of the string. Returns +nil+
9
+ # if the initial offset falls outside the string. Returns an empty string if
10
+ # the beginning of the range is greater than the end of the string.
11
+ #
12
+ # str = "hello"
13
+ # str.at(0) # => "h"
14
+ # str.at(1..3) # => "ell"
15
+ # str.at(-2) # => "l"
16
+ # str.at(-2..-1) # => "lo"
17
+ # str.at(5) # => nil
18
+ # str.at(5..-1) # => ""
19
+ #
20
+ # If a Regexp is given, the matching portion of the string is returned.
21
+ # If a String is given, that given string is returned if it occurs in
22
+ # the string. In both cases, +nil+ is returned if there is no match.
23
+ #
24
+ # str = "hello"
25
+ # str.at(/lo/) # => "lo"
26
+ # str.at(/ol/) # => nil
27
+ # str.at("lo") # => "lo"
28
+ # str.at("ol") # => nil
29
+ def at(position)
30
+ self[position]
31
+ end
32
+
33
+ # Returns a substring from the given position to the end of the string.
34
+ # If the position is negative, it is counted from the end of the string.
35
+ #
36
+ # str = "hello"
37
+ # str.from(0) # => "hello"
38
+ # str.from(3) # => "lo"
39
+ # str.from(-2) # => "lo"
40
+ #
41
+ # You can mix it with +to+ method and do fun things like:
42
+ #
43
+ # str = "hello"
44
+ # str.from(0).to(-1) # => "hello"
45
+ # str.from(1).to(-2) # => "ell"
46
+ def from(position)
47
+ self[position, length]
48
+ end
49
+
50
+ # Returns a substring from the beginning of the string to the given position.
51
+ # If the position is negative, it is counted from the end of the string.
52
+ #
53
+ # str = "hello"
54
+ # str.to(0) # => "h"
55
+ # str.to(3) # => "hell"
56
+ # str.to(-2) # => "hell"
57
+ #
58
+ # You can mix it with +from+ method and do fun things like:
59
+ #
60
+ # str = "hello"
61
+ # str.from(0).to(-1) # => "hello"
62
+ # str.from(1).to(-2) # => "ell"
63
+ def to(position)
64
+ position += size if position < 0
65
+ self[0, position + 1] || +""
66
+ end
67
+
68
+ # Returns the first character. If a limit is supplied, returns a substring
69
+ # from the beginning of the string until it reaches the limit value. If the
70
+ # given limit is greater than or equal to the string length, returns a copy of self.
71
+ #
72
+ # str = "hello"
73
+ # str.first # => "h"
74
+ # str.first(1) # => "h"
75
+ # str.first(2) # => "he"
76
+ # str.first(0) # => ""
77
+ # str.first(6) # => "hello"
78
+ def first(limit = 1)
79
+ self[0, limit] || raise(ArgumentError, "negative limit")
80
+ end
81
+
82
+ # Returns the last character of the string. If a limit is supplied, returns a substring
83
+ # from the end of the string until it reaches the limit value (counting backwards). If
84
+ # the given limit is greater than or equal to the string length, returns a copy of self.
85
+ #
86
+ # str = "hello"
87
+ # str.last # => "o"
88
+ # str.last(1) # => "o"
89
+ # str.last(2) # => "lo"
90
+ # str.last(0) # => ""
91
+ # str.last(6) # => "hello"
92
+ def last(limit = 1)
93
+ self[[length - limit, 0].max, limit] || raise(ArgumentError, "negative limit")
94
+ end
95
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ # Enables more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
5
+ def acts_like_string?
6
+ true
7
+ end
8
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "active_support/core_ext/time/calculations"
5
+
6
+ class String
7
+ # Converts a string to a Time value.
8
+ # The +form+ can be either +:utc+ or +:local+ (default +:local+).
9
+ #
10
+ # The time is parsed using Time.parse method.
11
+ # If +form+ is +:local+, then the time is in the system timezone.
12
+ # If the date part is missing then the current date is used and if
13
+ # the time part is missing then it is assumed to be 00:00:00.
14
+ #
15
+ # "13-12-2012".to_time # => 2012-12-13 00:00:00 +0100
16
+ # "06:12".to_time # => 2012-12-13 06:12:00 +0100
17
+ # "2012-12-13 06:12".to_time # => 2012-12-13 06:12:00 +0100
18
+ # "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 +0100
19
+ # "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 06:12:00 UTC
20
+ # "12/13/2012".to_time # => ArgumentError: argument out of range
21
+ # "1604326192".to_time # => ArgumentError: argument out of range
22
+ def to_time(form = :local)
23
+ parts = Date._parse(self, false)
24
+ used_keys = %i(year mon mday hour min sec sec_fraction offset)
25
+ return if !parts.keys.intersect?(used_keys)
26
+
27
+ now = Time.now
28
+ time = Time.new(
29
+ parts.fetch(:year, now.year),
30
+ parts.fetch(:mon, now.month),
31
+ parts.fetch(:mday, now.day),
32
+ parts.fetch(:hour, 0),
33
+ parts.fetch(:min, 0),
34
+ parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
35
+ parts.fetch(:offset, form == :utc ? 0 : nil)
36
+ )
37
+
38
+ form == :utc ? time.utc : time.to_time
39
+ end
40
+
41
+ # Converts a string to a Date value.
42
+ #
43
+ # "1-1-2012".to_date # => Sun, 01 Jan 2012
44
+ # "01/01/2012".to_date # => Sun, 01 Jan 2012
45
+ # "2012-12-13".to_date # => Thu, 13 Dec 2012
46
+ # "12/13/2012".to_date # => ArgumentError: invalid date
47
+ def to_date
48
+ ::Date.parse(self, false) unless blank?
49
+ end
50
+
51
+ # Converts a string to a DateTime value.
52
+ #
53
+ # "1-1-2012".to_datetime # => Sun, 01 Jan 2012 00:00:00 +0000
54
+ # "01/01/2012 23:59:59".to_datetime # => Sun, 01 Jan 2012 23:59:59 +0000
55
+ # "2012-12-13 12:50".to_datetime # => Thu, 13 Dec 2012 12:50:00 +0000
56
+ # "12/13/2012".to_datetime # => ArgumentError: invalid date
57
+ def to_datetime
58
+ ::DateTime.parse(self, false) unless blank?
59
+ end
60
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ # The inverse of <tt>String#include?</tt>. Returns true if the string
5
+ # does not include the other string.
6
+ #
7
+ # "hello".exclude? "lo" # => false
8
+ # "hello".exclude? "ol" # => true
9
+ # "hello".exclude? ?h # => false
10
+ def exclude?(string)
11
+ !include?(string)
12
+ end
13
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ # Returns the string, first removing all whitespace on both ends of
5
+ # the string, and then changing remaining consecutive whitespace
6
+ # groups into one space each.
7
+ #
8
+ # Note that it handles both ASCII and Unicode whitespace.
9
+ #
10
+ # %{ Multi-line
11
+ # string }.squish # => "Multi-line string"
12
+ # " foo bar \n \t boo".squish # => "foo bar boo"
13
+ def squish
14
+ dup.squish!
15
+ end
16
+
17
+ # Performs a destructive squish. See String#squish.
18
+ # str = " foo bar \n \t boo"
19
+ # str.squish! # => "foo bar boo"
20
+ # str # => "foo bar boo"
21
+ def squish!
22
+ gsub!(/[[:space:]]+/, " ")
23
+ strip!
24
+ self
25
+ end
26
+
27
+ # Returns a new string with all occurrences of the patterns removed.
28
+ # str = "foo bar test"
29
+ # str.remove(" test") # => "foo bar"
30
+ # str.remove(" test", /bar/) # => "foo "
31
+ # str # => "foo bar test"
32
+ def remove(*patterns)
33
+ dup.remove!(*patterns)
34
+ end
35
+
36
+ # Alters the string by removing all occurrences of the patterns.
37
+ # str = "foo bar test"
38
+ # str.remove!(" test", /bar/) # => "foo "
39
+ # str # => "foo "
40
+ def remove!(*patterns)
41
+ patterns.each do |pattern|
42
+ gsub! pattern, ""
43
+ end
44
+
45
+ self
46
+ end
47
+
48
+ # Truncates a given +text+ to length <tt>truncate_to</tt> if +text+ is longer than <tt>truncate_to</tt>:
49
+ #
50
+ # 'Once upon a time in a world far far away'.truncate(27)
51
+ # # => "Once upon a time in a wo..."
52
+ #
53
+ # Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break:
54
+ #
55
+ # 'Once upon a time in a world far far away'.truncate(27, separator: ' ')
56
+ # # => "Once upon a time in a..."
57
+ #
58
+ # 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
59
+ # # => "Once upon a time in a..."
60
+ #
61
+ # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...").
62
+ # The total length will not exceed <tt>truncate_to</tt> unless both +text+ and <tt>:omission</tt>
63
+ # are longer than <tt>truncate_to</tt>:
64
+ #
65
+ # 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
66
+ # # => "And they f... (continued)"
67
+ #
68
+ # 'And they found that many people were sleeping better.'.truncate(4, omission: '... (continued)')
69
+ # # => "... (continued)"
70
+ def truncate(truncate_to, options = {})
71
+ return dup unless length > truncate_to
72
+
73
+ omission = options[:omission] || "..."
74
+ length_with_room_for_omission = truncate_to - omission.length
75
+ stop = \
76
+ if options[:separator]
77
+ rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
78
+ else
79
+ length_with_room_for_omission
80
+ end
81
+
82
+ +"#{self[0, stop]}#{omission}"
83
+ end
84
+
85
+ # Truncates +text+ to at most <tt>truncate_to</tt> bytes in length without
86
+ # breaking string encoding by splitting multibyte characters or breaking
87
+ # grapheme clusters ("perceptual characters") by truncating at combining
88
+ # characters.
89
+ #
90
+ # >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".size
91
+ # => 20
92
+ # >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".bytesize
93
+ # => 80
94
+ # >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".truncate_bytes(20)
95
+ # => "🔪🔪🔪🔪…"
96
+ #
97
+ # The truncated text ends with the <tt>:omission</tt> string, defaulting
98
+ # to "…", for a total length not exceeding <tt>truncate_to</tt>.
99
+ #
100
+ # Raises +ArgumentError+ when the bytesize of <tt>:omission</tt> exceeds <tt>truncate_to</tt>.
101
+ def truncate_bytes(truncate_to, omission: "…")
102
+ omission ||= ""
103
+
104
+ case
105
+ when bytesize <= truncate_to
106
+ dup
107
+ when omission.bytesize > truncate_to
108
+ raise ArgumentError, "Omission #{omission.inspect} is #{omission.bytesize}, larger than the truncation length of #{truncate_to} bytes"
109
+ when omission.bytesize == truncate_to
110
+ omission.dup
111
+ else
112
+ self.class.new.force_encoding(encoding).tap do |cut|
113
+ cut_at = truncate_to - omission.bytesize
114
+
115
+ each_grapheme_cluster do |grapheme|
116
+ if cut.bytesize + grapheme.bytesize <= cut_at
117
+ cut << grapheme
118
+ else
119
+ break
120
+ end
121
+ end
122
+
123
+ cut << omission
124
+ end
125
+ end
126
+ end
127
+
128
+ # Truncates a given +text+ after a given number of words (<tt>words_count</tt>):
129
+ #
130
+ # 'Once upon a time in a world far far away'.truncate_words(4)
131
+ # # => "Once upon a time..."
132
+ #
133
+ # Pass a string or regexp <tt>:separator</tt> to specify a different separator of words:
134
+ #
135
+ # 'Once<br>upon<br>a<br>time<br>in<br>a<br>world'.truncate_words(5, separator: '<br>')
136
+ # # => "Once<br>upon<br>a<br>time<br>in..."
137
+ #
138
+ # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "..."):
139
+ #
140
+ # 'And they found that many people were sleeping better.'.truncate_words(5, omission: '... (continued)')
141
+ # # => "And they found that many... (continued)"
142
+ def truncate_words(words_count, options = {})
143
+ sep = options[:separator] || /\s+/
144
+ sep = Regexp.escape(sep.to_s) unless Regexp === sep
145
+ if self =~ /\A((?>.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m
146
+ $1 + (options[:omission] || "...")
147
+ else
148
+ dup
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ # Same as +indent+, except it indents the receiver in-place.
5
+ #
6
+ # Returns the indented string, or +nil+ if there was nothing to indent.
7
+ def indent!(amount, indent_string = nil, indent_empty_lines = false)
8
+ indent_string = indent_string || self[/^[ \t]/] || " "
9
+ re = indent_empty_lines ? /^/ : /^(?!$)/
10
+ gsub!(re, indent_string * amount)
11
+ end
12
+
13
+ # Indents the lines in the receiver:
14
+ #
15
+ # <<EOS.indent(2)
16
+ # def some_method
17
+ # some_code
18
+ # end
19
+ # EOS
20
+ # # =>
21
+ # def some_method
22
+ # some_code
23
+ # end
24
+ #
25
+ # The second argument, +indent_string+, specifies which indent string to
26
+ # use. The default is +nil+, which tells the method to make a guess by
27
+ # peeking at the first indented line, and fall back to a space if there is
28
+ # none.
29
+ #
30
+ # " foo".indent(2) # => " foo"
31
+ # "foo\n\t\tbar".indent(2) # => "\t\tfoo\n\t\t\t\tbar"
32
+ # "foo".indent(2, "\t") # => "\t\tfoo"
33
+ #
34
+ # While +indent_string+ is typically one space or tab, it may be any string.
35
+ #
36
+ # The third argument, +indent_empty_lines+, is a flag that says whether
37
+ # empty lines should be indented. Default is false.
38
+ #
39
+ # "foo\n\nbar".indent(2) # => " foo\n\n bar"
40
+ # "foo\n\nbar".indent(2, nil, true) # => " foo\n \n bar"
41
+ #
42
+ def indent(amount, indent_string = nil, indent_empty_lines = false)
43
+ dup.tap { |_| _.indent!(amount, indent_string, indent_empty_lines) }
44
+ end
45
+ end