[18425] | 1 | #
|
---|
| 2 | # irb.rb - irb main module
|
---|
| 3 | # $Release Version: 0.9.5 $
|
---|
| 4 | # $Revision: 11708 $
|
---|
| 5 | # $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $
|
---|
| 6 | # by Keiju ISHITSUKA([email protected])
|
---|
| 7 | #
|
---|
| 8 | # --
|
---|
| 9 | #
|
---|
| 10 | #
|
---|
| 11 | #
|
---|
| 12 | require "e2mmap"
|
---|
| 13 |
|
---|
| 14 | require "irb/init"
|
---|
| 15 | require "irb/context"
|
---|
| 16 | require "irb/extend-command"
|
---|
| 17 | #require "irb/workspace"
|
---|
| 18 |
|
---|
| 19 | require "irb/ruby-lex"
|
---|
| 20 | require "irb/input-method"
|
---|
| 21 | require "irb/locale"
|
---|
| 22 |
|
---|
| 23 | STDOUT.sync = true
|
---|
| 24 |
|
---|
| 25 | module IRB
|
---|
| 26 | @RCS_ID='-$Id: irb.rb 11708 2007-02-12 23:01:19Z shyouhei $-'
|
---|
| 27 |
|
---|
| 28 | class Abort < Exception;end
|
---|
| 29 |
|
---|
| 30 | #
|
---|
| 31 | @CONF = {}
|
---|
| 32 |
|
---|
| 33 | def IRB.conf
|
---|
| 34 | @CONF
|
---|
| 35 | end
|
---|
| 36 |
|
---|
| 37 | # IRB version method
|
---|
| 38 | def IRB.version
|
---|
| 39 | if v = @CONF[:VERSION] then return v end
|
---|
| 40 |
|
---|
| 41 | require "irb/version"
|
---|
| 42 | rv = @RELEASE_VERSION.sub(/\.0/, "")
|
---|
| 43 | @CONF[:VERSION] = format("irb %s(%s)", rv, @LAST_UPDATE_DATE)
|
---|
| 44 | end
|
---|
| 45 |
|
---|
| 46 | def IRB.CurrentContext
|
---|
| 47 | IRB.conf[:MAIN_CONTEXT]
|
---|
| 48 | end
|
---|
| 49 |
|
---|
| 50 | # initialize IRB and start TOP_LEVEL irb
|
---|
| 51 | def IRB.start(ap_path = nil)
|
---|
| 52 | $0 = File::basename(ap_path, ".rb") if ap_path
|
---|
| 53 |
|
---|
| 54 | IRB.setup(ap_path)
|
---|
| 55 |
|
---|
| 56 | if @CONF[:SCRIPT]
|
---|
| 57 | irb = Irb.new(nil, @CONF[:SCRIPT])
|
---|
| 58 | else
|
---|
| 59 | irb = Irb.new
|
---|
| 60 | end
|
---|
| 61 |
|
---|
| 62 | @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
|
---|
| 63 | @CONF[:MAIN_CONTEXT] = irb.context
|
---|
| 64 |
|
---|
| 65 | trap("SIGINT") do
|
---|
| 66 | irb.signal_handle
|
---|
| 67 | end
|
---|
| 68 |
|
---|
| 69 | catch(:IRB_EXIT) do
|
---|
| 70 | irb.eval_input
|
---|
| 71 | end
|
---|
| 72 | # print "\n"
|
---|
| 73 | end
|
---|
| 74 |
|
---|
| 75 | def IRB.irb_exit(irb, ret)
|
---|
| 76 | throw :IRB_EXIT, ret
|
---|
| 77 | end
|
---|
| 78 |
|
---|
| 79 | def IRB.irb_abort(irb, exception = Abort)
|
---|
| 80 | if defined? Thread
|
---|
| 81 | irb.context.thread.raise exception, "abort then interrupt!!"
|
---|
| 82 | else
|
---|
| 83 | raise exception, "abort then interrupt!!"
|
---|
| 84 | end
|
---|
| 85 | end
|
---|
| 86 |
|
---|
| 87 | #
|
---|
| 88 | # irb interpriter main routine
|
---|
| 89 | #
|
---|
| 90 | class Irb
|
---|
| 91 | def initialize(workspace = nil, input_method = nil, output_method = nil)
|
---|
| 92 | @context = Context.new(self, workspace, input_method, output_method)
|
---|
| 93 | @context.main.extend ExtendCommandBundle
|
---|
| 94 | @signal_status = :IN_IRB
|
---|
| 95 |
|
---|
| 96 | @scanner = RubyLex.new
|
---|
| 97 | @scanner.exception_on_syntax_error = false
|
---|
| 98 | end
|
---|
| 99 | attr_reader :context
|
---|
| 100 | attr_accessor :scanner
|
---|
| 101 |
|
---|
| 102 | def eval_input
|
---|
| 103 | @scanner.set_prompt do
|
---|
| 104 | |ltype, indent, continue, line_no|
|
---|
| 105 | if ltype
|
---|
| 106 | f = @context.prompt_s
|
---|
| 107 | elsif continue
|
---|
| 108 | f = @context.prompt_c
|
---|
| 109 | elsif indent > 0
|
---|
| 110 | f = @context.prompt_n
|
---|
| 111 | else @context.prompt_i
|
---|
| 112 | f = @context.prompt_i
|
---|
| 113 | end
|
---|
| 114 | f = "" unless f
|
---|
| 115 | if @context.prompting?
|
---|
| 116 | @context.io.prompt = p = prompt(f, ltype, indent, line_no)
|
---|
| 117 | else
|
---|
| 118 | @context.io.prompt = p = ""
|
---|
| 119 | end
|
---|
| 120 | if @context.auto_indent_mode
|
---|
| 121 | unless ltype
|
---|
| 122 | ind = prompt(@context.prompt_i, ltype, indent, line_no)[/.*\z/].size +
|
---|
| 123 | indent * 2 - p.size
|
---|
| 124 | ind += 2 if continue
|
---|
| 125 | @context.io.prompt = p + " " * ind if ind > 0
|
---|
| 126 | end
|
---|
| 127 | end
|
---|
| 128 | end
|
---|
| 129 |
|
---|
| 130 | @scanner.set_input(@context.io) do
|
---|
| 131 | signal_status(:IN_INPUT) do
|
---|
| 132 | if l = @context.io.gets
|
---|
| 133 | print l if @context.verbose?
|
---|
| 134 | else
|
---|
| 135 | if @context.ignore_eof? and @context.io.readable_atfer_eof?
|
---|
| 136 | l = "\n"
|
---|
| 137 | if @context.verbose?
|
---|
| 138 | printf "Use \"exit\" to leave %s\n", @context.ap_name
|
---|
| 139 | end
|
---|
| 140 | end
|
---|
| 141 | end
|
---|
| 142 | l
|
---|
| 143 | end
|
---|
| 144 | end
|
---|
| 145 |
|
---|
| 146 | @scanner.each_top_level_statement do |line, line_no|
|
---|
| 147 | signal_status(:IN_EVAL) do
|
---|
| 148 | begin
|
---|
| 149 | line.untaint
|
---|
| 150 | @context.evaluate(line, line_no)
|
---|
| 151 | output_value if @context.echo?
|
---|
| 152 | rescue StandardError, ScriptError, Abort
|
---|
| 153 | $! = RuntimeError.new("unknown exception raised") unless $!
|
---|
| 154 | print $!.class, ": ", $!, "\n"
|
---|
| 155 | if $@[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && $!.class.to_s !~ /^IRB/
|
---|
| 156 | irb_bug = true
|
---|
| 157 | else
|
---|
| 158 | irb_bug = false
|
---|
| 159 | end
|
---|
| 160 |
|
---|
| 161 | messages = []
|
---|
| 162 | lasts = []
|
---|
| 163 | levels = 0
|
---|
| 164 | for m in $@
|
---|
| 165 | m = @context.workspace.filter_backtrace(m) unless irb_bug
|
---|
| 166 | if m
|
---|
| 167 | if messages.size < @context.back_trace_limit
|
---|
| 168 | messages.push "\tfrom "+m
|
---|
| 169 | else
|
---|
| 170 | lasts.push "\tfrom "+m
|
---|
| 171 | if lasts.size > @context.back_trace_limit
|
---|
| 172 | lasts.shift
|
---|
| 173 | levels += 1
|
---|
| 174 | end
|
---|
| 175 | end
|
---|
| 176 | end
|
---|
| 177 | end
|
---|
| 178 | print messages.join("\n"), "\n"
|
---|
| 179 | unless lasts.empty?
|
---|
| 180 | printf "... %d levels...\n", levels if levels > 0
|
---|
| 181 | print lasts.join("\n")
|
---|
| 182 | end
|
---|
| 183 | print "Maybe IRB bug!!\n" if irb_bug
|
---|
| 184 | end
|
---|
| 185 | if $SAFE > 2
|
---|
| 186 | warn "Error: irb does not work for $SAFE level higher than 2"
|
---|
| 187 | exit 1
|
---|
| 188 | end
|
---|
| 189 | end
|
---|
| 190 | end
|
---|
| 191 | end
|
---|
| 192 |
|
---|
| 193 | def suspend_name(path = nil, name = nil)
|
---|
| 194 | @context.irb_path, back_path = path, @context.irb_path if path
|
---|
| 195 | @context.irb_name, back_name = name, @context.irb_name if name
|
---|
| 196 | begin
|
---|
| 197 | yield back_path, back_name
|
---|
| 198 | ensure
|
---|
| 199 | @context.irb_path = back_path if path
|
---|
| 200 | @context.irb_name = back_name if name
|
---|
| 201 | end
|
---|
| 202 | end
|
---|
| 203 |
|
---|
| 204 | def suspend_workspace(workspace)
|
---|
| 205 | @context.workspace, back_workspace = workspace, @context.workspace
|
---|
| 206 | begin
|
---|
| 207 | yield back_workspace
|
---|
| 208 | ensure
|
---|
| 209 | @context.workspace = back_workspace
|
---|
| 210 | end
|
---|
| 211 | end
|
---|
| 212 |
|
---|
| 213 | def suspend_input_method(input_method)
|
---|
| 214 | back_io = @context.io
|
---|
| 215 | @context.instance_eval{@io = input_method}
|
---|
| 216 | begin
|
---|
| 217 | yield back_io
|
---|
| 218 | ensure
|
---|
| 219 | @context.instance_eval{@io = back_io}
|
---|
| 220 | end
|
---|
| 221 | end
|
---|
| 222 |
|
---|
| 223 | def suspend_context(context)
|
---|
| 224 | @context, back_context = context, @context
|
---|
| 225 | begin
|
---|
| 226 | yield back_context
|
---|
| 227 | ensure
|
---|
| 228 | @context = back_context
|
---|
| 229 | end
|
---|
| 230 | end
|
---|
| 231 |
|
---|
| 232 | def signal_handle
|
---|
| 233 | unless @context.ignore_sigint?
|
---|
| 234 | print "\nabort!!\n" if @context.verbose?
|
---|
| 235 | exit
|
---|
| 236 | end
|
---|
| 237 |
|
---|
| 238 | case @signal_status
|
---|
| 239 | when :IN_INPUT
|
---|
| 240 | print "^C\n"
|
---|
| 241 | raise RubyLex::TerminateLineInput
|
---|
| 242 | when :IN_EVAL
|
---|
| 243 | IRB.irb_abort(self)
|
---|
| 244 | when :IN_LOAD
|
---|
| 245 | IRB.irb_abort(self, LoadAbort)
|
---|
| 246 | when :IN_IRB
|
---|
| 247 | # ignore
|
---|
| 248 | else
|
---|
| 249 | # ignore other cases as well
|
---|
| 250 | end
|
---|
| 251 | end
|
---|
| 252 |
|
---|
| 253 | def signal_status(status)
|
---|
| 254 | return yield if @signal_status == :IN_LOAD
|
---|
| 255 |
|
---|
| 256 | signal_status_back = @signal_status
|
---|
| 257 | @signal_status = status
|
---|
| 258 | begin
|
---|
| 259 | yield
|
---|
| 260 | ensure
|
---|
| 261 | @signal_status = signal_status_back
|
---|
| 262 | end
|
---|
| 263 | end
|
---|
| 264 |
|
---|
| 265 | def prompt(prompt, ltype, indent, line_no)
|
---|
| 266 | p = prompt.dup
|
---|
| 267 | p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
|
---|
| 268 | case $2
|
---|
| 269 | when "N"
|
---|
| 270 | @context.irb_name
|
---|
| 271 | when "m"
|
---|
| 272 | @context.main.to_s
|
---|
| 273 | when "M"
|
---|
| 274 | @context.main.inspect
|
---|
| 275 | when "l"
|
---|
| 276 | ltype
|
---|
| 277 | when "i"
|
---|
| 278 | if $1
|
---|
| 279 | format("%" + $1 + "d", indent)
|
---|
| 280 | else
|
---|
| 281 | indent.to_s
|
---|
| 282 | end
|
---|
| 283 | when "n"
|
---|
| 284 | if $1
|
---|
| 285 | format("%" + $1 + "d", line_no)
|
---|
| 286 | else
|
---|
| 287 | line_no.to_s
|
---|
| 288 | end
|
---|
| 289 | when "%"
|
---|
| 290 | "%"
|
---|
| 291 | end
|
---|
| 292 | end
|
---|
| 293 | p
|
---|
| 294 | end
|
---|
| 295 |
|
---|
| 296 | def output_value
|
---|
| 297 | if @context.inspect?
|
---|
| 298 | printf @context.return_format, @context.last_value.inspect
|
---|
| 299 | else
|
---|
| 300 | printf @context.return_format, @context.last_value
|
---|
| 301 | end
|
---|
| 302 | end
|
---|
| 303 |
|
---|
| 304 | def inspect
|
---|
| 305 | ary = []
|
---|
| 306 | for iv in instance_variables
|
---|
| 307 | case iv
|
---|
| 308 | when "@signal_status"
|
---|
| 309 | ary.push format("%s=:%s", iv, @signal_status.id2name)
|
---|
| 310 | when "@context"
|
---|
| 311 | ary.push format("%s=%s", iv, eval(iv).__to_s__)
|
---|
| 312 | else
|
---|
| 313 | ary.push format("%s=%s", iv, eval(iv))
|
---|
| 314 | end
|
---|
| 315 | end
|
---|
| 316 | format("#<%s: %s>", self.class, ary.join(", "))
|
---|
| 317 | end
|
---|
| 318 | end
|
---|
| 319 |
|
---|
| 320 | # Singleton method
|
---|
| 321 | def @CONF.inspect
|
---|
| 322 | IRB.version unless self[:VERSION]
|
---|
| 323 |
|
---|
| 324 | array = []
|
---|
| 325 | for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
|
---|
| 326 | case k
|
---|
| 327 | when :MAIN_CONTEXT, :__TMP__EHV__
|
---|
| 328 | array.push format("CONF[:%s]=...myself...", k.id2name)
|
---|
| 329 | when :PROMPT
|
---|
| 330 | s = v.collect{
|
---|
| 331 | |kk, vv|
|
---|
| 332 | ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
|
---|
| 333 | format(":%s=>{%s}", kk.id2name, ss.join(", "))
|
---|
| 334 | }
|
---|
| 335 | array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
|
---|
| 336 | else
|
---|
| 337 | array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
|
---|
| 338 | end
|
---|
| 339 | end
|
---|
| 340 | array.join("\n")
|
---|
| 341 | end
|
---|
| 342 | end
|
---|