Ruby元编程

  • 方法
  • 代码块
  • 类宏
  • Eval方法

实例变量、方法、类

实例变量(Instance Variables)是当你使用它们时,才会被建立的对象。因此,即使是同一个类的实例,也可以有不同的实例变量。

从技术层面上来看,一个对象(实例)只是存储了它的实例变量和其所属类的引用。因此,一个对象的实例变量仅存在于对象中,方法(我们称之为实例方法(Instance Methods))则存在于对象所属的类中。这也就是为什么同一个类的实例都共享类中的方法,却不能共享实例变量的原因了。

  • 类也是对象。
  • 因为类也是一个对象,能应用于对象的皆可运用于类。类和任何对象一样,有它们自己的类,Class类即是Class类的实例。
  • 与其它的对象一样,类也有方法。对象的方法即是其所属类的实例方法。亦即,任何一个类的方法就是Class类的实例方法。
  • 所有的类有共同的祖先Object类(都是从Object类直接或间接继承而来),而Object类又继承自BasicObject类,Ruby类的根本。
  • 类名是常量(Constant)。
  n = Class.new
  puts n.ancestors
  puts n.supperclass
  puts n.supperclass.supperclass
  puts n.supperclass.supperclass.supperclass

打开类

其实这个就跟方法重定义是一样的结果,不过随意改动可能会产生严重的后果,比如说你改的这个方法在其它地方有使用到,所以这种方法还是慎用,除非你非常明确该方法不会造成其它后果。

puts 'abc'.replace('a') # a
class String
  def replace(string)
    puts '重新打开了类'
  end
end
'abc'.replace('a')  #'重新打开了类'

我们也可以使用细化来实现这个过程

细化

module StringExtensions
  refine String do
    def replace(string)
       puts '细化'
    end
  end
end

在需要使用这个方法的地方使用using

如:using StringExtensions
细化的好处就是不会全局影响,在你需要使用的地方using就可以了,风险相对较小。

调用方法

类中的方法是怎么调用的?

  • 方法的查找(接收者和祖先链)
    Ruby中要在类中查找一个方法,首先在它的类查找这个方法,如果没有,则往上查找,如此类推,直到祖先链的顶端,到最后,如果还没找到,会抛出method_missing异常。如果有了解过JS,那么你肯定非常明白这个过程,因为JS中的方法查找也是类似于这个过程。
  • 执行方法
    在执行方法的过程中,Ruby始终需要一个接收者的引用,也就是self

self关键字

任何时刻,Ruby中只有一个对象能充当当前对象,并且没有哪个对象能长期充当这个角色,调用一个方法时,接收者就成为了self,从这一刻起,所有的实例变量都是self的实例变量,所有没有明确指明接收者的方法都在self上调用。
举个栗子:

class Book
  def get_library
    @book_count = 1000
    self
  end

  def self.is_my_book?(book)
    false
  end
end
b = Book.new
b.get_library # 这个时候,b就充当了self
b.is_my_book?('Ruby元编程') # undefined method `is_book?' for # (NoMethodError)
Book.is_my_book?('Ruby元编程') # false

上面调用is_my_book?的方法为什么会报错?
那是因为 self.is_my_book?(book) 等于 Book.is_my_book?(book)
当b调用的时候,self引用b实例对象,不等于Book,所以就会抛出找不到方法的错误

方法

  • 动态派发(调用方法:对象.send(方法名,参数))
class Book
  def create_book
    'Ruby元编程'  
  end  
  
  def update_book  
    'Ruby元编程'  
  end  
  
  def delete_book
    'Ruby元编程'    
  end  

  def search_book
    'Ruby元编程'  
  end
end  
  
s = Book.new  
  
puts s.send(:get_one_name)   
puts s.send(:get_two_name)  
puts s.send(:get_three_name) 
puts s.send(:get_four_name)  
  • 动态定义
class Book
  ['create', 'update', 'delete', 'search'].each do |item|
    define_method("#{item}_book"){
      puts "#{item}-Ruby元编程"
    }
  end
end
b = Book.new
b.create_book # create-Ruby元编程
b.update_book # update-Ruby元编程
b.delete_book # delete-Ruby元编程
b.search_book # search-Ruby元编程
  • method_missing(幽灵方法)
# encoding: utf-8
class Book
  def method_missing(name, *argc)
    if [:create_book, :update_book, :delete_book, :search_book].include?(name)  
      puts "#{name}-Ruby元编程" 
    else
      super  
    end
  end
end
b = Book.new
b.create_book# create-Ruby元编程
b.update_book# update-Ruby元编程
b.delete_book # delete-Ruby元编程
b.search_book# search-Ruby元编程
b.book # undefined method `book'

代码块

...

类宏

如果按照以前的做法,定义一个属性的读写必须将每个属性定义一个Get 和 Set方法,比如如下代码

class Post
  def title=(title)
    @title = title
  end
  def title
    @title
  end
 ....
 ....

如果像一篇文章这样,定义title,content,author等属性,就需要写3组这样的方法,非常不方便。这个时候,就要亮出Ruby的类宏attr_accessor(module的类里面的一个C语言写的方法,附上超链接,以上代码就可以写成

  class Post
    attr_accessor :title
  end

Eval方法

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