- 浏览: 1399890 次
- 性别:
- 来自: 火星
文章分类
最新评论
-
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 2131一个小技巧,在Ola Bini 的blog上看到的。 假设你 ... -
解决Colored Cubes问题
2008-06-02 10:43 2784Engineering Puzzle You have fo ... -
ruby1.9中的Iterators
2008-03-05 22:37 3718在ruby1.9中增加了External Iterators这 ... -
一个简单的ruby Metaprogram的例子
2008-03-03 23:49 4102比如下面一个文件 people.txt 引用name,age ... -
Ruby Object Model
2008-03-03 19:29 3574刚好看到,保存一下. -
一个检测方法的参数类型的小程序
2008-03-02 22:48 3248今天没事看blog的时候,看到一个小子实现了这个,不过他的程序 ... -
rails中的BlankSlate源码分析
2008-02-28 23:27 3446其实这个类实现的功能很简单,那就是实现一个没有predefin ... -
ruby中的类变量与类实例变量
2008-02-26 21:15 7634首先,在ruby1.8中类变量是所有子类和父类共享的,可以看下 ... -
在ubuntu上共存多个版本的ruby
2008-02-24 15:20 4376今天装Revactor库的时候,真把我郁闷了,没想到ubunt ... -
看到了一个用ruby写的scheme解释器
2008-02-16 21:35 3768,自己本来想等啥时候有时间做个类似的东西呢,没想到已经有人做 ... -
ruby way之处理RSS和Atom
2008-01-31 01:32 35191 rss 标准库 RSS 是基于xml的,因此你能简单的将 ... -
ruby way之使用REXML解析xml
2008-01-30 00:35 9253REXML 是一个完全用ruby写的processor ,他有 ... -
rails2中的一些被废弃的用法
2008-01-29 00:33 2542这些只是自己最近看web开发敏捷之道的时候(由于书中的版本是1 ... -
ruby way之动态特性之一
2008-01-23 01:25 45401 动态的evaluate代码 全局的方法eval 编译并且 ... -
ruby way之高级OOP特性之二
2008-01-20 03:43 29491 把代码像对象一样存储 当你想要以对象的形式存储一块代码的 ... -
ruby way之高级OOP特性之一
2008-01-19 12:14 22631 发送一条消息给一个对象 当你调用一个方法时,你也就是发送 ... -
ruby way之OOP之二
2008-01-16 23:59 23631 理解allocate 在一些特殊的环境中,你可能需要不调 ... -
ruby way之OOP之一
2008-01-16 00:25 26311 使用多个构造方法 在ruby中没有像c++或者ruby中 ... -
ruby way之连接数据库
2008-01-14 00:47 2475这边都只是个大概,具体的要自己去看文档了. 1 连接SQLi ... -
ruby way之高级数据存取
2008-01-13 02:31 3732经常我们需要以一种更 ...
相关推荐
这本书的第二版在2006年出版,由Addison-Wesley出版,作者通过深入浅出的方式,揭示了Ruby语言的强大功能和优雅特性。 Ruby是一种动态类型、面向对象的编程语言,它的设计理念是注重简洁和生产力,让开发者能够更...
这本书深入浅出地探讨了Ruby语言的各种特性,旨在帮助读者理解并掌握这门强大的动态脚本语言。Ruby以其简洁、优雅的语法和强大的元编程能力而备受赞誉,是许多开发者首选的编程工具。 在Ruby语言中,一切都是对象,...
通过学习《The Ruby Way》第二版,读者不仅可以掌握Ruby编程的基本技巧,还能了解到一些高级特性,从而在实践中发挥Ruby的最大潜力。无论是初学者还是有经验的开发者,这本书都能为他们提供宝贵的指导和启示。
《The Ruby Way》第二版是Addison-Wesley出版社在2006年推出的一本深入浅出的Ruby编程语言教程。这本书专为初学者设计,旨在帮助读者快速掌握Ruby语言的基础和高级特性,从而轻松入门Ruby编程。Ruby是一种动态、开放...
Ruby是一种面向对象的、动态类型的编程语言,以其简洁、优雅的语法著称,尤其适合Web开发,其中Rails框架是其最著名的应用之一。API(Application Programming Interface)是软件开发者用来与操作系统、库或服务进行...
2. **动态类型**:Ruby中不需要预先声明变量类型,类型会随着赋值自动确定,这使得代码更简洁,但同时也可能导致运行时错误。 3. **块和闭包**:Ruby中的块是代码段,可以与方法一起使用,闭包是能够记住其定义环境...
元编程在Ruby中尤为重要,因为它使得动态功能成为可能,这是Ruby语言最吸引人的特性之一。书中提到了Ruby on Rails的早期思想受到了第一版《The Ruby Way》中的一些概念的启发,特别是书中现在被称为第11章的内容,...
Ruby是一种面向对象的脚本语言,以其简洁、优雅的语法和强大的元编程能力著称。在编程领域,它被广泛用于Web开发,尤其是与Rails框架的结合...同时,关注Ruby和Rails的最新动态,了解新版本的特性,以便保持与时俱进。
第二版于2006年10月由Addison-Wesley出版,它全面地涵盖了Ruby语言的核心概念、语法特性以及高级编程技巧。 Ruby是一种动态类型、面向对象的脚本语言,由日本的松本行弘(Yukihiro Matsumoto)于1995年设计并开发。...
2. **编程技巧**:如何利用Ruby的特性编写出高效且易于维护的代码,如上下文敏感的语法糖和内建函数的巧妙使用。 3. **模块化设计**:书中可能会讲解如何通过模块来组织代码,以及如何使用模块实现命名空间和混入...
Ruby on Rails,简称Rails...总的来说,这些资源为学习Ruby和Ruby on Rails提供了一个全面的学习路径,从基础语言特性到Web开发的最佳实践,通过理论与实践相结合的方式,助力开发者快速上手并精通这个强大的开发框架。
最后,元编程部分将探讨Ruby语言中动态添加方法和属性,以及操作类和模块的能力,这是Ruby作为一种高度动态语言的独特之处。 整个教程不仅提供编程语言的基本知识,还提供了一些编码建议,帮助学习者避免常见错误并...
- **Web开发**:Ruby最著名的应用领域之一是Web开发,尤其是通过Ruby on Rails框架简化了Web应用的开发过程。 - **系统管理和自动化**:Ruby常用于系统管理和自动化脚本的编写,因其优雅的语法和强大的元编程能力。 ...
《The Rails Way》一书由Obie Fernandez撰写,属于Addison-Wesley Professional Ruby系列,该系列致力于为读者提供实用、面向人且深入的信息,帮助他们利用Ruby平台创建动态技术解决方案。这一系列书籍的创立基于一...
Ruby是一种面向对象的编程语言,以其简洁、优雅的语法而闻名,特别适合初学者入门。...记得实践是检验真理的唯一标准,理论学习之余,多动手编写代码,结合实际项目经验,将使你的Ruby之旅更加丰富多彩。