activesupport 4.2.11.1 → 6.0.3.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 (263) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +399 -411
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +5 -3
  7. data/lib/active_support/array_inquirer.rb +48 -0
  8. data/lib/active_support/backtrace_cleaner.rb +34 -6
  9. data/lib/active_support/benchmarkable.rb +6 -4
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +58 -53
  12. data/lib/active_support/cache/mem_cache_store.rb +95 -91
  13. data/lib/active_support/cache/memory_store.rb +39 -36
  14. data/lib/active_support/cache/null_store.rb +11 -7
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +75 -42
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +331 -217
  19. data/lib/active_support/callbacks.rb +650 -592
  20. data/lib/active_support/concern.rb +35 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +226 -0
  23. data/lib/active_support/configurable.rb +13 -14
  24. data/lib/active_support/core_ext/array/access.rb +41 -1
  25. data/lib/active_support/core_ext/array/conversions.rb +24 -20
  26. data/lib/active_support/core_ext/array/extract.rb +21 -0
  27. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  28. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  29. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  30. data/lib/active_support/core_ext/array/prepend_and_append.rb +4 -6
  31. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  32. data/lib/active_support/core_ext/array.rb +9 -6
  33. data/lib/active_support/core_ext/benchmark.rb +3 -1
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +45 -31
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +20 -6
  39. data/lib/active_support/core_ext/class.rb +4 -3
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +14 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +17 -14
  43. data/lib/active_support/core_ext/date/conversions.rb +25 -23
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +6 -4
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +154 -65
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -13
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  50. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +37 -19
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
  53. data/lib/active_support/core_ext/date_time/conversions.rb +16 -13
  54. data/lib/active_support/core_ext/date_time.rb +7 -5
  55. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +114 -22
  58. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/compact.rb +4 -23
  61. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  62. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  63. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  64. data/lib/active_support/core_ext/hash/except.rb +12 -9
  65. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  66. data/lib/active_support/core_ext/hash/keys.rb +19 -42
  67. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  68. data/lib/active_support/core_ext/hash/slice.rb +5 -27
  69. data/lib/active_support/core_ext/hash/transform_values.rb +4 -22
  70. data/lib/active_support/core_ext/hash.rb +10 -9
  71. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  72. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  73. data/lib/active_support/core_ext/integer/time.rb +11 -18
  74. data/lib/active_support/core_ext/integer.rb +5 -3
  75. data/lib/active_support/core_ext/kernel/concern.rb +5 -1
  76. data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
  77. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  78. data/lib/active_support/core_ext/kernel.rb +5 -5
  79. data/lib/active_support/core_ext/load_error.rb +3 -22
  80. data/lib/active_support/core_ext/marshal.rb +8 -8
  81. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  82. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  83. data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
  84. data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -46
  85. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  86. data/lib/active_support/core_ext/module/concerning.rb +11 -12
  87. data/lib/active_support/core_ext/module/delegation.rb +133 -30
  88. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  89. data/lib/active_support/core_ext/module/introspection.rb +44 -19
  90. data/lib/active_support/core_ext/module/reachable.rb +5 -7
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  93. data/lib/active_support/core_ext/module.rb +13 -11
  94. data/lib/active_support/core_ext/name_error.rb +22 -2
  95. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +129 -136
  97. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  99. data/lib/active_support/core_ext/numeric.rb +5 -3
  100. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  101. data/lib/active_support/core_ext/object/blank.rb +27 -3
  102. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  103. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  104. data/lib/active_support/core_ext/object/duplicable.rb +13 -93
  105. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  106. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  107. data/lib/active_support/core_ext/object/json.rb +51 -20
  108. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  109. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  110. data/lib/active_support/core_ext/object/try.rb +81 -23
  111. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  112. data/lib/active_support/core_ext/object.rb +14 -13
  113. data/lib/active_support/core_ext/range/compare_range.rb +76 -0
  114. data/lib/active_support/core_ext/range/conversions.rb +37 -15
  115. data/lib/active_support/core_ext/range/each.rb +18 -17
  116. data/lib/active_support/core_ext/range/include_range.rb +7 -21
  117. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  118. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  119. data/lib/active_support/core_ext/range.rb +7 -4
  120. data/lib/active_support/core_ext/regexp.rb +2 -0
  121. data/lib/active_support/core_ext/securerandom.rb +45 -0
  122. data/lib/active_support/core_ext/string/access.rb +16 -6
  123. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  124. data/lib/active_support/core_ext/string/conversions.rb +7 -4
  125. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  126. data/lib/active_support/core_ext/string/filters.rb +48 -6
  127. data/lib/active_support/core_ext/string/indent.rb +6 -4
  128. data/lib/active_support/core_ext/string/inflections.rb +66 -24
  129. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  130. data/lib/active_support/core_ext/string/multibyte.rb +16 -7
  131. data/lib/active_support/core_ext/string/output_safety.rb +93 -40
  132. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  133. data/lib/active_support/core_ext/string/strip.rb +6 -5
  134. data/lib/active_support/core_ext/string/zones.rb +4 -2
  135. data/lib/active_support/core_ext/string.rb +15 -13
  136. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  137. data/lib/active_support/core_ext/time/calculations.rb +115 -52
  138. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  139. data/lib/active_support/core_ext/time/conversions.rb +20 -13
  140. data/lib/active_support/core_ext/time/zones.rb +41 -7
  141. data/lib/active_support/core_ext/time.rb +7 -6
  142. data/lib/active_support/core_ext/uri.rb +6 -7
  143. data/lib/active_support/core_ext.rb +3 -1
  144. data/lib/active_support/current_attributes.rb +203 -0
  145. data/lib/active_support/dependencies/autoload.rb +2 -0
  146. data/lib/active_support/dependencies/interlock.rb +57 -0
  147. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  148. data/lib/active_support/dependencies.rb +208 -166
  149. data/lib/active_support/deprecation/behaviors.rb +44 -11
  150. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  151. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  152. data/lib/active_support/deprecation/method_wrappers.rb +61 -21
  153. data/lib/active_support/deprecation/proxy_wrappers.rb +81 -30
  154. data/lib/active_support/deprecation/reporting.rb +32 -12
  155. data/lib/active_support/deprecation.rb +12 -9
  156. data/lib/active_support/descendants_tracker.rb +57 -9
  157. data/lib/active_support/digest.rb +20 -0
  158. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  159. data/lib/active_support/duration/iso8601_serializer.rb +53 -0
  160. data/lib/active_support/duration.rb +315 -40
  161. data/lib/active_support/encrypted_configuration.rb +45 -0
  162. data/lib/active_support/encrypted_file.rb +100 -0
  163. data/lib/active_support/evented_file_update_checker.rb +234 -0
  164. data/lib/active_support/execution_wrapper.rb +129 -0
  165. data/lib/active_support/executor.rb +8 -0
  166. data/lib/active_support/file_update_checker.rb +62 -37
  167. data/lib/active_support/gem_version.rb +6 -4
  168. data/lib/active_support/gzip.rb +7 -5
  169. data/lib/active_support/hash_with_indifferent_access.rb +129 -30
  170. data/lib/active_support/i18n.rb +9 -6
  171. data/lib/active_support/i18n_railtie.rb +50 -14
  172. data/lib/active_support/inflections.rb +13 -11
  173. data/lib/active_support/inflector/inflections.rb +58 -13
  174. data/lib/active_support/inflector/methods.rb +159 -145
  175. data/lib/active_support/inflector/transliterate.rb +84 -34
  176. data/lib/active_support/inflector.rb +7 -5
  177. data/lib/active_support/json/decoding.rb +32 -30
  178. data/lib/active_support/json/encoding.rb +17 -60
  179. data/lib/active_support/json.rb +4 -2
  180. data/lib/active_support/key_generator.rb +11 -43
  181. data/lib/active_support/lazy_load_hooks.rb +53 -20
  182. data/lib/active_support/locale/en.rb +33 -0
  183. data/lib/active_support/locale/en.yml +2 -0
  184. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  185. data/lib/active_support/log_subscriber.rb +44 -19
  186. data/lib/active_support/logger.rb +9 -23
  187. data/lib/active_support/logger_silence.rb +32 -14
  188. data/lib/active_support/logger_thread_safe_level.rb +32 -8
  189. data/lib/active_support/message_encryptor.rb +166 -53
  190. data/lib/active_support/message_verifier.rb +149 -16
  191. data/lib/active_support/messages/metadata.rb +72 -0
  192. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  193. data/lib/active_support/messages/rotator.rb +56 -0
  194. data/lib/active_support/multibyte/chars.rb +56 -63
  195. data/lib/active_support/multibyte/unicode.rb +56 -290
  196. data/lib/active_support/multibyte.rb +4 -2
  197. data/lib/active_support/notifications/fanout.rb +109 -22
  198. data/lib/active_support/notifications/instrumenter.rb +107 -16
  199. data/lib/active_support/notifications.rb +51 -10
  200. data/lib/active_support/number_helper/number_converter.rb +16 -15
  201. data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -15
  202. data/lib/active_support/number_helper/number_to_delimited_converter.rb +11 -4
  203. data/lib/active_support/number_helper/number_to_human_converter.rb +13 -10
  204. data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -9
  205. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  206. data/lib/active_support/number_helper/number_to_phone_converter.rb +15 -5
  207. data/lib/active_support/number_helper/number_to_rounded_converter.rb +25 -57
  208. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  209. data/lib/active_support/number_helper.rb +105 -68
  210. data/lib/active_support/option_merger.rb +24 -4
  211. data/lib/active_support/ordered_hash.rb +7 -5
  212. data/lib/active_support/ordered_options.rb +27 -5
  213. data/lib/active_support/parameter_filter.rb +128 -0
  214. data/lib/active_support/per_thread_registry.rb +9 -4
  215. data/lib/active_support/proxy_object.rb +2 -0
  216. data/lib/active_support/rails.rb +10 -8
  217. data/lib/active_support/railtie.rb +43 -9
  218. data/lib/active_support/reloader.rb +130 -0
  219. data/lib/active_support/rescuable.rb +108 -53
  220. data/lib/active_support/security_utils.rb +15 -11
  221. data/lib/active_support/string_inquirer.rb +11 -4
  222. data/lib/active_support/subscriber.rb +74 -30
  223. data/lib/active_support/tagged_logging.rb +25 -13
  224. data/lib/active_support/test_case.rb +107 -44
  225. data/lib/active_support/testing/assertions.rb +151 -20
  226. data/lib/active_support/testing/autorun.rb +4 -2
  227. data/lib/active_support/testing/constant_lookup.rb +2 -1
  228. data/lib/active_support/testing/declarative.rb +3 -1
  229. data/lib/active_support/testing/deprecation.rb +13 -10
  230. data/lib/active_support/testing/file_fixtures.rb +38 -0
  231. data/lib/active_support/testing/isolation.rb +35 -26
  232. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  233. data/lib/active_support/testing/parallelization.rb +134 -0
  234. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  235. data/lib/active_support/testing/stream.rb +43 -0
  236. data/lib/active_support/testing/tagged_logging.rb +3 -1
  237. data/lib/active_support/testing/time_helpers.rb +84 -20
  238. data/lib/active_support/time.rb +14 -12
  239. data/lib/active_support/time_with_zone.rb +179 -39
  240. data/lib/active_support/values/time_zone.rb +203 -63
  241. data/lib/active_support/version.rb +3 -1
  242. data/lib/active_support/xml_mini/jdom.rb +116 -115
  243. data/lib/active_support/xml_mini/libxml.rb +16 -13
  244. data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
  245. data/lib/active_support/xml_mini/nokogiri.rb +14 -12
  246. data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
  247. data/lib/active_support/xml_mini/rexml.rb +11 -9
  248. data/lib/active_support/xml_mini.rb +38 -46
  249. data/lib/active_support.rb +13 -11
  250. metadata +84 -26
  251. data/lib/active_support/concurrency/latch.rb +0 -27
  252. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  253. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  254. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  255. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  256. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  257. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  258. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  259. data/lib/active_support/core_ext/object/itself.rb +0 -15
  260. data/lib/active_support/core_ext/struct.rb +0 -6
  261. data/lib/active_support/core_ext/thread.rb +0 -86
  262. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  263. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+
5
+ module ActiveSupport
6
+ module Messages #:nodoc:
7
+ class Metadata #:nodoc:
8
+ def initialize(message, expires_at = nil, purpose = nil)
9
+ @message, @purpose = message, purpose
10
+ @expires_at = expires_at.is_a?(String) ? Time.iso8601(expires_at) : expires_at
11
+ end
12
+
13
+ def as_json(options = {})
14
+ { _rails: { message: @message, exp: @expires_at, pur: @purpose } }
15
+ end
16
+
17
+ class << self
18
+ def wrap(message, expires_at: nil, expires_in: nil, purpose: nil)
19
+ if expires_at || expires_in || purpose
20
+ JSON.encode new(encode(message), pick_expiry(expires_at, expires_in), purpose)
21
+ else
22
+ message
23
+ end
24
+ end
25
+
26
+ def verify(message, purpose)
27
+ extract_metadata(message).verify(purpose)
28
+ end
29
+
30
+ private
31
+ def pick_expiry(expires_at, expires_in)
32
+ if expires_at
33
+ expires_at.utc.iso8601(3)
34
+ elsif expires_in
35
+ Time.now.utc.advance(seconds: expires_in).iso8601(3)
36
+ end
37
+ end
38
+
39
+ def extract_metadata(message)
40
+ data = JSON.decode(message) rescue nil
41
+
42
+ if data.is_a?(Hash) && data.key?("_rails")
43
+ new(decode(data["_rails"]["message"]), data["_rails"]["exp"], data["_rails"]["pur"])
44
+ else
45
+ new(message)
46
+ end
47
+ end
48
+
49
+ def encode(message)
50
+ ::Base64.strict_encode64(message)
51
+ end
52
+
53
+ def decode(message)
54
+ ::Base64.strict_decode64(message)
55
+ end
56
+ end
57
+
58
+ def verify(purpose)
59
+ @message if match?(purpose) && fresh?
60
+ end
61
+
62
+ private
63
+ def match?(purpose)
64
+ @purpose.to_s == purpose.to_s
65
+ end
66
+
67
+ def fresh?
68
+ @expires_at.nil? || Time.now.utc < @expires_at
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Messages
5
+ class RotationConfiguration # :nodoc:
6
+ attr_reader :signed, :encrypted
7
+
8
+ def initialize
9
+ @signed, @encrypted = [], []
10
+ end
11
+
12
+ def rotate(kind, *args)
13
+ case kind
14
+ when :signed
15
+ @signed << args
16
+ when :encrypted
17
+ @encrypted << args
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Messages
5
+ module Rotator # :nodoc:
6
+ def initialize(*, **options)
7
+ super
8
+
9
+ @options = options
10
+ @rotations = []
11
+ end
12
+
13
+ def rotate(*secrets, **options)
14
+ @rotations << build_rotation(*secrets, @options.merge(options))
15
+ end
16
+
17
+ module Encryptor
18
+ include Rotator
19
+
20
+ def decrypt_and_verify(*args, on_rotation: nil, **options)
21
+ super
22
+ rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
23
+ run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
24
+ end
25
+
26
+ private
27
+ def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
28
+ self.class.new(secret, sign_secret, **options)
29
+ end
30
+ end
31
+
32
+ module Verifier
33
+ include Rotator
34
+
35
+ def verified(*args, on_rotation: nil, **options)
36
+ super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
37
+ end
38
+
39
+ private
40
+ def build_rotation(secret = @secret, options)
41
+ self.class.new(secret, **options)
42
+ end
43
+ end
44
+
45
+ private
46
+ def run_rotations(on_rotation)
47
+ @rotations.find do |rotation|
48
+ if message = yield(rotation) rescue next
49
+ on_rotation.call if on_rotation
50
+ return message
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,8 +1,9 @@
1
- # encoding: utf-8
2
- require 'active_support/json'
3
- require 'active_support/core_ext/string/access'
4
- require 'active_support/core_ext/string/behavior'
5
- require 'active_support/core_ext/module/delegation'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/json"
4
+ require "active_support/core_ext/string/access"
5
+ require "active_support/core_ext/string/behavior"
6
+ require "active_support/core_ext/module/delegation"
6
7
 
7
8
  module ActiveSupport #:nodoc:
8
9
  module Multibyte #:nodoc:
@@ -16,7 +17,8 @@ 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 # => "the perfect string"
20
+ # 'The Perfect String '.mb_chars.downcase.strip
21
+ # # => #<ActiveSupport::Multibyte::Chars:0x007fdc434ccc10 @wrapped_string="the perfect string">
20
22
  #
21
23
  # Chars objects are perfectly interchangeable with String objects as long as
22
24
  # no explicit class checks are made. If certain methods do explicitly check
@@ -46,7 +48,7 @@ module ActiveSupport #:nodoc:
46
48
  alias to_s wrapped_string
47
49
  alias to_str wrapped_string
48
50
 
49
- delegate :<=>, :=~, :acts_like_string?, :to => :wrapped_string
51
+ delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string
50
52
 
51
53
  # Creates a new Chars instance by wrapping _string_.
52
54
  def initialize(string)
@@ -57,7 +59,7 @@ module ActiveSupport #:nodoc:
57
59
  # Forward all undefined methods to the wrapped string.
58
60
  def method_missing(method, *args, &block)
59
61
  result = @wrapped_string.__send__(method, *args, &block)
60
- if method.to_s =~ /!$/
62
+ if /!$/.match?(method)
61
63
  self if result
62
64
  else
63
65
  result.kind_of?(String) ? chars(result) : result
@@ -74,6 +76,11 @@ module ActiveSupport #:nodoc:
74
76
  # Returns +true+ when the proxy class can handle the string. Returns
75
77
  # +false+ otherwise.
76
78
  def self.consumes?(string)
79
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
80
+ ActiveSupport::Multibyte::Chars.consumes? is deprecated and will be
81
+ removed from Rails 6.1. Use string.is_utf8? instead.
82
+ MSG
83
+
77
84
  string.encoding == Encoding::UTF_8
78
85
  end
79
86
 
@@ -87,16 +94,26 @@ module ActiveSupport #:nodoc:
87
94
  end
88
95
 
89
96
  # Works like <tt>String#slice!</tt>, but returns an instance of
90
- # Chars, or nil if the string was not modified.
97
+ # Chars, or +nil+ if the string was not modified. The string will not be
98
+ # modified if the range given is out of bounds
99
+ #
100
+ # string = 'Welcome'
101
+ # string.mb_chars.slice!(3) # => #<ActiveSupport::Multibyte::Chars:0x000000038109b8 @wrapped_string="c">
102
+ # string # => 'Welome'
103
+ # string.mb_chars.slice!(0..3) # => #<ActiveSupport::Multibyte::Chars:0x00000002eb80a0 @wrapped_string="Welo">
104
+ # string # => 'me'
91
105
  def slice!(*args)
92
- chars(@wrapped_string.slice!(*args))
106
+ string_sliced = @wrapped_string.slice!(*args)
107
+ if string_sliced
108
+ chars(string_sliced)
109
+ end
93
110
  end
94
111
 
95
112
  # Reverses all characters in the string.
96
113
  #
97
114
  # 'Café'.mb_chars.reverse.to_s # => 'éfaC'
98
115
  def reverse
99
- chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack('U*'))
116
+ chars(@wrapped_string.scan(/\X/).reverse.join)
100
117
  end
101
118
 
102
119
  # Limits the byte size of the string to a number of bytes without breaking
@@ -105,43 +122,15 @@ module ActiveSupport #:nodoc:
105
122
  #
106
123
  # 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
107
124
  def limit(limit)
108
- slice(0...translate_offset(limit))
109
- end
110
-
111
- # Converts characters in the string to uppercase.
112
- #
113
- # 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
114
- def upcase
115
- chars Unicode.upcase(@wrapped_string)
116
- end
117
-
118
- # Converts characters in the string to lowercase.
119
- #
120
- # 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
121
- def downcase
122
- chars Unicode.downcase(@wrapped_string)
123
- end
124
-
125
- # Converts characters in the string to the opposite case.
126
- #
127
- # 'El Cañón".mb_chars.swapcase.to_s # => "eL cAÑÓN"
128
- def swapcase
129
- chars Unicode.swapcase(@wrapped_string)
130
- end
131
-
132
- # Converts the first character to uppercase and the remainder to lowercase.
133
- #
134
- # 'über'.mb_chars.capitalize.to_s # => "Über"
135
- def capitalize
136
- (slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase
125
+ chars(@wrapped_string.truncate_bytes(limit, omission: nil))
137
126
  end
138
127
 
139
128
  # Capitalizes the first letter of every word, when possible.
140
129
  #
141
- # "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
142
- # "日本語".mb_chars.titleize # => "日本語"
130
+ # "ÉL QUE SE ENTERÓ".mb_chars.titleize.to_s # => "Él Que Se Enteró"
131
+ # "日本語".mb_chars.titleize.to_s # => "日本語"
143
132
  def titleize
144
- chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1)})
133
+ chars(downcase.to_s.gsub(/\b('?\S)/u) { $1.upcase })
145
134
  end
146
135
  alias_method :titlecase, :titleize
147
136
 
@@ -153,7 +142,24 @@ module ActiveSupport #:nodoc:
153
142
  # <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
154
143
  # ActiveSupport::Multibyte::Unicode.default_normalization_form
155
144
  def normalize(form = nil)
156
- chars(Unicode.normalize(@wrapped_string, form))
145
+ form ||= Unicode.default_normalization_form
146
+
147
+ # See https://www.unicode.org/reports/tr15, Table 1
148
+ if alias_form = Unicode::NORMALIZATION_FORM_ALIASES[form]
149
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
150
+ ActiveSupport::Multibyte::Chars#normalize is deprecated and will be
151
+ removed from Rails 6.1. Use #unicode_normalize(:#{alias_form}) instead.
152
+ MSG
153
+
154
+ send(:unicode_normalize, alias_form)
155
+ else
156
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
157
+ ActiveSupport::Multibyte::Chars#normalize is deprecated and will be
158
+ removed from Rails 6.1. Use #unicode_normalize instead.
159
+ MSG
160
+
161
+ raise ArgumentError, "#{form} is not a valid normalization variant", caller
162
+ end
157
163
  end
158
164
 
159
165
  # Performs canonical decomposition on all the characters.
@@ -161,7 +167,7 @@ module ActiveSupport #:nodoc:
161
167
  # 'é'.length # => 2
162
168
  # 'é'.mb_chars.decompose.to_s.length # => 3
163
169
  def decompose
164
- chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack('U*'))
170
+ chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack("U*"))
165
171
  end
166
172
 
167
173
  # Performs composition on all the characters.
@@ -169,7 +175,7 @@ module ActiveSupport #:nodoc:
169
175
  # 'é'.length # => 3
170
176
  # 'é'.mb_chars.compose.to_s.length # => 2
171
177
  def compose
172
- chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack('U*'))
178
+ chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack("U*"))
173
179
  end
174
180
 
175
181
  # Returns the number of grapheme clusters in the string.
@@ -177,7 +183,7 @@ module ActiveSupport #:nodoc:
177
183
  # 'क्षि'.mb_chars.length # => 4
178
184
  # 'क्षि'.mb_chars.grapheme_length # => 3
179
185
  def grapheme_length
180
- Unicode.unpack_graphemes(@wrapped_string).length
186
+ @wrapped_string.scan(/\X/).length
181
187
  end
182
188
 
183
189
  # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
@@ -193,28 +199,15 @@ module ActiveSupport #:nodoc:
193
199
  to_s.as_json(options)
194
200
  end
195
201
 
196
- %w(capitalize downcase reverse tidy_bytes upcase).each do |method|
202
+ %w(reverse tidy_bytes).each do |method|
197
203
  define_method("#{method}!") do |*args|
198
204
  @wrapped_string = send(method, *args).to_s
199
205
  self
200
206
  end
201
207
  end
202
208
 
203
- protected
204
-
205
- def translate_offset(byte_offset) #:nodoc:
206
- return nil if byte_offset.nil?
207
- return 0 if @wrapped_string == ''
208
-
209
- begin
210
- @wrapped_string.byteslice(0...byte_offset).unpack('U*').length
211
- rescue ArgumentError
212
- byte_offset -= 1
213
- retry
214
- end
215
- end
216
-
217
- def chars(string) #:nodoc:
209
+ private
210
+ def chars(string)
218
211
  self.class.new(string)
219
212
  end
220
213
  end