自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

初探 Ruby Metaprogramming

開(kāi)發(fā) 前端 后端
接觸了一段時(shí)間得ruby on rails,深深被ror的magic,powerful,elegantly所折服,同時(shí)也對(duì)ruby這個(gè)神奇的語(yǔ)言本身產(chǎn)生了很大的好奇心,而其中最神奇的莫過(guò)于ruby 的 Metaprogramming。

51CTO推薦專題:Ruby On Rails開(kāi)發(fā)教程

Classes are open

我們先看一段代碼:

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

這里我們看到我們r(jià)eopen了String這個(gè)build-in的class,而且添加了一個(gè)新的方法say_hello(.NET 3.5中通過(guò)擴(kuò)展方法也實(shí)現(xiàn)了這個(gè)特性,但ruby的實(shí)現(xiàn)更加自然和靈活)這樣使得ruby語(yǔ)言自身提供了很大的可擴(kuò)展性,而這種從編程語(yǔ)言層面提供的可擴(kuò)展性為好處體現(xiàn)在兩個(gè)方面。

第一,對(duì)于ruby語(yǔ)言自身,在其以后的版本中可以對(duì)原有類在不破壞原有代碼的基礎(chǔ)之上提供更多更好的方法。.NET 3.5 已經(jīng)通過(guò)擴(kuò)展方法這個(gè)新特性,在原有集合類的方法之外增加了一些新的查詢方法。

第二,對(duì)于ruby的使用者,也就是我們這些ruby程序員來(lái)說(shuō)。classes are open,這就意味我們可以更加實(shí)現(xiàn)我們一些具體的特殊的需求。例如,我們希望我們應(yīng)用的程序中的String都可以提供一個(gè)encrype的方法,來(lái)實(shí)現(xiàn)加密。又或者我們對(duì)于String類的to_s方法的實(shí)現(xiàn)覺(jué)得不夠滿意,我們都可以reopen String這個(gè)類,然后定義我們的方法。因?yàn)閞uby的方法查找遵循

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

所有我們毋需擔(dān)心,我們對(duì)于to_s的調(diào)用出問(wèn)題。

前面我說(shuō)道,ruby的open class比.NET提供的擴(kuò)展方法更加靈活。而這個(gè)靈活體現(xiàn)在我們可以針對(duì)一個(gè)instance去增加方法,如下

  1. <SPAN style="FONT-FAMILY: 黑體">fred = 'fred' 
  2. def fred.say_hello  
  3.   p 'hello' 
  4. end 
  5.  
  6. fred.say_hello  
  7. </SPAN> 

這樣就滿足了我們對(duì)于一些特殊instance的需求。

Definition are active

  1. class Logger  
  2.   if ENV['debug']  
  3.     def log   
  4.       'debug' 
  5.     end 
  6.   else 
  7.     def log  
  8.       'non-debug' 
  9.     end 
  10.   end 
  11. end 

這是一段非常簡(jiǎn)單的代碼,但是我們可以看到我們是否定義debug這個(gè)ENV對(duì)于我們的程序會(huì)有完全不一樣的行為。這里也許有人會(huì)說(shuō)靜態(tài)語(yǔ)言的條件編譯同樣能完成這樣的任務(wù)。那么我們就再看一段代碼

  1. <SPAN style="FONT-FAMILY: 黑體">result = class Fred  
  2.   puts 'Hello' 
  3.   x = 3  
  4. end 
  5.  
  6. puts result  
  7. </SPAN> 

執(zhí)行這段代碼,我們會(huì)看到這樣的輸出結(jié)果:

Hello 
3

為什么會(huì)輸出Hello呢?因?yàn)閐efinition are active,也就是定義本身就是一段可執(zhí)行的代碼。為什么會(huì)輸出3呢?因?yàn)閞uby中所有的可執(zhí)行代碼都會(huì)有返回值。到這里肯定會(huì)有人問(wèn),那么class定義中的method呢?你可以試試在irb中定義一個(gè)method,你會(huì)發(fā)現(xiàn)在irb會(huì)返回一個(gè)nil給你。

但是definition are active在我們實(shí)際開(kāi)發(fā)中有什么用呢?那讓我們看一下一個(gè)rails的應(yīng)用

  1. module ActiveRecord  
  2.   class Base  
  3.     def has_many models  
  4.         
  5.     end 
  6.       
  7.     def belongs_to model  
  8.         
  9.     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, 還會(huì)有這樣優(yōu)雅的代碼嗎?

All methods have a receiver

在ruby中,方法的調(diào)用是以message的形式發(fā)送給相應(yīng)的instance的。比如說(shuō)foo.hello(),就是發(fā)送hello這個(gè)message給foo。這里很多人會(huì)好奇,那么如果我在irb上直接定義方法呢?其實(shí)ruby里面有一個(gè)概念叫top level execution, 它是一個(gè)Object的instance叫做main。當(dāng)你直接在irb中定義一個(gè)方法或者執(zhí)行一個(gè)方法(例如puts "hello"),同樣你只是發(fā)送了一個(gè)message,而這個(gè)message的receiver就是top level execution。

ruby代碼的執(zhí)行是與當(dāng)前代碼所在context相關(guān),不同的context關(guān)聯(lián)不同的receiver。也就是當(dāng)你的代碼在不同的context下執(zhí)行,由于context關(guān)聯(lián)的receiver不同也就有了不同的結(jié)果。

  1. class Context  
  2.   def name  
  3.     "smith" 
  4.   end     
  5.   p name      
  6.   def hi  
  7.     p name  
  8.   end 
  9. end  
  10. Context.new.hi 

結(jié)果為:

"Context"
 "smith"

如果你想知道在你當(dāng)前context下你方法的receiver,可以通過(guò)在當(dāng)前context下調(diào)用self來(lái)獲得。

Class are Object

我們都知道一個(gè)object有什么樣的行為和屬性是在ruby中由它的class決定。比如

  1. class Person  
  2.   attr_reader :name 
  3.     
  4.   def initialize(name)  
  5.     @name = name  
  6.   end 
  7.     
  8.   def introduce  
  9.     "I'm #{@name}." 
  10.   end 
  11. end 
  12.  
  13. p = Person.new "Dave" 

對(duì)于這個(gè)例子中,p具有什么樣的行為和屬性是由Person這個(gè)class決定的??墒俏覀兛吹綄?duì)于Person我們調(diào)用了一個(gè)new的方法,那么這個(gè)new方法是由誰(shuí)定義的呢?很簡(jiǎn)單啊,我們知道p的行為和屬性由它的class也就是Person決定,那么Person的new方法應(yīng)該也來(lái)自它的class。也就是引出了Class對(duì)象,Class對(duì)象中有兩個(gè)new方法,一個(gè)是class method另一個(gè)是instance method。我們的Person.new自然調(diào)用的就是Class對(duì)象中叫new的instance method, 那么那個(gè)叫做new的class method有什么用呢?

  1. Person = Class.new do 
  2.   attr_reader :name 
  3.     
  4.   def initialize(name)  
  5.     @name = name  
  6.   end 
  7.     
  8.   def introduce  
  9.     "I'm #{@name}." 
  10.   end 
  11. end 

這段代碼可以實(shí)現(xiàn)之前那段代碼一摸一樣的功能,而這里調(diào)用的就是Class中叫做new的class method。最奇怪的Class的superclass是Module,而Module的superclass是Object,但是Class的class是自身,Module的class是Class,而Object的class也是Class(superclass是Class的方法,class是Object的方法),我們也可以說(shuō)ruby中所有的Object的class都是Class(nil的class是NilClass,但是NilClass的class是Class)。Class間接繼承Object,但是Object的class又是Class,一個(gè)典型“雞生蛋,蛋生雞”的問(wèn)題。這個(gè)問(wèn)題給我最大困惑則是:如果我調(diào)用一個(gè)對(duì)象例如上面例子中p的XX方法,而這個(gè)XX方法并沒(méi)有直接在Person中定義,那么這個(gè)XX方法是來(lái)自Class還是Object呢?而對(duì)于這一點(diǎn)ruby的解決辦法是在方法的查找receiver的時(shí)候,會(huì)先檢查Person有沒(méi)有這個(gè)XX方法,會(huì)先檢查Class后檢查Object,也就是先檢查一個(gè)class的class,然后檢查superclass。
 

原文鏈接:http://www.cnblogs.com/feihe/archive/2011/04/17/1951274.html

【編輯推薦】

  1. 關(guān)于Ruby/RoR我的體驗(yàn)和看法
  2. 橫向壓力測(cè)試:Ruby on Rails PK CakePHP
  3. 在Nginx上運(yùn)行Ruby on Rails
  4. 解讀Ruby on Rails的成功秘籍
  5. 加速Ruby on Rails 消除N+1查詢問(wèn)題
責(zé)任編輯:陳貽新 來(lái)源: Fei He's Blog
相關(guān)推薦

2016-10-11 13:48:41

WebGLJavascriptWeb

2010-06-03 12:57:06

Hadoop

2009-06-24 13:22:27

Glassfish

2009-12-18 11:22:34

Ruby source

2011-05-17 14:11:06

Dijkstra

2015-01-21 16:35:49

Apple WatchWatchKit

2014-11-20 15:44:40

Apple Watch

2012-02-29 15:03:30

2009-12-18 11:37:54

Ruby關(guān)鍵字yiel

2009-08-27 10:21:22

Ruby on Rai

2014-11-05 11:05:15

Ruby

2012-07-09 10:22:28

Mono for An

2011-08-24 09:30:29

JavaJVM

2021-04-14 09:33:58

Kubernetes通信網(wǎng)絡(luò)模型

2013-04-10 11:23:27

2012-04-05 13:50:38

Java

2010-09-08 17:26:46

JavaScript

2011-06-16 10:25:29

AndroidAIR

2017-05-29 08:18:11

Serverless架構(gòu)軟件系統(tǒng)

2013-09-09 09:41:34

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)