activesupport 5.1.7 → 6.1.7

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 (262) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +434 -490
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -5
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +2 -0
  7. data/lib/active_support/array_inquirer.rb +6 -2
  8. data/lib/active_support/backtrace_cleaner.rb +31 -3
  9. data/lib/active_support/benchmarkable.rb +3 -1
  10. data/lib/active_support/builder.rb +2 -0
  11. data/lib/active_support/cache/file_store.rb +37 -36
  12. data/lib/active_support/cache/mem_cache_store.rb +72 -56
  13. data/lib/active_support/cache/memory_store.rb +61 -33
  14. data/lib/active_support/cache/null_store.rb +10 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +67 -21
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  18. data/lib/active_support/cache.rb +310 -126
  19. data/lib/active_support/callbacks.rb +106 -100
  20. data/lib/active_support/concern.rb +79 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  22. data/lib/active_support/concurrency/share_lock.rb +2 -1
  23. data/lib/active_support/configurable.rb +12 -14
  24. data/lib/active_support/configuration_file.rb +51 -0
  25. data/lib/active_support/core_ext/array/access.rb +21 -7
  26. data/lib/active_support/core_ext/array/conversions.rb +7 -5
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +2 -0
  30. data/lib/active_support/core_ext/array/inquiry.rb +2 -0
  31. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  32. data/lib/active_support/core_ext/array.rb +3 -1
  33. data/lib/active_support/core_ext/benchmark.rb +4 -2
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +2 -0
  35. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  36. data/lib/active_support/core_ext/class/attribute.rb +50 -47
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -40
  39. data/lib/active_support/core_ext/class.rb +2 -0
  40. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  41. data/lib/active_support/core_ext/date/blank.rb +2 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +8 -5
  43. data/lib/active_support/core_ext/date/conversions.rb +12 -10
  44. data/lib/active_support/core_ext/date/zones.rb +2 -0
  45. data/lib/active_support/core_ext/date.rb +2 -0
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +61 -37
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  50. data/lib/active_support/core_ext/date_time/blank.rb +2 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  53. data/lib/active_support/core_ext/date_time/conversions.rb +2 -1
  54. data/lib/active_support/core_ext/date_time.rb +2 -0
  55. data/lib/active_support/core_ext/digest/uuid.rb +4 -1
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +174 -71
  58. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  59. data/lib/active_support/core_ext/file.rb +2 -0
  60. data/lib/active_support/core_ext/hash/conversions.rb +7 -5
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  62. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  63. data/lib/active_support/core_ext/hash/except.rb +4 -2
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +2 -0
  65. data/lib/active_support/core_ext/hash/keys.rb +3 -30
  66. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  67. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  68. data/lib/active_support/core_ext/hash.rb +3 -2
  69. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +7 -14
  72. data/lib/active_support/core_ext/integer.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  74. data/lib/active_support/core_ext/kernel/reporting.rb +2 -0
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +2 -1
  77. data/lib/active_support/core_ext/load_error.rb +3 -8
  78. data/lib/active_support/core_ext/marshal.rb +4 -0
  79. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  80. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  81. data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +44 -56
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +18 -18
  84. data/lib/active_support/core_ext/module/concerning.rb +15 -10
  85. data/lib/active_support/core_ext/module/delegation.rb +103 -58
  86. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  87. data/lib/active_support/core_ext/module/introspection.rb +18 -15
  88. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  89. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  90. data/lib/active_support/core_ext/module.rb +3 -1
  91. data/lib/active_support/core_ext/name_error.rb +36 -2
  92. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  93. data/lib/active_support/core_ext/numeric/conversions.rb +131 -129
  94. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  95. data/lib/active_support/core_ext/numeric.rb +2 -1
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +13 -3
  98. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  99. data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
  100. data/lib/active_support/core_ext/object/duplicable.rb +9 -114
  101. data/lib/active_support/core_ext/object/inclusion.rb +2 -0
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +22 -2
  104. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  105. data/lib/active_support/core_ext/object/to_query.rb +2 -0
  106. data/lib/active_support/core_ext/object/try.rb +19 -7
  107. data/lib/active_support/core_ext/object/with_options.rb +4 -2
  108. data/lib/active_support/core_ext/object.rb +2 -0
  109. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  110. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  111. data/lib/active_support/core_ext/range/each.rb +5 -2
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +4 -1
  115. data/lib/active_support/core_ext/regexp.rb +10 -5
  116. data/lib/active_support/core_ext/securerandom.rb +25 -3
  117. data/lib/active_support/core_ext/string/access.rb +7 -16
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +3 -0
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +44 -1
  122. data/lib/active_support/core_ext/string/indent.rb +2 -0
  123. data/lib/active_support/core_ext/string/inflections.rb +69 -16
  124. data/lib/active_support/core_ext/string/inquiry.rb +3 -0
  125. data/lib/active_support/core_ext/string/multibyte.rb +9 -4
  126. data/lib/active_support/core_ext/string/output_safety.rb +104 -20
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  128. data/lib/active_support/core_ext/string/strip.rb +5 -1
  129. data/lib/active_support/core_ext/string/zones.rb +2 -0
  130. data/lib/active_support/core_ext/string.rb +2 -0
  131. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  132. data/lib/active_support/core_ext/symbol.rb +3 -0
  133. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  134. data/lib/active_support/core_ext/time/calculations.rb +76 -18
  135. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +4 -0
  137. data/lib/active_support/core_ext/time/zones.rb +6 -4
  138. data/lib/active_support/core_ext/time.rb +2 -0
  139. data/lib/active_support/core_ext/uri.rb +11 -6
  140. data/lib/active_support/core_ext.rb +3 -1
  141. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  142. data/lib/active_support/current_attributes.rb +210 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +2 -0
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +120 -0
  146. data/lib/active_support/dependencies.rb +134 -60
  147. data/lib/active_support/deprecation/behaviors.rb +43 -11
  148. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +2 -1
  151. data/lib/active_support/deprecation/method_wrappers.rb +29 -21
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +32 -6
  153. data/lib/active_support/deprecation/reporting.rb +54 -9
  154. data/lib/active_support/deprecation.rb +9 -2
  155. data/lib/active_support/descendants_tracker.rb +61 -9
  156. data/lib/active_support/digest.rb +22 -0
  157. data/lib/active_support/duration/iso8601_parser.rb +6 -6
  158. data/lib/active_support/duration/iso8601_serializer.rb +20 -14
  159. data/lib/active_support/duration.rb +102 -45
  160. data/lib/active_support/encrypted_configuration.rb +45 -0
  161. data/lib/active_support/encrypted_file.rb +117 -0
  162. data/lib/active_support/environment_inquirer.rb +20 -0
  163. data/lib/active_support/evented_file_update_checker.rb +84 -117
  164. data/lib/active_support/execution_wrapper.rb +19 -13
  165. data/lib/active_support/executor.rb +2 -0
  166. data/lib/active_support/file_update_checker.rb +2 -1
  167. data/lib/active_support/fork_tracker.rb +64 -0
  168. data/lib/active_support/gem_version.rb +3 -1
  169. data/lib/active_support/gzip.rb +2 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +123 -41
  171. data/lib/active_support/i18n.rb +4 -1
  172. data/lib/active_support/i18n_railtie.rb +19 -14
  173. data/lib/active_support/inflections.rb +2 -0
  174. data/lib/active_support/inflector/inflections.rb +19 -8
  175. data/lib/active_support/inflector/methods.rb +87 -77
  176. data/lib/active_support/inflector/transliterate.rb +56 -18
  177. data/lib/active_support/inflector.rb +2 -0
  178. data/lib/active_support/json/decoding.rb +27 -26
  179. data/lib/active_support/json/encoding.rb +13 -3
  180. data/lib/active_support/json.rb +2 -0
  181. data/lib/active_support/key_generator.rb +3 -33
  182. data/lib/active_support/lazy_load_hooks.rb +7 -2
  183. data/lib/active_support/locale/en.rb +33 -0
  184. data/lib/active_support/locale/en.yml +7 -3
  185. data/lib/active_support/log_subscriber/test_helper.rb +2 -0
  186. data/lib/active_support/log_subscriber.rb +42 -11
  187. data/lib/active_support/logger.rb +4 -17
  188. data/lib/active_support/logger_silence.rb +13 -20
  189. data/lib/active_support/logger_thread_safe_level.rb +54 -7
  190. data/lib/active_support/message_encryptor.rb +100 -32
  191. data/lib/active_support/message_verifier.rb +85 -14
  192. data/lib/active_support/messages/metadata.rb +80 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  194. data/lib/active_support/messages/rotator.rb +57 -0
  195. data/lib/active_support/multibyte/chars.rb +12 -68
  196. data/lib/active_support/multibyte/unicode.rb +17 -327
  197. data/lib/active_support/multibyte.rb +2 -0
  198. data/lib/active_support/notifications/fanout.rb +118 -16
  199. data/lib/active_support/notifications/instrumenter.rb +73 -9
  200. data/lib/active_support/notifications.rb +74 -8
  201. data/lib/active_support/number_helper/number_converter.rb +7 -6
  202. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
  203. data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -2
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -3
  206. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  207. data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -2
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
  209. data/lib/active_support/number_helper/rounding_helper.rb +16 -30
  210. data/lib/active_support/number_helper.rb +40 -12
  211. data/lib/active_support/option_merger.rb +24 -3
  212. data/lib/active_support/ordered_hash.rb +3 -1
  213. data/lib/active_support/ordered_options.rb +17 -5
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +4 -1
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +3 -10
  218. data/lib/active_support/railtie.rb +60 -9
  219. data/lib/active_support/reloader.rb +12 -11
  220. data/lib/active_support/rescuable.rb +7 -6
  221. data/lib/active_support/secure_compare_rotator.rb +51 -0
  222. data/lib/active_support/security_utils.rb +26 -15
  223. data/lib/active_support/string_inquirer.rb +6 -3
  224. data/lib/active_support/subscriber.rb +74 -24
  225. data/lib/active_support/tagged_logging.rb +44 -8
  226. data/lib/active_support/test_case.rb +94 -2
  227. data/lib/active_support/testing/assertions.rb +58 -20
  228. data/lib/active_support/testing/autorun.rb +2 -0
  229. data/lib/active_support/testing/constant_lookup.rb +2 -0
  230. data/lib/active_support/testing/declarative.rb +2 -0
  231. data/lib/active_support/testing/deprecation.rb +2 -1
  232. data/lib/active_support/testing/file_fixtures.rb +4 -0
  233. data/lib/active_support/testing/isolation.rb +4 -2
  234. data/lib/active_support/testing/method_call_assertions.rb +30 -1
  235. data/lib/active_support/testing/parallelization/server.rb +78 -0
  236. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  237. data/lib/active_support/testing/parallelization.rb +51 -0
  238. data/lib/active_support/testing/setup_and_teardown.rb +12 -7
  239. data/lib/active_support/testing/stream.rb +3 -2
  240. data/lib/active_support/testing/tagged_logging.rb +2 -0
  241. data/lib/active_support/testing/time_helpers.rb +78 -13
  242. data/lib/active_support/time.rb +2 -0
  243. data/lib/active_support/time_with_zone.rb +113 -41
  244. data/lib/active_support/values/time_zone.rb +54 -25
  245. data/lib/active_support/version.rb +2 -0
  246. data/lib/active_support/xml_mini/jdom.rb +5 -4
  247. data/lib/active_support/xml_mini/libxml.rb +4 -2
  248. data/lib/active_support/xml_mini/libxmlsax.rb +6 -4
  249. data/lib/active_support/xml_mini/nokogiri.rb +4 -2
  250. data/lib/active_support/xml_mini/nokogirisax.rb +5 -3
  251. data/lib/active_support/xml_mini/rexml.rb +12 -3
  252. data/lib/active_support/xml_mini.rb +5 -11
  253. data/lib/active_support.rb +18 -13
  254. metadata +71 -32
  255. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  256. data/lib/active_support/core_ext/hash/compact.rb +0 -27
  257. data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
  258. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  259. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  260. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  261. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  262. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,217 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  module Multibyte
3
5
  module Unicode
4
6
  extend self
5
7
 
6
- # A list of all available normalization forms.
7
- # See http://www.unicode.org/reports/tr15/tr15-29.html for more
8
- # information about normalization.
9
- NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
10
-
11
8
  # The Unicode version that is supported by the implementation
12
- UNICODE_VERSION = "9.0.0"
13
-
14
- # The default normalization used for operations that require
15
- # normalization. It can be set to any of the normalizations
16
- # in NORMALIZATION_FORMS.
17
- #
18
- # ActiveSupport::Multibyte::Unicode.default_normalization_form = :c
19
- attr_accessor :default_normalization_form
20
- @default_normalization_form = :kc
21
-
22
- # Hangul character boundaries and properties
23
- HANGUL_SBASE = 0xAC00
24
- HANGUL_LBASE = 0x1100
25
- HANGUL_VBASE = 0x1161
26
- HANGUL_TBASE = 0x11A7
27
- HANGUL_LCOUNT = 19
28
- HANGUL_VCOUNT = 21
29
- HANGUL_TCOUNT = 28
30
- HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT
31
- HANGUL_SCOUNT = 11172
32
- HANGUL_SLAST = HANGUL_SBASE + HANGUL_SCOUNT
33
-
34
- # Detect whether the codepoint is in a certain character class. Returns
35
- # +true+ when it's in the specified character class and +false+ otherwise.
36
- # Valid character classes are: <tt>:cr</tt>, <tt>:lf</tt>, <tt>:l</tt>,
37
- # <tt>:v</tt>, <tt>:lv</tt>, <tt>:lvt</tt> and <tt>:t</tt>.
38
- #
39
- # Primarily used by the grapheme cluster support.
40
- def in_char_class?(codepoint, classes)
41
- classes.detect { |c| database.boundary[c] === codepoint } ? true : false
42
- end
43
-
44
- # Unpack the string at grapheme boundaries. Returns a list of character
45
- # lists.
46
- #
47
- # Unicode.unpack_graphemes('क्षि') # => [[2325, 2381], [2359], [2367]]
48
- # Unicode.unpack_graphemes('Café') # => [[67], [97], [102], [233]]
49
- def unpack_graphemes(string)
50
- codepoints = string.codepoints.to_a
51
- unpacked = []
52
- pos = 0
53
- marker = 0
54
- eoc = codepoints.length
55
- while (pos < eoc)
56
- pos += 1
57
- previous = codepoints[pos - 1]
58
- current = codepoints[pos]
9
+ UNICODE_VERSION = RbConfig::CONFIG["UNICODE_VERSION"]
59
10
 
60
- # See http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules
61
- should_break =
62
- if pos == eoc
63
- true
64
- # GB3. CR X LF
65
- elsif previous == database.boundary[:cr] && current == database.boundary[:lf]
66
- false
67
- # GB4. (Control|CR|LF) ÷
68
- elsif previous && in_char_class?(previous, [:control, :cr, :lf])
69
- true
70
- # GB5. ÷ (Control|CR|LF)
71
- elsif in_char_class?(current, [:control, :cr, :lf])
72
- true
73
- # GB6. L X (L|V|LV|LVT)
74
- elsif database.boundary[:l] === previous && in_char_class?(current, [:l, :v, :lv, :lvt])
75
- false
76
- # GB7. (LV|V) X (V|T)
77
- elsif in_char_class?(previous, [:lv, :v]) && in_char_class?(current, [:v, :t])
78
- false
79
- # GB8. (LVT|T) X (T)
80
- elsif in_char_class?(previous, [:lvt, :t]) && database.boundary[:t] === current
81
- false
82
- # GB9. X (Extend | ZWJ)
83
- elsif in_char_class?(current, [:extend, :zwj])
84
- false
85
- # GB9a. X SpacingMark
86
- elsif database.boundary[:spacingmark] === current
87
- false
88
- # GB9b. Prepend X
89
- elsif database.boundary[:prepend] === previous
90
- false
91
- # GB10. (E_Base | EBG) Extend* X E_Modifier
92
- elsif (marker...pos).any? { |i| in_char_class?(codepoints[i], [:e_base, :e_base_gaz]) && codepoints[i + 1...pos].all? { |c| database.boundary[:extend] === c } } && database.boundary[:e_modifier] === current
93
- false
94
- # GB11. ZWJ X (Glue_After_Zwj | EBG)
95
- elsif database.boundary[:zwj] === previous && in_char_class?(current, [:glue_after_zwj, :e_base_gaz])
96
- false
97
- # GB12. ^ (RI RI)* RI X RI
98
- # GB13. [^RI] (RI RI)* RI X RI
99
- elsif codepoints[marker..pos].all? { |c| database.boundary[:regional_indicator] === c } && codepoints[marker..pos].count { |c| database.boundary[:regional_indicator] === c }.even?
100
- false
101
- # GB999. Any ÷ Any
102
- else
103
- true
104
- end
105
-
106
- if should_break
107
- unpacked << codepoints[marker..pos - 1]
108
- marker = pos
109
- end
110
- end
111
- unpacked
11
+ def default_normalization_form
12
+ ActiveSupport::Deprecation.warn(
13
+ "ActiveSupport::Multibyte::Unicode.default_normalization_form is deprecated and will be removed in Rails 7.0."
14
+ )
112
15
  end
113
16
 
114
- # Reverse operation of unpack_graphemes.
115
- #
116
- # Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि'
117
- def pack_graphemes(unpacked)
118
- unpacked.flatten.pack("U*")
119
- end
120
-
121
- # Re-order codepoints so the string becomes canonical.
122
- def reorder_characters(codepoints)
123
- length = codepoints.length - 1
124
- pos = 0
125
- while pos < length do
126
- cp1, cp2 = database.codepoints[codepoints[pos]], database.codepoints[codepoints[pos + 1]]
127
- if (cp1.combining_class > cp2.combining_class) && (cp2.combining_class > 0)
128
- codepoints[pos..pos + 1] = cp2.code, cp1.code
129
- pos += (pos > 0 ? -1 : 1)
130
- else
131
- pos += 1
132
- end
133
- end
134
- codepoints
17
+ def default_normalization_form=(_)
18
+ ActiveSupport::Deprecation.warn(
19
+ "ActiveSupport::Multibyte::Unicode.default_normalization_form= is deprecated and will be removed in Rails 7.0."
20
+ )
135
21
  end
136
22
 
137
23
  # Decompose composed characters to the decomposed form.
138
24
  def decompose(type, codepoints)
139
- codepoints.inject([]) do |decomposed, cp|
140
- # if it's a hangul syllable starter character
141
- if HANGUL_SBASE <= cp && cp < HANGUL_SLAST
142
- sindex = cp - HANGUL_SBASE
143
- ncp = [] # new codepoints
144
- ncp << HANGUL_LBASE + sindex / HANGUL_NCOUNT
145
- ncp << HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT
146
- tindex = sindex % HANGUL_TCOUNT
147
- ncp << (HANGUL_TBASE + tindex) unless tindex == 0
148
- decomposed.concat ncp
149
- # if the codepoint is decomposable in with the current decomposition type
150
- elsif (ncp = database.codepoints[cp].decomp_mapping) && (!database.codepoints[cp].decomp_type || type == :compatibility)
151
- decomposed.concat decompose(type, ncp.dup)
152
- else
153
- decomposed << cp
154
- end
25
+ if type == :compatibility
26
+ codepoints.pack("U*").unicode_normalize(:nfkd).codepoints
27
+ else
28
+ codepoints.pack("U*").unicode_normalize(:nfd).codepoints
155
29
  end
156
30
  end
157
31
 
158
32
  # Compose decomposed characters to the composed form.
159
33
  def compose(codepoints)
160
- pos = 0
161
- eoa = codepoints.length - 1
162
- starter_pos = 0
163
- starter_char = codepoints[0]
164
- previous_combining_class = -1
165
- while pos < eoa
166
- pos += 1
167
- lindex = starter_char - HANGUL_LBASE
168
- # -- Hangul
169
- if 0 <= lindex && lindex < HANGUL_LCOUNT
170
- vindex = codepoints[starter_pos + 1] - HANGUL_VBASE rescue vindex = -1
171
- if 0 <= vindex && vindex < HANGUL_VCOUNT
172
- tindex = codepoints[starter_pos + 2] - HANGUL_TBASE rescue tindex = -1
173
- if 0 <= tindex && tindex < HANGUL_TCOUNT
174
- j = starter_pos + 2
175
- eoa -= 2
176
- else
177
- tindex = 0
178
- j = starter_pos + 1
179
- eoa -= 1
180
- end
181
- codepoints[starter_pos..j] = (lindex * HANGUL_VCOUNT + vindex) * HANGUL_TCOUNT + tindex + HANGUL_SBASE
182
- end
183
- starter_pos += 1
184
- starter_char = codepoints[starter_pos]
185
- # -- Other characters
186
- else
187
- current_char = codepoints[pos]
188
- current = database.codepoints[current_char]
189
- if current.combining_class > previous_combining_class
190
- if ref = database.composition_map[starter_char]
191
- composition = ref[current_char]
192
- else
193
- composition = nil
194
- end
195
- unless composition.nil?
196
- codepoints[starter_pos] = composition
197
- starter_char = composition
198
- codepoints.delete_at pos
199
- eoa -= 1
200
- pos -= 1
201
- previous_combining_class = -1
202
- else
203
- previous_combining_class = current.combining_class
204
- end
205
- else
206
- previous_combining_class = current.combining_class
207
- end
208
- if current.combining_class == 0
209
- starter_pos = pos
210
- starter_char = codepoints[pos]
211
- end
212
- end
213
- end
214
- codepoints
34
+ codepoints.pack("U*").unicode_normalize(:nfc).codepoints
215
35
  end
216
36
 
217
37
  # Rubinius' String#scrub, however, doesn't support ASCII-incompatible chars.
@@ -222,7 +42,7 @@ module ActiveSupport
222
42
  # Passing +true+ will forcibly tidy all bytes, assuming that the string's
223
43
  # encoding is entirely CP1252 or ISO-8859-1.
224
44
  def tidy_bytes(string, force = false)
225
- return string if string.empty?
45
+ return string if string.empty? || string.ascii_only?
226
46
  return recode_windows1252_chars(string) if force
227
47
  string.scrub { |bad| recode_windows1252_chars(bad) }
228
48
  end
@@ -253,140 +73,10 @@ module ActiveSupport
253
73
  end
254
74
  end
255
75
 
256
- # Returns the KC normalization of the string by default. NFKC is
257
- # considered the best normalization form for passing strings to databases
258
- # and validations.
259
- #
260
- # * <tt>string</tt> - The string to perform normalization on.
261
- # * <tt>form</tt> - The form you want to normalize in. Should be one of
262
- # the following: <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>.
263
- # Default is ActiveSupport::Multibyte::Unicode.default_normalization_form.
264
- def normalize(string, form = nil)
265
- form ||= @default_normalization_form
266
- # See http://www.unicode.org/reports/tr15, Table 1
267
- codepoints = string.codepoints.to_a
268
- case form
269
- when :d
270
- reorder_characters(decompose(:canonical, codepoints))
271
- when :c
272
- compose(reorder_characters(decompose(:canonical, codepoints)))
273
- when :kd
274
- reorder_characters(decompose(:compatibility, codepoints))
275
- when :kc
276
- compose(reorder_characters(decompose(:compatibility, codepoints)))
277
- else
278
- raise ArgumentError, "#{form} is not a valid normalization variant", caller
279
- end.pack("U*".freeze)
280
- end
281
-
282
- def downcase(string)
283
- apply_mapping string, :lowercase_mapping
284
- end
285
-
286
- def upcase(string)
287
- apply_mapping string, :uppercase_mapping
288
- end
289
-
290
- def swapcase(string)
291
- apply_mapping string, :swapcase_mapping
292
- end
293
-
294
- # Holds data about a codepoint in the Unicode database.
295
- class Codepoint
296
- attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
297
-
298
- # Initializing Codepoint object with default values
299
- def initialize
300
- @combining_class = 0
301
- @uppercase_mapping = 0
302
- @lowercase_mapping = 0
303
- end
304
-
305
- def swapcase_mapping
306
- uppercase_mapping > 0 ? uppercase_mapping : lowercase_mapping
307
- end
308
- end
309
-
310
- # Holds static data from the Unicode database.
311
- class UnicodeDatabase
312
- ATTRIBUTES = :codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252
313
-
314
- attr_writer(*ATTRIBUTES)
315
-
316
- def initialize
317
- @codepoints = Hash.new(Codepoint.new)
318
- @composition_exclusion = []
319
- @composition_map = {}
320
- @boundary = {}
321
- @cp1252 = {}
322
- end
323
-
324
- # Lazy load the Unicode database so it's only loaded when it's actually used
325
- ATTRIBUTES.each do |attr_name|
326
- class_eval(<<-EOS, __FILE__, __LINE__ + 1)
327
- def #{attr_name} # def codepoints
328
- load # load
329
- @#{attr_name} # @codepoints
330
- end # end
331
- EOS
332
- end
333
-
334
- # Loads the Unicode database and returns all the internal objects of
335
- # UnicodeDatabase.
336
- def load
337
- begin
338
- @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, "rb") { |f| Marshal.load f.read }
339
- rescue => e
340
- raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable")
341
- end
342
-
343
- # Redefine the === method so we can write shorter rules for grapheme cluster breaks
344
- @boundary.each_key do |k|
345
- @boundary[k].instance_eval do
346
- def ===(other)
347
- detect { |i| i === other } ? true : false
348
- end
349
- end if @boundary[k].kind_of?(Array)
350
- end
351
-
352
- # define attr_reader methods for the instance variables
353
- class << self
354
- attr_reader(*ATTRIBUTES)
355
- end
356
- end
357
-
358
- # Returns the directory in which the data files are stored.
359
- def self.dirname
360
- File.dirname(__FILE__) + "/../values/"
361
- end
362
-
363
- # Returns the filename for the data file for this version.
364
- def self.filename
365
- File.expand_path File.join(dirname, "unicode_tables.dat")
366
- end
367
- end
368
-
369
76
  private
370
-
371
- def apply_mapping(string, mapping)
372
- database.codepoints
373
- string.each_codepoint.map do |codepoint|
374
- cp = database.codepoints[codepoint]
375
- if cp && (ncp = cp.send(mapping)) && ncp > 0
376
- ncp
377
- else
378
- codepoint
379
- end
380
- end.pack("U*")
381
- end
382
-
383
77
  def recode_windows1252_chars(string)
384
78
  string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
385
79
  end
386
-
387
- def database
388
- @database ||= UnicodeDatabase.new
389
- end
390
80
  end
391
81
  end
392
82
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport #:nodoc:
2
4
  module Multibyte
3
5
  autoload :Chars, "active_support/multibyte/chars"
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "mutex_m"
2
4
  require "concurrent/map"
5
+ require "set"
6
+ require "active_support/core_ext/object/try"
3
7
 
4
8
  module ActiveSupport
5
9
  module Notifications
@@ -11,16 +15,22 @@ module ActiveSupport
11
15
  include Mutex_m
12
16
 
13
17
  def initialize
14
- @subscribers = []
18
+ @string_subscribers = Hash.new { |h, k| h[k] = [] }
19
+ @other_subscribers = []
15
20
  @listeners_for = Concurrent::Map.new
16
21
  super
17
22
  end
18
23
 
19
- def subscribe(pattern = nil, block = Proc.new)
20
- subscriber = Subscribers.new pattern, block
24
+ def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
25
+ subscriber = Subscribers.new(pattern, callable || block, monotonic)
21
26
  synchronize do
22
- @subscribers << subscriber
23
- @listeners_for.clear
27
+ if String === pattern
28
+ @string_subscribers[pattern] << subscriber
29
+ @listeners_for.delete(pattern)
30
+ else
31
+ @other_subscribers << subscriber
32
+ @listeners_for.clear
33
+ end
24
34
  end
25
35
  subscriber
26
36
  end
@@ -29,12 +39,19 @@ module ActiveSupport
29
39
  synchronize do
30
40
  case subscriber_or_name
31
41
  when String
32
- @subscribers.reject! { |s| s.matches?(subscriber_or_name) }
42
+ @string_subscribers[subscriber_or_name].clear
43
+ @listeners_for.delete(subscriber_or_name)
44
+ @other_subscribers.each { |sub| sub.unsubscribe!(subscriber_or_name) }
33
45
  else
34
- @subscribers.delete(subscriber_or_name)
46
+ pattern = subscriber_or_name.try(:pattern)
47
+ if String === pattern
48
+ @string_subscribers[pattern].delete(subscriber_or_name)
49
+ @listeners_for.delete(pattern)
50
+ else
51
+ @other_subscribers.delete(subscriber_or_name)
52
+ @listeners_for.clear
53
+ end
35
54
  end
36
-
37
- @listeners_for.clear
38
55
  end
39
56
  end
40
57
 
@@ -54,7 +71,8 @@ module ActiveSupport
54
71
  # this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
55
72
  @listeners_for[name] || synchronize do
56
73
  # use synchronisation when accessing @subscribers
57
- @listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
74
+ @listeners_for[name] ||=
75
+ @string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
58
76
  end
59
77
  end
60
78
 
@@ -67,13 +85,26 @@ module ActiveSupport
67
85
  end
68
86
 
69
87
  module Subscribers # :nodoc:
70
- def self.new(pattern, listener)
88
+ def self.new(pattern, listener, monotonic)
89
+ subscriber_class = monotonic ? MonotonicTimed : Timed
90
+
71
91
  if listener.respond_to?(:start) && listener.respond_to?(:finish)
72
- subscriber = Evented.new pattern, listener
92
+ subscriber_class = Evented
73
93
  else
74
- subscriber = Timed.new pattern, listener
94
+ # Doing all this to detect a block like `proc { |x| }` vs
95
+ # `proc { |*x| }` or `proc { |**x| }`
96
+ if listener.respond_to?(:parameters)
97
+ params = listener.parameters
98
+ if params.length == 1 && params.first.first == :opt
99
+ subscriber_class = EventObject
100
+ end
101
+ end
75
102
  end
76
103
 
104
+ wrap_all pattern, subscriber_class.new(pattern, listener)
105
+ end
106
+
107
+ def self.wrap_all(pattern, subscriber)
77
108
  unless pattern
78
109
  AllMessages.new(subscriber)
79
110
  else
@@ -81,9 +112,33 @@ module ActiveSupport
81
112
  end
82
113
  end
83
114
 
115
+ class Matcher #:nodoc:
116
+ attr_reader :pattern, :exclusions
117
+
118
+ def self.wrap(pattern)
119
+ return pattern if String === pattern
120
+ new(pattern)
121
+ end
122
+
123
+ def initialize(pattern)
124
+ @pattern = pattern
125
+ @exclusions = Set.new
126
+ end
127
+
128
+ def unsubscribe!(name)
129
+ exclusions << -name if pattern === name
130
+ end
131
+
132
+ def ===(name)
133
+ pattern === name && !exclusions.include?(name)
134
+ end
135
+ end
136
+
84
137
  class Evented #:nodoc:
138
+ attr_reader :pattern
139
+
85
140
  def initialize(pattern, delegate)
86
- @pattern = pattern
141
+ @pattern = Matcher.wrap(pattern)
87
142
  @delegate = delegate
88
143
  @can_publish = delegate.respond_to?(:publish)
89
144
  end
@@ -103,11 +158,15 @@ module ActiveSupport
103
158
  end
104
159
 
105
160
  def subscribed_to?(name)
106
- @pattern === name
161
+ pattern === name
107
162
  end
108
163
 
109
164
  def matches?(name)
110
- @pattern && @pattern === name
165
+ pattern && pattern === name
166
+ end
167
+
168
+ def unsubscribe!(name)
169
+ pattern.unsubscribe!(name)
111
170
  end
112
171
  end
113
172
 
@@ -128,6 +187,45 @@ module ActiveSupport
128
187
  end
129
188
  end
130
189
 
190
+ class MonotonicTimed < Evented # :nodoc:
191
+ def publish(name, *args)
192
+ @delegate.call name, *args
193
+ end
194
+
195
+ def start(name, id, payload)
196
+ timestack = Thread.current[:_timestack_monotonic] ||= []
197
+ timestack.push Concurrent.monotonic_time
198
+ end
199
+
200
+ def finish(name, id, payload)
201
+ timestack = Thread.current[:_timestack_monotonic]
202
+ started = timestack.pop
203
+ @delegate.call(name, started, Concurrent.monotonic_time, id, payload)
204
+ end
205
+ end
206
+
207
+ class EventObject < Evented
208
+ def start(name, id, payload)
209
+ stack = Thread.current[:_event_stack] ||= []
210
+ event = build_event name, id, payload
211
+ event.start!
212
+ stack.push event
213
+ end
214
+
215
+ def finish(name, id, payload)
216
+ stack = Thread.current[:_event_stack]
217
+ event = stack.pop
218
+ event.payload = payload
219
+ event.finish!
220
+ @delegate.call event
221
+ end
222
+
223
+ private
224
+ def build_event(name, id, payload)
225
+ ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
226
+ end
227
+ end
228
+
131
229
  class AllMessages # :nodoc:
132
230
  def initialize(delegate)
133
231
  @delegate = delegate
@@ -149,6 +247,10 @@ module ActiveSupport
149
247
  true
150
248
  end
151
249
 
250
+ def unsubscribe!(*)
251
+ false
252
+ end
253
+
152
254
  alias :matches? :===
153
255
  end
154
256
  end