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,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module ActiveSupport
6
+ module CoreExt
7
+ module ERBUtil
8
+ # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
9
+ # This method is not for public consumption! Seriously!
10
+ def html_escape(s) # :nodoc:
11
+ s = s.to_s
12
+ if s.html_safe?
13
+ s
14
+ else
15
+ super(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
16
+ end
17
+ end
18
+ alias :unwrapped_html_escape :html_escape # :nodoc:
19
+
20
+ # A utility method for escaping HTML tag characters.
21
+ # This method is also aliased as <tt>h</tt>.
22
+ #
23
+ # puts html_escape('is a > 0 & a < 10?')
24
+ # # => is a &gt; 0 &amp; a &lt; 10?
25
+ def html_escape(s) # rubocop:disable Lint/DuplicateMethods
26
+ unwrapped_html_escape(s).html_safe
27
+ end
28
+ alias h html_escape
29
+ end
30
+
31
+ module ERBUtilPrivate
32
+ include ERBUtil
33
+ private :unwrapped_html_escape, :html_escape, :h
34
+ end
35
+ end
36
+ end
37
+
38
+ class ERB
39
+ module Util
40
+ HTML_ESCAPE = { "&" => "&amp;", ">" => "&gt;", "<" => "&lt;", '"' => "&quot;", "'" => "&#39;" }
41
+ HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
42
+
43
+ # Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
44
+ TAG_NAME_START_CODEPOINTS = "@:A-Z_a-z\u{C0}-\u{D6}\u{D8}-\u{F6}\u{F8}-\u{2FF}\u{370}-\u{37D}\u{37F}-\u{1FFF}" \
45
+ "\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
46
+ "\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
47
+ INVALID_TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_CODEPOINTS}]/
48
+ TAG_NAME_FOLLOWING_CODEPOINTS = "#{TAG_NAME_START_CODEPOINTS}\\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}"
49
+ INVALID_TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_FOLLOWING_CODEPOINTS}]/
50
+ SAFE_XML_TAG_NAME_REGEXP = /\A[#{TAG_NAME_START_CODEPOINTS}][#{TAG_NAME_FOLLOWING_CODEPOINTS}]*\z/
51
+ TAG_NAME_REPLACEMENT_CHAR = "_"
52
+
53
+ prepend ActiveSupport::CoreExt::ERBUtilPrivate
54
+ singleton_class.prepend ActiveSupport::CoreExt::ERBUtil
55
+
56
+ # A utility method for escaping HTML without affecting existing escaped entities.
57
+ #
58
+ # html_escape_once('1 < 2 &amp; 3')
59
+ # # => "1 &lt; 2 &amp; 3"
60
+ #
61
+ # html_escape_once('&lt;&lt; Accept & Checkout')
62
+ # # => "&lt;&lt; Accept &amp; Checkout"
63
+ def html_escape_once(s)
64
+ ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE).html_safe
65
+ end
66
+
67
+ module_function :html_escape_once
68
+
69
+ # A utility method for escaping HTML entities in JSON strings. Specifically, the
70
+ # &, > and < characters are replaced with their equivalent unicode escaped form -
71
+ # \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also
72
+ # escaped as they are treated as newline characters in some JavaScript engines.
73
+ # These sequences have identical meaning as the original characters inside the
74
+ # context of a JSON string, so assuming the input is a valid and well-formed
75
+ # JSON value, the output will have equivalent meaning when parsed:
76
+ #
77
+ # json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
78
+ # # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
79
+ #
80
+ # json_escape(json)
81
+ # # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
82
+ #
83
+ # JSON.parse(json) == JSON.parse(json_escape(json))
84
+ # # => true
85
+ #
86
+ # The intended use case for this method is to escape JSON strings before including
87
+ # them inside a script tag to avoid XSS vulnerability:
88
+ #
89
+ # <script>
90
+ # var currentUser = <%= raw json_escape(current_user.to_json) %>;
91
+ # </script>
92
+ #
93
+ # It is necessary to +raw+ the result of +json_escape+, so that quotation marks
94
+ # don't get converted to <tt>&quot;</tt> entities. +json_escape+ doesn't
95
+ # automatically flag the result as HTML safe, since the raw value is unsafe to
96
+ # use inside HTML attributes.
97
+ #
98
+ # If your JSON is being used downstream for insertion into the DOM, be aware of
99
+ # whether or not it is being inserted via <tt>html()</tt>. Most jQuery plugins do this.
100
+ # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
101
+ # content returned by your JSON.
102
+ #
103
+ # If you need to output JSON elsewhere in your HTML, you can just do something
104
+ # like this, as any unsafe characters (including quotation marks) will be
105
+ # automatically escaped for you:
106
+ #
107
+ # <div data-user-info="<%= current_user.to_json %>">...</div>
108
+ #
109
+ # WARNING: this helper only works with valid JSON. Using this on non-JSON values
110
+ # will open up serious XSS vulnerabilities. For example, if you replace the
111
+ # +current_user.to_json+ in the example above with user input instead, the browser
112
+ # will happily <tt>eval()</tt> that string as JavaScript.
113
+ #
114
+ # The escaping performed in this method is identical to those performed in the
115
+ # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
116
+ # set to true. Because this transformation is idempotent, this helper can be
117
+ # applied even if +ActiveSupport.escape_html_entities_in_json+ is already true.
118
+ #
119
+ # Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+
120
+ # is enabled, or if you are unsure where your JSON string originated from, it
121
+ # is recommended that you always apply this helper (other libraries, such as the
122
+ # JSON gem, do not provide this kind of protection by default; also some gems
123
+ # might override +to_json+ to bypass Active Support's encoder).
124
+ def json_escape(s)
125
+ result = s.to_s.dup
126
+ result.gsub!(">", '\u003e')
127
+ result.gsub!("<", '\u003c')
128
+ result.gsub!("&", '\u0026')
129
+ result.gsub!("\u2028", '\u2028')
130
+ result.gsub!("\u2029", '\u2029')
131
+ s.html_safe? ? result.html_safe : result
132
+ end
133
+
134
+ module_function :json_escape
135
+
136
+ # A utility method for escaping XML names of tags and names of attributes.
137
+ #
138
+ # xml_name_escape('1 < 2 & 3')
139
+ # # => "1___2___3"
140
+ #
141
+ # It follows the requirements of the specification: https://www.w3.org/TR/REC-xml/#NT-Name
142
+ def xml_name_escape(name)
143
+ name = name.to_s
144
+ return "" if name.blank?
145
+ return name if name.match?(SAFE_XML_TAG_NAME_REGEXP)
146
+
147
+ starting_char = name[0]
148
+ starting_char.gsub!(INVALID_TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
149
+
150
+ return starting_char if name.size == 1
151
+
152
+ following_chars = name[1..-1]
153
+ following_chars.gsub!(INVALID_TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
154
+
155
+ starting_char << following_chars
156
+ end
157
+ module_function :xml_name_escape
158
+
159
+ # Tokenizes a line of ERB. This is really just for error reporting and
160
+ # nobody should use it.
161
+ def self.tokenize(source) # :nodoc:
162
+ require "strscan"
163
+ source = StringScanner.new(source.chomp)
164
+ tokens = []
165
+
166
+ start_re = /<%(?:={1,2}|-|\#|%)?/m
167
+ finish_re = /(?:[-=])?%>/m
168
+
169
+ while !source.eos?
170
+ pos = source.pos
171
+ source.scan_until(/(?:#{start_re}|#{finish_re})/)
172
+ raise NotImplementedError if source.matched.nil?
173
+ len = source.pos - source.matched.bytesize - pos
174
+
175
+ case source.matched
176
+ when start_re
177
+ tokens << [:TEXT, source.string[pos, len]] if len > 0
178
+ tokens << [:OPEN, source.matched]
179
+ if source.scan(/(.*?)(?=#{finish_re}|\z)/m)
180
+ tokens << [:CODE, source.matched] unless source.matched.empty?
181
+ tokens << [:CLOSE, source.scan(finish_re)] unless source.eos?
182
+ else
183
+ raise NotImplementedError
184
+ end
185
+ when finish_re
186
+ tokens << [:CODE, source.string[pos, len]] if len > 0
187
+ tokens << [:CLOSE, source.matched]
188
+ else
189
+ raise NotImplementedError, source.matched
190
+ end
191
+
192
+ unless source.eos? || source.exist?(start_re) || source.exist?(finish_re)
193
+ tokens << [:TEXT, source.rest]
194
+ source.terminate
195
+ end
196
+ end
197
+
198
+ tokens
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ class File
6
+ # Write to a file atomically. Useful for situations where you don't
7
+ # want other processes or threads to see half-written files.
8
+ #
9
+ # File.atomic_write('important.file') do |file|
10
+ # file.write('hello')
11
+ # end
12
+ #
13
+ # This method needs to create a temporary file. By default it will create it
14
+ # in the same directory as the destination file. If you don't like this
15
+ # behavior you can provide a different directory but it must be on the
16
+ # same physical filesystem as the file you're trying to write.
17
+ #
18
+ # File.atomic_write('/data/something.important', '/data/tmp') do |file|
19
+ # file.write('hello')
20
+ # end
21
+ def self.atomic_write(file_name, temp_dir = dirname(file_name))
22
+ require "tempfile" unless defined?(Tempfile)
23
+
24
+ Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
25
+ temp_file.binmode
26
+ return_val = yield temp_file
27
+ temp_file.close
28
+
29
+ old_stat = if exist?(file_name)
30
+ # Get original file permissions
31
+ stat(file_name)
32
+ else
33
+ # If not possible, probe which are the default permissions in the
34
+ # destination directory.
35
+ probe_stat_in(dirname(file_name))
36
+ end
37
+
38
+ if old_stat
39
+ # Set correct permissions on new file
40
+ begin
41
+ chown(old_stat.uid, old_stat.gid, temp_file.path)
42
+ # This operation will affect filesystem ACL's
43
+ chmod(old_stat.mode, temp_file.path)
44
+ rescue Errno::EPERM, Errno::EACCES
45
+ # Changing file ownership failed, moving on.
46
+ end
47
+ end
48
+
49
+ # Overwrite original file with temp file
50
+ rename(temp_file.path, file_name)
51
+ return_val
52
+ end
53
+ end
54
+
55
+ # Private utility method.
56
+ def self.probe_stat_in(dir) # :nodoc:
57
+ basename = [
58
+ ".permissions_check",
59
+ Thread.current.object_id,
60
+ Process.pid,
61
+ rand(1000000)
62
+ ].join(".")
63
+
64
+ file_name = join(dir, basename)
65
+ FileUtils.touch(file_name)
66
+ stat(file_name)
67
+ rescue Errno::ENOENT
68
+ file_name = nil
69
+ ensure
70
+ FileUtils.rm_f(file_name) if file_name
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/file/atomic"
@@ -0,0 +1,262 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/blank"
4
+ require "active_support/core_ext/object/to_param"
5
+ require "active_support/core_ext/object/to_query"
6
+ require "active_support/core_ext/object/try"
7
+ require "active_support/core_ext/array/wrap"
8
+ require "active_support/core_ext/hash/reverse_merge"
9
+ require "active_support/core_ext/string/inflections"
10
+
11
+ class Hash
12
+ # Returns a string containing an XML representation of its receiver:
13
+ #
14
+ # { foo: 1, bar: 2 }.to_xml
15
+ # # =>
16
+ # # <?xml version="1.0" encoding="UTF-8"?>
17
+ # # <hash>
18
+ # # <foo type="integer">1</foo>
19
+ # # <bar type="integer">2</bar>
20
+ # # </hash>
21
+ #
22
+ # To do so, the method loops over the pairs and builds nodes that depend on
23
+ # the _values_. Given a pair +key+, +value+:
24
+ #
25
+ # * If +value+ is a hash there's a recursive call with +key+ as <tt>:root</tt>.
26
+ #
27
+ # * If +value+ is an array there's a recursive call with +key+ as <tt>:root</tt>,
28
+ # and +key+ singularized as <tt>:children</tt>.
29
+ #
30
+ # * If +value+ is a callable object it must expect one or two arguments. Depending
31
+ # on the arity, the callable is invoked with the +options+ hash as first argument
32
+ # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
33
+ # callable can add nodes by using <tt>options[:builder]</tt>.
34
+ #
35
+ # {foo: lambda { |options, key| options[:builder].b(key) }}.to_xml
36
+ # # => "<b>foo</b>"
37
+ #
38
+ # * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
39
+ #
40
+ # class Foo
41
+ # def to_xml(options)
42
+ # options[:builder].bar 'fooing!'
43
+ # end
44
+ # end
45
+ #
46
+ # { foo: Foo.new }.to_xml(skip_instruct: true)
47
+ # # =>
48
+ # # <hash>
49
+ # # <bar>fooing!</bar>
50
+ # # </hash>
51
+ #
52
+ # * Otherwise, a node with +key+ as tag is created with a string representation of
53
+ # +value+ as text node. If +value+ is +nil+ an attribute "nil" set to "true" is added.
54
+ # Unless the option <tt>:skip_types</tt> exists and is true, an attribute "type" is
55
+ # added as well according to the following mapping:
56
+ #
57
+ # XML_TYPE_NAMES = {
58
+ # "Symbol" => "symbol",
59
+ # "Integer" => "integer",
60
+ # "BigDecimal" => "decimal",
61
+ # "Float" => "float",
62
+ # "TrueClass" => "boolean",
63
+ # "FalseClass" => "boolean",
64
+ # "Date" => "date",
65
+ # "DateTime" => "dateTime",
66
+ # "Time" => "dateTime"
67
+ # }
68
+ #
69
+ # By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
70
+ #
71
+ # The default XML builder is a fresh instance of +Builder::XmlMarkup+. You can
72
+ # configure your own builder with the <tt>:builder</tt> option. The method also accepts
73
+ # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
74
+ def to_xml(options = {})
75
+ require "active_support/builder" unless defined?(Builder::XmlMarkup)
76
+
77
+ options = options.dup
78
+ options[:indent] ||= 2
79
+ options[:root] ||= "hash"
80
+ options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
81
+
82
+ builder = options[:builder]
83
+ builder.instruct! unless options.delete(:skip_instruct)
84
+
85
+ root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
86
+
87
+ builder.tag!(root) do
88
+ each { |key, value| ActiveSupport::XmlMini.to_tag(key, value, options) }
89
+ yield builder if block_given?
90
+ end
91
+ end
92
+
93
+ class << self
94
+ # Returns a Hash containing a collection of pairs when the key is the node name and the value is
95
+ # its content
96
+ #
97
+ # xml = <<-XML
98
+ # <?xml version="1.0" encoding="UTF-8"?>
99
+ # <hash>
100
+ # <foo type="integer">1</foo>
101
+ # <bar type="integer">2</bar>
102
+ # </hash>
103
+ # XML
104
+ #
105
+ # hash = Hash.from_xml(xml)
106
+ # # => {"hash"=>{"foo"=>1, "bar"=>2}}
107
+ #
108
+ # +DisallowedType+ is raised if the XML contains attributes with <tt>type="yaml"</tt> or
109
+ # <tt>type="symbol"</tt>. Use <tt>Hash.from_trusted_xml</tt> to
110
+ # parse this XML.
111
+ #
112
+ # Custom +disallowed_types+ can also be passed in the form of an
113
+ # array.
114
+ #
115
+ # xml = <<-XML
116
+ # <?xml version="1.0" encoding="UTF-8"?>
117
+ # <hash>
118
+ # <foo type="integer">1</foo>
119
+ # <bar type="string">"David"</bar>
120
+ # </hash>
121
+ # XML
122
+ #
123
+ # hash = Hash.from_xml(xml, ['integer'])
124
+ # # => ActiveSupport::XMLConverter::DisallowedType: Disallowed type attribute: "integer"
125
+ #
126
+ # Note that passing custom disallowed types will override the default types,
127
+ # which are Symbol and YAML.
128
+ def from_xml(xml, disallowed_types = nil)
129
+ ActiveSupport::XMLConverter.new(xml, disallowed_types).to_h
130
+ end
131
+
132
+ # Builds a Hash from XML just like <tt>Hash.from_xml</tt>, but also allows Symbol and YAML.
133
+ def from_trusted_xml(xml)
134
+ from_xml xml, []
135
+ end
136
+ end
137
+ end
138
+
139
+ module ActiveSupport
140
+ class XMLConverter # :nodoc:
141
+ # Raised if the XML contains attributes with type="yaml" or
142
+ # type="symbol". Read Hash#from_xml for more details.
143
+ class DisallowedType < StandardError
144
+ def initialize(type)
145
+ super "Disallowed type attribute: #{type.inspect}"
146
+ end
147
+ end
148
+
149
+ DISALLOWED_TYPES = %w(symbol yaml)
150
+
151
+ def initialize(xml, disallowed_types = nil)
152
+ @xml = normalize_keys(XmlMini.parse(xml))
153
+ @disallowed_types = disallowed_types || DISALLOWED_TYPES
154
+ end
155
+
156
+ def to_h
157
+ deep_to_h(@xml)
158
+ end
159
+
160
+ private
161
+ def normalize_keys(params)
162
+ case params
163
+ when Hash
164
+ Hash[params.map { |k, v| [k.to_s.tr("-", "_"), normalize_keys(v)] } ]
165
+ when Array
166
+ params.map { |v| normalize_keys(v) }
167
+ else
168
+ params
169
+ end
170
+ end
171
+
172
+ def deep_to_h(value)
173
+ case value
174
+ when Hash
175
+ process_hash(value)
176
+ when Array
177
+ process_array(value)
178
+ when String
179
+ value
180
+ else
181
+ raise "can't typecast #{value.class.name} - #{value.inspect}"
182
+ end
183
+ end
184
+
185
+ def process_hash(value)
186
+ if value.include?("type") && !value["type"].is_a?(Hash) && @disallowed_types.include?(value["type"])
187
+ raise DisallowedType, value["type"]
188
+ end
189
+
190
+ if become_array?(value)
191
+ _, entries = Array.wrap(value.detect { |k, v| not v.is_a?(String) })
192
+ if entries.nil? || value["__content__"].try(:empty?)
193
+ []
194
+ else
195
+ case entries
196
+ when Array
197
+ entries.collect { |v| deep_to_h(v) }
198
+ when Hash
199
+ [deep_to_h(entries)]
200
+ else
201
+ raise "can't typecast #{entries.inspect}"
202
+ end
203
+ end
204
+ elsif become_content?(value)
205
+ process_content(value)
206
+
207
+ elsif become_empty_string?(value)
208
+ ""
209
+ elsif become_hash?(value)
210
+ xml_value = value.transform_values { |v| deep_to_h(v) }
211
+
212
+ # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
213
+ # how multipart uploaded files from HTML appear
214
+ xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
215
+ end
216
+ end
217
+
218
+ def become_content?(value)
219
+ value["type"] == "file" || (value["__content__"] && (value.keys.size == 1 || value["__content__"].present?))
220
+ end
221
+
222
+ def become_array?(value)
223
+ value["type"] == "array"
224
+ end
225
+
226
+ def become_empty_string?(value)
227
+ # { "string" => true }
228
+ # No tests fail when the second term is removed.
229
+ value["type"] == "string" && value["nil"] != "true"
230
+ end
231
+
232
+ def become_hash?(value)
233
+ !nothing?(value) && !garbage?(value)
234
+ end
235
+
236
+ def nothing?(value)
237
+ # blank or nil parsed values are represented by nil
238
+ value.blank? || value["nil"] == "true"
239
+ end
240
+
241
+ def garbage?(value)
242
+ # If the type is the only element which makes it then
243
+ # this still makes the value nil, except if type is
244
+ # an XML node(where type['value'] is a Hash)
245
+ value["type"] && !value["type"].is_a?(::Hash) && value.size == 1
246
+ end
247
+
248
+ def process_content(value)
249
+ content = value["__content__"]
250
+ if parser = ActiveSupport::XmlMini::PARSING[value["type"]]
251
+ parser.arity == 1 ? parser.call(content) : parser.call(content, value)
252
+ else
253
+ content
254
+ end
255
+ end
256
+
257
+ def process_array(value)
258
+ value.map! { |i| deep_to_h(i) }
259
+ value.length > 1 ? value : value.first
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/deep_mergeable"
4
+
5
+ class Hash
6
+ include ActiveSupport::DeepMergeable
7
+
8
+ ##
9
+ # :method: deep_merge
10
+ # :call-seq: deep_merge(other_hash, &block)
11
+ #
12
+ # Returns a new hash with +self+ and +other_hash+ merged recursively.
13
+ #
14
+ # h1 = { a: true, b: { c: [1, 2, 3] } }
15
+ # h2 = { a: false, b: { x: [3, 4, 5] } }
16
+ #
17
+ # h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
18
+ #
19
+ # Like with Hash#merge in the standard library, a block can be provided
20
+ # to merge values:
21
+ #
22
+ # h1 = { a: 100, b: 200, c: { c1: 100 } }
23
+ # h2 = { b: 250, c: { c1: 200 } }
24
+ # h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
25
+ # # => { a: 100, b: 450, c: { c1: 300 } }
26
+ #
27
+ #--
28
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge.
29
+
30
+ ##
31
+ # :method: deep_merge!
32
+ # :call-seq: deep_merge!(other_hash, &block)
33
+ #
34
+ # Same as #deep_merge, but modifies +self+.
35
+ #
36
+ #--
37
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge!.
38
+
39
+ def deep_merge?(other) # :nodoc:
40
+ other.is_a?(Hash)
41
+ end
42
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Returns a new hash with all values converted by the block operation.
5
+ # This includes the values from the root hash and from all
6
+ # nested hashes and arrays.
7
+ #
8
+ # hash = { person: { name: 'Rob', age: '28' } }
9
+ #
10
+ # hash.deep_transform_values{ |value| value.to_s.upcase }
11
+ # # => {person: {name: "ROB", age: "28"}}
12
+ def deep_transform_values(&block)
13
+ _deep_transform_values_in_object(self, &block)
14
+ end
15
+
16
+ # Destructively converts all values by using the block operation.
17
+ # This includes the values from the root hash and from all
18
+ # nested hashes and arrays.
19
+ def deep_transform_values!(&block)
20
+ _deep_transform_values_in_object!(self, &block)
21
+ end
22
+
23
+ private
24
+ # Support methods for deep transforming nested hashes and arrays.
25
+ def _deep_transform_values_in_object(object, &block)
26
+ case object
27
+ when Hash
28
+ object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
29
+ when Array
30
+ object.map { |e| _deep_transform_values_in_object(e, &block) }
31
+ else
32
+ yield(object)
33
+ end
34
+ end
35
+
36
+ def _deep_transform_values_in_object!(object, &block)
37
+ case object
38
+ when Hash
39
+ object.transform_values! { |value| _deep_transform_values_in_object!(value, &block) }
40
+ when Array
41
+ object.map! { |e| _deep_transform_values_in_object!(e, &block) }
42
+ else
43
+ yield(object)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Removes the given keys from hash and returns it.
5
+ # hash = { a: true, b: false, c: nil }
6
+ # hash.except!(:c) # => { a: true, b: false }
7
+ # hash # => { a: true, b: false }
8
+ def except!(*keys)
9
+ keys.each { |key| delete(key) }
10
+ self
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/hash_with_indifferent_access"
4
+
5
+ class Hash
6
+ # Returns an ActiveSupport::HashWithIndifferentAccess out of its receiver:
7
+ #
8
+ # { a: 1 }.with_indifferent_access['a'] # => 1
9
+ def with_indifferent_access
10
+ ActiveSupport::HashWithIndifferentAccess.new(self)
11
+ end
12
+
13
+ # Called when object is nested under an object that receives
14
+ # #with_indifferent_access. This method will be called on the current object
15
+ # by the enclosing object and is aliased to #with_indifferent_access by
16
+ # default. Subclasses of Hash may override this method to return +self+ if
17
+ # converting to an ActiveSupport::HashWithIndifferentAccess would not be
18
+ # desirable.
19
+ #
20
+ # b = { b: 1 }
21
+ # { a: b }.with_indifferent_access['a'] # calls b.nested_under_indifferent_access
22
+ # # => {"b"=>1}
23
+ alias nested_under_indifferent_access with_indifferent_access
24
+ end