- 浏览: 1386554 次
- 性别:
- 来自: 火星
文章分类
最新评论
-
aidd:
内核处理time_wait状态详解 -
ahtest:
赞一下~~
一个简单的ruby Metaprogram的例子 -
itiProCareer:
简直胡说八道,误人子弟啊。。。。谁告诉你 Ruby 1.9 ...
ruby中的类变量与类实例变量 -
dear531:
还得补充一句,惊群了之后,数据打印显示,只有一个子线程继续接受 ...
linux已经不存在惊群现象 -
dear531:
我用select试验了,用的ubuntu12.10,内核3.5 ...
linux已经不存在惊群现象
1 得到所定义的实体的列表
ruby的反射api能够使我们在运行时检测类和对象。因此我们下面将会介绍Module, Class, 和Object中的定义的一些方法。
Module模块有一个constants 的方法,它将会返回系统中所有的常量名,包括类名和模块名。nesting 方法则是返回当前调用点上的嵌套的模块的列表.
Module#ancestors 返回指定的类或者模块的所有包含的类或者模块.
class_variables 方法返回给定的类和他的超类的所有类变量的一个表。included_modules 方法列出包含在这个类中的所有模块。
Class的方法instance_methods和public_instance_methods 是同义的。他们返回这个类的所有公有的方法。private_instance_methods和 protected_instance_methods 也就是返回私有和保护的实例方法。这几个方法都还带有一个参数,默认是true的。如果被设置为false,超类将不会被搜索。
Object 类有很多操作实例的类似的方法。methods 方法将会返回这个对象的所有可以被调用的方法。调用 public_methods 方法,将会返回所有公有的方法。他也有一个参数来判断是否去父类搜索。private_methods, protected_methods,和singleton_methods 也都有类似的参数。
2 测试调用栈
有时我们想要知道我们的调用者是谁,这个有时是非常有用的。看下面的例子:
3 监控程序的执行
一个ruby程序能够内省,或者说是检测他自己的执行。很多程序都用到了这个功能,有兴趣的话可以看看这几个ruby的源码:debug.rb, profile.rb, 和 tracer.rb。
我们能够使用 set_trace_func方法,他接受一个block作为参数。无论在程序的执行中发生任何事情时,这个block都会被调用,我们看下面的例子:
可以看到输出类似这样的:
还有一个方法是Kernel#trace_var,它是当全局变量被赋值时,才会被自动调用。
假设你想要在程序的外面得到程序的运行轨迹。最简单的方法就是使用tracer 库,假设有个prog.rb的文件:
然后我们在命令行load TRacer :
当源代码执行时每一个事件类型都包含"'-'",'>'表示一个调用,'<' 表示一个返回,'C'代表一个类,'E' 代表结束。
4 Traversing the Object Space
ruby的运行系统需要保存所有已知对象的踪迹(只是为了能够垃圾回收那些没有长时间使用的引用,也就是gc)。这个信息是通过 ObjectSpace.each_object 来得到的。
如果你指定一个类名或者模块名给each_object,它就只会返回这种类型的对象.
5 使用method_missing
起始和前面的const_missing差不多,也就是说当你在这个对象上调用一个不存在的方法时,它就会默认调用method_missing 方法:
在Object中定义的method_missing方法是默认抛出一个异常的.
6 跟踪类或者对象的改变
我们现在想要写一个模块,它能够被任何类所包含,然后在这个类中的每调用一个方法,都会打印出相应的信息,比如我们所期待的是这样的:
对于子类我们也是能够跟踪的:
下面来看它的实现:
这个代码其实很简单.首先它有两个主方法,第一个是included,它是一个回调方法,当这个模块被插入到一个类中时,就会调用这个方法。在我们上面的例子中,他做了两件事,一件是为include这个模块的类的每一个方法调用hook_method方法,第二件事是,为这个类重新定义了method_added 方法。这就意味着,这个类如果加方法的话,就会调用这个方法,也就是说会被检测到。
而hook_method的实现也是很漂亮,使用了define_method来动态的定义方法,打印出信息后,再使用send来调用老的方法。
这里还要注意一个alias_method ,它和alias很类似,只不过它只能用在方法。并且他自己就是一个方法:
检测一个新的类方法被加到一个类或者模块,我们能够定义一个类方法singleton_method_added :
输出将会是这样子:
inherited 方法使用也很类似,当一个类被子类化,就会调用这个方法:
我们也能够跟踪加一个模块的实例方法到一个对象。extend_object 方法就是做这个的:
这里要注意super是必须的,和append_features 重的原因一样。
7 为对象定义一个Finalizers
ruby类有构造器,可是没有析构器。原因很简单,就是因为ruby使用了mark-and-sweep garbage collection 来删除没有引用的对象。
虽然在ruby中不能真正的做到调用析构器来删除对象。这里有个方法define_finalizer,它是当一个对象被gc时,就会调用它:
输出的结果类似这样的:
当finalizer 被调用的同时对象就被销毁了。如果此时你调用ObjectSpace._id2ref,然后参数为刚才那个对象的id,则会报一个RangeError:
由于ruby使用的是mark-and-sweep GC 的策略,那么他就不能保证当程序结束之前,对象什么时候被GC。
可是所有的一切都是不确定的。在ruby中,经常使用block来压缩一个源(也就是一段代码)的使用,在block的结尾,这个源将会被删除(也就是说。然后其他的对象没有任何改变(其实这个也就是说讲代码封装在block里面比较好,因为当block退出时,它的那些局部变量,或者说,传进来的哪些参数都会被GC掉,因此在ruby1.9里面,block里面的局部变量和外面的变量已经不是同一个变量了(假设名字相同)。)。看下面的代码:
在这里当block退出时,file 被删除,这一切都是在open方法里控制。如果你想要实现一个open方法的子集,你可以这么做:
这边使用begin ensure是因为要做到就算异常被抛出,文件也要被关闭.
ruby的反射api能够使我们在运行时检测类和对象。因此我们下面将会介绍Module, Class, 和Object中的定义的一些方法。
Module模块有一个constants 的方法,它将会返回系统中所有的常量名,包括类名和模块名。nesting 方法则是返回当前调用点上的嵌套的模块的列表.
list = Math.constants # ["E", "PI"]
Module#ancestors 返回指定的类或者模块的所有包含的类或者模块.
list = Array.ancestors # [Array, Enumerable, Object, Kernel]
class_variables 方法返回给定的类和他的超类的所有类变量的一个表。included_modules 方法列出包含在这个类中的所有模块。
class Parent @@var1 = nil end class Child < Parent @@var2 = nil end list1 = Parent.class_variables # ["@@var1"] list2 = Array.included_modules # [Enumerable, Kernel]
Class的方法instance_methods和public_instance_methods 是同义的。他们返回这个类的所有公有的方法。private_instance_methods和 protected_instance_methods 也就是返回私有和保护的实例方法。这几个方法都还带有一个参数,默认是true的。如果被设置为false,超类将不会被搜索。
n1 = Array.instance_methods.size # 121 n2 = Array.public_instance_methods.size # 121 n3 = Array.private_instance_methods.size # 71 n4 = Array.protected_instance_methods.size # 0 n5 = Array.public_instance_methods(falsee).size # 71
Object 类有很多操作实例的类似的方法。methods 方法将会返回这个对象的所有可以被调用的方法。调用 public_methods 方法,将会返回所有公有的方法。他也有一个参数来判断是否去父类搜索。private_methods, protected_methods,和singleton_methods 也都有类似的参数。
class SomeClass def initialize @a = 1 @b = 2 end def mymeth #... end protected :mymeth end x = SomeClass.new def x.newmeth # ... end iv = x.instance_variables # ["@b", "@a"] p x.methods.size # 42 p x.public_methods.size # 41 p x.public_methods(false).size # 1 p x.private_methods.size # 71 p x.private_methods(false).size # 1 p x.protected_methods.size # 1 p x.singleton_methods.size # 1
2 测试调用栈
有时我们想要知道我们的调用者是谁,这个有时是非常有用的。看下面的例子:
def func1 puts caller[0] end def func2 func1 end func2 # 打印出fucn1在那里被调用
3 监控程序的执行
一个ruby程序能够内省,或者说是检测他自己的执行。很多程序都用到了这个功能,有兴趣的话可以看看这几个ruby的源码:debug.rb, profile.rb, 和 tracer.rb。
我们能够使用 set_trace_func方法,他接受一个block作为参数。无论在程序的执行中发生任何事情时,这个block都会被调用,我们看下面的例子:
def meth(n) sum = 0 for i in 1..n sum += i end sum end set_trace_func(proc do |event, file, line, id, binding, klass, *rest| printf "%8s %s:%d %s/%s\n", event, file, line, klass, id end) meth(2)
可以看到输出类似这样的:
引用
line D:/develop/rubyWorkspace/RubyWay/lib/DynamicFeaturesTest.rb:171 false/
call D:/develop/rubyWorkspace/RubyWay/lib/DynamicFeaturesTest.rb:157 Object/meth
............................
call D:/develop/rubyWorkspace/RubyWay/lib/DynamicFeaturesTest.rb:157 Object/meth
............................
还有一个方法是Kernel#trace_var,它是当全局变量被赋值时,才会被自动调用。
假设你想要在程序的外面得到程序的运行轨迹。最简单的方法就是使用tracer 库,假设有个prog.rb的文件:
def meth(n) (1..n).each {|i| puts i} end meth(3)
然后我们在命令行load TRacer :
引用
% ruby -r tracer prog.rb
#0:prog.rb:1::-: def meth(n)
#0:prog.rb:1:Module:>: def meth(n)
。。。。。。。。。。。。。。。
#0:prog.rb:1::-: def meth(n)
#0:prog.rb:1:Module:>: def meth(n)
。。。。。。。。。。。。。。。
当源代码执行时每一个事件类型都包含"'-'",'>'表示一个调用,'<' 表示一个返回,'C'代表一个类,'E' 代表结束。
4 Traversing the Object Space
ruby的运行系统需要保存所有已知对象的踪迹(只是为了能够垃圾回收那些没有长时间使用的引用,也就是gc)。这个信息是通过 ObjectSpace.each_object 来得到的。
ObjectSpace.each_object do |obj| printf "%20s: %s\n", obj.class, obj.inspect end
如果你指定一个类名或者模块名给each_object,它就只会返回这种类型的对象.
5 使用method_missing
起始和前面的const_missing差不多,也就是说当你在这个对象上调用一个不存在的方法时,它就会默认调用method_missing 方法:
class CommandWrapper def method_missing(method, *args) system(method.to_s, *args) end end cw = CommandWrapper.new cw.date # Sat Apr 28 22:50:11 CDT 2001 cw.du '-s', '/tmp' # 166749 /tmp
在Object中定义的method_missing方法是默认抛出一个异常的.
6 跟踪类或者对象的改变
我们现在想要写一个模块,它能够被任何类所包含,然后在这个类中的每调用一个方法,都会打印出相应的信息,比如我们所期待的是这样的:
class MyClass include Tracing def one end def two(x, y) end end m = MyClass.new m.one # one called. Params = m.two(1, 'cat') # two called. Params = 1, cat
对于子类我们也是能够跟踪的:
class Fred < MyClass def meth(*a) end end Fred.new.meth(2,3,4,5) # meth called. Params = 2, 3, 4, 5
下面来看它的实现:
module Tracing def Tracing.included(into) into.instance_methods(false).each { |m| Tracing.hook_method(into, m) } def into.method_added(meth) unless @adding @adding = true Tracing.hook_method(self, meth) @adding = false end end end def Tracing.hook_method(klass, meth) klass.class_eval do alias_method "old_#{meth}", "#{meth}" define_method(meth) do |*args| puts "#{meth} called. Params = #{args.join(', ')}" self.send("old_#{meth}",*args) end end end end class MyClass include Tracing def first_meth end def second_meth(x, y) end end m = MyClass.new p m.first_meth # one called. Params = p m.second_meth(1, 'cat') # two called. Params = 1, cat
这个代码其实很简单.首先它有两个主方法,第一个是included,它是一个回调方法,当这个模块被插入到一个类中时,就会调用这个方法。在我们上面的例子中,他做了两件事,一件是为include这个模块的类的每一个方法调用hook_method方法,第二件事是,为这个类重新定义了method_added 方法。这就意味着,这个类如果加方法的话,就会调用这个方法,也就是说会被检测到。
而hook_method的实现也是很漂亮,使用了define_method来动态的定义方法,打印出信息后,再使用send来调用老的方法。
这里还要注意一个alias_method ,它和alias很类似,只不过它只能用在方法。并且他自己就是一个方法:
# Two other ways to write that line... # Symbols with interpolation: alias_method :"old_#{meth}", :"#{meth}" # Strings converted via to_sym: alias_method "old_#{meth}".to_sym, meth.to_sym
检测一个新的类方法被加到一个类或者模块,我们能够定义一个类方法singleton_method_added :
class MyClass def MyClass.singleton_method_added(sym) puts "Added method #{sym.to_s} to class MyClass." end def MyClass.meth1 puts "I'm meth1." end end def MyClass.meth2 puts "And I'm meth2." end
输出将会是这样子:
引用
Added method singleton_method_added to class MyClass.
Added method meth1 to class MyClass.
Added method meth2 to class MyClass.
Added method meth1 to class MyClass.
Added method meth2 to class MyClass.
inherited 方法使用也很类似,当一个类被子类化,就会调用这个方法:
class MyClass def MyClass.inherited(subclass) puts "#{subclass} inherits from MyClass." end # ... end class OtherClass < MyClass # ... end # Output: OtherClass inherits from MyClass.
我们也能够跟踪加一个模块的实例方法到一个对象。extend_object 方法就是做这个的:
module MyMod def MyMod.extend_object(obj) puts "Extending object id #{obj.object_id}, class #{obj.class}" super end # ... end x = [1, 2, 3] x.extend(MyMod) # Output: # Extending object id 36491192, type Array
这里要注意super是必须的,和append_features 重的原因一样。
7 为对象定义一个Finalizers
ruby类有构造器,可是没有析构器。原因很简单,就是因为ruby使用了mark-and-sweep garbage collection 来删除没有引用的对象。
虽然在ruby中不能真正的做到调用析构器来删除对象。这里有个方法define_finalizer,它是当一个对象被gc时,就会调用它:
a = "hello" puts "The string 'hello' has an object id #{a.object_id}" ObjectSpace.define_finalizer(a) { |id| puts "Destroying #{id}" } puts "Nothing to tidy" GC.start a = nil puts "The original string is now a candidate for collection" GC.start
输出的结果类似这样的:
The string 'hello' has an object id 21089680 Nothing to tidy The original string is now a candidate for collection Destroying 21089680
当finalizer 被调用的同时对象就被销毁了。如果此时你调用ObjectSpace._id2ref,然后参数为刚才那个对象的id,则会报一个RangeError:
ObjectSpace._id2ref 21089630 #in `_id2ref': 0x141cd5e is recycled object (RangeError)
由于ruby使用的是mark-and-sweep GC 的策略,那么他就不能保证当程序结束之前,对象什么时候被GC。
可是所有的一切都是不确定的。在ruby中,经常使用block来压缩一个源(也就是一段代码)的使用,在block的结尾,这个源将会被删除(也就是说。然后其他的对象没有任何改变(其实这个也就是说讲代码封装在block里面比较好,因为当block退出时,它的那些局部变量,或者说,传进来的哪些参数都会被GC掉,因此在ruby1.9里面,block里面的局部变量和外面的变量已经不是同一个变量了(假设名字相同)。)。看下面的代码:
File.open("myfile.txt") do |file| line1 = file.read # ... end
在这里当block退出时,file 被删除,这一切都是在open方法里控制。如果你想要实现一个open方法的子集,你可以这么做:
def File.open(name, mode = "r") f = os_file_open(name, mode) if block_given? begin yield f ensure f.close end return nil else return f end end
这边使用begin ensure是因为要做到就算异常被抛出,文件也要被关闭.
评论
2 楼
simohayha
2008-01-25
Module#ancestors 返回指定的类或者模块的所有存取方法。
--------------------
这个说错了吧,是返回所有包含的模块
哈哈,恩,错了。。。。
--------------------
这个说错了吧,是返回所有包含的模块
哈哈,恩,错了。。。。
1 楼
dennis_zane
2008-01-25
Module#ancestors 返回指定的类或者模块的所有存取方法。
--------------------
这个说错了吧,是返回所有包含的模块
--------------------
这个说错了吧,是返回所有包含的模块
发表评论
-
一个创建闭包的小技巧
2008-06-05 00:12 2077一个小技巧,在Ola Bini 的blog上看到的。 假设你 ... -
解决Colored Cubes问题
2008-06-02 10:43 2733Engineering Puzzle You have fo ... -
ruby1.9中的Iterators
2008-03-05 22:37 3659在ruby1.9中增加了External Iterators这 ... -
一个简单的ruby Metaprogram的例子
2008-03-03 23:49 4037比如下面一个文件 people.txt 引用name,age ... -
Ruby Object Model
2008-03-03 19:29 3489刚好看到,保存一下. -
一个检测方法的参数类型的小程序
2008-03-02 22:48 3211今天没事看blog的时候,看到一个小子实现了这个,不过他的程序 ... -
rails中的BlankSlate源码分析
2008-02-28 23:27 3399其实这个类实现的功能很简单,那就是实现一个没有predefin ... -
ruby中的类变量与类实例变量
2008-02-26 21:15 7566首先,在ruby1.8中类变量是所有子类和父类共享的,可以看下 ... -
在ubuntu上共存多个版本的ruby
2008-02-24 15:20 4337今天装Revactor库的时候,真把我郁闷了,没想到ubunt ... -
看到了一个用ruby写的scheme解释器
2008-02-16 21:35 3698,自己本来想等啥时候有时间做个类似的东西呢,没想到已经有人做 ... -
ruby way之处理RSS和Atom
2008-01-31 01:32 34711 rss 标准库 RSS 是基于xml的,因此你能简单的将 ... -
ruby way之使用REXML解析xml
2008-01-30 00:35 9187REXML 是一个完全用ruby写的processor ,他有 ... -
rails2中的一些被废弃的用法
2008-01-29 00:33 2488这些只是自己最近看web开发敏捷之道的时候(由于书中的版本是1 ... -
ruby way之动态特性之一
2008-01-23 01:25 44451 动态的evaluate代码 全局的方法eval 编译并且 ... -
ruby way之高级OOP特性之二
2008-01-20 03:43 28841 把代码像对象一样存储 当你想要以对象的形式存储一块代码的 ... -
ruby way之高级OOP特性之一
2008-01-19 12:14 21971 发送一条消息给一个对象 当你调用一个方法时,你也就是发送 ... -
ruby way之OOP之二
2008-01-16 23:59 23031 理解allocate 在一些特殊的环境中,你可能需要不调 ... -
ruby way之OOP之一
2008-01-16 00:25 25931 使用多个构造方法 在ruby中没有像c++或者ruby中 ... -
ruby way之连接数据库
2008-01-14 00:47 2435这边都只是个大概,具体的要自己去看文档了. 1 连接SQLi ... -
ruby way之高级数据存取
2008-01-13 02:31 3660经常我们需要以一种更 ...
相关推荐
The Ruby Way(第2版) <br>The Ruby Way assumes that the reader is already familiar with the subject matter. Using many code samples it focuses on "how-to use Ruby" for specific applications, either ...
The Ruby Way 第三版(英文版),全书22章,书中包含600多个按主题分类的示例。每个示例都回答了“如何使用Ruby来完成”的问题。 ——Ruby on Rails之父David Heinemeier Hansson倾力推荐!
the ruby way 2ed. the ruby way 2ed.
《The Ruby Way 第二版》...“《The Ruby Way (第2版)中文版》在阐述元编程(metaprogramming)等方面尤其出类拔萃,而元编程是Ruby最引人注目的方面之一。” ——Ruby on Rails之父David Heinemeier Hansson倾力推荐!
在ruby代码中,其实我们一直都在进行元编程,虽然可能只是一句非常简单的代码,比如说,在“”中嵌入一个表达式,这就是元编程。毕竟,嵌入的的表达式并非真正的代码,它只是一个字符串,但是ruby却可以将它转换成...
内含以下4个文档: 1、Addison.Wesley.The.Ruby.Way.2nd.Edition.Oct.2006.chm 2、O'Reilly.Learning.Ruby.May.2007.chm 3、Programming Ruby 2e.pdf 4、ruby中文文档.chm
TheRubyWay(Ruby之道)英文版 Addison.Wesley.The.Ruby.Way.2nd.Edition.Oct.2006.pdf
the ruby way the ruby way
11.5 时间日期the ruby way.rar
the ruby way,ruby 入门经典
The Ruby Way(处理文件和目录)
Addison Wesley The Ruby Way 2Nd Edition Oct 2006.pdf(英文版)
ruby2ruby 提供一些用来根据 RubyParser 兼容的 Sexps 轻松生成纯 Ruby 代码的方法。可在 Ruby 中轻松实现动态语言处理。 标签:ruby2ruby
2. 动态性:Ruby是一门动态性极强的编程语言,允许开发人员在运行时通过元编程(metaprogramming)来修改和扩展代码的行为。这种动态性使得Ruby具有很大的灵活性,可以应对各种需求和场景。 3. 面向对象编程:Ruby...
关于ruby的电子书,CHM格式 《The ruby way》这本书例子比较多!
Ruby Way by Hal fulton its about Ruby language programming
很好的讲ruby如何使用的书,ruby老手和java使用方法完全不同。不过只有部分,但,简单阅读,同样精彩
ruby代码ruby代码ruby代码ruby代码ruby代码ruby代码ruby代码ruby代码