zoukankan      html  css  js  c++  java
  • 利用ruby演示程序执行

    介绍

    Ruby支持元编程,简单的说就是在运行时改变程序自身。利用这一点,可以做出很有趣的程序。本文介绍利用ruby演示程序的执行过程,显示包括函数调用和数据变化。

    演示程序执行

    Ruby每个class都有一个方法method_missing(name, *args)。当调用对象的方法不存在时,系统默认调用这个方法来处理。这就相当于一个系统后门,可以得到方法调用的轨迹。

    下面的程序演示如何把大象放进冰箱里。

    class User
    
      def act
    
        f = Frig.new
    
        f.open
    
        f.put_elephant
    
        f.close
    
      end
    
    end
    
    class Frig
    
      def indent; ' '*4; end
    
      def method_missing(name, *args)
    
        if name[0]=='_'
    
          return
    
        end
    
        puts "#{indent}Frig.#{name} "
    
      end
    
    end
    
    user = User.new
    
    user.act

    输出为:

        Frig.open

        Frig.put_elephant

        Frig.close

    这里面user.act没有打印出来。为了做到这一点,需要把method_missing放到一个公共类中共享;而且需要把act变成未知方法,激活method_missing;然后再利用一个技巧,映射到已知的方法。

    在这里把已知方法定义成下划线开头,在调用的地方取掉下划线,让method_missing完成两者之间的连接。

    class Show
    
      def initialize(name = "", pos = 0)
    
        @name, @pos = name, pos
    
      end
    
     
    
      def indent; ' '*@pos*4; end
    
     
    
      def method_missing(name, *args)
    
        if name[0]=='_'
    
          return
    
        end
    
        puts "#{indent}#{@name}.#{name} "
    
        if methods.grep(/_#{name}/)
    
          send "_#{name}", *args
    
        end
    
      end
    
    end
    
     
    
    class User < Show
    
      def _act
    
        f = Frig.new("frig", 1)
    
        f.open
    
        f.put_elephant
    
        f.close
    
      end
    
    end
    
     
    
    class Frig < Show
    
    end
    
     
    
    user = User.new
    
    user.act

    输出为:

    user.act

        frig.open

        frig.put_elephant

        frig.close

    添加数据显示

    上一节演示了程序的执行,但是充其量只是一个调用树。为了进一步揭示程序的运行状态,这一节加入状态机。

    class Stm
    
      def initialize
    
        @edges = Hash.new
    
        @current = '$'
    
      end
    
     
    
      def get_current; @current; end
    
      def empty?; @edges.empty?; end
    
     
    
      def def_edge(from, to, event)
    
        edges = @edges[from.to_s]
    
        if edges==nil
    
          @edges[from.to_s] = Hash.new
    
        end
    
        @edges[from.to_s][event.to_s] = to.to_s
    
      end
    
     
    
      def accept(event)
    
        edges = @edges[@current.to_s]
    
        st = nil
    
        if edges!=nil
    
          st = edges[event.to_s]
    
          if st!=nil
    
            @current = st
    
          end
    
        end
    
        if st==nil
    
          "**error** #{event} is not accepted "
    
        else
    
          st
    
        end
    
      end
    
      end
    
     
    
    class Show
    
      def initialize(name = "", pos = 0)
    
        @name, @pos = name, pos
    
        @m_stm = Stm.new
    
      end
    
     
    
      def indent; ' '*@pos*4; end
    
     
    
      def method_missing(name, *args)
    
        if name[0]=='_'
    
          return
    
        end
    
        print "#{indent}#{@name}.#{name} "
    
        if !@m_stm.empty?
    
          error = @m_stm.accept(name.to_s)
    
          if error && error[0]=='*'
    
            puts error+" when #{@name}'s  = #{@m_stm.get_current}"
    
          else
    
            puts 'STATUS("'+error+"\")"
    
          end
    
        else
    
          puts ""
    
        end
    
        if methods.grep(/_#{name}/)
    
          send "_#{name}", *args
    
        end
    
      end
    
    end
    
     
    
    class User < Show
    
      def _act
    
        f = Frig.new("frig", 1)
    
        f.open
    
        f.put_elephant
    
        #f.put_elephant
    
        f.close
    
      end
    
    end
    
     
    
    class Frig < Show
    
      def initialize(name = "", pos = 0)
    
        super
    
        @m_stm.def_edge('$', 'door is opened', 'open')
    
        @m_stm.def_edge('door is opened', 'door is closed', 'close')
    
        @m_stm.def_edge('door is opened', 'door is opened w/ elephant', 'put_elephant')
    
        @m_stm.def_edge('door is opened w/ elephant', 'door is closed w/ elephant', 'close')
    
      end
    
    end

    输出:

    user.act

        frig.open STATUS("door is opened")

        frig.put_elephant STATUS("door is opened w/ elephant")

    frig.close STATUS("door is closed w/ elephant")

    如果把大象两次放入冰箱,程序还会报错:

    user.act

        frig.open STATUS("door is opened")

        frig.put_elephant STATUS("door is opened w/ elephant")

        frig.put_elephant **error** put_elephant is not accepted  when frig's  = door is opened w/ elephant

        frig.close STATUS("door is closed w/ elephant

  • 相关阅读:
    内存条的物理结构分析【转载】
    JDK动态代理[2]----动态代理设计模式(文章转载于别处)
    shell 计算
    如何使用Vagrant创建linux环境(MacOS版)
    JavaFreemarker01快速上手
    7、验证信息
    6、更新文档
    5、删除文档
    4、查询文档02
    3、查询文档01
  • 原文地址:https://www.cnblogs.com/liuyunfeng/p/2765128.html
Copyright © 2011-2022 走看看