activesupport 3.1.0 → 5.0.0
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 +7 -0
- data/CHANGELOG.md +798 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +13 -7
- data/lib/active_support/array_inquirer.rb +44 -0
- data/lib/active_support/backtrace_cleaner.rb +38 -34
- data/lib/active_support/benchmarkable.rb +17 -28
- data/lib/active_support/cache/file_store.rb +85 -70
- data/lib/active_support/cache/mem_cache_store.rb +75 -66
- data/lib/active_support/cache/memory_store.rb +31 -23
- data/lib/active_support/cache/null_store.rb +41 -0
- data/lib/active_support/cache/strategy/local_cache.rb +73 -70
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
- data/lib/active_support/cache.rb +360 -294
- data/lib/active_support/callbacks.rb +563 -393
- data/lib/active_support/concern.rb +42 -34
- data/lib/active_support/concurrency/latch.rb +19 -0
- data/lib/active_support/concurrency/share_lock.rb +186 -0
- data/lib/active_support/configurable.rb +70 -12
- data/lib/active_support/core_ext/array/access.rb +53 -9
- data/lib/active_support/core_ext/array/conversions.rb +109 -62
- data/lib/active_support/core_ext/array/extract_options.rb +2 -2
- data/lib/active_support/core_ext/array/grouping.rb +39 -32
- data/lib/active_support/core_ext/array/inquiry.rb +17 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -0
- data/lib/active_support/core_ext/array/wrap.rb +16 -18
- data/lib/active_support/core_ext/array.rb +2 -2
- data/lib/active_support/core_ext/benchmark.rb +7 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -36
- data/lib/active_support/core_ext/class/attribute.rb +47 -34
- data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -79
- data/lib/active_support/core_ext/class/subclasses.rb +12 -7
- data/lib/active_support/core_ext/class.rb +0 -3
- data/lib/active_support/core_ext/date/blank.rb +12 -0
- data/lib/active_support/core_ext/date/calculations.rb +57 -167
- data/lib/active_support/core_ext/date/conversions.rb +31 -42
- data/lib/active_support/core_ext/date/zones.rb +2 -10
- data/lib/active_support/core_ext/date.rb +5 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +335 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +1 -0
- data/lib/active_support/core_ext/date_time/blank.rb +12 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +132 -65
- data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +36 -34
- data/lib/active_support/core_ext/date_time.rb +5 -0
- data/lib/active_support/core_ext/digest/uuid.rb +51 -0
- data/lib/active_support/core_ext/enumerable.rb +81 -74
- data/lib/active_support/core_ext/file/atomic.rb +53 -26
- data/lib/active_support/core_ext/file.rb +0 -1
- data/lib/active_support/core_ext/hash/compact.rb +20 -0
- data/lib/active_support/core_ext/hash/conversions.rb +175 -70
- data/lib/active_support/core_ext/hash/deep_merge.rb +30 -8
- data/lib/active_support/core_ext/hash/except.rb +11 -12
- data/lib/active_support/core_ext/hash/indifferent_access.rb +7 -8
- data/lib/active_support/core_ext/hash/keys.rb +147 -24
- data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
- data/lib/active_support/core_ext/hash/slice.rb +22 -14
- data/lib/active_support/core_ext/hash/transform_values.rb +29 -0
- data/lib/active_support/core_ext/hash.rb +2 -2
- data/lib/active_support/core_ext/integer/inflections.rb +13 -1
- data/lib/active_support/core_ext/integer/multiple.rb +4 -0
- data/lib/active_support/core_ext/integer/time.rb +12 -22
- data/lib/active_support/core_ext/kernel/agnostics.rb +2 -2
- data/lib/active_support/core_ext/kernel/concern.rb +12 -0
- data/lib/active_support/core_ext/kernel/debugger.rb +2 -15
- data/lib/active_support/core_ext/kernel/reporting.rb +12 -62
- data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
- data/lib/active_support/core_ext/kernel.rb +2 -3
- data/lib/active_support/core_ext/load_error.rb +14 -7
- data/lib/active_support/core_ext/marshal.rb +22 -0
- data/lib/active_support/core_ext/module/aliasing.rb +16 -12
- data/lib/active_support/core_ext/module/anonymous.rb +12 -8
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
- data/lib/active_support/core_ext/module/attribute_accessors.rb +165 -13
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
- data/lib/active_support/core_ext/module/concerning.rb +135 -0
- data/lib/active_support/core_ext/module/delegation.rb +141 -68
- data/lib/active_support/core_ext/module/deprecation.rb +17 -3
- data/lib/active_support/core_ext/module/introspection.rb +9 -31
- data/lib/active_support/core_ext/module/method_transplanting.rb +3 -0
- data/lib/active_support/core_ext/module/qualified_const.rb +70 -0
- data/lib/active_support/core_ext/module/reachable.rb +1 -3
- data/lib/active_support/core_ext/module/remove_method.rb +24 -5
- data/lib/active_support/core_ext/module.rb +3 -3
- data/lib/active_support/core_ext/name_error.rb +15 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
- data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
- data/lib/active_support/core_ext/numeric/time.rb +31 -36
- data/lib/active_support/core_ext/numeric.rb +2 -0
- data/lib/active_support/core_ext/object/acts_like.rb +4 -4
- data/lib/active_support/core_ext/object/blank.rb +52 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +53 -0
- data/lib/active_support/core_ext/object/duplicable.rb +12 -20
- data/lib/active_support/core_ext/object/inclusion.rb +13 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
- data/lib/active_support/core_ext/object/json.rb +205 -0
- data/lib/active_support/core_ext/object/to_param.rb +1 -55
- data/lib/active_support/core_ext/object/to_query.rb +66 -9
- data/lib/active_support/core_ext/object/try.rb +124 -33
- data/lib/active_support/core_ext/object/with_options.rb +37 -11
- data/lib/active_support/core_ext/object.rb +2 -1
- data/lib/active_support/core_ext/range/conversions.rb +17 -7
- data/lib/active_support/core_ext/range/each.rb +21 -0
- data/lib/active_support/core_ext/range/include_range.rb +20 -18
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +23 -0
- data/lib/active_support/core_ext/string/access.rb +95 -90
- data/lib/active_support/core_ext/string/behavior.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +41 -38
- data/lib/active_support/core_ext/string/exclude.rb +6 -1
- data/lib/active_support/core_ext/string/filters.rb +70 -17
- data/lib/active_support/core_ext/string/indent.rb +43 -0
- data/lib/active_support/core_ext/string/inflections.rb +139 -59
- data/lib/active_support/core_ext/string/inquiry.rb +2 -2
- data/lib/active_support/core_ext/string/multibyte.rb +46 -65
- data/lib/active_support/core_ext/string/output_safety.rb +153 -56
- data/lib/active_support/core_ext/string/strip.rb +3 -6
- data/lib/active_support/core_ext/string/zones.rb +14 -0
- data/lib/active_support/core_ext/string.rb +2 -3
- data/lib/active_support/core_ext/struct.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +173 -173
- data/lib/active_support/core_ext/time/compatibility.rb +5 -0
- data/lib/active_support/core_ext/time/conversions.rb +33 -29
- data/lib/active_support/core_ext/time/marshal.rb +2 -56
- data/lib/active_support/core_ext/time/zones.rb +57 -32
- data/lib/active_support/core_ext/time.rb +5 -0
- data/lib/active_support/core_ext/uri.rb +13 -19
- data/lib/active_support/core_ext.rb +3 -2
- data/lib/active_support/dependencies/autoload.rb +47 -20
- data/lib/active_support/dependencies/interlock.rb +51 -0
- data/lib/active_support/dependencies.rb +315 -265
- data/lib/active_support/deprecation/behaviors.rb +71 -30
- data/lib/active_support/deprecation/instance_delegator.rb +24 -0
- data/lib/active_support/deprecation/method_wrappers.rb +59 -18
- data/lib/active_support/deprecation/proxy_wrappers.rb +82 -14
- data/lib/active_support/deprecation/reporting.rb +61 -14
- data/lib/active_support/deprecation.rb +38 -13
- data/lib/active_support/descendants_tracker.rb +34 -19
- data/lib/active_support/duration/iso8601_parser.rb +122 -0
- data/lib/active_support/duration/iso8601_serializer.rb +51 -0
- data/lib/active_support/duration.rb +85 -14
- data/lib/active_support/evented_file_update_checker.rb +194 -0
- data/lib/active_support/execution_wrapper.rb +117 -0
- data/lib/active_support/executor.rb +6 -0
- data/lib/active_support/file_update_checker.rb +138 -17
- data/lib/active_support/gem_version.rb +15 -0
- data/lib/active_support/gzip.rb +11 -5
- data/lib/active_support/hash_with_indifferent_access.rb +199 -49
- data/lib/active_support/i18n.rb +6 -2
- data/lib/active_support/i18n_railtie.rb +40 -21
- data/lib/active_support/inflections.rb +22 -13
- data/lib/active_support/inflector/inflections.rb +175 -144
- data/lib/active_support/inflector/methods.rb +328 -91
- data/lib/active_support/inflector/transliterate.rb +51 -37
- data/lib/active_support/json/decoding.rb +31 -22
- data/lib/active_support/json/encoding.rb +88 -248
- data/lib/active_support/key_generator.rb +71 -0
- data/lib/active_support/lazy_load_hooks.rb +27 -25
- data/lib/active_support/locale/en.yml +102 -3
- data/lib/active_support/log_subscriber/test_helper.rb +24 -21
- data/lib/active_support/log_subscriber.rb +36 -49
- data/lib/active_support/logger.rb +106 -0
- data/lib/active_support/logger_silence.rb +28 -0
- data/lib/active_support/logger_thread_safe_level.rb +31 -0
- data/lib/active_support/message_encryptor.rb +72 -36
- data/lib/active_support/message_verifier.rb +96 -24
- data/lib/active_support/multibyte/chars.rb +88 -333
- data/lib/active_support/multibyte/unicode.rb +156 -136
- data/lib/active_support/multibyte.rb +5 -28
- data/lib/active_support/notifications/fanout.rb +115 -19
- data/lib/active_support/notifications/instrumenter.rb +52 -15
- data/lib/active_support/notifications.rb +168 -33
- data/lib/active_support/number_helper/number_converter.rb +182 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +44 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +28 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +62 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +92 -0
- data/lib/active_support/number_helper.rb +368 -0
- data/lib/active_support/option_merger.rb +1 -1
- data/lib/active_support/ordered_hash.rb +18 -183
- data/lib/active_support/ordered_options.rb +44 -24
- data/lib/active_support/per_thread_registry.rb +58 -0
- data/lib/active_support/proxy_object.rb +13 -0
- data/lib/active_support/rails.rb +27 -0
- data/lib/active_support/railtie.rb +25 -34
- data/lib/active_support/reloader.rb +129 -0
- data/lib/active_support/rescuable.rb +98 -48
- data/lib/active_support/security_utils.rb +27 -0
- data/lib/active_support/string_inquirer.rb +14 -9
- data/lib/active_support/subscriber.rb +120 -0
- data/lib/active_support/tagged_logging.rb +78 -0
- data/lib/active_support/test_case.rb +69 -17
- data/lib/active_support/testing/assertions.rb +43 -41
- data/lib/active_support/testing/autorun.rb +12 -0
- data/lib/active_support/testing/constant_lookup.rb +50 -0
- data/lib/active_support/testing/declarative.rb +7 -21
- data/lib/active_support/testing/deprecation.rb +14 -33
- data/lib/active_support/testing/file_fixtures.rb +34 -0
- data/lib/active_support/testing/isolation.rb +53 -95
- data/lib/active_support/testing/method_call_assertions.rb +41 -0
- data/lib/active_support/testing/setup_and_teardown.rb +21 -82
- data/lib/active_support/testing/stream.rb +42 -0
- data/lib/active_support/testing/tagged_logging.rb +25 -0
- data/lib/active_support/testing/time_helpers.rb +134 -0
- data/lib/active_support/time.rb +6 -23
- data/lib/active_support/time_with_zone.rb +239 -92
- data/lib/active_support/values/time_zone.rb +236 -160
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +5 -7
- data/lib/active_support/xml_mini/jdom.rb +19 -13
- data/lib/active_support/xml_mini/libxml.rb +3 -4
- data/lib/active_support/xml_mini/libxmlsax.rb +2 -3
- data/lib/active_support/xml_mini/nokogiri.rb +3 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -3
- data/lib/active_support/xml_mini/rexml.rb +8 -10
- data/lib/active_support/xml_mini.rb +66 -34
- data/lib/active_support.rb +40 -23
- metadata +185 -134
- data/CHANGELOG +0 -1534
- data/lib/active_support/base64.rb +0 -42
- data/lib/active_support/basic_object.rb +0 -21
- data/lib/active_support/buffered_logger.rb +0 -137
- data/lib/active_support/cache/compressed_mem_cache_store.rb +0 -13
- data/lib/active_support/cache/synchronized_memory_store.rb +0 -11
- data/lib/active_support/core_ext/array/random_access.rb +0 -30
- data/lib/active_support/core_ext/array/uniq_by.rb +0 -16
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -44
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +0 -178
- data/lib/active_support/core_ext/date/freeze.rb +0 -31
- data/lib/active_support/core_ext/date_time/zones.rb +0 -21
- data/lib/active_support/core_ext/exception.rb +0 -3
- data/lib/active_support/core_ext/file/path.rb +0 -5
- data/lib/active_support/core_ext/float/rounding.rb +0 -19
- data/lib/active_support/core_ext/float.rb +0 -1
- data/lib/active_support/core_ext/hash/deep_dup.rb +0 -11
- data/lib/active_support/core_ext/hash/diff.rb +0 -13
- data/lib/active_support/core_ext/kernel/requires.rb +0 -28
- data/lib/active_support/core_ext/logger.rb +0 -81
- data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +0 -31
- data/lib/active_support/core_ext/module/method_names.rb +0 -14
- data/lib/active_support/core_ext/module/synchronization.rb +0 -43
- data/lib/active_support/core_ext/object/to_json.rb +0 -19
- data/lib/active_support/core_ext/proc.rb +0 -14
- data/lib/active_support/core_ext/process/daemon.rb +0 -23
- data/lib/active_support/core_ext/process.rb +0 -1
- data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
- data/lib/active_support/core_ext/range/cover.rb +0 -3
- data/lib/active_support/core_ext/rexml.rb +0 -46
- data/lib/active_support/core_ext/string/encoding.rb +0 -11
- data/lib/active_support/core_ext/string/interpolation.rb +0 -2
- data/lib/active_support/core_ext/string/xchar.rb +0 -18
- data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
- data/lib/active_support/file_watcher.rb +0 -36
- data/lib/active_support/json/variable.rb +0 -9
- data/lib/active_support/memoizable.rb +0 -105
- data/lib/active_support/multibyte/exceptions.rb +0 -8
- data/lib/active_support/multibyte/utils.rb +0 -60
- data/lib/active_support/ruby/shim.rb +0 -22
- data/lib/active_support/secure_random.rb +0 -6
- data/lib/active_support/testing/mochaing.rb +0 -7
- data/lib/active_support/testing/pending.rb +0 -52
- data/lib/active_support/testing/performance/jruby.rb +0 -115
- data/lib/active_support/testing/performance/rubinius.rb +0 -113
- data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
- data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
- data/lib/active_support/testing/performance/ruby.rb +0 -152
- data/lib/active_support/testing/performance.rb +0 -317
- data/lib/active_support/time/autoload.rb +0 -5
- data/lib/active_support/whiny_nil.rb +0 -60
@@ -1,25 +1,31 @@
|
|
1
|
-
|
1
|
+
require 'active_support/json'
|
2
2
|
require 'active_support/core_ext/string/access'
|
3
3
|
require 'active_support/core_ext/string/behavior'
|
4
|
+
require 'active_support/core_ext/module/delegation'
|
4
5
|
|
5
6
|
module ActiveSupport #:nodoc:
|
6
7
|
module Multibyte #:nodoc:
|
7
|
-
# Chars enables you to work transparently with UTF-8 encoding in the Ruby
|
8
|
-
# knowledge about the encoding. A
|
9
|
-
#
|
8
|
+
# Chars enables you to work transparently with UTF-8 encoding in the Ruby
|
9
|
+
# String class without having extensive knowledge about the encoding. A
|
10
|
+
# Chars object accepts a string upon initialization and proxies String
|
11
|
+
# methods in an encoding safe manner. All the normal String methods are also
|
12
|
+
# implemented on the proxy.
|
10
13
|
#
|
11
|
-
# String methods are proxied through the Chars object, and can be accessed
|
12
|
-
#
|
14
|
+
# String methods are proxied through the Chars object, and can be accessed
|
15
|
+
# through the +mb_chars+ method. Methods which would normally return a
|
16
|
+
# String object now return a Chars object so methods can be chained.
|
13
17
|
#
|
14
|
-
#
|
18
|
+
# 'The Perfect String '.mb_chars.downcase.strip.normalize # => "the perfect string"
|
15
19
|
#
|
16
|
-
# Chars objects are perfectly interchangeable with String objects as long as
|
17
|
-
#
|
20
|
+
# Chars objects are perfectly interchangeable with String objects as long as
|
21
|
+
# no explicit class checks are made. If certain methods do explicitly check
|
22
|
+
# the class, call +to_s+ before you pass chars objects to them.
|
18
23
|
#
|
19
|
-
# bad.explicit_checking_method
|
24
|
+
# bad.explicit_checking_method 'T'.mb_chars.downcase.to_s
|
20
25
|
#
|
21
|
-
# The default Chars implementation assumes that the encoding of the string
|
22
|
-
#
|
26
|
+
# The default Chars implementation assumes that the encoding of the string
|
27
|
+
# is UTF-8, if you want to handle different encodings you can write your own
|
28
|
+
# multibyte string handler and configure it through
|
23
29
|
# ActiveSupport::Multibyte.proxy_class.
|
24
30
|
#
|
25
31
|
# class CharsForUTF32
|
@@ -34,327 +40,106 @@ module ActiveSupport #:nodoc:
|
|
34
40
|
#
|
35
41
|
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
|
36
42
|
class Chars
|
43
|
+
include Comparable
|
37
44
|
attr_reader :wrapped_string
|
38
45
|
alias to_s wrapped_string
|
39
46
|
alias to_str wrapped_string
|
40
47
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
else
|
48
|
-
def initialize(string) #:nodoc:
|
49
|
-
@wrapped_string = string
|
50
|
-
end
|
48
|
+
delegate :<=>, :=~, :acts_like_string?, :to => :wrapped_string
|
49
|
+
|
50
|
+
# Creates a new Chars instance by wrapping _string_.
|
51
|
+
def initialize(string)
|
52
|
+
@wrapped_string = string
|
53
|
+
@wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
|
51
54
|
end
|
52
55
|
|
53
56
|
# Forward all undefined methods to the wrapped string.
|
54
57
|
def method_missing(method, *args, &block)
|
58
|
+
result = @wrapped_string.__send__(method, *args, &block)
|
55
59
|
if method.to_s =~ /!$/
|
56
|
-
|
57
|
-
self
|
60
|
+
self if result
|
58
61
|
else
|
59
|
-
result = @wrapped_string.__send__(method, *args, &block)
|
60
62
|
result.kind_of?(String) ? chars(result) : result
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
|
-
# Returns +true+ if _obj_ responds to the given method. Private methods
|
65
|
-
# only if the optional second parameter
|
66
|
-
|
67
|
-
|
66
|
+
# Returns +true+ if _obj_ responds to the given method. Private methods
|
67
|
+
# are included in the search only if the optional second parameter
|
68
|
+
# evaluates to +true+.
|
69
|
+
def respond_to_missing?(method, include_private)
|
70
|
+
@wrapped_string.respond_to?(method, include_private)
|
68
71
|
end
|
69
72
|
|
70
|
-
#
|
71
|
-
|
72
|
-
true
|
73
|
-
end
|
74
|
-
|
75
|
-
# Returns +true+ when the proxy class can handle the string. Returns +false+ otherwise.
|
73
|
+
# Returns +true+ when the proxy class can handle the string. Returns
|
74
|
+
# +false+ otherwise.
|
76
75
|
def self.consumes?(string)
|
77
|
-
|
78
|
-
string.unpack('U*')
|
79
|
-
true
|
80
|
-
rescue ArgumentError
|
81
|
-
false
|
82
|
-
end
|
83
|
-
|
84
|
-
include Comparable
|
85
|
-
|
86
|
-
# Returns -1, 0, or 1, depending on whether the Chars object is to be sorted before,
|
87
|
-
# equal or after the object on the right side of the operation. It accepts any object
|
88
|
-
# that implements +to_s+:
|
89
|
-
#
|
90
|
-
# 'é'.mb_chars <=> 'ü'.mb_chars # => -1
|
91
|
-
#
|
92
|
-
# See <tt>String#<=></tt> for more details.
|
93
|
-
def <=>(other)
|
94
|
-
@wrapped_string <=> other.to_s
|
95
|
-
end
|
96
|
-
|
97
|
-
if RUBY_VERSION < "1.9"
|
98
|
-
# Returns +true+ if the Chars class can and should act as a proxy for the string _string_. Returns
|
99
|
-
# +false+ otherwise.
|
100
|
-
def self.wants?(string)
|
101
|
-
$KCODE == 'UTF8' && consumes?(string)
|
102
|
-
end
|
103
|
-
|
104
|
-
# Returns a new Chars object containing the _other_ object concatenated to the string.
|
105
|
-
#
|
106
|
-
# Example:
|
107
|
-
# ('Café'.mb_chars + ' périferôl').to_s # => "Café périferôl"
|
108
|
-
def +(other)
|
109
|
-
chars(@wrapped_string + other)
|
110
|
-
end
|
111
|
-
|
112
|
-
# Like <tt>String#=~</tt> only it returns the character offset (in codepoints) instead of the byte offset.
|
113
|
-
#
|
114
|
-
# Example:
|
115
|
-
# 'Café périferôl'.mb_chars =~ /ô/ # => 12
|
116
|
-
def =~(other)
|
117
|
-
translate_offset(@wrapped_string =~ other)
|
118
|
-
end
|
119
|
-
|
120
|
-
# Inserts the passed string at specified codepoint offsets.
|
121
|
-
#
|
122
|
-
# Example:
|
123
|
-
# 'Café'.mb_chars.insert(4, ' périferôl').to_s # => "Café périferôl"
|
124
|
-
def insert(offset, fragment)
|
125
|
-
unpacked = Unicode.u_unpack(@wrapped_string)
|
126
|
-
unless offset > unpacked.length
|
127
|
-
@wrapped_string.replace(
|
128
|
-
Unicode.u_unpack(@wrapped_string).insert(offset, *Unicode.u_unpack(fragment)).pack('U*')
|
129
|
-
)
|
130
|
-
else
|
131
|
-
raise IndexError, "index #{offset} out of string"
|
132
|
-
end
|
133
|
-
self
|
134
|
-
end
|
135
|
-
|
136
|
-
# Returns +true+ if contained string contains _other_. Returns +false+ otherwise.
|
137
|
-
#
|
138
|
-
# Example:
|
139
|
-
# 'Café'.mb_chars.include?('é') # => true
|
140
|
-
def include?(other)
|
141
|
-
# We have to redefine this method because Enumerable defines it.
|
142
|
-
@wrapped_string.include?(other)
|
143
|
-
end
|
144
|
-
|
145
|
-
# Returns the position _needle_ in the string, counting in codepoints. Returns +nil+ if _needle_ isn't found.
|
146
|
-
#
|
147
|
-
# Example:
|
148
|
-
# 'Café périferôl'.mb_chars.index('ô') # => 12
|
149
|
-
# 'Café périferôl'.mb_chars.index(/\w/u) # => 0
|
150
|
-
def index(needle, offset=0)
|
151
|
-
wrapped_offset = first(offset).wrapped_string.length
|
152
|
-
index = @wrapped_string.index(needle, wrapped_offset)
|
153
|
-
index ? (Unicode.u_unpack(@wrapped_string.slice(0...index)).size) : nil
|
154
|
-
end
|
155
|
-
|
156
|
-
# Returns the position _needle_ in the string, counting in
|
157
|
-
# codepoints, searching backward from _offset_ or the end of the
|
158
|
-
# string. Returns +nil+ if _needle_ isn't found.
|
159
|
-
#
|
160
|
-
# Example:
|
161
|
-
# 'Café périferôl'.mb_chars.rindex('é') # => 6
|
162
|
-
# 'Café périferôl'.mb_chars.rindex(/\w/u) # => 13
|
163
|
-
def rindex(needle, offset=nil)
|
164
|
-
offset ||= length
|
165
|
-
wrapped_offset = first(offset).wrapped_string.length
|
166
|
-
index = @wrapped_string.rindex(needle, wrapped_offset)
|
167
|
-
index ? (Unicode.u_unpack(@wrapped_string.slice(0...index)).size) : nil
|
168
|
-
end
|
169
|
-
|
170
|
-
# Returns the number of codepoints in the string
|
171
|
-
def size
|
172
|
-
Unicode.u_unpack(@wrapped_string).size
|
173
|
-
end
|
174
|
-
alias_method :length, :size
|
175
|
-
|
176
|
-
# Strips entire range of Unicode whitespace from the right of the string.
|
177
|
-
def rstrip
|
178
|
-
chars(@wrapped_string.gsub(Unicode::TRAILERS_PAT, ''))
|
179
|
-
end
|
180
|
-
|
181
|
-
# Strips entire range of Unicode whitespace from the left of the string.
|
182
|
-
def lstrip
|
183
|
-
chars(@wrapped_string.gsub(Unicode::LEADERS_PAT, ''))
|
184
|
-
end
|
185
|
-
|
186
|
-
# Strips entire range of Unicode whitespace from the right and left of the string.
|
187
|
-
def strip
|
188
|
-
rstrip.lstrip
|
189
|
-
end
|
190
|
-
|
191
|
-
# Returns the codepoint of the first character in the string.
|
192
|
-
#
|
193
|
-
# Example:
|
194
|
-
# 'こんにちは'.mb_chars.ord # => 12371
|
195
|
-
def ord
|
196
|
-
Unicode.u_unpack(@wrapped_string)[0]
|
197
|
-
end
|
198
|
-
|
199
|
-
# Works just like <tt>String#rjust</tt>, only integer specifies characters instead of bytes.
|
200
|
-
#
|
201
|
-
# Example:
|
202
|
-
#
|
203
|
-
# "¾ cup".mb_chars.rjust(8).to_s
|
204
|
-
# # => " ¾ cup"
|
205
|
-
#
|
206
|
-
# "¾ cup".mb_chars.rjust(8, " ").to_s # Use non-breaking whitespace
|
207
|
-
# # => " ¾ cup"
|
208
|
-
def rjust(integer, padstr=' ')
|
209
|
-
justify(integer, :right, padstr)
|
210
|
-
end
|
211
|
-
|
212
|
-
# Works just like <tt>String#ljust</tt>, only integer specifies characters instead of bytes.
|
213
|
-
#
|
214
|
-
# Example:
|
215
|
-
#
|
216
|
-
# "¾ cup".mb_chars.rjust(8).to_s
|
217
|
-
# # => "¾ cup "
|
218
|
-
#
|
219
|
-
# "¾ cup".mb_chars.rjust(8, " ").to_s # Use non-breaking whitespace
|
220
|
-
# # => "¾ cup "
|
221
|
-
def ljust(integer, padstr=' ')
|
222
|
-
justify(integer, :left, padstr)
|
223
|
-
end
|
224
|
-
|
225
|
-
# Works just like <tt>String#center</tt>, only integer specifies characters instead of bytes.
|
226
|
-
#
|
227
|
-
# Example:
|
228
|
-
#
|
229
|
-
# "¾ cup".mb_chars.center(8).to_s
|
230
|
-
# # => " ¾ cup "
|
231
|
-
#
|
232
|
-
# "¾ cup".mb_chars.center(8, " ").to_s # Use non-breaking whitespace
|
233
|
-
# # => " ¾ cup "
|
234
|
-
def center(integer, padstr=' ')
|
235
|
-
justify(integer, :center, padstr)
|
236
|
-
end
|
237
|
-
|
238
|
-
else
|
239
|
-
def =~(other)
|
240
|
-
@wrapped_string =~ other
|
241
|
-
end
|
76
|
+
string.encoding == Encoding::UTF_8
|
242
77
|
end
|
243
78
|
|
244
|
-
# Works just like <tt>String#split</tt>, with the exception that the items
|
245
|
-
# instances instead of String. This makes
|
79
|
+
# Works just like <tt>String#split</tt>, with the exception that the items
|
80
|
+
# in the resulting list are Chars instances instead of String. This makes
|
81
|
+
# chaining methods easier.
|
246
82
|
#
|
247
|
-
# Example:
|
248
83
|
# 'Café périferôl'.mb_chars.split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"]
|
249
84
|
def split(*args)
|
250
|
-
@wrapped_string.split(*args).map { |i| i
|
85
|
+
@wrapped_string.split(*args).map { |i| self.class.new(i) }
|
251
86
|
end
|
252
87
|
|
253
|
-
#
|
254
|
-
#
|
255
|
-
#
|
256
|
-
#
|
257
|
-
# s = "Müller"
|
258
|
-
# s.mb_chars[2] = "e" # Replace character with offset 2
|
259
|
-
# s
|
260
|
-
# # => "Müeler"
|
88
|
+
# Works like <tt>String#slice!</tt>, but returns an instance of
|
89
|
+
# Chars, or nil if the string was not modified. The string will not be
|
90
|
+
# modified if the range given is out of bounds
|
261
91
|
#
|
262
|
-
#
|
263
|
-
#
|
264
|
-
#
|
265
|
-
# # => "
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
if
|
270
|
-
|
271
|
-
else
|
272
|
-
result = Unicode.u_unpack(@wrapped_string)
|
273
|
-
case args.first
|
274
|
-
when Fixnum
|
275
|
-
raise IndexError, "index #{args[0]} out of string" if args[0] >= result.length
|
276
|
-
min = args[0]
|
277
|
-
max = args[1].nil? ? min : (min + args[1] - 1)
|
278
|
-
range = Range.new(min, max)
|
279
|
-
replace_by = [replace_by].pack('U') if replace_by.is_a?(Fixnum)
|
280
|
-
when Range
|
281
|
-
raise RangeError, "#{args[0]} out of range" if args[0].min >= result.length
|
282
|
-
range = args[0]
|
283
|
-
else
|
284
|
-
needle = args[0].to_s
|
285
|
-
min = index(needle)
|
286
|
-
max = min + Unicode.u_unpack(needle).length - 1
|
287
|
-
range = Range.new(min, max)
|
288
|
-
end
|
289
|
-
result[range] = Unicode.u_unpack(replace_by)
|
290
|
-
@wrapped_string.replace(result.pack('U*'))
|
92
|
+
# string = 'Welcome'
|
93
|
+
# string.mb_chars.slice!(3) # => #<ActiveSupport::Multibyte::Chars:0x000000038109b8 @wrapped_string="c">
|
94
|
+
# string # => 'Welome'
|
95
|
+
# string.mb_chars.slice!(0..3) # => #<ActiveSupport::Multibyte::Chars:0x00000002eb80a0 @wrapped_string="Welo">
|
96
|
+
# string # => 'me'
|
97
|
+
def slice!(*args)
|
98
|
+
string_sliced = @wrapped_string.slice!(*args)
|
99
|
+
if string_sliced
|
100
|
+
chars(string_sliced)
|
291
101
|
end
|
292
102
|
end
|
293
103
|
|
294
104
|
# Reverses all characters in the string.
|
295
105
|
#
|
296
|
-
# Example:
|
297
106
|
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
|
298
107
|
def reverse
|
299
|
-
chars(Unicode.
|
300
|
-
end
|
301
|
-
|
302
|
-
# Implements Unicode-aware slice with codepoints. Slicing on one point returns the codepoints for that
|
303
|
-
# character.
|
304
|
-
#
|
305
|
-
# Example:
|
306
|
-
# 'こんにちは'.mb_chars.slice(2..3).to_s # => "にち"
|
307
|
-
def slice(*args)
|
308
|
-
if args.size > 2
|
309
|
-
raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" # Do as if we were native
|
310
|
-
elsif (args.size == 2 && !(args.first.is_a?(Numeric) || args.first.is_a?(Regexp)))
|
311
|
-
raise TypeError, "cannot convert #{args.first.class} into Integer" # Do as if we were native
|
312
|
-
elsif (args.size == 2 && !args[1].is_a?(Numeric))
|
313
|
-
raise TypeError, "cannot convert #{args[1].class} into Integer" # Do as if we were native
|
314
|
-
elsif args[0].kind_of? Range
|
315
|
-
cps = Unicode.u_unpack(@wrapped_string).slice(*args)
|
316
|
-
result = cps.nil? ? nil : cps.pack('U*')
|
317
|
-
elsif args[0].kind_of? Regexp
|
318
|
-
result = @wrapped_string.slice(*args)
|
319
|
-
elsif args.size == 1 && args[0].kind_of?(Numeric)
|
320
|
-
character = Unicode.u_unpack(@wrapped_string)[args[0]]
|
321
|
-
result = character && [character].pack('U')
|
322
|
-
else
|
323
|
-
cps = Unicode.u_unpack(@wrapped_string).slice(*args)
|
324
|
-
result = cps && cps.pack('U*')
|
325
|
-
end
|
326
|
-
result && chars(result)
|
108
|
+
chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack('U*'))
|
327
109
|
end
|
328
|
-
alias_method :[], :slice
|
329
110
|
|
330
|
-
#
|
331
|
-
# when the storage for a string is limited for some
|
111
|
+
# Limits the byte size of the string to a number of bytes without breaking
|
112
|
+
# characters. Usable when the storage for a string is limited for some
|
113
|
+
# reason.
|
332
114
|
#
|
333
|
-
# Example:
|
334
115
|
# 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
|
335
116
|
def limit(limit)
|
336
117
|
slice(0...translate_offset(limit))
|
337
118
|
end
|
338
119
|
|
339
|
-
#
|
120
|
+
# Converts characters in the string to uppercase.
|
340
121
|
#
|
341
|
-
# Example:
|
342
122
|
# 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
|
343
123
|
def upcase
|
344
|
-
chars
|
124
|
+
chars Unicode.upcase(@wrapped_string)
|
345
125
|
end
|
346
126
|
|
347
|
-
#
|
127
|
+
# Converts characters in the string to lowercase.
|
348
128
|
#
|
349
|
-
# Example:
|
350
129
|
# 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
|
351
130
|
def downcase
|
352
|
-
chars
|
131
|
+
chars Unicode.downcase(@wrapped_string)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Converts characters in the string to the opposite case.
|
135
|
+
#
|
136
|
+
# 'El Cañón".mb_chars.swapcase.to_s # => "eL cAÑÓN"
|
137
|
+
def swapcase
|
138
|
+
chars Unicode.swapcase(@wrapped_string)
|
353
139
|
end
|
354
140
|
|
355
141
|
# Converts the first character to uppercase and the remainder to lowercase.
|
356
142
|
#
|
357
|
-
# Example:
|
358
143
|
# 'über'.mb_chars.capitalize.to_s # => "Über"
|
359
144
|
def capitalize
|
360
145
|
(slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase
|
@@ -362,16 +147,16 @@ module ActiveSupport #:nodoc:
|
|
362
147
|
|
363
148
|
# Capitalizes the first letter of every word, when possible.
|
364
149
|
#
|
365
|
-
# Example:
|
366
150
|
# "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
|
367
151
|
# "日本語".mb_chars.titleize # => "日本語"
|
368
152
|
def titleize
|
369
|
-
chars(downcase.to_s.gsub(/\b('
|
153
|
+
chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1)})
|
370
154
|
end
|
371
155
|
alias_method :titlecase, :titleize
|
372
156
|
|
373
|
-
# Returns the KC normalization of the string by default. NFKC is
|
374
|
-
# passing strings to databases
|
157
|
+
# Returns the KC normalization of the string by default. NFKC is
|
158
|
+
# considered the best normalization form for passing strings to databases
|
159
|
+
# and validations.
|
375
160
|
#
|
376
161
|
# * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
|
377
162
|
# <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
|
@@ -382,46 +167,45 @@ module ActiveSupport #:nodoc:
|
|
382
167
|
|
383
168
|
# Performs canonical decomposition on all the characters.
|
384
169
|
#
|
385
|
-
# Example:
|
386
170
|
# 'é'.length # => 2
|
387
171
|
# 'é'.mb_chars.decompose.to_s.length # => 3
|
388
172
|
def decompose
|
389
|
-
chars(Unicode.
|
173
|
+
chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack('U*'))
|
390
174
|
end
|
391
175
|
|
392
176
|
# Performs composition on all the characters.
|
393
177
|
#
|
394
|
-
# Example:
|
395
178
|
# 'é'.length # => 3
|
396
179
|
# 'é'.mb_chars.compose.to_s.length # => 2
|
397
180
|
def compose
|
398
|
-
chars(Unicode.
|
181
|
+
chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack('U*'))
|
399
182
|
end
|
400
183
|
|
401
184
|
# Returns the number of grapheme clusters in the string.
|
402
185
|
#
|
403
|
-
# Example:
|
404
186
|
# 'क्षि'.mb_chars.length # => 4
|
405
|
-
# 'क्षि'.mb_chars.
|
406
|
-
def
|
407
|
-
Unicode.
|
187
|
+
# 'क्षि'.mb_chars.grapheme_length # => 3
|
188
|
+
def grapheme_length
|
189
|
+
Unicode.unpack_graphemes(@wrapped_string).length
|
408
190
|
end
|
409
191
|
|
410
|
-
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
192
|
+
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
193
|
+
# resulting in a valid UTF-8 string.
|
411
194
|
#
|
412
|
-
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
|
195
|
+
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
|
196
|
+
# encoding is entirely CP1252 or ISO-8859-1.
|
413
197
|
def tidy_bytes(force = false)
|
414
198
|
chars(Unicode.tidy_bytes(@wrapped_string, force))
|
415
199
|
end
|
416
200
|
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
201
|
+
def as_json(options = nil) #:nodoc:
|
202
|
+
to_s.as_json(options)
|
203
|
+
end
|
204
|
+
|
205
|
+
%w(capitalize downcase reverse tidy_bytes upcase).each do |method|
|
206
|
+
define_method("#{method}!") do |*args|
|
207
|
+
@wrapped_string = send(method, *args).to_s
|
208
|
+
self
|
425
209
|
end
|
426
210
|
end
|
427
211
|
|
@@ -431,43 +215,14 @@ module ActiveSupport #:nodoc:
|
|
431
215
|
return nil if byte_offset.nil?
|
432
216
|
return 0 if @wrapped_string == ''
|
433
217
|
|
434
|
-
if @wrapped_string.respond_to?(:force_encoding)
|
435
|
-
@wrapped_string = @wrapped_string.dup.force_encoding(Encoding::ASCII_8BIT)
|
436
|
-
end
|
437
|
-
|
438
218
|
begin
|
439
|
-
@wrapped_string
|
219
|
+
@wrapped_string.byteslice(0...byte_offset).unpack('U*').length
|
440
220
|
rescue ArgumentError
|
441
221
|
byte_offset -= 1
|
442
222
|
retry
|
443
223
|
end
|
444
224
|
end
|
445
225
|
|
446
|
-
def justify(integer, way, padstr=' ') #:nodoc:
|
447
|
-
raise ArgumentError, "zero width padding" if padstr.length == 0
|
448
|
-
padsize = integer - size
|
449
|
-
padsize = padsize > 0 ? padsize : 0
|
450
|
-
case way
|
451
|
-
when :right
|
452
|
-
result = @wrapped_string.dup.insert(0, padding(padsize, padstr))
|
453
|
-
when :left
|
454
|
-
result = @wrapped_string.dup.insert(-1, padding(padsize, padstr))
|
455
|
-
when :center
|
456
|
-
lpad = padding((padsize / 2.0).floor, padstr)
|
457
|
-
rpad = padding((padsize / 2.0).ceil, padstr)
|
458
|
-
result = @wrapped_string.dup.insert(0, lpad).insert(-1, rpad)
|
459
|
-
end
|
460
|
-
chars(result)
|
461
|
-
end
|
462
|
-
|
463
|
-
def padding(padsize, padstr=' ') #:nodoc:
|
464
|
-
if padsize != 0
|
465
|
-
chars(padstr * ((padsize / Unicode.u_unpack(padstr).size) + 1)).slice(0, padsize)
|
466
|
-
else
|
467
|
-
''
|
468
|
-
end
|
469
|
-
end
|
470
|
-
|
471
226
|
def chars(string) #:nodoc:
|
472
227
|
self.class.new(string)
|
473
228
|
end
|