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,387 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/inflections"
4
+
5
+ module ActiveSupport
6
+ # = Active Support \Inflector
7
+ #
8
+ # The Inflector transforms words from singular to plural, class names to table
9
+ # names, modularized class names to ones without, and class names to foreign
10
+ # keys. The default inflections for pluralization, singularization, and
11
+ # uncountable words are kept in inflections.rb.
12
+ #
13
+ # The \Rails core team has stated patches for the inflections library will not
14
+ # be accepted in order to avoid breaking legacy applications which may be
15
+ # relying on errant inflections. If you discover an incorrect inflection and
16
+ # require it for your application or wish to define rules for languages other
17
+ # than English, please correct or add them yourself (explained below).
18
+ module Inflector
19
+ extend self
20
+
21
+ # Returns the plural form of the word in the string.
22
+ #
23
+ # If passed an optional +locale+ parameter, the word will be
24
+ # pluralized using rules defined for that language. By default,
25
+ # this parameter is set to <tt>:en</tt>.
26
+ #
27
+ # pluralize('post') # => "posts"
28
+ # pluralize('octopus') # => "octopi"
29
+ # pluralize('sheep') # => "sheep"
30
+ # pluralize('words') # => "words"
31
+ # pluralize('CamelOctopus') # => "CamelOctopi"
32
+ # pluralize('ley', :es) # => "leyes"
33
+ def pluralize(word, locale = :en)
34
+ apply_inflections(word, inflections(locale).plurals, locale)
35
+ end
36
+
37
+ # The reverse of #pluralize, returns the singular form of a word in a
38
+ # string.
39
+ #
40
+ # If passed an optional +locale+ parameter, the word will be
41
+ # singularized using rules defined for that language. By default,
42
+ # this parameter is set to <tt>:en</tt>.
43
+ #
44
+ # singularize('posts') # => "post"
45
+ # singularize('octopi') # => "octopus"
46
+ # singularize('sheep') # => "sheep"
47
+ # singularize('word') # => "word"
48
+ # singularize('CamelOctopi') # => "CamelOctopus"
49
+ # singularize('leyes', :es) # => "ley"
50
+ def singularize(word, locale = :en)
51
+ apply_inflections(word, inflections(locale).singulars, locale)
52
+ end
53
+
54
+ # Converts strings to UpperCamelCase.
55
+ # If the +uppercase_first_letter+ parameter is set to false, then produces
56
+ # lowerCamelCase.
57
+ #
58
+ # Also converts '/' to '::' which is useful for converting
59
+ # paths to namespaces.
60
+ #
61
+ # camelize('active_model') # => "ActiveModel"
62
+ # camelize('active_model', false) # => "activeModel"
63
+ # camelize('active_model/errors') # => "ActiveModel::Errors"
64
+ # camelize('active_model/errors', false) # => "activeModel::Errors"
65
+ #
66
+ # As a rule of thumb you can think of +camelize+ as the inverse of
67
+ # #underscore, though there are cases where that does not hold:
68
+ #
69
+ # camelize(underscore('SSLError')) # => "SslError"
70
+ def camelize(term, uppercase_first_letter = true)
71
+ string = term.to_s
72
+ # String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent.
73
+ if !uppercase_first_letter || uppercase_first_letter == :lower
74
+ string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase! || match }
75
+ elsif string.match?(/\A[a-z\d]*\z/)
76
+ return inflections.acronyms[string]&.dup || string.capitalize
77
+ else
78
+ string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize! || match }
79
+ end
80
+ string.gsub!(/(?:_|(\/))([a-z\d]*)/i) do
81
+ word = $2
82
+ substituted = inflections.acronyms[word] || word.capitalize! || word
83
+ $1 ? "::#{substituted}" : substituted
84
+ end
85
+ string
86
+ end
87
+
88
+ # Makes an underscored, lowercase form from the expression in the string.
89
+ #
90
+ # Changes '::' to '/' to convert namespaces to paths.
91
+ #
92
+ # underscore('ActiveModel') # => "active_model"
93
+ # underscore('ActiveModel::Errors') # => "active_model/errors"
94
+ #
95
+ # As a rule of thumb you can think of +underscore+ as the inverse of
96
+ # #camelize, though there are cases where that does not hold:
97
+ #
98
+ # camelize(underscore('SSLError')) # => "SslError"
99
+ def underscore(camel_cased_word)
100
+ return camel_cased_word.to_s.dup unless /[A-Z-]|::/.match?(camel_cased_word)
101
+ word = camel_cased_word.to_s.gsub("::", "/")
102
+ word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
103
+ word.gsub!(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_")
104
+ word.tr!("-", "_")
105
+ word.downcase!
106
+ word
107
+ end
108
+
109
+ # Tweaks an attribute name for display to end users.
110
+ #
111
+ # Specifically, performs these transformations:
112
+ #
113
+ # * Applies human inflection rules to the argument.
114
+ # * Deletes leading underscores, if any.
115
+ # * Removes an "_id" suffix if present.
116
+ # * Replaces underscores with spaces, if any.
117
+ # * Downcases all words except acronyms.
118
+ # * Capitalizes the first word.
119
+ # The capitalization of the first word can be turned off by setting the
120
+ # +:capitalize+ option to false (default is true).
121
+ #
122
+ # The trailing '_id' can be kept and capitalized by setting the
123
+ # optional parameter +keep_id_suffix+ to true (default is false).
124
+ #
125
+ # humanize('employee_salary') # => "Employee salary"
126
+ # humanize('author_id') # => "Author"
127
+ # humanize('author_id', capitalize: false) # => "author"
128
+ # humanize('_id') # => "Id"
129
+ # humanize('author_id', keep_id_suffix: true) # => "Author id"
130
+ #
131
+ # If "SSL" was defined to be an acronym:
132
+ #
133
+ # humanize('ssl_error') # => "SSL error"
134
+ #
135
+ def humanize(lower_case_and_underscored_word, capitalize: true, keep_id_suffix: false)
136
+ result = lower_case_and_underscored_word.to_s.dup
137
+
138
+ inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
139
+
140
+ result.tr!("_", " ")
141
+ result.lstrip!
142
+ if !keep_id_suffix && lower_case_and_underscored_word&.end_with?("_id")
143
+ result.delete_suffix!(" id")
144
+ end
145
+
146
+ result.gsub!(/([a-z\d]+)/i) do |match|
147
+ match.downcase!
148
+ inflections.acronyms[match] || match
149
+ end
150
+
151
+ if capitalize
152
+ result.sub!(/\A\w/) do |match|
153
+ match.upcase!
154
+ match
155
+ end
156
+ end
157
+
158
+ result
159
+ end
160
+
161
+ # Converts the first character in the string to uppercase.
162
+ #
163
+ # upcase_first('what a Lovely Day') # => "What a Lovely Day"
164
+ # upcase_first('w') # => "W"
165
+ # upcase_first('') # => ""
166
+ def upcase_first(string)
167
+ string.length > 0 ? string[0].upcase.concat(string[1..-1]) : +""
168
+ end
169
+
170
+ # Converts the first character in the string to lowercase.
171
+ #
172
+ # downcase_first('If they enjoyed The Matrix') # => "if they enjoyed The Matrix"
173
+ # downcase_first('I') # => "i"
174
+ # downcase_first('') # => ""
175
+ def downcase_first(string)
176
+ string.length > 0 ? string[0].downcase.concat(string[1..-1]) : +""
177
+ end
178
+
179
+ # Capitalizes all the words and replaces some characters in the string to
180
+ # create a nicer looking title. +titleize+ is meant for creating pretty
181
+ # output. It is not used in the \Rails internals.
182
+ #
183
+ # The trailing '_id','Id'.. can be kept and capitalized by setting the
184
+ # optional parameter +keep_id_suffix+ to true.
185
+ # By default, this parameter is false.
186
+ #
187
+ # titleize('man from the boondocks') # => "Man From The Boondocks"
188
+ # titleize('x-men: the last stand') # => "X Men: The Last Stand"
189
+ # titleize('TheManWithoutAPast') # => "The Man Without A Past"
190
+ # titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
191
+ # titleize('string_ending_with_id', keep_id_suffix: true) # => "String Ending With Id"
192
+ def titleize(word, keep_id_suffix: false)
193
+ humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`()])[a-z]/) do |match|
194
+ match.capitalize
195
+ end
196
+ end
197
+
198
+ # Creates the name of a table like \Rails does for models to table names.
199
+ # This method uses the #pluralize method on the last word in the string.
200
+ #
201
+ # tableize('RawScaledScorer') # => "raw_scaled_scorers"
202
+ # tableize('ham_and_egg') # => "ham_and_eggs"
203
+ # tableize('fancyCategory') # => "fancy_categories"
204
+ def tableize(class_name)
205
+ pluralize(underscore(class_name))
206
+ end
207
+
208
+ # Creates a class name from a plural table name like \Rails does for table
209
+ # names to models. Note that this returns a string and not a Class. (To
210
+ # convert to an actual class follow +classify+ with #constantize.)
211
+ #
212
+ # classify('ham_and_eggs') # => "HamAndEgg"
213
+ # classify('posts') # => "Post"
214
+ #
215
+ # Singular names are not handled correctly:
216
+ #
217
+ # classify('calculus') # => "Calculu"
218
+ def classify(table_name)
219
+ # strip out any leading schema name
220
+ camelize(singularize(table_name.to_s.sub(/.*\./, "")))
221
+ end
222
+
223
+ # Replaces underscores with dashes in the string.
224
+ #
225
+ # dasherize('puni_puni') # => "puni-puni"
226
+ def dasherize(underscored_word)
227
+ underscored_word.tr("_", "-")
228
+ end
229
+
230
+ # Removes the module part from the expression in the string.
231
+ #
232
+ # demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
233
+ # demodulize('Inflections') # => "Inflections"
234
+ # demodulize('::Inflections') # => "Inflections"
235
+ # demodulize('') # => ""
236
+ #
237
+ # See also #deconstantize.
238
+ def demodulize(path)
239
+ path = path.to_s
240
+ if i = path.rindex("::")
241
+ path[(i + 2), path.length]
242
+ else
243
+ path
244
+ end
245
+ end
246
+
247
+ # Removes the rightmost segment from the constant expression in the string.
248
+ #
249
+ # deconstantize('Net::HTTP') # => "Net"
250
+ # deconstantize('::Net::HTTP') # => "::Net"
251
+ # deconstantize('String') # => ""
252
+ # deconstantize('::String') # => ""
253
+ # deconstantize('') # => ""
254
+ #
255
+ # See also #demodulize.
256
+ def deconstantize(path)
257
+ path.to_s[0, path.rindex("::") || 0] # implementation based on the one in facets' Module#spacename
258
+ end
259
+
260
+ # Creates a foreign key name from a class name.
261
+ # +separate_class_name_and_id_with_underscore+ sets whether
262
+ # the method should put '_' between the name and 'id'.
263
+ #
264
+ # foreign_key('Message') # => "message_id"
265
+ # foreign_key('Message', false) # => "messageid"
266
+ # foreign_key('Admin::Post') # => "post_id"
267
+ def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
268
+ underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
269
+ end
270
+
271
+ # Tries to find a constant with the name specified in the argument string.
272
+ #
273
+ # constantize('Module') # => Module
274
+ # constantize('Foo::Bar') # => Foo::Bar
275
+ #
276
+ # The name is assumed to be the one of a top-level constant, no matter
277
+ # whether it starts with "::" or not. No lexical context is taken into
278
+ # account:
279
+ #
280
+ # C = 'outside'
281
+ # module M
282
+ # C = 'inside'
283
+ # C # => 'inside'
284
+ # constantize('C') # => 'outside', same as ::C
285
+ # end
286
+ #
287
+ # NameError is raised when the name is not in CamelCase or the constant is
288
+ # unknown.
289
+ def constantize(camel_cased_word)
290
+ Object.const_get(camel_cased_word)
291
+ end
292
+
293
+ # Tries to find a constant with the name specified in the argument string.
294
+ #
295
+ # safe_constantize('Module') # => Module
296
+ # safe_constantize('Foo::Bar') # => Foo::Bar
297
+ #
298
+ # The name is assumed to be the one of a top-level constant, no matter
299
+ # whether it starts with "::" or not. No lexical context is taken into
300
+ # account:
301
+ #
302
+ # C = 'outside'
303
+ # module M
304
+ # C = 'inside'
305
+ # C # => 'inside'
306
+ # safe_constantize('C') # => 'outside', same as ::C
307
+ # end
308
+ #
309
+ # +nil+ is returned when the name is not in CamelCase or the constant (or
310
+ # part of it) is unknown.
311
+ #
312
+ # safe_constantize('blargle') # => nil
313
+ # safe_constantize('UnknownModule') # => nil
314
+ # safe_constantize('UnknownModule::Foo::Bar') # => nil
315
+ def safe_constantize(camel_cased_word)
316
+ constantize(camel_cased_word)
317
+ rescue NameError => e
318
+ raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
319
+ e.name.to_s == camel_cased_word.to_s)
320
+ rescue LoadError => e
321
+ message = e.respond_to?(:original_message) ? e.original_message : e.message
322
+ raise unless /Unable to autoload constant #{const_regexp(camel_cased_word)}/.match?(message)
323
+ end
324
+
325
+ # Returns the suffix that should be added to a number to denote the position
326
+ # in an ordered sequence such as 1st, 2nd, 3rd, 4th.
327
+ #
328
+ # ordinal(1) # => "st"
329
+ # ordinal(2) # => "nd"
330
+ # ordinal(1002) # => "nd"
331
+ # ordinal(1003) # => "rd"
332
+ # ordinal(-11) # => "th"
333
+ # ordinal(-1021) # => "st"
334
+ def ordinal(number)
335
+ I18n.translate("number.nth.ordinals", number: number)
336
+ end
337
+
338
+ # Turns a number into an ordinal string used to denote the position in an
339
+ # ordered sequence such as 1st, 2nd, 3rd, 4th.
340
+ #
341
+ # ordinalize(1) # => "1st"
342
+ # ordinalize(2) # => "2nd"
343
+ # ordinalize(1002) # => "1002nd"
344
+ # ordinalize(1003) # => "1003rd"
345
+ # ordinalize(-11) # => "-11th"
346
+ # ordinalize(-1021) # => "-1021st"
347
+ def ordinalize(number)
348
+ I18n.translate("number.nth.ordinalized", number: number)
349
+ end
350
+
351
+ private
352
+ # Mounts a regular expression, returned as a string to ease interpolation,
353
+ # that will match part by part the given constant.
354
+ #
355
+ # const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
356
+ # const_regexp("::") # => "::"
357
+ def const_regexp(camel_cased_word)
358
+ parts = camel_cased_word.split("::")
359
+
360
+ return Regexp.escape(camel_cased_word) if parts.empty?
361
+
362
+ last = parts.pop
363
+
364
+ parts.reverse!.inject(last) do |acc, part|
365
+ part.empty? ? acc : "#{part}(::#{acc})?"
366
+ end
367
+ end
368
+
369
+ # Applies inflection rules for +singularize+ and +pluralize+.
370
+ #
371
+ # If passed an optional +locale+ parameter, the uncountables will be
372
+ # found for that locale.
373
+ #
374
+ # apply_inflections('post', inflections.plurals, :en) # => "posts"
375
+ # apply_inflections('posts', inflections.singulars, :en) # => "post"
376
+ def apply_inflections(word, rules, locale = :en)
377
+ result = word.to_s.dup
378
+
379
+ if word.empty? || inflections(locale).uncountables.uncountable?(result)
380
+ result
381
+ else
382
+ rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
383
+ result
384
+ end
385
+ end
386
+ end
387
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/multibyte"
4
+ require "active_support/i18n"
5
+
6
+ module ActiveSupport
7
+ module Inflector
8
+ ALLOWED_ENCODINGS_FOR_TRANSLITERATE = [Encoding::UTF_8, Encoding::US_ASCII, Encoding::GB18030].freeze
9
+
10
+ # Replaces non-ASCII characters with an ASCII approximation, or if none
11
+ # exists, a replacement character which defaults to "?".
12
+ #
13
+ # transliterate('Ærøskøbing')
14
+ # # => "AEroskobing"
15
+ #
16
+ # Default approximations are provided for Western/Latin characters,
17
+ # e.g, "ø", "ñ", "é", "ß", etc.
18
+ #
19
+ # This method is I18n aware, so you can set up custom approximations for a
20
+ # locale. This can be useful, for example, to transliterate German's "ü"
21
+ # and "ö" to "ue" and "oe", or to add support for transliterating Russian
22
+ # to ASCII.
23
+ #
24
+ # In order to make your custom transliterations available, you must set
25
+ # them as the <tt>i18n.transliterate.rule</tt> i18n key:
26
+ #
27
+ # # Store the transliterations in locales/de.yml
28
+ # i18n:
29
+ # transliterate:
30
+ # rule:
31
+ # ü: "ue"
32
+ # ö: "oe"
33
+ #
34
+ # # Or set them using Ruby
35
+ # I18n.backend.store_translations(:de, i18n: {
36
+ # transliterate: {
37
+ # rule: {
38
+ # 'ü' => 'ue',
39
+ # 'ö' => 'oe'
40
+ # }
41
+ # }
42
+ # })
43
+ #
44
+ # The value for <tt>i18n.transliterate.rule</tt> can be a simple Hash that
45
+ # maps characters to ASCII approximations as shown above, or, for more
46
+ # complex requirements, a Proc:
47
+ #
48
+ # I18n.backend.store_translations(:de, i18n: {
49
+ # transliterate: {
50
+ # rule: ->(string) { MyTransliterator.transliterate(string) }
51
+ # }
52
+ # })
53
+ #
54
+ # Now you can have different transliterations for each locale:
55
+ #
56
+ # transliterate('Jürgen', locale: :en)
57
+ # # => "Jurgen"
58
+ #
59
+ # transliterate('Jürgen', locale: :de)
60
+ # # => "Juergen"
61
+ #
62
+ # Transliteration is restricted to UTF-8, US-ASCII, and GB18030 strings.
63
+ # Other encodings will raise an ArgumentError.
64
+ def transliterate(string, replacement = "?", locale: nil)
65
+ raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
66
+ raise ArgumentError, "Cannot transliterate strings with #{string.encoding} encoding" unless ALLOWED_ENCODINGS_FOR_TRANSLITERATE.include?(string.encoding)
67
+
68
+ return string.dup if string.ascii_only?
69
+ string = string.dup if string.frozen?
70
+
71
+ input_encoding = string.encoding
72
+
73
+ # US-ASCII is a subset of UTF-8 so we'll force encoding as UTF-8 if
74
+ # US-ASCII is given. This way we can let tidy_bytes handle the string
75
+ # in the same way as we do for UTF-8
76
+ string.force_encoding(Encoding::UTF_8) if string.encoding == Encoding::US_ASCII
77
+
78
+ # GB18030 is Unicode compatible but is not a direct mapping so needs to be
79
+ # transcoded. Using invalid/undef :replace will result in loss of data in
80
+ # the event of invalid characters, but since tidy_bytes will replace
81
+ # invalid/undef with a "?" we're safe to do the same beforehand
82
+ string.encode!(Encoding::UTF_8, invalid: :replace, undef: :replace) if string.encoding == Encoding::GB18030
83
+
84
+ transliterated = I18n.transliterate(
85
+ ActiveSupport::Multibyte::Unicode.tidy_bytes(string).unicode_normalize(:nfc),
86
+ replacement: replacement,
87
+ locale: locale
88
+ )
89
+
90
+ # Restore the string encoding of the input if it was not UTF-8.
91
+ # Apply invalid/undef :replace as tidy_bytes does
92
+ transliterated.encode!(input_encoding, invalid: :replace, undef: :replace) if input_encoding != transliterated.encoding
93
+
94
+ transliterated
95
+ end
96
+
97
+ # Replaces special characters in a string so that it may be used as part of
98
+ # a 'pretty' URL.
99
+ #
100
+ # parameterize("Donald E. Knuth") # => "donald-e-knuth"
101
+ # parameterize("^très|Jolie-- ") # => "tres-jolie"
102
+ #
103
+ # To use a custom separator, override the +separator+ argument.
104
+ #
105
+ # parameterize("Donald E. Knuth", separator: '_') # => "donald_e_knuth"
106
+ # parameterize("^très|Jolie__ ", separator: '_') # => "tres_jolie"
107
+ #
108
+ # To preserve the case of the characters in a string, use the +preserve_case+ argument.
109
+ #
110
+ # parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth"
111
+ # parameterize("^très|Jolie-- ", preserve_case: true) # => "tres-Jolie"
112
+ #
113
+ # It preserves dashes and underscores unless they are used as separators:
114
+ #
115
+ # parameterize("^très|Jolie__ ") # => "tres-jolie__"
116
+ # parameterize("^très|Jolie-- ", separator: "_") # => "tres_jolie--"
117
+ # parameterize("^très_Jolie-- ", separator: ".") # => "tres_jolie--"
118
+ #
119
+ # If the optional parameter +locale+ is specified,
120
+ # the word will be parameterized as a word of that language.
121
+ # By default, this parameter is set to <tt>nil</tt> and it will use
122
+ # the configured <tt>I18n.locale</tt>.
123
+ def parameterize(string, separator: "-", preserve_case: false, locale: nil)
124
+ # Replace accented chars with their ASCII equivalents.
125
+ parameterized_string = transliterate(string, locale: locale)
126
+
127
+ # Turn unwanted chars into the separator.
128
+ parameterized_string.gsub!(/[^a-z0-9\-_]+/i, separator)
129
+
130
+ unless separator.nil? || separator.empty?
131
+ if separator == "-"
132
+ re_duplicate_separator = /-{2,}/
133
+ re_leading_trailing_separator = /^-|-$/i
134
+ else
135
+ re_sep = Regexp.escape(separator)
136
+ re_duplicate_separator = /#{re_sep}{2,}/
137
+ re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/i
138
+ end
139
+ # No more than one of the separator in a row.
140
+ parameterized_string.gsub!(re_duplicate_separator, separator)
141
+ # Remove leading/trailing separator.
142
+ parameterized_string.gsub!(re_leading_trailing_separator, "")
143
+ end
144
+
145
+ parameterized_string.downcase! unless preserve_case
146
+ parameterized_string
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # in case active_support/inflector is required without the rest of active_support
4
+ require "active_support/inflector/inflections"
5
+ require "active_support/inflector/transliterate"
6
+ require "active_support/inflector/methods"
7
+
8
+ require "active_support/inflections"
9
+ require "active_support/core_ext/string/inflections"
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module ActiveSupport
5
+ module IsolatedExecutionState # :nodoc:
6
+ @isolation_level = nil
7
+
8
+ Thread.attr_accessor :active_support_execution_state
9
+ Fiber.attr_accessor :active_support_execution_state
10
+
11
+ class << self
12
+ attr_reader :isolation_level, :scope
13
+
14
+ def isolation_level=(level)
15
+ return if level == @isolation_level
16
+
17
+ unless %i(thread fiber).include?(level)
18
+ raise ArgumentError, "isolation_level must be `:thread` or `:fiber`, got: `#{level.inspect}`"
19
+ end
20
+
21
+ clear if @isolation_level
22
+
23
+ @scope =
24
+ case level
25
+ when :thread; Thread
26
+ when :fiber; Fiber
27
+ end
28
+
29
+ @isolation_level = level
30
+ end
31
+
32
+ def unique_id
33
+ self[:__id__] ||= Object.new
34
+ end
35
+
36
+ def [](key)
37
+ state[key]
38
+ end
39
+
40
+ def []=(key, value)
41
+ state[key] = value
42
+ end
43
+
44
+ def key?(key)
45
+ state.key?(key)
46
+ end
47
+
48
+ def delete(key)
49
+ state.delete(key)
50
+ end
51
+
52
+ def clear
53
+ state.clear
54
+ end
55
+
56
+ def context
57
+ scope.current
58
+ end
59
+
60
+ def share_with(other)
61
+ # Action Controller streaming spawns a new thread and copy thread locals.
62
+ # We do the same here for backward compatibility, but this is very much a hack
63
+ # and streaming should be rethought.
64
+ context.active_support_execution_state = other.active_support_execution_state.dup
65
+ end
66
+
67
+ private
68
+ def state
69
+ context.active_support_execution_state ||= {}
70
+ end
71
+ end
72
+
73
+ self.isolation_level = :thread
74
+ end
75
+ end