activesupport 2.3.18 → 3.0.0.beta

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 (403) hide show
  1. data/CHANGELOG +30 -53
  2. data/lib/active_support.rb +43 -31
  3. data/lib/active_support/all.rb +3 -7
  4. data/lib/active_support/backtrace_cleaner.rb +24 -8
  5. data/lib/active_support/base64.rb +9 -0
  6. data/lib/active_support/benchmarkable.rb +60 -0
  7. data/lib/active_support/buffered_logger.rb +12 -9
  8. data/lib/active_support/cache.rb +75 -55
  9. data/lib/active_support/cache/compressed_mem_cache_store.rb +2 -0
  10. data/lib/active_support/cache/file_store.rb +35 -17
  11. data/lib/active_support/cache/mem_cache_store.rb +29 -20
  12. data/lib/active_support/cache/memory_store.rb +18 -17
  13. data/lib/active_support/cache/strategy/local_cache.rb +9 -1
  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.rb +2 -7
  18. data/lib/active_support/core_ext/array.rb +2 -10
  19. data/lib/active_support/core_ext/array/access.rb +39 -46
  20. data/lib/active_support/core_ext/array/conversions.rb +146 -182
  21. data/lib/active_support/core_ext/array/extract_options.rb +12 -18
  22. data/lib/active_support/core_ext/array/grouping.rb +87 -93
  23. data/lib/active_support/core_ext/array/random_access.rb +4 -40
  24. data/lib/active_support/core_ext/array/uniq_by.rb +17 -0
  25. data/lib/active_support/core_ext/array/wrap.rb +22 -0
  26. data/lib/active_support/core_ext/big_decimal.rb +1 -0
  27. data/lib/active_support/core_ext/big_decimal/conversions.rb +27 -0
  28. data/lib/active_support/core_ext/cgi.rb +0 -4
  29. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +16 -20
  30. data/lib/active_support/core_ext/class.rb +0 -2
  31. data/lib/active_support/core_ext/class/attribute.rb +8 -39
  32. data/lib/active_support/core_ext/class/attribute_accessors.rb +31 -35
  33. data/lib/active_support/core_ext/class/delegating_attributes.rb +34 -40
  34. data/lib/active_support/core_ext/class/inheritable_attributes.rb +100 -16
  35. data/lib/active_support/core_ext/date/acts_like.rb +8 -0
  36. data/lib/active_support/core_ext/date/calculations.rb +218 -238
  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 +83 -95
  42. data/lib/active_support/core_ext/date_time/zones.rb +17 -0
  43. data/lib/active_support/core_ext/enumerable.rb +14 -15
  44. data/lib/active_support/core_ext/exception.rb +1 -43
  45. data/lib/active_support/core_ext/file.rb +0 -4
  46. data/lib/active_support/core_ext/file/atomic.rb +34 -41
  47. data/lib/active_support/core_ext/float.rb +0 -6
  48. data/lib/active_support/core_ext/float/rounding.rb +15 -20
  49. data/lib/active_support/core_ext/hash.rb +8 -14
  50. data/lib/active_support/core_ext/hash/conversions.rb +236 -236
  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/integer.rb +1 -7
  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/kernel/reporting.rb +9 -7
  63. data/lib/active_support/core_ext/kernel/requires.rb +3 -1
  64. data/lib/active_support/core_ext/load_error.rb +16 -33
  65. data/lib/active_support/core_ext/logger.rb +3 -2
  66. data/lib/active_support/core_ext/module.rb +3 -16
  67. data/lib/active_support/core_ext/module/aliasing.rb +64 -68
  68. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +1 -1
  69. data/lib/active_support/core_ext/module/attr_internal.rb +4 -4
  70. data/lib/active_support/core_ext/module/attribute_accessors.rb +36 -41
  71. data/lib/active_support/core_ext/module/delegation.rb +1 -1
  72. data/lib/active_support/core_ext/module/deprecation.rb +9 -0
  73. data/lib/active_support/core_ext/module/introspection.rb +77 -79
  74. data/lib/active_support/core_ext/module/loading.rb +2 -0
  75. data/lib/active_support/core_ext/module/synchronization.rb +4 -1
  76. data/lib/active_support/core_ext/name_error.rb +3 -4
  77. data/lib/active_support/core_ext/numeric.rb +1 -8
  78. data/lib/active_support/core_ext/numeric/bytes.rb +35 -41
  79. data/lib/active_support/core_ext/numeric/time.rb +70 -74
  80. data/lib/active_support/core_ext/object.rb +4 -2
  81. data/lib/active_support/core_ext/object/acts_like.rb +10 -0
  82. data/lib/active_support/core_ext/object/conversions.rb +4 -15
  83. data/lib/active_support/core_ext/object/duplicable.rb +65 -0
  84. data/lib/active_support/core_ext/object/instance_variables.rb +0 -7
  85. data/lib/active_support/core_ext/object/metaclass.rb +5 -6
  86. data/lib/active_support/core_ext/object/misc.rb +2 -93
  87. data/lib/active_support/core_ext/object/returning.rb +42 -0
  88. data/lib/active_support/core_ext/object/to_param.rb +49 -0
  89. data/lib/active_support/core_ext/object/to_query.rb +27 -0
  90. data/lib/active_support/core_ext/{try.rb → object/try.rb} +4 -4
  91. data/lib/active_support/core_ext/object/with_options.rb +24 -0
  92. data/lib/active_support/core_ext/proc.rb +6 -4
  93. data/lib/active_support/core_ext/process/daemon.rb +17 -19
  94. data/lib/active_support/core_ext/range.rb +2 -9
  95. data/lib/active_support/core_ext/range/blockless_step.rb +24 -27
  96. data/lib/active_support/core_ext/range/conversions.rb +17 -23
  97. data/lib/active_support/core_ext/range/include_range.rb +18 -27
  98. data/lib/active_support/core_ext/range/overlaps.rb +6 -13
  99. data/lib/active_support/core_ext/regexp.rb +5 -0
  100. data/lib/active_support/core_ext/rexml.rb +12 -7
  101. data/lib/active_support/core_ext/string.rb +6 -19
  102. data/lib/active_support/core_ext/string/access.rb +88 -95
  103. data/lib/active_support/core_ext/string/behavior.rb +6 -12
  104. data/lib/active_support/core_ext/string/conversions.rb +19 -21
  105. data/lib/active_support/core_ext/string/exclude.rb +6 -0
  106. data/lib/active_support/core_ext/string/filters.rb +17 -23
  107. data/lib/active_support/core_ext/string/inflections.rb +146 -153
  108. data/lib/active_support/{vendor/i18n-0.4.1/i18n/core_ext/string/interpolate.rb → core_ext/string/interpolation.rb} +8 -15
  109. data/lib/active_support/core_ext/string/multibyte.rb +68 -74
  110. data/lib/active_support/core_ext/string/output_safety.rb +21 -17
  111. data/lib/active_support/core_ext/string/starts_ends_with.rb +3 -32
  112. data/lib/active_support/core_ext/string/xchar.rb +10 -3
  113. data/lib/active_support/core_ext/time/acts_like.rb +8 -0
  114. data/lib/active_support/core_ext/time/calculations.rb +276 -308
  115. data/lib/active_support/core_ext/time/conversions.rb +78 -84
  116. data/lib/active_support/core_ext/time/marshal_with_utc_flag.rb +22 -0
  117. data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +10 -0
  118. data/lib/active_support/core_ext/time/zones.rb +73 -81
  119. data/lib/active_support/core_ext/uri.rb +2 -1
  120. data/lib/active_support/dependencies.rb +38 -48
  121. data/lib/active_support/dependencies/autoload.rb +49 -0
  122. data/lib/active_support/deprecation.rb +9 -195
  123. data/lib/active_support/deprecation/behaviors.rb +38 -0
  124. data/lib/active_support/deprecation/method_wrappers.rb +29 -0
  125. data/lib/active_support/deprecation/proxy_wrappers.rb +74 -0
  126. data/lib/active_support/deprecation/reporting.rb +55 -0
  127. data/lib/active_support/duration.rb +6 -2
  128. data/lib/active_support/hash_with_indifferent_access.rb +137 -0
  129. data/lib/active_support/i18n.rb +2 -0
  130. data/lib/active_support/inflections.rb +1 -1
  131. data/lib/active_support/inflector.rb +4 -406
  132. data/lib/active_support/inflector/inflections.rb +211 -0
  133. data/lib/active_support/inflector/methods.rb +139 -0
  134. data/lib/active_support/inflector/transliterate.rb +61 -0
  135. data/lib/active_support/json/backends/jsongem.rb +16 -10
  136. data/lib/active_support/json/backends/yaml.rb +72 -2
  137. data/lib/active_support/json/decoding.rb +2 -16
  138. data/lib/active_support/json/encoding.rb +153 -33
  139. data/lib/active_support/json/variable.rb +4 -3
  140. data/lib/active_support/locale/en.yml +1 -4
  141. data/lib/active_support/memoizable.rb +7 -6
  142. data/lib/active_support/message_encryptor.rb +1 -0
  143. data/lib/active_support/message_verifier.rb +12 -29
  144. data/lib/active_support/multibyte.rb +9 -4
  145. data/lib/active_support/multibyte/chars.rb +25 -17
  146. data/lib/active_support/multibyte/unicode_database.rb +5 -5
  147. data/lib/active_support/multibyte/utils.rb +1 -1
  148. data/lib/active_support/notifications.rb +77 -0
  149. data/lib/active_support/notifications/fanout.rb +69 -0
  150. data/lib/active_support/notifications/instrumenter.rb +50 -0
  151. data/lib/active_support/option_merger.rb +2 -0
  152. data/lib/active_support/ordered_hash.rb +33 -37
  153. data/lib/active_support/ordered_options.rb +3 -1
  154. data/lib/active_support/railtie.rb +64 -0
  155. data/lib/active_support/rescuable.rb +11 -6
  156. data/lib/active_support/ruby/shim.rb +19 -0
  157. data/lib/active_support/test_case.rb +8 -1
  158. data/lib/active_support/testing/assertions.rb +2 -14
  159. data/lib/active_support/testing/declarative.rb +31 -12
  160. data/lib/active_support/testing/deprecation.rb +8 -10
  161. data/lib/active_support/testing/isolation.rb +153 -0
  162. data/lib/active_support/testing/pending.rb +48 -0
  163. data/lib/active_support/testing/performance.rb +342 -339
  164. data/lib/active_support/testing/setup_and_teardown.rb +48 -31
  165. data/lib/active_support/time.rb +34 -0
  166. data/lib/active_support/time/autoload.rb +5 -0
  167. data/lib/active_support/time_with_zone.rb +18 -12
  168. data/lib/active_support/values/time_zone.rb +97 -93
  169. data/lib/active_support/version.rb +3 -3
  170. data/lib/active_support/whiny_nil.rb +1 -4
  171. data/lib/active_support/xml_mini.rb +2 -0
  172. data/lib/active_support/xml_mini/jdom.rb +13 -7
  173. data/lib/active_support/xml_mini/libxml.rb +19 -12
  174. data/lib/active_support/xml_mini/libxmlsax.rb +19 -9
  175. data/lib/active_support/xml_mini/nokogiri.rb +18 -12
  176. data/lib/active_support/xml_mini/nokogirisax.rb +15 -6
  177. data/lib/active_support/xml_mini/rexml.rb +24 -9
  178. metadata +94 -244
  179. data/lib/active_support/cache/drb_store.rb +0 -14
  180. data/lib/active_support/core_ext/array/wrapper.rb +0 -24
  181. data/lib/active_support/core_ext/base64.rb +0 -4
  182. data/lib/active_support/core_ext/base64/encoding.rb +0 -16
  183. data/lib/active_support/core_ext/bigdecimal.rb +0 -6
  184. data/lib/active_support/core_ext/bigdecimal/conversions.rb +0 -37
  185. data/lib/active_support/core_ext/blank.rb +0 -2
  186. data/lib/active_support/core_ext/class/removal.rb +0 -50
  187. data/lib/active_support/core_ext/date.rb +0 -10
  188. data/lib/active_support/core_ext/date/behavior.rb +0 -42
  189. data/lib/active_support/core_ext/date_time.rb +0 -12
  190. data/lib/active_support/core_ext/duplicable.rb +0 -43
  191. data/lib/active_support/core_ext/float/time.rb +0 -27
  192. data/lib/active_support/core_ext/integer/even_odd.rb +0 -29
  193. data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -13
  194. data/lib/active_support/core_ext/module/model_naming.rb +0 -25
  195. data/lib/active_support/core_ext/module/remove_method.rb +0 -6
  196. data/lib/active_support/core_ext/numeric/conversions.rb +0 -19
  197. data/lib/active_support/core_ext/object/extending.rb +0 -80
  198. data/lib/active_support/core_ext/object/singleton_class.rb +0 -13
  199. data/lib/active_support/core_ext/pathname.rb +0 -7
  200. data/lib/active_support/core_ext/pathname/clean_within.rb +0 -14
  201. data/lib/active_support/core_ext/string/bytesize.rb +0 -5
  202. data/lib/active_support/core_ext/string/iterators.rb +0 -23
  203. data/lib/active_support/core_ext/symbol.rb +0 -14
  204. data/lib/active_support/core_ext/time.rb +0 -46
  205. data/lib/active_support/core_ext/time/behavior.rb +0 -13
  206. data/lib/active_support/json/backends/okjson.rb +0 -644
  207. data/lib/active_support/json/backends/yajl.rb +0 -40
  208. data/lib/active_support/json/encoders/date.rb +0 -22
  209. data/lib/active_support/json/encoders/date_time.rb +0 -22
  210. data/lib/active_support/json/encoders/enumerable.rb +0 -17
  211. data/lib/active_support/json/encoders/false_class.rb +0 -7
  212. data/lib/active_support/json/encoders/hash.rb +0 -56
  213. data/lib/active_support/json/encoders/nil_class.rb +0 -7
  214. data/lib/active_support/json/encoders/numeric.rb +0 -21
  215. data/lib/active_support/json/encoders/object.rb +0 -10
  216. data/lib/active_support/json/encoders/regexp.rb +0 -9
  217. data/lib/active_support/json/encoders/string.rb +0 -9
  218. data/lib/active_support/json/encoders/symbol.rb +0 -5
  219. data/lib/active_support/json/encoders/time.rb +0 -22
  220. data/lib/active_support/json/encoders/true_class.rb +0 -7
  221. data/lib/active_support/vendor.rb +0 -36
  222. data/lib/active_support/vendor/builder-2.1.2/blankslate.rb +0 -113
  223. data/lib/active_support/vendor/builder-2.1.2/builder.rb +0 -13
  224. data/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb +0 -20
  225. data/lib/active_support/vendor/builder-2.1.2/builder/css.rb +0 -250
  226. data/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb +0 -115
  227. data/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb +0 -139
  228. data/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +0 -63
  229. data/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb +0 -328
  230. data/lib/active_support/vendor/i18n-0.4.1/i18n.rb +0 -322
  231. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend.rb +0 -20
  232. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/active_record.rb +0 -61
  233. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/active_record/missing.rb +0 -65
  234. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/active_record/store_procs.rb +0 -38
  235. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/active_record/translation.rb +0 -93
  236. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/base.rb +0 -237
  237. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/cache.rb +0 -77
  238. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/cascade.rb +0 -57
  239. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/chain.rb +0 -77
  240. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/cldr.rb +0 -100
  241. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/fallbacks.rb +0 -69
  242. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/flatten.rb +0 -113
  243. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/gettext.rb +0 -75
  244. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/interpolation_compiler.rb +0 -123
  245. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/key_value.rb +0 -102
  246. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/memoize.rb +0 -48
  247. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/metadata.rb +0 -65
  248. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/pluralization.rb +0 -57
  249. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/simple.rb +0 -87
  250. data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/transliterator.rb +0 -98
  251. data/lib/active_support/vendor/i18n-0.4.1/i18n/config.rb +0 -84
  252. data/lib/active_support/vendor/i18n-0.4.1/i18n/core_ext/hash.rb +0 -29
  253. data/lib/active_support/vendor/i18n-0.4.1/i18n/exceptions.rb +0 -61
  254. data/lib/active_support/vendor/i18n-0.4.1/i18n/gettext.rb +0 -27
  255. data/lib/active_support/vendor/i18n-0.4.1/i18n/gettext/helpers.rb +0 -65
  256. data/lib/active_support/vendor/i18n-0.4.1/i18n/gettext/po_parser.rb +0 -329
  257. data/lib/active_support/vendor/i18n-0.4.1/i18n/locale.rb +0 -6
  258. data/lib/active_support/vendor/i18n-0.4.1/i18n/locale/fallbacks.rb +0 -98
  259. data/lib/active_support/vendor/i18n-0.4.1/i18n/locale/tag.rb +0 -28
  260. data/lib/active_support/vendor/i18n-0.4.1/i18n/locale/tag/parents.rb +0 -24
  261. data/lib/active_support/vendor/i18n-0.4.1/i18n/locale/tag/rfc4646.rb +0 -76
  262. data/lib/active_support/vendor/i18n-0.4.1/i18n/locale/tag/simple.rb +0 -41
  263. data/lib/active_support/vendor/i18n-0.4.1/i18n/version.rb +0 -3
  264. data/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb +0 -1107
  265. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo.rb +0 -33
  266. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/data_timezone.rb +0 -47
  267. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/data_timezone_info.rb +0 -228
  268. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Algiers.rb +0 -55
  269. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Cairo.rb +0 -219
  270. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Casablanca.rb +0 -40
  271. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Harare.rb +0 -18
  272. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Johannesburg.rb +0 -25
  273. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Monrovia.rb +0 -22
  274. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Nairobi.rb +0 -23
  275. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Argentina/Buenos_Aires.rb +0 -166
  276. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Argentina/San_Juan.rb +0 -86
  277. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Bogota.rb +0 -23
  278. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Caracas.rb +0 -23
  279. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Chicago.rb +0 -283
  280. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Chihuahua.rb +0 -136
  281. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Denver.rb +0 -204
  282. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Godthab.rb +0 -161
  283. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Guatemala.rb +0 -27
  284. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Halifax.rb +0 -274
  285. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Indiana/Indianapolis.rb +0 -149
  286. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Juneau.rb +0 -194
  287. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/La_Paz.rb +0 -22
  288. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Lima.rb +0 -35
  289. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Los_Angeles.rb +0 -232
  290. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Mazatlan.rb +0 -139
  291. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Mexico_City.rb +0 -144
  292. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Monterrey.rb +0 -131
  293. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/New_York.rb +0 -282
  294. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Phoenix.rb +0 -30
  295. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Regina.rb +0 -74
  296. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Santiago.rb +0 -205
  297. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Sao_Paulo.rb +0 -171
  298. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/St_Johns.rb +0 -288
  299. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Tijuana.rb +0 -196
  300. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Almaty.rb +0 -67
  301. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Baghdad.rb +0 -73
  302. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Baku.rb +0 -161
  303. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Bangkok.rb +0 -20
  304. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Chongqing.rb +0 -33
  305. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Colombo.rb +0 -30
  306. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Dhaka.rb +0 -27
  307. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Hong_Kong.rb +0 -87
  308. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Irkutsk.rb +0 -165
  309. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Jakarta.rb +0 -30
  310. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Jerusalem.rb +0 -163
  311. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kabul.rb +0 -20
  312. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kamchatka.rb +0 -163
  313. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Karachi.rb +0 -30
  314. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Katmandu.rb +0 -20
  315. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kolkata.rb +0 -25
  316. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Krasnoyarsk.rb +0 -163
  317. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kuala_Lumpur.rb +0 -31
  318. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kuwait.rb +0 -18
  319. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Magadan.rb +0 -163
  320. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Muscat.rb +0 -18
  321. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Novosibirsk.rb +0 -164
  322. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Rangoon.rb +0 -24
  323. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Riyadh.rb +0 -18
  324. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Seoul.rb +0 -34
  325. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Shanghai.rb +0 -35
  326. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Singapore.rb +0 -33
  327. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Taipei.rb +0 -59
  328. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tashkent.rb +0 -47
  329. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tbilisi.rb +0 -78
  330. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tehran.rb +0 -121
  331. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tokyo.rb +0 -30
  332. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Ulaanbaatar.rb +0 -65
  333. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Urumqi.rb +0 -33
  334. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Vladivostok.rb +0 -164
  335. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Yakutsk.rb +0 -163
  336. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Yekaterinburg.rb +0 -165
  337. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Yerevan.rb +0 -165
  338. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Atlantic/Azores.rb +0 -270
  339. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Atlantic/Cape_Verde.rb +0 -23
  340. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Atlantic/South_Georgia.rb +0 -18
  341. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Adelaide.rb +0 -187
  342. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Brisbane.rb +0 -35
  343. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Darwin.rb +0 -29
  344. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Hobart.rb +0 -193
  345. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Melbourne.rb +0 -185
  346. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Perth.rb +0 -37
  347. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Sydney.rb +0 -185
  348. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Etc/UTC.rb +0 -16
  349. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Amsterdam.rb +0 -228
  350. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Athens.rb +0 -185
  351. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Belgrade.rb +0 -163
  352. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Berlin.rb +0 -188
  353. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Bratislava.rb +0 -13
  354. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Brussels.rb +0 -232
  355. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Bucharest.rb +0 -181
  356. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Budapest.rb +0 -197
  357. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Copenhagen.rb +0 -179
  358. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Dublin.rb +0 -276
  359. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Helsinki.rb +0 -163
  360. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Istanbul.rb +0 -218
  361. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Kiev.rb +0 -168
  362. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Lisbon.rb +0 -268
  363. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Ljubljana.rb +0 -13
  364. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/London.rb +0 -288
  365. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Madrid.rb +0 -211
  366. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Minsk.rb +0 -170
  367. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Moscow.rb +0 -181
  368. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Paris.rb +0 -232
  369. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Prague.rb +0 -187
  370. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Riga.rb +0 -176
  371. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Rome.rb +0 -215
  372. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Sarajevo.rb +0 -13
  373. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Skopje.rb +0 -13
  374. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Sofia.rb +0 -173
  375. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Stockholm.rb +0 -165
  376. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Tallinn.rb +0 -172
  377. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Vienna.rb +0 -183
  378. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Vilnius.rb +0 -170
  379. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Warsaw.rb +0 -212
  380. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Zagreb.rb +0 -13
  381. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Auckland.rb +0 -202
  382. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Fiji.rb +0 -23
  383. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Guam.rb +0 -22
  384. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Honolulu.rb +0 -28
  385. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Majuro.rb +0 -20
  386. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Midway.rb +0 -25
  387. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Noumea.rb +0 -25
  388. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Pago_Pago.rb +0 -26
  389. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Port_Moresby.rb +0 -20
  390. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Tongatapu.rb +0 -27
  391. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/info_timezone.rb +0 -52
  392. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/linked_timezone.rb +0 -51
  393. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/linked_timezone_info.rb +0 -44
  394. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/offset_rationals.rb +0 -98
  395. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/ruby_core_support.rb +0 -56
  396. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/time_or_datetime.rb +0 -292
  397. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone.rb +0 -508
  398. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_definition.rb +0 -56
  399. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_info.rb +0 -40
  400. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_offset_info.rb +0 -94
  401. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_period.rb +0 -198
  402. data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_transition_info.rb +0 -129
  403. data/lib/activesupport.rb +0 -2
@@ -1,3 +1,5 @@
1
+ require 'active_support/gzip'
2
+
1
3
  module ActiveSupport
2
4
  module Cache
3
5
  class CompressedMemCacheStore < MemCacheStore
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/file/atomic'
2
+
1
3
  module ActiveSupport
2
4
  module Cache
3
5
  # A cache store implementation which stores everything on the filesystem.
@@ -8,43 +10,59 @@ module ActiveSupport
8
10
  @cache_path = cache_path
9
11
  end
10
12
 
13
+ # Reads a value from the cache.
14
+ #
15
+ # Possible options:
16
+ # - +:expires_in+ - the number of seconds that this value may stay in
17
+ # the cache.
11
18
  def read(name, options = nil)
12
- super
13
- File.open(real_file_path(name), 'rb') { |f| Marshal.load(f) } rescue nil
19
+ super do
20
+ file_name = real_file_path(name)
21
+ expires = expires_in(options)
22
+
23
+ if File.exist?(file_name) && (expires <= 0 || Time.now - File.mtime(file_name) < expires)
24
+ File.open(file_name, 'rb') { |f| Marshal.load(f) }
25
+ end
26
+ end
14
27
  end
15
28
 
29
+ # Writes a value to the cache.
16
30
  def write(name, value, options = nil)
17
- super
18
- ensure_cache_path(File.dirname(real_file_path(name)))
19
- File.atomic_write(real_file_path(name), cache_path) { |f| Marshal.dump(value, f) }
20
- value
31
+ super do
32
+ ensure_cache_path(File.dirname(real_file_path(name)))
33
+ File.atomic_write(real_file_path(name), cache_path) { |f| Marshal.dump(value, f) }
34
+ value
35
+ end
21
36
  rescue => e
22
37
  logger.error "Couldn't create cache directory: #{name} (#{e.message})" if logger
23
38
  end
24
39
 
25
40
  def delete(name, options = nil)
26
- super
27
- File.delete(real_file_path(name))
41
+ super do
42
+ File.delete(real_file_path(name))
43
+ end
28
44
  rescue SystemCallError => e
29
45
  # If there's no cache, then there's nothing to complain about
30
46
  end
31
47
 
32
48
  def delete_matched(matcher, options = nil)
33
- super
34
- search_dir(@cache_path) do |f|
35
- if f =~ matcher
36
- begin
37
- File.delete(f)
38
- rescue SystemCallError => e
39
- # If there's no cache, then there's nothing to complain about
49
+ super do
50
+ search_dir(@cache_path) do |f|
51
+ if f =~ matcher
52
+ begin
53
+ File.delete(f)
54
+ rescue SystemCallError => e
55
+ # If there's no cache, then there's nothing to complain about
56
+ end
40
57
  end
41
58
  end
42
59
  end
43
60
  end
44
61
 
45
62
  def exist?(name, options = nil)
46
- super
47
- File.exist?(real_file_path(name))
63
+ super do
64
+ File.exist?(real_file_path(name))
65
+ end
48
66
  end
49
67
 
50
68
  private
@@ -1,4 +1,5 @@
1
1
  require 'memcache'
2
+ require 'active_support/core_ext/array/extract_options'
2
3
 
3
4
  module ActiveSupport
4
5
  module Cache
@@ -12,7 +13,7 @@ module ActiveSupport
12
13
  # and MemCacheStore will load balance between all available servers. If a
13
14
  # server goes down, then MemCacheStore will ignore it until it goes back
14
15
  # online.
15
- # - Time-based expiry support. See #write and the +:expires_in+ option.
16
+ # - Time-based expiry support. See #write and the <tt>:expires_in</tt> option.
16
17
  # - Per-request in memory cache for all communication with the MemCache server(s).
17
18
  class MemCacheStore < Store
18
19
  module Response # :nodoc:
@@ -59,8 +60,9 @@ module ActiveSupport
59
60
  end
60
61
 
61
62
  def read(key, options = nil) # :nodoc:
62
- super
63
- @data.get(key, raw?(options))
63
+ super do
64
+ @data.get(key, raw?(options))
65
+ end
64
66
  rescue MemCache::MemCacheError => e
65
67
  logger.error("MemCacheError (#{e}): #{e.message}")
66
68
  nil
@@ -69,27 +71,29 @@ module ActiveSupport
69
71
  # Writes a value to the cache.
70
72
  #
71
73
  # Possible options:
72
- # - +:unless_exist+ - set to true if you don't want to update the cache
74
+ # - <tt>:unless_exist</tt> - set to true if you don't want to update the cache
73
75
  # if the key is already set.
74
- # - +:expires_in+ - the number of seconds that this value may stay in
76
+ # - <tt>:expires_in</tt> - the number of seconds that this value may stay in
75
77
  # the cache. See ActiveSupport::Cache::Store#write for an example.
76
78
  def write(key, value, options = nil)
77
- super
78
- method = options && options[:unless_exist] ? :add : :set
79
- # memcache-client will break the connection if you send it an integer
80
- # in raw mode, so we convert it to a string to be sure it continues working.
81
- value = value.to_s if raw?(options)
82
- response = @data.send(method, key, value, expires_in(options), raw?(options))
83
- response == Response::STORED
79
+ super do
80
+ method = options && options[:unless_exist] ? :add : :set
81
+ # memcache-client will break the connection if you send it an integer
82
+ # in raw mode, so we convert it to a string to be sure it continues working.
83
+ value = value.to_s if raw?(options)
84
+ response = @data.send(method, key, value, expires_in(options), raw?(options))
85
+ response == Response::STORED
86
+ end
84
87
  rescue MemCache::MemCacheError => e
85
88
  logger.error("MemCacheError (#{e}): #{e.message}")
86
89
  false
87
90
  end
88
91
 
89
92
  def delete(key, options = nil) # :nodoc:
90
- super
91
- response = @data.delete(key, expires_in(options))
92
- response == Response::DELETED
93
+ super do
94
+ response = @data.delete(key, expires_in(options))
95
+ response == Response::DELETED
96
+ end
93
97
  rescue MemCache::MemCacheError => e
94
98
  logger.error("MemCacheError (#{e}): #{e.message}")
95
99
  false
@@ -99,21 +103,26 @@ module ActiveSupport
99
103
  # Doesn't call super, cause exist? in memcache is in fact a read
100
104
  # But who cares? Reading is very fast anyway
101
105
  # Local cache is checked first, if it doesn't know then memcache itself is read from
102
- !read(key, options).nil?
106
+ super do
107
+ !read(key, options).nil?
108
+ end
103
109
  end
104
110
 
105
111
  def increment(key, amount = 1) # :nodoc:
106
- log("incrementing", key, amount)
112
+ response = instrument(:increment, key, :amount => amount) do
113
+ @data.incr(key, amount)
114
+ end
107
115
 
108
- response = @data.incr(key, amount)
109
116
  response == Response::NOT_FOUND ? nil : response
110
117
  rescue MemCache::MemCacheError
111
118
  nil
112
119
  end
113
120
 
114
121
  def decrement(key, amount = 1) # :nodoc:
115
- log("decrement", key, amount)
116
- response = @data.decr(key, amount)
122
+ response = instrument(:decrement, key, :amount => amount) do
123
+ @data.decr(key, amount)
124
+ end
125
+
117
126
  response == Response::NOT_FOUND ? nil : response
118
127
  rescue MemCache::MemCacheError
119
128
  nil
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/object/duplicable'
2
+
1
3
  module ActiveSupport
2
4
  module Cache
3
5
  # A cache store implementation which stores everything into memory in the
@@ -19,35 +21,34 @@ module ActiveSupport
19
21
  @data = {}
20
22
  end
21
23
 
22
- def read_multi(*names)
23
- results = {}
24
- names.each { |n| results[n] = read(n) }
25
- results
26
- end
27
-
28
24
  def read(name, options = nil)
29
- super
30
- @data[name]
25
+ super do
26
+ @data[name]
27
+ end
31
28
  end
32
29
 
33
30
  def write(name, value, options = nil)
34
- super
35
- @data[name] = value.freeze
31
+ super do
32
+ @data[name] = (value.duplicable? ? value.dup : value).freeze
33
+ end
36
34
  end
37
35
 
38
36
  def delete(name, options = nil)
39
- super
40
- @data.delete(name)
37
+ super do
38
+ @data.delete(name)
39
+ end
41
40
  end
42
41
 
43
42
  def delete_matched(matcher, options = nil)
44
- super
45
- @data.delete_if { |k,v| k =~ matcher }
43
+ super do
44
+ @data.delete_if { |k,v| k =~ matcher }
45
+ end
46
46
  end
47
47
 
48
- def exist?(name, options = nil)
49
- super
50
- @data.has_key?(name)
48
+ def exist?(name,options = nil)
49
+ super do
50
+ @data.has_key?(name)
51
+ end
51
52
  end
52
53
 
53
54
  def clear
@@ -1,3 +1,6 @@
1
+ require 'active_support/core_ext/object/duplicable'
2
+ require 'active_support/core_ext/string/inflections'
3
+
1
4
  module ActiveSupport
2
5
  module Cache
3
6
  module Strategy
@@ -15,7 +18,7 @@ module ActiveSupport
15
18
  def middleware
16
19
  @middleware ||= begin
17
20
  klass = Class.new
18
- klass.class_eval(<<-EOS, __FILE__, __LINE__ + 1)
21
+ klass.class_eval(<<-EOS, __FILE__, __LINE__)
19
22
  def initialize(app)
20
23
  @app = app
21
24
  end
@@ -27,6 +30,11 @@ module ActiveSupport
27
30
  Thread.current[:#{thread_local_key}] = nil
28
31
  end
29
32
  EOS
33
+
34
+ def klass.to_s
35
+ "ActiveSupport::Cache::Strategy::LocalCache"
36
+ end
37
+
30
38
  klass
31
39
  end
32
40
  end
@@ -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/object/metaclass'
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.metaclass.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__
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