Oh!Coder

Coding Life

读《Ruby编程语言》笔记(五)

| Comments

这次读完了第八章,关于Ruby元编程。翻看了下本书后面的部分,基本上都是在讲一些Ruby基础类库的应用,感觉实践性很强,多用一用就熟练了,没有太多需要理解的地方,所以笔记先做到这里吧,后面如果有需要再记。

一、类型、类和模块的判断(P.266~P.267)

  • o.class 返回对象o的类。
  • c.superclass 返回类c的超类。
  • o.instance_of? c 判断是否o.class == c
  • o.is_a? c 判断o是否是c或它某个子类的实例。如果c是模块,则这个方法判断o.class(或它的任意祖先类)是否包含了该模块。
  • o.kind\_of? c kind\_of?is_a?的同义词。
  • c === o 对于任意类或模块c,判断是否o.is_a?(c)
  • o.respond_to? name 判断对象o是否具有一个给定名称的公开或被保护方法。如果给出第二个参数并设为true,该方法将会检查私有方法。

#### 二、instance\_evalclass\_eval方法(P.270) * Object类定义了一个名为instance\_eval的方法,Module类定义了一个名为class\_eval的方法(module\_evalclass\_eval的同义词),这些方法都能像eval一样对Ruby代码进行求值,但是有两个重要区别。 * 第一个区别是这些方法会在指定对象或模块的上下文中对代码进行求值,该对象或模块成为代码求值时self的值。例如: * o.instance\_eval("@x") # Return the value of o's instance variable @x # Define an instance method len of String to return string length String.class\_eval("def len; size; end") # Here's another way to do that \# That quoted code behaves just as if it was inside "class String" and "end" String.class\_eval("alias len size") # Use instance\_eval to define class method String.empty \# Note that quote within quotes get a little tricky... String.instance\_eval("def empty; ''; end") * instance\_eval为这个对象创建一个单键方法(当对象是一个类对象时,该方法成为类方法),class\_eval则定义一个普通的实例方法。 * 这两个方法与eval的第二个重要区别是它们可以对代码块进行求值。当参数是代码块而飞字符串时,代码块中的代码会在适当的上下文中执行。这样,上面的调用可以用如下方式进行改写: * o.instance\_eval{ @x } String.class\_eval{ def len size end } String.class\_eval{ alias len size } String.instance\_eval{ def empty; ""; end }

三、方法的列举和测试(P.272~P.273)

  • Object定义了一组用于列举对象所定义方法名的方法,这些方法会返回方法名数组。方法名在Ruby 1.8中用字符串表示,而在Ruby 1.9中则使用符号。
  • o = "a string"
  • o.methods # => [ names of all public methods ]
  • o.public\_methods # => the same thing
  • o.public\_methods(false) # Exclude inherited methods
  • o.protected\_methods # => []: there aren't any
  • o.private\_methods # => array of all private methods
  • o.private\_methods(false) # => Exclude inherited private methods
  • def o.single; 1; end # Define a singleton method
  • o.singleton\_methods # => \["single"\] (or \[:single\] in 1.9)

四、send方法调用(P.274)

  • 通常,调用一个有名字的方法更简单的方式是使用send方法:
  • "hello".send :upcase # => "HELLO": invoke an instance method
  • Math.send(:sin, Math: :PI/2) # => 1.0: invoke a class method
  • send在接收者对象上调用名为第一个参数的方法,后面的其他参数会作为调用方法的参数。
  • send可以调用一个对象的任意有名方法,也包括私有或被保护方法。

五、定义方法(P.274)

  • 如果想为类或模块定义一个新的实例方法,你可以用define\_method方法。它是Module的一个实例方法,第一个参数是新方法的名字(用符号表示),方法体要么用Method对象表示作为第二个参数,要么用代码块表示。
  • 要记住define\_method是一个私有方法,必须在需要使用它的类或模块来调用它:
  • Add an instance method named m to class c with body b def add\_method(c, m, &b) c.class\_eval { define\_method(m, &b) } end add\_method(String, :greet){ "Hello, " + self } "world".greet \# => "Hello, world"

六、删除方法(P.276)

  • 如果需要动态删除由程序计算得到名字的方法,有两个选择:remove\_methodundef\_method。它们都是Module的私有方法,remove\_method删除当前类中的方法定义。如果该方法在超类中有定义,该定义在执行该方法后被继承下来。undef\_method则更严厉一些,它阻止给定方法在任何实例上的调用,即使存在这样一个在超类中继承而来的方法。

七、钩子方法(P.277)

  • ModuleClassObject类实现了若干回调方法,或者被称为钩子方法。这些方法并非默认定义的,不过如果为一个模块、类或对象定义了这些方法,它们会在特定事件发生时被调用,这使得在定义子类时、包含模块时或定义方法时,我们可以扩展Ruby的行为。这些钩子方法名以“ed”结尾。

八、跟踪(P.279)

  • Ruby定义了很多特性用于跟踪程序的执行,对于调试代码和打印有意义的错误消息,它们很有用处。其中最简单的两个特性是两个关键字:\_\_FILE\_\_\_\_LINE\_\_。这些关键字表示代码文件名及代码所出现的行号,这样你可以用它们来获得错误发生的确切位置:
  • STDERR.puts "#{\_\_FILE\_\_}:#{\_\_LINE\_\_}: invalid data"
  • 另外,值得注意的是,Kernel.evalObject.instance\_evalModule.class\_eval方法都接受一个文件名(或其他字符串)和一个行号作为它们最后两个参数。
  • 无疑,你已经注意到当一个异常抛出时,打印到控制台的错误消息包含了文件名和行号信息。这些信息当然是基于\_\_FILE\_\_\_\_LINE\_\_而得来的。每个Exception对象关联一个追踪信息,可以准确得知它是在哪里跑出的,是在方法中的什么地方抛出的,以及是在调用哪个方法时抛出的,等等。

九、ObjectSpace(P.281)

  • ObjectSpace模块定义了一组方便的低级方法,它们有时对调试和元编程有用。
  • 最值得注意的方法是each\_object,它是一个迭代器方法,可以迭代出解释器知道的每个对象(或者某个指定类的所有实例):
  • # Print out a list of all known classes ObjectSpace.each\_object(Class){ |c| puts c }
  • ObjectSpace.\_id2refObject.object\_id的反向方法,它的参数是一个对象ID,它返回相对应的对象;如果没有对应的对象,则抛出一个RangeError异常。
  • ObjectSpace.define\_finalizer可以注册一个Proc对象或一个代码块,它们在给定对象被垃圾收集时调用。
  • 任何用于终结(finalize)对象的值必须能被finalizer块获得,这样它们无需通过被终结对象而使用。你可以用ObjectSpace.undefine\_finalizer方法为一个对象删除所有注册的finalizer块。
  • 最后一个要介绍的ObjectSpace方法是ObjectSpace.garbage\_collect,它强制让Ruby运行垃圾收集器。垃圾收集功能也可以通过GC模块获得。GC.startObjectSpace.garbage\_collect的同义词方法,可以通过GC.diable方法临时关闭垃圾收集,用GC.enable使之再次生效。

十、别名链(P.290)

  • 首先,创建一个要修改方法的别名。这个别名用作该方法未修改版本的名称。
  • 接着,定义该方法的新版本。这个新方法应该通过别名调用该方法未修改的版本,不过在调用它之前或之后可以加入新的功能。

Comments