activesupport 2.3.5 → 3.0.0.beta3

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 (391) hide show
  1. data/CHANGELOG +66 -9
  2. data/lib/active_support/all.rb +2 -7
  3. data/lib/active_support/backtrace_cleaner.rb +31 -9
  4. data/lib/active_support/base64.rb +9 -0
  5. data/lib/active_support/basic_object.rb +7 -10
  6. data/lib/active_support/benchmarkable.rb +60 -0
  7. data/lib/active_support/buffered_logger.rb +14 -9
  8. data/lib/active_support/cache/compressed_mem_cache_store.rb +2 -0
  9. data/lib/active_support/cache/file_store.rb +35 -17
  10. data/lib/active_support/cache/mem_cache_store.rb +32 -23
  11. data/lib/active_support/cache/memory_store.rb +17 -10
  12. data/lib/active_support/cache/strategy/local_cache.rb +9 -1
  13. data/lib/active_support/cache.rb +75 -55
  14. data/lib/active_support/callbacks.rb +490 -169
  15. data/lib/active_support/concern.rb +29 -0
  16. data/lib/active_support/configurable.rb +35 -0
  17. data/lib/active_support/core_ext/array/access.rb +39 -46
  18. data/lib/active_support/core_ext/array/conversions.rb +145 -182
  19. data/lib/active_support/core_ext/array/extract_options.rb +26 -17
  20. data/lib/active_support/core_ext/array/grouping.rb +87 -93
  21. data/lib/active_support/core_ext/array/random_access.rb +4 -10
  22. data/lib/active_support/core_ext/array/uniq_by.rb +17 -0
  23. data/lib/active_support/core_ext/array/wrap.rb +22 -0
  24. data/lib/active_support/core_ext/array.rb +2 -10
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +27 -0
  26. data/lib/active_support/core_ext/big_decimal.rb +1 -0
  27. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +16 -20
  28. data/lib/active_support/core_ext/cgi.rb +0 -4
  29. data/lib/active_support/core_ext/class/attribute.rb +70 -0
  30. data/lib/active_support/core_ext/class/attribute_accessors.rb +40 -31
  31. data/lib/active_support/core_ext/class/delegating_attributes.rb +37 -40
  32. data/lib/active_support/core_ext/class/inheritable_attributes.rb +100 -11
  33. data/lib/active_support/core_ext/class/subclasses.rb +55 -0
  34. data/lib/active_support/core_ext/class.rb +1 -1
  35. data/lib/active_support/core_ext/date/acts_like.rb +8 -0
  36. data/lib/active_support/core_ext/date/calculations.rb +218 -228
  37. data/lib/active_support/core_ext/date/conversions.rb +87 -96
  38. data/lib/active_support/core_ext/date/freeze.rb +31 -0
  39. data/lib/active_support/core_ext/date_time/acts_like.rb +13 -0
  40. data/lib/active_support/core_ext/date_time/calculations.rb +97 -110
  41. data/lib/active_support/core_ext/date_time/conversions.rb +85 -85
  42. data/lib/active_support/core_ext/date_time/zones.rb +17 -0
  43. data/lib/active_support/core_ext/enumerable.rb +18 -13
  44. data/lib/active_support/core_ext/exception.rb +1 -43
  45. data/lib/active_support/core_ext/file/atomic.rb +35 -40
  46. data/lib/active_support/core_ext/file/path.rb +5 -0
  47. data/lib/active_support/core_ext/file.rb +0 -4
  48. data/lib/active_support/core_ext/float/rounding.rb +15 -20
  49. data/lib/active_support/core_ext/float.rb +0 -6
  50. data/lib/active_support/core_ext/hash/conversions.rb +255 -229
  51. data/lib/active_support/core_ext/hash/deep_merge.rb +12 -19
  52. data/lib/active_support/core_ext/hash/diff.rb +11 -17
  53. data/lib/active_support/core_ext/hash/except.rb +21 -22
  54. data/lib/active_support/core_ext/hash/indifferent_access.rb +8 -137
  55. data/lib/active_support/core_ext/hash/keys.rb +38 -45
  56. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -32
  57. data/lib/active_support/core_ext/hash/slice.rb +35 -37
  58. data/lib/active_support/core_ext/hash.rb +8 -14
  59. data/lib/active_support/core_ext/integer/inflections.rb +10 -16
  60. data/lib/active_support/core_ext/integer/multiple.rb +6 -0
  61. data/lib/active_support/core_ext/integer/time.rb +36 -42
  62. data/lib/active_support/core_ext/integer.rb +1 -7
  63. data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
  64. data/lib/active_support/core_ext/kernel/reporting.rb +9 -7
  65. data/lib/active_support/core_ext/kernel/requires.rb +3 -1
  66. data/lib/active_support/core_ext/kernel/singleton_class.rb +13 -0
  67. data/lib/active_support/core_ext/kernel.rb +1 -1
  68. data/lib/active_support/core_ext/load_error.rb +16 -32
  69. data/lib/active_support/core_ext/logger.rb +3 -2
  70. data/lib/active_support/core_ext/module/aliasing.rb +64 -68
  71. data/lib/active_support/core_ext/module/anonymous.rb +24 -0
  72. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +1 -1
  73. data/lib/active_support/core_ext/module/attr_internal.rb +4 -4
  74. data/lib/active_support/core_ext/module/attribute_accessors.rb +48 -42
  75. data/lib/active_support/core_ext/module/delegation.rb +22 -11
  76. data/lib/active_support/core_ext/module/deprecation.rb +9 -0
  77. data/lib/active_support/core_ext/module/introspection.rb +77 -79
  78. data/lib/active_support/core_ext/module/method_names.rb +14 -0
  79. data/lib/active_support/core_ext/module/reachable.rb +10 -0
  80. data/lib/active_support/core_ext/module/remove_method.rb +6 -0
  81. data/lib/active_support/core_ext/module/synchronization.rb +4 -1
  82. data/lib/active_support/core_ext/module.rb +7 -18
  83. data/lib/active_support/core_ext/name_error.rb +3 -4
  84. data/lib/active_support/core_ext/numeric/bytes.rb +35 -41
  85. data/lib/active_support/core_ext/numeric/time.rb +70 -74
  86. data/lib/active_support/core_ext/numeric.rb +1 -8
  87. data/lib/active_support/core_ext/object/acts_like.rb +10 -0
  88. data/lib/active_support/core_ext/object/blank.rb +20 -2
  89. data/lib/active_support/core_ext/object/conversions.rb +4 -15
  90. data/lib/active_support/core_ext/object/duplicable.rb +65 -0
  91. data/lib/active_support/core_ext/object/extending.rb +8 -77
  92. data/lib/active_support/core_ext/object/instance_variables.rb +0 -7
  93. data/lib/active_support/core_ext/object/misc.rb +2 -90
  94. data/lib/active_support/core_ext/object/returning.rb +42 -0
  95. data/lib/active_support/core_ext/object/to_param.rb +49 -0
  96. data/lib/active_support/core_ext/object/to_query.rb +27 -0
  97. data/lib/active_support/core_ext/{try.rb → object/try.rb} +4 -4
  98. data/lib/active_support/core_ext/object/with_options.rb +24 -0
  99. data/lib/active_support/core_ext/object.rb +10 -2
  100. data/lib/active_support/core_ext/proc.rb +3 -1
  101. data/lib/active_support/core_ext/process/daemon.rb +17 -19
  102. data/lib/active_support/core_ext/range/blockless_step.rb +24 -27
  103. data/lib/active_support/core_ext/range/conversions.rb +17 -23
  104. data/lib/active_support/core_ext/range/include_range.rb +18 -27
  105. data/lib/active_support/core_ext/range/overlaps.rb +6 -13
  106. data/lib/active_support/core_ext/range.rb +2 -9
  107. data/lib/active_support/core_ext/regexp.rb +5 -0
  108. data/lib/active_support/core_ext/rexml.rb +12 -7
  109. data/lib/active_support/core_ext/string/access.rb +88 -95
  110. data/lib/active_support/core_ext/string/behavior.rb +6 -12
  111. data/lib/active_support/core_ext/string/conversions.rb +20 -21
  112. data/lib/active_support/core_ext/string/exclude.rb +6 -0
  113. data/lib/active_support/core_ext/string/filters.rb +17 -23
  114. data/lib/active_support/core_ext/string/inflections.rb +147 -154
  115. data/lib/active_support/core_ext/string/interpolation.rb +1 -0
  116. data/lib/active_support/core_ext/string/multibyte.rb +68 -74
  117. data/lib/active_support/core_ext/string/output_safety.rb +105 -44
  118. data/lib/active_support/core_ext/string/starts_ends_with.rb +3 -34
  119. data/lib/active_support/core_ext/string/xchar.rb +10 -3
  120. data/lib/active_support/core_ext/string.rb +6 -20
  121. data/lib/active_support/core_ext/time/acts_like.rb +8 -0
  122. data/lib/active_support/core_ext/time/calculations.rb +276 -299
  123. data/lib/active_support/core_ext/time/conversions.rb +79 -84
  124. data/lib/active_support/core_ext/time/marshal.rb +56 -0
  125. data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +10 -0
  126. data/lib/active_support/core_ext/time/zones.rb +73 -81
  127. data/lib/active_support/core_ext/uri.rb +2 -1
  128. data/lib/active_support/core_ext.rb +2 -7
  129. data/lib/active_support/dependencies/autoload.rb +50 -0
  130. data/lib/active_support/dependencies.rb +168 -197
  131. data/lib/active_support/deprecation/behaviors.rb +38 -0
  132. data/lib/active_support/deprecation/method_wrappers.rb +29 -0
  133. data/lib/active_support/deprecation/proxy_wrappers.rb +74 -0
  134. data/lib/active_support/deprecation/reporting.rb +56 -0
  135. data/lib/active_support/deprecation.rb +9 -187
  136. data/lib/active_support/duration.rb +6 -2
  137. data/lib/active_support/hash_with_indifferent_access.rb +141 -0
  138. data/lib/active_support/i18n.rb +3 -0
  139. data/lib/active_support/inflections.rb +1 -1
  140. data/lib/active_support/inflector/inflections.rb +211 -0
  141. data/lib/active_support/inflector/methods.rb +141 -0
  142. data/lib/active_support/inflector/transliterate.rb +77 -0
  143. data/lib/active_support/inflector.rb +4 -403
  144. data/lib/active_support/json/backends/jsongem.rb +16 -10
  145. data/lib/active_support/json/backends/yajl.rb +40 -0
  146. data/lib/active_support/json/backends/yaml.rb +14 -8
  147. data/lib/active_support/json/decoding.rb +17 -1
  148. data/lib/active_support/json/encoding.rb +164 -35
  149. data/lib/active_support/json/variable.rb +4 -3
  150. data/lib/active_support/lazy_load_hooks.rb +17 -0
  151. data/lib/active_support/memoizable.rb +8 -5
  152. data/lib/active_support/message_encryptor.rb +1 -0
  153. data/lib/active_support/message_verifier.rb +12 -29
  154. data/lib/active_support/multibyte/chars.rb +88 -31
  155. data/lib/active_support/multibyte/unicode_database.rb +5 -5
  156. data/lib/active_support/multibyte/utils.rb +6 -7
  157. data/lib/active_support/multibyte.rb +11 -6
  158. data/lib/active_support/notifications/fanout.rb +83 -0
  159. data/lib/active_support/notifications/instrumenter.rb +50 -0
  160. data/lib/active_support/notifications.rb +81 -0
  161. data/lib/active_support/option_merger.rb +2 -0
  162. data/lib/active_support/ordered_hash.rb +28 -11
  163. data/lib/active_support/ordered_options.rb +9 -1
  164. data/lib/active_support/railtie.rb +64 -0
  165. data/lib/active_support/rescuable.rb +11 -6
  166. data/lib/active_support/ruby/shim.rb +21 -0
  167. data/lib/active_support/test_case.rb +10 -8
  168. data/lib/active_support/testing/assertions.rb +17 -0
  169. data/lib/active_support/testing/declarative.rb +31 -12
  170. data/lib/active_support/testing/deprecation.rb +8 -10
  171. data/lib/active_support/testing/isolation.rb +153 -0
  172. data/lib/active_support/testing/pending.rb +48 -0
  173. data/lib/active_support/testing/performance.rb +342 -339
  174. data/lib/active_support/testing/setup_and_teardown.rb +48 -31
  175. data/lib/active_support/time/autoload.rb +5 -0
  176. data/lib/active_support/time.rb +34 -0
  177. data/lib/active_support/time_with_zone.rb +18 -12
  178. data/lib/active_support/values/time_zone.rb +51 -68
  179. data/lib/active_support/version.rb +5 -4
  180. data/lib/active_support/whiny_nil.rb +5 -9
  181. data/lib/active_support/xml_mini/jdom.rb +13 -7
  182. data/lib/active_support/xml_mini/libxml.rb +38 -91
  183. data/lib/active_support/xml_mini/libxmlsax.rb +85 -0
  184. data/lib/active_support/xml_mini/nokogiri.rb +40 -31
  185. data/lib/active_support/xml_mini/nokogirisax.rb +83 -0
  186. data/lib/active_support/xml_mini/rexml.rb +30 -9
  187. data/lib/active_support/xml_mini.rb +2 -0
  188. data/lib/active_support.rb +46 -30
  189. metadata +136 -215
  190. data/lib/active_support/cache/drb_store.rb +0 -14
  191. data/lib/active_support/core_ext/array/wrapper.rb +0 -24
  192. data/lib/active_support/core_ext/base64/encoding.rb +0 -16
  193. data/lib/active_support/core_ext/base64.rb +0 -4
  194. data/lib/active_support/core_ext/bigdecimal/conversions.rb +0 -37
  195. data/lib/active_support/core_ext/bigdecimal.rb +0 -6
  196. data/lib/active_support/core_ext/blank.rb +0 -2
  197. data/lib/active_support/core_ext/class/removal.rb +0 -50
  198. data/lib/active_support/core_ext/date/behavior.rb +0 -42
  199. data/lib/active_support/core_ext/date.rb +0 -10
  200. data/lib/active_support/core_ext/date_time.rb +0 -12
  201. data/lib/active_support/core_ext/duplicable.rb +0 -43
  202. data/lib/active_support/core_ext/float/time.rb +0 -27
  203. data/lib/active_support/core_ext/integer/even_odd.rb +0 -29
  204. data/lib/active_support/core_ext/kernel/daemonizing.rb +0 -7
  205. data/lib/active_support/core_ext/module/inclusion.rb +0 -30
  206. data/lib/active_support/core_ext/module/loading.rb +0 -23
  207. data/lib/active_support/core_ext/module/model_naming.rb +0 -25
  208. data/lib/active_support/core_ext/numeric/conversions.rb +0 -19
  209. data/lib/active_support/core_ext/object/metaclass.rb +0 -13
  210. data/lib/active_support/core_ext/pathname/clean_within.rb +0 -14
  211. data/lib/active_support/core_ext/pathname.rb +0 -7
  212. data/lib/active_support/core_ext/string/bytesize.rb +0 -5
  213. data/lib/active_support/core_ext/string/iterators.rb +0 -23
  214. data/lib/active_support/core_ext/symbol.rb +0 -14
  215. data/lib/active_support/core_ext/time/behavior.rb +0 -13
  216. data/lib/active_support/core_ext/time.rb +0 -42
  217. data/lib/active_support/json/encoders/date.rb +0 -22
  218. data/lib/active_support/json/encoders/date_time.rb +0 -22
  219. data/lib/active_support/json/encoders/enumerable.rb +0 -17
  220. data/lib/active_support/json/encoders/false_class.rb +0 -7
  221. data/lib/active_support/json/encoders/hash.rb +0 -56
  222. data/lib/active_support/json/encoders/nil_class.rb +0 -7
  223. data/lib/active_support/json/encoders/numeric.rb +0 -21
  224. data/lib/active_support/json/encoders/object.rb +0 -10
  225. data/lib/active_support/json/encoders/regexp.rb +0 -9
  226. data/lib/active_support/json/encoders/string.rb +0 -9
  227. data/lib/active_support/json/encoders/symbol.rb +0 -5
  228. data/lib/active_support/json/encoders/time.rb +0 -22
  229. data/lib/active_support/json/encoders/true_class.rb +0 -7
  230. data/lib/active_support/vendor/builder-2.1.2/blankslate.rb +0 -113
  231. data/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb +0 -20
  232. data/lib/active_support/vendor/builder-2.1.2/builder/css.rb +0 -250
  233. data/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb +0 -115
  234. data/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb +0 -139
  235. data/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +0 -63
  236. data/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb +0 -328
  237. data/lib/active_support/vendor/builder-2.1.2/builder.rb +0 -13
  238. data/lib/active_support/vendor/i18n-0.1.3/MIT-LICENSE +0 -20
  239. data/lib/active_support/vendor/i18n-0.1.3/README.textile +0 -20
  240. data/lib/active_support/vendor/i18n-0.1.3/Rakefile +0 -5
  241. data/lib/active_support/vendor/i18n-0.1.3/i18n.gemspec +0 -27
  242. data/lib/active_support/vendor/i18n-0.1.3/lib/i18n/backend/simple.rb +0 -214
  243. data/lib/active_support/vendor/i18n-0.1.3/lib/i18n/exceptions.rb +0 -53
  244. data/lib/active_support/vendor/i18n-0.1.3/lib/i18n.rb +0 -199
  245. data/lib/active_support/vendor/i18n-0.1.3/test/all.rb +0 -5
  246. data/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb +0 -99
  247. data/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb +0 -124
  248. data/lib/active_support/vendor/i18n-0.1.3/test/locale/en.rb +0 -1
  249. data/lib/active_support/vendor/i18n-0.1.3/test/locale/en.yml +0 -3
  250. data/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb +0 -567
  251. data/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb +0 -1107
  252. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/data_timezone.rb +0 -47
  253. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/data_timezone_info.rb +0 -228
  254. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Algiers.rb +0 -55
  255. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Cairo.rb +0 -219
  256. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Casablanca.rb +0 -40
  257. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Harare.rb +0 -18
  258. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Johannesburg.rb +0 -25
  259. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Monrovia.rb +0 -22
  260. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Nairobi.rb +0 -23
  261. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Argentina/Buenos_Aires.rb +0 -166
  262. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Argentina/San_Juan.rb +0 -86
  263. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Bogota.rb +0 -23
  264. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Caracas.rb +0 -23
  265. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Chicago.rb +0 -283
  266. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Chihuahua.rb +0 -136
  267. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Denver.rb +0 -204
  268. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Godthab.rb +0 -161
  269. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Guatemala.rb +0 -27
  270. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Halifax.rb +0 -274
  271. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Indiana/Indianapolis.rb +0 -149
  272. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Juneau.rb +0 -194
  273. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/La_Paz.rb +0 -22
  274. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Lima.rb +0 -35
  275. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Los_Angeles.rb +0 -232
  276. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Mazatlan.rb +0 -139
  277. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Mexico_City.rb +0 -144
  278. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Monterrey.rb +0 -131
  279. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/New_York.rb +0 -282
  280. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Phoenix.rb +0 -30
  281. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Regina.rb +0 -74
  282. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Santiago.rb +0 -205
  283. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Sao_Paulo.rb +0 -171
  284. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/St_Johns.rb +0 -288
  285. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Tijuana.rb +0 -196
  286. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Almaty.rb +0 -67
  287. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Baghdad.rb +0 -73
  288. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Baku.rb +0 -161
  289. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Bangkok.rb +0 -20
  290. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Chongqing.rb +0 -33
  291. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Colombo.rb +0 -30
  292. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Dhaka.rb +0 -27
  293. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Hong_Kong.rb +0 -87
  294. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Irkutsk.rb +0 -165
  295. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Jakarta.rb +0 -30
  296. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Jerusalem.rb +0 -163
  297. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kabul.rb +0 -20
  298. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kamchatka.rb +0 -163
  299. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Karachi.rb +0 -30
  300. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Katmandu.rb +0 -20
  301. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kolkata.rb +0 -25
  302. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Krasnoyarsk.rb +0 -163
  303. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kuala_Lumpur.rb +0 -31
  304. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kuwait.rb +0 -18
  305. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Magadan.rb +0 -163
  306. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Muscat.rb +0 -18
  307. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Novosibirsk.rb +0 -164
  308. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Rangoon.rb +0 -24
  309. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Riyadh.rb +0 -18
  310. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Seoul.rb +0 -34
  311. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Shanghai.rb +0 -35
  312. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Singapore.rb +0 -33
  313. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Taipei.rb +0 -59
  314. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tashkent.rb +0 -47
  315. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tbilisi.rb +0 -78
  316. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tehran.rb +0 -121
  317. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tokyo.rb +0 -30
  318. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Ulaanbaatar.rb +0 -65
  319. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Urumqi.rb +0 -33
  320. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Vladivostok.rb +0 -164
  321. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Yakutsk.rb +0 -163
  322. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Yekaterinburg.rb +0 -165
  323. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Yerevan.rb +0 -165
  324. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Atlantic/Azores.rb +0 -270
  325. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Atlantic/Cape_Verde.rb +0 -23
  326. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Atlantic/South_Georgia.rb +0 -18
  327. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Adelaide.rb +0 -187
  328. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Brisbane.rb +0 -35
  329. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Darwin.rb +0 -29
  330. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Hobart.rb +0 -193
  331. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Melbourne.rb +0 -185
  332. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Perth.rb +0 -37
  333. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Sydney.rb +0 -185
  334. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Etc/UTC.rb +0 -16
  335. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Amsterdam.rb +0 -228
  336. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Athens.rb +0 -185
  337. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Belgrade.rb +0 -163
  338. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Berlin.rb +0 -188
  339. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Bratislava.rb +0 -13
  340. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Brussels.rb +0 -232
  341. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Bucharest.rb +0 -181
  342. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Budapest.rb +0 -197
  343. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Copenhagen.rb +0 -179
  344. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Dublin.rb +0 -276
  345. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Helsinki.rb +0 -163
  346. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Istanbul.rb +0 -218
  347. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Kiev.rb +0 -168
  348. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Lisbon.rb +0 -268
  349. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Ljubljana.rb +0 -13
  350. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/London.rb +0 -288
  351. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Madrid.rb +0 -211
  352. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Minsk.rb +0 -170
  353. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Moscow.rb +0 -181
  354. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Paris.rb +0 -232
  355. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Prague.rb +0 -187
  356. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Riga.rb +0 -176
  357. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Rome.rb +0 -215
  358. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Sarajevo.rb +0 -13
  359. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Skopje.rb +0 -13
  360. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Sofia.rb +0 -173
  361. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Stockholm.rb +0 -165
  362. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Tallinn.rb +0 -172
  363. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Vienna.rb +0 -183
  364. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Vilnius.rb +0 -170
  365. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Warsaw.rb +0 -212
  366. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Zagreb.rb +0 -13
  367. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Auckland.rb +0 -202
  368. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Fiji.rb +0 -23
  369. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Guam.rb +0 -22
  370. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Honolulu.rb +0 -28
  371. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Majuro.rb +0 -20
  372. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Midway.rb +0 -25
  373. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Noumea.rb +0 -25
  374. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Pago_Pago.rb +0 -26
  375. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Port_Moresby.rb +0 -20
  376. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Tongatapu.rb +0 -27
  377. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/info_timezone.rb +0 -52
  378. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/linked_timezone.rb +0 -51
  379. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/linked_timezone_info.rb +0 -44
  380. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/offset_rationals.rb +0 -98
  381. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/ruby_core_support.rb +0 -56
  382. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/time_or_datetime.rb +0 -292
  383. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone.rb +0 -508
  384. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_definition.rb +0 -56
  385. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_info.rb +0 -40
  386. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_offset_info.rb +0 -94
  387. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_period.rb +0 -198
  388. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_transition_info.rb +0 -129
  389. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo.rb +0 -33
  390. data/lib/active_support/vendor.rb +0 -28
  391. data/lib/activesupport.rb +0 -2
@@ -1,3 +1,8 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+ require 'active_support/core_ext/class/inheritable_attributes'
3
+ require 'active_support/core_ext/kernel/reporting'
4
+ require 'active_support/core_ext/kernel/singleton_class'
5
+
1
6
  module ActiveSupport
2
7
  # Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
3
8
  # before or after an alteration of the object state.
@@ -8,23 +13,23 @@ module ActiveSupport
8
13
  # class Storage
9
14
  # include ActiveSupport::Callbacks
10
15
  #
11
- # define_callbacks :before_save, :after_save
16
+ # define_callbacks :save
12
17
  # end
13
18
  #
14
19
  # class ConfigStorage < Storage
15
- # before_save :saving_message
20
+ # set_callback :save, :before, :saving_message
16
21
  # def saving_message
17
22
  # puts "saving..."
18
23
  # end
19
24
  #
20
- # after_save do |object|
25
+ # set_callback :save, :after do |object|
21
26
  # puts "saved"
22
27
  # end
23
28
  #
24
29
  # def save
25
- # run_callbacks(:before_save)
26
- # puts "- save"
27
- # run_callbacks(:after_save)
30
+ # run_callbacks :save do
31
+ # puts "- save"
32
+ # end
28
33
  # end
29
34
  # end
30
35
  #
@@ -42,28 +47,28 @@ module ActiveSupport
42
47
  # class Storage
43
48
  # include ActiveSupport::Callbacks
44
49
  #
45
- # define_callbacks :before_save, :after_save
50
+ # define_callbacks :save
46
51
  #
47
- # before_save :prepare
52
+ # set_callback :save, :before, :prepare
48
53
  # def prepare
49
54
  # puts "preparing save"
50
55
  # end
51
56
  # end
52
57
  #
53
58
  # class ConfigStorage < Storage
54
- # before_save :saving_message
59
+ # set_callback :save, :before, :saving_message
55
60
  # def saving_message
56
61
  # puts "saving..."
57
62
  # end
58
63
  #
59
- # after_save do |object|
64
+ # set_callback :save, :after do |object|
60
65
  # puts "saved"
61
66
  # end
62
67
  #
63
68
  # def save
64
- # run_callbacks(:before_save)
65
- # puts "- save"
66
- # run_callbacks(:after_save)
69
+ # run_callbacks :save do
70
+ # puts "- save"
71
+ # end
67
72
  # end
68
73
  # end
69
74
  #
@@ -75,205 +80,521 @@ module ActiveSupport
75
80
  # saving...
76
81
  # - save
77
82
  # saved
83
+ #
78
84
  module Callbacks
79
- class CallbackChain < Array
80
- def self.build(kind, *methods, &block)
81
- methods, options = extract_options(*methods, &block)
82
- methods.map! { |method| Callback.new(kind, method, options) }
83
- new(methods)
85
+ extend Concern
86
+
87
+ def run_callbacks(kind, *args, &block)
88
+ send("_run_#{kind}_callbacks", *args, &block)
89
+ end
90
+
91
+ class Callback
92
+ @@_callback_sequence = 0
93
+
94
+ attr_accessor :chain, :filter, :kind, :options, :per_key, :klass, :raw_filter
95
+
96
+ def initialize(chain, filter, kind, options, klass)
97
+ @chain, @kind, @klass = chain, kind, klass
98
+ normalize_options!(options)
99
+
100
+ @per_key = options.delete(:per_key)
101
+ @raw_filter, @options = filter, options
102
+ @filter = _compile_filter(filter)
103
+ @compiled_options = _compile_options(options)
104
+ @callback_id = next_id
105
+
106
+ _compile_per_key_options
84
107
  end
85
108
 
86
- def run(object, options = {}, &terminator)
87
- enumerator = options[:enumerator] || :each
109
+ def clone(chain, klass)
110
+ obj = super()
111
+ obj.chain = chain
112
+ obj.klass = klass
113
+ obj.per_key = @per_key.dup
114
+ obj.options = @options.dup
115
+ obj.per_key[:if] = @per_key[:if].dup
116
+ obj.per_key[:unless] = @per_key[:unless].dup
117
+ obj.options[:if] = @options[:if].dup
118
+ obj.options[:unless] = @options[:unless].dup
119
+ obj
120
+ end
88
121
 
89
- unless block_given?
90
- send(enumerator) { |callback| callback.call(object) }
91
- else
92
- send(enumerator) do |callback|
93
- result = callback.call(object)
94
- break result if terminator.call(result, object)
122
+ def normalize_options!(options)
123
+ options[:if] = Array.wrap(options[:if])
124
+ options[:unless] = Array.wrap(options[:unless])
125
+
126
+ options[:per_key] ||= {}
127
+ options[:per_key][:if] = Array.wrap(options[:per_key][:if])
128
+ options[:per_key][:unless] = Array.wrap(options[:per_key][:unless])
129
+ end
130
+
131
+ def name
132
+ chain.name
133
+ end
134
+
135
+ def next_id
136
+ @@_callback_sequence += 1
137
+ end
138
+
139
+ def matches?(_kind, _filter)
140
+ @kind == _kind && @filter == _filter
141
+ end
142
+
143
+ def _update_filter(filter_options, new_options)
144
+ filter_options[:if].push(new_options[:unless]) if new_options.key?(:unless)
145
+ filter_options[:unless].push(new_options[:if]) if new_options.key?(:if)
146
+ end
147
+
148
+ def recompile!(_options, _per_key)
149
+ _update_filter(self.options, _options)
150
+ _update_filter(self.per_key, _per_key)
151
+
152
+ @callback_id = next_id
153
+ @filter = _compile_filter(@raw_filter)
154
+ @compiled_options = _compile_options(@options)
155
+ _compile_per_key_options
156
+ end
157
+
158
+ def _compile_per_key_options
159
+ key_options = _compile_options(@per_key)
160
+
161
+ @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
162
+ def _one_time_conditions_valid_#{@callback_id}?
163
+ true #{key_options[0]}
95
164
  end
96
- end
165
+ RUBY_EVAL
97
166
  end
98
167
 
99
- # TODO: Decompose into more Array like behavior
100
- def replace_or_append!(chain)
101
- if index = index(chain)
102
- self[index] = chain
103
- else
104
- self << chain
168
+ # This will supply contents for before and around filters, and no
169
+ # contents for after filters (for the forward pass).
170
+ def start(key=nil, object=nil)
171
+ return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
172
+
173
+ # options[0] is the compiled form of supplied conditions
174
+ # options[1] is the "end" for the conditional
175
+ #
176
+ if @kind == :before || @kind == :around
177
+ if @kind == :before
178
+ # if condition # before_save :filter_name, :if => :condition
179
+ # filter_name
180
+ # end
181
+ filter = <<-RUBY_EVAL
182
+ unless halted
183
+ result = #{@filter}
184
+ halted = (#{chain.config[:terminator]})
185
+ end
186
+ RUBY_EVAL
187
+
188
+ [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
189
+ else
190
+ # Compile around filters with conditions into proxy methods
191
+ # that contain the conditions.
192
+ #
193
+ # For `around_save :filter_name, :if => :condition':
194
+ #
195
+ # def _conditional_callback_save_17
196
+ # if condition
197
+ # filter_name do
198
+ # yield self
199
+ # end
200
+ # else
201
+ # yield self
202
+ # end
203
+ # end
204
+ #
205
+ name = "_conditional_callback_#{@kind}_#{next_id}"
206
+ txt, line = <<-RUBY_EVAL, __LINE__ + 1
207
+ def #{name}(halted)
208
+ #{@compiled_options[0] || "if true"} && !halted
209
+ #{@filter} do
210
+ yield self
211
+ end
212
+ else
213
+ yield self
214
+ end
215
+ end
216
+ RUBY_EVAL
217
+ @klass.class_eval(txt, __FILE__, line)
218
+ "#{name}(halted) do"
219
+ end
105
220
  end
106
- self
107
221
  end
108
222
 
109
- def find(callback, &block)
110
- select { |c| c == callback && (!block_given? || yield(c)) }.first
111
- end
223
+ # This will supply contents for around and after filters, but not
224
+ # before filters (for the backward pass).
225
+ def end(key=nil, object=nil)
226
+ return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
112
227
 
113
- def delete(callback)
114
- super(callback.is_a?(Callback) ? callback : find(callback))
228
+ if @kind == :around || @kind == :after
229
+ # if condition # after_save :filter_name, :if => :condition
230
+ # filter_name
231
+ # end
232
+ if @kind == :after
233
+ [@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
234
+ else
235
+ "end"
236
+ end
237
+ end
115
238
  end
116
239
 
117
240
  private
118
- def self.extract_options(*methods, &block)
119
- methods.flatten!
120
- options = methods.extract_options!
121
- methods << block if block_given?
122
- return methods, options
123
- end
124
241
 
125
- def extract_options(*methods, &block)
126
- self.class.extract_options(*methods, &block)
242
+ # Options support the same options as filters themselves (and support
243
+ # symbols, string, procs, and objects), so compile a conditional
244
+ # expression based on the options
245
+ def _compile_options(options)
246
+ return [] if options[:if].empty? && options[:unless].empty?
247
+
248
+ conditions = []
249
+
250
+ unless options[:if].empty?
251
+ conditions << Array.wrap(_compile_filter(options[:if]))
127
252
  end
128
- end
129
253
 
130
- class Callback
131
- attr_reader :kind, :method, :identifier, :options
254
+ unless options[:unless].empty?
255
+ conditions << Array.wrap(_compile_filter(options[:unless])).map {|f| "!#{f}"}
256
+ end
132
257
 
133
- def initialize(kind, method, options = {})
134
- @kind = kind
135
- @method = method
136
- @identifier = options[:identifier]
137
- @options = options
258
+ ["if #{conditions.flatten.join(" && ")}", "end"]
138
259
  end
139
260
 
140
- def ==(other)
141
- case other
142
- when Callback
143
- (self.identifier && self.identifier == other.identifier) || self.method == other.method
261
+ # Filters support:
262
+ #
263
+ # Arrays:: Used in conditions. This is used to specify
264
+ # multiple conditions. Used internally to
265
+ # merge conditions from skip_* filters
266
+ # Symbols:: A method to call
267
+ # Strings:: Some content to evaluate
268
+ # Procs:: A proc to call with the object
269
+ # Objects:: An object with a before_foo method on it to call
270
+ #
271
+ # All of these objects are compiled into methods and handled
272
+ # the same after this point:
273
+ #
274
+ # Arrays:: Merged together into a single filter
275
+ # Symbols:: Already methods
276
+ # Strings:: class_eval'ed into methods
277
+ # Procs:: define_method'ed into methods
278
+ # Objects::
279
+ # a method is created that calls the before_foo method
280
+ # on the object.
281
+ #
282
+ def _compile_filter(filter)
283
+ method_name = "_callback_#{@kind}_#{next_id}"
284
+ case filter
285
+ when Array
286
+ filter.map {|f| _compile_filter(f)}
287
+ when Symbol
288
+ filter
289
+ when String
290
+ "(#{filter})"
291
+ when Proc
292
+ @klass.send(:define_method, method_name, &filter)
293
+ return method_name if filter.arity <= 0
294
+
295
+ method_name << (filter.arity == 1 ? "(self)" : " self, Proc.new ")
144
296
  else
145
- (self.identifier && self.identifier == other) || self.method == other
297
+ @klass.send(:define_method, "#{method_name}_object") { filter }
298
+
299
+ _normalize_legacy_filter(kind, filter)
300
+ scopes = Array.wrap(chain.config[:scope])
301
+ method_to_call = scopes.map{ |s| s.is_a?(Symbol) ? send(s) : s }.join("_")
302
+
303
+ @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
304
+ def #{method_name}(&blk)
305
+ #{method_name}_object.send(:#{method_to_call}, self, &blk)
306
+ end
307
+ RUBY_EVAL
308
+
309
+ method_name
146
310
  end
147
311
  end
148
312
 
149
- def eql?(other)
150
- self == other
313
+ def _normalize_legacy_filter(kind, filter)
314
+ if !filter.respond_to?(kind) && filter.respond_to?(:filter)
315
+ filter.singleton_class.class_eval(
316
+ "def #{kind}(context, &block) filter(context, &block) end",
317
+ __FILE__, __LINE__ - 1)
318
+ elsif filter.respond_to?(:before) && filter.respond_to?(:after) && kind == :around
319
+ def filter.around(context)
320
+ should_continue = before(context)
321
+ yield if should_continue
322
+ after(context)
323
+ end
324
+ end
151
325
  end
326
+ end
327
+
328
+ # An Array with a compile method
329
+ class CallbackChain < Array
330
+ attr_reader :name, :config
152
331
 
153
- def dup
154
- self.class.new(@kind, @method, @options.dup)
332
+ def initialize(name, config)
333
+ @name = name
334
+ @config = {
335
+ :terminator => "false",
336
+ :rescuable => false,
337
+ :scope => [ :kind ]
338
+ }.merge(config)
155
339
  end
156
340
 
157
- def hash
158
- if @identifier
159
- @identifier.hash
160
- else
161
- @method.hash
341
+ def compile(key=nil, object=nil)
342
+ method = []
343
+ method << "value = nil"
344
+ method << "halted = false"
345
+
346
+ each do |callback|
347
+ method << callback.start(key, object)
348
+ end
349
+
350
+ if config[:rescuable]
351
+ method << "rescued_error = nil"
352
+ method << "begin"
353
+ end
354
+
355
+ method << "value = yield if block_given? && !halted"
356
+
357
+ if config[:rescuable]
358
+ method << "rescue Exception => e"
359
+ method << "rescued_error = e"
360
+ method << "end"
361
+ end
362
+
363
+ reverse_each do |callback|
364
+ method << callback.end(key, object)
162
365
  end
163
- end
164
366
 
165
- def call(*args, &block)
166
- evaluate_method(method, *args, &block) if should_run_callback?(*args)
167
- rescue LocalJumpError
168
- raise ArgumentError,
169
- "Cannot yield from a Proc type filter. The Proc must take two " +
170
- "arguments and execute #call on the second argument."
367
+ method << "raise rescued_error if rescued_error" if config[:rescuable]
368
+ method << "halted ? false : (block_given? ? value : true)"
369
+ method.compact.join("\n")
171
370
  end
371
+ end
172
372
 
173
- private
174
- def evaluate_method(method, *args, &block)
175
- case method
176
- when Symbol
177
- object = args.shift
178
- object.send(method, *args, &block)
179
- when String
180
- eval(method, args.first.instance_eval { binding })
181
- when Proc, Method
182
- method.call(*args, &block)
183
- else
184
- if method.respond_to?(kind)
185
- method.send(kind, *args, &block)
186
- else
187
- raise ArgumentError,
188
- "Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
189
- "a block to be invoked, or an object responding to the callback method."
373
+ module ClassMethods
374
+ # Make the run_callbacks :save method. The generated method takes
375
+ # a block that it'll yield to. It'll call the before and around filters
376
+ # in order, yield the block, and then run the after filters.
377
+ #
378
+ # run_callbacks :save do
379
+ # save
380
+ # end
381
+ #
382
+ # The run_callbacks :save method can optionally take a key, which
383
+ # will be used to compile an optimized callback method for each
384
+ # key. See #define_callbacks for more information.
385
+ #
386
+ def __define_runner(symbol) #:nodoc:
387
+ send("_update_#{symbol}_superclass_callbacks")
388
+ body = send("_#{symbol}_callbacks").compile(nil)
389
+
390
+ body, line = <<-RUBY_EVAL, __LINE__ + 1
391
+ def _run_#{symbol}_callbacks(key = nil, &blk)
392
+ if self.class.send("_update_#{symbol}_superclass_callbacks")
393
+ self.class.__define_runner(#{symbol.inspect})
394
+ return _run_#{symbol}_callbacks(key, &blk)
395
+ end
396
+
397
+ if key
398
+ name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
399
+
400
+ unless respond_to?(name)
401
+ self.class.__create_keyed_callback(name, :#{symbol}, self, &blk)
190
402
  end
403
+
404
+ send(name, &blk)
405
+ else
406
+ #{body}
407
+ end
191
408
  end
409
+ private :_run_#{symbol}_callbacks
410
+ RUBY_EVAL
411
+
412
+ silence_warnings do
413
+ undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
414
+ class_eval body, __FILE__, line
192
415
  end
416
+ end
193
417
 
194
- def should_run_callback?(*args)
195
- [options[:if]].flatten.compact.all? { |a| evaluate_method(a, *args) } &&
196
- ![options[:unless]].flatten.compact.any? { |a| evaluate_method(a, *args) }
418
+ # This is called the first time a callback is called with a particular
419
+ # key. It creates a new callback method for the key, calculating
420
+ # which callbacks can be omitted because of per_key conditions.
421
+ #
422
+ def __create_keyed_callback(name, kind, object, &blk) #:nodoc:
423
+ @_keyed_callbacks ||= {}
424
+ @_keyed_callbacks[name] ||= begin
425
+ str = send("_#{kind}_callbacks").compile(name, object)
426
+ class_eval "def #{name}() #{str} end", __FILE__, __LINE__
427
+ true
197
428
  end
198
- end
429
+ end
199
430
 
200
- def self.included(base)
201
- base.extend ClassMethods
202
- end
431
+ # This is used internally to append, prepend and skip callbacks to the
432
+ # CallbackChain.
433
+ #
434
+ def __update_callbacks(name, filters = [], block = nil) #:nodoc:
435
+ send("_update_#{name}_superclass_callbacks")
203
436
 
204
- module ClassMethods
437
+ type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
438
+ options = filters.last.is_a?(Hash) ? filters.pop : {}
439
+ filters.unshift(block) if block
440
+
441
+ chain = send("_#{name}_callbacks")
442
+ yield chain, type, filters, options if block_given?
443
+
444
+ __define_runner(name)
445
+ end
446
+
447
+ # Set callbacks for a previously defined callback.
448
+ #
449
+ # Syntax:
450
+ # set_callback :save, :before, :before_meth
451
+ # set_callback :save, :after, :after_meth, :if => :condition
452
+ # set_callback :save, :around, lambda { |r| stuff; yield; stuff }
453
+ #
454
+ # Use skip_callback to skip any defined one.
455
+ #
456
+ # When creating or skipping callbacks, you can specify conditions that
457
+ # are always the same for a given key. For instance, in ActionPack,
458
+ # we convert :only and :except conditions into per-key conditions.
459
+ #
460
+ # before_filter :authenticate, :except => "index"
461
+ # becomes
462
+ # dispatch_callback :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
463
+ #
464
+ # Per-Key conditions are evaluated only once per use of a given key.
465
+ # In the case of the above example, you would do:
466
+ #
467
+ # run_callbacks(:dispatch, action_name) { ... dispatch stuff ... }
468
+ #
469
+ # In that case, each action_name would get its own compiled callback
470
+ # method that took into consideration the per_key conditions. This
471
+ # is a speed improvement for ActionPack.
472
+ #
473
+ def set_callback(name, *filter_list, &block)
474
+ __update_callbacks(name, filter_list, block) do |chain, type, filters, options|
475
+ filters.map! do |filter|
476
+ removed = chain.delete_if {|c| c.matches?(type, filter) }
477
+ send("_removed_#{name}_callbacks").push(*removed)
478
+ Callback.new(chain, filter, type, options.dup, self)
479
+ end
480
+
481
+ options[:prepend] ? chain.unshift(*filters) : chain.push(*filters)
482
+ end
483
+ end
484
+
485
+ # Skip a previously defined callback for a given type.
486
+ #
487
+ def skip_callback(name, *filter_list, &block)
488
+ __update_callbacks(name, filter_list, block) do |chain, type, filters, options|
489
+ filters.each do |filter|
490
+ filter = chain.find {|c| c.matches?(type, filter) }
491
+
492
+ if filter && options.any?
493
+ new_filter = filter.clone(chain, self)
494
+ chain.insert(chain.index(filter), new_filter)
495
+ new_filter.recompile!(options, options[:per_key] || {})
496
+ end
497
+
498
+ chain.delete(filter)
499
+ send("_removed_#{name}_callbacks") << filter
500
+ end
501
+ end
502
+ end
503
+
504
+ # Reset callbacks for a given type.
505
+ #
506
+ def reset_callbacks(symbol)
507
+ callbacks = send("_#{symbol}_callbacks")
508
+ callbacks.clear
509
+ send("_removed_#{symbol}_callbacks").concat(callbacks)
510
+ __define_runner(symbol)
511
+ end
512
+
513
+ # Define callbacks types.
514
+ #
515
+ # ==== Example
516
+ #
517
+ # define_callbacks :validate
518
+ #
519
+ # ==== Options
520
+ #
521
+ # * <tt>:terminator</tt> - Indicates when a before filter is considered
522
+ # to be halted.
523
+ #
524
+ # define_callbacks :validate, :terminator => "result == false"
525
+ #
526
+ # In the example above, if any before validate callbacks returns false,
527
+ # other callbacks are not executed. Defaults to "false".
528
+ #
529
+ # * <tt>:rescuable</tt> - By default, after filters are not executed if
530
+ # the given block or an before_filter raises an error. Supply :rescuable => true
531
+ # to change this behavior.
532
+ #
533
+ # * <tt>:scope</tt> - Show which methods should be executed when a class
534
+ # is given as callback:
535
+ #
536
+ # define_callbacks :filters, :scope => [ :kind ]
537
+ #
538
+ # When a class is given:
539
+ #
540
+ # before_filter MyFilter
541
+ #
542
+ # It will call the type of the filter in the given class, which in this
543
+ # case, is "before".
544
+ #
545
+ # If, for instance, you supply the given scope:
546
+ #
547
+ # define_callbacks :validate, :scope => [ :kind, :name ]
548
+ #
549
+ # It will call "#{kind}_#{name}" in the given class. So "before_validate"
550
+ # will be called in the class below:
551
+ #
552
+ # before_validate MyValidation
553
+ #
554
+ # Defaults to :kind.
555
+ #
205
556
  def define_callbacks(*callbacks)
557
+ config = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
206
558
  callbacks.each do |callback|
207
- class_eval <<-"end_eval"
208
- def self.#{callback}(*methods, &block) # def self.before_save(*methods, &block)
209
- callbacks = CallbackChain.build(:#{callback}, *methods, &block) # callbacks = CallbackChain.build(:before_save, *methods, &block)
210
- @#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
211
- @#{callback}_callbacks.concat callbacks # @before_save_callbacks.concat callbacks
212
- end # end
213
- #
214
- def self.#{callback}_callback_chain # def self.before_save_callback_chain
215
- @#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
216
- #
217
- if superclass.respond_to?(:#{callback}_callback_chain) # if superclass.respond_to?(:before_save_callback_chain)
218
- CallbackChain.new( # CallbackChain.new(
219
- superclass.#{callback}_callback_chain + # superclass.before_save_callback_chain +
220
- @#{callback}_callbacks # @before_save_callbacks
221
- ) # )
222
- else # else
223
- @#{callback}_callbacks # @before_save_callbacks
224
- end # end
225
- end # end
226
- end_eval
559
+ extlib_inheritable_reader("_#{callback}_callbacks") do
560
+ CallbackChain.new(callback, config)
561
+ end
562
+
563
+ extlib_inheritable_reader("_removed_#{callback}_callbacks") do
564
+ []
565
+ end
566
+
567
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
568
+ def self._#{callback}_superclass_callbacks
569
+ if superclass.respond_to?(:_#{callback}_callbacks)
570
+ superclass._#{callback}_callbacks + superclass._#{callback}_superclass_callbacks
571
+ else
572
+ []
573
+ end
574
+ end
575
+
576
+ def self._update_#{callback}_superclass_callbacks
577
+ changed, index = false, 0
578
+
579
+ callbacks = (_#{callback}_superclass_callbacks -
580
+ _#{callback}_callbacks) - _removed_#{callback}_callbacks
581
+
582
+ callbacks.each do |callback|
583
+ if new_index = _#{callback}_callbacks.index(callback)
584
+ index = new_index + 1
585
+ else
586
+ changed = true
587
+ _#{callback}_callbacks.insert(index, callback)
588
+ index = index + 1
589
+ end
590
+ end
591
+ changed
592
+ end
593
+ METHOD
594
+
595
+ __define_runner(callback)
227
596
  end
228
597
  end
229
598
  end
230
-
231
- # Runs all the callbacks defined for the given options.
232
- #
233
- # If a block is given it will be called after each callback receiving as arguments:
234
- #
235
- # * the result from the callback
236
- # * the object which has the callback
237
- #
238
- # If the result from the block evaluates to false, the callback chain is stopped.
239
- #
240
- # Example:
241
- # class Storage
242
- # include ActiveSupport::Callbacks
243
- #
244
- # define_callbacks :before_save, :after_save
245
- # end
246
- #
247
- # class ConfigStorage < Storage
248
- # before_save :pass
249
- # before_save :pass
250
- # before_save :stop
251
- # before_save :pass
252
- #
253
- # def pass
254
- # puts "pass"
255
- # end
256
- #
257
- # def stop
258
- # puts "stop"
259
- # return false
260
- # end
261
- #
262
- # def save
263
- # result = run_callbacks(:before_save) { |result, object| result == false }
264
- # puts "- save" if result
265
- # end
266
- # end
267
- #
268
- # config = ConfigStorage.new
269
- # config.save
270
- #
271
- # Output:
272
- # pass
273
- # pass
274
- # stop
275
- def run_callbacks(kind, options = {}, &block)
276
- self.class.send("#{kind}_callback_chain").run(self, options, &block)
277
- end
278
599
  end
279
600
  end