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.

Files changed (276) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +798 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +13 -7
  5. data/lib/active_support/array_inquirer.rb +44 -0
  6. data/lib/active_support/backtrace_cleaner.rb +38 -34
  7. data/lib/active_support/benchmarkable.rb +17 -28
  8. data/lib/active_support/cache/file_store.rb +85 -70
  9. data/lib/active_support/cache/mem_cache_store.rb +75 -66
  10. data/lib/active_support/cache/memory_store.rb +31 -23
  11. data/lib/active_support/cache/null_store.rb +41 -0
  12. data/lib/active_support/cache/strategy/local_cache.rb +73 -70
  13. data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
  14. data/lib/active_support/cache.rb +360 -294
  15. data/lib/active_support/callbacks.rb +563 -393
  16. data/lib/active_support/concern.rb +42 -34
  17. data/lib/active_support/concurrency/latch.rb +19 -0
  18. data/lib/active_support/concurrency/share_lock.rb +186 -0
  19. data/lib/active_support/configurable.rb +70 -12
  20. data/lib/active_support/core_ext/array/access.rb +53 -9
  21. data/lib/active_support/core_ext/array/conversions.rb +109 -62
  22. data/lib/active_support/core_ext/array/extract_options.rb +2 -2
  23. data/lib/active_support/core_ext/array/grouping.rb +39 -32
  24. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  25. data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -0
  26. data/lib/active_support/core_ext/array/wrap.rb +16 -18
  27. data/lib/active_support/core_ext/array.rb +2 -2
  28. data/lib/active_support/core_ext/benchmark.rb +7 -0
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -36
  30. data/lib/active_support/core_ext/class/attribute.rb +47 -34
  31. data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -79
  32. data/lib/active_support/core_ext/class/subclasses.rb +12 -7
  33. data/lib/active_support/core_ext/class.rb +0 -3
  34. data/lib/active_support/core_ext/date/blank.rb +12 -0
  35. data/lib/active_support/core_ext/date/calculations.rb +57 -167
  36. data/lib/active_support/core_ext/date/conversions.rb +31 -42
  37. data/lib/active_support/core_ext/date/zones.rb +2 -10
  38. data/lib/active_support/core_ext/date.rb +5 -0
  39. data/lib/active_support/core_ext/date_and_time/calculations.rb +335 -0
  40. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
  41. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  42. data/lib/active_support/core_ext/date_time/acts_like.rb +1 -0
  43. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  44. data/lib/active_support/core_ext/date_time/calculations.rb +132 -65
  45. data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
  46. data/lib/active_support/core_ext/date_time/conversions.rb +36 -34
  47. data/lib/active_support/core_ext/date_time.rb +5 -0
  48. data/lib/active_support/core_ext/digest/uuid.rb +51 -0
  49. data/lib/active_support/core_ext/enumerable.rb +81 -74
  50. data/lib/active_support/core_ext/file/atomic.rb +53 -26
  51. data/lib/active_support/core_ext/file.rb +0 -1
  52. data/lib/active_support/core_ext/hash/compact.rb +20 -0
  53. data/lib/active_support/core_ext/hash/conversions.rb +175 -70
  54. data/lib/active_support/core_ext/hash/deep_merge.rb +30 -8
  55. data/lib/active_support/core_ext/hash/except.rb +11 -12
  56. data/lib/active_support/core_ext/hash/indifferent_access.rb +7 -8
  57. data/lib/active_support/core_ext/hash/keys.rb +147 -24
  58. data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
  59. data/lib/active_support/core_ext/hash/slice.rb +22 -14
  60. data/lib/active_support/core_ext/hash/transform_values.rb +29 -0
  61. data/lib/active_support/core_ext/hash.rb +2 -2
  62. data/lib/active_support/core_ext/integer/inflections.rb +13 -1
  63. data/lib/active_support/core_ext/integer/multiple.rb +4 -0
  64. data/lib/active_support/core_ext/integer/time.rb +12 -22
  65. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -2
  66. data/lib/active_support/core_ext/kernel/concern.rb +12 -0
  67. data/lib/active_support/core_ext/kernel/debugger.rb +2 -15
  68. data/lib/active_support/core_ext/kernel/reporting.rb +12 -62
  69. data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
  70. data/lib/active_support/core_ext/kernel.rb +2 -3
  71. data/lib/active_support/core_ext/load_error.rb +14 -7
  72. data/lib/active_support/core_ext/marshal.rb +22 -0
  73. data/lib/active_support/core_ext/module/aliasing.rb +16 -12
  74. data/lib/active_support/core_ext/module/anonymous.rb +12 -8
  75. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  76. data/lib/active_support/core_ext/module/attribute_accessors.rb +165 -13
  77. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  78. data/lib/active_support/core_ext/module/concerning.rb +135 -0
  79. data/lib/active_support/core_ext/module/delegation.rb +141 -68
  80. data/lib/active_support/core_ext/module/deprecation.rb +17 -3
  81. data/lib/active_support/core_ext/module/introspection.rb +9 -31
  82. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -0
  83. data/lib/active_support/core_ext/module/qualified_const.rb +70 -0
  84. data/lib/active_support/core_ext/module/reachable.rb +1 -3
  85. data/lib/active_support/core_ext/module/remove_method.rb +24 -5
  86. data/lib/active_support/core_ext/module.rb +3 -3
  87. data/lib/active_support/core_ext/name_error.rb +15 -2
  88. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  89. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  90. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  91. data/lib/active_support/core_ext/numeric/time.rb +31 -36
  92. data/lib/active_support/core_ext/numeric.rb +2 -0
  93. data/lib/active_support/core_ext/object/acts_like.rb +4 -4
  94. data/lib/active_support/core_ext/object/blank.rb +52 -18
  95. data/lib/active_support/core_ext/object/deep_dup.rb +53 -0
  96. data/lib/active_support/core_ext/object/duplicable.rb +12 -20
  97. data/lib/active_support/core_ext/object/inclusion.rb +13 -1
  98. data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
  99. data/lib/active_support/core_ext/object/json.rb +205 -0
  100. data/lib/active_support/core_ext/object/to_param.rb +1 -55
  101. data/lib/active_support/core_ext/object/to_query.rb +66 -9
  102. data/lib/active_support/core_ext/object/try.rb +124 -33
  103. data/lib/active_support/core_ext/object/with_options.rb +37 -11
  104. data/lib/active_support/core_ext/object.rb +2 -1
  105. data/lib/active_support/core_ext/range/conversions.rb +17 -7
  106. data/lib/active_support/core_ext/range/each.rb +21 -0
  107. data/lib/active_support/core_ext/range/include_range.rb +20 -18
  108. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  109. data/lib/active_support/core_ext/range.rb +1 -2
  110. data/lib/active_support/core_ext/securerandom.rb +23 -0
  111. data/lib/active_support/core_ext/string/access.rb +95 -90
  112. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  113. data/lib/active_support/core_ext/string/conversions.rb +41 -38
  114. data/lib/active_support/core_ext/string/exclude.rb +6 -1
  115. data/lib/active_support/core_ext/string/filters.rb +70 -17
  116. data/lib/active_support/core_ext/string/indent.rb +43 -0
  117. data/lib/active_support/core_ext/string/inflections.rb +139 -59
  118. data/lib/active_support/core_ext/string/inquiry.rb +2 -2
  119. data/lib/active_support/core_ext/string/multibyte.rb +46 -65
  120. data/lib/active_support/core_ext/string/output_safety.rb +153 -56
  121. data/lib/active_support/core_ext/string/strip.rb +3 -6
  122. data/lib/active_support/core_ext/string/zones.rb +14 -0
  123. data/lib/active_support/core_ext/string.rb +2 -3
  124. data/lib/active_support/core_ext/struct.rb +3 -0
  125. data/lib/active_support/core_ext/time/calculations.rb +173 -173
  126. data/lib/active_support/core_ext/time/compatibility.rb +5 -0
  127. data/lib/active_support/core_ext/time/conversions.rb +33 -29
  128. data/lib/active_support/core_ext/time/marshal.rb +2 -56
  129. data/lib/active_support/core_ext/time/zones.rb +57 -32
  130. data/lib/active_support/core_ext/time.rb +5 -0
  131. data/lib/active_support/core_ext/uri.rb +13 -19
  132. data/lib/active_support/core_ext.rb +3 -2
  133. data/lib/active_support/dependencies/autoload.rb +47 -20
  134. data/lib/active_support/dependencies/interlock.rb +51 -0
  135. data/lib/active_support/dependencies.rb +315 -265
  136. data/lib/active_support/deprecation/behaviors.rb +71 -30
  137. data/lib/active_support/deprecation/instance_delegator.rb +24 -0
  138. data/lib/active_support/deprecation/method_wrappers.rb +59 -18
  139. data/lib/active_support/deprecation/proxy_wrappers.rb +82 -14
  140. data/lib/active_support/deprecation/reporting.rb +61 -14
  141. data/lib/active_support/deprecation.rb +38 -13
  142. data/lib/active_support/descendants_tracker.rb +34 -19
  143. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  144. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  145. data/lib/active_support/duration.rb +85 -14
  146. data/lib/active_support/evented_file_update_checker.rb +194 -0
  147. data/lib/active_support/execution_wrapper.rb +117 -0
  148. data/lib/active_support/executor.rb +6 -0
  149. data/lib/active_support/file_update_checker.rb +138 -17
  150. data/lib/active_support/gem_version.rb +15 -0
  151. data/lib/active_support/gzip.rb +11 -5
  152. data/lib/active_support/hash_with_indifferent_access.rb +199 -49
  153. data/lib/active_support/i18n.rb +6 -2
  154. data/lib/active_support/i18n_railtie.rb +40 -21
  155. data/lib/active_support/inflections.rb +22 -13
  156. data/lib/active_support/inflector/inflections.rb +175 -144
  157. data/lib/active_support/inflector/methods.rb +328 -91
  158. data/lib/active_support/inflector/transliterate.rb +51 -37
  159. data/lib/active_support/json/decoding.rb +31 -22
  160. data/lib/active_support/json/encoding.rb +88 -248
  161. data/lib/active_support/key_generator.rb +71 -0
  162. data/lib/active_support/lazy_load_hooks.rb +27 -25
  163. data/lib/active_support/locale/en.yml +102 -3
  164. data/lib/active_support/log_subscriber/test_helper.rb +24 -21
  165. data/lib/active_support/log_subscriber.rb +36 -49
  166. data/lib/active_support/logger.rb +106 -0
  167. data/lib/active_support/logger_silence.rb +28 -0
  168. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  169. data/lib/active_support/message_encryptor.rb +72 -36
  170. data/lib/active_support/message_verifier.rb +96 -24
  171. data/lib/active_support/multibyte/chars.rb +88 -333
  172. data/lib/active_support/multibyte/unicode.rb +156 -136
  173. data/lib/active_support/multibyte.rb +5 -28
  174. data/lib/active_support/notifications/fanout.rb +115 -19
  175. data/lib/active_support/notifications/instrumenter.rb +52 -15
  176. data/lib/active_support/notifications.rb +168 -33
  177. data/lib/active_support/number_helper/number_converter.rb +182 -0
  178. data/lib/active_support/number_helper/number_to_currency_converter.rb +44 -0
  179. data/lib/active_support/number_helper/number_to_delimited_converter.rb +28 -0
  180. data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
  181. data/lib/active_support/number_helper/number_to_human_size_converter.rb +62 -0
  182. data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
  183. data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
  184. data/lib/active_support/number_helper/number_to_rounded_converter.rb +92 -0
  185. data/lib/active_support/number_helper.rb +368 -0
  186. data/lib/active_support/option_merger.rb +1 -1
  187. data/lib/active_support/ordered_hash.rb +18 -183
  188. data/lib/active_support/ordered_options.rb +44 -24
  189. data/lib/active_support/per_thread_registry.rb +58 -0
  190. data/lib/active_support/proxy_object.rb +13 -0
  191. data/lib/active_support/rails.rb +27 -0
  192. data/lib/active_support/railtie.rb +25 -34
  193. data/lib/active_support/reloader.rb +129 -0
  194. data/lib/active_support/rescuable.rb +98 -48
  195. data/lib/active_support/security_utils.rb +27 -0
  196. data/lib/active_support/string_inquirer.rb +14 -9
  197. data/lib/active_support/subscriber.rb +120 -0
  198. data/lib/active_support/tagged_logging.rb +78 -0
  199. data/lib/active_support/test_case.rb +69 -17
  200. data/lib/active_support/testing/assertions.rb +43 -41
  201. data/lib/active_support/testing/autorun.rb +12 -0
  202. data/lib/active_support/testing/constant_lookup.rb +50 -0
  203. data/lib/active_support/testing/declarative.rb +7 -21
  204. data/lib/active_support/testing/deprecation.rb +14 -33
  205. data/lib/active_support/testing/file_fixtures.rb +34 -0
  206. data/lib/active_support/testing/isolation.rb +53 -95
  207. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  208. data/lib/active_support/testing/setup_and_teardown.rb +21 -82
  209. data/lib/active_support/testing/stream.rb +42 -0
  210. data/lib/active_support/testing/tagged_logging.rb +25 -0
  211. data/lib/active_support/testing/time_helpers.rb +134 -0
  212. data/lib/active_support/time.rb +6 -23
  213. data/lib/active_support/time_with_zone.rb +239 -92
  214. data/lib/active_support/values/time_zone.rb +236 -160
  215. data/lib/active_support/values/unicode_tables.dat +0 -0
  216. data/lib/active_support/version.rb +5 -7
  217. data/lib/active_support/xml_mini/jdom.rb +19 -13
  218. data/lib/active_support/xml_mini/libxml.rb +3 -4
  219. data/lib/active_support/xml_mini/libxmlsax.rb +2 -3
  220. data/lib/active_support/xml_mini/nokogiri.rb +3 -4
  221. data/lib/active_support/xml_mini/nokogirisax.rb +2 -3
  222. data/lib/active_support/xml_mini/rexml.rb +8 -10
  223. data/lib/active_support/xml_mini.rb +66 -34
  224. data/lib/active_support.rb +40 -23
  225. metadata +185 -134
  226. data/CHANGELOG +0 -1534
  227. data/lib/active_support/base64.rb +0 -42
  228. data/lib/active_support/basic_object.rb +0 -21
  229. data/lib/active_support/buffered_logger.rb +0 -137
  230. data/lib/active_support/cache/compressed_mem_cache_store.rb +0 -13
  231. data/lib/active_support/cache/synchronized_memory_store.rb +0 -11
  232. data/lib/active_support/core_ext/array/random_access.rb +0 -30
  233. data/lib/active_support/core_ext/array/uniq_by.rb +0 -16
  234. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -44
  235. data/lib/active_support/core_ext/class/inheritable_attributes.rb +0 -178
  236. data/lib/active_support/core_ext/date/freeze.rb +0 -31
  237. data/lib/active_support/core_ext/date_time/zones.rb +0 -21
  238. data/lib/active_support/core_ext/exception.rb +0 -3
  239. data/lib/active_support/core_ext/file/path.rb +0 -5
  240. data/lib/active_support/core_ext/float/rounding.rb +0 -19
  241. data/lib/active_support/core_ext/float.rb +0 -1
  242. data/lib/active_support/core_ext/hash/deep_dup.rb +0 -11
  243. data/lib/active_support/core_ext/hash/diff.rb +0 -13
  244. data/lib/active_support/core_ext/kernel/requires.rb +0 -28
  245. data/lib/active_support/core_ext/logger.rb +0 -81
  246. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +0 -31
  247. data/lib/active_support/core_ext/module/method_names.rb +0 -14
  248. data/lib/active_support/core_ext/module/synchronization.rb +0 -43
  249. data/lib/active_support/core_ext/object/to_json.rb +0 -19
  250. data/lib/active_support/core_ext/proc.rb +0 -14
  251. data/lib/active_support/core_ext/process/daemon.rb +0 -23
  252. data/lib/active_support/core_ext/process.rb +0 -1
  253. data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
  254. data/lib/active_support/core_ext/range/cover.rb +0 -3
  255. data/lib/active_support/core_ext/rexml.rb +0 -46
  256. data/lib/active_support/core_ext/string/encoding.rb +0 -11
  257. data/lib/active_support/core_ext/string/interpolation.rb +0 -2
  258. data/lib/active_support/core_ext/string/xchar.rb +0 -18
  259. data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
  260. data/lib/active_support/file_watcher.rb +0 -36
  261. data/lib/active_support/json/variable.rb +0 -9
  262. data/lib/active_support/memoizable.rb +0 -105
  263. data/lib/active_support/multibyte/exceptions.rb +0 -8
  264. data/lib/active_support/multibyte/utils.rb +0 -60
  265. data/lib/active_support/ruby/shim.rb +0 -22
  266. data/lib/active_support/secure_random.rb +0 -6
  267. data/lib/active_support/testing/mochaing.rb +0 -7
  268. data/lib/active_support/testing/pending.rb +0 -52
  269. data/lib/active_support/testing/performance/jruby.rb +0 -115
  270. data/lib/active_support/testing/performance/rubinius.rb +0 -113
  271. data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
  272. data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
  273. data/lib/active_support/testing/performance/ruby.rb +0 -152
  274. data/lib/active_support/testing/performance.rb +0 -317
  275. data/lib/active_support/time/autoload.rb +0 -5
  276. 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. See http://www.unicode.org/reports/tr15/tr15-29.html for more
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 = '5.2.0'
13
+ UNICODE_VERSION = '8.0.0'
14
14
 
15
- # The default normalization used for operations that require normalization. It can be set to any of the
16
- # normalizations in NORMALIZATION_FORMS.
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 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.
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 codepoints
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
- # 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>,
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 lists.
75
+ # Unpack the string at grapheme boundaries. Returns a list of character
76
+ # lists.
87
77
  #
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)
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
- if (
102
- # CR X LF
103
- ( previous == database.boundary[:cr] and current == database.boundary[:lf] ) or
104
- # L X (L|V|LV|LVT)
105
- ( database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt]) ) or
106
- # (LV|V) X (V|T)
107
- ( in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t]) ) or
108
- # (LVT|T) X (T)
109
- ( in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current ) or
110
- # X Extend
111
- (database.boundary[:extend] === current)
112
- )
113
- else
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 g_unpack.
135
+ # Reverse operation of unpack_graphemes.
122
136
  #
123
- # Example:
124
- # Unicode.g_pack(Unicode.g_unpack('क्षि')) # => 'क्षि'
125
- def g_pack(unpacked)
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 decompose_codepoints(type, codepoints)
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 == :compatability)
159
- decomposed.concat decompose_codepoints(type, ncp.dup)
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 compose_codepoints(codepoints)
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
- # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent resulting in a valid UTF-8 string.
226
- #
227
- # Passing +true+ will forcibly tidy all bytes, assuming that the string's encoding is entirely CP1252 or ISO-8859-1.
228
- def tidy_bytes(string, force = false)
229
- if force
230
- return string.unpack("C*").map do |b|
231
- tidy_byte(b)
232
- end.flatten.compact.pack("C*").unpack("U*").pack("U*")
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
- bytes = string.unpack("C*")
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
- # Impossible or highly unlikely byte? Clean it.
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 considered the best normalization form for
277
- # passing strings to databases and validations.
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 the following:
281
- # <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
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 = u_unpack(string)
288
+ codepoints = string.codepoints.to_a
287
289
  case form
288
290
  when :d
289
- reorder_characters(decompose_codepoints(:canonical, codepoints))
291
+ reorder_characters(decompose(:canonical, codepoints))
290
292
  when :c
291
- compose_codepoints(reorder_characters(decompose_codepoints(:canonical, codepoints)))
293
+ compose(reorder_characters(decompose(:canonical, codepoints)))
292
294
  when :kd
293
- reorder_characters(decompose_codepoints(:compatability, codepoints))
295
+ reorder_characters(decompose(:compatibility, codepoints))
294
296
  when :kc
295
- compose_codepoints(reorder_characters(decompose_codepoints(:compatability, codepoints)))
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 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*')
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 UnicodeDatabase.
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 Exception => e
346
- raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable")
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.each do |k,_|
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 tidy_byte(byte)
378
- if byte < 160
379
- [database.cp1252[byte] || byte].pack("U").unpack("C*")
380
- elsif byte < 192
381
- [194, byte]
382
- else
383
- [195, byte - 64]
384
- end
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 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,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 = 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
- def unsubscribe(subscriber)
20
- @subscribers.reject! {|s| s.matches?(subscriber)}
21
- @listeners_for.clear
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
- @listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
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
- class Subscriber #:nodoc:
41
- def initialize(pattern, delegate)
42
- @pattern = pattern
43
- @delegate = delegate
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
- def publish(message, *args)
47
- @delegate.call(message, *args)
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
- def subscribed_to?(name)
51
- !@pattern || @pattern === name.to_s
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
- def matches?(subscriber_or_name)
55
- self === subscriber_or_name ||
56
- @pattern && @pattern === subscriber_or_name
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