RUBY元編程學習之”編寫你的第一種領域專屬語言“

來源:互聯網
上載者:User

今天又學了一會RUBY的閉包,主要是看《RUBY元編程(metapromgramming ruby)》一書:

http://book.douban.com/subject/4086938/

第三章閉包結尾的守關BOSS是一道題:編寫你的第一種領域專屬語言。

event "the sky is falling" do    @sky_height < 300endevent "It's getting closer" do    @sky_height < @mountains_heightendsetup do    puts "Setting up sky"    @sky_height = 100endsetup do    puts "Setting up mountains"    @mountains_height = 200end

  要求編寫一個程式:redflag.rb. 對上面這段測試檔案運行,得到如下的輸出

Setting up skySetting up mountainsAlert: the sky is fallingSetting up skySetting up mountainsAlert: It's getting closer

  

     原書作者的給出的答案如下:

def event(name,&block)    @events[name] = block enddef setup(&block)    @setups.push(block)endDir.glob('*event.rb').each do |file|    @events={}    @setups=[]    load file    #puts file    @events.each do |name,event|        env = Object.new()        @setups.each do |setup|            env.instance_eval &setup        end        puts "Alert: #{name}" if env.instance_eval &event    end    #puts @events.to_s    #puts @setups.to_send#我加的這兩行,用來測試@sky_height的範圍puts @sky_height   puts @mountains_heigh

  

前面的都好理解,關鍵是後來做的這個Clean Room:  

        env = Object.new()        @setups.each do |setupa|            env.instance_eval &setup        end        puts "Alert: #{name}" if env.instance_eval &event

這一段,主要是為了讓 &setup 這個區塊與 &event 區塊在同一個對象env的空間內運行,達到來共用兩個變數的值:@sky_height , @mountains_height的目的。

 

我去掉了這個clean room後,改為proc.call的方式做了下面的這個測試:

def event(name,&block)    @events[name] = block enddef setup(&block)    @setups.push(block)endDir.glob('*event.rb').each do |file|    @events={}    @setups=[]    load file    #puts file    @events.each do |name,event|        env = Object.new()        @setups.each do |setup|           setup.call         end        puts "Alert: #{name}" if event.call    end    #puts @events.to_s    #puts @setups.to_send

#我加的這兩行,用來測試@sky_height的範圍
puts @sky_height
puts @mountains_heigh

也能通過。不過這時候發現這兩個變數@sky_height @mountains_heigh已經變成一個全域變數--proc層級的變數。在程式的末尾打出了變數的值。

 

而用作者的潔淨室方法,這兩個變數只是在env的上下文環境中存在,是這個Object對象的執行個體變數。在程式的末尾這兩個變數是nil。

 

作者通過這個例子極好地展示了 潔淨室 和 扁平範圍 的功能。

這章的最後,作者給出了另外一個更完美的方法,連@events @setups 這兩個全域變數也去掉了:

#---# Excerpted from "Metaprogramming Ruby",# published by The Pragmatic Bookshelf.# Copyrights apply to this code. It may not be used to create training material, # courses, books, articles, and the like. Contact us if you are in doubt.# We make no guarantees that this code is fit for any purpose. # Visit http://www.pragmaticprogrammer.com/titles/ppmetr for more book information.#---lambda {  setups = []  events = {}  Kernel.send :define_method, :event do |name, &block|    events[name] = block  end  Kernel.send :define_method, :setup do |&block|    setups << block  end  Kernel.send :define_method, :each_event do |&block|    events.each_pair do |name, event|      block.call name, event    end  end  Kernel.send :define_method, :each_setup do |&block|    setups.each do |setup|      block.call setup    end  end}.callDir.glob('*events.rb').each do |file|  load file  each_event do |name, event|    env = Object.new    each_setup do |setup|      env.instance_eval &setup    end    puts "ALERT: #{name}" if env.instance_eval &event  endend

  

 

附:關於instance_eval的解釋: 

instance_eval可以在一個執行個體的上下文中eval一個字串或者一個block:

instance_eval()方法做下面3件事情:

a,改變self為instance_eval的接收器。

b,改變預設的definee給接收器的eigenclass,如果沒有,則建立它。

c, 執行block的內容。 


參考:http://book.douban.com/subject/4086938/annotation?sort=rank&start=20  blackanger 的書評

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.