activesupport 6.0.6.1 → 7.1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +865 -438
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -6
- data/lib/active_support/actionable_error.rb +4 -2
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +30 -10
- data/lib/active_support/benchmarkable.rb +4 -3
- data/lib/active_support/broadcast_logger.rb +250 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +53 -20
- data/lib/active_support/cache/mem_cache_store.rb +208 -63
- data/lib/active_support/cache/memory_store.rb +120 -38
- data/lib/active_support/cache/null_store.rb +16 -2
- data/lib/active_support/cache/redis_cache_store.rb +201 -208
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +73 -66
- data/lib/active_support/cache.rb +539 -261
- data/lib/active_support/callbacks.rb +273 -142
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +53 -7
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +19 -6
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +15 -13
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +19 -29
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +24 -9
- data/lib/active_support/core_ext/date/conversions.rb +18 -16
- data/lib/active_support/core_ext/date_and_time/calculations.rb +27 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
- data/lib/active_support/core_ext/digest/uuid.rb +30 -13
- data/lib/active_support/core_ext/enumerable.rb +146 -72
- data/lib/active_support/core_ext/erb/util.rb +196 -0
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +3 -4
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +4 -4
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +5 -5
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +31 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +51 -20
- data/lib/active_support/core_ext/module/concerning.rb +14 -8
- data/lib/active_support/core_ext/module/delegation.rb +75 -42
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +1 -26
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +82 -73
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
- data/lib/active_support/core_ext/object/duplicable.rb +15 -4
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
- data/lib/active_support/core_ext/object/json.rb +52 -28
- data/lib/active_support/core_ext/object/to_query.rb +2 -4
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +25 -6
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +16 -0
- data/lib/active_support/core_ext/pathname/existence.rb +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +6 -25
- data/lib/active_support/core_ext/range/conversions.rb +34 -13
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/securerandom.rb +25 -13
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +3 -2
- data/lib/active_support/core_ext/string/filters.rb +21 -15
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +51 -10
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +85 -194
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +46 -8
- data/lib/active_support/core_ext/time/conversions.rb +16 -13
- data/lib/active_support/core_ext/time/zones.rb +12 -28
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +54 -22
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -769
- data/lib/active_support/deprecation/behaviors.rb +77 -38
- data/lib/active_support/deprecation/constant_accessor.rb +5 -4
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +54 -0
- data/lib/active_support/deprecation/instance_delegator.rb +31 -5
- data/lib/active_support/deprecation/method_wrappers.rb +12 -28
- data/lib/active_support/deprecation/proxy_wrappers.rb +40 -25
- data/lib/active_support/deprecation/reporting.rb +76 -16
- data/lib/active_support/deprecation.rb +36 -4
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +150 -68
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +24 -12
- data/lib/active_support/duration.rb +136 -56
- data/lib/active_support/encrypted_configuration.rb +72 -9
- data/lib/active_support/encrypted_file.rb +46 -13
- data/lib/active_support/environment_inquirer.rb +40 -0
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +203 -0
- data/lib/active_support/evented_file_update_checker.rb +86 -137
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +31 -12
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +79 -0
- data/lib/active_support/gem_version.rb +5 -5
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +86 -42
- data/lib/active_support/html_safe_translation.rb +53 -0
- data/lib/active_support/i18n.rb +2 -1
- data/lib/active_support/i18n_railtie.rb +29 -27
- data/lib/active_support/inflector/inflections.rb +26 -9
- data/lib/active_support/inflector/methods.rb +54 -64
- data/lib/active_support/inflector/transliterate.rb +7 -5
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +6 -5
- data/lib/active_support/json/encoding.rb +31 -45
- data/lib/active_support/key_generator.rb +32 -7
- data/lib/active_support/lazy_load_hooks.rb +33 -7
- data/lib/active_support/locale/en.yml +10 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +101 -32
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +24 -25
- data/lib/active_support/message_encryptor.rb +205 -58
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +292 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +237 -86
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +112 -46
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +35 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +15 -52
- data/lib/active_support/multibyte/unicode.rb +8 -122
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +310 -105
- data/lib/active_support/notifications/instrumenter.rb +113 -48
- data/lib/active_support/notifications.rb +56 -29
- data/lib/active_support/number_helper/number_converter.rb +15 -8
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -5
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +379 -304
- data/lib/active_support/option_merger.rb +11 -18
- data/lib/active_support/ordered_hash.rb +4 -4
- data/lib/active_support/ordered_options.rb +23 -3
- data/lib/active_support/parameter_filter.rb +104 -75
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +90 -6
- data/lib/active_support/reloader.rb +12 -4
- data/lib/active_support/rescuable.rb +18 -16
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +58 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +5 -3
- data/lib/active_support/subscriber.rb +23 -47
- data/lib/active_support/syntax_error_proxy.rb +70 -0
- data/lib/active_support/tagged_logging.rb +84 -23
- data/lib/active_support/test_case.rb +166 -27
- data/lib/active_support/testing/assertions.rb +73 -20
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +32 -0
- data/lib/active_support/testing/deprecation.rb +53 -2
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +30 -29
- data/lib/active_support/testing/method_call_assertions.rb +24 -11
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +16 -95
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/stream.rb +4 -6
- data/lib/active_support/testing/strict_warnings.rb +39 -0
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +89 -19
- data/lib/active_support/time_with_zone.rb +105 -70
- data/lib/active_support/values/time_zone.rb +59 -26
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +4 -11
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +5 -5
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
- data/lib/active_support/xml_mini/rexml.rb +9 -2
- data/lib/active_support/xml_mini.rb +7 -6
- data/lib/active_support.rb +40 -1
- metadata +127 -40
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -23
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/uri.rb +0 -25
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
- data/lib/active_support/per_thread_registry.rb +0 -60
@@ -2,6 +2,5 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/range/conversions"
|
4
4
|
require "active_support/core_ext/range/compare_range"
|
5
|
-
require "active_support/core_ext/range/
|
6
|
-
require "active_support/core_ext/range/overlaps"
|
5
|
+
require "active_support/core_ext/range/overlap"
|
7
6
|
require "active_support/core_ext/range/each"
|
@@ -1,6 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class Regexp
|
3
|
+
class Regexp
|
4
|
+
# Returns +true+ if the regexp has the multiline flag set.
|
5
|
+
#
|
6
|
+
# (/./).multiline? # => false
|
7
|
+
# (/./m).multiline? # => true
|
8
|
+
#
|
9
|
+
# Regexp.new(".").multiline? # => false
|
10
|
+
# Regexp.new(".", Regexp::MULTILINE).multiline? # => true
|
4
11
|
def multiline?
|
5
12
|
options & MULTILINE == MULTILINE
|
6
13
|
end
|
@@ -12,16 +12,22 @@ module SecureRandom
|
|
12
12
|
#
|
13
13
|
# If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
|
14
14
|
#
|
15
|
-
# The result may contain alphanumeric characters except 0, O, I and l.
|
15
|
+
# The result may contain alphanumeric characters except 0, O, I, and l.
|
16
16
|
#
|
17
17
|
# p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
|
18
18
|
# p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
if RUBY_VERSION >= "3.3"
|
20
|
+
def self.base58(n = 16)
|
21
|
+
SecureRandom.alphanumeric(n, chars: BASE58_ALPHABET)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
def self.base58(n = 16)
|
25
|
+
SecureRandom.random_bytes(n).unpack("C*").map do |byte|
|
26
|
+
idx = byte % 64
|
27
|
+
idx = SecureRandom.random_number(58) if idx >= 58
|
28
|
+
BASE58_ALPHABET[idx]
|
29
|
+
end.join
|
30
|
+
end
|
25
31
|
end
|
26
32
|
|
27
33
|
# SecureRandom.base36 generates a random base36 string in lowercase.
|
@@ -35,11 +41,17 @@ module SecureRandom
|
|
35
41
|
#
|
36
42
|
# p SecureRandom.base36 # => "4kugl2pdqmscqtje"
|
37
43
|
# p SecureRandom.base36(24) # => "77tmhrhjfvfdwodq8w7ev2m7"
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
+
if RUBY_VERSION >= "3.3"
|
45
|
+
def self.base36(n = 16)
|
46
|
+
SecureRandom.alphanumeric(n, chars: BASE36_ALPHABET)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
def self.base36(n = 16)
|
50
|
+
SecureRandom.random_bytes(n).unpack("C*").map do |byte|
|
51
|
+
idx = byte % 64
|
52
|
+
idx = SecureRandom.random_number(36) if idx >= 36
|
53
|
+
BASE36_ALPHABET[idx]
|
54
|
+
end.join
|
55
|
+
end
|
44
56
|
end
|
45
57
|
end
|
@@ -44,7 +44,7 @@ class String
|
|
44
44
|
# str.from(0).to(-1) # => "hello"
|
45
45
|
# str.from(1).to(-2) # => "ell"
|
46
46
|
def from(position)
|
47
|
-
self[position
|
47
|
+
self[position, length]
|
48
48
|
end
|
49
49
|
|
50
50
|
# Returns a substring from the beginning of the string to the given position.
|
@@ -61,7 +61,8 @@ class String
|
|
61
61
|
# str.from(0).to(-1) # => "hello"
|
62
62
|
# str.from(1).to(-2) # => "ell"
|
63
63
|
def to(position)
|
64
|
-
|
64
|
+
position += size if position < 0
|
65
|
+
self[0, position + 1] || +""
|
65
66
|
end
|
66
67
|
|
67
68
|
# Returns the first character. If a limit is supplied, returns a substring
|
@@ -75,17 +76,7 @@ class String
|
|
75
76
|
# str.first(0) # => ""
|
76
77
|
# str.first(6) # => "hello"
|
77
78
|
def first(limit = 1)
|
78
|
-
|
79
|
-
"Calling String#first with a negative integer limit " \
|
80
|
-
"will raise an ArgumentError in Rails 6.1."
|
81
|
-
) if limit < 0
|
82
|
-
if limit == 0
|
83
|
-
""
|
84
|
-
elsif limit >= size
|
85
|
-
dup
|
86
|
-
else
|
87
|
-
to(limit - 1)
|
88
|
-
end
|
79
|
+
self[0, limit] || raise(ArgumentError, "negative limit")
|
89
80
|
end
|
90
81
|
|
91
82
|
# Returns the last character of the string. If a limit is supplied, returns a substring
|
@@ -99,16 +90,6 @@ class String
|
|
99
90
|
# str.last(0) # => ""
|
100
91
|
# str.last(6) # => "hello"
|
101
92
|
def last(limit = 1)
|
102
|
-
|
103
|
-
"Calling String#last with a negative integer limit " \
|
104
|
-
"will raise an ArgumentError in Rails 6.1."
|
105
|
-
) if limit < 0
|
106
|
-
if limit == 0
|
107
|
-
""
|
108
|
-
elsif limit >= size
|
109
|
-
dup
|
110
|
-
else
|
111
|
-
from(-limit)
|
112
|
-
end
|
93
|
+
self[[length - limit, 0].max, limit] || raise(ArgumentError, "negative limit")
|
113
94
|
end
|
114
95
|
end
|
@@ -5,10 +5,10 @@ require "active_support/core_ext/time/calculations"
|
|
5
5
|
|
6
6
|
class String
|
7
7
|
# Converts a string to a Time value.
|
8
|
-
# The +form+ can be either
|
8
|
+
# The +form+ can be either +:utc+ or +:local+ (default +:local+).
|
9
9
|
#
|
10
10
|
# The time is parsed using Time.parse method.
|
11
|
-
# If +form+ is
|
11
|
+
# If +form+ is +:local+, then the time is in the system timezone.
|
12
12
|
# If the date part is missing then the current date is used and if
|
13
13
|
# the time part is missing then it is assumed to be 00:00:00.
|
14
14
|
#
|
@@ -18,6 +18,7 @@ class String
|
|
18
18
|
# "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 +0100
|
19
19
|
# "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 06:12:00 UTC
|
20
20
|
# "12/13/2012".to_time # => ArgumentError: argument out of range
|
21
|
+
# "1604326192".to_time # => ArgumentError: argument out of range
|
21
22
|
def to_time(form = :local)
|
22
23
|
parts = Date._parse(self, false)
|
23
24
|
used_keys = %i(year mon mday hour min sec sec_fraction offset)
|
@@ -45,7 +45,7 @@ class String
|
|
45
45
|
self
|
46
46
|
end
|
47
47
|
|
48
|
-
# Truncates a given +text+
|
48
|
+
# Truncates a given +text+ to length <tt>truncate_to</tt> if +text+ is longer than <tt>truncate_to</tt>:
|
49
49
|
#
|
50
50
|
# 'Once upon a time in a world far far away'.truncate(27)
|
51
51
|
# # => "Once upon a time in a wo..."
|
@@ -58,16 +58,20 @@ class String
|
|
58
58
|
# 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
|
59
59
|
# # => "Once upon a time in a..."
|
60
60
|
#
|
61
|
-
# The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
|
62
|
-
#
|
61
|
+
# The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...").
|
62
|
+
# The total length will not exceed <tt>truncate_to</tt> unless both +text+ and <tt>:omission</tt>
|
63
|
+
# are longer than <tt>truncate_to</tt>:
|
63
64
|
#
|
64
65
|
# 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
|
65
66
|
# # => "And they f... (continued)"
|
66
|
-
|
67
|
-
|
67
|
+
#
|
68
|
+
# 'And they found that many people were sleeping better.'.truncate(4, omission: '... (continued)')
|
69
|
+
# # => "... (continued)"
|
70
|
+
def truncate(truncate_to, options = {})
|
71
|
+
return dup unless length > truncate_to
|
68
72
|
|
69
73
|
omission = options[:omission] || "..."
|
70
|
-
length_with_room_for_omission =
|
74
|
+
length_with_room_for_omission = truncate_to - omission.length
|
71
75
|
stop = \
|
72
76
|
if options[:separator]
|
73
77
|
rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
|
@@ -78,7 +82,7 @@ class String
|
|
78
82
|
+"#{self[0, stop]}#{omission}"
|
79
83
|
end
|
80
84
|
|
81
|
-
# Truncates +text+ to at most <tt>
|
85
|
+
# Truncates +text+ to at most <tt>truncate_to</tt> bytes in length without
|
82
86
|
# breaking string encoding by splitting multibyte characters or breaking
|
83
87
|
# grapheme clusters ("perceptual characters") by truncating at combining
|
84
88
|
# characters.
|
@@ -91,22 +95,24 @@ class String
|
|
91
95
|
# => "🔪🔪🔪🔪…"
|
92
96
|
#
|
93
97
|
# The truncated text ends with the <tt>:omission</tt> string, defaulting
|
94
|
-
# to "…", for a total length not exceeding <tt>
|
95
|
-
|
98
|
+
# to "…", for a total length not exceeding <tt>truncate_to</tt>.
|
99
|
+
#
|
100
|
+
# Raises +ArgumentError+ when the bytesize of <tt>:omission</tt> exceeds <tt>truncate_to</tt>.
|
101
|
+
def truncate_bytes(truncate_to, omission: "…")
|
96
102
|
omission ||= ""
|
97
103
|
|
98
104
|
case
|
99
|
-
when bytesize <=
|
105
|
+
when bytesize <= truncate_to
|
100
106
|
dup
|
101
|
-
when omission.bytesize >
|
102
|
-
raise ArgumentError, "Omission #{omission.inspect} is #{omission.bytesize}, larger than the truncation length of #{
|
103
|
-
when omission.bytesize ==
|
107
|
+
when omission.bytesize > truncate_to
|
108
|
+
raise ArgumentError, "Omission #{omission.inspect} is #{omission.bytesize}, larger than the truncation length of #{truncate_to} bytes"
|
109
|
+
when omission.bytesize == truncate_to
|
104
110
|
omission.dup
|
105
111
|
else
|
106
112
|
self.class.new.tap do |cut|
|
107
|
-
cut_at =
|
113
|
+
cut_at = truncate_to - omission.bytesize
|
108
114
|
|
109
|
-
|
115
|
+
each_grapheme_cluster do |grapheme|
|
110
116
|
if cut.bytesize + grapheme.bytesize <= cut_at
|
111
117
|
cut << grapheme
|
112
118
|
else
|
@@ -24,7 +24,7 @@ class String
|
|
24
24
|
#
|
25
25
|
# The second argument, +indent_string+, specifies which indent string to
|
26
26
|
# use. The default is +nil+, which tells the method to make a guess by
|
27
|
-
# peeking at the first indented line, and
|
27
|
+
# peeking at the first indented line, and fall back to a space if there is
|
28
28
|
# none.
|
29
29
|
#
|
30
30
|
# " foo".indent(2) # => " foo"
|
@@ -30,6 +30,8 @@ class String
|
|
30
30
|
# 'apple'.pluralize(2) # => "apples"
|
31
31
|
# 'ley'.pluralize(:es) # => "leyes"
|
32
32
|
# 'ley'.pluralize(1, :es) # => "ley"
|
33
|
+
#
|
34
|
+
# See ActiveSupport::Inflector.pluralize.
|
33
35
|
def pluralize(count = nil, locale = :en)
|
34
36
|
locale = count if count.is_a?(Symbol)
|
35
37
|
if count == 1
|
@@ -53,28 +55,34 @@ class String
|
|
53
55
|
# 'the blue mailmen'.singularize # => "the blue mailman"
|
54
56
|
# 'CamelOctopi'.singularize # => "CamelOctopus"
|
55
57
|
# 'leyes'.singularize(:es) # => "ley"
|
58
|
+
#
|
59
|
+
# See ActiveSupport::Inflector.singularize.
|
56
60
|
def singularize(locale = :en)
|
57
61
|
ActiveSupport::Inflector.singularize(self, locale)
|
58
62
|
end
|
59
63
|
|
60
64
|
# +constantize+ tries to find a declared constant with the name specified
|
61
65
|
# in the string. It raises a NameError when the name is not in CamelCase
|
62
|
-
# or is not initialized.
|
66
|
+
# or is not initialized.
|
63
67
|
#
|
64
68
|
# 'Module'.constantize # => Module
|
65
69
|
# 'Class'.constantize # => Class
|
66
70
|
# 'blargle'.constantize # => NameError: wrong constant name blargle
|
71
|
+
#
|
72
|
+
# See ActiveSupport::Inflector.constantize.
|
67
73
|
def constantize
|
68
74
|
ActiveSupport::Inflector.constantize(self)
|
69
75
|
end
|
70
76
|
|
71
77
|
# +safe_constantize+ tries to find a declared constant with the name specified
|
72
78
|
# in the string. It returns +nil+ when the name is not in CamelCase
|
73
|
-
# or is not initialized.
|
79
|
+
# or is not initialized.
|
74
80
|
#
|
75
81
|
# 'Module'.safe_constantize # => Module
|
76
82
|
# 'Class'.safe_constantize # => Class
|
77
83
|
# 'blargle'.safe_constantize # => nil
|
84
|
+
#
|
85
|
+
# See ActiveSupport::Inflector.safe_constantize.
|
78
86
|
def safe_constantize
|
79
87
|
ActiveSupport::Inflector.safe_constantize(self)
|
80
88
|
end
|
@@ -88,6 +96,8 @@ class String
|
|
88
96
|
# 'active_record'.camelize(:lower) # => "activeRecord"
|
89
97
|
# 'active_record/errors'.camelize # => "ActiveRecord::Errors"
|
90
98
|
# 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
|
99
|
+
#
|
100
|
+
# See ActiveSupport::Inflector.camelize.
|
91
101
|
def camelize(first_letter = :upper)
|
92
102
|
case first_letter
|
93
103
|
when :upper
|
@@ -102,17 +112,17 @@ class String
|
|
102
112
|
|
103
113
|
# Capitalizes all the words and replaces some characters in the string to create
|
104
114
|
# a nicer looking title. +titleize+ is meant for creating pretty output. It is not
|
105
|
-
# used in the Rails internals.
|
115
|
+
# used in the \Rails internals.
|
106
116
|
#
|
107
117
|
# The trailing '_id','Id'.. can be kept and capitalized by setting the
|
108
118
|
# optional parameter +keep_id_suffix+ to true.
|
109
119
|
# By default, this parameter is false.
|
110
120
|
#
|
111
|
-
# +titleize+ is also aliased as +titlecase+.
|
112
|
-
#
|
113
121
|
# 'man from the boondocks'.titleize # => "Man From The Boondocks"
|
114
122
|
# 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
|
115
123
|
# 'string_ending_with_id'.titleize(keep_id_suffix: true) # => "String Ending With Id"
|
124
|
+
#
|
125
|
+
# See ActiveSupport::Inflector.titleize.
|
116
126
|
def titleize(keep_id_suffix: false)
|
117
127
|
ActiveSupport::Inflector.titleize(self, keep_id_suffix: keep_id_suffix)
|
118
128
|
end
|
@@ -124,6 +134,8 @@ class String
|
|
124
134
|
#
|
125
135
|
# 'ActiveModel'.underscore # => "active_model"
|
126
136
|
# 'ActiveModel::Errors'.underscore # => "active_model/errors"
|
137
|
+
#
|
138
|
+
# See ActiveSupport::Inflector.underscore.
|
127
139
|
def underscore
|
128
140
|
ActiveSupport::Inflector.underscore(self)
|
129
141
|
end
|
@@ -131,6 +143,8 @@ class String
|
|
131
143
|
# Replaces underscores with dashes in the string.
|
132
144
|
#
|
133
145
|
# 'puni_puni'.dasherize # => "puni-puni"
|
146
|
+
#
|
147
|
+
# See ActiveSupport::Inflector.dasherize.
|
134
148
|
def dasherize
|
135
149
|
ActiveSupport::Inflector.dasherize(self)
|
136
150
|
end
|
@@ -142,6 +156,8 @@ class String
|
|
142
156
|
# '::Inflections'.demodulize # => "Inflections"
|
143
157
|
# ''.demodulize # => ''
|
144
158
|
#
|
159
|
+
# See ActiveSupport::Inflector.demodulize.
|
160
|
+
#
|
145
161
|
# See also +deconstantize+.
|
146
162
|
def demodulize
|
147
163
|
ActiveSupport::Inflector.demodulize(self)
|
@@ -155,6 +171,8 @@ class String
|
|
155
171
|
# '::String'.deconstantize # => ""
|
156
172
|
# ''.deconstantize # => ""
|
157
173
|
#
|
174
|
+
# See ActiveSupport::Inflector.deconstantize.
|
175
|
+
#
|
158
176
|
# See also +demodulize+.
|
159
177
|
def deconstantize
|
160
178
|
ActiveSupport::Inflector.deconstantize(self)
|
@@ -192,31 +210,37 @@ class String
|
|
192
210
|
#
|
193
211
|
# <%= link_to(@person.name, person_path) %>
|
194
212
|
# # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a>
|
213
|
+
#
|
214
|
+
# See ActiveSupport::Inflector.parameterize.
|
195
215
|
def parameterize(separator: "-", preserve_case: false, locale: nil)
|
196
216
|
ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case, locale: locale)
|
197
217
|
end
|
198
218
|
|
199
|
-
# Creates the name of a table like Rails does for models to table names. This method
|
219
|
+
# Creates the name of a table like \Rails does for models to table names. This method
|
200
220
|
# uses the +pluralize+ method on the last word in the string.
|
201
221
|
#
|
202
222
|
# 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
|
203
223
|
# 'ham_and_egg'.tableize # => "ham_and_eggs"
|
204
224
|
# 'fancyCategory'.tableize # => "fancy_categories"
|
225
|
+
#
|
226
|
+
# See ActiveSupport::Inflector.tableize.
|
205
227
|
def tableize
|
206
228
|
ActiveSupport::Inflector.tableize(self)
|
207
229
|
end
|
208
230
|
|
209
|
-
# Creates a class name from a plural table name like Rails does for table names to models.
|
231
|
+
# Creates a class name from a plural table name like \Rails does for table names to models.
|
210
232
|
# Note that this returns a string and not a class. (To convert to an actual class
|
211
233
|
# follow +classify+ with +constantize+.)
|
212
234
|
#
|
213
235
|
# 'ham_and_eggs'.classify # => "HamAndEgg"
|
214
236
|
# 'posts'.classify # => "Post"
|
237
|
+
#
|
238
|
+
# See ActiveSupport::Inflector.classify.
|
215
239
|
def classify
|
216
240
|
ActiveSupport::Inflector.classify(self)
|
217
241
|
end
|
218
242
|
|
219
|
-
# Capitalizes the first word, turns underscores into spaces, and (by default)strips a
|
243
|
+
# Capitalizes the first word, turns underscores into spaces, and (by default) strips a
|
220
244
|
# trailing '_id' if present.
|
221
245
|
# Like +titleize+, this is meant for creating pretty output.
|
222
246
|
#
|
@@ -232,20 +256,35 @@ class String
|
|
232
256
|
# 'author_id'.humanize # => "Author"
|
233
257
|
# 'author_id'.humanize(capitalize: false) # => "author"
|
234
258
|
# '_id'.humanize # => "Id"
|
235
|
-
# 'author_id'.humanize(keep_id_suffix: true) # => "Author
|
259
|
+
# 'author_id'.humanize(keep_id_suffix: true) # => "Author id"
|
260
|
+
#
|
261
|
+
# See ActiveSupport::Inflector.humanize.
|
236
262
|
def humanize(capitalize: true, keep_id_suffix: false)
|
237
263
|
ActiveSupport::Inflector.humanize(self, capitalize: capitalize, keep_id_suffix: keep_id_suffix)
|
238
264
|
end
|
239
265
|
|
240
|
-
# Converts
|
266
|
+
# Converts the first character to uppercase.
|
241
267
|
#
|
242
268
|
# 'what a Lovely Day'.upcase_first # => "What a Lovely Day"
|
243
269
|
# 'w'.upcase_first # => "W"
|
244
270
|
# ''.upcase_first # => ""
|
271
|
+
#
|
272
|
+
# See ActiveSupport::Inflector.upcase_first.
|
245
273
|
def upcase_first
|
246
274
|
ActiveSupport::Inflector.upcase_first(self)
|
247
275
|
end
|
248
276
|
|
277
|
+
# Converts the first character to lowercase.
|
278
|
+
#
|
279
|
+
# 'If they enjoyed The Matrix'.downcase_first # => "if they enjoyed The Matrix"
|
280
|
+
# 'I'.downcase_first # => "i"
|
281
|
+
# ''.downcase_first # => ""
|
282
|
+
#
|
283
|
+
# See ActiveSupport::Inflector.downcase_first.
|
284
|
+
def downcase_first
|
285
|
+
ActiveSupport::Inflector.downcase_first(self)
|
286
|
+
end
|
287
|
+
|
249
288
|
# Creates a foreign key name from a class name.
|
250
289
|
# +separate_class_name_and_id_with_underscore+ sets whether
|
251
290
|
# the method should put '_' between the name and 'id'.
|
@@ -253,6 +292,8 @@ class String
|
|
253
292
|
# 'Message'.foreign_key # => "message_id"
|
254
293
|
# 'Message'.foreign_key(false) # => "messageid"
|
255
294
|
# 'Admin::Post'.foreign_key # => "post_id"
|
295
|
+
#
|
296
|
+
# See ActiveSupport::Inflector.foreign_key.
|
256
297
|
def foreign_key(separate_class_name_and_id_with_underscore = true)
|
257
298
|
ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
|
258
299
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/string_inquirer"
|
4
|
+
require "active_support/environment_inquirer"
|
4
5
|
|
5
6
|
class String
|
6
|
-
# Wraps the current string in the
|
7
|
+
# Wraps the current string in the ActiveSupport::StringInquirer class,
|
7
8
|
# which gives you a prettier way to test for equality.
|
8
9
|
#
|
9
10
|
# env = 'production'.inquiry
|
@@ -47,9 +47,9 @@ class String
|
|
47
47
|
# iso_str.is_utf8? # => false
|
48
48
|
def is_utf8?
|
49
49
|
case encoding
|
50
|
-
when Encoding::UTF_8
|
50
|
+
when Encoding::UTF_8, Encoding::US_ASCII
|
51
51
|
valid_encoding?
|
52
|
-
when Encoding::ASCII_8BIT
|
52
|
+
when Encoding::ASCII_8BIT
|
53
53
|
dup.force_encoding(Encoding::UTF_8).valid_encoding?
|
54
54
|
else
|
55
55
|
false
|