activesupport 3.0.20 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. data/CHANGELOG +24 -28
  2. data/README.rdoc +2 -2
  3. data/lib/active_support/backtrace_cleaner.rb +17 -12
  4. data/lib/active_support/buffered_logger.rb +7 -9
  5. data/lib/active_support/cache/file_store.rb +4 -3
  6. data/lib/active_support/cache/mem_cache_store.rb +10 -2
  7. data/lib/active_support/cache/strategy/local_cache.rb +28 -23
  8. data/lib/active_support/cache.rb +11 -14
  9. data/lib/active_support/callbacks.rb +195 -175
  10. data/lib/active_support/concern.rb +105 -35
  11. data/lib/active_support/configurable.rb +50 -8
  12. data/lib/active_support/core_ext/array/access.rb +2 -2
  13. data/lib/active_support/core_ext/array/conversions.rb +2 -2
  14. data/lib/active_support/core_ext/array/random_access.rb +10 -7
  15. data/lib/active_support/core_ext/array/uniq_by.rb +2 -3
  16. data/lib/active_support/core_ext/array/wrap.rb +1 -1
  17. data/lib/active_support/core_ext/big_decimal/conversions.rb +0 -2
  18. data/lib/active_support/core_ext/class/attribute.rb +15 -1
  19. data/lib/active_support/core_ext/class/inheritable_attributes.rb +10 -86
  20. data/lib/active_support/core_ext/class/subclasses.rb +20 -34
  21. data/lib/active_support/core_ext/date/calculations.rb +17 -5
  22. data/lib/active_support/core_ext/date/conversions.rb +9 -2
  23. data/lib/active_support/core_ext/date_time/calculations.rb +26 -9
  24. data/lib/active_support/core_ext/date_time/conversions.rb +9 -9
  25. data/lib/active_support/core_ext/date_time/zones.rb +1 -1
  26. data/lib/active_support/core_ext/enumerable.rb +3 -6
  27. data/lib/active_support/core_ext/float/rounding.rb +1 -1
  28. data/lib/active_support/core_ext/hash/conversions.rb +22 -34
  29. data/lib/active_support/core_ext/hash/deep_dup.rb +11 -0
  30. data/lib/active_support/core_ext/hash/indifferent_access.rb +12 -0
  31. data/lib/active_support/core_ext/hash/keys.rb +6 -4
  32. data/lib/active_support/core_ext/hash/reverse_merge.rb +9 -14
  33. data/lib/active_support/core_ext/hash/slice.rb +3 -1
  34. data/lib/active_support/core_ext/hash.rb +1 -0
  35. data/lib/active_support/core_ext/integer/inflections.rb +7 -4
  36. data/lib/active_support/core_ext/kernel/reporting.rb +31 -0
  37. data/lib/active_support/core_ext/kernel/requires.rb +2 -0
  38. data/lib/active_support/core_ext/logger.rb +11 -38
  39. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +12 -12
  40. data/lib/active_support/core_ext/module/attr_internal.rb +13 -6
  41. data/lib/active_support/core_ext/module/delegation.rb +1 -5
  42. data/lib/active_support/core_ext/module/remove_method.rb +7 -2
  43. data/lib/active_support/core_ext/numeric/time.rb +2 -0
  44. data/lib/active_support/core_ext/object/blank.rb +45 -12
  45. data/lib/active_support/core_ext/object/duplicable.rb +50 -9
  46. data/lib/active_support/core_ext/object/inclusion.rb +15 -0
  47. data/lib/active_support/core_ext/object/instance_variables.rb +1 -35
  48. data/lib/active_support/core_ext/object/to_param.rb +13 -8
  49. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  50. data/lib/active_support/core_ext/object/try.rb +29 -10
  51. data/lib/active_support/core_ext/object/with_options.rb +25 -8
  52. data/lib/active_support/core_ext/object.rb +1 -1
  53. data/lib/active_support/core_ext/range/cover.rb +3 -0
  54. data/lib/active_support/core_ext/range.rb +1 -0
  55. data/lib/active_support/core_ext/string/behavior.rb +1 -2
  56. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  57. data/lib/active_support/core_ext/string/exclude.rb +1 -1
  58. data/lib/active_support/core_ext/string/filters.rb +3 -3
  59. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  60. data/lib/active_support/core_ext/string/inquiry.rb +13 -0
  61. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  62. data/lib/active_support/core_ext/string/output_safety.rb +45 -62
  63. data/lib/active_support/core_ext/string.rb +1 -0
  64. data/lib/active_support/core_ext/time/calculations.rb +19 -16
  65. data/lib/active_support/core_ext/time/conversions.rb +2 -24
  66. data/lib/active_support/core_ext/time/zones.rb +32 -21
  67. data/lib/active_support/core_ext/uri.rb +8 -0
  68. data/lib/active_support/dependencies.rb +74 -28
  69. data/lib/active_support/deprecation/behaviors.rb +7 -0
  70. data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
  71. data/lib/active_support/deprecation/reporting.rb +4 -0
  72. data/lib/active_support/deprecation.rb +2 -2
  73. data/lib/active_support/descendants_tracker.rb +9 -7
  74. data/lib/active_support/duration.rb +5 -0
  75. data/lib/active_support/file_update_checker.rb +1 -1
  76. data/lib/active_support/file_watcher.rb +36 -0
  77. data/lib/active_support/hash_with_indifferent_access.rb +20 -8
  78. data/lib/active_support/i18n.rb +0 -1
  79. data/lib/active_support/i18n_railtie.rb +2 -2
  80. data/lib/active_support/inflections.rb +1 -0
  81. data/lib/active_support/inflector/inflections.rb +1 -1
  82. data/lib/active_support/inflector/methods.rb +5 -3
  83. data/lib/active_support/json/decoding.rb +37 -23
  84. data/lib/active_support/json/encoding.rb +12 -4
  85. data/lib/active_support/lazy_load_hooks.rb +7 -7
  86. data/lib/active_support/log_subscriber/test_helper.rb +5 -3
  87. data/lib/active_support/log_subscriber.rb +6 -6
  88. data/lib/active_support/message_encryptor.rb +1 -1
  89. data/lib/active_support/message_verifier.rb +1 -1
  90. data/lib/active_support/multibyte/chars.rb +5 -5
  91. data/lib/active_support/multibyte/unicode.rb +2 -1
  92. data/lib/active_support/notifications/fanout.rb +3 -3
  93. data/lib/active_support/notifications/instrumenter.rb +1 -1
  94. data/lib/active_support/notifications.rb +9 -10
  95. data/lib/active_support/ordered_hash.rb +23 -2
  96. data/lib/active_support/ordered_options.rb +37 -3
  97. data/lib/active_support/railtie.rb +1 -1
  98. data/lib/active_support/rescuable.rb +1 -0
  99. data/lib/active_support/secure_random.rb +3 -196
  100. data/lib/active_support/test_case.rb +2 -10
  101. data/lib/active_support/testing/assertions.rb +20 -7
  102. data/lib/active_support/testing/mochaing.rb +7 -0
  103. data/lib/active_support/testing/pending.rb +27 -23
  104. data/lib/active_support/testing/performance/jruby.rb +115 -0
  105. data/lib/active_support/testing/performance/rubinius.rb +113 -0
  106. data/lib/active_support/testing/performance/ruby/mri.rb +57 -0
  107. data/lib/active_support/testing/performance/ruby/yarv.rb +57 -0
  108. data/lib/active_support/testing/performance/ruby.rb +152 -0
  109. data/lib/active_support/testing/performance.rb +214 -322
  110. data/lib/active_support/testing/setup_and_teardown.rb +8 -11
  111. data/lib/active_support/time_with_zone.rb +6 -3
  112. data/lib/active_support/values/time_zone.rb +26 -8
  113. data/lib/active_support/version.rb +2 -2
  114. data/lib/active_support/whiny_nil.rb +1 -1
  115. data/lib/active_support/xml_mini/jdom.rb +1 -1
  116. data/lib/active_support/xml_mini/libxml.rb +1 -0
  117. data/lib/active_support/xml_mini/libxmlsax.rb +2 -1
  118. data/lib/active_support/xml_mini/nokogiri.rb +1 -0
  119. data/lib/active_support/xml_mini/nokogirisax.rb +1 -0
  120. data/lib/active_support/xml_mini/rexml.rb +1 -0
  121. data/lib/active_support/xml_mini.rb +8 -3
  122. data/lib/active_support.rb +4 -2
  123. metadata +70 -32
  124. checksums.yaml +0 -7
  125. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -19
  126. data/lib/active_support/core_ext/cgi.rb +0 -1
  127. data/lib/active_support/core_ext/object/returning.rb +0 -43
  128. data/lib/active_support/json/backends/jsongem.rb +0 -47
  129. data/lib/active_support/json/backends/okjson.rb +0 -644
  130. data/lib/active_support/json/backends/yajl.rb +0 -44
  131. data/lib/active_support/json/backends/yaml.rb +0 -19
  132. data/lib/active_support/testing/default.rb +0 -9
@@ -1,32 +1,34 @@
1
1
  require 'active_support/concern'
2
2
  require 'active_support/descendants_tracker'
3
3
  require 'active_support/core_ext/array/wrap'
4
- require 'active_support/core_ext/class/inheritable_attributes'
4
+ require 'active_support/core_ext/class/attribute'
5
5
  require 'active_support/core_ext/kernel/reporting'
6
6
  require 'active_support/core_ext/kernel/singleton_class'
7
+ require 'active_support/core_ext/object/inclusion'
7
8
 
8
9
  module ActiveSupport
9
- # Callbacks are hooks into the life cycle of an object that allow you to trigger logic
10
- # before or after an alteration of the object state.
10
+ # \Callbacks are code hooks that are run at key points in an object's lifecycle.
11
+ # The typical use case is to have a base class define a set of callbacks relevant
12
+ # to the other functionality it supplies, so that subclasses can install callbacks
13
+ # that enhance or modify the base functionality without needing to override
14
+ # or redefine methods of the base class.
11
15
  #
12
- # Mixing in this module allows you to define callbacks in your class.
16
+ # Mixing in this module allows you to define the events in the object's lifecycle
17
+ # that will support callbacks (via +ClassMethods.define_callbacks+), set the instance
18
+ # methods, procs, or callback objects to be called (via +ClassMethods.set_callback+),
19
+ # and run the installed callbacks at the appropriate times (via +run_callbacks+).
13
20
  #
14
- # Example:
15
- # class Storage
16
- # include ActiveSupport::Callbacks
17
- #
18
- # define_callbacks :save
19
- # end
21
+ # Three kinds of callbacks are supported: before callbacks, run before a certain event;
22
+ # after callbacks, run after the event; and around callbacks, blocks that surround the
23
+ # event, triggering it when they yield. Callback code can be contained in instance
24
+ # methods, procs or lambdas, or callback objects that respond to certain predetermined
25
+ # methods. See +ClassMethods.set_callback+ for details.
20
26
  #
21
- # class ConfigStorage < Storage
22
- # set_callback :save, :before, :saving_message
23
- # def saving_message
24
- # puts "saving..."
25
- # end
27
+ # ==== Example
26
28
  #
27
- # set_callback :save, :after do |object|
28
- # puts "saved"
29
- # end
29
+ # class Record
30
+ # include ActiveSupport::Callbacks
31
+ # define_callbacks :save
30
32
  #
31
33
  # def save
32
34
  # run_callbacks :save do
@@ -35,29 +37,7 @@ module ActiveSupport
35
37
  # end
36
38
  # end
37
39
  #
38
- # config = ConfigStorage.new
39
- # config.save
40
- #
41
- # Output:
42
- # saving...
43
- # - save
44
- # saved
45
- #
46
- # Callbacks from parent classes are inherited.
47
- #
48
- # Example:
49
- # class Storage
50
- # include ActiveSupport::Callbacks
51
- #
52
- # define_callbacks :save
53
- #
54
- # set_callback :save, :before, :prepare
55
- # def prepare
56
- # puts "preparing save"
57
- # end
58
- # end
59
- #
60
- # class ConfigStorage < Storage
40
+ # class PersonRecord < Record
61
41
  # set_callback :save, :before, :saving_message
62
42
  # def saving_message
63
43
  # puts "saving..."
@@ -66,19 +46,12 @@ module ActiveSupport
66
46
  # set_callback :save, :after do |object|
67
47
  # puts "saved"
68
48
  # end
69
- #
70
- # def save
71
- # run_callbacks :save do
72
- # puts "- save"
73
- # end
74
- # end
75
49
  # end
76
50
  #
77
- # config = ConfigStorage.new
78
- # config.save
51
+ # person = PersonRecord.new
52
+ # person.save
79
53
  #
80
54
  # Output:
81
- # preparing save
82
55
  # saving...
83
56
  # - save
84
57
  # saved
@@ -90,16 +63,25 @@ module ActiveSupport
90
63
  extend ActiveSupport::DescendantsTracker
91
64
  end
92
65
 
66
+ # Runs the callbacks for the given event.
67
+ #
68
+ # Calls the before and around callbacks in the order they were set, yields
69
+ # the block (if given one), and then runs the after callbacks in reverse order.
70
+ # Optionally accepts a key, which will be used to compile an optimized callback
71
+ # method for each key. See +ClassMethods.define_callbacks+ for more information.
72
+ #
73
+ # If the callback chain was halted, returns +false+. Otherwise returns the result
74
+ # of the block, or +true+ if no block is given.
75
+ #
76
+ # run_callbacks :save do
77
+ # save
78
+ # end
79
+ #
93
80
  def run_callbacks(kind, *args, &block)
94
81
  send("_run_#{kind}_callbacks", *args, &block)
95
82
  end
96
83
 
97
- def callback(kind)
98
- ActiveSupport::Deprecation.warn("callback is deprecated. Please use run_callbacks")
99
- send("_run_#{kind}_callbacks")
100
- end
101
-
102
- class Callback
84
+ class Callback #:nodoc:#
103
85
  @@_callback_sequence = 0
104
86
 
105
87
  attr_accessor :chain, :filter, :kind, :options, :per_key, :klass, :raw_filter
@@ -184,49 +166,52 @@ module ActiveSupport
184
166
  # options[0] is the compiled form of supplied conditions
185
167
  # options[1] is the "end" for the conditional
186
168
  #
187
- if @kind == :before || @kind == :around
188
- if @kind == :before
189
- # if condition # before_save :filter_name, :if => :condition
190
- # filter_name
191
- # end
192
- filter = <<-RUBY_EVAL
193
- unless halted
194
- result = #{@filter}
195
- halted = (#{chain.config[:terminator]})
196
- end
197
- RUBY_EVAL
198
-
199
- [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
200
- else
201
- # Compile around filters with conditions into proxy methods
202
- # that contain the conditions.
203
- #
204
- # For `around_save :filter_name, :if => :condition':
205
- #
206
- # def _conditional_callback_save_17
207
- # if condition
208
- # filter_name do
209
- # yield self
210
- # end
211
- # else
212
- # yield self
213
- # end
214
- # end
215
- #
216
- name = "_conditional_callback_#{@kind}_#{next_id}"
217
- @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
218
- def #{name}(halted)
219
- #{@compiled_options[0] || "if true"} && !halted
220
- #{@filter} do
221
- yield self
222
- end
223
- else
169
+ case @kind
170
+ when :before
171
+ # if condition # before_save :filter_name, :if => :condition
172
+ # filter_name
173
+ # end
174
+ filter = <<-RUBY_EVAL
175
+ unless halted
176
+ # This double assignment is to prevent warnings in 1.9.3. I would
177
+ # remove the `result` variable, but apparently some other
178
+ # generated code is depending on this variable being set sometimes
179
+ # and sometimes not.
180
+ result = result = #{@filter}
181
+ halted = (#{chain.config[:terminator]})
182
+ end
183
+ RUBY_EVAL
184
+
185
+ [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
186
+ when :around
187
+ # Compile around filters with conditions into proxy methods
188
+ # that contain the conditions.
189
+ #
190
+ # For `around_save :filter_name, :if => :condition':
191
+ #
192
+ # def _conditional_callback_save_17
193
+ # if condition
194
+ # filter_name do
195
+ # yield self
196
+ # end
197
+ # else
198
+ # yield self
199
+ # end
200
+ # end
201
+ #
202
+ name = "_conditional_callback_#{@kind}_#{next_id}"
203
+ @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
204
+ def #{name}(halted)
205
+ #{@compiled_options[0] || "if true"} && !halted
206
+ #{@filter} do
224
207
  yield self
225
208
  end
209
+ else
210
+ yield self
226
211
  end
227
- RUBY_EVAL
228
- "#{name}(halted) do"
229
- end
212
+ end
213
+ RUBY_EVAL
214
+ "#{name}(halted) do"
230
215
  end
231
216
  end
232
217
 
@@ -235,15 +220,17 @@ module ActiveSupport
235
220
  def end(key=nil, object=nil)
236
221
  return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
237
222
 
238
- if @kind == :around || @kind == :after
223
+ case @kind
224
+ when :after
239
225
  # if condition # after_save :filter_name, :if => :condition
240
226
  # filter_name
241
227
  # end
242
- if @kind == :after
243
- [@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
244
- else
245
- "end"
228
+ [@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
229
+ when :around
230
+ <<-RUBY_EVAL
231
+ value
246
232
  end
233
+ RUBY_EVAL
247
234
  end
248
235
  end
249
236
 
@@ -336,7 +323,7 @@ module ActiveSupport
336
323
  end
337
324
 
338
325
  # An Array with a compile method
339
- class CallbackChain < Array
326
+ class CallbackChain < Array #:nodoc:#
340
327
  attr_reader :name, :config
341
328
 
342
329
  def initialize(name, config)
@@ -381,20 +368,9 @@ module ActiveSupport
381
368
  end
382
369
 
383
370
  module ClassMethods
384
- # Make the run_callbacks :save method. The generated method takes
385
- # a block that it'll yield to. It'll call the before and around filters
386
- # in order, yield the block, and then run the after filters.
387
- #
388
- # run_callbacks :save do
389
- # save
390
- # end
391
- #
392
- # The run_callbacks :save method can optionally take a key, which
393
- # will be used to compile an optimized callback method for each
394
- # key. See #define_callbacks for more information.
395
- #
371
+ # Generate the internal runner method called by +run_callbacks+.
396
372
  def __define_runner(symbol) #:nodoc:
397
- body = send("_#{symbol}_callbacks").compile(nil)
373
+ body = send("_#{symbol}_callbacks").compile
398
374
 
399
375
  silence_warnings do
400
376
  undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
@@ -437,25 +413,56 @@ module ActiveSupport
437
413
  # CallbackChain.
438
414
  #
439
415
  def __update_callbacks(name, filters = [], block = nil) #:nodoc:
440
- type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
416
+ type = filters.first.in?([:before, :after, :around]) ? filters.shift : :before
441
417
  options = filters.last.is_a?(Hash) ? filters.pop : {}
442
418
  filters.unshift(block) if block
443
419
 
444
- ([self] + ActiveSupport::DescendantsTracker.descendants(self)).each do |target|
420
+ ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse.each do |target|
445
421
  chain = target.send("_#{name}_callbacks")
446
- yield chain, type, filters, options
422
+ yield target, chain.dup, type, filters, options
447
423
  target.__define_runner(name)
448
424
  end
449
425
  end
450
426
 
451
- # Set callbacks for a previously defined callback.
427
+ # Install a callback for the given event.
452
428
  #
453
- # Syntax:
454
429
  # set_callback :save, :before, :before_meth
455
430
  # set_callback :save, :after, :after_meth, :if => :condition
456
- # set_callback :save, :around, lambda { |r| stuff; yield; stuff }
431
+ # set_callback :save, :around, lambda { |r| stuff; result = yield; stuff }
432
+ #
433
+ # The second arguments indicates whether the callback is to be run +:before+,
434
+ # +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This
435
+ # means the first example above can also be written as:
436
+ #
437
+ # set_callback :save, :before_meth
438
+ #
439
+ # The callback can specified as a symbol naming an instance method; as a proc,
440
+ # lambda, or block; as a string to be instance evaluated; or as an object that
441
+ # responds to a certain method determined by the <tt>:scope</tt> argument to
442
+ # +define_callback+.
443
+ #
444
+ # If a proc, lambda, or block is given, its body is evaluated in the context
445
+ # of the current object. It can also optionally accept the current object as
446
+ # an argument.
457
447
  #
458
- # Use skip_callback to skip any defined one.
448
+ # Before and around callbacks are called in the order that they are set; after
449
+ # callbacks are called in the reverse order.
450
+ #
451
+ # Around callbacks can access the return value from the event, if it
452
+ # wasn't halted, from the +yield+ call.
453
+ #
454
+ # ===== Options
455
+ #
456
+ # * <tt>:if</tt> - A symbol naming an instance method or a proc; the callback
457
+ # will be called only when it returns a true value.
458
+ # * <tt>:unless</tt> - A symbol naming an instance method or a proc; the callback
459
+ # will be called only when it returns a false value.
460
+ # * <tt>:prepend</tt> - If true, the callback will be prepended to the existing
461
+ # chain rather than appended.
462
+ # * <tt>:per_key</tt> - A hash with <tt>:if</tt> and <tt>:unless</tt> options;
463
+ # see "Per-key conditions" below.
464
+ #
465
+ # ===== Per-key conditions
459
466
  #
460
467
  # When creating or skipping callbacks, you can specify conditions that
461
468
  # are always the same for a given key. For instance, in Action Pack,
@@ -465,12 +472,12 @@ module ActiveSupport
465
472
  #
466
473
  # becomes
467
474
  #
468
- # dispatch_callback :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
475
+ # set_callback :process_action, :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
469
476
  #
470
- # Per-Key conditions are evaluated only once per use of a given key.
477
+ # Per-key conditions are evaluated only once per use of a given key.
471
478
  # In the case of the above example, you would do:
472
479
  #
473
- # run_callbacks(:dispatch, action_name) { ... dispatch stuff ... }
480
+ # run_callbacks(:process_action, action_name) { ... dispatch stuff ... }
474
481
  #
475
482
  # In that case, each action_name would get its own compiled callback
476
483
  # method that took into consideration the per_key conditions. This
@@ -479,7 +486,7 @@ module ActiveSupport
479
486
  def set_callback(name, *filter_list, &block)
480
487
  mapped = nil
481
488
 
482
- __update_callbacks(name, filter_list, block) do |chain, type, filters, options|
489
+ __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
483
490
  mapped ||= filters.map do |filter|
484
491
  Callback.new(chain, filter, type, options.dup, self)
485
492
  end
@@ -489,13 +496,20 @@ module ActiveSupport
489
496
  end
490
497
 
491
498
  options[:prepend] ? chain.unshift(*(mapped.reverse)) : chain.push(*mapped)
499
+
500
+ target.send("_#{name}_callbacks=", chain)
492
501
  end
493
502
  end
494
503
 
495
- # Skip a previously defined callback for a given type.
504
+ # Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or <tt>:unless</tt>
505
+ # options may be passed in order to control when the callback is skipped.
506
+ #
507
+ # class Writer < Person
508
+ # skip_callback :validate, :before, :check_membership, :if => lambda { self.age > 18 }
509
+ # end
496
510
  #
497
511
  def skip_callback(name, *filter_list, &block)
498
- __update_callbacks(name, filter_list, block) do |chain, type, filters, options|
512
+ __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
499
513
  filters.each do |filter|
500
514
  filter = chain.find {|c| c.matches?(type, filter) }
501
515
 
@@ -507,92 +521,98 @@ module ActiveSupport
507
521
 
508
522
  chain.delete(filter)
509
523
  end
524
+ target.send("_#{name}_callbacks=", chain)
510
525
  end
511
526
  end
512
527
 
513
- # Reset callbacks for a given type.
528
+ # Remove all set callbacks for the given event.
514
529
  #
515
530
  def reset_callbacks(symbol)
516
531
  callbacks = send("_#{symbol}_callbacks")
517
532
 
518
533
  ActiveSupport::DescendantsTracker.descendants(self).each do |target|
519
- chain = target.send("_#{symbol}_callbacks")
534
+ chain = target.send("_#{symbol}_callbacks").dup
520
535
  callbacks.each { |c| chain.delete(c) }
536
+ target.send("_#{symbol}_callbacks=", chain)
521
537
  target.__define_runner(symbol)
522
538
  end
523
539
 
524
- callbacks.clear
540
+ self.send("_#{symbol}_callbacks=", callbacks.dup.clear)
541
+
525
542
  __define_runner(symbol)
526
543
  end
527
544
 
528
- # Defines callbacks types:
545
+ # Define sets of events in the object lifecycle that support callbacks.
529
546
  #
530
547
  # define_callbacks :validate
548
+ # define_callbacks :initialize, :save, :destroy
531
549
  #
532
- # This macro accepts the following options:
550
+ # ===== Options
533
551
  #
534
- # * <tt>:terminator</tt> - Indicates when a before filter is considered
535
- # to be halted.
552
+ # * <tt>:terminator</tt> - Determines when a before filter will halt the callback
553
+ # chain, preventing following callbacks from being called and the event from being
554
+ # triggered. This is a string to be eval'ed. The result of the callback is available
555
+ # in the <tt>result</tt> variable.
536
556
  #
537
- # define_callbacks :validate, :terminator => "result == false"
557
+ # define_callbacks :validate, :terminator => "result == false"
538
558
  #
539
- # In the example above, if any before validate callbacks returns +false+,
540
- # other callbacks are not executed. Defaults to "false", meaning no value
541
- # halts the chain.
559
+ # In this example, if any before validate callbacks returns +false+,
560
+ # other callbacks are not executed. Defaults to "false", meaning no value
561
+ # halts the chain.
542
562
  #
543
563
  # * <tt>:rescuable</tt> - By default, after filters are not executed if
544
- # the given block or a before filter raises an error. Set this option to
545
- # true to change this behavior.
564
+ # the given block or a before filter raises an error. By setting this option
565
+ # to <tt>true</tt> exception raised by given block is stored and after
566
+ # executing all the after callbacks the stored exception is raised.
546
567
  #
547
- # * <tt>:scope</tt> - Indicates which methods should be executed when a class
548
- # is given as callback. Defaults to <tt>[:kind]</tt>.
568
+ # * <tt>:scope</tt> - Indicates which methods should be executed when an object
569
+ # is used as a callback.
549
570
  #
550
- # class Audit
551
- # def before(caller)
552
- # puts 'Audit: before is called'
553
- # end
571
+ # class Audit
572
+ # def before(caller)
573
+ # puts 'Audit: before is called'
574
+ # end
554
575
  #
555
- # def before_save(caller)
556
- # puts 'Audit: before_save is called'
557
- # end
558
- # end
576
+ # def before_save(caller)
577
+ # puts 'Audit: before_save is called'
578
+ # end
579
+ # end
559
580
  #
560
- # class Account
561
- # include ActiveSupport::Callbacks
581
+ # class Account
582
+ # include ActiveSupport::Callbacks
562
583
  #
563
- # define_callbacks :save
564
- # set_callback :save, :before, Audit.new
584
+ # define_callbacks :save
585
+ # set_callback :save, :before, Audit.new
565
586
  #
566
- # def save
567
- # run_callbacks :save do
568
- # puts 'save in main'
569
- # end
570
- # end
571
- # end
587
+ # def save
588
+ # run_callbacks :save do
589
+ # puts 'save in main'
590
+ # end
591
+ # end
592
+ # end
572
593
  #
573
- # In the above case whenever you save an account the method <tt>Audit#before</tt> will
574
- # be called. On the other hand
594
+ # In the above case whenever you save an account the method <tt>Audit#before</tt> will
595
+ # be called. On the other hand
575
596
  #
576
- # define_callbacks :save, :scope => [:kind, :name]
597
+ # define_callbacks :save, :scope => [:kind, :name]
577
598
  #
578
- # would trigger <tt>Audit#before_save</tt> instead. That's constructed by calling
579
- # <tt>"#{kind}_#{name}"</tt> on the given instance. In this case "kind" is "before" and
580
- # "name" is "save". In this context ":kind" and ":name" have special meanings: ":kind"
581
- # refers to the kind of callback (before/after/around) and ":name" refers to the
582
- # method on which callbacks are being defined.
599
+ # would trigger <tt>Audit#before_save</tt> instead. That's constructed by calling
600
+ # <tt>#{kind}_#{name}</tt> on the given instance. In this case "kind" is "before" and
601
+ # "name" is "save". In this context +:kind+ and +:name+ have special meanings: +:kind+
602
+ # refers to the kind of callback (before/after/around) and +:name+ refers to the
603
+ # method on which callbacks are being defined.
583
604
  #
584
- # A declaration like
605
+ # A declaration like
585
606
  #
586
- # define_callbacks :save, :scope => [:name]
607
+ # define_callbacks :save, :scope => [:name]
587
608
  #
588
- # would call <tt>Audit#save</tt>.
609
+ # would call <tt>Audit#save</tt>.
589
610
  #
590
611
  def define_callbacks(*callbacks)
591
612
  config = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
592
613
  callbacks.each do |callback|
593
- extlib_inheritable_reader("_#{callback}_callbacks") do
594
- CallbackChain.new(callback, config)
595
- end
614
+ class_attribute "_#{callback}_callbacks"
615
+ send("_#{callback}_callbacks=", CallbackChain.new(callback, config))
596
616
  __define_runner(callback)
597
617
  end
598
618
  end