ruby元编程(1)

面试中碰到一些面试官提到的关于ruby元编程的问题的总结

  • class和module的区别
  1. 官方说明
    1. class doc 类是第一类型(first-class)的对象,每一个类都是Class类的对象。
    2. module doc 模块(Module)是方法和常量的集合。方法可以是实例方法也可以是模块方法,当一个模块被include到一个类中时,实例方法会出现在该类中,而模块方法是不会出现的。
module Mod
  def one
    "This is one"
  end
  module_function :one
end

class Cls
  include Mod
  def call_one
    one
  end
end

Mod.one     #=> "This is one"
c = Cls.new
c.call_one  #=> "This is one"

module Mod
  def one
    "This is the new one"
  end
end

Mod.one     #=> "This is one"
c.call_one  #=> "This is the new one"
  1. extend & include & prepend
module A
  def t
    puts "t method in A"
  end
end

class B
  include A
end

class C
  extend A
end

B将新增一个实例方法t,C将新增一个类方法t,同时,B的祖先链ancestors中将增加A,而C的祖先链中没有A。

module A
  def t
    puts "in A"
  end
end

class B
  include A
  def t
    puts "in B"
  end
end

class C
  prepend A
  def t
    puts "in C"
  end
end

B.new.t   #输出 ‘in B’
C.new.t   #输出 ‘in A’

puts B.ancestors
puts C.ancestors

输出如下图所示:

ruby元编程(1)_第1张图片
inheritance diagram

prependinclude类似,首先都是添加实例方法的,不同的是扩展module在祖先链上的放置位置不同。

  1. ruby类的继承关系
ruby元编程(1)_第2张图片
继承关系图

所有类的基类

ruby元编程(1)_第3张图片
BasicObject

类的类与超类

ruby元编程(1)_第4张图片
Metaprogramming Ruby 2
  1. 方法如何调用
    1. 实例方法,首先在实例中找,然后在实例对象的单件类中找,之后沿祖先链依次向上找
    2. 类方法,首先在类的单件类中找,然后沿着类的单件类的祖先链依次向上找(类的单件类的祖先链 = 类的祖先链的各个节点的单件类组成的链)
  • instance_eval & class_eval
class A
  def t1
    p "t1"
  end
end
obj1 = A.new

def obj1.t0
  p "t0"
end

class << obj1
  def t2
    p "t2"
  end
end

class << A
  def t3
    p "t3"
  end
end

obj1.instance_eval %{
  def t4
    p "t4"
  end

  def self.t5
    p "t5"
  end
}

A.instance_eval %{  
  def t6
    p "t6"
  end
}

A.class_eval %{  
  def t7
    p "t7"
  end
}

obj1.singleton_class.send(:define_method, :t8){p 't8'}

obj1.class.send(:define_method, :t9){p 't9'}

A.singleton_class.send(:define_method, :t10){p '10'}

各自拥有的方法如下图所示:

ruby元编程(1)_第5张图片
methods

参考文章

动态添加对象方法
动态添加类方法
ruby include extend prepend 使用方法

你可能感兴趣的:(ruby元编程(1))