lib/irb/ext/multi-irb.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  #   irb/multi-irb.rb - multiple irb module
   3  #       $Release Version: 0.9$
   4  #       $Revision: 1.1 $
   5  #       $Date: 2002/07/09 11:17:17 $
   6  #       by Keiju ISHITSUKA(keiju@ishitsuka.com)
   7  #
   8  # --
   9  #
  10  #   
  11  #
  12  IRB.fail CanNotGoMultiIrbMode unless defined?(Thread)
  13  require "thread"
  14  
  15  module IRB
  16    # job management class
  17    class JobManager
  18      @RCS_ID='-$Id: multi-irb.rb,v 1.1 2002/07/09 11:17:17 keiju Exp $-'
  19  
  20      def initialize
  21        # @jobs = [[thread, irb],...]
  22        @jobs = []
  23        @current_job = nil
  24      end
  25  
  26      attr_accessor :current_job
  27  
  28      def n_jobs
  29        @jobs.size
  30      end
  31  
  32      def thread(key)
  33        th, irb = search(key)
  34        th
  35      end
  36  
  37      def irb(key)
  38        th, irb = search(key)
  39        irb
  40      end
  41  
  42      def main_thread
  43        @jobs[0][0]
  44      end
  45  
  46      def main_irb
  47        @jobs[0][1]
  48      end
  49  
  50      def insert(irb)
  51        @jobs.push [Thread.current, irb]
  52      end
  53  
  54      def switch(key)
  55        th, irb = search(key)
  56        IRB.fail IrbAlreadyDead unless th.alive?
  57        IRB.fail IrbSwitchToCurrentThread if th == Thread.current
  58        @current_job = irb
  59        th.run
  60        Thread.stop
  61        @current_job = irb(Thread.current)
  62      end
  63  
  64      def kill(*keys)
  65        for key in keys
  66          th, irb = search(key)
  67          IRB.fail IrbAlreadyDead unless th.alive?
  68          th.exit
  69        end
  70      end    
  71  
  72      def search(key)
  73        case key
  74        when Integer
  75          @jobs[key]
  76        when Irb
  77          @jobs.find{|k, v| v.equal?(key)}
  78        when Thread
  79          @jobs.assoc(key)
  80        else
  81          assoc = @jobs.find{|k, v| v.context.main.equal?(key)}
  82          IRB.fail NoSuchJob, key if assoc.nil?
  83          assoc
  84        end
  85      end
  86  
  87      def delete(key)
  88        case key
  89        when Integer
  90          IRB.fail NoSuchJob, key unless @jobs[key]
  91          @jobs[key] = nil
  92        else
  93          catch(:EXISTS) do
  94            @jobs.each_index do
  95              |i|
  96              if @jobs[i] and (@jobs[i][0] == key ||
  97                               @jobs[i][1] == key ||
  98                               @jobs[i][1].context.main.equal?(key))
  99                @jobs[i] = nil
 100                throw :EXISTS
 101              end
 102            end
 103            IRB.fail NoSuchJob, key
 104          end
 105        end
 106        until assoc = @jobs.pop; end unless @jobs.empty?
 107        @jobs.push assoc
 108      end
 109  
 110      def inspect
 111        ary = []
 112        @jobs.each_index do
 113          |i|
 114          th, irb = @jobs[i]
 115          next if th.nil?
 116  
 117          if th.alive?
 118            if th.stop?
 119              t_status = "stop"
 120            else
 121              t_status = "running"
 122            end
 123          else
 124            t_status = "exited"
 125          end
 126          ary.push format("#%d->%s on %s (%s: %s)",
 127                          i, 
 128                          irb.context.irb_name, 
 129                          irb.context.main,
 130                          th,
 131                          t_status)
 132        end
 133        ary.join("\n")
 134      end
 135    end
 136  
 137    @JobManager = JobManager.new
 138  
 139    def IRB.JobManager
 140      @JobManager
 141    end
 142  
 143    def IRB.CurrentContext
 144      IRB.JobManager.irb(Thread.current).context
 145    end
 146  
 147    # invoke multi-irb 
 148    def IRB.irb(file = nil, *main)
 149      workspace = WorkSpace.new(*main)
 150      parent_thread = Thread.current
 151      Thread.start do
 152        begin
 153          irb = Irb.new(workspace, file)
 154        rescue 
 155          print "Subirb can't start with context(self): ", workspace.main.inspect, "\n"
 156          print "return to main irb\n"
 157          Thread.pass
 158          Thread.main.wakeup
 159          Thread.exit
 160        end
 161        @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
 162        @JobManager.insert(irb)
 163        @JobManager.current_job = irb
 164        begin
 165          system_exit = false
 166          catch(:IRB_EXIT) do
 167            irb.eval_input
 168          end
 169        rescue SystemExit
 170          system_exit = true
 171          raise
 172          #fail
 173        ensure
 174          unless system_exit
 175            @JobManager.delete(irb)
 176            if parent_thread.alive?
 177              @JobManager.current_job = @JobManager.irb(parent_thread)
 178              parent_thread.run
 179            else
 180              @JobManager.current_job = @JobManager.main_irb
 181              @JobManager.main_thread.run
 182            end
 183          end
 184        end
 185      end
 186      Thread.stop
 187      @JobManager.current_job = @JobManager.irb(Thread.current)
 188    end
 189  
 190  #   class Context
 191  #     def set_last_value(value)
 192  #       @last_value = value
 193  #       @workspace.evaluate "_ = IRB.JobManager.irb(Thread.current).context.last_value"
 194  #       if @eval_history #and !@__.equal?(@last_value)
 195  #       @eval_history_values.push @line_no, @last_value
 196  #       @workspace.evaluate "__ = IRB.JobManager.irb(Thread.current).context.instance_eval{@eval_history_values}"
 197  #       end
 198  #       @last_value
 199  #     end
 200  #   end
 201  
 202  #  module ExtendCommand
 203  #     def irb_context
 204  #       IRB.JobManager.irb(Thread.current).context
 205  #     end
 206  # #    alias conf irb_context
 207  #   end
 208  
 209    @CONF[:SINGLE_IRB_MODE] = false
 210    @JobManager.insert(@CONF[:MAIN_CONTEXT].irb)
 211    @JobManager.current_job = @CONF[:MAIN_CONTEXT].irb
 212  
 213    class Irb
 214      def signal_handle
 215        unless @context.ignore_sigint?
 216          print "\nabort!!\n" if @context.verbose?
 217          exit
 218        end
 219  
 220        case @signal_status
 221        when :IN_INPUT
 222          print "^C\n"
 223          IRB.JobManager.thread(self).raise RubyLex::TerminateLineInput
 224        when :IN_EVAL
 225          IRB.irb_abort(self)
 226        when :IN_LOAD
 227          IRB.irb_abort(self, LoadAbort)
 228        when :IN_IRB
 229          # ignore
 230        else
 231          # ignore other cases as well
 232        end
 233      end
 234    end
 235  
 236    trap("SIGINT") do
 237      @JobManager.current_job.signal_handle
 238      Thread.stop
 239    end
 240  
 241  end