activesupport 4.0.12 → 7.0.2.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (295) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +249 -501
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -5
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +5 -3
  7. data/lib/active_support/array_inquirer.rb +48 -0
  8. data/lib/active_support/backtrace_cleaner.rb +41 -13
  9. data/lib/active_support/benchmarkable.rb +7 -15
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +96 -74
  12. data/lib/active_support/cache/mem_cache_store.rb +211 -103
  13. data/lib/active_support/cache/memory_store.rb +90 -58
  14. data/lib/active_support/cache/null_store.rb +19 -7
  15. data/lib/active_support/cache/redis_cache_store.rb +468 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +86 -83
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  18. data/lib/active_support/cache.rb +580 -241
  19. data/lib/active_support/callbacks.rb +812 -425
  20. data/lib/active_support/code_generator.rb +65 -0
  21. data/lib/active_support/concern.rb +103 -14
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +33 -0
  23. data/lib/active_support/concurrency/share_lock.rb +226 -0
  24. data/lib/active_support/configurable.rb +21 -19
  25. data/lib/active_support/configuration_file.rb +51 -0
  26. data/lib/active_support/core_ext/array/access.rb +47 -1
  27. data/lib/active_support/core_ext/array/conversions.rb +35 -44
  28. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +26 -16
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  34. data/lib/active_support/core_ext/array.rb +10 -7
  35. data/lib/active_support/core_ext/benchmark.rb +5 -3
  36. data/lib/active_support/core_ext/big_decimal/conversions.rb +9 -26
  37. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  38. data/lib/active_support/core_ext/class/attribute.rb +52 -49
  39. data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
  40. data/lib/active_support/core_ext/class/subclasses.rb +25 -26
  41. data/lib/active_support/core_ext/class.rb +4 -4
  42. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  43. data/lib/active_support/core_ext/date/blank.rb +14 -0
  44. data/lib/active_support/core_ext/date/calculations.rb +31 -18
  45. data/lib/active_support/core_ext/date/conversions.rb +43 -32
  46. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  47. data/lib/active_support/core_ext/date/zones.rb +5 -34
  48. data/lib/active_support/core_ext/date.rb +7 -4
  49. data/lib/active_support/core_ext/date_and_time/calculations.rb +198 -66
  50. data/lib/active_support/core_ext/date_and_time/compatibility.rb +31 -0
  51. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +79 -38
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +31 -26
  57. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  58. data/lib/active_support/core_ext/date_time.rb +8 -4
  59. data/lib/active_support/core_ext/digest/uuid.rb +79 -0
  60. data/lib/active_support/core_ext/digest.rb +3 -0
  61. data/lib/active_support/core_ext/enumerable.rb +249 -17
  62. data/lib/active_support/core_ext/file/atomic.rb +41 -32
  63. data/lib/active_support/core_ext/file.rb +3 -1
  64. data/lib/active_support/core_ext/hash/conversions.rb +71 -49
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +14 -5
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
  69. data/lib/active_support/core_ext/hash/keys.rb +39 -56
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  71. data/lib/active_support/core_ext/hash/slice.rb +8 -23
  72. data/lib/active_support/core_ext/hash.rb +10 -8
  73. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  74. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  75. data/lib/active_support/core_ext/integer/time.rb +11 -33
  76. data/lib/active_support/core_ext/integer.rb +5 -3
  77. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  78. data/lib/active_support/core_ext/kernel/reporting.rb +9 -78
  79. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  80. data/lib/active_support/core_ext/kernel.rb +5 -4
  81. data/lib/active_support/core_ext/load_error.rb +5 -21
  82. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  83. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  84. data/lib/active_support/core_ext/module/attr_internal.rb +8 -8
  85. data/lib/active_support/core_ext/module/attribute_accessors.rb +186 -44
  86. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +157 -0
  87. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  88. data/lib/active_support/core_ext/module/delegation.rb +172 -45
  89. data/lib/active_support/core_ext/module/deprecation.rb +3 -3
  90. data/lib/active_support/core_ext/module/introspection.rb +23 -38
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  93. data/lib/active_support/core_ext/module.rb +13 -10
  94. data/lib/active_support/core_ext/name_error.rb +45 -4
  95. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +135 -127
  97. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +37 -50
  99. data/lib/active_support/core_ext/numeric.rb +6 -3
  100. data/lib/active_support/core_ext/object/acts_like.rb +41 -6
  101. data/lib/active_support/core_ext/object/blank.rb +70 -20
  102. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  103. data/lib/active_support/core_ext/object/deep_dup.rb +19 -10
  104. data/lib/active_support/core_ext/object/duplicable.rb +17 -47
  105. data/lib/active_support/core_ext/object/inclusion.rb +18 -15
  106. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  107. data/lib/active_support/core_ext/object/json.rb +244 -0
  108. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  109. data/lib/active_support/core_ext/object/to_query.rb +21 -8
  110. data/lib/active_support/core_ext/object/try.rb +106 -26
  111. data/lib/active_support/core_ext/object/with_options.rb +64 -5
  112. data/lib/active_support/core_ext/object.rb +14 -12
  113. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  114. data/lib/active_support/core_ext/pathname.rb +3 -0
  115. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  116. data/lib/active_support/core_ext/range/conversions.rb +37 -15
  117. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  118. data/lib/active_support/core_ext/range/each.rb +18 -17
  119. data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
  120. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  121. data/lib/active_support/core_ext/range.rb +7 -4
  122. data/lib/active_support/core_ext/regexp.rb +10 -1
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string/access.rb +42 -51
  125. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  126. data/lib/active_support/core_ext/string/conversions.rb +18 -13
  127. data/lib/active_support/core_ext/string/exclude.rb +5 -3
  128. data/lib/active_support/core_ext/string/filters.rb +97 -7
  129. data/lib/active_support/core_ext/string/indent.rb +6 -4
  130. data/lib/active_support/core_ext/string/inflections.rb +106 -25
  131. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  132. data/lib/active_support/core_ext/string/multibyte.rb +18 -9
  133. data/lib/active_support/core_ext/string/output_safety.rb +227 -54
  134. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  135. data/lib/active_support/core_ext/string/strip.rb +6 -5
  136. data/lib/active_support/core_ext/string/zones.rb +4 -1
  137. data/lib/active_support/core_ext/string.rb +15 -13
  138. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  139. data/lib/active_support/core_ext/symbol.rb +3 -0
  140. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  141. data/lib/active_support/core_ext/time/calculations.rb +178 -116
  142. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  143. data/lib/active_support/core_ext/time/conversions.rb +37 -25
  144. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  145. data/lib/active_support/core_ext/time/zones.rb +44 -42
  146. data/lib/active_support/core_ext/time.rb +8 -5
  147. data/lib/active_support/core_ext/uri.rb +4 -25
  148. data/lib/active_support/core_ext.rb +4 -2
  149. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  150. data/lib/active_support/current_attributes.rb +226 -0
  151. data/lib/active_support/dependencies/autoload.rb +3 -1
  152. data/lib/active_support/dependencies/interlock.rb +49 -0
  153. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  154. data/lib/active_support/dependencies.rb +71 -696
  155. data/lib/active_support/deprecation/behaviors.rb +65 -16
  156. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  157. data/lib/active_support/deprecation/disallowed.rb +56 -0
  158. data/lib/active_support/deprecation/instance_delegator.rb +16 -2
  159. data/lib/active_support/deprecation/method_wrappers.rb +62 -21
  160. data/lib/active_support/deprecation/proxy_wrappers.rb +82 -31
  161. data/lib/active_support/deprecation/reporting.rb +81 -18
  162. data/lib/active_support/deprecation.rb +19 -11
  163. data/lib/active_support/descendants_tracker.rb +192 -34
  164. data/lib/active_support/digest.rb +22 -0
  165. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  166. data/lib/active_support/duration/iso8601_serializer.rb +67 -0
  167. data/lib/active_support/duration.rb +437 -39
  168. data/lib/active_support/encrypted_configuration.rb +56 -0
  169. data/lib/active_support/encrypted_file.rb +117 -0
  170. data/lib/active_support/environment_inquirer.rb +20 -0
  171. data/lib/active_support/error_reporter.rb +117 -0
  172. data/lib/active_support/evented_file_update_checker.rb +170 -0
  173. data/lib/active_support/execution_context/test_helper.rb +13 -0
  174. data/lib/active_support/execution_context.rb +53 -0
  175. data/lib/active_support/execution_wrapper.rb +151 -0
  176. data/lib/active_support/executor/test_helper.rb +7 -0
  177. data/lib/active_support/executor.rb +8 -0
  178. data/lib/active_support/file_update_checker.rb +62 -37
  179. data/lib/active_support/fork_tracker.rb +71 -0
  180. data/lib/active_support/gem_version.rb +17 -0
  181. data/lib/active_support/gzip.rb +7 -5
  182. data/lib/active_support/hash_with_indifferent_access.rb +207 -54
  183. data/lib/active_support/html_safe_translation.rb +43 -0
  184. data/lib/active_support/i18n.rb +10 -6
  185. data/lib/active_support/i18n_railtie.rb +48 -19
  186. data/lib/active_support/inflections.rb +19 -12
  187. data/lib/active_support/inflector/inflections.rb +97 -37
  188. data/lib/active_support/inflector/methods.rb +192 -157
  189. data/lib/active_support/inflector/transliterate.rb +83 -33
  190. data/lib/active_support/inflector.rb +7 -5
  191. data/lib/active_support/isolated_execution_state.rb +64 -0
  192. data/lib/active_support/json/decoding.rb +37 -42
  193. data/lib/active_support/json/encoding.rb +93 -293
  194. data/lib/active_support/json.rb +4 -2
  195. data/lib/active_support/key_generator.rb +30 -47
  196. data/lib/active_support/lazy_load_hooks.rb +54 -21
  197. data/lib/active_support/locale/en.rb +33 -0
  198. data/lib/active_support/locale/en.yml +10 -4
  199. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  200. data/lib/active_support/log_subscriber.rb +61 -18
  201. data/lib/active_support/logger.rb +40 -4
  202. data/lib/active_support/logger_silence.rb +17 -20
  203. data/lib/active_support/logger_thread_safe_level.rb +69 -0
  204. data/lib/active_support/message_encryptor.rb +178 -55
  205. data/lib/active_support/message_verifier.rb +195 -26
  206. data/lib/active_support/messages/metadata.rb +80 -0
  207. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  208. data/lib/active_support/messages/rotator.rb +57 -0
  209. data/lib/active_support/multibyte/chars.rb +45 -92
  210. data/lib/active_support/multibyte/unicode.rb +44 -377
  211. data/lib/active_support/multibyte.rb +5 -3
  212. data/lib/active_support/notifications/fanout.rb +177 -44
  213. data/lib/active_support/notifications/instrumenter.rb +117 -17
  214. data/lib/active_support/notifications.rb +106 -39
  215. data/lib/active_support/number_helper/number_converter.rb +181 -0
  216. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  217. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  218. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  219. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  220. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  221. data/lib/active_support/number_helper/number_to_phone_converter.rb +59 -0
  222. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  223. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  224. data/lib/active_support/number_helper.rb +152 -394
  225. data/lib/active_support/option_merger.rb +18 -5
  226. data/lib/active_support/ordered_hash.rb +8 -6
  227. data/lib/active_support/ordered_options.rb +43 -7
  228. data/lib/active_support/parameter_filter.rb +138 -0
  229. data/lib/active_support/per_thread_registry.rb +24 -11
  230. data/lib/active_support/proxy_object.rb +2 -0
  231. data/lib/active_support/rails.rb +10 -11
  232. data/lib/active_support/railtie.rb +118 -12
  233. data/lib/active_support/reloader.rb +130 -0
  234. data/lib/active_support/rescuable.rb +112 -57
  235. data/lib/active_support/ruby_features.rb +7 -0
  236. data/lib/active_support/secure_compare_rotator.rb +51 -0
  237. data/lib/active_support/security_utils.rb +38 -0
  238. data/lib/active_support/string_inquirer.rb +11 -4
  239. data/lib/active_support/subscriber.rb +109 -39
  240. data/lib/active_support/tagged_logging.rb +54 -17
  241. data/lib/active_support/test_case.rb +121 -37
  242. data/lib/active_support/testing/assertions.rb +177 -39
  243. data/lib/active_support/testing/autorun.rb +5 -3
  244. data/lib/active_support/testing/constant_lookup.rb +3 -6
  245. data/lib/active_support/testing/declarative.rb +10 -22
  246. data/lib/active_support/testing/deprecation.rb +65 -11
  247. data/lib/active_support/testing/file_fixtures.rb +38 -0
  248. data/lib/active_support/testing/isolation.rb +56 -87
  249. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  250. data/lib/active_support/testing/parallelization/server.rb +82 -0
  251. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  252. data/lib/active_support/testing/parallelization.rb +55 -0
  253. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  254. data/lib/active_support/testing/setup_and_teardown.rb +30 -10
  255. data/lib/active_support/testing/stream.rb +41 -0
  256. data/lib/active_support/testing/tagged_logging.rb +6 -4
  257. data/lib/active_support/testing/time_helpers.rb +246 -0
  258. data/lib/active_support/time.rb +13 -13
  259. data/lib/active_support/time_with_zone.rb +315 -90
  260. data/lib/active_support/values/time_zone.rb +306 -135
  261. data/lib/active_support/version.rb +6 -7
  262. data/lib/active_support/xml_mini/jdom.rb +117 -115
  263. data/lib/active_support/xml_mini/libxml.rb +22 -21
  264. data/lib/active_support/xml_mini/libxmlsax.rb +17 -19
  265. data/lib/active_support/xml_mini/nokogiri.rb +19 -19
  266. data/lib/active_support/xml_mini/nokogirisax.rb +16 -17
  267. data/lib/active_support/xml_mini/rexml.rb +25 -17
  268. data/lib/active_support/xml_mini.rb +67 -56
  269. data/lib/active_support.rb +58 -3
  270. metadata +125 -66
  271. data/lib/active_support/basic_object.rb +0 -11
  272. data/lib/active_support/buffered_logger.rb +0 -21
  273. data/lib/active_support/concurrency/latch.rb +0 -27
  274. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  275. data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
  276. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -40
  277. data/lib/active_support/core_ext/date_time/zones.rb +0 -24
  278. data/lib/active_support/core_ext/hash/diff.rb +0 -14
  279. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  280. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  281. data/lib/active_support/core_ext/logger.rb +0 -67
  282. data/lib/active_support/core_ext/marshal.rb +0 -21
  283. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  284. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  285. data/lib/active_support/core_ext/object/to_json.rb +0 -27
  286. data/lib/active_support/core_ext/proc.rb +0 -17
  287. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  288. data/lib/active_support/core_ext/string/encoding.rb +0 -8
  289. data/lib/active_support/core_ext/struct.rb +0 -6
  290. data/lib/active_support/core_ext/thread.rb +0 -79
  291. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  292. data/lib/active_support/file_watcher.rb +0 -36
  293. data/lib/active_support/json/variable.rb +0 -18
  294. data/lib/active_support/testing/pending.rb +0 -14
  295. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,5 +1,6 @@
1
- # encoding: utf-8
2
- require 'active_support/multibyte'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/multibyte"
3
4
 
4
5
  class String
5
6
  # == Multibyte proxy
@@ -10,12 +11,13 @@ class String
10
11
  # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
11
12
  # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
12
13
  #
13
- # name = 'Claus Müller'
14
- # name.reverse # => "rell??M sualC"
15
- # name.length # => 13
14
+ # >> "lj".mb_chars.upcase.to_s
15
+ # => "LJ"
16
+ #
17
+ # NOTE: Ruby 2.4 and later support native Unicode case mappings:
16
18
  #
17
- # name.mb_chars.reverse.to_s # => "rellüM sualC"
18
- # name.mb_chars.length # => 12
19
+ # >> "lj".upcase
20
+ # => "LJ"
19
21
  #
20
22
  # == Method chaining
21
23
  #
@@ -36,11 +38,18 @@ class String
36
38
  ActiveSupport::Multibyte.proxy_class.new(self)
37
39
  end
38
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
39
48
  def is_utf8?
40
49
  case encoding
41
- when Encoding::UTF_8
50
+ when Encoding::UTF_8, Encoding::US_ASCII
42
51
  valid_encoding?
43
- when Encoding::ASCII_8BIT, Encoding::US_ASCII
52
+ when Encoding::ASCII_8BIT
44
53
  dup.force_encoding(Encoding::UTF_8).valid_encoding?
45
54
  else
46
55
  false
@@ -1,39 +1,53 @@
1
- require 'erb'
2
- require 'active_support/core_ext/kernel/singleton_class'
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "active_support/core_ext/module/redefine_method"
5
+ require "active_support/multibyte/unicode"
3
6
 
4
7
  class ERB
5
8
  module Util
6
- HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
7
- JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
8
- HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
9
- JSON_ESCAPE_REGEXP = /[&"><]/
9
+ HTML_ESCAPE = { "&" => "&amp;", ">" => "&gt;", "<" => "&lt;", '"' => "&quot;", "'" => "&#39;" }
10
+ JSON_ESCAPE = { "&" => '\u0026', ">" => '\u003e', "<" => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
11
+ HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
12
+ JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
13
+
14
+ # Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
15
+ TAG_NAME_START_REGEXP_SET = ":A-Z_a-z\u{C0}-\u{D6}\u{D8}-\u{F6}\u{F8}-\u{2FF}\u{370}-\u{37D}\u{37F}-\u{1FFF}" \
16
+ "\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
17
+ "\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
18
+ TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}]/
19
+ TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}]/
20
+ TAG_NAME_REPLACEMENT_CHAR = "_"
10
21
 
11
22
  # A utility method for escaping HTML tag characters.
12
23
  # This method is also aliased as <tt>h</tt>.
13
24
  #
14
- # In your ERB templates, use this method to escape any unsafe content. For example:
15
- # <%=h @person.name %>
16
- #
17
25
  # puts html_escape('is a > 0 & a < 10?')
18
26
  # # => is a &gt; 0 &amp; a &lt; 10?
19
27
  def html_escape(s)
20
- s = s.to_s
21
- if s.html_safe?
22
- s
23
- else
24
- s.gsub(/[&"'><]/, HTML_ESCAPE).html_safe
25
- end
28
+ unwrapped_html_escape(s).html_safe
26
29
  end
27
30
 
28
- # Aliasing twice issues a warning "discarding old...". Remove first to avoid it.
29
- remove_method(:h)
31
+ silence_redefinition_of_method :h
30
32
  alias h html_escape
31
33
 
32
34
  module_function :h
33
35
 
34
- singleton_class.send(:remove_method, :html_escape)
36
+ singleton_class.silence_redefinition_of_method :html_escape
35
37
  module_function :html_escape
36
38
 
39
+ # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
40
+ # This method is not for public consumption! Seriously!
41
+ def unwrapped_html_escape(s) # :nodoc:
42
+ s = s.to_s
43
+ if s.html_safe?
44
+ s
45
+ else
46
+ CGI.escapeHTML(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
47
+ end
48
+ end
49
+ module_function :unwrapped_html_escape
50
+
37
51
  # A utility method for escaping HTML without affecting existing escaped entities.
38
52
  #
39
53
  # html_escape_once('1 < 2 &amp; 3')
@@ -42,29 +56,93 @@ class ERB
42
56
  # html_escape_once('&lt;&lt; Accept & Checkout')
43
57
  # # => "&lt;&lt; Accept &amp; Checkout"
44
58
  def html_escape_once(s)
45
- result = s.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
59
+ result = ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
46
60
  s.html_safe? ? result.html_safe : result
47
61
  end
48
62
 
49
63
  module_function :html_escape_once
50
64
 
51
- # A utility method for escaping HTML entities in JSON strings
52
- # using \uXXXX JavaScript escape sequences for string literals:
65
+ # A utility method for escaping HTML entities in JSON strings. Specifically, the
66
+ # &, > and < characters are replaced with their equivalent unicode escaped form -
67
+ # \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also
68
+ # escaped as they are treated as newline characters in some JavaScript engines.
69
+ # These sequences have identical meaning as the original characters inside the
70
+ # context of a JSON string, so assuming the input is a valid and well-formed
71
+ # JSON value, the output will have equivalent meaning when parsed:
72
+ #
73
+ # json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
74
+ # # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
75
+ #
76
+ # json_escape(json)
77
+ # # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
78
+ #
79
+ # JSON.parse(json) == JSON.parse(json_escape(json))
80
+ # # => true
53
81
  #
54
- # json_escape('is a > 0 & a < 10?')
55
- # # => is a \u003E 0 \u0026 a \u003C 10?
82
+ # The intended use case for this method is to escape JSON strings before including
83
+ # them inside a script tag to avoid XSS vulnerability:
56
84
  #
57
- # Note that after this operation is performed the output is not
58
- # valid JSON. In particular double quotes are removed:
85
+ # <script>
86
+ # var currentUser = <%= raw json_escape(current_user.to_json) %>;
87
+ # </script>
59
88
  #
60
- # json_escape('{"name":"john","created_at":"2010-04-28T01:39:31Z","id":1}')
61
- # # => {name:john,created_at:2010-04-28T01:39:31Z,id:1}
89
+ # It is necessary to +raw+ the result of +json_escape+, so that quotation marks
90
+ # don't get converted to <tt>&quot;</tt> entities. +json_escape+ doesn't
91
+ # automatically flag the result as HTML safe, since the raw value is unsafe to
92
+ # use inside HTML attributes.
93
+ #
94
+ # If your JSON is being used downstream for insertion into the DOM, be aware of
95
+ # whether or not it is being inserted via <tt>html()</tt>. Most jQuery plugins do this.
96
+ # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
97
+ # content returned by your JSON.
98
+ #
99
+ # If you need to output JSON elsewhere in your HTML, you can just do something
100
+ # like this, as any unsafe characters (including quotation marks) will be
101
+ # automatically escaped for you:
102
+ #
103
+ # <div data-user-info="<%= current_user.to_json %>">...</div>
104
+ #
105
+ # WARNING: this helper only works with valid JSON. Using this on non-JSON values
106
+ # will open up serious XSS vulnerabilities. For example, if you replace the
107
+ # +current_user.to_json+ in the example above with user input instead, the browser
108
+ # will happily eval() that string as JavaScript.
109
+ #
110
+ # The escaping performed in this method is identical to those performed in the
111
+ # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
112
+ # set to true. Because this transformation is idempotent, this helper can be
113
+ # applied even if +ActiveSupport.escape_html_entities_in_json+ is already true.
114
+ #
115
+ # Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+
116
+ # is enabled, or if you are unsure where your JSON string originated from, it
117
+ # is recommended that you always apply this helper (other libraries, such as the
118
+ # JSON gem, do not provide this kind of protection by default; also some gems
119
+ # might override +to_json+ to bypass Active Support's encoder).
62
120
  def json_escape(s)
63
121
  result = s.to_s.gsub(JSON_ESCAPE_REGEXP, JSON_ESCAPE)
64
122
  s.html_safe? ? result.html_safe : result
65
123
  end
66
124
 
67
125
  module_function :json_escape
126
+
127
+ # A utility method for escaping XML names of tags and names of attributes.
128
+ #
129
+ # xml_name_escape('1 < 2 & 3')
130
+ # # => "1___2___3"
131
+ #
132
+ # It follows the requirements of the specification: https://www.w3.org/TR/REC-xml/#NT-Name
133
+ def xml_name_escape(name)
134
+ name = name.to_s
135
+ return "" if name.blank?
136
+
137
+ starting_char = name[0].gsub(TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
138
+
139
+ return starting_char if name.size == 1
140
+
141
+ following_chars = name[1..-1].gsub(TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
142
+
143
+ starting_char + following_chars
144
+ end
145
+ module_function :xml_name_escape
68
146
  end
69
147
  end
70
148
 
@@ -80,33 +158,37 @@ class Numeric
80
158
  end
81
159
  end
82
160
 
83
- module ActiveSupport #:nodoc:
161
+ module ActiveSupport # :nodoc:
84
162
  class SafeBuffer < String
85
163
  UNSAFE_STRING_METHODS = %w(
86
- capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
87
- slice squeeze strip sub succ swapcase tr tr_s upcase prepend
164
+ capitalize chomp chop delete delete_prefix delete_suffix
165
+ downcase lstrip next reverse rstrip scrub slice squeeze strip
166
+ succ swapcase tr tr_s unicode_normalize upcase
88
167
  )
89
168
 
169
+ UNSAFE_STRING_METHODS_WITH_BACKREF = %w(gsub sub)
170
+
90
171
  alias_method :original_concat, :concat
91
172
  private :original_concat
92
173
 
174
+ # Raised when <tt>ActiveSupport::SafeBuffer#safe_concat</tt> is called on unsafe buffers.
93
175
  class SafeConcatError < StandardError
94
176
  def initialize
95
- super 'Could not concatenate to the buffer because it is not html safe.'
177
+ super "Could not concatenate to the buffer because it is not html safe."
96
178
  end
97
179
  end
98
180
 
99
181
  def [](*args)
100
- if args.size < 2
101
- super
182
+ if html_safe?
183
+ new_string = super
184
+
185
+ return unless new_string
186
+
187
+ new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
188
+ new_safe_buffer.instance_variable_set :@html_safe, true
189
+ new_safe_buffer
102
190
  else
103
- if html_safe?
104
- new_safe_buffer = super
105
- new_safe_buffer.instance_eval { @html_safe = true }
106
- new_safe_buffer
107
- else
108
- to_str[*args]
109
- end
191
+ to_str[*args]
110
192
  end
111
193
  end
112
194
 
@@ -115,7 +197,7 @@ module ActiveSupport #:nodoc:
115
197
  original_concat(value)
116
198
  end
117
199
 
118
- def initialize(*)
200
+ def initialize(str = "")
119
201
  @html_safe = true
120
202
  super
121
203
  end
@@ -130,28 +212,53 @@ module ActiveSupport #:nodoc:
130
212
  end
131
213
 
132
214
  def concat(value)
133
- if !html_safe? || value.html_safe?
134
- super(value)
135
- else
136
- super(ERB::Util.h(value))
215
+ unless value.nil?
216
+ super(implicit_html_escape_interpolated_argument(value))
137
217
  end
218
+ self
138
219
  end
139
220
  alias << concat
140
221
 
222
+ def insert(index, value)
223
+ super(index, implicit_html_escape_interpolated_argument(value))
224
+ end
225
+
226
+ def prepend(value)
227
+ super(implicit_html_escape_interpolated_argument(value))
228
+ end
229
+
230
+ def replace(value)
231
+ super(implicit_html_escape_interpolated_argument(value))
232
+ end
233
+
234
+ def []=(*args)
235
+ if args.length == 3
236
+ super(args[0], args[1], implicit_html_escape_interpolated_argument(args[2]))
237
+ else
238
+ super(args[0], implicit_html_escape_interpolated_argument(args[1]))
239
+ end
240
+ end
241
+
141
242
  def +(other)
142
243
  dup.concat(other)
143
244
  end
144
245
 
246
+ def *(*)
247
+ new_string = super
248
+ new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
249
+ new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
250
+ new_safe_buffer
251
+ end
252
+
145
253
  def %(args)
146
- args = Array(args).map do |arg|
147
- if !html_safe? || arg.html_safe?
148
- arg
149
- else
150
- ERB::Util.h(arg)
151
- end
254
+ case args
255
+ when Hash
256
+ escaped_args = args.transform_values { |arg| explicit_html_escape_interpolated_argument(arg) }
257
+ else
258
+ escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
152
259
  end
153
260
 
154
- self.class.new(super(args))
261
+ self.class.new(super(escaped_args))
155
262
  end
156
263
 
157
264
  def html_safe?
@@ -167,11 +274,11 @@ module ActiveSupport #:nodoc:
167
274
  end
168
275
 
169
276
  def encode_with(coder)
170
- coder.represent_scalar nil, to_str
277
+ coder.represent_object nil, to_str
171
278
  end
172
279
 
173
280
  UNSAFE_STRING_METHODS.each do |unsafe_method|
174
- if 'String'.respond_to?(unsafe_method)
281
+ if unsafe_method.respond_to?(unsafe_method)
175
282
  class_eval <<-EOT, __FILE__, __LINE__ + 1
176
283
  def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
177
284
  to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
@@ -184,10 +291,76 @@ module ActiveSupport #:nodoc:
184
291
  EOT
185
292
  end
186
293
  end
294
+
295
+ UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
296
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
297
+ def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
298
+ if block # if block
299
+ to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
300
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
301
+ block.call(*params) # block.call(*params)
302
+ } # }
303
+ else # else
304
+ to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
305
+ end # end
306
+ end # end
307
+
308
+ def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
309
+ @html_safe = false # @html_safe = false
310
+ if block # if block
311
+ super(*args) { |*params| # super(*args) { |*params|
312
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
313
+ block.call(*params) # block.call(*params)
314
+ } # }
315
+ else # else
316
+ super # super
317
+ end # end
318
+ end # end
319
+ EOT
320
+ end
321
+
322
+ private
323
+ def explicit_html_escape_interpolated_argument(arg)
324
+ (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
325
+ end
326
+
327
+ def implicit_html_escape_interpolated_argument(arg)
328
+ if !html_safe? || arg.html_safe?
329
+ arg
330
+ else
331
+ arg_string = begin
332
+ arg.to_str
333
+ rescue NoMethodError => error
334
+ if error.name == :to_str
335
+ str = arg.to_s
336
+ ActiveSupport::Deprecation.warn <<~MSG.squish
337
+ Implicit conversion of #{arg.class} into String by ActiveSupport::SafeBuffer
338
+ is deprecated and will be removed in Rails 7.1.
339
+ You must explicitly cast it to a String.
340
+ MSG
341
+ str
342
+ else
343
+ raise
344
+ end
345
+ end
346
+ CGI.escapeHTML(arg_string)
347
+ end
348
+ end
349
+
350
+ def set_block_back_references(block, match_data)
351
+ block.binding.eval("proc { |m| $~ = m }").call(match_data)
352
+ rescue ArgumentError
353
+ # Can't create binding from C level Proc
354
+ end
187
355
  end
188
356
  end
189
357
 
190
358
  class String
359
+ # Marks a string as trusted safe. It will be inserted into HTML with no
360
+ # additional escaping performed. It is your responsibility to ensure that the
361
+ # string contains no malicious content. This method is equivalent to the
362
+ # +raw+ helper in views. It is recommended that you use +sanitize+ instead of
363
+ # this method. It should never be called on user input.
191
364
  def html_safe
192
365
  ActiveSupport::SafeBuffer.new(self)
193
366
  end
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
- alias_method :starts_with?, :start_with?
3
- alias_method :ends_with?, :end_with?
4
+ alias :starts_with? :start_with?
5
+ alias :ends_with? :end_with?
4
6
  end
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/object/try'
1
+ # frozen_string_literal: true
2
2
 
3
3
  class String
4
4
  # Strips indentation in heredocs.
@@ -17,10 +17,11 @@ class String
17
17
  #
18
18
  # the user would see the usage message aligned against the left margin.
19
19
  #
20
- # Technically, it looks for the least indented line in the whole string, and removes
21
- # that amount of leading whitespace.
20
+ # Technically, it looks for the least indented non-empty line
21
+ # in the whole string, and removes that amount of leading whitespace.
22
22
  def strip_heredoc
23
- indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
24
- gsub(/^[ \t]{#{indent}}/, '')
23
+ gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "").tap do |stripped|
24
+ stripped.freeze if frozen?
25
+ end
25
26
  end
26
27
  end
@@ -1,4 +1,7 @@
1
- require 'active_support/core_ext/time/zones'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/conversions"
4
+ require "active_support/core_ext/time/zones"
2
5
 
3
6
  class String
4
7
  # Converts String to a TimeWithZone in the current zone if Time.zone or Time.zone_default
@@ -1,13 +1,15 @@
1
- require 'active_support/core_ext/string/conversions'
2
- require 'active_support/core_ext/string/filters'
3
- require 'active_support/core_ext/string/multibyte'
4
- require 'active_support/core_ext/string/starts_ends_with'
5
- require 'active_support/core_ext/string/inflections'
6
- require 'active_support/core_ext/string/access'
7
- require 'active_support/core_ext/string/behavior'
8
- require 'active_support/core_ext/string/output_safety'
9
- require 'active_support/core_ext/string/exclude'
10
- require 'active_support/core_ext/string/strip'
11
- require 'active_support/core_ext/string/inquiry'
12
- require 'active_support/core_ext/string/indent'
13
- require 'active_support/core_ext/string/zones'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/conversions"
4
+ require "active_support/core_ext/string/filters"
5
+ require "active_support/core_ext/string/multibyte"
6
+ require "active_support/core_ext/string/starts_ends_with"
7
+ require "active_support/core_ext/string/inflections"
8
+ require "active_support/core_ext/string/access"
9
+ require "active_support/core_ext/string/behavior"
10
+ require "active_support/core_ext/string/output_safety"
11
+ require "active_support/core_ext/string/exclude"
12
+ require "active_support/core_ext/string/strip"
13
+ require "active_support/core_ext/string/inquiry"
14
+ require "active_support/core_ext/string/indent"
15
+ require "active_support/core_ext/string/zones"
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Symbol
4
+ alias :starts_with? :start_with?
5
+ alias :ends_with? :end_with?
6
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/symbol/starts_ends_with"
@@ -1,4 +1,6 @@
1
- require 'active_support/core_ext/object/acts_like'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/acts_like"
2
4
 
3
5
  class Time
4
6
  # Duck-types as a Time-like class. See Object#acts_like?.