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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +399 -411
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -7
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +34 -6
- data/lib/active_support/benchmarkable.rb +6 -4
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +58 -53
- data/lib/active_support/cache/mem_cache_store.rb +95 -91
- data/lib/active_support/cache/memory_store.rb +39 -36
- data/lib/active_support/cache/null_store.rb +11 -7
- data/lib/active_support/cache/redis_cache_store.rb +493 -0
- data/lib/active_support/cache/strategy/local_cache.rb +75 -42
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
- data/lib/active_support/cache.rb +331 -217
- data/lib/active_support/callbacks.rb +650 -592
- data/lib/active_support/concern.rb +35 -6
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
- data/lib/active_support/concurrency/share_lock.rb +226 -0
- data/lib/active_support/configurable.rb +13 -14
- data/lib/active_support/core_ext/array/access.rb +41 -1
- data/lib/active_support/core_ext/array/conversions.rb +24 -20
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +11 -18
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +4 -6
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/array.rb +9 -6
- data/lib/active_support/core_ext/benchmark.rb +3 -1
- data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +45 -31
- data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
- data/lib/active_support/core_ext/class/subclasses.rb +20 -6
- data/lib/active_support/core_ext/class.rb +4 -3
- data/lib/active_support/core_ext/date/acts_like.rb +3 -1
- data/lib/active_support/core_ext/date/blank.rb +14 -0
- data/lib/active_support/core_ext/date/calculations.rb +17 -14
- data/lib/active_support/core_ext/date/conversions.rb +25 -23
- data/lib/active_support/core_ext/date/zones.rb +4 -2
- data/lib/active_support/core_ext/date.rb +6 -4
- data/lib/active_support/core_ext/date_and_time/calculations.rb +154 -65
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
- data/lib/active_support/core_ext/date_and_time/zones.rb +12 -13
- data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
- data/lib/active_support/core_ext/date_time/blank.rb +14 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +37 -19
- data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
- data/lib/active_support/core_ext/date_time/conversions.rb +16 -13
- data/lib/active_support/core_ext/date_time.rb +7 -5
- data/lib/active_support/core_ext/digest/uuid.rb +7 -5
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +114 -22
- data/lib/active_support/core_ext/file/atomic.rb +38 -31
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/compact.rb +4 -23
- data/lib/active_support/core_ext/hash/conversions.rb +62 -41
- data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +12 -9
- data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
- data/lib/active_support/core_ext/hash/keys.rb +19 -42
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +5 -27
- data/lib/active_support/core_ext/hash/transform_values.rb +4 -22
- data/lib/active_support/core_ext/hash.rb +10 -9
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +11 -18
- data/lib/active_support/core_ext/integer.rb +5 -3
- data/lib/active_support/core_ext/kernel/concern.rb +5 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +5 -5
- data/lib/active_support/core_ext/load_error.rb +3 -22
- data/lib/active_support/core_ext/marshal.rb +8 -8
- data/lib/active_support/core_ext/module/aliasing.rb +6 -44
- data/lib/active_support/core_ext/module/anonymous.rb +12 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
- data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -46
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
- data/lib/active_support/core_ext/module/concerning.rb +11 -12
- data/lib/active_support/core_ext/module/delegation.rb +133 -30
- data/lib/active_support/core_ext/module/deprecation.rb +4 -2
- data/lib/active_support/core_ext/module/introspection.rb +44 -19
- data/lib/active_support/core_ext/module/reachable.rb +5 -7
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +8 -3
- data/lib/active_support/core_ext/module.rb +13 -11
- data/lib/active_support/core_ext/name_error.rb +22 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -136
- data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
- data/lib/active_support/core_ext/numeric/time.rb +35 -23
- data/lib/active_support/core_ext/numeric.rb +5 -3
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +27 -3
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
- data/lib/active_support/core_ext/object/duplicable.rb +13 -93
- data/lib/active_support/core_ext/object/inclusion.rb +5 -3
- data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
- data/lib/active_support/core_ext/object/json.rb +51 -20
- data/lib/active_support/core_ext/object/to_param.rb +3 -1
- data/lib/active_support/core_ext/object/to_query.rb +10 -5
- data/lib/active_support/core_ext/object/try.rb +81 -23
- data/lib/active_support/core_ext/object/with_options.rb +16 -3
- data/lib/active_support/core_ext/object.rb +14 -13
- data/lib/active_support/core_ext/range/compare_range.rb +76 -0
- data/lib/active_support/core_ext/range/conversions.rb +37 -15
- data/lib/active_support/core_ext/range/each.rb +18 -17
- data/lib/active_support/core_ext/range/include_range.rb +7 -21
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +7 -4
- data/lib/active_support/core_ext/regexp.rb +2 -0
- data/lib/active_support/core_ext/securerandom.rb +45 -0
- data/lib/active_support/core_ext/string/access.rb +16 -6
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +7 -4
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +48 -6
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +66 -24
- data/lib/active_support/core_ext/string/inquiry.rb +3 -1
- data/lib/active_support/core_ext/string/multibyte.rb +16 -7
- data/lib/active_support/core_ext/string/output_safety.rb +93 -40
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
- data/lib/active_support/core_ext/string/strip.rb +6 -5
- data/lib/active_support/core_ext/string/zones.rb +4 -2
- data/lib/active_support/core_ext/string.rb +15 -13
- data/lib/active_support/core_ext/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +115 -52
- data/lib/active_support/core_ext/time/compatibility.rb +4 -2
- data/lib/active_support/core_ext/time/conversions.rb +20 -13
- data/lib/active_support/core_ext/time/zones.rb +41 -7
- data/lib/active_support/core_ext/time.rb +7 -6
- data/lib/active_support/core_ext/uri.rb +6 -7
- data/lib/active_support/core_ext.rb +3 -1
- data/lib/active_support/current_attributes.rb +203 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +208 -166
- data/lib/active_support/deprecation/behaviors.rb +44 -11
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/instance_delegator.rb +17 -2
- data/lib/active_support/deprecation/method_wrappers.rb +61 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +81 -30
- data/lib/active_support/deprecation/reporting.rb +32 -12
- data/lib/active_support/deprecation.rb +12 -9
- data/lib/active_support/descendants_tracker.rb +57 -9
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration/iso8601_parser.rb +123 -0
- data/lib/active_support/duration/iso8601_serializer.rb +53 -0
- data/lib/active_support/duration.rb +315 -40
- data/lib/active_support/encrypted_configuration.rb +45 -0
- data/lib/active_support/encrypted_file.rb +100 -0
- data/lib/active_support/evented_file_update_checker.rb +234 -0
- data/lib/active_support/execution_wrapper.rb +129 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +62 -37
- data/lib/active_support/gem_version.rb +6 -4
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +129 -30
- data/lib/active_support/i18n.rb +9 -6
- data/lib/active_support/i18n_railtie.rb +50 -14
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector/inflections.rb +58 -13
- data/lib/active_support/inflector/methods.rb +159 -145
- data/lib/active_support/inflector/transliterate.rb +84 -34
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/json/decoding.rb +32 -30
- data/lib/active_support/json/encoding.rb +17 -60
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +11 -43
- data/lib/active_support/lazy_load_hooks.rb +53 -20
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- data/lib/active_support/log_subscriber.rb +44 -19
- data/lib/active_support/logger.rb +9 -23
- data/lib/active_support/logger_silence.rb +32 -14
- data/lib/active_support/logger_thread_safe_level.rb +32 -8
- data/lib/active_support/message_encryptor.rb +166 -53
- data/lib/active_support/message_verifier.rb +149 -16
- data/lib/active_support/messages/metadata.rb +72 -0
- data/lib/active_support/messages/rotation_configuration.rb +22 -0
- data/lib/active_support/messages/rotator.rb +56 -0
- data/lib/active_support/multibyte/chars.rb +56 -63
- data/lib/active_support/multibyte/unicode.rb +56 -290
- data/lib/active_support/multibyte.rb +4 -2
- data/lib/active_support/notifications/fanout.rb +109 -22
- data/lib/active_support/notifications/instrumenter.rb +107 -16
- data/lib/active_support/notifications.rb +51 -10
- data/lib/active_support/number_helper/number_converter.rb +16 -15
- data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -15
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +11 -4
- data/lib/active_support/number_helper/number_to_human_converter.rb +13 -10
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -9
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +15 -5
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +25 -57
- data/lib/active_support/number_helper/rounding_helper.rb +66 -0
- data/lib/active_support/number_helper.rb +105 -68
- data/lib/active_support/option_merger.rb +24 -4
- data/lib/active_support/ordered_hash.rb +7 -5
- data/lib/active_support/ordered_options.rb +27 -5
- data/lib/active_support/parameter_filter.rb +128 -0
- data/lib/active_support/per_thread_registry.rb +9 -4
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +10 -8
- data/lib/active_support/railtie.rb +43 -9
- data/lib/active_support/reloader.rb +130 -0
- data/lib/active_support/rescuable.rb +108 -53
- data/lib/active_support/security_utils.rb +15 -11
- data/lib/active_support/string_inquirer.rb +11 -4
- data/lib/active_support/subscriber.rb +74 -30
- data/lib/active_support/tagged_logging.rb +25 -13
- data/lib/active_support/test_case.rb +107 -44
- data/lib/active_support/testing/assertions.rb +151 -20
- data/lib/active_support/testing/autorun.rb +4 -2
- data/lib/active_support/testing/constant_lookup.rb +2 -1
- data/lib/active_support/testing/declarative.rb +3 -1
- data/lib/active_support/testing/deprecation.rb +13 -10
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +35 -26
- data/lib/active_support/testing/method_call_assertions.rb +70 -0
- data/lib/active_support/testing/parallelization.rb +134 -0
- data/lib/active_support/testing/setup_and_teardown.rb +13 -8
- data/lib/active_support/testing/stream.rb +43 -0
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +84 -20
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +179 -39
- data/lib/active_support/values/time_zone.rb +203 -63
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +116 -115
- data/lib/active_support/xml_mini/libxml.rb +16 -13
- data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
- data/lib/active_support/xml_mini/nokogiri.rb +14 -12
- data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
- data/lib/active_support/xml_mini/rexml.rb +11 -9
- data/lib/active_support/xml_mini.rb +38 -46
- data/lib/active_support.rb +13 -11
- metadata +84 -26
- data/lib/active_support/concurrency/latch.rb +0 -27
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
- data/lib/active_support/core_ext/date_time/zones.rb +0 -6
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
- data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
- data/lib/active_support/core_ext/object/itself.rb +0 -15
- data/lib/active_support/core_ext/struct.rb +0 -6
- data/lib/active_support/core_ext/thread.rb +0 -86
- data/lib/active_support/core_ext/time/marshal.rb +0 -30
- 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
|
-
#
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
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
|
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?, :
|
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
|
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
|
-
|
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(
|
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
|
-
|
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) {
|
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
|
-
|
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(
|
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(
|
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
|
-
|
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(
|
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
|
-
|
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
|