`
CharlesCui
  • 浏览: 432878 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Ruby如何打开一个函数?

阅读更多
Ruby可以打开一个对象,但能够打开一个函数么?

Ruby打开一个对象的meta class并向其中重写方法,比如:

这是定义TT2这个类
class TT2
  class << self
    def pa
      out
    end    
    def out(a)
      p a
    end
    private :out
  end
end


下面向TT2这个类对象添加一个新的out方法
class << TT2
  alias_method :_out,:out
  def out(a)
    p "new out"
    _out(a)
  end
end


问题来了:
以上操作都是在类层面方法外面做的hack,如果我想把这句代码p "new out" 直接放到原来的out方法体内,比如我打算放到out方法的最后一行该怎么办?

需求是这样的:
有一个第三方的库,里面有个私有方法并不符合我的需求,我想hack一下得到这个方法体中的一个对象,这个对象只存在与这个函数空间内,所以我只能hack这个方法。
但是:1、我不想更改这个库的源代码,为了保持通用性。2、它这个方法太长了,我不想整段copy从而再写个一样的方法然后类似这样alias_method :_out,:out的,把原来方法覆盖掉。


ruby中大多数东西都是对象都是类,只是ruby不像javascript,js中函数也是一个对象,ruby中函数不是对象,如果ruby中函数也是对象的话,我想我是否也可以用class << Function;#code;end这样的操作打开我想操作的函数了?

分享到:
评论
15 楼 jack 2008-11-13  
CharlesCui 写道


把方法变成了对象然后打开,然后添加想注入的代码。挺好!

不过问题如下:

class A      
 class << self     
   def old         
       puts rand
       abc='a girl'
       return 'a boy'
   end           
  end  
end          
  
  
old=A.method(:old)   
class << old     
  attr_accessor :name  
  return abc#这里希望old方法返回'a girl'
end     
  
old.call


这段代码运行的时候报错了,说找不到abc这个变量!
你这个方法能对abc这个变量操作么?让它返回。


你这个abc要能够正确调用的话,这个想法的最接近的解决方案 在这里
http://www.iteye.com/topic/263174
14 楼 liusong1111 2008-11-13  
CharlesCui 写道

liusong1111 写道
倒也是. 不过@name在哪里都能取到啊. 如果想取局部变量,直接改源码或者整个重写方法比较好,因为局部变量体现的是内部实现.
将来原始版本升级后,新的"补丁"方法一样要完蛋.

跟补丁没任何关系,也不会完蛋,上面写的都放到了一个module里面,引入这个module就会自动hack目标方法,不引入这个module就相当于使用库自己,没任何影响。



请注意加粗的地方.

一个方法的外在功能体现在它的签名上.
如果hack它时,依赖于原始代码的某个局部变量(abc),就相当于依赖了不稳定的具体实现而非公开的抽象.
有违设计原则.

随着工程的实施,当它原始代码发生改变时(比如去掉了这个局部变量),你的hack方法同时失效了.

如果它原始代码不正确,就大胆的整体改写它. 你上面的手段,相当于把这种不合理性从原始位置扩散到了两个地方(并依赖这种不合理性).
ruby即使灵活到能做这个,它也属于尽管避免的反模式.

假如原始代码不存在将来被改动的可能,而且现在你没有权力修改它,就在新module里整个改写它吧.
如果要修正rails框架的bug,最好提交patch到它官方.

如果在原始方法里,要提供灵活的可定制性,考虑一下将它改成可接受block(里面yield).

ruby的everything is object还没有达到极致完美,比如inspection,modification. 但你上面的需求不能证明这一点.

13 楼 CharlesCui 2008-11-13  
axgle 写道
class A   
 class << self  
   def old      
       puts rand      
   end        
  end
end       


old=A.method(:old)
class << old  
  attr_accessor :name
end  

old.name = '对象^_^'
puts old.name
old.call
 


还有个问题,你这个old=A.method(:old)对象是对A的method方法的一个copy,并没有从根本上改变A的old方法,能否直接更改A的old方法,使得以后A.old的调用都是一样的。
12 楼 CharlesCui 2008-11-13  
axgle 写道
class A   
 class << self  
   def old      
       puts rand      
   end        
  end
end       


old=A.method(:old)
class << old  
  attr_accessor :name
end  

old.name = '对象^_^'
puts old.name
old.call
 

嘿哥们,你这个例子很有意思!

把方法变成了对象然后打开,然后添加想注入的代码。挺好!

不过问题如下:

class A      
 class << self     
   def old         
       puts rand
       abc='a girl'
       return 'a boy'
   end           
  end  
end          
  
  
old=A.method(:old)   
class << old     
  attr_accessor :name  
  return abc#这里希望old方法返回'a girl'
end     
  
old.call


这段代码运行的时候报错了,说找不到abc这个变量!
你这个方法能对abc这个变量操作么?让它返回。
11 楼 axgle 2008-11-13  
class A   
 class << self  
   def old      
       puts rand      
   end        
  end
end       


old=A.method(:old)
class << old  
  attr_accessor :name
end  

old.name = '对象^_^'
puts old.name
old.call
 
10 楼 CharlesCui 2008-11-13  
liusong1111 写道
倒也是. 不过@name在哪里都能取到啊. 如果想取局部变量,直接改源码或者整个重写方法比较好,因为局部变量体现的是内部实现.
将来原始版本升级后,新的"补丁"方法一样要完蛋.

跟补丁没任何关系,也不会完蛋,上面写的都放到了一个module里面,引入这个module就会自动hack目标方法,不引入这个module就相当于使用库自己,没任何影响。

axgle 写道
CharlesCui 写道
Ruby可以打开一个对象,但能够打开一个函数么?
ruby中大多数东西都是对象都是类,只是ruby不像javascript,js中函数也是一个对象,ruby中函数不是对象,如果ruby中函数也是对象的话,我想我是否也可以用class << Function;#code;end这样的操作打开我想操作的函数了?

你举一个javascript的例子,来演示一下你的需求?


js没有打开对象的方法吧?
我提到js是因为js的函数也可以当对象来用,ruby的函数却不是对象!
9 楼 axgle 2008-11-13  
CharlesCui 写道
Ruby可以打开一个对象,但能够打开一个函数么?
ruby中大多数东西都是对象都是类,只是ruby不像javascript,js中函数也是一个对象,ruby中函数不是对象,如果ruby中函数也是对象的话,我想我是否也可以用class << Function;#code;end这样的操作打开我想操作的函数了?

你举一个javascript的例子,来演示一下你的需求?
8 楼 liusong1111 2008-11-13  
倒也是. 不过@name在哪里都能取到啊. 如果想取局部变量,直接改源码或者整个重写方法比较好,因为局部变量体现的是内部实现.
将来原始版本升级后,新的"补丁"方法一样要完蛋.
7 楼 jack 2008-11-13  
这个是注入阿,这个是重新包装了下. 你根本没有改动old函数的任何逻辑阿....


6 楼 liusong1111 2008-11-13  
就是典型alias_method_chain的使用场景啊

require 'rubygems'
require 'activesupport'

class T
  def test
    puts 'my code here'
  end
end

puts '--- original output ---'
T.new.test

class T
  def test_with_verbose
    test_without_verbose
    puts 'additional code here'
  end
  
  alias_method_chain :test, :verbose
end

puts '--- post version output ---'
T.new.test


输出:
引用
--- original output ---
my code here
--- post version output ---
my code here
additional code here

5 楼 CharlesCui 2008-11-13  
axgle 写道
CharlesCui 写道
jack,不是你说的那样。

我需要的不是aliase_method :new,:old

我是要把一行代码注射到old方法中去,默认注入到最后一行就可以。

class A
 def old
   puts rand
 end  
end 
############
class A
  alias _old old
  def old
    _old
    puts 'new line'
  end  
end  
###########
A.new.old

把一行代码注射到old方法中去,默认注入到最后一行就可以。不就这样的效果么?



如果我的old方法和你的不一样呢?

比如:
class A   
 def old   
   @name="Lucy"
   puts rand   
 end     
end    
############   
class A   
  alias _old old   
  def old   
    _old   
    puts 'new line' #你不打开_old的话,你在这个位置无论写什么都无法得到@name 
  end     
end     
###########   
A.new.old 


我想给_old方法做如下的操作:
class << _old
  attr :name
end

可惜_old是个方法而不是对象。
求能打开方法的办法。
4 楼 axgle 2008-11-13  
CharlesCui 写道
jack,不是你说的那样。

我需要的不是aliase_method :new,:old

我是要把一行代码注射到old方法中去,默认注入到最后一行就可以。

class A
 def old
   puts rand
 end  
end 
############
class A
  alias _old old
  def old
    _old
    puts 'new line'
  end  
end  
###########
A.new.old

把一行代码注射到old方法中去,默认注入到最后一行就可以。不就这样的效果么?
3 楼 jack 2008-11-13  
这样好像没有什么办法. 函数可以添加,删除,可以重新定义,但是修改内容,不行的.
2 楼 CharlesCui 2008-11-13  
jack,不是你说的那样。

我需要的不是aliase_method :new,:old

我是要把一行代码注射到old方法中去,默认注入到最后一行就可以。
1 楼 jack 2008-11-13  
好像有个alias_method_chain 插件,可以以aop的方式来处理函数,这个版有人发过类似的文章吧,具体不记得了,找找看吧

相关推荐

    Ruby-PyCall从Ruby语言调用Python函数

    Ruby-PyCall是一个非常有用的库,它允许Ruby程序员无缝地调用Python的函数和模块,极大地扩展了Ruby的生态系统。这个库使得两个语言之间的交互变得简单而高效,特别是在需要利用Python的强大科学计算或数据处理能力...

    ruby实用函数和实例

    Minitest则是一个轻量级的测试库,内置于Ruby标准库中,它提供了测试套件、断言和模拟等功能。在进行数据采集时,Ruby的HTTP库如Net::HTTP可以用来从网页抓取数据,Nokogiri用于解析HTML和XML文档,而JSON库则帮助...

    透视Ruby 1.9的Lambda函数

    下面的代码示例展示了在Ruby 1.9中如何正确地在一个Block中调用另一个Block: ```ruby class SandBox def abc(*args) yield(*args) end define_method :xyz do |*args, &block| block.call(*args) end end ...

    Ruby基础语法+Ruby变量与数据类型+Ruby控制结构+Ruby函数与方法+Ruby面向对象编程等全套教程

    Ruby函数与方法 Ruby面向对象编程 Ruby模块与包 Ruby错误处理 Ruby文件与I/O操作 Ruby正则表达式 Ruby网络编程 Ruby数据库交互 Ruby测试框架 RubyWeb框架Rails入门 Ruby高级特性 Ruby性能优化与最佳实践

    [转] ruby学习一个综合小练习

    标题中的“ruby学习一个综合小练习”表明这是一个关于Ruby编程语言的学习资源,可能是通过一个实际的小项目或练习来帮助学习者提升对Ruby的理解。描述中提到的“博文链接”指向了一个特定的博客文章,虽然没有给出...

    函数式-确定性-Ruby取笑___下载.zip

    4. **映射(Map)**:在Ruby中,Array类提供了`map`方法,可以对数组的每个元素应用一个函数,然后返回一个新的数组,包含了应用函数后的结果。这是函数式编程中常见的操作。 5. **过滤(Filter)**:`select`或`...

    Ruby-一个Racket库可让您通过MarionetteProtocol控制Firefox

    【标题】:“Ruby-一个Racket库可让您通过MarionetteProtocol控制Firefox” 【描述】:“一个Racket库,可让您通过Marionette Protocol控制Firefox”这个描述涉及到两个主要技术领域:Ruby和Marionette Protocol。...

    Ruby-Functo是ruby中的可组合方法对象

    总之,Ruby-Functo是Ruby开发中的一个重要工具,尤其对于那些喜欢函数式编程风格的开发者来说,它提供了一套强大的工具集,用于构建可组合、可重用的方法对象,提升了代码的可读性和维护性。通过熟练掌握Functo,...

    从Ruby语言调用Python函数-Ruby开发

    PyCall:从Ruby语言中调用Python函数该库提供了直接从Ruby语言中调用Python并与之进行部分互操作的功能。 您可以在PyCall中导入任意Python模块:从Ruby语言调用Python函数该库提供了直接从Ruby语言调用Python并与之...

    ruby的二进制字符串与hex互转,二进制字符串与整数互转的工具函数

    本资源是ruby代码,提供了一系列封装好的函数,用于快速进行转换,一个函数搞定,包括如下转换,二进制字符串与hex字符串的互转。二进制字符串与整数互转,包括uint8,uin16,uint32, 以及本地字节序和网络字节序两种...

    Ruby-LazyHighCharts一个简单和非常灵活的方式从ruby代码使用HighCharts

    Ruby-LazyHighCharts是一个针对Ruby编程语言设计的库,它提供了一种简单且高度灵活的方法来利用HighCharts库进行数据可视化。HighCharts是一个广泛使用的JavaScript图表库,用于在Web应用中创建高质量的交互式图表。...

    Ruby-LightIO是一个ruby网络库它结合了rubyfiber和快速IOeventloop

    Ruby-LightIO是一个针对Ruby开发者的网络库,其核心特性在于将Ruby的Fiber和高效的IO事件循环(event loop)相结合。这个库的设计目标是为了提供更高效、更轻量级的网络服务处理能力,尤其适合于构建高并发、低延迟...

    Ruby-Savon是一个Ruby编程语言的SOAP客户端

    Ruby-Savon是Ruby编程语言中的一个强大的SOAP(Simple Object Access Protocol)客户端库,它使得在Ruby中与SOAP服务交互变得简单而高效。SOAP是一种基于XML的协议,用于在不同系统之间交换结构化和类型化的数据,常...

    Ruby工具 windows 环境

    在Windows上安装Ruby,你需要下载一个合适的Ruby安装包。在这个例子中,我们有“rubyinstaller-1.9.1-p430.exe”文件,这是一个针对Windows的Ruby安装程序。安装过程非常直观,只需双击该exe文件,按照向导指示进行...

    Ruby-RubyJMeter一个基于Ruby的DSL用于构建JMeter测试计划

    Ruby-JMeter是一个强大的工具,它将Ruby编程语言与Apache JMeter测试框架相结合,为性能测试和负载测试提供了灵活且易于使用的领域特定语言(DSL)。这个工具使得测试人员和开发者能够用Ruby编写JMeter测试计划,...

    python和ruby,我选谁?

    - **国际化支持**:目前Ruby在国际化方面的支持较弱,这是Ruby相对于Python的一个明显短板。 #### 二、语言选择建议 - **简单至上**:如果你更倾向于简单易用的语言,那么Python可能是更好的选择。Python的简洁性...

    Ruby-TensorStream用Ruby重新实现TensorFlow

    Ruby-TensorStream是一个开源项目,旨在为Ruby开发者提供一个类似于Google TensorFlow的深度学习框架。它的核心目标是让Ruby程序员能够利用TensorFlow的强大功能,同时保持Ruby语言的优雅和简洁。这个项目在设计时...

    Programming Ruby.pdf

    Ruby拥有一个活跃且热情的全球开发者社区,这个社区为Ruby的发展贡献了无数的开源项目、库和框架。通过参与社区活动、交流经验和问题,开发者可以更快地成长,并为自己的项目找到解决方案。此外,《Programming Ruby...

    javascript 好用及常用函数(ruby)

    这个函数允许我们遍历数组的每个元素,并执行一个回调函数。例如: ```javascript let array = [1, 2, 3]; array.forEach((value, index) =&gt; { console.log(`Value at index ${index} is ${value}`); }); ```...

    Ruby分解质因数

    在Ruby中,我们可以编写一个函数来实现这个功能。以下是一个简单的示例: ```ruby def prime_factors(n) factors = [] divisor = 2 while n &gt; 1 if n % divisor == 0 factors n /= divisor else divisor ...

Global site tag (gtag.js) - Google Analytics