1# 2# irb.rb - irb main module 3# $Release Version: 0.9.6 $ 4# $Revision: 39075 $ 5# by Keiju ISHITSUKA(keiju@ruby-lang.org) 6# 7# -- 8# 9# 10# 11require "e2mmap" 12 13require "irb/init" 14require "irb/context" 15require "irb/extend-command" 16#require "irb/workspace" 17 18require "irb/ruby-lex" 19require "irb/input-method" 20require "irb/locale" 21 22STDOUT.sync = true 23 24# IRB stands for "interactive ruby" and is a tool to interactively execute ruby 25# expressions read from the standard input. 26# 27# The +irb+ command from your shell will start the interpreter. 28# 29# == Usage 30# 31# Use of irb is easy if you know ruby. 32# 33# When executing irb, prompts are displayed as follows. Then, enter the ruby 34# expression. An input is executed when it is syntactically complete. 35# 36# $ irb 37# irb(main):001:0> 1+2 38# #=> 3 39# irb(main):002:0> class Foo 40# irb(main):003:1> def foo 41# irb(main):004:2> print 1 42# irb(main):005:2> end 43# irb(main):006:1> end 44# #=> nil 45# 46# The Readline extension module can be used with irb. Use of Readline is 47# default if it's installed. 48# 49# == Command line options 50# 51# Usage: irb.rb [options] [programfile] [arguments] 52# -f Suppress read of ~/.irbrc 53# -m Bc mode (load mathn, fraction or matrix are available) 54# -d Set $DEBUG to true (same as `ruby -d') 55# -r load-module Same as `ruby -r' 56# -I path Specify $LOAD_PATH directory 57# -U Same as `ruby -U` 58# -E enc Same as `ruby -E` 59# -w Same as `ruby -w` 60# -W[level=2] Same as `ruby -W` 61# --inspect Use `inspect' for output (default except for bc mode) 62# --noinspect Don't use inspect for output 63# --readline Use Readline extension module 64# --noreadline Don't use Readline extension module 65# --prompt prompt-mode 66# --prompt-mode prompt-mode 67# Switch prompt mode. Pre-defined prompt modes are 68# `default', `simple', `xmp' and `inf-ruby' 69# --inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs. 70# Suppresses --readline. 71# --simple-prompt Simple prompt mode 72# --noprompt No prompt mode 73# --tracer Display trace for each execution of commands. 74# --back-trace-limit n 75# Display backtrace top n and tail n. The default 76# value is 16. 77# --irb_debug n Set internal debug level to n (not for popular use) 78# -v, --version Print the version of irb 79# 80# == Configuration 81# 82# IRB reads from <code>~/.irbrc</code> when it's invoked. 83# 84# If <code>~/.irbrc</code> doesn't exist, +irb+ will try to read in the following order: 85# 86# * +.irbrc+ 87# * +irb.rc+ 88# * +_irbrc+ 89# * <code>$irbrc</code> 90# 91# The following are alternatives to the command line options. To use them type 92# as follows in an +irb+ session: 93# 94# IRB.conf[:IRB_NAME]="irb" 95# IRB.conf[:MATH_MODE]=false 96# IRB.conf[:INSPECT_MODE]=nil 97# IRB.conf[:IRB_RC] = nil 98# IRB.conf[:BACK_TRACE_LIMIT]=16 99# IRB.conf[:USE_LOADER] = false 100# IRB.conf[:USE_READLINE] = nil 101# IRB.conf[:USE_TRACER] = false 102# IRB.conf[:IGNORE_SIGINT] = true 103# IRB.conf[:IGNORE_EOF] = false 104# IRB.conf[:PROMPT_MODE] = :DEFALUT 105# IRB.conf[:PROMPT] = {...} 106# IRB.conf[:DEBUG_LEVEL]=0 107# 108# === Auto indentation 109# 110# To enable auto-indent mode in irb, add the following to your +.irbrc+: 111# 112# IRB.conf[:AUTO_INDENT] = true 113# 114# === Autocompletion 115# 116# To enable autocompletion for irb, add the following to your +.irbrc+: 117# 118# require 'irb/completion' 119# 120# === History 121# 122# By default, irb disables history and will not store any commands you used. 123# 124# If you want to enable history, add the following to your +.irbrc+: 125# 126# IRB.conf[:SAVE_HISTORY] = 1000 127# 128# This will now store the last 1000 commands in <code>~/.irb_history</code>. 129# 130# See IRB::Context#save_history= for more information. 131# 132# == Customizing the IRB Prompt 133# 134# In order to customize the prompt, you can change the following Hash: 135# 136# IRB.conf[:PROMPT] 137# 138# This example can be used in your +.irbrc+ 139# 140# IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode 141# :AUTO_INDENT => true # enables auto-indent mode 142# :PROMPT_I => nil, # normal prompt 143# :PROMPT_S => nil, # prompt for continuated strings 144# :PROMPT_C => nil, # prompt for continuated statement 145# :RETURN => " ==>%s\n" # format to return value 146# } 147# 148# IRB.conf[:PROMPT_MODE] = :MY_PROMPT 149# 150# Or, invoke irb with the above prompt mode by: 151# 152# irb --prompt my-prompt 153# 154# Constants +PROMPT_I+, +PROMPT_S+ and +PROMPT_C+ specify the format. In the 155# prompt specification, some special strings are available: 156# 157# %N # command name which is running 158# %m # to_s of main object (self) 159# %M # inspect of main object (self) 160# %l # type of string(", ', /, ]), `]' is inner %w[...] 161# %NNi # indent level. NN is degits and means as same as printf("%NNd"). 162# # It can be ommited 163# %NNn # line number. 164# %% # % 165# 166# For instance, the default prompt mode is defined as follows: 167# 168# IRB.conf[:PROMPT_MODE][:DEFAULT] = { 169# :PROMPT_I => "%N(%m):%03n:%i> ", 170# :PROMPT_S => "%N(%m):%03n:%i%l ", 171# :PROMPT_C => "%N(%m):%03n:%i* ", 172# :RETURN => "%s\n" # used to printf 173# } 174# 175# irb comes with a number of available modes: 176# 177# # :NULL: 178# # :PROMPT_I: 179# # :PROMPT_N: 180# # :PROMPT_S: 181# # :PROMPT_C: 182# # :RETURN: | 183# # %s 184# # :DEFAULT: 185# # :PROMPT_I: ! '%N(%m):%03n:%i> ' 186# # :PROMPT_N: ! '%N(%m):%03n:%i> ' 187# # :PROMPT_S: ! '%N(%m):%03n:%i%l ' 188# # :PROMPT_C: ! '%N(%m):%03n:%i* ' 189# # :RETURN: | 190# # => %s 191# # :CLASSIC: 192# # :PROMPT_I: ! '%N(%m):%03n:%i> ' 193# # :PROMPT_N: ! '%N(%m):%03n:%i> ' 194# # :PROMPT_S: ! '%N(%m):%03n:%i%l ' 195# # :PROMPT_C: ! '%N(%m):%03n:%i* ' 196# # :RETURN: | 197# # %s 198# # :SIMPLE: 199# # :PROMPT_I: ! '>> ' 200# # :PROMPT_N: ! '>> ' 201# # :PROMPT_S: 202# # :PROMPT_C: ! '?> ' 203# # :RETURN: | 204# # => %s 205# # :INF_RUBY: 206# # :PROMPT_I: ! '%N(%m):%03n:%i> ' 207# # :PROMPT_N: 208# # :PROMPT_S: 209# # :PROMPT_C: 210# # :RETURN: | 211# # %s 212# # :AUTO_INDENT: true 213# # :XMP: 214# # :PROMPT_I: 215# # :PROMPT_N: 216# # :PROMPT_S: 217# # :PROMPT_C: 218# # :RETURN: |2 219# # ==>%s 220# 221# == Restrictions 222# 223# Because irb evaluates input immediately after it is syntactically complete, 224# the results may be slightly different than directly using ruby. 225# 226# == IRB Sessions 227# 228# IRB has a special feature, that allows you to manage many sessions at once. 229# 230# You can create new sessions with Irb.irb, and get a list of current sessions 231# with the +jobs+ command in the prompt. 232# 233# === Commands 234# 235# JobManager provides commands to handle the current sessions: 236# 237# jobs # List of current sessions 238# fg # Switches to the session of the given number 239# kill # Kills the session with the given number 240# 241# The +exit+ command, or ::irb_exit, will quit the current session and call any 242# exit hooks with IRB.irb_at_exit. 243# 244# A few commands for loading files within the session are also available: 245# 246# +source+:: 247# Loads a given file in the current session and displays the source lines, 248# see IrbLoader#source_file 249# +irb_load+:: 250# Loads the given file similarly to Kernel#load, see IrbLoader#irb_load 251# +irb_require+:: 252# Loads the given file similarly to Kernel#require 253# 254# === Configuration 255# 256# The command line options, or IRB.conf, specify the default behavior of 257# Irb.irb. 258# 259# On the other hand, each conf in IRB@Command+line+options is used to 260# individually configure IRB.irb. 261# 262# If a proc is set for IRB.conf[:IRB_RC], its will be invoked after execution 263# of that proc with the context of the current session as its argument. Each 264# session can be configured using this mechanism. 265# 266# === Session variables 267# 268# There are a few variables in every Irb session that can come in handy: 269# 270# <code>_</code>:: 271# The value command executed, as a local variable 272# <code>__</code>:: 273# The history of evaluated commands 274# <code>__[line_no]</code>:: 275# Returns the evaluation value at the given line number, +line_no+. 276# If +line_no+ is a negative, the return value +line_no+ many lines before 277# the most recent return value. 278# 279# === Example using IRB Sessions 280# 281# # invoke a new session 282# irb(main):001:0> irb 283# # list open sessions 284# irb.1(main):001:0> jobs 285# #0->irb on main (#<Thread:0x400fb7e4> : stop) 286# #1->irb#1 on main (#<Thread:0x40125d64> : running) 287# 288# # change the active session 289# irb.1(main):002:0> fg 0 290# # define class Foo in top-level session 291# irb(main):002:0> class Foo;end 292# # invoke a new session with the context of Foo 293# irb(main):003:0> irb Foo 294# # define Foo#foo 295# irb.2(Foo):001:0> def foo 296# irb.2(Foo):002:1> print 1 297# irb.2(Foo):003:1> end 298# 299# # change the active session 300# irb.2(Foo):004:0> fg 0 301# # list open sessions 302# irb(main):004:0> jobs 303# #0->irb on main (#<Thread:0x400fb7e4> : running) 304# #1->irb#1 on main (#<Thread:0x40125d64> : stop) 305# #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop) 306# # check if Foo#foo is available 307# irb(main):005:0> Foo.instance_methods #=> [:foo, ...] 308# 309# # change the active sesssion 310# irb(main):006:0> fg 2 311# # define Foo#bar in the context of Foo 312# irb.2(Foo):005:0> def bar 313# irb.2(Foo):006:1> print "bar" 314# irb.2(Foo):007:1> end 315# irb.2(Foo):010:0> Foo.instance_methods #=> [:bar, :foo, ...] 316# 317# # change the active session 318# irb.2(Foo):011:0> fg 0 319# irb(main):007:0> f = Foo.new #=> #<Foo:0x4010af3c> 320# # invoke a new session with the context of f (instance of Foo) 321# irb(main):008:0> irb f 322# # list open sessions 323# irb.3(<Foo:0x4010af3c>):001:0> jobs 324# #0->irb on main (#<Thread:0x400fb7e4> : stop) 325# #1->irb#1 on main (#<Thread:0x40125d64> : stop) 326# #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop) 327# #3->irb#3 on #<Foo:0x4010af3c> (#<Thread:0x4010a1e0> : running) 328# # evaluate f.foo 329# irb.3(<Foo:0x4010af3c>):002:0> foo #=> 1 => nil 330# # evaluate f.bar 331# irb.3(<Foo:0x4010af3c>):003:0> bar #=> bar => nil 332# # kill jobs 1, 2, and 3 333# irb.3(<Foo:0x4010af3c>):004:0> kill 1, 2, 3 334# # list open sesssions, should only include main session 335# irb(main):009:0> jobs 336# #0->irb on main (#<Thread:0x400fb7e4> : running) 337# # quit irb 338# irb(main):010:0> exit 339module IRB 340 @RCS_ID='-$Id: irb.rb 39075 2013-02-05 15:57:19Z zzak $-' 341 342 # An exception raised by IRB.irb_abort 343 class Abort < Exception;end 344 345 @CONF = {} 346 347 348 # Displays current configuration. 349 # 350 # Modifing the configuration is achieved by sending a message to IRB.conf. 351 # 352 # See IRB@Configuration for more information. 353 def IRB.conf 354 @CONF 355 end 356 357 # Returns the current version of IRB, including release version and last 358 # updated date. 359 def IRB.version 360 if v = @CONF[:VERSION] then return v end 361 362 require "irb/version" 363 rv = @RELEASE_VERSION.sub(/\.0/, "") 364 @CONF[:VERSION] = format("irb %s(%s)", rv, @LAST_UPDATE_DATE) 365 end 366 367 # The current IRB::Context of the session, see IRB.conf 368 # 369 # irb 370 # irb(main):001:0> IRB.CurrentContext.irb_name = "foo" 371 # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo" 372 def IRB.CurrentContext 373 IRB.conf[:MAIN_CONTEXT] 374 end 375 376 # Initializes IRB and creates a new Irb.irb object at the +TOPLEVEL_BINDING+ 377 def IRB.start(ap_path = nil) 378 $0 = File::basename(ap_path, ".rb") if ap_path 379 380 IRB.setup(ap_path) 381 382 if @CONF[:SCRIPT] 383 irb = Irb.new(nil, @CONF[:SCRIPT]) 384 else 385 irb = Irb.new 386 end 387 388 @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] 389 @CONF[:MAIN_CONTEXT] = irb.context 390 391 trap("SIGINT") do 392 irb.signal_handle 393 end 394 395 begin 396 catch(:IRB_EXIT) do 397 irb.eval_input 398 end 399 ensure 400 irb_at_exit 401 end 402# print "\n" 403 end 404 405 # Calls each event hook of IRB.conf[:AT_EXIT] when the current session quits. 406 def IRB.irb_at_exit 407 @CONF[:AT_EXIT].each{|hook| hook.call} 408 end 409 410 # Quits irb 411 def IRB.irb_exit(irb, ret) 412 throw :IRB_EXIT, ret 413 end 414 415 # Aborts then interrupts irb. 416 # 417 # Will raise an Abort exception, or the given +exception+. 418 def IRB.irb_abort(irb, exception = Abort) 419 if defined? Thread 420 irb.context.thread.raise exception, "abort then interrupt!" 421 else 422 raise exception, "abort then interrupt!" 423 end 424 end 425 426 class Irb 427 # Creates a new irb session 428 def initialize(workspace = nil, input_method = nil, output_method = nil) 429 @context = Context.new(self, workspace, input_method, output_method) 430 @context.main.extend ExtendCommandBundle 431 @signal_status = :IN_IRB 432 433 @scanner = RubyLex.new 434 @scanner.exception_on_syntax_error = false 435 end 436 # Returns the current context of this irb session 437 attr_reader :context 438 # The lexer used by this irb session 439 attr_accessor :scanner 440 441 # Evaluates input for this session. 442 def eval_input 443 @scanner.set_prompt do 444 |ltype, indent, continue, line_no| 445 if ltype 446 f = @context.prompt_s 447 elsif continue 448 f = @context.prompt_c 449 elsif indent > 0 450 f = @context.prompt_n 451 else 452 f = @context.prompt_i 453 end 454 f = "" unless f 455 if @context.prompting? 456 @context.io.prompt = p = prompt(f, ltype, indent, line_no) 457 else 458 @context.io.prompt = p = "" 459 end 460 if @context.auto_indent_mode 461 unless ltype 462 ind = prompt(@context.prompt_i, ltype, indent, line_no)[/.*\z/].size + 463 indent * 2 - p.size 464 ind += 2 if continue 465 @context.io.prompt = p + " " * ind if ind > 0 466 end 467 end 468 end 469 470 @scanner.set_input(@context.io) do 471 signal_status(:IN_INPUT) do 472 if l = @context.io.gets 473 print l if @context.verbose? 474 else 475 if @context.ignore_eof? and @context.io.readable_after_eof? 476 l = "\n" 477 if @context.verbose? 478 printf "Use \"exit\" to leave %s\n", @context.ap_name 479 end 480 else 481 print "\n" 482 end 483 end 484 l 485 end 486 end 487 488 @scanner.each_top_level_statement do |line, line_no| 489 signal_status(:IN_EVAL) do 490 begin 491 line.untaint 492 @context.evaluate(line, line_no) 493 output_value if @context.echo? 494 exc = nil 495 rescue Interrupt => exc 496 rescue SystemExit, SignalException 497 raise 498 rescue Exception => exc 499 end 500 if exc 501 print exc.class, ": ", exc, "\n" 502 if exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ && 503 !(SyntaxError === exc) 504 irb_bug = true 505 else 506 irb_bug = false 507 end 508 509 messages = [] 510 lasts = [] 511 levels = 0 512 for m in exc.backtrace 513 m = @context.workspace.filter_backtrace(m) unless irb_bug 514 if m 515 if messages.size < @context.back_trace_limit 516 messages.push "\tfrom "+m 517 else 518 lasts.push "\tfrom "+m 519 if lasts.size > @context.back_trace_limit 520 lasts.shift 521 levels += 1 522 end 523 end 524 end 525 end 526 print messages.join("\n"), "\n" 527 unless lasts.empty? 528 printf "... %d levels...\n", levels if levels > 0 529 print lasts.join("\n") 530 end 531 print "Maybe IRB bug!\n" if irb_bug 532 end 533 if $SAFE > 2 534 abort "Error: irb does not work for $SAFE level higher than 2" 535 end 536 end 537 end 538 end 539 540 # Evaluates the given block using the given +path+ as the Context#irb_path 541 # and +name+ as the Context#irb_name. 542 # 543 # Used by the irb command +source+, see IRB@IRB+Sessions for more 544 # information. 545 def suspend_name(path = nil, name = nil) 546 @context.irb_path, back_path = path, @context.irb_path if path 547 @context.irb_name, back_name = name, @context.irb_name if name 548 begin 549 yield back_path, back_name 550 ensure 551 @context.irb_path = back_path if path 552 @context.irb_name = back_name if name 553 end 554 end 555 556 # Evaluates the given block using the given +workspace+ as the 557 # Context#workspace. 558 # 559 # Used by the irb command +irb_load+, see IRB@IRB+Sessions for more 560 # information. 561 def suspend_workspace(workspace) 562 @context.workspace, back_workspace = workspace, @context.workspace 563 begin 564 yield back_workspace 565 ensure 566 @context.workspace = back_workspace 567 end 568 end 569 570 # Evaluates the given block using the given +input_method+ as the 571 # Context#io. 572 # 573 # Used by the irb commands +source+ and +irb_load+, see IRB@IRB+Sessions 574 # for more information. 575 def suspend_input_method(input_method) 576 back_io = @context.io 577 @context.instance_eval{@io = input_method} 578 begin 579 yield back_io 580 ensure 581 @context.instance_eval{@io = back_io} 582 end 583 end 584 585 # Evaluates the given block using the given +context+ as the Context. 586 def suspend_context(context) 587 @context, back_context = context, @context 588 begin 589 yield back_context 590 ensure 591 @context = back_context 592 end 593 end 594 595 # Handler for the signal SIGINT, see Kernel#trap for more information. 596 def signal_handle 597 unless @context.ignore_sigint? 598 print "\nabort!\n" if @context.verbose? 599 exit 600 end 601 602 case @signal_status 603 when :IN_INPUT 604 print "^C\n" 605 raise RubyLex::TerminateLineInput 606 when :IN_EVAL 607 IRB.irb_abort(self) 608 when :IN_LOAD 609 IRB.irb_abort(self, LoadAbort) 610 when :IN_IRB 611 # ignore 612 else 613 # ignore other cases as well 614 end 615 end 616 617 # Evaluates the given block using the given +status+. 618 def signal_status(status) 619 return yield if @signal_status == :IN_LOAD 620 621 signal_status_back = @signal_status 622 @signal_status = status 623 begin 624 yield 625 ensure 626 @signal_status = signal_status_back 627 end 628 end 629 630 def prompt(prompt, ltype, indent, line_no) # :nodoc: 631 p = prompt.dup 632 p.gsub!(/%([0-9]+)?([a-zA-Z])/) do 633 case $2 634 when "N" 635 @context.irb_name 636 when "m" 637 @context.main.to_s 638 when "M" 639 @context.main.inspect 640 when "l" 641 ltype 642 when "i" 643 if $1 644 format("%" + $1 + "d", indent) 645 else 646 indent.to_s 647 end 648 when "n" 649 if $1 650 format("%" + $1 + "d", line_no) 651 else 652 line_no.to_s 653 end 654 when "%" 655 "%" 656 end 657 end 658 p 659 end 660 661 def output_value # :nodoc: 662 printf @context.return_format, @context.inspect_last_value 663 end 664 665 # Outputs the local variables to this current session, including 666 # #signal_status and #context, using IRB::Locale. 667 def inspect 668 ary = [] 669 for iv in instance_variables 670 case (iv = iv.to_s) 671 when "@signal_status" 672 ary.push format("%s=:%s", iv, @signal_status.id2name) 673 when "@context" 674 ary.push format("%s=%s", iv, eval(iv).__to_s__) 675 else 676 ary.push format("%s=%s", iv, eval(iv)) 677 end 678 end 679 format("#<%s: %s>", self.class, ary.join(", ")) 680 end 681 end 682 683 def @CONF.inspect 684 IRB.version unless self[:VERSION] 685 686 array = [] 687 for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name} 688 case k 689 when :MAIN_CONTEXT, :__TMP__EHV__ 690 array.push format("CONF[:%s]=...myself...", k.id2name) 691 when :PROMPT 692 s = v.collect{ 693 |kk, vv| 694 ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"} 695 format(":%s=>{%s}", kk.id2name, ss.join(", ")) 696 } 697 array.push format("CONF[:%s]={%s}", k.id2name, s.join(", ")) 698 else 699 array.push format("CONF[:%s]=%s", k.id2name, v.inspect) 700 end 701 end 702 array.join("\n") 703 end 704end 705