activesupport 5.1.7 → 6.1.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +434 -490
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -5
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +2 -0
- data/lib/active_support/array_inquirer.rb +6 -2
- data/lib/active_support/backtrace_cleaner.rb +31 -3
- data/lib/active_support/benchmarkable.rb +3 -1
- data/lib/active_support/builder.rb +2 -0
- data/lib/active_support/cache/file_store.rb +37 -36
- data/lib/active_support/cache/mem_cache_store.rb +72 -56
- data/lib/active_support/cache/memory_store.rb +61 -33
- data/lib/active_support/cache/null_store.rb +10 -3
- data/lib/active_support/cache/redis_cache_store.rb +493 -0
- data/lib/active_support/cache/strategy/local_cache.rb +67 -21
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
- data/lib/active_support/cache.rb +310 -126
- data/lib/active_support/callbacks.rb +106 -100
- data/lib/active_support/concern.rb +79 -6
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -1
- data/lib/active_support/configurable.rb +12 -14
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +21 -7
- data/lib/active_support/core_ext/array/conversions.rb +7 -5
- 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 +2 -0
- data/lib/active_support/core_ext/array/inquiry.rb +2 -0
- data/lib/active_support/core_ext/array/wrap.rb +2 -0
- data/lib/active_support/core_ext/array.rb +3 -1
- data/lib/active_support/core_ext/benchmark.rb +4 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +2 -0
- data/lib/active_support/core_ext/big_decimal.rb +2 -0
- data/lib/active_support/core_ext/class/attribute.rb +50 -47
- data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/class/subclasses.rb +18 -40
- data/lib/active_support/core_ext/class.rb +2 -0
- data/lib/active_support/core_ext/date/acts_like.rb +2 -0
- data/lib/active_support/core_ext/date/blank.rb +2 -0
- data/lib/active_support/core_ext/date/calculations.rb +8 -5
- data/lib/active_support/core_ext/date/conversions.rb +12 -10
- data/lib/active_support/core_ext/date/zones.rb +2 -0
- data/lib/active_support/core_ext/date.rb +2 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +61 -37
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
- data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
- data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
- data/lib/active_support/core_ext/date_time/blank.rb +2 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
- data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_time.rb +2 -0
- data/lib/active_support/core_ext/digest/uuid.rb +4 -1
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +174 -71
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/file.rb +2 -0
- data/lib/active_support/core_ext/hash/conversions.rb +7 -5
- data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +4 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +2 -0
- data/lib/active_support/core_ext/hash/keys.rb +3 -30
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -29
- data/lib/active_support/core_ext/hash.rb +3 -2
- data/lib/active_support/core_ext/integer/inflections.rb +2 -0
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +7 -14
- data/lib/active_support/core_ext/integer.rb +2 -0
- data/lib/active_support/core_ext/kernel/concern.rb +2 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +2 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +2 -1
- data/lib/active_support/core_ext/load_error.rb +3 -8
- data/lib/active_support/core_ext/marshal.rb +4 -0
- data/lib/active_support/core_ext/module/aliasing.rb +2 -0
- data/lib/active_support/core_ext/module/anonymous.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +44 -56
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +18 -18
- data/lib/active_support/core_ext/module/concerning.rb +15 -10
- data/lib/active_support/core_ext/module/delegation.rb +103 -58
- data/lib/active_support/core_ext/module/deprecation.rb +2 -0
- data/lib/active_support/core_ext/module/introspection.rb +18 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +5 -23
- data/lib/active_support/core_ext/module.rb +3 -1
- data/lib/active_support/core_ext/name_error.rb +36 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +131 -129
- data/lib/active_support/core_ext/numeric/time.rb +7 -15
- data/lib/active_support/core_ext/numeric.rb +2 -1
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +13 -3
- data/lib/active_support/core_ext/object/conversions.rb +2 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
- data/lib/active_support/core_ext/object/duplicable.rb +9 -114
- data/lib/active_support/core_ext/object/inclusion.rb +2 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
- data/lib/active_support/core_ext/object/json.rb +22 -2
- data/lib/active_support/core_ext/object/to_param.rb +2 -0
- data/lib/active_support/core_ext/object/to_query.rb +2 -0
- data/lib/active_support/core_ext/object/try.rb +19 -7
- data/lib/active_support/core_ext/object/with_options.rb +4 -2
- data/lib/active_support/core_ext/object.rb +2 -0
- data/lib/active_support/core_ext/range/compare_range.rb +82 -0
- data/lib/active_support/core_ext/range/conversions.rb +35 -25
- data/lib/active_support/core_ext/range/each.rb +5 -2
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +4 -1
- data/lib/active_support/core_ext/regexp.rb +10 -5
- data/lib/active_support/core_ext/securerandom.rb +25 -3
- data/lib/active_support/core_ext/string/access.rb +7 -16
- data/lib/active_support/core_ext/string/behavior.rb +2 -0
- data/lib/active_support/core_ext/string/conversions.rb +3 -0
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +44 -1
- data/lib/active_support/core_ext/string/indent.rb +2 -0
- data/lib/active_support/core_ext/string/inflections.rb +69 -16
- data/lib/active_support/core_ext/string/inquiry.rb +3 -0
- data/lib/active_support/core_ext/string/multibyte.rb +9 -4
- data/lib/active_support/core_ext/string/output_safety.rb +104 -20
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +5 -1
- data/lib/active_support/core_ext/string/zones.rb +2 -0
- data/lib/active_support/core_ext/string.rb +2 -0
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/acts_like.rb +2 -0
- data/lib/active_support/core_ext/time/calculations.rb +76 -18
- data/lib/active_support/core_ext/time/compatibility.rb +4 -2
- data/lib/active_support/core_ext/time/conversions.rb +4 -0
- data/lib/active_support/core_ext/time/zones.rb +6 -4
- data/lib/active_support/core_ext/time.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +11 -6
- data/lib/active_support/core_ext.rb +3 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +210 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +2 -0
- data/lib/active_support/dependencies/zeitwerk_integration.rb +120 -0
- data/lib/active_support/dependencies.rb +134 -60
- data/lib/active_support/deprecation/behaviors.rb +43 -11
- data/lib/active_support/deprecation/constant_accessor.rb +4 -2
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +2 -1
- data/lib/active_support/deprecation/method_wrappers.rb +29 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +32 -6
- data/lib/active_support/deprecation/reporting.rb +54 -9
- data/lib/active_support/deprecation.rb +9 -2
- data/lib/active_support/descendants_tracker.rb +61 -9
- data/lib/active_support/digest.rb +22 -0
- data/lib/active_support/duration/iso8601_parser.rb +6 -6
- data/lib/active_support/duration/iso8601_serializer.rb +20 -14
- data/lib/active_support/duration.rb +102 -45
- data/lib/active_support/encrypted_configuration.rb +45 -0
- data/lib/active_support/encrypted_file.rb +117 -0
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +84 -117
- data/lib/active_support/execution_wrapper.rb +19 -13
- data/lib/active_support/executor.rb +2 -0
- data/lib/active_support/file_update_checker.rb +2 -1
- data/lib/active_support/fork_tracker.rb +64 -0
- data/lib/active_support/gem_version.rb +3 -1
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +123 -41
- data/lib/active_support/i18n.rb +4 -1
- data/lib/active_support/i18n_railtie.rb +19 -14
- data/lib/active_support/inflections.rb +2 -0
- data/lib/active_support/inflector/inflections.rb +19 -8
- data/lib/active_support/inflector/methods.rb +87 -77
- data/lib/active_support/inflector/transliterate.rb +56 -18
- data/lib/active_support/inflector.rb +2 -0
- data/lib/active_support/json/decoding.rb +27 -26
- data/lib/active_support/json/encoding.rb +13 -3
- data/lib/active_support/json.rb +2 -0
- data/lib/active_support/key_generator.rb +3 -33
- data/lib/active_support/lazy_load_hooks.rb +7 -2
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber/test_helper.rb +2 -0
- data/lib/active_support/log_subscriber.rb +42 -11
- data/lib/active_support/logger.rb +4 -17
- data/lib/active_support/logger_silence.rb +13 -20
- data/lib/active_support/logger_thread_safe_level.rb +54 -7
- data/lib/active_support/message_encryptor.rb +100 -32
- data/lib/active_support/message_verifier.rb +85 -14
- data/lib/active_support/messages/metadata.rb +80 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotator.rb +57 -0
- data/lib/active_support/multibyte/chars.rb +12 -68
- data/lib/active_support/multibyte/unicode.rb +17 -327
- data/lib/active_support/multibyte.rb +2 -0
- data/lib/active_support/notifications/fanout.rb +118 -16
- data/lib/active_support/notifications/instrumenter.rb +73 -9
- data/lib/active_support/notifications.rb +74 -8
- data/lib/active_support/number_helper/number_converter.rb +7 -6
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -3
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -2
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
- data/lib/active_support/number_helper/rounding_helper.rb +16 -30
- data/lib/active_support/number_helper.rb +40 -12
- data/lib/active_support/option_merger.rb +24 -3
- data/lib/active_support/ordered_hash.rb +3 -1
- data/lib/active_support/ordered_options.rb +17 -5
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +4 -1
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +3 -10
- data/lib/active_support/railtie.rb +60 -9
- data/lib/active_support/reloader.rb +12 -11
- data/lib/active_support/rescuable.rb +7 -6
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +26 -15
- data/lib/active_support/string_inquirer.rb +6 -3
- data/lib/active_support/subscriber.rb +74 -24
- data/lib/active_support/tagged_logging.rb +44 -8
- data/lib/active_support/test_case.rb +94 -2
- data/lib/active_support/testing/assertions.rb +58 -20
- data/lib/active_support/testing/autorun.rb +2 -0
- data/lib/active_support/testing/constant_lookup.rb +2 -0
- data/lib/active_support/testing/declarative.rb +2 -0
- data/lib/active_support/testing/deprecation.rb +2 -1
- data/lib/active_support/testing/file_fixtures.rb +4 -0
- data/lib/active_support/testing/isolation.rb +4 -2
- data/lib/active_support/testing/method_call_assertions.rb +30 -1
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +51 -0
- data/lib/active_support/testing/setup_and_teardown.rb +12 -7
- data/lib/active_support/testing/stream.rb +3 -2
- data/lib/active_support/testing/tagged_logging.rb +2 -0
- data/lib/active_support/testing/time_helpers.rb +78 -13
- data/lib/active_support/time.rb +2 -0
- data/lib/active_support/time_with_zone.rb +113 -41
- data/lib/active_support/values/time_zone.rb +54 -25
- data/lib/active_support/version.rb +2 -0
- data/lib/active_support/xml_mini/jdom.rb +5 -4
- data/lib/active_support/xml_mini/libxml.rb +4 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +6 -4
- data/lib/active_support/xml_mini/nokogiri.rb +4 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +5 -3
- data/lib/active_support/xml_mini/rexml.rb +12 -3
- data/lib/active_support/xml_mini.rb +5 -11
- data/lib/active_support.rb +18 -13
- metadata +71 -32
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/hash/compact.rb +0 -27
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
- data/lib/active_support/core_ext/range/include_range.rb +0 -23
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -0,0 +1,80 @@
|
|
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) ? parse_expires_at(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
|
+
|
71
|
+
def parse_expires_at(expires_at)
|
72
|
+
if ActiveSupport.use_standard_json_time_format
|
73
|
+
Time.iso8601(expires_at)
|
74
|
+
else
|
75
|
+
Time.parse(expires_at)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,23 @@
|
|
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, **options)
|
13
|
+
args << options unless options.empty?
|
14
|
+
case kind
|
15
|
+
when :signed
|
16
|
+
@signed << args
|
17
|
+
when :encrypted
|
18
|
+
@encrypted << args
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Messages
|
5
|
+
module Rotator # :nodoc:
|
6
|
+
def initialize(*secrets, on_rotation: nil, **options)
|
7
|
+
super(*secrets, **options)
|
8
|
+
|
9
|
+
@options = options
|
10
|
+
@rotations = []
|
11
|
+
@on_rotation = on_rotation
|
12
|
+
end
|
13
|
+
|
14
|
+
def rotate(*secrets, **options)
|
15
|
+
@rotations << build_rotation(*secrets, @options.merge(options))
|
16
|
+
end
|
17
|
+
|
18
|
+
module Encryptor
|
19
|
+
include Rotator
|
20
|
+
|
21
|
+
def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
|
22
|
+
super
|
23
|
+
rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
|
24
|
+
run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
|
29
|
+
self.class.new(secret, sign_secret, **options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module Verifier
|
34
|
+
include Rotator
|
35
|
+
|
36
|
+
def verified(*args, on_rotation: @on_rotation, **options)
|
37
|
+
super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def build_rotation(secret = @secret, options)
|
42
|
+
self.class.new(secret, **options)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def run_rotations(on_rotation)
|
48
|
+
@rotations.find do |rotation|
|
49
|
+
if message = yield(rotation) rescue next
|
50
|
+
on_rotation&.call
|
51
|
+
return message
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,8 +1,10 @@
|
|
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"
|
6
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
4
7
|
require "active_support/core_ext/module/delegation"
|
5
|
-
require "active_support/core_ext/regexp"
|
6
8
|
|
7
9
|
module ActiveSupport #:nodoc:
|
8
10
|
module Multibyte #:nodoc:
|
@@ -16,7 +18,7 @@ module ActiveSupport #:nodoc:
|
|
16
18
|
# through the +mb_chars+ method. Methods which would normally return a
|
17
19
|
# String object now return a Chars object so methods can be chained.
|
18
20
|
#
|
19
|
-
# 'The Perfect String '.mb_chars.downcase.strip
|
21
|
+
# 'The Perfect String '.mb_chars.downcase.strip
|
20
22
|
# # => #<ActiveSupport::Multibyte::Chars:0x007fdc434ccc10 @wrapped_string="the perfect string">
|
21
23
|
#
|
22
24
|
# Chars objects are perfectly interchangeable with String objects as long as
|
@@ -47,7 +49,7 @@ module ActiveSupport #:nodoc:
|
|
47
49
|
alias to_s wrapped_string
|
48
50
|
alias to_str wrapped_string
|
49
51
|
|
50
|
-
delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string
|
52
|
+
delegate :<=>, :=~, :match?, :acts_like_string?, to: :wrapped_string
|
51
53
|
|
52
54
|
# Creates a new Chars instance by wrapping _string_.
|
53
55
|
def initialize(string)
|
@@ -58,7 +60,7 @@ module ActiveSupport #:nodoc:
|
|
58
60
|
# Forward all undefined methods to the wrapped string.
|
59
61
|
def method_missing(method, *args, &block)
|
60
62
|
result = @wrapped_string.__send__(method, *args, &block)
|
61
|
-
if
|
63
|
+
if method.end_with?("!")
|
62
64
|
self if result
|
63
65
|
else
|
64
66
|
result.kind_of?(String) ? chars(result) : result
|
@@ -72,12 +74,6 @@ module ActiveSupport #:nodoc:
|
|
72
74
|
@wrapped_string.respond_to?(method, include_private)
|
73
75
|
end
|
74
76
|
|
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
77
|
# Works just like <tt>String#split</tt>, with the exception that the items
|
82
78
|
# in the resulting list are Chars instances instead of String. This makes
|
83
79
|
# chaining methods easier.
|
@@ -107,7 +103,7 @@ module ActiveSupport #:nodoc:
|
|
107
103
|
#
|
108
104
|
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
|
109
105
|
def reverse
|
110
|
-
chars(
|
106
|
+
chars(@wrapped_string.scan(/\X/).reverse.join)
|
111
107
|
end
|
112
108
|
|
113
109
|
# Limits the byte size of the string to a number of bytes without breaking
|
@@ -116,35 +112,7 @@ module ActiveSupport #:nodoc:
|
|
116
112
|
#
|
117
113
|
# 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
|
118
114
|
def limit(limit)
|
119
|
-
|
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
|
115
|
+
chars(@wrapped_string.truncate_bytes(limit, omission: nil))
|
148
116
|
end
|
149
117
|
|
150
118
|
# Capitalizes the first letter of every word, when possible.
|
@@ -152,21 +120,10 @@ module ActiveSupport #:nodoc:
|
|
152
120
|
# "ÉL QUE SE ENTERÓ".mb_chars.titleize.to_s # => "Él Que Se Enteró"
|
153
121
|
# "日本語".mb_chars.titleize.to_s # => "日本語"
|
154
122
|
def titleize
|
155
|
-
chars(downcase.to_s.gsub(/\b('?\S)/u) {
|
123
|
+
chars(downcase.to_s.gsub(/\b('?\S)/u) { $1.upcase })
|
156
124
|
end
|
157
125
|
alias_method :titlecase, :titleize
|
158
126
|
|
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
127
|
# Performs canonical decomposition on all the characters.
|
171
128
|
#
|
172
129
|
# 'é'.length # => 2
|
@@ -188,7 +145,7 @@ module ActiveSupport #:nodoc:
|
|
188
145
|
# 'क्षि'.mb_chars.length # => 4
|
189
146
|
# 'क्षि'.mb_chars.grapheme_length # => 3
|
190
147
|
def grapheme_length
|
191
|
-
|
148
|
+
@wrapped_string.scan(/\X/).length
|
192
149
|
end
|
193
150
|
|
194
151
|
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
@@ -204,27 +161,14 @@ module ActiveSupport #:nodoc:
|
|
204
161
|
to_s.as_json(options)
|
205
162
|
end
|
206
163
|
|
207
|
-
%w(
|
164
|
+
%w(reverse tidy_bytes).each do |method|
|
208
165
|
define_method("#{method}!") do |*args|
|
209
|
-
@wrapped_string =
|
166
|
+
@wrapped_string = public_send(method, *args).to_s
|
210
167
|
self
|
211
168
|
end
|
212
169
|
end
|
213
170
|
|
214
171
|
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
172
|
def chars(string)
|
229
173
|
self.class.new(string)
|
230
174
|
end
|