activesupport 3.2.22.5 → 4.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +325 -136
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -2
- data/lib/active_support.rb +8 -21
- data/lib/active_support/backtrace_cleaner.rb +33 -25
- data/lib/active_support/basic_object.rb +7 -17
- data/lib/active_support/benchmarkable.rb +19 -15
- data/lib/active_support/buffered_logger.rb +9 -113
- data/lib/active_support/cache.rb +203 -171
- data/lib/active_support/cache/file_store.rb +12 -12
- data/lib/active_support/cache/mem_cache_store.rb +24 -30
- data/lib/active_support/cache/memory_store.rb +2 -0
- data/lib/active_support/callbacks.rb +195 -247
- data/lib/active_support/concern.rb +16 -23
- data/lib/active_support/concurrency/latch.rb +27 -0
- data/lib/active_support/configurable.rb +69 -12
- data/lib/active_support/core_ext.rb +1 -0
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/array/access.rb +17 -9
- data/lib/active_support/core_ext/array/conversions.rb +113 -55
- data/lib/active_support/core_ext/array/extract_options.rb +2 -2
- data/lib/active_support/core_ext/array/grouping.rb +21 -22
- data/lib/active_support/core_ext/array/uniq_by.rb +12 -9
- data/lib/active_support/core_ext/array/wrap.rb +11 -14
- data/lib/active_support/core_ext/big_decimal/conversions.rb +7 -24
- data/lib/active_support/core_ext/class/attribute.rb +12 -8
- data/lib/active_support/core_ext/class/attribute_accessors.rb +14 -12
- data/lib/active_support/core_ext/class/delegating_attributes.rb +15 -19
- data/lib/active_support/core_ext/class/subclasses.rb +11 -5
- data/lib/active_support/core_ext/date.rb +6 -0
- data/lib/active_support/core_ext/date/calculations.rb +34 -188
- data/lib/active_support/core_ext/date/conversions.rb +16 -38
- data/lib/active_support/core_ext/date/infinite_comparable.rb +5 -0
- data/lib/active_support/core_ext/date/zones.rb +25 -2
- data/lib/active_support/core_ext/date_and_time/calculations.rb +232 -0
- data/lib/active_support/core_ext/date_time.rb +5 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +73 -65
- data/lib/active_support/core_ext/date_time/conversions.rb +21 -33
- data/lib/active_support/core_ext/date_time/infinite_comparable.rb +5 -0
- data/lib/active_support/core_ext/date_time/zones.rb +11 -8
- data/lib/active_support/core_ext/enumerable.rb +26 -73
- data/lib/active_support/core_ext/file.rb +0 -1
- data/lib/active_support/core_ext/file/atomic.rb +27 -11
- data/lib/active_support/core_ext/hash.rb +0 -1
- data/lib/active_support/core_ext/hash/conversions.rb +145 -79
- data/lib/active_support/core_ext/hash/deep_merge.rb +14 -8
- data/lib/active_support/core_ext/hash/diff.rb +5 -4
- data/lib/active_support/core_ext/hash/except.rb +1 -9
- data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -5
- data/lib/active_support/core_ext/hash/keys.rb +108 -24
- data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
- data/lib/active_support/core_ext/hash/slice.rb +12 -12
- data/lib/active_support/core_ext/infinite_comparable.rb +35 -0
- data/lib/active_support/core_ext/integer/inflections.rb +13 -1
- data/lib/active_support/core_ext/integer/time.rb +17 -12
- data/lib/active_support/core_ext/kernel/debugger.rb +2 -2
- data/lib/active_support/core_ext/kernel/reporting.rb +36 -22
- data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
- data/lib/active_support/core_ext/load_error.rb +7 -5
- data/lib/active_support/core_ext/logger.rb +7 -23
- data/lib/active_support/core_ext/marshal.rb +19 -0
- data/lib/active_support/core_ext/module.rb +1 -3
- data/lib/active_support/core_ext/module/aliasing.rb +8 -9
- data/lib/active_support/core_ext/module/anonymous.rb +2 -7
- data/lib/active_support/core_ext/module/attr_internal.rb +0 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +12 -10
- data/lib/active_support/core_ext/module/delegation.rb +57 -40
- data/lib/active_support/core_ext/module/deprecation.rb +19 -3
- data/lib/active_support/core_ext/module/introspection.rb +17 -27
- data/lib/active_support/core_ext/module/qualified_const.rb +8 -20
- data/lib/active_support/core_ext/module/remove_method.rb +1 -5
- data/lib/active_support/core_ext/numeric.rb +2 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +135 -0
- data/lib/active_support/core_ext/numeric/infinite_comparable.rb +9 -0
- data/lib/active_support/core_ext/numeric/time.rb +6 -6
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +4 -4
- data/lib/active_support/core_ext/object/blank.rb +7 -23
- data/lib/active_support/core_ext/object/deep_dup.rb +46 -0
- data/lib/active_support/core_ext/object/duplicable.rb +1 -30
- data/lib/active_support/core_ext/object/inclusion.rb +6 -6
- data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
- data/lib/active_support/core_ext/object/to_json.rb +8 -0
- data/lib/active_support/core_ext/object/to_param.rb +5 -2
- data/lib/active_support/core_ext/object/try.rb +46 -25
- data/lib/active_support/core_ext/object/with_options.rb +7 -8
- data/lib/active_support/core_ext/proc.rb +3 -0
- data/lib/active_support/core_ext/range.rb +0 -2
- data/lib/active_support/core_ext/range/conversions.rb +0 -2
- data/lib/active_support/core_ext/range/include_range.rb +1 -1
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/string.rb +2 -2
- data/lib/active_support/core_ext/string/access.rb +95 -90
- data/lib/active_support/core_ext/string/conversions.rb +29 -38
- data/lib/active_support/core_ext/string/encoding.rb +6 -9
- data/lib/active_support/core_ext/string/filters.rb +24 -18
- data/lib/active_support/core_ext/string/indent.rb +43 -0
- data/lib/active_support/core_ext/string/inflections.rb +70 -60
- data/lib/active_support/core_ext/string/inquiry.rb +2 -2
- data/lib/active_support/core_ext/string/multibyte.rb +41 -64
- data/lib/active_support/core_ext/string/output_safety.rb +59 -51
- data/lib/active_support/core_ext/string/zones.rb +13 -0
- data/lib/active_support/core_ext/struct.rb +6 -0
- data/lib/active_support/core_ext/thread.rb +74 -0
- data/lib/active_support/core_ext/time.rb +6 -0
- data/lib/active_support/core_ext/time/calculations.rb +105 -193
- data/lib/active_support/core_ext/time/conversions.rb +27 -51
- data/lib/active_support/core_ext/time/infinite_comparable.rb +5 -0
- data/lib/active_support/core_ext/time/marshal.rb +0 -27
- data/lib/active_support/core_ext/time/zones.rb +27 -17
- data/lib/active_support/core_ext/uri.rb +13 -17
- data/lib/active_support/dependencies.rb +160 -141
- data/lib/active_support/dependencies/autoload.rb +47 -20
- data/lib/active_support/deprecation.rb +39 -14
- data/lib/active_support/deprecation/behaviors.rb +44 -30
- data/lib/active_support/deprecation/instance_delegator.rb +24 -0
- data/lib/active_support/deprecation/method_wrappers.rb +33 -18
- data/lib/active_support/deprecation/proxy_wrappers.rb +58 -13
- data/lib/active_support/deprecation/reporting.rb +40 -11
- data/lib/active_support/descendants_tracker.rb +34 -19
- data/lib/active_support/duration.rb +6 -8
- data/lib/active_support/file_update_checker.rb +63 -47
- data/lib/active_support/gzip.rb +11 -5
- data/lib/active_support/hash_with_indifferent_access.rb +112 -37
- data/lib/active_support/i18n.rb +4 -0
- data/lib/active_support/i18n_railtie.rb +5 -22
- data/lib/active_support/inflections.rb +14 -12
- data/lib/active_support/inflector/inflections.rb +108 -71
- data/lib/active_support/inflector/methods.rb +181 -160
- data/lib/active_support/inflector/transliterate.rb +16 -17
- data/lib/active_support/json/decoding.rb +18 -17
- data/lib/active_support/json/encoding.rb +93 -39
- data/lib/active_support/json/variable.rb +10 -1
- data/lib/active_support/key_generator.rb +75 -0
- data/lib/active_support/lazy_load_hooks.rb +21 -19
- data/lib/active_support/locale/en.yml +100 -3
- data/lib/active_support/log_subscriber.rb +56 -36
- data/lib/active_support/log_subscriber/test_helper.rb +18 -15
- data/lib/active_support/logger.rb +57 -0
- data/lib/active_support/logger_silence.rb +24 -0
- data/lib/active_support/message_encryptor.rb +32 -29
- data/lib/active_support/message_verifier.rb +8 -14
- data/lib/active_support/multibyte.rb +5 -28
- data/lib/active_support/multibyte/chars.rb +80 -333
- data/lib/active_support/multibyte/unicode.rb +74 -64
- data/lib/active_support/notifications.rb +57 -25
- data/lib/active_support/notifications/fanout.rb +105 -18
- data/lib/active_support/notifications/instrumenter.rb +32 -13
- data/lib/active_support/number_helper.rb +636 -0
- data/lib/active_support/ordered_hash.rb +8 -190
- data/lib/active_support/ordered_options.rb +21 -23
- data/lib/active_support/proxy_object.rb +13 -0
- data/lib/active_support/rails.rb +27 -0
- data/lib/active_support/railtie.rb +12 -32
- data/lib/active_support/rescuable.rb +9 -4
- data/lib/active_support/string_inquirer.rb +13 -8
- data/lib/active_support/tagged_logging.rb +51 -73
- data/lib/active_support/test_case.rb +46 -17
- data/lib/active_support/testing/assertions.rb +56 -26
- data/lib/active_support/testing/autorun.rb +5 -0
- data/lib/active_support/testing/constant_lookup.rb +52 -0
- data/lib/active_support/testing/declarative.rb +1 -1
- data/lib/active_support/testing/deprecation.rb +0 -19
- data/lib/active_support/testing/isolation.rb +25 -58
- data/lib/active_support/testing/pending.rb +5 -43
- data/lib/active_support/testing/setup_and_teardown.rb +6 -92
- data/lib/active_support/testing/tagged_logging.rb +25 -0
- data/lib/active_support/time.rb +6 -21
- data/lib/active_support/time_with_zone.rb +78 -43
- data/lib/active_support/values/time_zone.rb +77 -58
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +4 -4
- data/lib/active_support/xml_mini.rb +35 -17
- data/lib/active_support/xml_mini/jdom.rb +9 -17
- data/lib/active_support/xml_mini/libxml.rb +1 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -2
- data/lib/active_support/xml_mini/nokogiri.rb +1 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -2
- data/lib/active_support/xml_mini/rexml.rb +6 -8
- metadata +107 -77
- data/lib/active_support/base64.rb +0 -54
- data/lib/active_support/core_ext/array/random_access.rb +0 -30
- data/lib/active_support/core_ext/date/freeze.rb +0 -33
- 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.rb +0 -1
- data/lib/active_support/core_ext/float/rounding.rb +0 -19
- data/lib/active_support/core_ext/hash/deep_dup.rb +0 -18
- data/lib/active_support/core_ext/io.rb +0 -15
- data/lib/active_support/core_ext/module/method_names.rb +0 -14
- data/lib/active_support/core_ext/module/synchronization.rb +0 -45
- data/lib/active_support/core_ext/process.rb +0 -1
- data/lib/active_support/core_ext/process/daemon.rb +0 -23
- 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/interpolation.rb +0 -2
- data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
- data/lib/active_support/memoizable.rb +0 -116
- 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/security_utils.rb +0 -27
- data/lib/active_support/testing/mochaing.rb +0 -7
- data/lib/active_support/testing/performance.rb +0 -317
- 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.rb +0 -152
- 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/time/autoload.rb +0 -5
- data/lib/active_support/whiny_nil.rb +0 -24
@@ -5,17 +5,18 @@ module ActiveSupport
|
|
5
5
|
|
6
6
|
extend self
|
7
7
|
|
8
|
-
# A list of all available normalization forms.
|
8
|
+
# A list of all available normalization forms.
|
9
|
+
# See http://www.unicode.org/reports/tr15/tr15-29.html for more
|
9
10
|
# information about normalization.
|
10
11
|
NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
|
11
12
|
|
12
13
|
# The Unicode version that is supported by the implementation
|
13
|
-
UNICODE_VERSION = '
|
14
|
+
UNICODE_VERSION = '6.2.0'
|
14
15
|
|
15
|
-
# The default normalization used for operations that require
|
16
|
-
#
|
16
|
+
# The default normalization used for operations that require
|
17
|
+
# normalization. It can be set to any of the normalizations
|
18
|
+
# in NORMALIZATION_FORMS.
|
17
19
|
#
|
18
|
-
# Example:
|
19
20
|
# ActiveSupport::Multibyte::Unicode.default_normalization_form = :c
|
20
21
|
attr_accessor :default_normalization_form
|
21
22
|
@default_normalization_form = :kc
|
@@ -50,32 +51,22 @@ module ActiveSupport
|
|
50
51
|
0x3000, # White_Space # Zs IDEOGRAPHIC SPACE
|
51
52
|
].flatten.freeze
|
52
53
|
|
53
|
-
# BOM (byte order mark) can also be seen as whitespace, it's a
|
54
|
-
#
|
54
|
+
# BOM (byte order mark) can also be seen as whitespace, it's a
|
55
|
+
# non-rendering character used to distinguish between little and big
|
56
|
+
# endian. This is not an issue in utf-8, so it must be ignored.
|
55
57
|
LEADERS_AND_TRAILERS = WHITESPACE + [65279] # ZERO-WIDTH NO-BREAK SPACE aka BOM
|
56
58
|
|
57
|
-
# Returns a regular expression pattern that matches the passed Unicode
|
59
|
+
# Returns a regular expression pattern that matches the passed Unicode
|
60
|
+
# codepoints.
|
58
61
|
def self.codepoints_to_pattern(array_of_codepoints) #:nodoc:
|
59
62
|
array_of_codepoints.collect{ |e| [e].pack 'U*' }.join('|')
|
60
63
|
end
|
61
64
|
TRAILERS_PAT = /(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+\Z/u
|
62
65
|
LEADERS_PAT = /\A(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+/u
|
63
66
|
|
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>,
|
67
|
+
# Detect whether the codepoint is in a certain character class. Returns
|
68
|
+
# +true+ when it's in the specified character class and +false+ otherwise.
|
69
|
+
# Valid character classes are: <tt>:cr</tt>, <tt>:lf</tt>, <tt>:l</tt>,
|
79
70
|
# <tt>:v</tt>, <tt>:lv</tt>, <tt>:lvt</tt> and <tt>:t</tt>.
|
80
71
|
#
|
81
72
|
# Primarily used by the grapheme cluster support.
|
@@ -83,13 +74,13 @@ module ActiveSupport
|
|
83
74
|
classes.detect { |c| database.boundary[c] === codepoint } ? true : false
|
84
75
|
end
|
85
76
|
|
86
|
-
# Unpack the string at grapheme boundaries. Returns a list of character
|
77
|
+
# Unpack the string at grapheme boundaries. Returns a list of character
|
78
|
+
# lists.
|
87
79
|
#
|
88
|
-
#
|
89
|
-
# Unicode.
|
90
|
-
|
91
|
-
|
92
|
-
codepoints = u_unpack(string)
|
80
|
+
# Unicode.unpack_graphemes('क्षि') # => [[2325, 2381], [2359], [2367]]
|
81
|
+
# Unicode.unpack_graphemes('Café') # => [[67], [97], [102], [233]]
|
82
|
+
def unpack_graphemes(string)
|
83
|
+
codepoints = string.codepoints.to_a
|
93
84
|
unpacked = []
|
94
85
|
pos = 0
|
95
86
|
marker = 0
|
@@ -118,12 +109,11 @@ module ActiveSupport
|
|
118
109
|
unpacked
|
119
110
|
end
|
120
111
|
|
121
|
-
# Reverse operation of
|
112
|
+
# Reverse operation of unpack_graphemes.
|
122
113
|
#
|
123
|
-
#
|
124
|
-
|
125
|
-
|
126
|
-
(unpacked.flatten).pack('U*')
|
114
|
+
# Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि'
|
115
|
+
def pack_graphemes(unpacked)
|
116
|
+
unpacked.flatten.pack('U*')
|
127
117
|
end
|
128
118
|
|
129
119
|
# Re-order codepoints so the string becomes canonical.
|
@@ -143,7 +133,7 @@ module ActiveSupport
|
|
143
133
|
end
|
144
134
|
|
145
135
|
# Decompose composed characters to the decomposed form.
|
146
|
-
def
|
136
|
+
def decompose(type, codepoints)
|
147
137
|
codepoints.inject([]) do |decomposed, cp|
|
148
138
|
# if it's a hangul syllable starter character
|
149
139
|
if HANGUL_SBASE <= cp and cp < HANGUL_SLAST
|
@@ -156,7 +146,7 @@ module ActiveSupport
|
|
156
146
|
decomposed.concat ncp
|
157
147
|
# if the codepoint is decomposable in with the current decomposition type
|
158
148
|
elsif (ncp = database.codepoints[cp].decomp_mapping) and (!database.codepoints[cp].decomp_type || type == :compatability)
|
159
|
-
decomposed.concat
|
149
|
+
decomposed.concat decompose(type, ncp.dup)
|
160
150
|
else
|
161
151
|
decomposed << cp
|
162
152
|
end
|
@@ -164,7 +154,7 @@ module ActiveSupport
|
|
164
154
|
end
|
165
155
|
|
166
156
|
# Compose decomposed characters to the composed form.
|
167
|
-
def
|
157
|
+
def compose(codepoints)
|
168
158
|
pos = 0
|
169
159
|
eoa = codepoints.length - 1
|
170
160
|
starter_pos = 0
|
@@ -222,9 +212,11 @@ module ActiveSupport
|
|
222
212
|
codepoints
|
223
213
|
end
|
224
214
|
|
225
|
-
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
215
|
+
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
216
|
+
# resulting in a valid UTF-8 string.
|
226
217
|
#
|
227
|
-
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
|
218
|
+
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
|
219
|
+
# encoding is entirely CP1252 or ISO-8859-1.
|
228
220
|
def tidy_bytes(string, force = false)
|
229
221
|
if force
|
230
222
|
return string.unpack("C*").map do |b|
|
@@ -273,48 +265,54 @@ module ActiveSupport
|
|
273
265
|
bytes.empty? ? "" : bytes.flatten.compact.pack("C*").unpack("U*").pack("U*")
|
274
266
|
end
|
275
267
|
|
276
|
-
# Returns the KC normalization of the string by default. NFKC is
|
277
|
-
# passing strings to databases
|
268
|
+
# Returns the KC normalization of the string by default. NFKC is
|
269
|
+
# considered the best normalization form for passing strings to databases
|
270
|
+
# and validations.
|
278
271
|
#
|
279
272
|
# * <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
|
273
|
+
# * <tt>form</tt> - The form you want to normalize in. Should be one of
|
274
|
+
# the following: <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>.
|
275
|
+
# Default is ActiveSupport::Multibyte.default_normalization_form.
|
283
276
|
def normalize(string, form=nil)
|
284
277
|
form ||= @default_normalization_form
|
285
278
|
# See http://www.unicode.org/reports/tr15, Table 1
|
286
|
-
codepoints =
|
279
|
+
codepoints = string.codepoints.to_a
|
287
280
|
case form
|
288
281
|
when :d
|
289
|
-
reorder_characters(
|
282
|
+
reorder_characters(decompose(:canonical, codepoints))
|
290
283
|
when :c
|
291
|
-
|
284
|
+
compose(reorder_characters(decompose(:canonical, codepoints)))
|
292
285
|
when :kd
|
293
|
-
reorder_characters(
|
286
|
+
reorder_characters(decompose(:compatability, codepoints))
|
294
287
|
when :kc
|
295
|
-
|
288
|
+
compose(reorder_characters(decompose(:compatability, codepoints)))
|
296
289
|
else
|
297
290
|
raise ArgumentError, "#{form} is not a valid normalization variant", caller
|
298
291
|
end.pack('U*')
|
299
292
|
end
|
300
293
|
|
301
|
-
def
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
codepoint
|
308
|
-
end
|
309
|
-
end.pack('U*')
|
294
|
+
def downcase(string)
|
295
|
+
apply_mapping string, :lowercase_mapping
|
296
|
+
end
|
297
|
+
|
298
|
+
def upcase(string)
|
299
|
+
apply_mapping string, :uppercase_mapping
|
310
300
|
end
|
311
301
|
|
312
|
-
|
302
|
+
def swapcase(string)
|
303
|
+
apply_mapping string, :swapcase_mapping
|
304
|
+
end
|
305
|
+
|
306
|
+
# Holds data about a codepoint in the Unicode database.
|
313
307
|
class Codepoint
|
314
308
|
attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
|
309
|
+
|
310
|
+
def swapcase_mapping
|
311
|
+
uppercase_mapping > 0 ? uppercase_mapping : lowercase_mapping
|
312
|
+
end
|
315
313
|
end
|
316
314
|
|
317
|
-
# Holds static data from the Unicode database
|
315
|
+
# Holds static data from the Unicode database.
|
318
316
|
class UnicodeDatabase
|
319
317
|
ATTRIBUTES = :codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252
|
320
318
|
|
@@ -338,11 +336,12 @@ module ActiveSupport
|
|
338
336
|
EOS
|
339
337
|
end
|
340
338
|
|
341
|
-
# Loads the Unicode database and returns all the internal objects of
|
339
|
+
# Loads the Unicode database and returns all the internal objects of
|
340
|
+
# UnicodeDatabase.
|
342
341
|
def load
|
343
342
|
begin
|
344
343
|
@codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read }
|
345
|
-
rescue
|
344
|
+
rescue => e
|
346
345
|
raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable")
|
347
346
|
end
|
348
347
|
|
@@ -361,12 +360,12 @@ module ActiveSupport
|
|
361
360
|
end
|
362
361
|
end
|
363
362
|
|
364
|
-
# Returns the directory in which the data files are stored
|
363
|
+
# Returns the directory in which the data files are stored.
|
365
364
|
def self.dirname
|
366
365
|
File.dirname(__FILE__) + '/../values/'
|
367
366
|
end
|
368
367
|
|
369
|
-
# Returns the filename for the data file for this version
|
368
|
+
# Returns the filename for the data file for this version.
|
370
369
|
def self.filename
|
371
370
|
File.expand_path File.join(dirname, "unicode_tables.dat")
|
372
371
|
end
|
@@ -374,6 +373,17 @@ module ActiveSupport
|
|
374
373
|
|
375
374
|
private
|
376
375
|
|
376
|
+
def apply_mapping(string, mapping) #:nodoc:
|
377
|
+
string.each_codepoint.map do |codepoint|
|
378
|
+
cp = database.codepoints[codepoint]
|
379
|
+
if cp and (ncp = cp.send(mapping)) and ncp > 0
|
380
|
+
ncp
|
381
|
+
else
|
382
|
+
codepoint
|
383
|
+
end
|
384
|
+
end.pack('U*')
|
385
|
+
end
|
386
|
+
|
377
387
|
def tidy_byte(byte)
|
378
388
|
if byte < 160
|
379
389
|
[database.cp1252[byte] || byte].pack("U").unpack("C*")
|
@@ -1,19 +1,23 @@
|
|
1
|
+
require 'active_support/notifications/instrumenter'
|
2
|
+
require 'active_support/notifications/fanout'
|
3
|
+
|
1
4
|
module ActiveSupport
|
2
5
|
# = Notifications
|
3
6
|
#
|
4
|
-
#
|
7
|
+
# <tt>ActiveSupport::Notifications</tt> provides an instrumentation API for
|
8
|
+
# Ruby.
|
5
9
|
#
|
6
10
|
# == Instrumenters
|
7
11
|
#
|
8
12
|
# To instrument an event you just need to do:
|
9
13
|
#
|
10
|
-
# ActiveSupport::Notifications.instrument(
|
11
|
-
# render :
|
14
|
+
# ActiveSupport::Notifications.instrument('render', extra: :information) do
|
15
|
+
# render text: 'Foo'
|
12
16
|
# end
|
13
17
|
#
|
14
18
|
# That executes the block first and notifies all subscribers once done.
|
15
19
|
#
|
16
|
-
# In the example above
|
20
|
+
# In the example above +render+ is the name of the event, and the rest is called
|
17
21
|
# the _payload_. The payload is a mechanism that allows instrumenters to pass
|
18
22
|
# extra information to subscribers. Payloads consist of a hash whose contents
|
19
23
|
# are arbitrary and generally depend on the event.
|
@@ -21,46 +25,83 @@ module ActiveSupport
|
|
21
25
|
# == Subscribers
|
22
26
|
#
|
23
27
|
# You can consume those events and the information they provide by registering
|
24
|
-
# a subscriber.
|
28
|
+
# a subscriber.
|
29
|
+
#
|
30
|
+
# ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
|
31
|
+
# name # => String, name of the event (such as 'render' from above)
|
32
|
+
# start # => Time, when the instrumented block started execution
|
33
|
+
# finish # => Time, when the instrumented block ended execution
|
34
|
+
# id # => String, unique ID for this notification
|
35
|
+
# payload # => Hash, the payload
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# For instance, let's store all "render" events in an array:
|
25
39
|
#
|
26
40
|
# events = []
|
27
41
|
#
|
28
|
-
# ActiveSupport::Notifications.subscribe(
|
42
|
+
# ActiveSupport::Notifications.subscribe('render') do |*args|
|
29
43
|
# events << ActiveSupport::Notifications::Event.new(*args)
|
30
44
|
# end
|
31
45
|
#
|
32
46
|
# That code returns right away, you are just subscribing to "render" events.
|
33
|
-
# The block will be called
|
47
|
+
# The block is saved and will be called whenever someone instruments "render":
|
34
48
|
#
|
35
|
-
# ActiveSupport::Notifications.instrument(
|
36
|
-
# render :
|
49
|
+
# ActiveSupport::Notifications.instrument('render', extra: :information) do
|
50
|
+
# render text: 'Foo'
|
37
51
|
# end
|
38
52
|
#
|
39
53
|
# event = events.first
|
40
54
|
# event.name # => "render"
|
41
55
|
# event.duration # => 10 (in milliseconds)
|
42
|
-
# event.payload # => { :
|
56
|
+
# event.payload # => { extra: :information }
|
43
57
|
#
|
44
|
-
# The block in the
|
58
|
+
# The block in the <tt>subscribe</tt> call gets the name of the event, start
|
45
59
|
# timestamp, end timestamp, a string with a unique identifier for that event
|
46
60
|
# (something like "535801666f04d0298cd6"), and a hash with the payload, in
|
47
61
|
# that order.
|
48
62
|
#
|
49
63
|
# If an exception happens during that particular instrumentation the payload will
|
50
|
-
# have a key
|
64
|
+
# have a key <tt>:exception</tt> with an array of two elements as value: a string with
|
51
65
|
# the name of the exception class, and the exception message.
|
52
66
|
#
|
53
|
-
# As the previous example depicts, the class
|
67
|
+
# As the previous example depicts, the class <tt>ActiveSupport::Notifications::Event</tt>
|
54
68
|
# is able to take the arguments as they come and provide an object-oriented
|
55
69
|
# interface to that data.
|
56
70
|
#
|
71
|
+
# It is also possible to pass an object as the second parameter passed to the
|
72
|
+
# <tt>subscribe</tt> method instead of a block:
|
73
|
+
#
|
74
|
+
# module ActionController
|
75
|
+
# class PageRequest
|
76
|
+
# def call(name, started, finished, unique_id, payload)
|
77
|
+
# Rails.logger.debug ['notification:', name, started, finished, unique_id, payload].join(' ')
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# ActiveSupport::Notifications.subscribe('process_action.action_controller', ActionController::PageRequest.new)
|
83
|
+
#
|
84
|
+
# resulting in the following output within the logs including a hash with the payload:
|
85
|
+
#
|
86
|
+
# notification: process_action.action_controller 2012-04-13 01:08:35 +0300 2012-04-13 01:08:35 +0300 af358ed7fab884532ec7 {
|
87
|
+
# controller: "Devise::SessionsController",
|
88
|
+
# action: "new",
|
89
|
+
# params: {"action"=>"new", "controller"=>"devise/sessions"},
|
90
|
+
# format: :html,
|
91
|
+
# method: "GET",
|
92
|
+
# path: "/login/sign_in",
|
93
|
+
# status: 200,
|
94
|
+
# view_runtime: 279.3080806732178,
|
95
|
+
# db_runtime: 40.053
|
96
|
+
# }
|
97
|
+
#
|
57
98
|
# You can also subscribe to all events whose name matches a certain regexp:
|
58
99
|
#
|
59
100
|
# ActiveSupport::Notifications.subscribe(/render/) do |*args|
|
60
101
|
# ...
|
61
102
|
# end
|
62
103
|
#
|
63
|
-
# and even pass no argument to
|
104
|
+
# and even pass no argument to <tt>subscribe</tt>, in which case you are subscribing
|
64
105
|
# to all events.
|
65
106
|
#
|
66
107
|
# == Temporary Subscriptions
|
@@ -105,12 +146,6 @@ module ActiveSupport
|
|
105
146
|
# to log subscribers in a thread. You can use any queue implementation you want.
|
106
147
|
#
|
107
148
|
module Notifications
|
108
|
-
autoload :Instrumenter, 'active_support/notifications/instrumenter'
|
109
|
-
autoload :Event, 'active_support/notifications/instrumenter'
|
110
|
-
autoload :Fanout, 'active_support/notifications/fanout'
|
111
|
-
|
112
|
-
@instrumenters = Hash.new { |h,k| h[k] = notifier.listening?(k) }
|
113
|
-
|
114
149
|
class << self
|
115
150
|
attr_accessor :notifier
|
116
151
|
|
@@ -119,7 +154,7 @@ module ActiveSupport
|
|
119
154
|
end
|
120
155
|
|
121
156
|
def instrument(name, payload = {})
|
122
|
-
if
|
157
|
+
if notifier.listening?(name)
|
123
158
|
instrumenter.instrument(name, payload) { yield payload if block_given? }
|
124
159
|
else
|
125
160
|
yield payload if block_given?
|
@@ -127,9 +162,7 @@ module ActiveSupport
|
|
127
162
|
end
|
128
163
|
|
129
164
|
def subscribe(*args, &block)
|
130
|
-
notifier.subscribe(*args, &block)
|
131
|
-
@instrumenters.clear
|
132
|
-
end
|
165
|
+
notifier.subscribe(*args, &block)
|
133
166
|
end
|
134
167
|
|
135
168
|
def subscribed(callback, *args, &block)
|
@@ -141,7 +174,6 @@ module ActiveSupport
|
|
141
174
|
|
142
175
|
def unsubscribe(args)
|
143
176
|
notifier.unsubscribe(args)
|
144
|
-
@instrumenters.clear
|
145
177
|
end
|
146
178
|
|
147
179
|
def instrumenter
|
@@ -1,24 +1,43 @@
|
|
1
|
+
require 'mutex_m'
|
2
|
+
require 'thread_safe'
|
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 = ThreadSafe::Cache.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
28
|
def unsubscribe(subscriber)
|
20
|
-
|
21
|
-
|
29
|
+
synchronize do
|
30
|
+
@subscribers.reject! { |s| s.matches?(subscriber) }
|
31
|
+
@listeners_for.clear
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def start(name, id, payload)
|
36
|
+
listeners_for(name).each { |s| s.start(name, id, payload) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def finish(name, id, payload)
|
40
|
+
listeners_for(name).each { |s| s.finish(name, id, payload) }
|
22
41
|
end
|
23
42
|
|
24
43
|
def publish(name, *args)
|
@@ -26,7 +45,11 @@ module ActiveSupport
|
|
26
45
|
end
|
27
46
|
|
28
47
|
def listeners_for(name)
|
29
|
-
|
48
|
+
# this is correctly done double-checked locking (ThreadSafe::Cache's lookups have volatile semantics)
|
49
|
+
@listeners_for[name] || synchronize do
|
50
|
+
# use synchronisation when accessing @subscribers
|
51
|
+
@listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
|
52
|
+
end
|
30
53
|
end
|
31
54
|
|
32
55
|
def listening?(name)
|
@@ -37,23 +60,87 @@ module ActiveSupport
|
|
37
60
|
def wait
|
38
61
|
end
|
39
62
|
|
40
|
-
|
41
|
-
def
|
42
|
-
|
43
|
-
|
63
|
+
module Subscribers # :nodoc:
|
64
|
+
def self.new(pattern, listener)
|
65
|
+
if listener.respond_to?(:start) and listener.respond_to?(:finish)
|
66
|
+
subscriber = Evented.new pattern, listener
|
67
|
+
else
|
68
|
+
subscriber = Timed.new pattern, listener
|
69
|
+
end
|
70
|
+
|
71
|
+
unless pattern
|
72
|
+
AllMessages.new(subscriber)
|
73
|
+
else
|
74
|
+
subscriber
|
75
|
+
end
|
44
76
|
end
|
45
77
|
|
46
|
-
|
47
|
-
|
78
|
+
class Evented #:nodoc:
|
79
|
+
def initialize(pattern, delegate)
|
80
|
+
@pattern = pattern
|
81
|
+
@delegate = delegate
|
82
|
+
end
|
83
|
+
|
84
|
+
def start(name, id, payload)
|
85
|
+
@delegate.start name, id, payload
|
86
|
+
end
|
87
|
+
|
88
|
+
def finish(name, id, payload)
|
89
|
+
@delegate.finish name, id, payload
|
90
|
+
end
|
91
|
+
|
92
|
+
def subscribed_to?(name)
|
93
|
+
@pattern === name.to_s
|
94
|
+
end
|
95
|
+
|
96
|
+
def matches?(subscriber_or_name)
|
97
|
+
self === subscriber_or_name ||
|
98
|
+
@pattern && @pattern === subscriber_or_name
|
99
|
+
end
|
48
100
|
end
|
49
101
|
|
50
|
-
|
51
|
-
|
102
|
+
class Timed < Evented
|
103
|
+
def initialize(pattern, delegate)
|
104
|
+
@timestack = []
|
105
|
+
super
|
106
|
+
end
|
107
|
+
|
108
|
+
def publish(name, *args)
|
109
|
+
@delegate.call name, *args
|
110
|
+
end
|
111
|
+
|
112
|
+
def start(name, id, payload)
|
113
|
+
@timestack.push Time.now
|
114
|
+
end
|
115
|
+
|
116
|
+
def finish(name, id, payload)
|
117
|
+
started = @timestack.pop
|
118
|
+
@delegate.call(name, started, Time.now, id, payload)
|
119
|
+
end
|
52
120
|
end
|
53
121
|
|
54
|
-
|
55
|
-
|
56
|
-
@
|
122
|
+
class AllMessages # :nodoc:
|
123
|
+
def initialize(delegate)
|
124
|
+
@delegate = delegate
|
125
|
+
end
|
126
|
+
|
127
|
+
def start(name, id, payload)
|
128
|
+
@delegate.start name, id, payload
|
129
|
+
end
|
130
|
+
|
131
|
+
def finish(name, id, payload)
|
132
|
+
@delegate.finish name, id, payload
|
133
|
+
end
|
134
|
+
|
135
|
+
def publish(name, *args)
|
136
|
+
@delegate.publish name, *args
|
137
|
+
end
|
138
|
+
|
139
|
+
def subscribed_to?(name)
|
140
|
+
true
|
141
|
+
end
|
142
|
+
|
143
|
+
alias :matches? :===
|
57
144
|
end
|
58
145
|
end
|
59
146
|
end
|