zoukankan      html  css  js  c++  java
  • 初窥Ruby Metaprogramming

    Everything should be made as simple as possible, but not simpler.

    http://www.cnblogs.com/feihe/archive/2011/04/17/1951274.html

    接触了一段时间得ruby on rails,深深被ror的magic,powerful,elegantly所折服,同时也对ruby这个神奇的语言本身产生了很大的好奇心,而其中最神奇的莫过于ruby 的 Metaprogramming。

    • Classes are open

      我们先看一段代码:

    1 class String
    2   def say_hello
    3     "Hello!"
    4   end
    5 end
    6  
    7 "Fred".say_hello

    这里我们看到我们reopen了String这个build-in的class,而且添加了一个新的方法say_hello(.NET 3.5中通过扩展方法也实现了这个特性,但ruby的实现更加自然和灵活)这样使得ruby语言自身提供了很大的可扩展性,而这种从编程语言层面提供的可扩展性为好处体现在两个方面。

      第一,对于ruby语言自身,在其以后的版本中可以对原有类在不破坏原有代码的基础之上提供更多更好的方法。.NET 3.5 已经通过扩展方法这个新特性,在原有集合类的方法之外增加了一些新的查询方法。

      第二,对于ruby的使用者,也就是我们这些ruby程序员来说。classes are open,这就意味我们可以更加实现我们一些具体的特殊的需求。例如,我们希望我们应用的程序中的String都可以提供一个encrype的方法,来实现加密。又或者我们对于String类的to_s方法的实现觉得不够满意,我们都可以reopen String这个类,然后定义们的方法。因为ruby的方法查找遵循

     ”Define a method twice inside the same class, the second method definition takes precedence“

    所有我们毋需担心,我们对于to_s的调用出问题。

      前面我说道,ruby的open class比.NET提供的扩展方法更加灵活。而这个灵活体现在我们可以针对一个instance去增加方法,如下

    1 fred = 'fred'
    2 def fred.say_hello
    3   'hello'
    4 end
    5  
    6 fred.say_hello
    这样就满足了我们对于一些特殊instance的需求。
    • Definition are active
    01 class Logger
    02   if ENV['debug']
    03     def log
    04       'debug'
    05     end
    06   else
    07     def log
    08       'non-debug'
    09     end
    10   end
    11 end

    这是一段非常简单的代码,但是我们可以看到我们是否定义debug这个ENV对于我们的程序会有完全不一样的行为。这里也许有人会说静态语言的条件编译同样能完成这样的任务。那么我们就再看一段代码

    1 result = class Fred
    2   puts 'Hello'
    3   x = 3
    4 end
    5  
    6 puts result

    执行这段代码,我们会看到这样的输出结果:

    Hello

    3

    为什么会输出Hello呢?因为definition are active,也就是定义本身就是一段可执行的代码。为什么会输出3呢?因为ruby中所有的可执行代码都会有返回值。到这里肯定会有人问,那么class定义中的method呢?你可以试试在irb中定义一个method,你会发现在irb会返回一个nil给你。

     但是definition are active在我们实际开发中有什么用呢?那让我们看一下一个rails的应用

    01 module ActiveRecord
    02   class Base
    03     def has_many models
    04        
    05     end
    06      
    07     def belongs_to model
    08        
    09     end
    10      
    11   end
    12 end
    13  
    14 class Order < ActiveRecord::Base
    15   has_many :items
    16 end
    17  
    18 class Item < ActiveRecord::Base
    19   belongs_to :order
    20 end
    你能想想如果definition aren't activity, 还会有这样优雅的代码吗?
    • All methods have a receiver

    在ruby中,方法的调用是以message的形式发送给相应的instance的。比如说foo.hello(),就是发送hello这个message给foo。这里很多人会好奇,那么如果我在irb上直接定义方法呢?其实ruby里面有一个概念叫top level execution, 它是一个Object的instance叫做main。当你直接在irb中定义一个方法或者执行一个方法(例如puts "hello"),同样你只是发送了一个message,而这个message的receiver就是top level execution。

      ruby代码的执行是与当前代码所在context相关,不同的context关联不同的receiver。也就是当你的代码在不同的context下执行,由于context关联的receiver不同也就有了不同的结果。

    01 class Context
    02   def name
    03     "smith"
    04   end
    05    
    06   p name
    07    
    08   def hi
    09     p name
    10   end
    11 end
    12  
    13 Context.new.hi

    结果为:

    "Context"

    "smith"

    如果你想知道在你当前context下你方法的receiver,可以通过在当前context下调用self来获得。

    • Class are Object

    我们都知道一个object有什么样的行为和属性是在ruby中由它的class决定。比如

    01 class Person
    02   attr_reader :name
    03    
    04   def initialize(name)
    05     @name = name
    06   end
    07    
    08   def introduce
    09     "I'm #{@name}."
    10   end
    11 end
    12  
    13 p = Person.new "Dave"

    对于这个例子中,p具有什么样的行为和属性是由Person这个class决定的。可是我们看到对于Person我们调用了一个new的方法,那么这个new方法是由谁定义的呢?很简单啊,我们知道p的行为和属性由它的class也就是Person决定,那么Person的new方法应该也来自它的class。也就是引出了Class对象,Class对象中有两个new方法,一个是class method另一个是instance method。我们的Person.new自然调用的就是Class对象中叫new的instance method, 那么那个叫做new的class method有什么用呢?

    01 Person = Class.new do
    02   attr_reader :name
    03    
    04   def initialize(name)
    05     @name = name
    06   end
    07    
    08   def introduce
    09     "I'm #{@name}."
    10   end
    11 end

    这段代码可以实现之前那段代码一摸一样的功能,而这里调用的就是Class中叫做new的class method。最奇怪的Class的superclass是Module,而Module的superclass是Object,但是Class的class是自身,Module的class是Class,而Object的class也是Class(superclass是Class的方法,class是Object的方法),我们也可以说ruby中所有的Object的class都是Class(nil的class是NilClass,但是NilClass的class是Class)。Class间接继承Object,但是Object的class又是Class,一个典型“鸡生蛋,蛋生鸡”的问题。这个问题给我最大困惑则是:如果我调用一个对象例如上面例子中p的XX方法,而这个XX方法并没有直接在Person中定义,那么这个XX方法是来自Class还是Object呢?而对于这一点ruby的解决办法是在方法的查找receiver的时候,会先检查Person有没有这个XX方法,会先检查Class后检查Object,也就是先检查一个class的class,然后检查superclass。

  • 相关阅读:
    java arraylist int[] 转换
    nginx installl
    "segmentation fault " when "import tensorflow as tf"
    preprocessing MinMaxScaler
    java对集合的操作,jxl操作excel
    IPython安装过程 @win7 64bit
    JavaScript学习——创建对象
    JavaScript学习——理解对象
    JavaScript学习——Math对象
    JavaScript学习——Global对象
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2032289.html
Copyright © 2011-2022 走看看