activesupport 5.2.5 → 6.0.4.1

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