activesupport 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +572 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support.rb +96 -0
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/all.rb +5 -0
  8. data/lib/active_support/array_inquirer.rb +48 -0
  9. data/lib/active_support/backtrace_cleaner.rb +132 -0
  10. data/lib/active_support/benchmarkable.rb +51 -0
  11. data/lib/active_support/builder.rb +8 -0
  12. data/lib/active_support/cache.rb +830 -0
  13. data/lib/active_support/cache/file_store.rb +196 -0
  14. data/lib/active_support/cache/mem_cache_store.rb +212 -0
  15. data/lib/active_support/cache/memory_store.rb +174 -0
  16. data/lib/active_support/cache/null_store.rb +48 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +488 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +194 -0
  19. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  20. data/lib/active_support/callbacks.rb +856 -0
  21. data/lib/active_support/concern.rb +171 -0
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  23. data/lib/active_support/concurrency/share_lock.rb +227 -0
  24. data/lib/active_support/configurable.rb +146 -0
  25. data/lib/active_support/core_ext.rb +5 -0
  26. data/lib/active_support/core_ext/array.rb +9 -0
  27. data/lib/active_support/core_ext/array/access.rb +104 -0
  28. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
  34. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  35. data/lib/active_support/core_ext/benchmark.rb +16 -0
  36. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  37. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  38. data/lib/active_support/core_ext/class.rb +4 -0
  39. data/lib/active_support/core_ext/class/attribute.rb +141 -0
  40. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  41. data/lib/active_support/core_ext/class/subclasses.rb +54 -0
  42. data/lib/active_support/core_ext/date.rb +7 -0
  43. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  44. data/lib/active_support/core_ext/date/blank.rb +14 -0
  45. data/lib/active_support/core_ext/date/calculations.rb +146 -0
  46. data/lib/active_support/core_ext/date/conversions.rb +96 -0
  47. data/lib/active_support/core_ext/date/zones.rb +8 -0
  48. data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
  49. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  50. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  51. data/lib/active_support/core_ext/date_time.rb +7 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
  57. data/lib/active_support/core_ext/digest.rb +3 -0
  58. data/lib/active_support/core_ext/digest/uuid.rb +53 -0
  59. data/lib/active_support/core_ext/enumerable.rb +188 -0
  60. data/lib/active_support/core_ext/file.rb +3 -0
  61. data/lib/active_support/core_ext/file/atomic.rb +70 -0
  62. data/lib/active_support/core_ext/hash.rb +10 -0
  63. data/lib/active_support/core_ext/hash/compact.rb +5 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +263 -0
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +24 -0
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  69. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  71. data/lib/active_support/core_ext/hash/slice.rb +26 -0
  72. data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
  73. data/lib/active_support/core_ext/integer.rb +5 -0
  74. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  75. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  76. data/lib/active_support/core_ext/integer/time.rb +22 -0
  77. data/lib/active_support/core_ext/kernel.rb +5 -0
  78. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  79. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  80. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  81. data/lib/active_support/core_ext/load_error.rb +9 -0
  82. data/lib/active_support/core_ext/marshal.rb +24 -0
  83. data/lib/active_support/core_ext/module.rb +13 -0
  84. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  85. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  86. data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
  87. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  88. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  89. data/lib/active_support/core_ext/module/concerning.rb +134 -0
  90. data/lib/active_support/core_ext/module/delegation.rb +313 -0
  91. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  92. data/lib/active_support/core_ext/module/introspection.rb +86 -0
  93. data/lib/active_support/core_ext/module/reachable.rb +6 -0
  94. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  95. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  96. data/lib/active_support/core_ext/name_error.rb +38 -0
  97. data/lib/active_support/core_ext/numeric.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
  99. data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
  100. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  101. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  102. data/lib/active_support/core_ext/object.rb +16 -0
  103. data/lib/active_support/core_ext/object/acts_like.rb +21 -0
  104. data/lib/active_support/core_ext/object/blank.rb +155 -0
  105. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  106. data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
  107. data/lib/active_support/core_ext/object/duplicable.rb +49 -0
  108. data/lib/active_support/core_ext/object/inclusion.rb +29 -0
  109. data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
  110. data/lib/active_support/core_ext/object/json.rb +228 -0
  111. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  112. data/lib/active_support/core_ext/object/to_query.rb +89 -0
  113. data/lib/active_support/core_ext/object/try.rb +156 -0
  114. data/lib/active_support/core_ext/object/with_options.rb +82 -0
  115. data/lib/active_support/core_ext/range.rb +7 -0
  116. data/lib/active_support/core_ext/range/compare_range.rb +70 -0
  117. data/lib/active_support/core_ext/range/conversions.rb +41 -0
  118. data/lib/active_support/core_ext/range/each.rb +25 -0
  119. data/lib/active_support/core_ext/range/include_range.rb +9 -0
  120. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  121. data/lib/active_support/core_ext/range/overlaps.rb +10 -0
  122. data/lib/active_support/core_ext/regexp.rb +7 -0
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string.rb +15 -0
  125. data/lib/active_support/core_ext/string/access.rb +114 -0
  126. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  127. data/lib/active_support/core_ext/string/conversions.rb +59 -0
  128. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  129. data/lib/active_support/core_ext/string/filters.rb +145 -0
  130. data/lib/active_support/core_ext/string/indent.rb +45 -0
  131. data/lib/active_support/core_ext/string/inflections.rb +259 -0
  132. data/lib/active_support/core_ext/string/inquiry.rb +15 -0
  133. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  134. data/lib/active_support/core_ext/string/output_safety.rb +314 -0
  135. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  136. data/lib/active_support/core_ext/string/strip.rb +27 -0
  137. data/lib/active_support/core_ext/string/zones.rb +16 -0
  138. data/lib/active_support/core_ext/time.rb +7 -0
  139. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  140. data/lib/active_support/core_ext/time/calculations.rb +344 -0
  141. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  142. data/lib/active_support/core_ext/time/conversions.rb +72 -0
  143. data/lib/active_support/core_ext/time/zones.rb +113 -0
  144. data/lib/active_support/core_ext/uri.rb +25 -0
  145. data/lib/active_support/current_attributes.rb +203 -0
  146. data/lib/active_support/dependencies.rb +806 -0
  147. data/lib/active_support/dependencies/autoload.rb +79 -0
  148. data/lib/active_support/dependencies/interlock.rb +57 -0
  149. data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
  150. data/lib/active_support/deprecation.rb +46 -0
  151. data/lib/active_support/deprecation/behaviors.rb +109 -0
  152. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  153. data/lib/active_support/deprecation/instance_delegator.rb +39 -0
  154. data/lib/active_support/deprecation/method_wrappers.rb +78 -0
  155. data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
  156. data/lib/active_support/deprecation/reporting.rb +114 -0
  157. data/lib/active_support/descendants_tracker.rb +109 -0
  158. data/lib/active_support/digest.rb +20 -0
  159. data/lib/active_support/duration.rb +433 -0
  160. data/lib/active_support/duration/iso8601_parser.rb +124 -0
  161. data/lib/active_support/duration/iso8601_serializer.rb +54 -0
  162. data/lib/active_support/encrypted_configuration.rb +45 -0
  163. data/lib/active_support/encrypted_file.rb +100 -0
  164. data/lib/active_support/evented_file_update_checker.rb +235 -0
  165. data/lib/active_support/execution_wrapper.rb +129 -0
  166. data/lib/active_support/executor.rb +8 -0
  167. data/lib/active_support/file_update_checker.rb +163 -0
  168. data/lib/active_support/gem_version.rb +17 -0
  169. data/lib/active_support/gzip.rb +38 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +399 -0
  171. data/lib/active_support/i18n.rb +16 -0
  172. data/lib/active_support/i18n_railtie.rb +126 -0
  173. data/lib/active_support/inflections.rb +72 -0
  174. data/lib/active_support/inflector.rb +9 -0
  175. data/lib/active_support/inflector/inflections.rb +257 -0
  176. data/lib/active_support/inflector/methods.rb +398 -0
  177. data/lib/active_support/inflector/transliterate.rb +147 -0
  178. data/lib/active_support/json.rb +4 -0
  179. data/lib/active_support/json/decoding.rb +76 -0
  180. data/lib/active_support/json/encoding.rb +134 -0
  181. data/lib/active_support/key_generator.rb +41 -0
  182. data/lib/active_support/lazy_load_hooks.rb +82 -0
  183. data/lib/active_support/locale/en.rb +31 -0
  184. data/lib/active_support/locale/en.yml +135 -0
  185. data/lib/active_support/log_subscriber.rb +135 -0
  186. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  187. data/lib/active_support/logger.rb +93 -0
  188. data/lib/active_support/logger_silence.rb +45 -0
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -0
  190. data/lib/active_support/message_encryptor.rb +227 -0
  191. data/lib/active_support/message_verifier.rb +205 -0
  192. data/lib/active_support/messages/metadata.rb +71 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  194. data/lib/active_support/messages/rotator.rb +56 -0
  195. data/lib/active_support/multibyte.rb +23 -0
  196. data/lib/active_support/multibyte/chars.rb +216 -0
  197. data/lib/active_support/multibyte/unicode.rb +157 -0
  198. data/lib/active_support/notifications.rb +253 -0
  199. data/lib/active_support/notifications/fanout.rb +244 -0
  200. data/lib/active_support/notifications/instrumenter.rb +164 -0
  201. data/lib/active_support/number_helper.rb +378 -0
  202. data/lib/active_support/number_helper/number_converter.rb +184 -0
  203. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  204. data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
  205. data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
  206. data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
  207. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  208. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  209. data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
  210. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  211. data/lib/active_support/option_merger.rb +27 -0
  212. data/lib/active_support/ordered_hash.rb +50 -0
  213. data/lib/active_support/ordered_options.rb +85 -0
  214. data/lib/active_support/parameter_filter.rb +129 -0
  215. data/lib/active_support/per_thread_registry.rb +60 -0
  216. data/lib/active_support/proxy_object.rb +15 -0
  217. data/lib/active_support/rails.rb +29 -0
  218. data/lib/active_support/railtie.rb +80 -0
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +174 -0
  221. data/lib/active_support/security_utils.rb +31 -0
  222. data/lib/active_support/string_inquirer.rb +34 -0
  223. data/lib/active_support/subscriber.rb +169 -0
  224. data/lib/active_support/tagged_logging.rb +88 -0
  225. data/lib/active_support/test_case.rb +163 -0
  226. data/lib/active_support/testing/assertions.rb +228 -0
  227. data/lib/active_support/testing/autorun.rb +7 -0
  228. data/lib/active_support/testing/constant_lookup.rb +51 -0
  229. data/lib/active_support/testing/declarative.rb +28 -0
  230. data/lib/active_support/testing/deprecation.rb +38 -0
  231. data/lib/active_support/testing/file_fixtures.rb +38 -0
  232. data/lib/active_support/testing/isolation.rb +110 -0
  233. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  234. data/lib/active_support/testing/parallelization.rb +128 -0
  235. data/lib/active_support/testing/setup_and_teardown.rb +55 -0
  236. data/lib/active_support/testing/stream.rb +44 -0
  237. data/lib/active_support/testing/tagged_logging.rb +27 -0
  238. data/lib/active_support/testing/time_helpers.rb +200 -0
  239. data/lib/active_support/time.rb +20 -0
  240. data/lib/active_support/time_with_zone.rb +561 -0
  241. data/lib/active_support/values/time_zone.rb +570 -0
  242. data/lib/active_support/version.rb +10 -0
  243. data/lib/active_support/xml_mini.rb +202 -0
  244. data/lib/active_support/xml_mini/jdom.rb +183 -0
  245. data/lib/active_support/xml_mini/libxml.rb +80 -0
  246. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  247. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  248. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  249. data/lib/active_support/xml_mini/rexml.rb +130 -0
  250. metadata +385 -0
@@ -0,0 +1,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 fallback 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
@@ -0,0 +1,259 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/inflector/methods"
4
+ require "active_support/inflector/transliterate"
5
+
6
+ # String inflections define new methods on the String class to transform names for different purposes.
7
+ # For instance, you can figure out the name of a table from the name of a class.
8
+ #
9
+ # 'ScaleScore'.tableize # => "scale_scores"
10
+ #
11
+ class String
12
+ # Returns the plural form of the word in the string.
13
+ #
14
+ # If the optional parameter +count+ is specified,
15
+ # the singular form will be returned if <tt>count == 1</tt>.
16
+ # For any other value of +count+ the plural will be returned.
17
+ #
18
+ # If the optional parameter +locale+ is specified,
19
+ # the word will be pluralized as a word of that language.
20
+ # By default, this parameter is set to <tt>:en</tt>.
21
+ # You must define your own inflection rules for languages other than English.
22
+ #
23
+ # 'post'.pluralize # => "posts"
24
+ # 'octopus'.pluralize # => "octopi"
25
+ # 'sheep'.pluralize # => "sheep"
26
+ # 'words'.pluralize # => "words"
27
+ # 'the blue mailman'.pluralize # => "the blue mailmen"
28
+ # 'CamelOctopus'.pluralize # => "CamelOctopi"
29
+ # 'apple'.pluralize(1) # => "apple"
30
+ # 'apple'.pluralize(2) # => "apples"
31
+ # 'ley'.pluralize(:es) # => "leyes"
32
+ # 'ley'.pluralize(1, :es) # => "ley"
33
+ def pluralize(count = nil, locale = :en)
34
+ locale = count if count.is_a?(Symbol)
35
+ if count == 1
36
+ dup
37
+ else
38
+ ActiveSupport::Inflector.pluralize(self, locale)
39
+ end
40
+ end
41
+
42
+ # The reverse of +pluralize+, returns the singular form of a word in a string.
43
+ #
44
+ # If the optional parameter +locale+ is specified,
45
+ # the word will be singularized as a word of that language.
46
+ # By default, this parameter is set to <tt>:en</tt>.
47
+ # You must define your own inflection rules for languages other than English.
48
+ #
49
+ # 'posts'.singularize # => "post"
50
+ # 'octopi'.singularize # => "octopus"
51
+ # 'sheep'.singularize # => "sheep"
52
+ # 'word'.singularize # => "word"
53
+ # 'the blue mailmen'.singularize # => "the blue mailman"
54
+ # 'CamelOctopi'.singularize # => "CamelOctopus"
55
+ # 'leyes'.singularize(:es) # => "ley"
56
+ def singularize(locale = :en)
57
+ ActiveSupport::Inflector.singularize(self, locale)
58
+ end
59
+
60
+ # +constantize+ tries to find a declared constant with the name specified
61
+ # in the string. It raises a NameError when the name is not in CamelCase
62
+ # or is not initialized. See ActiveSupport::Inflector.constantize
63
+ #
64
+ # 'Module'.constantize # => Module
65
+ # 'Class'.constantize # => Class
66
+ # 'blargle'.constantize # => NameError: wrong constant name blargle
67
+ def constantize
68
+ ActiveSupport::Inflector.constantize(self)
69
+ end
70
+
71
+ # +safe_constantize+ tries to find a declared constant with the name specified
72
+ # in the string. It returns +nil+ when the name is not in CamelCase
73
+ # or is not initialized. See ActiveSupport::Inflector.safe_constantize
74
+ #
75
+ # 'Module'.safe_constantize # => Module
76
+ # 'Class'.safe_constantize # => Class
77
+ # 'blargle'.safe_constantize # => nil
78
+ def safe_constantize
79
+ ActiveSupport::Inflector.safe_constantize(self)
80
+ end
81
+
82
+ # By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
83
+ # is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
84
+ #
85
+ # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
86
+ #
87
+ # 'active_record'.camelize # => "ActiveRecord"
88
+ # 'active_record'.camelize(:lower) # => "activeRecord"
89
+ # 'active_record/errors'.camelize # => "ActiveRecord::Errors"
90
+ # 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
91
+ def camelize(first_letter = :upper)
92
+ case first_letter
93
+ when :upper
94
+ ActiveSupport::Inflector.camelize(self, true)
95
+ when :lower
96
+ ActiveSupport::Inflector.camelize(self, false)
97
+ else
98
+ raise ArgumentError, "Invalid option, use either :upper or :lower."
99
+ end
100
+ end
101
+ alias_method :camelcase, :camelize
102
+
103
+ # Capitalizes all the words and replaces some characters in the string to create
104
+ # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
105
+ # used in the Rails internals.
106
+ #
107
+ # The trailing '_id','Id'.. can be kept and capitalized by setting the
108
+ # optional parameter +keep_id_suffix+ to true.
109
+ # By default, this parameter is false.
110
+ #
111
+ # +titleize+ is also aliased as +titlecase+.
112
+ #
113
+ # 'man from the boondocks'.titleize # => "Man From The Boondocks"
114
+ # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
115
+ # 'string_ending_with_id'.titleize(keep_id_suffix: true) # => "String Ending With Id"
116
+ def titleize(keep_id_suffix: false)
117
+ ActiveSupport::Inflector.titleize(self, keep_id_suffix: keep_id_suffix)
118
+ end
119
+ alias_method :titlecase, :titleize
120
+
121
+ # The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
122
+ #
123
+ # +underscore+ will also change '::' to '/' to convert namespaces to paths.
124
+ #
125
+ # 'ActiveModel'.underscore # => "active_model"
126
+ # 'ActiveModel::Errors'.underscore # => "active_model/errors"
127
+ def underscore
128
+ ActiveSupport::Inflector.underscore(self)
129
+ end
130
+
131
+ # Replaces underscores with dashes in the string.
132
+ #
133
+ # 'puni_puni'.dasherize # => "puni-puni"
134
+ def dasherize
135
+ ActiveSupport::Inflector.dasherize(self)
136
+ end
137
+
138
+ # Removes the module part from the constant expression in the string.
139
+ #
140
+ # 'ActiveSupport::Inflector::Inflections'.demodulize # => "Inflections"
141
+ # 'Inflections'.demodulize # => "Inflections"
142
+ # '::Inflections'.demodulize # => "Inflections"
143
+ # ''.demodulize # => ''
144
+ #
145
+ # See also +deconstantize+.
146
+ def demodulize
147
+ ActiveSupport::Inflector.demodulize(self)
148
+ end
149
+
150
+ # Removes the rightmost segment from the constant expression in the string.
151
+ #
152
+ # 'Net::HTTP'.deconstantize # => "Net"
153
+ # '::Net::HTTP'.deconstantize # => "::Net"
154
+ # 'String'.deconstantize # => ""
155
+ # '::String'.deconstantize # => ""
156
+ # ''.deconstantize # => ""
157
+ #
158
+ # See also +demodulize+.
159
+ def deconstantize
160
+ ActiveSupport::Inflector.deconstantize(self)
161
+ end
162
+
163
+ # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
164
+ #
165
+ # If the optional parameter +locale+ is specified,
166
+ # the word will be parameterized as a word of that language.
167
+ # By default, this parameter is set to <tt>nil</tt> and it will use
168
+ # the configured <tt>I18n.locale</tt>.
169
+ #
170
+ # class Person
171
+ # def to_param
172
+ # "#{id}-#{name.parameterize}"
173
+ # end
174
+ # end
175
+ #
176
+ # @person = Person.find(1)
177
+ # # => #<Person id: 1, name: "Donald E. Knuth">
178
+ #
179
+ # <%= link_to(@person.name, person_path) %>
180
+ # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
181
+ #
182
+ # To preserve the case of the characters in a string, use the +preserve_case+ argument.
183
+ #
184
+ # class Person
185
+ # def to_param
186
+ # "#{id}-#{name.parameterize(preserve_case: true)}"
187
+ # end
188
+ # end
189
+ #
190
+ # @person = Person.find(1)
191
+ # # => #<Person id: 1, name: "Donald E. Knuth">
192
+ #
193
+ # <%= link_to(@person.name, person_path) %>
194
+ # # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a>
195
+ def parameterize(separator: "-", preserve_case: false, locale: nil)
196
+ ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case, locale: locale)
197
+ end
198
+
199
+ # Creates the name of a table like Rails does for models to table names. This method
200
+ # uses the +pluralize+ method on the last word in the string.
201
+ #
202
+ # 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
203
+ # 'ham_and_egg'.tableize # => "ham_and_eggs"
204
+ # 'fancyCategory'.tableize # => "fancy_categories"
205
+ def tableize
206
+ ActiveSupport::Inflector.tableize(self)
207
+ end
208
+
209
+ # Creates a class name from a plural table name like Rails does for table names to models.
210
+ # Note that this returns a string and not a class. (To convert to an actual class
211
+ # follow +classify+ with +constantize+.)
212
+ #
213
+ # 'ham_and_eggs'.classify # => "HamAndEgg"
214
+ # 'posts'.classify # => "Post"
215
+ def classify
216
+ ActiveSupport::Inflector.classify(self)
217
+ end
218
+
219
+ # Capitalizes the first word, turns underscores into spaces, and (by default)strips a
220
+ # trailing '_id' if present.
221
+ # Like +titleize+, this is meant for creating pretty output.
222
+ #
223
+ # The capitalization of the first word can be turned off by setting the
224
+ # optional parameter +capitalize+ to false.
225
+ # By default, this parameter is true.
226
+ #
227
+ # The trailing '_id' can be kept and capitalized by setting the
228
+ # optional parameter +keep_id_suffix+ to true.
229
+ # By default, this parameter is false.
230
+ #
231
+ # 'employee_salary'.humanize # => "Employee salary"
232
+ # 'author_id'.humanize # => "Author"
233
+ # 'author_id'.humanize(capitalize: false) # => "author"
234
+ # '_id'.humanize # => "Id"
235
+ # 'author_id'.humanize(keep_id_suffix: true) # => "Author Id"
236
+ def humanize(capitalize: true, keep_id_suffix: false)
237
+ ActiveSupport::Inflector.humanize(self, capitalize: capitalize, keep_id_suffix: keep_id_suffix)
238
+ end
239
+
240
+ # Converts just the first character to uppercase.
241
+ #
242
+ # 'what a Lovely Day'.upcase_first # => "What a Lovely Day"
243
+ # 'w'.upcase_first # => "W"
244
+ # ''.upcase_first # => ""
245
+ def upcase_first
246
+ ActiveSupport::Inflector.upcase_first(self)
247
+ end
248
+
249
+ # Creates a foreign key name from a class name.
250
+ # +separate_class_name_and_id_with_underscore+ sets whether
251
+ # the method should put '_' between the name and 'id'.
252
+ #
253
+ # 'Message'.foreign_key # => "message_id"
254
+ # 'Message'.foreign_key(false) # => "messageid"
255
+ # 'Admin::Post'.foreign_key # => "post_id"
256
+ def foreign_key(separate_class_name_and_id_with_underscore = true)
257
+ ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
258
+ end
259
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/string_inquirer"
4
+
5
+ class String
6
+ # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
7
+ # which gives you a prettier way to test for equality.
8
+ #
9
+ # env = 'production'.inquiry
10
+ # env.production? # => true
11
+ # env.development? # => false
12
+ def inquiry
13
+ ActiveSupport::StringInquirer.new(self)
14
+ end
15
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/multibyte"
4
+
5
+ class String
6
+ # == Multibyte proxy
7
+ #
8
+ # +mb_chars+ is a multibyte safe proxy for string methods.
9
+ #
10
+ # It creates and returns an instance of the ActiveSupport::Multibyte::Chars class which
11
+ # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
12
+ # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
13
+ #
14
+ # >> "lj".mb_chars.upcase.to_s
15
+ # => "LJ"
16
+ #
17
+ # NOTE: Ruby 2.4 and later support native Unicode case mappings:
18
+ #
19
+ # >> "lj".upcase
20
+ # => "LJ"
21
+ #
22
+ # == Method chaining
23
+ #
24
+ # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
25
+ # method chaining on the result of any of these methods.
26
+ #
27
+ # name.mb_chars.reverse.length # => 12
28
+ #
29
+ # == Interoperability and configuration
30
+ #
31
+ # The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
32
+ # String and Char work like expected. The bang! methods change the internal string representation in the Chars
33
+ # object. Interoperability problems can be resolved easily with a +to_s+ call.
34
+ #
35
+ # For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars. For
36
+ # information about how to change the default Multibyte behavior see ActiveSupport::Multibyte.
37
+ def mb_chars
38
+ ActiveSupport::Multibyte.proxy_class.new(self)
39
+ end
40
+
41
+ # Returns +true+ if string has utf_8 encoding.
42
+ #
43
+ # utf_8_str = "some string".encode "UTF-8"
44
+ # iso_str = "some string".encode "ISO-8859-1"
45
+ #
46
+ # utf_8_str.is_utf8? # => true
47
+ # iso_str.is_utf8? # => false
48
+ def is_utf8?
49
+ case encoding
50
+ when Encoding::UTF_8
51
+ valid_encoding?
52
+ when Encoding::ASCII_8BIT, Encoding::US_ASCII
53
+ dup.force_encoding(Encoding::UTF_8).valid_encoding?
54
+ else
55
+ false
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,314 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "active_support/core_ext/kernel/singleton_class"
5
+ require "active_support/core_ext/module/redefine_method"
6
+ require "active_support/multibyte/unicode"
7
+
8
+ class ERB
9
+ module Util
10
+ HTML_ESCAPE = { "&" => "&amp;", ">" => "&gt;", "<" => "&lt;", '"' => "&quot;", "'" => "&#39;" }
11
+ JSON_ESCAPE = { "&" => '\u0026', ">" => '\u003e', "<" => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
12
+ HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
13
+ JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
14
+
15
+ # A utility method for escaping HTML tag characters.
16
+ # This method is also aliased as <tt>h</tt>.
17
+ #
18
+ # puts html_escape('is a > 0 & a < 10?')
19
+ # # => is a &gt; 0 &amp; a &lt; 10?
20
+ def html_escape(s)
21
+ unwrapped_html_escape(s).html_safe
22
+ end
23
+
24
+ silence_redefinition_of_method :h
25
+ alias h html_escape
26
+
27
+ module_function :h
28
+
29
+ singleton_class.silence_redefinition_of_method :html_escape
30
+ module_function :html_escape
31
+
32
+ # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
33
+ # This method is not for public consumption! Seriously!
34
+ def unwrapped_html_escape(s) # :nodoc:
35
+ s = s.to_s
36
+ if s.html_safe?
37
+ s
38
+ else
39
+ CGI.escapeHTML(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
40
+ end
41
+ end
42
+ module_function :unwrapped_html_escape
43
+
44
+ # A utility method for escaping HTML without affecting existing escaped entities.
45
+ #
46
+ # html_escape_once('1 < 2 &amp; 3')
47
+ # # => "1 &lt; 2 &amp; 3"
48
+ #
49
+ # html_escape_once('&lt;&lt; Accept & Checkout')
50
+ # # => "&lt;&lt; Accept &amp; Checkout"
51
+ def html_escape_once(s)
52
+ result = ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
53
+ s.html_safe? ? result.html_safe : result
54
+ end
55
+
56
+ module_function :html_escape_once
57
+
58
+ # A utility method for escaping HTML entities in JSON strings. Specifically, the
59
+ # &, > and < characters are replaced with their equivalent unicode escaped form -
60
+ # \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also
61
+ # escaped as they are treated as newline characters in some JavaScript engines.
62
+ # These sequences have identical meaning as the original characters inside the
63
+ # context of a JSON string, so assuming the input is a valid and well-formed
64
+ # JSON value, the output will have equivalent meaning when parsed:
65
+ #
66
+ # json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
67
+ # # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
68
+ #
69
+ # json_escape(json)
70
+ # # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
71
+ #
72
+ # JSON.parse(json) == JSON.parse(json_escape(json))
73
+ # # => true
74
+ #
75
+ # The intended use case for this method is to escape JSON strings before including
76
+ # them inside a script tag to avoid XSS vulnerability:
77
+ #
78
+ # <script>
79
+ # var currentUser = <%= raw json_escape(current_user.to_json) %>;
80
+ # </script>
81
+ #
82
+ # It is necessary to +raw+ the result of +json_escape+, so that quotation marks
83
+ # don't get converted to <tt>&quot;</tt> entities. +json_escape+ doesn't
84
+ # automatically flag the result as HTML safe, since the raw value is unsafe to
85
+ # use inside HTML attributes.
86
+ #
87
+ # If your JSON is being used downstream for insertion into the DOM, be aware of
88
+ # whether or not it is being inserted via +html()+. Most jQuery plugins do this.
89
+ # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
90
+ # content returned by your JSON.
91
+ #
92
+ # If you need to output JSON elsewhere in your HTML, you can just do something
93
+ # like this, as any unsafe characters (including quotation marks) will be
94
+ # automatically escaped for you:
95
+ #
96
+ # <div data-user-info="<%= current_user.to_json %>">...</div>
97
+ #
98
+ # WARNING: this helper only works with valid JSON. Using this on non-JSON values
99
+ # will open up serious XSS vulnerabilities. For example, if you replace the
100
+ # +current_user.to_json+ in the example above with user input instead, the browser
101
+ # will happily eval() that string as JavaScript.
102
+ #
103
+ # The escaping performed in this method is identical to those performed in the
104
+ # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
105
+ # set to true. Because this transformation is idempotent, this helper can be
106
+ # applied even if +ActiveSupport.escape_html_entities_in_json+ is already true.
107
+ #
108
+ # Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+
109
+ # is enabled, or if you are unsure where your JSON string originated from, it
110
+ # is recommended that you always apply this helper (other libraries, such as the
111
+ # JSON gem, do not provide this kind of protection by default; also some gems
112
+ # might override +to_json+ to bypass Active Support's encoder).
113
+ def json_escape(s)
114
+ result = s.to_s.gsub(JSON_ESCAPE_REGEXP, JSON_ESCAPE)
115
+ s.html_safe? ? result.html_safe : result
116
+ end
117
+
118
+ module_function :json_escape
119
+ end
120
+ end
121
+
122
+ class Object
123
+ def html_safe?
124
+ false
125
+ end
126
+ end
127
+
128
+ class Numeric
129
+ def html_safe?
130
+ true
131
+ end
132
+ end
133
+
134
+ module ActiveSupport #:nodoc:
135
+ class SafeBuffer < String
136
+ UNSAFE_STRING_METHODS = %w(
137
+ capitalize chomp chop delete delete_prefix delete_suffix
138
+ downcase lstrip next reverse rstrip slice squeeze strip
139
+ succ swapcase tr tr_s unicode_normalize upcase
140
+ )
141
+
142
+ UNSAFE_STRING_METHODS_WITH_BACKREF = %w(gsub sub)
143
+
144
+ alias_method :original_concat, :concat
145
+ private :original_concat
146
+
147
+ # Raised when <tt>ActiveSupport::SafeBuffer#safe_concat</tt> is called on unsafe buffers.
148
+ class SafeConcatError < StandardError
149
+ def initialize
150
+ super "Could not concatenate to the buffer because it is not html safe."
151
+ end
152
+ end
153
+
154
+ def [](*args)
155
+ if html_safe?
156
+ new_safe_buffer = super
157
+
158
+ if new_safe_buffer
159
+ new_safe_buffer.instance_variable_set :@html_safe, true
160
+ end
161
+
162
+ new_safe_buffer
163
+ else
164
+ to_str[*args]
165
+ end
166
+ end
167
+
168
+ def safe_concat(value)
169
+ raise SafeConcatError unless html_safe?
170
+ original_concat(value)
171
+ end
172
+
173
+ def initialize(str = "")
174
+ @html_safe = true
175
+ super
176
+ end
177
+
178
+ def initialize_copy(other)
179
+ super
180
+ @html_safe = other.html_safe?
181
+ end
182
+
183
+ def clone_empty
184
+ self[0, 0]
185
+ end
186
+
187
+ def concat(value)
188
+ super(html_escape_interpolated_argument(value))
189
+ end
190
+ alias << concat
191
+
192
+ def insert(index, value)
193
+ super(index, html_escape_interpolated_argument(value))
194
+ end
195
+
196
+ def prepend(value)
197
+ super(html_escape_interpolated_argument(value))
198
+ end
199
+
200
+ def replace(value)
201
+ super(html_escape_interpolated_argument(value))
202
+ end
203
+
204
+ def []=(*args)
205
+ if args.count == 3
206
+ super(args[0], args[1], html_escape_interpolated_argument(args[2]))
207
+ else
208
+ super(args[0], html_escape_interpolated_argument(args[1]))
209
+ end
210
+ end
211
+
212
+ def +(other)
213
+ dup.concat(other)
214
+ end
215
+
216
+ def *(*)
217
+ new_safe_buffer = super
218
+ new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
219
+ new_safe_buffer
220
+ end
221
+
222
+ def %(args)
223
+ case args
224
+ when Hash
225
+ escaped_args = Hash[args.map { |k, arg| [k, html_escape_interpolated_argument(arg)] }]
226
+ else
227
+ escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
228
+ end
229
+
230
+ self.class.new(super(escaped_args))
231
+ end
232
+
233
+ def html_safe?
234
+ defined?(@html_safe) && @html_safe
235
+ end
236
+
237
+ def to_s
238
+ self
239
+ end
240
+
241
+ def to_param
242
+ to_str
243
+ end
244
+
245
+ def encode_with(coder)
246
+ coder.represent_object nil, to_str
247
+ end
248
+
249
+ UNSAFE_STRING_METHODS.each do |unsafe_method|
250
+ if unsafe_method.respond_to?(unsafe_method)
251
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
252
+ def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
253
+ to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
254
+ end # end
255
+
256
+ def #{unsafe_method}!(*args) # def capitalize!(*args)
257
+ @html_safe = false # @html_safe = false
258
+ super # super
259
+ end # end
260
+ EOT
261
+ end
262
+ end
263
+
264
+ UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
265
+ if unsafe_method.respond_to?(unsafe_method)
266
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
267
+ def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
268
+ if block # if block
269
+ to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
270
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
271
+ block.call(*params) # block.call(*params)
272
+ } # }
273
+ else # else
274
+ to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
275
+ end # end
276
+ end # end
277
+
278
+ def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
279
+ @html_safe = false # @html_safe = false
280
+ if block # if block
281
+ super(*args) { |*params| # super(*args) { |*params|
282
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
283
+ block.call(*params) # block.call(*params)
284
+ } # }
285
+ else # else
286
+ super # super
287
+ end # end
288
+ end # end
289
+ EOT
290
+ end
291
+ end
292
+
293
+ private
294
+
295
+ def html_escape_interpolated_argument(arg)
296
+ (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
297
+ end
298
+
299
+ def set_block_back_references(block, match_data)
300
+ block.binding.eval("proc { |m| $~ = m }").call(match_data)
301
+ end
302
+ end
303
+ end
304
+
305
+ class String
306
+ # Marks a string as trusted safe. It will be inserted into HTML with no
307
+ # additional escaping performed. It is your responsibility to ensure that the
308
+ # string contains no malicious content. This method is equivalent to the
309
+ # +raw+ helper in views. It is recommended that you use +sanitize+ instead of
310
+ # this method. It should never be called on user input.
311
+ def html_safe
312
+ ActiveSupport::SafeBuffer.new(self)
313
+ end
314
+ end