Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
23122ab2
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
23122ab2
编写于
5月 09, 2013
作者:
A
Aaron Patterson
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
callbacks are wrapped with lambdas
上级
cc0fd31f
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
78 addition
and
108 deletion
+78
-108
activemodel/test/cases/validations_test.rb
activemodel/test/cases/validations_test.rb
+1
-1
activerecord/test/cases/callbacks_test.rb
activerecord/test/cases/callbacks_test.rb
+1
-1
activesupport/lib/active_support/callbacks.rb
activesupport/lib/active_support/callbacks.rb
+76
-106
未找到文件。
activemodel/test/cases/validations_test.rb
浏览文件 @
23122ab2
...
...
@@ -166,7 +166,7 @@ def test_validate_block_with_params
def
test_invalid_validator
Topic
.
validate
:i_dont_exist
assert_raise
(
Name
Error
)
do
assert_raise
s
(
NoMethod
Error
)
do
t
=
Topic
.
new
t
.
valid?
end
...
...
activerecord/test/cases/callbacks_test.rb
浏览文件 @
23122ab2
...
...
@@ -43,7 +43,7 @@ def history
end
class
CallbackDeveloperWithFalseValidation
<
CallbackDeveloper
before_validation
proc
{
|
model
|
model
.
history
<<
[
:before_validation
,
:returning_false
];
return
false
}
before_validation
proc
{
|
model
|
model
.
history
<<
[
:before_validation
,
:returning_false
];
false
}
before_validation
proc
{
|
model
|
model
.
history
<<
[
:before_validation
,
:should_never_get_here
]
}
end
...
...
activesupport/lib/active_support/callbacks.rb
浏览文件 @
23122ab2
...
...
@@ -119,8 +119,6 @@ def initialize(chain, filter, kind, options, klass)
@raw_filter
,
@options
=
filter
,
options
@key
=
compute_identifier
filter
@source
=
_compile_source
(
filter
)
recompile_options!
end
def
filter
...
...
@@ -174,42 +172,57 @@ def _update_filter(filter_options, new_options)
def
recompile!
(
_options
)
deprecate_per_key_option
(
_options
)
_update_filter
(
self
.
options
,
_options
)
recompile_options!
end
# Wraps code with filter
def
apply
(
code
)
conditions
=
conditions_lambdas
source
=
make_lambda
@raw_filter
case
@kind
when
:before
<<-
RUBY_EVAL
if !halted &&
#{
@compiled_options
}
(value)
# This double assignment is to prevent warnings in 1.9.3 as
# the `result` variable is not always used except if the
# terminator code refers to it.
result = result =
#{
@source
}
(value)
halted = (
#{
chain
.
config
[
:terminator
]
}
)
halted_lambda
=
eval
"lambda { |result|
#{
chain
.
config
[
:terminator
]
}
}"
lambda
{
|
target
,
halted
,
value
,
&
block
|
if
!
halted
&&
conditions
.
all?
{
|
c
|
c
.
call
(
target
,
value
)
}
result
=
source
.
call
target
,
value
halted
=
halted_lambda
.
call
result
if
halted
halted_callback_hook(
#{
@raw_filter
.
inspect
.
inspect
}
)
target
.
send
:halted_callback_hook
,
@raw_filter
.
inspect
end
end
#{
code
}
RUBY_EVAL
code
.
call
target
,
halted
,
value
,
&
block
}
when
:after
<<-
RUBY_EVAL
#{
code
}
if
#{
!
chain
.
config
[
:skip_after_callbacks_if_terminated
]
||
"!halted"
}
&&
#{
@compiled_options
}
(value)
#{
@source
}
(value)
if
chain
.
config
[
:skip_after_callbacks_if_terminated
]
lambda
{
|
target
,
halted
,
value
,
&
block
|
target
,
halted
,
value
=
code
.
call
target
,
halted
,
value
,
&
block
if
!
halted
&&
conditions
.
all?
{
|
c
|
c
.
call
(
target
,
value
)
}
source
.
call
target
,
value
end
[
target
,
halted
,
value
]
}
else
lambda
{
|
target
,
halted
,
value
,
&
block
|
target
,
halted
,
value
=
code
.
call
target
,
halted
,
value
,
&
block
if
conditions
.
all?
{
|
c
|
c
.
call
(
target
,
value
)
}
source
.
call
target
,
value
end
[
target
,
halted
,
value
]
}
end
RUBY_EVAL
when
:around
name
=
define_conditional_callback
<<-
RUBY_EVAL
#{
name
}
(halted, value) do
#{
code
}
value
end
RUBY_EVAL
lambda
{
|
target
,
halted
,
value
,
&
block
|
if
!
halted
&&
conditions
.
all?
{
|
c
|
c
.
call
(
target
,
value
)
}
retval
=
nil
source
.
call
(
target
,
value
)
{
retval
=
code
.
call
(
target
,
halted
,
value
,
&
block
)
retval
.
last
}
retval
else
code
.
call
target
,
halted
,
value
,
&
block
end
}
end
end
...
...
@@ -219,6 +232,26 @@ def invert_lambda(l)
lambda
{
|*
args
,
&
blk
|
!
l
.
call
(
*
args
,
&
blk
)
}
end
# Filters support:
#
# Arrays:: Used in conditions. This is used to specify
# multiple conditions. Used internally to
# merge conditions from skip_* filters.
# Symbols:: A method to call.
# Strings:: Some content to evaluate.
# Procs:: A proc to call with the object.
# Objects:: An object with a <tt>before_foo</tt> method on it to call.
#
# All of these objects are compiled into methods and handled
# the same after this point:
#
# Arrays:: Merged together into a single filter.
# Symbols:: Already methods.
# Strings:: class_eval'ed into methods.
# Procs:: define_method'ed into methods.
# Objects::
# a method is created that calls the before_foo method
# on the object.
def
make_lambda
(
filter
)
case
filter
when
Array
...
...
@@ -263,40 +296,7 @@ def compute_identifier(filter)
end
end
# Compile around filters with conditions into proxy methods
# that contain the conditions.
#
# For `set_callback :save, :around, :filter_name, if: :condition':
#
# def _conditional_callback_save_17
# if condition
# filter_name do
# yield self
# end
# else
# yield self
# end
# end
def
define_conditional_callback
name
=
"_conditional_callback_
#{
@kind
}
_
#{
next_id
}
"
@klass
.
class_eval
<<-
RUBY_EVAL
,
__FILE__
,
__LINE__
+
1
def
#{
name
}
(halted, value)
if
#{
@compiled_options
}
(value) && !halted
#{
@source
}
(value) do
yield self
end
else
yield self
end
end
RUBY_EVAL
name
end
# Options support the same options as filters themselves (and support
# symbols, string, procs, and objects), so compile a conditional
# expression based on the options.
def
recompile_options!
def
conditions_lambdas
conditions
=
[]
unless
options
[
:if
].
empty?
...
...
@@ -308,43 +308,7 @@ def recompile_options!
lambdas
=
Array
(
options
[
:unless
]).
map
{
|
c
|
make_lambda
c
}
conditions
.
concat
lambdas
.
map
{
|
l
|
invert_lambda
l
}
end
method_name
=
"_callback_
#{
@kind
}
_
#{
next_id
}
"
@klass
.
send
(
:define_method
,
method_name
)
do
|*
args
,
&
block
|
conditions
.
all?
{
|
c
|
c
.
call
(
self
,
*
args
,
&
block
)
}
end
@compiled_options
=
method_name
end
# Filters support:
#
# Arrays:: Used in conditions. This is used to specify
# multiple conditions. Used internally to
# merge conditions from skip_* filters.
# Symbols:: A method to call.
# Strings:: Some content to evaluate.
# Procs:: A proc to call with the object.
# Objects:: An object with a <tt>before_foo</tt> method on it to call.
#
# All of these objects are compiled into methods and handled
# the same after this point:
#
# Arrays:: Merged together into a single filter.
# Symbols:: Already methods.
# Strings:: class_eval'ed into methods.
# Procs:: define_method'ed into methods.
# Objects::
# a method is created that calls the before_foo method
# on the object.
def
_compile_source
(
filter
)
l
=
make_lambda
filter
method_name
=
"_callback_
#{
@kind
}
_
#{
next_id
}
"
@klass
.
send
(
:define_method
,
method_name
)
do
|*
args
,
&
block
|
l
.
call
(
self
,
*
args
,
&
block
)
end
method_name
conditions
end
def
_normalize_legacy_filter
(
kind
,
filter
)
...
...
@@ -380,15 +344,19 @@ def initialize(name, config)
end
def
compile
method
=
[
"value = nil"
,
"halted = false"
]
callbacks
=
"value = !halted && (!block_given? || yield)"
callbacks
=
lambda
{
|
target
,
halted
,
value
,
&
block
|
value
=
!
halted
&&
(
!
block
||
block
.
call
)
[
target
,
halted
,
value
]
}
reverse_each
do
|
callback
|
callbacks
=
callback
.
apply
(
callbacks
)
end
method
<<
callbacks
method
<<
"value"
method
.
join
(
"
\n
"
)
lambda
{
|
target
,
&
block
|
value
=
nil
halted
=
false
callbacks
.
call
(
target
,
halted
,
value
,
&
block
)[
2
]
}
end
def
append
(
*
callbacks
)
...
...
@@ -426,10 +394,12 @@ def __define_callbacks(kind, object) #:nodoc:
name
=
__callback_runner_name
(
kind
)
unless
object
.
respond_to?
(
name
,
true
)
str
=
object
.
send
(
"_
#{
kind
}
_callbacks"
).
compile
class_eval
<<-
RUBY_EVAL
,
__FILE__
,
__LINE__
+
1
def
#{
name
}
()
#{
str
}
end
protected :
#{
name
}
RUBY_EVAL
class_eval
do
define_method
(
name
)
do
|&
block
|
str
.
call
self
,
&
block
end
protected
name
end
end
name
end
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录