赞 | 342 |
VIP | 10 |
好人卡 | 8 |
积分 | 262 |
经验 | 235776 |
最后登录 | 2024-9-23 |
在线时间 | 2387 小时 |
Lv5.捕梦者 (版主) 遠航の猫咪
- 梦石
- 3
- 星屑
- 23186
- 在线时间
- 2387 小时
- 注册时间
- 2005-10-15
- 帖子
- 1166
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 SailCat 于 2021-3-7 14:25 编辑
解决alias黑洞的办法就是不要用alias
解决了传参问题和参数不一样个数(可多可少)的问题
还有以下问题
1. 可选参数(ruby 1.81的可选参数运行时定义就是个天坑) 通过将原方法接口暴露变通解决
2. singleton方法(Module的def self.xxx) 已解决
基本算是可以涵盖大部分情况的解决方案了
调用方法如:
Module X/Class X
define_alias_method(原方法名, 重定义方式, [增补参数], 挂接方法名)
或者
define_alias_method(原方法名, 重定义方式, [增补参数]) {|参数接口| 块}
end
参数接口如果等于多于原方法参数个数,不需要增补参数
参数接口如果少于原方法参数个数,需要按顺序增补缺少的必要参数
新方法需要用到可选参数的情况下,只能另行定义并用前面的调用方法(ruby 1.81不能在块里面用可选参数)
重定义方式目前有以下9种:
:before 将新方法挂在原方法之前
:after 将新方法挂在原方法之后,并返回原方法的返回值
:alter 将新方法挂在原方法之后,并返回新方法的返回值
:around 将新方法包含在原方法周围,原方法会成为块中的第一个参数(Method对象),可以改变参数自主调用原方法
:inherit 将新方法包含在原方法周围,但可以在块中利用原方法的返回值做一些邪恶的事情
:if 如果原方法执行成功,则执行新方法
:unless 如果原方法执行不成功,则执行新方法
:and 如果新方法执行成功,则执行原方法
:or 如果新方法执行不成功,则执行原方法
module SailCat Object.send :include, self Module.send :include, self def singleton_class class << self; self; end end def define_alias_method(symbol, manner = :alter, *arg, &block) in_class = self.is_a?(Class) attr_sym = in_class ? :instance_method : :method def_sym = in_class ? :class_eval : :eval old = send(attr_sym, symbol) old_n = old.arity old_n = ~old_n if old_n < 0 if block_given? (in_class ? self : singleton_class).send :define_method, symbol, &block new = send(attr_sym, symbol) else new = send(attr_sym, arg[-1]) arg = arg[0..-2] end s_new = "new#{in_class ? '.bind(self)' : ''}.call(*args)" s_old = "old#{in_class ? '.bind(self)' : ''}.call(*old_args)" case manner when :before method_eval = "#{s_new}; #{s_old}" when :after method_eval = "v = #{s_old}; #{s_new}; v" when :alter method_eval = "#{s_old}; #{s_new}" when :around method_eval = s_new.sub(/\*args/) {s_old[0..-17] + ", *args"} when :inherit method_eval = s_new.sub(/\*args/) {s_old + ", *args"} when :if method_eval = "#{s_new} if v = #{s_old}; v" when :unless method_eval = "#{s_new} unless v = #{s_old}; v" when :and method_eval = "#{s_new} and #{s_old}" when :or method_eval = "#{s_new} or #{s_old}" end context = in_class ? "self" : "singleton_class" send def_sym, %(#{context}.send :define_method, symbol do |*args| old_args = args[0, old_n] + arg; #{method_eval} end) end end module A def self.b(a, b = 6) a + b end def self.b2 0 end define_alias_method(:b, :around) {|b, x| p x, b.call(x, 9); } define_alias_method(:b, :before, 4) { p 1 } define_alias_method(:b, :alter, :b2) define_alias_method(:b, :inherit) {|b, x| p b - x} end A.b(5) #=> 1/4, 13/-5
module SailCat
Object.send :include, self
Module.send :include, self
def singleton_class
class << self; self; end
end
def define_alias_method(symbol, manner = :alter, *arg, &block)
in_class = self.is_a?(Class)
attr_sym = in_class ? :instance_method : :method
def_sym = in_class ? :class_eval : :eval
old = send(attr_sym, symbol)
old_n = old.arity
old_n = ~old_n if old_n < 0
if block_given?
(in_class ? self : singleton_class).send :define_method, symbol, &block
new = send(attr_sym, symbol)
else
new = send(attr_sym, arg[-1])
arg = arg[0..-2]
end
s_new = "new#{in_class ? '.bind(self)' : ''}.call(*args)"
s_old = "old#{in_class ? '.bind(self)' : ''}.call(*old_args)"
case manner
when :before
method_eval = "#{s_new}; #{s_old}"
when :after
method_eval = "v = #{s_old}; #{s_new}; v"
when :alter
method_eval = "#{s_old}; #{s_new}"
when :around
method_eval = s_new.sub(/\*args/) {s_old[0..-17] + ", *args"}
when :inherit
method_eval = s_new.sub(/\*args/) {s_old + ", *args"}
when :if
method_eval = "#{s_new} if v = #{s_old}; v"
when :unless
method_eval = "#{s_new} unless v = #{s_old}; v"
when :and
method_eval = "#{s_new} and #{s_old}"
when :or
method_eval = "#{s_new} or #{s_old}"
end
context = in_class ? "self" : "singleton_class"
send def_sym, %(#{context}.send :define_method, symbol do |*args|
old_args = args[0, old_n] + arg; #{method_eval}
end)
end
end
module A
def self.b(a, b = 6)
a + b
end
def self.b2
0
end
define_alias_method(:b, :around) {|b, x| p x, b.call(x, 9); }
define_alias_method(:b, :before, 4) { p 1 }
define_alias_method(:b, :alter, :b2)
define_alias_method(:b, :inherit) {|b, x| p b - x}
end
A.b(5) #=> 1/4, 13/-5
ruby 1.81真的是各种戴脚镣,但凡有个define_singleton_method我也不至于这么麻烦:(
|
评分
-
查看全部评分
|