Skip to content

Commit 0e8dda7

Browse files
committed
Merge pull request rails#3637 from bogdan/compile_options
AS::Callbacks::Callback refactor
2 parents be52f1b + 3dc80b7 commit 0e8dda7

File tree

1 file changed

+62
-58
lines changed

1 file changed

+62
-58
lines changed

activesupport/lib/active_support/callbacks.rb

+62-58
Original file line numberDiff line numberDiff line change
@@ -166,19 +166,10 @@ def _one_time_conditions_valid_#{@callback_id}?
166166
RUBY_EVAL
167167
end
168168

169-
# This will supply contents for before and around filters, and no
170-
# contents for after filters (for the forward pass).
171-
def start(key=nil, object=nil)
172-
return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
173-
174-
# options[0] is the compiled form of supplied conditions
175-
# options[1] is the "end" for the conditional
176-
#
169+
# Wraps code with filter
170+
def apply(code, key=nil, object=nil)
177171
case @kind
178172
when :before
179-
# if condition # before_save :filter_name, :if => :condition
180-
# filter_name
181-
# end
182173
<<-RUBY_EVAL
183174
if !halted && #{@compiled_options}
184175
# This double assignment is to prevent warnings in 1.9.3 as
@@ -190,62 +181,64 @@ def start(key=nil, object=nil)
190181
halted_callback_hook(#{@raw_filter.inspect.inspect})
191182
end
192183
end
184+
#{code}
193185
RUBY_EVAL
194-
when :around
195-
# Compile around filters with conditions into proxy methods
196-
# that contain the conditions.
197-
#
198-
# For `around_save :filter_name, :if => :condition':
199-
#
200-
# def _conditional_callback_save_17
201-
# if condition
202-
# filter_name do
203-
# yield self
204-
# end
205-
# else
206-
# yield self
207-
# end
208-
# end
209-
#
210-
name = "_conditional_callback_#{@kind}_#{next_id}"
211-
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
212-
def #{name}(halted)
213-
if #{@compiled_options} && !halted
214-
#{@filter} do
215-
yield self
216-
end
217-
else
218-
yield self
219-
end
220-
end
221-
RUBY_EVAL
222-
"#{name}(halted) do"
223-
end
224-
end
225-
226-
# This will supply contents for around and after filters, but not
227-
# before filters (for the backward pass).
228-
def end(key=nil, object=nil)
229-
return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
230-
231-
case @kind
232186
when :after
233-
# after_save :filter_name, :if => :condition
234187
<<-RUBY_EVAL
188+
#{code}
235189
if #{@compiled_options}
236190
#{@filter}
237191
end
238192
RUBY_EVAL
239193
when :around
194+
name = define_conditional_callback
240195
<<-RUBY_EVAL
196+
#{name}(halted) do
197+
#{code}
241198
value
242199
end
243200
RUBY_EVAL
244201
end
245202
end
246203

204+
205+
def one_time_conditions_valid?(object)
206+
object.send("_one_time_conditions_valid_#{@callback_id}?")
207+
end
208+
247209
private
248210

211+
# Compile around filters with conditions into proxy methods
212+
# that contain the conditions.
213+
#
214+
# For `around_save :filter_name, :if => :condition':
215+
#
216+
# def _conditional_callback_save_17
217+
# if condition
218+
# filter_name do
219+
# yield self
220+
# end
221+
# else
222+
# yield self
223+
# end
224+
# end
225+
#
226+
def define_conditional_callback
227+
name = "_conditional_callback_#{@kind}_#{next_id}"
228+
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
229+
def #{name}(halted)
230+
if #{@compiled_options} && !halted
231+
#{@filter} do
232+
yield self
233+
end
234+
else
235+
yield self
236+
end
237+
end
238+
RUBY_EVAL
239+
name
240+
end
241+
249242
# Options support the same options as filters themselves (and support
250243
# symbols, string, procs, and objects), so compile a conditional
251244
# expression based on the options
@@ -348,10 +341,20 @@ def compile(key=nil, object=nil)
348341
method << "value = nil"
349342
method << "halted = false"
350343

351-
each do |callback|
352-
method << callback.start(key, object)
344+
callbacks = yielding
345+
applicable_callbacks_for(key, object).reverse_each do |callback|
346+
callbacks = callback.apply(callbacks, key, object)
353347
end
348+
method << callbacks
349+
350+
method << "raise rescued_error if rescued_error" if config[:rescuable]
351+
method << "halted ? false : (block_given? ? value : true)"
352+
method.flatten.compact.join("\n")
353+
end
354354

355+
# Returns part of method that evaluates the callback block
356+
def yielding
357+
method = []
355358
if config[:rescuable]
356359
method << "rescued_error = nil"
357360
method << "begin"
@@ -364,14 +367,15 @@ def compile(key=nil, object=nil)
364367
method << "rescued_error = e"
365368
method << "end"
366369
end
370+
method.join("\n")
371+
end
367372

368-
reverse_each do |callback|
369-
method << callback.end(key, object)
373+
# Selects callbacks that have valid <tt>:per_key</tt> condition
374+
def applicable_callbacks_for(key, object)
375+
return self unless key
376+
select do |callback|
377+
callback.one_time_conditions_valid?(object)
370378
end
371-
372-
method << "raise rescued_error if rescued_error" if config[:rescuable]
373-
method << "halted ? false : (block_given? ? value : true)"
374-
method.compact.join("\n")
375379
end
376380
end
377381

0 commit comments

Comments
 (0)