• RUBY元编程学习之”编写你的第一种领域专属语言“


    今天又学了一会RUBY的闭包,主要是看《RUBY元编程(metapromgramming ruby)》一书:

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

    第三章闭包结尾的守关BOSS是一道题:编写你的第一种领域专属语言。

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

      要求编写一个程序:redflag.rb. 对上面这段测试文件运行,得到如下的输出

    Setting up sky
    Setting up mountains
    Alert: the sky is falling
    Setting up sky
    Setting up mountains
    Alert: It's getting closer
    

      

         原书作者的给出的答案如下:

    def event(name,&block)
        @events[name] = block 
    end
    
    def setup(&block)
        @setups.push(block)
    end
    
    Dir.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_s
    end
    
    #我加的这两行,用来测试@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 
    end
    
    def setup(&block)
        @setups.push(block)
    end
    
    Dir.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_s
    end
    

    #我加的这两行,用来测试@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
    }.call
    
    Dir.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
      end
    end
    

      

    附:关于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 的书评

  • 相关阅读:
    NPOI创建DOCX常用操作
    【Python】django多对多 查询 ,反查等操作
    【Python】python 普通继承方式和super继承方式
    【云计算】开源装机自动化系统 CloudBoot OSInstall 介绍
    【Python】Python AES 对称加密示例
    【Python】Django 如何直接返回404 被 curl,wget 捕获到
    【Python】Django 支持 restful 风格 url
    【Python】Django 聚合 Count与Sum用法,注意点
    【Python】使用 boto 调用 S3 对象存储API
    【Other】千字文 硬笔 楷书 字帖
  • 原文地址:https://www.cnblogs.com/likeyu/p/2386031.html
Copyright © 2020-2023  润新知