activesupport 5.1.7 → 7.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 (279) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +259 -585
  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 +4 -2
  8. data/lib/active_support/backtrace_cleaner.rb +33 -5
  9. data/lib/active_support/benchmarkable.rb +5 -3
  10. data/lib/active_support/builder.rb +2 -0
  11. data/lib/active_support/cache/file_store.rb +50 -43
  12. data/lib/active_support/cache/mem_cache_store.rb +194 -67
  13. data/lib/active_support/cache/memory_store.rb +70 -34
  14. data/lib/active_support/cache/null_store.rb +18 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +474 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +73 -50
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  18. data/lib/active_support/cache.rb +556 -220
  19. data/lib/active_support/callbacks.rb +264 -159
  20. data/lib/active_support/code_generator.rb +65 -0
  21. data/lib/active_support/concern.rb +81 -8
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
  23. data/lib/active_support/concurrency/share_lock.rb +4 -3
  24. data/lib/active_support/configurable.rb +17 -16
  25. data/lib/active_support/configuration_file.rb +51 -0
  26. data/lib/active_support/core_ext/array/access.rb +18 -8
  27. data/lib/active_support/core_ext/array/conversions.rb +20 -17
  28. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +8 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +4 -2
  33. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  34. data/lib/active_support/core_ext/array.rb +4 -1
  35. data/lib/active_support/core_ext/benchmark.rb +4 -2
  36. data/lib/active_support/core_ext/big_decimal/conversions.rb +3 -1
  37. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  38. data/lib/active_support/core_ext/class/attribute.rb +50 -47
  39. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  40. data/lib/active_support/core_ext/class/subclasses.rb +10 -24
  41. data/lib/active_support/core_ext/class.rb +2 -0
  42. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  43. data/lib/active_support/core_ext/date/blank.rb +3 -1
  44. data/lib/active_support/core_ext/date/calculations.rb +17 -14
  45. data/lib/active_support/core_ext/date/conversions.rb +24 -22
  46. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  47. data/lib/active_support/core_ext/date/zones.rb +2 -0
  48. data/lib/active_support/core_ext/date.rb +3 -0
  49. data/lib/active_support/core_ext/date_and_time/calculations.rb +65 -41
  50. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
  51. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +3 -1
  54. data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  56. data/lib/active_support/core_ext/date_time/conversions.rb +15 -14
  57. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  58. data/lib/active_support/core_ext/date_time.rb +3 -0
  59. data/lib/active_support/core_ext/digest/uuid.rb +42 -14
  60. data/lib/active_support/core_ext/digest.rb +3 -0
  61. data/lib/active_support/core_ext/enumerable.rb +244 -72
  62. data/lib/active_support/core_ext/file/atomic.rb +6 -2
  63. data/lib/active_support/core_ext/file.rb +2 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +7 -6
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +4 -2
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
  69. data/lib/active_support/core_ext/hash/keys.rb +4 -31
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  71. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  72. data/lib/active_support/core_ext/hash.rb +3 -2
  73. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  74. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  75. data/lib/active_support/core_ext/integer/time.rb +7 -14
  76. data/lib/active_support/core_ext/integer.rb +2 -0
  77. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  78. data/lib/active_support/core_ext/kernel/reporting.rb +6 -4
  79. data/lib/active_support/core_ext/kernel/singleton_class.rb +3 -1
  80. data/lib/active_support/core_ext/kernel.rb +2 -1
  81. data/lib/active_support/core_ext/load_error.rb +3 -8
  82. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  83. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  84. data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
  85. data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -56
  86. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +36 -27
  87. data/lib/active_support/core_ext/module/concerning.rb +15 -10
  88. data/lib/active_support/core_ext/module/delegation.rb +97 -58
  89. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  90. data/lib/active_support/core_ext/module/introspection.rb +18 -15
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  93. data/lib/active_support/core_ext/module.rb +3 -1
  94. data/lib/active_support/core_ext/name_error.rb +30 -2
  95. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +134 -129
  97. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  99. data/lib/active_support/core_ext/numeric.rb +3 -1
  100. data/lib/active_support/core_ext/object/acts_like.rb +41 -6
  101. data/lib/active_support/core_ext/object/blank.rb +15 -5
  102. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  103. data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
  104. data/lib/active_support/core_ext/object/duplicable.rb +16 -110
  105. data/lib/active_support/core_ext/object/inclusion.rb +2 -0
  106. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  107. data/lib/active_support/core_ext/object/json.rb +51 -26
  108. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  109. data/lib/active_support/core_ext/object/to_query.rb +4 -2
  110. data/lib/active_support/core_ext/object/try.rb +26 -14
  111. data/lib/active_support/core_ext/object/with_options.rb +24 -3
  112. data/lib/active_support/core_ext/object.rb +2 -0
  113. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  114. data/lib/active_support/core_ext/pathname.rb +3 -0
  115. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  116. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  117. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  118. data/lib/active_support/core_ext/range/each.rb +6 -3
  119. data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
  120. data/lib/active_support/core_ext/range/overlaps.rb +3 -1
  121. data/lib/active_support/core_ext/range.rb +4 -1
  122. data/lib/active_support/core_ext/regexp.rb +10 -5
  123. data/lib/active_support/core_ext/securerandom.rb +25 -3
  124. data/lib/active_support/core_ext/string/access.rb +7 -16
  125. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  126. data/lib/active_support/core_ext/string/conversions.rb +5 -2
  127. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  128. data/lib/active_support/core_ext/string/filters.rb +44 -1
  129. data/lib/active_support/core_ext/string/indent.rb +2 -0
  130. data/lib/active_support/core_ext/string/inflections.rb +69 -16
  131. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  132. data/lib/active_support/core_ext/string/multibyte.rb +9 -4
  133. data/lib/active_support/core_ext/string/output_safety.rb +135 -27
  134. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  135. data/lib/active_support/core_ext/string/strip.rb +5 -1
  136. data/lib/active_support/core_ext/string/zones.rb +2 -0
  137. data/lib/active_support/core_ext/string.rb +2 -0
  138. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  139. data/lib/active_support/core_ext/symbol.rb +3 -0
  140. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  141. data/lib/active_support/core_ext/time/calculations.rb +81 -24
  142. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  143. data/lib/active_support/core_ext/time/conversions.rb +17 -12
  144. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  145. data/lib/active_support/core_ext/time/zones.rb +12 -25
  146. data/lib/active_support/core_ext/time.rb +3 -0
  147. data/lib/active_support/core_ext/uri.rb +4 -23
  148. data/lib/active_support/core_ext.rb +4 -1
  149. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  150. data/lib/active_support/current_attributes.rb +226 -0
  151. data/lib/active_support/dependencies/autoload.rb +2 -0
  152. data/lib/active_support/dependencies/interlock.rb +12 -18
  153. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  154. data/lib/active_support/dependencies.rb +59 -715
  155. data/lib/active_support/deprecation/behaviors.rb +48 -13
  156. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  157. data/lib/active_support/deprecation/disallowed.rb +56 -0
  158. data/lib/active_support/deprecation/instance_delegator.rb +2 -1
  159. data/lib/active_support/deprecation/method_wrappers.rb +29 -21
  160. data/lib/active_support/deprecation/proxy_wrappers.rb +34 -8
  161. data/lib/active_support/deprecation/reporting.rb +54 -9
  162. data/lib/active_support/deprecation.rb +10 -3
  163. data/lib/active_support/descendants_tracker.rb +192 -34
  164. data/lib/active_support/digest.rb +22 -0
  165. data/lib/active_support/duration/iso8601_parser.rb +9 -9
  166. data/lib/active_support/duration/iso8601_serializer.rb +29 -15
  167. data/lib/active_support/duration.rb +158 -72
  168. data/lib/active_support/encrypted_configuration.rb +56 -0
  169. data/lib/active_support/encrypted_file.rb +129 -0
  170. data/lib/active_support/environment_inquirer.rb +20 -0
  171. data/lib/active_support/error_reporter.rb +117 -0
  172. data/lib/active_support/evented_file_update_checker.rb +87 -122
  173. data/lib/active_support/execution_context/test_helper.rb +13 -0
  174. data/lib/active_support/execution_context.rb +53 -0
  175. data/lib/active_support/execution_wrapper.rb +46 -21
  176. data/lib/active_support/executor/test_helper.rb +7 -0
  177. data/lib/active_support/executor.rb +2 -0
  178. data/lib/active_support/file_update_checker.rb +2 -1
  179. data/lib/active_support/fork_tracker.rb +71 -0
  180. data/lib/active_support/gem_version.rb +7 -5
  181. data/lib/active_support/gzip.rb +2 -0
  182. data/lib/active_support/hash_with_indifferent_access.rb +126 -42
  183. data/lib/active_support/html_safe_translation.rb +43 -0
  184. data/lib/active_support/i18n.rb +5 -1
  185. data/lib/active_support/i18n_railtie.rb +19 -14
  186. data/lib/active_support/inflections.rb +2 -0
  187. data/lib/active_support/inflector/inflections.rb +41 -14
  188. data/lib/active_support/inflector/methods.rb +73 -87
  189. data/lib/active_support/inflector/transliterate.rb +56 -18
  190. data/lib/active_support/inflector.rb +2 -0
  191. data/lib/active_support/isolated_execution_state.rb +72 -0
  192. data/lib/active_support/json/decoding.rb +27 -26
  193. data/lib/active_support/json/encoding.rb +16 -6
  194. data/lib/active_support/json.rb +2 -0
  195. data/lib/active_support/key_generator.rb +25 -38
  196. data/lib/active_support/lazy_load_hooks.rb +35 -6
  197. data/lib/active_support/locale/en.rb +33 -0
  198. data/lib/active_support/locale/en.yml +8 -4
  199. data/lib/active_support/log_subscriber/test_helper.rb +4 -2
  200. data/lib/active_support/log_subscriber.rb +54 -13
  201. data/lib/active_support/logger.rb +4 -17
  202. data/lib/active_support/logger_silence.rb +13 -20
  203. data/lib/active_support/logger_thread_safe_level.rb +48 -10
  204. data/lib/active_support/message_encryptor.rb +111 -37
  205. data/lib/active_support/message_verifier.rb +124 -21
  206. data/lib/active_support/messages/metadata.rb +80 -0
  207. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  208. data/lib/active_support/messages/rotator.rb +57 -0
  209. data/lib/active_support/multibyte/chars.rb +19 -76
  210. data/lib/active_support/multibyte/unicode.rb +9 -331
  211. data/lib/active_support/multibyte.rb +3 -1
  212. data/lib/active_support/notifications/fanout.rb +165 -37
  213. data/lib/active_support/notifications/instrumenter.rb +92 -11
  214. data/lib/active_support/notifications.rb +96 -30
  215. data/lib/active_support/number_helper/number_converter.rb +8 -9
  216. data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -12
  217. data/lib/active_support/number_helper/number_to_delimited_converter.rb +6 -3
  218. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
  219. data/lib/active_support/number_helper/number_to_human_size_converter.rb +7 -4
  220. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  221. data/lib/active_support/number_helper/number_to_phone_converter.rb +6 -3
  222. data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
  223. data/lib/active_support/number_helper/rounding_helper.rb +16 -34
  224. data/lib/active_support/number_helper.rb +38 -12
  225. data/lib/active_support/option_merger.rb +19 -6
  226. data/lib/active_support/ordered_hash.rb +4 -2
  227. data/lib/active_support/ordered_options.rb +18 -6
  228. data/lib/active_support/parameter_filter.rb +138 -0
  229. data/lib/active_support/per_thread_registry.rb +8 -1
  230. data/lib/active_support/proxy_object.rb +2 -0
  231. data/lib/active_support/rails.rb +3 -10
  232. data/lib/active_support/railtie.rb +112 -11
  233. data/lib/active_support/reloader.rb +12 -11
  234. data/lib/active_support/rescuable.rb +19 -18
  235. data/lib/active_support/ruby_features.rb +7 -0
  236. data/lib/active_support/secure_compare_rotator.rb +51 -0
  237. data/lib/active_support/security_utils.rb +26 -15
  238. data/lib/active_support/string_inquirer.rb +4 -3
  239. data/lib/active_support/subscriber.rb +81 -42
  240. data/lib/active_support/tagged_logging.rb +45 -9
  241. data/lib/active_support/test_case.rb +86 -2
  242. data/lib/active_support/testing/assertions.rb +89 -21
  243. data/lib/active_support/testing/autorun.rb +2 -0
  244. data/lib/active_support/testing/constant_lookup.rb +2 -0
  245. data/lib/active_support/testing/declarative.rb +2 -0
  246. data/lib/active_support/testing/deprecation.rb +54 -2
  247. data/lib/active_support/testing/file_fixtures.rb +4 -0
  248. data/lib/active_support/testing/isolation.rb +6 -4
  249. data/lib/active_support/testing/method_call_assertions.rb +34 -5
  250. data/lib/active_support/testing/parallelization/server.rb +82 -0
  251. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  252. data/lib/active_support/testing/parallelization.rb +55 -0
  253. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  254. data/lib/active_support/testing/setup_and_teardown.rb +12 -7
  255. data/lib/active_support/testing/stream.rb +6 -7
  256. data/lib/active_support/testing/tagged_logging.rb +3 -1
  257. data/lib/active_support/testing/time_helpers.rb +91 -15
  258. data/lib/active_support/time.rb +2 -0
  259. data/lib/active_support/time_with_zone.rb +168 -56
  260. data/lib/active_support/values/time_zone.rb +85 -37
  261. data/lib/active_support/version.rb +3 -1
  262. data/lib/active_support/xml_mini/jdom.rb +6 -5
  263. data/lib/active_support/xml_mini/libxml.rb +9 -7
  264. data/lib/active_support/xml_mini/libxmlsax.rb +7 -5
  265. data/lib/active_support/xml_mini/nokogiri.rb +8 -6
  266. data/lib/active_support/xml_mini/nokogirisax.rb +6 -4
  267. data/lib/active_support/xml_mini/rexml.rb +13 -4
  268. data/lib/active_support/xml_mini.rb +10 -15
  269. data/lib/active_support.rb +30 -9
  270. metadata +76 -35
  271. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  272. data/lib/active_support/core_ext/hash/compact.rb +0 -27
  273. data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
  274. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  275. data/lib/active_support/core_ext/marshal.rb +0 -22
  276. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  277. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  278. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  279. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,11 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/json"
2
4
  require "active_support/core_ext/string/access"
3
5
  require "active_support/core_ext/string/behavior"
4
6
  require "active_support/core_ext/module/delegation"
5
- require "active_support/core_ext/regexp"
6
7
 
7
- module ActiveSupport #:nodoc:
8
- module Multibyte #:nodoc:
8
+ module ActiveSupport # :nodoc:
9
+ module Multibyte # :nodoc:
9
10
  # Chars enables you to work transparently with UTF-8 encoding in the Ruby
10
11
  # String class without having extensive knowledge about the encoding. A
11
12
  # Chars object accepts a string upon initialization and proxies String
@@ -16,7 +17,7 @@ module ActiveSupport #:nodoc:
16
17
  # through the +mb_chars+ method. Methods which would normally return a
17
18
  # String object now return a Chars object so methods can be chained.
18
19
  #
19
- # 'The Perfect String '.mb_chars.downcase.strip.normalize
20
+ # 'The Perfect String '.mb_chars.downcase.strip
20
21
  # # => #<ActiveSupport::Multibyte::Chars:0x007fdc434ccc10 @wrapped_string="the perfect string">
21
22
  #
22
23
  # Chars objects are perfectly interchangeable with String objects as long as
@@ -47,7 +48,7 @@ module ActiveSupport #:nodoc:
47
48
  alias to_s wrapped_string
48
49
  alias to_str wrapped_string
49
50
 
50
- delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string
51
+ delegate :<=>, :=~, :match?, :acts_like_string?, to: :wrapped_string
51
52
 
52
53
  # Creates a new Chars instance by wrapping _string_.
53
54
  def initialize(string)
@@ -58,7 +59,7 @@ module ActiveSupport #:nodoc:
58
59
  # Forward all undefined methods to the wrapped string.
59
60
  def method_missing(method, *args, &block)
60
61
  result = @wrapped_string.__send__(method, *args, &block)
61
- if /!$/.match?(method)
62
+ if method.end_with?("!")
62
63
  self if result
63
64
  else
64
65
  result.kind_of?(String) ? chars(result) : result
@@ -72,12 +73,6 @@ module ActiveSupport #:nodoc:
72
73
  @wrapped_string.respond_to?(method, include_private)
73
74
  end
74
75
 
75
- # Returns +true+ when the proxy class can handle the string. Returns
76
- # +false+ otherwise.
77
- def self.consumes?(string)
78
- string.encoding == Encoding::UTF_8
79
- end
80
-
81
76
  # Works just like <tt>String#split</tt>, with the exception that the items
82
77
  # in the resulting list are Chars instances instead of String. This makes
83
78
  # chaining methods easier.
@@ -107,7 +102,7 @@ module ActiveSupport #:nodoc:
107
102
  #
108
103
  # 'Café'.mb_chars.reverse.to_s # => 'éfaC'
109
104
  def reverse
110
- chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack("U*"))
105
+ chars(@wrapped_string.grapheme_clusters.reverse.join)
111
106
  end
112
107
 
113
108
  # Limits the byte size of the string to a number of bytes without breaking
@@ -116,35 +111,7 @@ module ActiveSupport #:nodoc:
116
111
  #
117
112
  # 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
118
113
  def limit(limit)
119
- slice(0...translate_offset(limit))
120
- end
121
-
122
- # Converts characters in the string to uppercase.
123
- #
124
- # 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
125
- def upcase
126
- chars Unicode.upcase(@wrapped_string)
127
- end
128
-
129
- # Converts characters in the string to lowercase.
130
- #
131
- # 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
132
- def downcase
133
- chars Unicode.downcase(@wrapped_string)
134
- end
135
-
136
- # Converts characters in the string to the opposite case.
137
- #
138
- # 'El Cañón'.mb_chars.swapcase.to_s # => "eL cAÑÓN"
139
- def swapcase
140
- chars Unicode.swapcase(@wrapped_string)
141
- end
142
-
143
- # Converts the first character to uppercase and the remainder to lowercase.
144
- #
145
- # 'über'.mb_chars.capitalize.to_s # => "Über"
146
- def capitalize
147
- (slice(0) || chars("")).upcase + (slice(1..-1) || chars("")).downcase
114
+ chars(@wrapped_string.truncate_bytes(limit, omission: nil))
148
115
  end
149
116
 
150
117
  # Capitalizes the first letter of every word, when possible.
@@ -152,33 +119,22 @@ module ActiveSupport #:nodoc:
152
119
  # "ÉL QUE SE ENTERÓ".mb_chars.titleize.to_s # => "Él Que Se Enteró"
153
120
  # "日本語".mb_chars.titleize.to_s # => "日本語"
154
121
  def titleize
155
- chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1) })
122
+ chars(downcase.to_s.gsub(/\b('?\S)/u) { $1.upcase })
156
123
  end
157
124
  alias_method :titlecase, :titleize
158
125
 
159
- # Returns the KC normalization of the string by default. NFKC is
160
- # considered the best normalization form for passing strings to databases
161
- # and validations.
162
- #
163
- # * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
164
- # <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
165
- # ActiveSupport::Multibyte::Unicode.default_normalization_form
166
- def normalize(form = nil)
167
- chars(Unicode.normalize(@wrapped_string, form))
168
- end
169
-
170
126
  # Performs canonical decomposition on all the characters.
171
127
  #
172
- # 'é'.length # => 2
173
- # 'é'.mb_chars.decompose.to_s.length # => 3
128
+ # 'é'.length # => 1
129
+ # 'é'.mb_chars.decompose.to_s.length # => 2
174
130
  def decompose
175
131
  chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack("U*"))
176
132
  end
177
133
 
178
134
  # Performs composition on all the characters.
179
135
  #
180
- # 'é'.length # => 3
181
- # 'é'.mb_chars.compose.to_s.length # => 2
136
+ # 'é'.length # => 1
137
+ # 'é'.mb_chars.compose.to_s.length # => 1
182
138
  def compose
183
139
  chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack("U*"))
184
140
  end
@@ -186,9 +142,9 @@ module ActiveSupport #:nodoc:
186
142
  # Returns the number of grapheme clusters in the string.
187
143
  #
188
144
  # 'क्षि'.mb_chars.length # => 4
189
- # 'क्षि'.mb_chars.grapheme_length # => 3
145
+ # 'क्षि'.mb_chars.grapheme_length # => 2
190
146
  def grapheme_length
191
- Unicode.unpack_graphemes(@wrapped_string).length
147
+ @wrapped_string.grapheme_clusters.length
192
148
  end
193
149
 
194
150
  # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
@@ -200,31 +156,18 @@ module ActiveSupport #:nodoc:
200
156
  chars(Unicode.tidy_bytes(@wrapped_string, force))
201
157
  end
202
158
 
203
- def as_json(options = nil) #:nodoc:
159
+ def as_json(options = nil) # :nodoc:
204
160
  to_s.as_json(options)
205
161
  end
206
162
 
207
- %w(capitalize downcase reverse tidy_bytes upcase).each do |method|
163
+ %w(reverse tidy_bytes).each do |method|
208
164
  define_method("#{method}!") do |*args|
209
- @wrapped_string = send(method, *args).to_s
165
+ @wrapped_string = public_send(method, *args).to_s
210
166
  self
211
167
  end
212
168
  end
213
169
 
214
170
  private
215
-
216
- def translate_offset(byte_offset)
217
- return nil if byte_offset.nil?
218
- return 0 if @wrapped_string == ""
219
-
220
- begin
221
- @wrapped_string.byteslice(0...byte_offset).unpack("U*").length
222
- rescue ArgumentError
223
- byte_offset -= 1
224
- retry
225
- end
226
- end
227
-
228
171
  def chars(string)
229
172
  self.class.new(string)
230
173
  end
@@ -1,217 +1,25 @@
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]
59
-
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
112
- end
113
-
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
135
- end
9
+ UNICODE_VERSION = RbConfig::CONFIG["UNICODE_VERSION"]
136
10
 
137
11
  # Decompose composed characters to the decomposed form.
138
12
  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
13
+ if type == :compatibility
14
+ codepoints.pack("U*").unicode_normalize(:nfkd).codepoints
15
+ else
16
+ codepoints.pack("U*").unicode_normalize(:nfd).codepoints
155
17
  end
156
18
  end
157
19
 
158
20
  # Compose decomposed characters to the composed form.
159
21
  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
22
+ codepoints.pack("U*").unicode_normalize(:nfc).codepoints
215
23
  end
216
24
 
217
25
  # Rubinius' String#scrub, however, doesn't support ASCII-incompatible chars.
@@ -222,7 +30,7 @@ module ActiveSupport
222
30
  # Passing +true+ will forcibly tidy all bytes, assuming that the string's
223
31
  # encoding is entirely CP1252 or ISO-8859-1.
224
32
  def tidy_bytes(string, force = false)
225
- return string if string.empty?
33
+ return string if string.empty? || string.ascii_only?
226
34
  return recode_windows1252_chars(string) if force
227
35
  string.scrub { |bad| recode_windows1252_chars(bad) }
228
36
  end
@@ -253,140 +61,10 @@ module ActiveSupport
253
61
  end
254
62
  end
255
63
 
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
64
  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
65
  def recode_windows1252_chars(string)
384
66
  string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
385
67
  end
386
-
387
- def database
388
- @database ||= UnicodeDatabase.new
389
- end
390
68
  end
391
69
  end
392
70
  end
@@ -1,4 +1,6 @@
1
- module ActiveSupport #:nodoc:
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport # :nodoc:
2
4
  module Multibyte
3
5
  autoload :Chars, "active_support/multibyte/chars"
4
6
  autoload :Unicode, "active_support/multibyte/unicode"