ruby 周围的怪异现象
Weirdness with around aspect in ruby
我是新手 ruby
正在尝试写一个环绕方面。我的代码如下
我的代码如下所示
module Utils
module Aspects
def self.included(base)
base.extend(self)
end
def around_aspect(method_name, before_proc, after_proc)
code = %Q[
def #{method_name} *args, &block
#{before_proc.call}
old_#{method_name} *args, &block
#{after_proc.call}
end
]
class_eval %Q[
alias_method :old_#{method_name}, :#{method_name}
]
class_eval code
end
# def before_aspect method_name, before_proc
# around_aspect method_name, before_proc, ->(){}
# end
#
# def after_aspect method_name, after_proc
# around_aspect method_name, ->(){}, after_proc
# end
end
end
class Test
include Utils::Aspects
def test
puts 'test'
end
before = ->(){puts 'before'}
after = ->(){puts 'after'}
around_aspect :test,before,after
end
Test.new.test
问题是当我这样做时 Test.new.test
我希望它打印出来
before, test and after" 按顺序排列。但现在它打印 "before,after and test"
The problem is that when i do Test.new.test
I expect it to print
before, test and after" in order. But right now it prints "before,after and test"
不,不是。当调用 Test.new.test
时,它只打印 test
。 before
和 after
在定义包装方法时打印,即在调用 around_advice
.
时
尝试在对 around_advice
的调用和对 Test.new.test
的调用之间放置一个 puts
(并尝试多次调用 test
)以观察这一点:
puts '______________________'
Test.new.test
Test.new.test
# before
# after
# ______________________
# test
# test
您只调用了一次 lambda,在定义方法时:
code = %Q[
def #{method_name} *args, &block
#{before_proc.call}
# ^^^^^^^^^^^^^^^^^^^
old_#{method_name} *args, &block
#{after_proc.call}
# ^^^^^^^^^^^^^^^^^^
end
]
每次调用方法时都需要调用它们:
code = %Q[
def #{method_name} *args, &block
before_proc.call
old_#{method_name} *args, &block
after_proc.call
end
]
但是,直接使用 Module#prepend
会容易得多,毕竟,这就是它的用途:
module Aspects
refine Module do
def around_aspect(method_name, before_proc, after_proc)
prepend(Module.new do
define_method(method_name) do |*args, &block|
before_proc.()
super(*args, &block)
after_proc.()
end
end)
end
end
end
class Test
using Aspects
def test
puts 'test'
end
before = -> {puts 'before'}
after = -> {puts 'after'}
around_aspect :test, before, after
end
只是把我的代码放在这里。这就是我最终实现我想要做的事情的方式,module.prepend 上面建议的是另一种方式
module Utils
module Aspects
def self.included(base)
base.extend(self)
end
def around_aspect(method_name, before_proc, after_proc)
new_method_name = Random.new_seed.to_s
alias_method :"#{new_method_name}", :"#{method_name}"
define_method "#{method_name}" do |*args, &block|
before_proc.call
send(:"#{new_method_name}", *args, &block)
after_proc.call
end
end
def before_aspect method_name, before_proc
around_aspect method_name, before_proc, ->(){}
end
def after_aspect method_name, after_proc
around_aspect method_name, ->(){}, after_proc
end
end
end
class Test
include Utils::Aspects
def test
puts 'test'
end
before = ->(){puts 'before'}
after = ->(){puts 'after'}
before_aspect :test, before
after_aspect :test, after
end
Test.new.test
我是新手 ruby
正在尝试写一个环绕方面。我的代码如下
我的代码如下所示
module Utils
module Aspects
def self.included(base)
base.extend(self)
end
def around_aspect(method_name, before_proc, after_proc)
code = %Q[
def #{method_name} *args, &block
#{before_proc.call}
old_#{method_name} *args, &block
#{after_proc.call}
end
]
class_eval %Q[
alias_method :old_#{method_name}, :#{method_name}
]
class_eval code
end
# def before_aspect method_name, before_proc
# around_aspect method_name, before_proc, ->(){}
# end
#
# def after_aspect method_name, after_proc
# around_aspect method_name, ->(){}, after_proc
# end
end
end
class Test
include Utils::Aspects
def test
puts 'test'
end
before = ->(){puts 'before'}
after = ->(){puts 'after'}
around_aspect :test,before,after
end
Test.new.test
问题是当我这样做时 Test.new.test
我希望它打印出来
before, test and after" 按顺序排列。但现在它打印 "before,after and test"
The problem is that when i do
Test.new.test
I expect it to print before, test and after" in order. But right now it prints "before,after and test"
不,不是。当调用 Test.new.test
时,它只打印 test
。 before
和 after
在定义包装方法时打印,即在调用 around_advice
.
尝试在对 around_advice
的调用和对 Test.new.test
的调用之间放置一个 puts
(并尝试多次调用 test
)以观察这一点:
puts '______________________'
Test.new.test
Test.new.test
# before
# after
# ______________________
# test
# test
您只调用了一次 lambda,在定义方法时:
code = %Q[
def #{method_name} *args, &block
#{before_proc.call}
# ^^^^^^^^^^^^^^^^^^^
old_#{method_name} *args, &block
#{after_proc.call}
# ^^^^^^^^^^^^^^^^^^
end
]
每次调用方法时都需要调用它们:
code = %Q[
def #{method_name} *args, &block
before_proc.call
old_#{method_name} *args, &block
after_proc.call
end
]
但是,直接使用 Module#prepend
会容易得多,毕竟,这就是它的用途:
module Aspects
refine Module do
def around_aspect(method_name, before_proc, after_proc)
prepend(Module.new do
define_method(method_name) do |*args, &block|
before_proc.()
super(*args, &block)
after_proc.()
end
end)
end
end
end
class Test
using Aspects
def test
puts 'test'
end
before = -> {puts 'before'}
after = -> {puts 'after'}
around_aspect :test, before, after
end
只是把我的代码放在这里。这就是我最终实现我想要做的事情的方式,module.prepend 上面建议的是另一种方式
module Utils
module Aspects
def self.included(base)
base.extend(self)
end
def around_aspect(method_name, before_proc, after_proc)
new_method_name = Random.new_seed.to_s
alias_method :"#{new_method_name}", :"#{method_name}"
define_method "#{method_name}" do |*args, &block|
before_proc.call
send(:"#{new_method_name}", *args, &block)
after_proc.call
end
end
def before_aspect method_name, before_proc
around_aspect method_name, before_proc, ->(){}
end
def after_aspect method_name, after_proc
around_aspect method_name, ->(){}, after_proc
end
end
end
class Test
include Utils::Aspects
def test
puts 'test'
end
before = ->(){puts 'before'}
after = ->(){puts 'after'}
before_aspect :test, before
after_aspect :test, after
end
Test.new.test