设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 2386|回复: 7
打印 上一主题 下一主题

[讨论] 尝试了一下彻底解决alias黑洞

[复制链接]

Lv5.捕梦者 (版主)

遠航の猫咪

梦石
3
星屑
23129
在线时间
2387 小时
注册时间
2005-10-15
帖子
1166

开拓者

跳转到指定楼层
1
发表于 2021-3-7 00:24:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

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 如果新方法执行不成功,则执行原方法

RUBY 代码复制
  1. module SailCat
  2.   Object.send :include, self
  3.   Module.send :include, self
  4.   def singleton_class
  5.     class << self; self; end
  6.   end
  7.  
  8.   def define_alias_method(symbol, manner = :alter, *arg, &block)
  9.     in_class = self.is_a?(Class)
  10.     attr_sym = in_class ? :instance_method : :method
  11.     def_sym = in_class ? :class_eval : :eval
  12.     old = send(attr_sym, symbol)
  13.     old_n = old.arity
  14.     old_n = ~old_n if old_n < 0
  15.     if block_given?
  16.       (in_class ? self : singleton_class).send :define_method, symbol, &block
  17.       new = send(attr_sym, symbol)
  18.     else
  19.       new = send(attr_sym, arg[-1])
  20.       arg = arg[0..-2]
  21.     end
  22.     s_new = "new#{in_class ? '.bind(self)' : ''}.call(*args)"
  23.     s_old = "old#{in_class ? '.bind(self)' : ''}.call(*old_args)"
  24.     case manner
  25.     when :before
  26.       method_eval = "#{s_new}; #{s_old}"
  27.     when :after
  28.       method_eval = "v = #{s_old}; #{s_new}; v"
  29.     when :alter
  30.       method_eval = "#{s_old}; #{s_new}"
  31.     when :around
  32.       method_eval = s_new.sub(/\*args/) {s_old[0..-17] + ", *args"}
  33.     when :inherit
  34.       method_eval = s_new.sub(/\*args/) {s_old + ", *args"}
  35.     when :if
  36.       method_eval = "#{s_new} if v = #{s_old}; v"
  37.     when :unless
  38.       method_eval = "#{s_new} unless v = #{s_old}; v"
  39.     when :and
  40.       method_eval = "#{s_new} and #{s_old}"
  41.     when :or
  42.       method_eval = "#{s_new} or #{s_old}"
  43.     end
  44.     context = in_class ? "self" : "singleton_class"
  45.     send def_sym, %(#{context}.send :define_method, symbol do |*args|
  46.       old_args = args[0, old_n] + arg; #{method_eval}
  47.     end)
  48.   end
  49. end
  50.  
  51. module A
  52.   def self.b(a, b = 6)
  53.     a + b
  54.   end
  55.   def self.b2
  56.     0
  57.   end
  58.   define_alias_method(:b, :around) {|b, x| p x, b.call(x, 9);  }
  59.   define_alias_method(:b, :before, 4) { p 1 }
  60.   define_alias_method(:b, :alter, :b2)
  61.   define_alias_method(:b, :inherit) {|b, x| p b - x}
  62. end
  63.  
  64. A.b(5)     #=> 1/4, 13/-5


ruby 1.81真的是各种戴脚镣,但凡有个define_singleton_method我也不至于这么麻烦:(

评分

参与人数 1+1 收起 理由
KB.Driver + 1 精品文章

查看全部评分

SailCat (小猫子·要开心一点) 共上站 24 次,发表过 11 篇文章 上 次 在: [2006年01月28日11:41:18 星期六] 从 [162.105.120.91] 到本站一游。

Lv4.逐梦者

梦石
1
星屑
9792
在线时间
4415 小时
注册时间
2005-10-22
帖子
6901

开拓者贵宾

2
发表于 2021-3-7 01:36:10 | 只看该作者
开个全局变量把那些alias后的方法名丢里面
再做一堆 ||= 怎么样呢?

实在不行强行升到1.9吧

点评

那1.9会变成什么  发表于 2021-3-16 14:16
对哒~这就是P社风格的解决方案 (✺ω✺)  发表于 2021-3-7 19:50
为了解决一个bug,引发十个新bug……  发表于 2021-3-7 19:46
重定义字符串(✺ω✺)  发表于 2021-3-7 18:01
1.9会有其他问题……最典型的就是字符串不是字节数组了  发表于 2021-3-7 04:47
回复 支持 反对

使用道具 举报

Lv2.观梦者

梦石
0
星屑
777
在线时间
70 小时
注册时间
2017-12-2
帖子
14
3
发表于 2021-3-15 14:34:20 | 只看该作者
我过年时重搞的 1.9 方案 https://rpg.blue/forum.php?mod=viewthread&tid=484700 ,只写了after和around,其它那些都可以用类似手法简单实现。没拼字符串,走的instance_exec,手里没有1.8的环境,不过看1.8.7的文档是有instance_exec的,可以参考下。
java.lang.NullPointerException
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-9-28 05:27

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表