activesupport 3.2.22.5 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +364 -135
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -4
  5. data/lib/active_support/backtrace_cleaner.rb +33 -25
  6. data/lib/active_support/basic_object.rb +7 -17
  7. data/lib/active_support/benchmarkable.rb +19 -15
  8. data/lib/active_support/buffered_logger.rb +9 -113
  9. data/lib/active_support/cache/file_store.rb +14 -14
  10. data/lib/active_support/cache/mem_cache_store.rb +24 -30
  11. data/lib/active_support/cache/memory_store.rb +2 -0
  12. data/lib/active_support/cache/strategy/local_cache.rb +48 -37
  13. data/lib/active_support/cache.rb +228 -183
  14. data/lib/active_support/callbacks.rb +201 -253
  15. data/lib/active_support/concern.rb +16 -23
  16. data/lib/active_support/concurrency/latch.rb +27 -0
  17. data/lib/active_support/configurable.rb +69 -12
  18. data/lib/active_support/core_ext/array/access.rb +17 -9
  19. data/lib/active_support/core_ext/array/conversions.rb +115 -55
  20. data/lib/active_support/core_ext/array/extract_options.rb +2 -2
  21. data/lib/active_support/core_ext/array/grouping.rb +21 -22
  22. data/lib/active_support/core_ext/array/uniq_by.rb +12 -9
  23. data/lib/active_support/core_ext/array/wrap.rb +13 -16
  24. data/lib/active_support/core_ext/array.rb +0 -1
  25. data/lib/active_support/core_ext/benchmark.rb +7 -0
  26. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -24
  27. data/lib/active_support/core_ext/class/attribute.rb +40 -32
  28. data/lib/active_support/core_ext/class/attribute_accessors.rb +14 -12
  29. data/lib/active_support/core_ext/class/delegating_attributes.rb +15 -19
  30. data/lib/active_support/core_ext/class/subclasses.rb +11 -5
  31. data/lib/active_support/core_ext/date/calculations.rb +44 -187
  32. data/lib/active_support/core_ext/date/conversions.rb +16 -38
  33. data/lib/active_support/core_ext/date/zones.rb +25 -2
  34. data/lib/active_support/core_ext/date.rb +5 -0
  35. data/lib/active_support/core_ext/date_and_time/calculations.rb +232 -0
  36. data/lib/active_support/core_ext/date_time/acts_like.rb +0 -1
  37. data/lib/active_support/core_ext/date_time/calculations.rb +77 -62
  38. data/lib/active_support/core_ext/date_time/conversions.rb +21 -33
  39. data/lib/active_support/core_ext/date_time/zones.rb +11 -8
  40. data/lib/active_support/core_ext/date_time.rb +4 -0
  41. data/lib/active_support/core_ext/enumerable.rb +26 -73
  42. data/lib/active_support/core_ext/file/atomic.rb +27 -11
  43. data/lib/active_support/core_ext/file.rb +0 -1
  44. data/lib/active_support/core_ext/hash/conversions.rb +145 -79
  45. data/lib/active_support/core_ext/hash/deep_merge.rb +14 -8
  46. data/lib/active_support/core_ext/hash/diff.rb +5 -4
  47. data/lib/active_support/core_ext/hash/except.rb +1 -9
  48. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -5
  49. data/lib/active_support/core_ext/hash/keys.rb +108 -24
  50. data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
  51. data/lib/active_support/core_ext/hash/slice.rb +12 -12
  52. data/lib/active_support/core_ext/hash.rb +0 -1
  53. data/lib/active_support/core_ext/integer/inflections.rb +13 -1
  54. data/lib/active_support/core_ext/integer/time.rb +17 -12
  55. data/lib/active_support/core_ext/kernel/debugger.rb +2 -2
  56. data/lib/active_support/core_ext/kernel/reporting.rb +36 -22
  57. data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
  58. data/lib/active_support/core_ext/load_error.rb +7 -5
  59. data/lib/active_support/core_ext/logger.rb +7 -23
  60. data/lib/active_support/core_ext/marshal.rb +21 -0
  61. data/lib/active_support/core_ext/module/aliasing.rb +8 -9
  62. data/lib/active_support/core_ext/module/anonymous.rb +2 -7
  63. data/lib/active_support/core_ext/module/attr_internal.rb +0 -1
  64. data/lib/active_support/core_ext/module/attribute_accessors.rb +12 -10
  65. data/lib/active_support/core_ext/module/delegation.rb +92 -49
  66. data/lib/active_support/core_ext/module/deprecation.rb +19 -3
  67. data/lib/active_support/core_ext/module/introspection.rb +17 -27
  68. data/lib/active_support/core_ext/module/qualified_const.rb +8 -20
  69. data/lib/active_support/core_ext/module/remove_method.rb +1 -5
  70. data/lib/active_support/core_ext/module.rb +1 -3
  71. data/lib/active_support/core_ext/numeric/conversions.rb +135 -0
  72. data/lib/active_support/core_ext/numeric/time.rb +6 -6
  73. data/lib/active_support/core_ext/numeric.rb +1 -0
  74. data/lib/active_support/core_ext/object/acts_like.rb +4 -4
  75. data/lib/active_support/core_ext/object/blank.rb +7 -23
  76. data/lib/active_support/core_ext/object/deep_dup.rb +46 -0
  77. data/lib/active_support/core_ext/object/duplicable.rb +1 -30
  78. data/lib/active_support/core_ext/object/inclusion.rb +8 -7
  79. data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
  80. data/lib/active_support/core_ext/object/to_json.rb +8 -0
  81. data/lib/active_support/core_ext/object/to_param.rb +5 -2
  82. data/lib/active_support/core_ext/object/try.rb +46 -25
  83. data/lib/active_support/core_ext/object/with_options.rb +7 -8
  84. data/lib/active_support/core_ext/object.rb +1 -0
  85. data/lib/active_support/core_ext/proc.rb +3 -0
  86. data/lib/active_support/core_ext/range/conversions.rb +0 -2
  87. data/lib/active_support/core_ext/range/include_range.rb +3 -1
  88. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  89. data/lib/active_support/core_ext/range.rb +0 -2
  90. data/lib/active_support/core_ext/string/access.rb +95 -90
  91. data/lib/active_support/core_ext/string/conversions.rb +27 -38
  92. data/lib/active_support/core_ext/string/encoding.rb +6 -9
  93. data/lib/active_support/core_ext/string/filters.rb +24 -18
  94. data/lib/active_support/core_ext/string/indent.rb +43 -0
  95. data/lib/active_support/core_ext/string/inflections.rb +70 -60
  96. data/lib/active_support/core_ext/string/inquiry.rb +2 -2
  97. data/lib/active_support/core_ext/string/multibyte.rb +41 -64
  98. data/lib/active_support/core_ext/string/output_safety.rb +59 -51
  99. data/lib/active_support/core_ext/string/zones.rb +13 -0
  100. data/lib/active_support/core_ext/string.rb +2 -3
  101. data/lib/active_support/core_ext/struct.rb +6 -0
  102. data/lib/active_support/core_ext/thread.rb +74 -0
  103. data/lib/active_support/core_ext/time/calculations.rb +108 -184
  104. data/lib/active_support/core_ext/time/conversions.rb +27 -51
  105. data/lib/active_support/core_ext/time/marshal.rb +0 -27
  106. data/lib/active_support/core_ext/time/zones.rb +27 -17
  107. data/lib/active_support/core_ext/time.rb +5 -0
  108. data/lib/active_support/core_ext/uri.rb +13 -17
  109. data/lib/active_support/core_ext.rb +3 -2
  110. data/lib/active_support/dependencies/autoload.rb +47 -20
  111. data/lib/active_support/dependencies.rb +160 -141
  112. data/lib/active_support/deprecation/behaviors.rb +44 -30
  113. data/lib/active_support/deprecation/instance_delegator.rb +24 -0
  114. data/lib/active_support/deprecation/method_wrappers.rb +33 -18
  115. data/lib/active_support/deprecation/proxy_wrappers.rb +58 -13
  116. data/lib/active_support/deprecation/reporting.rb +40 -11
  117. data/lib/active_support/deprecation.rb +39 -14
  118. data/lib/active_support/descendants_tracker.rb +34 -19
  119. data/lib/active_support/duration.rb +6 -8
  120. data/lib/active_support/file_update_checker.rb +63 -47
  121. data/lib/active_support/gzip.rb +11 -5
  122. data/lib/active_support/hash_with_indifferent_access.rb +127 -42
  123. data/lib/active_support/i18n.rb +4 -0
  124. data/lib/active_support/i18n_railtie.rb +5 -22
  125. data/lib/active_support/inflections.rb +14 -12
  126. data/lib/active_support/inflector/inflections.rb +108 -71
  127. data/lib/active_support/inflector/methods.rb +181 -160
  128. data/lib/active_support/inflector/transliterate.rb +16 -17
  129. data/lib/active_support/json/decoding.rb +18 -17
  130. data/lib/active_support/json/encoding.rb +93 -39
  131. data/lib/active_support/json/variable.rb +10 -1
  132. data/lib/active_support/key_generator.rb +75 -0
  133. data/lib/active_support/lazy_load_hooks.rb +21 -19
  134. data/lib/active_support/locale/en.yml +100 -3
  135. data/lib/active_support/log_subscriber/test_helper.rb +18 -15
  136. data/lib/active_support/log_subscriber.rb +35 -52
  137. data/lib/active_support/logger.rb +57 -0
  138. data/lib/active_support/logger_silence.rb +24 -0
  139. data/lib/active_support/message_encryptor.rb +38 -35
  140. data/lib/active_support/message_verifier.rb +9 -15
  141. data/lib/active_support/multibyte/chars.rb +80 -333
  142. data/lib/active_support/multibyte/unicode.rb +74 -64
  143. data/lib/active_support/multibyte.rb +5 -28
  144. data/lib/active_support/notifications/fanout.rb +112 -18
  145. data/lib/active_support/notifications/instrumenter.rb +33 -14
  146. data/lib/active_support/notifications.rb +79 -26
  147. data/lib/active_support/number_helper.rb +637 -0
  148. data/lib/active_support/ordered_hash.rb +8 -190
  149. data/lib/active_support/ordered_options.rb +21 -23
  150. data/lib/active_support/per_thread_registry.rb +52 -0
  151. data/lib/active_support/proxy_object.rb +13 -0
  152. data/lib/active_support/rails.rb +27 -0
  153. data/lib/active_support/railtie.rb +12 -32
  154. data/lib/active_support/rescuable.rb +9 -4
  155. data/lib/active_support/string_inquirer.rb +13 -8
  156. data/lib/active_support/subscriber.rb +93 -0
  157. data/lib/active_support/tagged_logging.rb +51 -73
  158. data/lib/active_support/test_case.rb +46 -17
  159. data/lib/active_support/testing/assertions.rb +56 -26
  160. data/lib/active_support/testing/autorun.rb +5 -0
  161. data/lib/active_support/testing/constant_lookup.rb +54 -0
  162. data/lib/active_support/testing/declarative.rb +1 -1
  163. data/lib/active_support/testing/deprecation.rb +0 -19
  164. data/lib/active_support/testing/isolation.rb +29 -58
  165. data/lib/active_support/testing/pending.rb +5 -43
  166. data/lib/active_support/testing/setup_and_teardown.rb +6 -92
  167. data/lib/active_support/testing/tagged_logging.rb +25 -0
  168. data/lib/active_support/time.rb +6 -21
  169. data/lib/active_support/time_with_zone.rb +80 -43
  170. data/lib/active_support/values/time_zone.rb +81 -60
  171. data/lib/active_support/values/unicode_tables.dat +0 -0
  172. data/lib/active_support/version.rb +7 -6
  173. data/lib/active_support/xml_mini/jdom.rb +9 -11
  174. data/lib/active_support/xml_mini/libxml.rb +1 -2
  175. data/lib/active_support/xml_mini/libxmlsax.rb +2 -3
  176. data/lib/active_support/xml_mini/nokogiri.rb +1 -2
  177. data/lib/active_support/xml_mini/nokogirisax.rb +2 -3
  178. data/lib/active_support/xml_mini/rexml.rb +6 -8
  179. data/lib/active_support/xml_mini.rb +35 -17
  180. data/lib/active_support.rb +8 -21
  181. metadata +104 -72
  182. data/lib/active_support/base64.rb +0 -54
  183. data/lib/active_support/core_ext/array/random_access.rb +0 -30
  184. data/lib/active_support/core_ext/date/freeze.rb +0 -33
  185. data/lib/active_support/core_ext/exception.rb +0 -3
  186. data/lib/active_support/core_ext/file/path.rb +0 -5
  187. data/lib/active_support/core_ext/float/rounding.rb +0 -19
  188. data/lib/active_support/core_ext/float.rb +0 -1
  189. data/lib/active_support/core_ext/hash/deep_dup.rb +0 -18
  190. data/lib/active_support/core_ext/io.rb +0 -15
  191. data/lib/active_support/core_ext/module/method_names.rb +0 -14
  192. data/lib/active_support/core_ext/module/synchronization.rb +0 -45
  193. data/lib/active_support/core_ext/process/daemon.rb +0 -23
  194. data/lib/active_support/core_ext/process.rb +0 -1
  195. data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
  196. data/lib/active_support/core_ext/range/cover.rb +0 -3
  197. data/lib/active_support/core_ext/rexml.rb +0 -46
  198. data/lib/active_support/core_ext/string/interpolation.rb +0 -2
  199. data/lib/active_support/core_ext/string/xchar.rb +0 -18
  200. data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
  201. data/lib/active_support/memoizable.rb +0 -116
  202. data/lib/active_support/multibyte/exceptions.rb +0 -8
  203. data/lib/active_support/multibyte/utils.rb +0 -60
  204. data/lib/active_support/ruby/shim.rb +0 -22
  205. data/lib/active_support/security_utils.rb +0 -27
  206. data/lib/active_support/testing/mochaing.rb +0 -7
  207. data/lib/active_support/testing/performance/jruby.rb +0 -115
  208. data/lib/active_support/testing/performance/rubinius.rb +0 -113
  209. data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
  210. data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
  211. data/lib/active_support/testing/performance/ruby.rb +0 -152
  212. data/lib/active_support/testing/performance.rb +0 -317
  213. data/lib/active_support/time/autoload.rb +0 -5
  214. 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. See http://www.unicode.org/reports/tr15/tr15-29.html for more
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 = '5.2.0'
14
+ UNICODE_VERSION = '6.2.0'
14
15
 
15
- # The default normalization used for operations that require normalization. It can be set to any of the
16
- # normalizations in NORMALIZATION_FORMS.
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 non-rendering character used to distinguish
54
- # between little and big endian. This is not an issue in utf-8, so it must be ignored.
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 codepoints
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
- # Unpack the string at codepoints boundaries. Raises an EncodingError when the encoding of the string isn't
65
- # valid UTF-8.
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 lists.
77
+ # Unpack the string at grapheme boundaries. Returns a list of character
78
+ # lists.
87
79
  #
88
- # Example:
89
- # Unicode.g_unpack('क्षि') # => [[2325, 2381], [2359], [2367]]
90
- # Unicode.g_unpack('Café') # => [[67], [97], [102], [233]]
91
- def g_unpack(string)
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 g_unpack.
112
+ # Reverse operation of unpack_graphemes.
122
113
  #
123
- # Example:
124
- # Unicode.g_pack(Unicode.g_unpack('क्षि')) # => 'क्षि'
125
- def g_pack(unpacked)
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 decompose_codepoints(type, codepoints)
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 decompose_codepoints(type, ncp.dup)
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 compose_codepoints(codepoints)
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 resulting in a valid UTF-8 string.
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 encoding is entirely CP1252 or ISO-8859-1.
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 considered the best normalization form for
277
- # passing strings to databases and validations.
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 the following:
281
- # <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
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 = u_unpack(string)
279
+ codepoints = string.codepoints.to_a
287
280
  case form
288
281
  when :d
289
- reorder_characters(decompose_codepoints(:canonical, codepoints))
282
+ reorder_characters(decompose(:canonical, codepoints))
290
283
  when :c
291
- compose_codepoints(reorder_characters(decompose_codepoints(:canonical, codepoints)))
284
+ compose(reorder_characters(decompose(:canonical, codepoints)))
292
285
  when :kd
293
- reorder_characters(decompose_codepoints(:compatability, codepoints))
286
+ reorder_characters(decompose(:compatability, codepoints))
294
287
  when :kc
295
- compose_codepoints(reorder_characters(decompose_codepoints(:compatability, codepoints)))
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 apply_mapping(string, mapping) #:nodoc:
302
- u_unpack(string).map do |codepoint|
303
- cp = database.codepoints[codepoint]
304
- if cp and (ncp = cp.send(mapping)) and ncp > 0
305
- ncp
306
- else
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
- # Holds data about a codepoint in the Unicode database
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 UnicodeDatabase.
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 Exception => e
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,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 to configure your own proxy
11
- # class so you can support other encodings. See the ActiveSupport::Multibyte::Chars implementation for
12
- # an example how to do this.
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,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 = Subscriber.new(pattern, block).tap do |s|
13
- @subscribers << s
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
- @subscribers.reject! {|s| s.matches?(subscriber)}
21
- @listeners_for.clear
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
- @listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
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,94 @@ module ActiveSupport
37
60
  def wait
38
61
  end
39
62
 
40
- class Subscriber #:nodoc:
41
- def initialize(pattern, delegate)
42
- @pattern = pattern
43
- @delegate = delegate
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
- def publish(message, *args)
47
- @delegate.call(message, *args)
78
+ class Evented #:nodoc:
79
+ def initialize(pattern, delegate)
80
+ @pattern = pattern
81
+ @delegate = delegate
82
+ @can_publish = delegate.respond_to?(:publish)
83
+ end
84
+
85
+ def publish(name, *args)
86
+ if @can_publish
87
+ @delegate.publish name, *args
88
+ end
89
+ end
90
+
91
+ def start(name, id, payload)
92
+ @delegate.start name, id, payload
93
+ end
94
+
95
+ def finish(name, id, payload)
96
+ @delegate.finish name, id, payload
97
+ end
98
+
99
+ def subscribed_to?(name)
100
+ @pattern === name.to_s
101
+ end
102
+
103
+ def matches?(subscriber_or_name)
104
+ self === subscriber_or_name ||
105
+ @pattern && @pattern === subscriber_or_name
106
+ end
48
107
  end
49
108
 
50
- def subscribed_to?(name)
51
- !@pattern || @pattern === name.to_s
109
+ class Timed < Evented
110
+ def initialize(pattern, delegate)
111
+ @timestack = []
112
+ super
113
+ end
114
+
115
+ def publish(name, *args)
116
+ @delegate.call name, *args
117
+ end
118
+
119
+ def start(name, id, payload)
120
+ @timestack.push Time.now
121
+ end
122
+
123
+ def finish(name, id, payload)
124
+ started = @timestack.pop
125
+ @delegate.call(name, started, Time.now, id, payload)
126
+ end
52
127
  end
53
128
 
54
- def matches?(subscriber_or_name)
55
- self === subscriber_or_name ||
56
- @pattern && @pattern === subscriber_or_name
129
+ class AllMessages # :nodoc:
130
+ def initialize(delegate)
131
+ @delegate = delegate
132
+ end
133
+
134
+ def start(name, id, payload)
135
+ @delegate.start name, id, payload
136
+ end
137
+
138
+ def finish(name, id, payload)
139
+ @delegate.finish name, id, payload
140
+ end
141
+
142
+ def publish(name, *args)
143
+ @delegate.publish name, *args
144
+ end
145
+
146
+ def subscribed_to?(name)
147
+ true
148
+ end
149
+
150
+ alias :matches? :===
57
151
  end
58
152
  end
59
153
  end
@@ -1,39 +1,51 @@
1
- require 'active_support/core_ext/module/delegation'
1
+ require 'securerandom'
2
2
 
3
3
  module ActiveSupport
4
4
  module Notifications
5
+ # Instrumenters are stored in a thread local.
5
6
  class Instrumenter
6
7
  attr_reader :id
7
8
 
8
9
  def initialize(notifier)
9
- @id = unique_id
10
+ @id = unique_id
10
11
  @notifier = notifier
11
12
  end
12
13
 
13
14
  # Instrument the given block by measuring the time taken to execute it
14
15
  # and publish it. Notice that events get sent even if an error occurs
15
- # in the passed-in block
16
+ # in the passed-in block.
16
17
  def instrument(name, payload={})
17
- started = Time.now
18
-
18
+ start name, payload
19
19
  begin
20
- yield
20
+ yield payload
21
21
  rescue Exception => e
22
22
  payload[:exception] = [e.class.name, e.message]
23
23
  raise e
24
24
  ensure
25
- @notifier.publish(name, started, Time.now, @id, payload)
25
+ finish name, payload
26
26
  end
27
27
  end
28
28
 
29
+ # Send a start notification with +name+ and +payload+.
30
+ def start(name, payload)
31
+ @notifier.start name, @id, payload
32
+ end
33
+
34
+ # Send a finish notification with +name+ and +payload+.
35
+ def finish(name, payload)
36
+ @notifier.finish name, @id, payload
37
+ end
38
+
29
39
  private
30
- def unique_id
31
- SecureRandom.hex(10)
32
- end
40
+
41
+ def unique_id
42
+ SecureRandom.hex(10)
43
+ end
33
44
  end
34
45
 
35
46
  class Event
36
- attr_reader :name, :time, :end, :transaction_id, :payload, :duration
47
+ attr_reader :name, :time, :transaction_id, :payload, :children
48
+ attr_accessor :end
37
49
 
38
50
  def initialize(name, start, ending, transaction_id, payload)
39
51
  @name = name
@@ -41,12 +53,19 @@ module ActiveSupport
41
53
  @time = start
42
54
  @transaction_id = transaction_id
43
55
  @end = ending
44
- @duration = 1000.0 * (@end - @time)
56
+ @children = []
57
+ end
58
+
59
+ def duration
60
+ 1000.0 * (self.end - time)
61
+ end
62
+
63
+ def <<(event)
64
+ @children << event
45
65
  end
46
66
 
47
67
  def parent_of?(event)
48
- start = (time - event.time) * 1000
49
- start <= 0 && (start + duration >= event.duration)
68
+ @children.include? event
50
69
  end
51
70
  end
52
71
  end