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,21 +1,21 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
module ActiveSupport
|
3
2
|
module Multibyte
|
4
3
|
module Unicode
|
5
4
|
|
6
5
|
extend self
|
7
6
|
|
8
|
-
# A list of all available normalization forms.
|
7
|
+
# A list of all available normalization forms.
|
8
|
+
# See http://www.unicode.org/reports/tr15/tr15-29.html for more
|
9
9
|
# information about normalization.
|
10
10
|
NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
|
11
11
|
|
12
12
|
# The Unicode version that is supported by the implementation
|
13
|
-
UNICODE_VERSION = '
|
13
|
+
UNICODE_VERSION = '8.0.0'
|
14
14
|
|
15
|
-
# The default normalization used for operations that require
|
16
|
-
#
|
15
|
+
# The default normalization used for operations that require
|
16
|
+
# normalization. It can be set to any of the normalizations
|
17
|
+
# in NORMALIZATION_FORMS.
|
17
18
|
#
|
18
|
-
# Example:
|
19
19
|
# ActiveSupport::Multibyte::Unicode.default_normalization_form = :c
|
20
20
|
attr_accessor :default_normalization_form
|
21
21
|
@default_normalization_form = :kc
|
@@ -41,7 +41,6 @@ module ActiveSupport
|
|
41
41
|
0x0085, # White_Space # Cc <control-0085>
|
42
42
|
0x00A0, # White_Space # Zs NO-BREAK SPACE
|
43
43
|
0x1680, # White_Space # Zs OGHAM SPACE MARK
|
44
|
-
0x180E, # White_Space # Zs MONGOLIAN VOWEL SEPARATOR
|
45
44
|
(0x2000..0x200A).to_a, # White_Space # Zs [11] EN QUAD..HAIR SPACE
|
46
45
|
0x2028, # White_Space # Zl LINE SEPARATOR
|
47
46
|
0x2029, # White_Space # Zp PARAGRAPH SEPARATOR
|
@@ -50,32 +49,22 @@ module ActiveSupport
|
|
50
49
|
0x3000, # White_Space # Zs IDEOGRAPHIC SPACE
|
51
50
|
].flatten.freeze
|
52
51
|
|
53
|
-
# BOM (byte order mark) can also be seen as whitespace, it's a
|
54
|
-
#
|
52
|
+
# BOM (byte order mark) can also be seen as whitespace, it's a
|
53
|
+
# non-rendering character used to distinguish between little and big
|
54
|
+
# endian. This is not an issue in utf-8, so it must be ignored.
|
55
55
|
LEADERS_AND_TRAILERS = WHITESPACE + [65279] # ZERO-WIDTH NO-BREAK SPACE aka BOM
|
56
56
|
|
57
|
-
# Returns a regular expression pattern that matches the passed Unicode
|
57
|
+
# Returns a regular expression pattern that matches the passed Unicode
|
58
|
+
# codepoints.
|
58
59
|
def self.codepoints_to_pattern(array_of_codepoints) #:nodoc:
|
59
|
-
array_of_codepoints.collect{ |e| [e].pack 'U*' }.join('|')
|
60
|
+
array_of_codepoints.collect{ |e| [e].pack 'U*'.freeze }.join('|'.freeze)
|
60
61
|
end
|
61
62
|
TRAILERS_PAT = /(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+\Z/u
|
62
63
|
LEADERS_PAT = /\A(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+/u
|
63
64
|
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
# Example:
|
68
|
-
# Unicode.u_unpack('Café') # => [67, 97, 102, 233]
|
69
|
-
def u_unpack(string)
|
70
|
-
begin
|
71
|
-
string.unpack 'U*'
|
72
|
-
rescue ArgumentError
|
73
|
-
raise EncodingError, 'malformed UTF-8 character'
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Detect whether the codepoint is in a certain character class. Returns +true+ when it's in the specified
|
78
|
-
# character class and +false+ otherwise. Valid character classes are: <tt>:cr</tt>, <tt>:lf</tt>, <tt>:l</tt>,
|
65
|
+
# Detect whether the codepoint is in a certain character class. Returns
|
66
|
+
# +true+ when it's in the specified character class and +false+ otherwise.
|
67
|
+
# Valid character classes are: <tt>:cr</tt>, <tt>:lf</tt>, <tt>:l</tt>,
|
79
68
|
# <tt>:v</tt>, <tt>:lv</tt>, <tt>:lvt</tt> and <tt>:t</tt>.
|
80
69
|
#
|
81
70
|
# Primarily used by the grapheme cluster support.
|
@@ -83,13 +72,13 @@ module ActiveSupport
|
|
83
72
|
classes.detect { |c| database.boundary[c] === codepoint } ? true : false
|
84
73
|
end
|
85
74
|
|
86
|
-
# Unpack the string at grapheme boundaries. Returns a list of character
|
75
|
+
# Unpack the string at grapheme boundaries. Returns a list of character
|
76
|
+
# lists.
|
87
77
|
#
|
88
|
-
#
|
89
|
-
# Unicode.
|
90
|
-
|
91
|
-
|
92
|
-
codepoints = u_unpack(string)
|
78
|
+
# Unicode.unpack_graphemes('क्षि') # => [[2325, 2381], [2359], [2367]]
|
79
|
+
# Unicode.unpack_graphemes('Café') # => [[67], [97], [102], [233]]
|
80
|
+
def unpack_graphemes(string)
|
81
|
+
codepoints = string.codepoints.to_a
|
93
82
|
unpacked = []
|
94
83
|
pos = 0
|
95
84
|
marker = 0
|
@@ -98,19 +87,44 @@ module ActiveSupport
|
|
98
87
|
pos += 1
|
99
88
|
previous = codepoints[pos-1]
|
100
89
|
current = codepoints[pos]
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
)
|
113
|
-
|
90
|
+
|
91
|
+
should_break =
|
92
|
+
# GB3. CR X LF
|
93
|
+
if previous == database.boundary[:cr] and current == database.boundary[:lf]
|
94
|
+
false
|
95
|
+
# GB4. (Control|CR|LF) ÷
|
96
|
+
elsif previous and in_char_class?(previous, [:control,:cr,:lf])
|
97
|
+
true
|
98
|
+
# GB5. ÷ (Control|CR|LF)
|
99
|
+
elsif in_char_class?(current, [:control,:cr,:lf])
|
100
|
+
true
|
101
|
+
# GB6. L X (L|V|LV|LVT)
|
102
|
+
elsif database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt])
|
103
|
+
false
|
104
|
+
# GB7. (LV|V) X (V|T)
|
105
|
+
elsif in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t])
|
106
|
+
false
|
107
|
+
# GB8. (LVT|T) X (T)
|
108
|
+
elsif in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current
|
109
|
+
false
|
110
|
+
# GB8a. Regional_Indicator X Regional_Indicator
|
111
|
+
elsif database.boundary[:regional_indicator] === previous and database.boundary[:regional_indicator] === current
|
112
|
+
false
|
113
|
+
# GB9. X Extend
|
114
|
+
elsif database.boundary[:extend] === current
|
115
|
+
false
|
116
|
+
# GB9a. X SpacingMark
|
117
|
+
elsif database.boundary[:spacingmark] === current
|
118
|
+
false
|
119
|
+
# GB9b. Prepend X
|
120
|
+
elsif database.boundary[:prepend] === previous
|
121
|
+
false
|
122
|
+
# GB10. Any ÷ Any
|
123
|
+
else
|
124
|
+
true
|
125
|
+
end
|
126
|
+
|
127
|
+
if should_break
|
114
128
|
unpacked << codepoints[marker..pos-1]
|
115
129
|
marker = pos
|
116
130
|
end
|
@@ -118,12 +132,11 @@ module ActiveSupport
|
|
118
132
|
unpacked
|
119
133
|
end
|
120
134
|
|
121
|
-
# Reverse operation of
|
135
|
+
# Reverse operation of unpack_graphemes.
|
122
136
|
#
|
123
|
-
#
|
124
|
-
|
125
|
-
|
126
|
-
(unpacked.flatten).pack('U*')
|
137
|
+
# Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि'
|
138
|
+
def pack_graphemes(unpacked)
|
139
|
+
unpacked.flatten.pack('U*')
|
127
140
|
end
|
128
141
|
|
129
142
|
# Re-order codepoints so the string becomes canonical.
|
@@ -143,7 +156,7 @@ module ActiveSupport
|
|
143
156
|
end
|
144
157
|
|
145
158
|
# Decompose composed characters to the decomposed form.
|
146
|
-
def
|
159
|
+
def decompose(type, codepoints)
|
147
160
|
codepoints.inject([]) do |decomposed, cp|
|
148
161
|
# if it's a hangul syllable starter character
|
149
162
|
if HANGUL_SBASE <= cp and cp < HANGUL_SLAST
|
@@ -155,8 +168,8 @@ module ActiveSupport
|
|
155
168
|
ncp << (HANGUL_TBASE + tindex) unless tindex == 0
|
156
169
|
decomposed.concat ncp
|
157
170
|
# if the codepoint is decomposable in with the current decomposition type
|
158
|
-
elsif (ncp = database.codepoints[cp].decomp_mapping) and (!database.codepoints[cp].decomp_type || type == :
|
159
|
-
decomposed.concat
|
171
|
+
elsif (ncp = database.codepoints[cp].decomp_mapping) and (!database.codepoints[cp].decomp_type || type == :compatibility)
|
172
|
+
decomposed.concat decompose(type, ncp.dup)
|
160
173
|
else
|
161
174
|
decomposed << cp
|
162
175
|
end
|
@@ -164,7 +177,7 @@ module ActiveSupport
|
|
164
177
|
end
|
165
178
|
|
166
179
|
# Compose decomposed characters to the composed form.
|
167
|
-
def
|
180
|
+
def compose(codepoints)
|
168
181
|
pos = 0
|
169
182
|
eoa = codepoints.length - 1
|
170
183
|
starter_pos = 0
|
@@ -222,99 +235,100 @@ module ActiveSupport
|
|
222
235
|
codepoints
|
223
236
|
end
|
224
237
|
|
225
|
-
#
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
238
|
+
# Rubinius' String#scrub, however, doesn't support ASCII-incompatible chars.
|
239
|
+
if !defined?(Rubinius)
|
240
|
+
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
241
|
+
# resulting in a valid UTF-8 string.
|
242
|
+
#
|
243
|
+
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
|
244
|
+
# encoding is entirely CP1252 or ISO-8859-1.
|
245
|
+
def tidy_bytes(string, force = false)
|
246
|
+
return string if string.empty?
|
247
|
+
return recode_windows1252_chars(string) if force
|
248
|
+
string.scrub { |bad| recode_windows1252_chars(bad) }
|
233
249
|
end
|
250
|
+
else
|
251
|
+
def tidy_bytes(string, force = false)
|
252
|
+
return string if string.empty?
|
253
|
+
return recode_windows1252_chars(string) if force
|
254
|
+
|
255
|
+
# We can't transcode to the same format, so we choose a nearly-identical encoding.
|
256
|
+
# We're going to 'transcode' bytes from UTF-8 when possible, then fall back to
|
257
|
+
# CP1252 when we get errors. The final string will be 'converted' back to UTF-8
|
258
|
+
# before returning.
|
259
|
+
reader = Encoding::Converter.new(Encoding::UTF_8, Encoding::UTF_16LE)
|
260
|
+
|
261
|
+
source = string.dup
|
262
|
+
out = ''.force_encoding(Encoding::UTF_16LE)
|
263
|
+
|
264
|
+
loop do
|
265
|
+
reader.primitive_convert(source, out)
|
266
|
+
_, _, _, error_bytes, _ = reader.primitive_errinfo
|
267
|
+
break if error_bytes.nil?
|
268
|
+
out << error_bytes.encode(Encoding::UTF_16LE, Encoding::Windows_1252, invalid: :replace, undef: :replace)
|
269
|
+
end
|
234
270
|
|
235
|
-
|
236
|
-
conts_expected = 0
|
237
|
-
last_lead = 0
|
238
|
-
|
239
|
-
bytes.each_index do |i|
|
240
|
-
|
241
|
-
byte = bytes[i]
|
242
|
-
is_cont = byte > 127 && byte < 192
|
243
|
-
is_lead = byte > 191 && byte < 245
|
244
|
-
is_unused = byte > 240
|
245
|
-
is_restricted = byte > 244
|
271
|
+
reader.finish
|
246
272
|
|
247
|
-
|
248
|
-
if is_unused || is_restricted
|
249
|
-
bytes[i] = tidy_byte(byte)
|
250
|
-
elsif is_cont
|
251
|
-
# Not expecting continuation byte? Clean up. Otherwise, now expect one less.
|
252
|
-
conts_expected == 0 ? bytes[i] = tidy_byte(byte) : conts_expected -= 1
|
253
|
-
else
|
254
|
-
if conts_expected > 0
|
255
|
-
# Expected continuation, but got ASCII or leading? Clean backwards up to
|
256
|
-
# the leading byte.
|
257
|
-
(1..(i - last_lead)).each {|j| bytes[i - j] = tidy_byte(bytes[i - j])}
|
258
|
-
conts_expected = 0
|
259
|
-
end
|
260
|
-
if is_lead
|
261
|
-
# Final byte is leading? Clean it.
|
262
|
-
if i == bytes.length - 1
|
263
|
-
bytes[i] = tidy_byte(bytes.last)
|
264
|
-
else
|
265
|
-
# Valid leading byte? Expect continuations determined by position of
|
266
|
-
# first zero bit, with max of 3.
|
267
|
-
conts_expected = byte < 224 ? 1 : byte < 240 ? 2 : 3
|
268
|
-
last_lead = i
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
273
|
+
out.encode!(Encoding::UTF_8)
|
272
274
|
end
|
273
|
-
bytes.empty? ? "" : bytes.flatten.compact.pack("C*").unpack("U*").pack("U*")
|
274
275
|
end
|
275
276
|
|
276
|
-
# Returns the KC normalization of the string by default. NFKC is
|
277
|
-
# passing strings to databases
|
277
|
+
# Returns the KC normalization of the string by default. NFKC is
|
278
|
+
# considered the best normalization form for passing strings to databases
|
279
|
+
# and validations.
|
278
280
|
#
|
279
281
|
# * <tt>string</tt> - The string to perform normalization on.
|
280
|
-
# * <tt>form</tt> - The form you want to normalize in. Should be one of
|
281
|
-
# <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>.
|
282
|
-
# ActiveSupport::Multibyte.default_normalization_form
|
282
|
+
# * <tt>form</tt> - The form you want to normalize in. Should be one of
|
283
|
+
# the following: <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>.
|
284
|
+
# Default is ActiveSupport::Multibyte::Unicode.default_normalization_form.
|
283
285
|
def normalize(string, form=nil)
|
284
286
|
form ||= @default_normalization_form
|
285
287
|
# See http://www.unicode.org/reports/tr15, Table 1
|
286
|
-
codepoints =
|
288
|
+
codepoints = string.codepoints.to_a
|
287
289
|
case form
|
288
290
|
when :d
|
289
|
-
reorder_characters(
|
291
|
+
reorder_characters(decompose(:canonical, codepoints))
|
290
292
|
when :c
|
291
|
-
|
293
|
+
compose(reorder_characters(decompose(:canonical, codepoints)))
|
292
294
|
when :kd
|
293
|
-
reorder_characters(
|
295
|
+
reorder_characters(decompose(:compatibility, codepoints))
|
294
296
|
when :kc
|
295
|
-
|
297
|
+
compose(reorder_characters(decompose(:compatibility, codepoints)))
|
296
298
|
else
|
297
299
|
raise ArgumentError, "#{form} is not a valid normalization variant", caller
|
298
|
-
end.pack('U*')
|
300
|
+
end.pack('U*'.freeze)
|
299
301
|
end
|
300
302
|
|
301
|
-
def
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
303
|
+
def downcase(string)
|
304
|
+
apply_mapping string, :lowercase_mapping
|
305
|
+
end
|
306
|
+
|
307
|
+
def upcase(string)
|
308
|
+
apply_mapping string, :uppercase_mapping
|
309
|
+
end
|
310
|
+
|
311
|
+
def swapcase(string)
|
312
|
+
apply_mapping string, :swapcase_mapping
|
310
313
|
end
|
311
314
|
|
312
|
-
# Holds data about a codepoint in the Unicode database
|
315
|
+
# Holds data about a codepoint in the Unicode database.
|
313
316
|
class Codepoint
|
314
317
|
attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
|
318
|
+
|
319
|
+
# Initializing Codepoint object with default values
|
320
|
+
def initialize
|
321
|
+
@combining_class = 0
|
322
|
+
@uppercase_mapping = 0
|
323
|
+
@lowercase_mapping = 0
|
324
|
+
end
|
325
|
+
|
326
|
+
def swapcase_mapping
|
327
|
+
uppercase_mapping > 0 ? uppercase_mapping : lowercase_mapping
|
328
|
+
end
|
315
329
|
end
|
316
330
|
|
317
|
-
# Holds static data from the Unicode database
|
331
|
+
# Holds static data from the Unicode database.
|
318
332
|
class UnicodeDatabase
|
319
333
|
ATTRIBUTES = :codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252
|
320
334
|
|
@@ -338,16 +352,17 @@ module ActiveSupport
|
|
338
352
|
EOS
|
339
353
|
end
|
340
354
|
|
341
|
-
# Loads the Unicode database and returns all the internal objects of
|
355
|
+
# Loads the Unicode database and returns all the internal objects of
|
356
|
+
# UnicodeDatabase.
|
342
357
|
def load
|
343
358
|
begin
|
344
359
|
@codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read }
|
345
|
-
rescue
|
346
|
-
|
360
|
+
rescue => e
|
361
|
+
raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable")
|
347
362
|
end
|
348
363
|
|
349
364
|
# Redefine the === method so we can write shorter rules for grapheme cluster breaks
|
350
|
-
@boundary.
|
365
|
+
@boundary.each_key do |k|
|
351
366
|
@boundary[k].instance_eval do
|
352
367
|
def ===(other)
|
353
368
|
detect { |i| i === other } ? true : false
|
@@ -361,12 +376,12 @@ module ActiveSupport
|
|
361
376
|
end
|
362
377
|
end
|
363
378
|
|
364
|
-
# Returns the directory in which the data files are stored
|
379
|
+
# Returns the directory in which the data files are stored.
|
365
380
|
def self.dirname
|
366
381
|
File.dirname(__FILE__) + '/../values/'
|
367
382
|
end
|
368
383
|
|
369
|
-
# Returns the filename for the data file for this version
|
384
|
+
# Returns the filename for the data file for this version.
|
370
385
|
def self.filename
|
371
386
|
File.expand_path File.join(dirname, "unicode_tables.dat")
|
372
387
|
end
|
@@ -374,20 +389,25 @@ module ActiveSupport
|
|
374
389
|
|
375
390
|
private
|
376
391
|
|
377
|
-
def
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
392
|
+
def apply_mapping(string, mapping) #:nodoc:
|
393
|
+
database.codepoints
|
394
|
+
string.each_codepoint.map do |codepoint|
|
395
|
+
cp = database.codepoints[codepoint]
|
396
|
+
if cp and (ncp = cp.send(mapping)) and ncp > 0
|
397
|
+
ncp
|
398
|
+
else
|
399
|
+
codepoint
|
400
|
+
end
|
401
|
+
end.pack('U*')
|
402
|
+
end
|
403
|
+
|
404
|
+
def recode_windows1252_chars(string)
|
405
|
+
string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
|
385
406
|
end
|
386
407
|
|
387
408
|
def database
|
388
409
|
@database ||= UnicodeDatabase.new
|
389
410
|
end
|
390
|
-
|
391
411
|
end
|
392
412
|
end
|
393
413
|
end
|
@@ -1,44 +1,21 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'active_support/core_ext/module/attribute_accessors'
|
3
|
-
|
4
1
|
module ActiveSupport #:nodoc:
|
5
2
|
module Multibyte
|
6
|
-
autoload :EncodingError, 'active_support/multibyte/exceptions'
|
7
3
|
autoload :Chars, 'active_support/multibyte/chars'
|
8
4
|
autoload :Unicode, 'active_support/multibyte/unicode'
|
9
5
|
|
10
|
-
# The proxy class returned when calling mb_chars. You can use this accessor
|
11
|
-
# class so you can support other encodings. See
|
12
|
-
# an example how to
|
6
|
+
# The proxy class returned when calling mb_chars. You can use this accessor
|
7
|
+
# to configure your own proxy class so you can support other encodings. See
|
8
|
+
# the ActiveSupport::Multibyte::Chars implementation for an example how to
|
9
|
+
# do this.
|
13
10
|
#
|
14
|
-
# Example:
|
15
11
|
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
|
16
12
|
def self.proxy_class=(klass)
|
17
13
|
@proxy_class = klass
|
18
14
|
end
|
19
15
|
|
20
|
-
# Returns the current proxy class
|
16
|
+
# Returns the current proxy class.
|
21
17
|
def self.proxy_class
|
22
18
|
@proxy_class ||= ActiveSupport::Multibyte::Chars
|
23
19
|
end
|
24
|
-
|
25
|
-
# Regular expressions that describe valid byte sequences for a character
|
26
|
-
VALID_CHARACTER = {
|
27
|
-
# Borrowed from the Kconv library by Shinji KONO - (also as seen on the W3C site)
|
28
|
-
'UTF-8' => /\A(?:
|
29
|
-
[\x00-\x7f] |
|
30
|
-
[\xc2-\xdf] [\x80-\xbf] |
|
31
|
-
\xe0 [\xa0-\xbf] [\x80-\xbf] |
|
32
|
-
[\xe1-\xef] [\x80-\xbf] [\x80-\xbf] |
|
33
|
-
\xf0 [\x90-\xbf] [\x80-\xbf] [\x80-\xbf] |
|
34
|
-
[\xf1-\xf3] [\x80-\xbf] [\x80-\xbf] [\x80-\xbf] |
|
35
|
-
\xf4 [\x80-\x8f] [\x80-\xbf] [\x80-\xbf])\z /xn,
|
36
|
-
# Quick check for valid Shift-JIS characters, disregards the odd-even pairing
|
37
|
-
'Shift_JIS' => /\A(?:
|
38
|
-
[\x00-\x7e\xa1-\xdf] |
|
39
|
-
[\x81-\x9f\xe0-\xef] [\x40-\x7e\x80-\x9e\x9f-\xfc])\z /xn
|
40
|
-
}
|
41
20
|
end
|
42
21
|
end
|
43
|
-
|
44
|
-
require 'active_support/multibyte/utils'
|
@@ -1,24 +1,49 @@
|
|
1
|
+
require 'mutex_m'
|
2
|
+
require 'concurrent/map'
|
3
|
+
|
1
4
|
module ActiveSupport
|
2
5
|
module Notifications
|
3
6
|
# This is a default queue implementation that ships with Notifications.
|
4
7
|
# It just pushes events to all registered log subscribers.
|
8
|
+
#
|
9
|
+
# This class is thread safe. All methods are reentrant.
|
5
10
|
class Fanout
|
11
|
+
include Mutex_m
|
12
|
+
|
6
13
|
def initialize
|
7
14
|
@subscribers = []
|
8
|
-
@listeners_for =
|
15
|
+
@listeners_for = Concurrent::Map.new
|
16
|
+
super
|
9
17
|
end
|
10
18
|
|
11
19
|
def subscribe(pattern = nil, block = Proc.new)
|
12
|
-
subscriber =
|
13
|
-
|
20
|
+
subscriber = Subscribers.new pattern, block
|
21
|
+
synchronize do
|
22
|
+
@subscribers << subscriber
|
23
|
+
@listeners_for.clear
|
14
24
|
end
|
15
|
-
@listeners_for.clear
|
16
25
|
subscriber
|
17
26
|
end
|
18
27
|
|
19
|
-
def unsubscribe(
|
20
|
-
|
21
|
-
|
28
|
+
def unsubscribe(subscriber_or_name)
|
29
|
+
synchronize do
|
30
|
+
case subscriber_or_name
|
31
|
+
when String
|
32
|
+
@subscribers.reject! { |s| s.matches?(subscriber_or_name) }
|
33
|
+
else
|
34
|
+
@subscribers.delete(subscriber_or_name)
|
35
|
+
end
|
36
|
+
|
37
|
+
@listeners_for.clear
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def start(name, id, payload)
|
42
|
+
listeners_for(name).each { |s| s.start(name, id, payload) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def finish(name, id, payload, listeners = listeners_for(name))
|
46
|
+
listeners.each { |s| s.finish(name, id, payload) }
|
22
47
|
end
|
23
48
|
|
24
49
|
def publish(name, *args)
|
@@ -26,7 +51,11 @@ module ActiveSupport
|
|
26
51
|
end
|
27
52
|
|
28
53
|
def listeners_for(name)
|
29
|
-
|
54
|
+
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
|
55
|
+
@listeners_for[name] || synchronize do
|
56
|
+
# use synchronisation when accessing @subscribers
|
57
|
+
@listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
|
58
|
+
end
|
30
59
|
end
|
31
60
|
|
32
61
|
def listening?(name)
|
@@ -37,23 +66,90 @@ module ActiveSupport
|
|
37
66
|
def wait
|
38
67
|
end
|
39
68
|
|
40
|
-
|
41
|
-
def
|
42
|
-
|
43
|
-
|
69
|
+
module Subscribers # :nodoc:
|
70
|
+
def self.new(pattern, listener)
|
71
|
+
if listener.respond_to?(:start) and listener.respond_to?(:finish)
|
72
|
+
subscriber = Evented.new pattern, listener
|
73
|
+
else
|
74
|
+
subscriber = Timed.new pattern, listener
|
75
|
+
end
|
76
|
+
|
77
|
+
unless pattern
|
78
|
+
AllMessages.new(subscriber)
|
79
|
+
else
|
80
|
+
subscriber
|
81
|
+
end
|
44
82
|
end
|
45
83
|
|
46
|
-
|
47
|
-
|
84
|
+
class Evented #:nodoc:
|
85
|
+
def initialize(pattern, delegate)
|
86
|
+
@pattern = pattern
|
87
|
+
@delegate = delegate
|
88
|
+
@can_publish = delegate.respond_to?(:publish)
|
89
|
+
end
|
90
|
+
|
91
|
+
def publish(name, *args)
|
92
|
+
if @can_publish
|
93
|
+
@delegate.publish name, *args
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def start(name, id, payload)
|
98
|
+
@delegate.start name, id, payload
|
99
|
+
end
|
100
|
+
|
101
|
+
def finish(name, id, payload)
|
102
|
+
@delegate.finish name, id, payload
|
103
|
+
end
|
104
|
+
|
105
|
+
def subscribed_to?(name)
|
106
|
+
@pattern === name
|
107
|
+
end
|
108
|
+
|
109
|
+
def matches?(name)
|
110
|
+
@pattern && @pattern === name
|
111
|
+
end
|
48
112
|
end
|
49
113
|
|
50
|
-
|
51
|
-
|
114
|
+
class Timed < Evented # :nodoc:
|
115
|
+
def publish(name, *args)
|
116
|
+
@delegate.call name, *args
|
117
|
+
end
|
118
|
+
|
119
|
+
def start(name, id, payload)
|
120
|
+
timestack = Thread.current[:_timestack] ||= []
|
121
|
+
timestack.push Time.now
|
122
|
+
end
|
123
|
+
|
124
|
+
def finish(name, id, payload)
|
125
|
+
timestack = Thread.current[:_timestack]
|
126
|
+
started = timestack.pop
|
127
|
+
@delegate.call(name, started, Time.now, id, payload)
|
128
|
+
end
|
52
129
|
end
|
53
130
|
|
54
|
-
|
55
|
-
|
56
|
-
@
|
131
|
+
class AllMessages # :nodoc:
|
132
|
+
def initialize(delegate)
|
133
|
+
@delegate = delegate
|
134
|
+
end
|
135
|
+
|
136
|
+
def start(name, id, payload)
|
137
|
+
@delegate.start name, id, payload
|
138
|
+
end
|
139
|
+
|
140
|
+
def finish(name, id, payload)
|
141
|
+
@delegate.finish name, id, payload
|
142
|
+
end
|
143
|
+
|
144
|
+
def publish(name, *args)
|
145
|
+
@delegate.publish name, *args
|
146
|
+
end
|
147
|
+
|
148
|
+
def subscribed_to?(name)
|
149
|
+
true
|
150
|
+
end
|
151
|
+
|
152
|
+
alias :matches? :===
|
57
153
|
end
|
58
154
|
end
|
59
155
|
end
|