Class: IRB::Irb
Constant Summary collapse
- ASSIGNMENT_NODE_TYPES =
[ # Local, instance, global, class, constant, instance, and index assignment: # "foo = bar", # "@foo = bar", # "$foo = bar", # "@@foo = bar", # "::Foo = bar", # "a::Foo = bar", # "Foo = bar" # "foo.bar = 1" # "foo[1] = bar" :assign, # Operation assignment: # "foo += bar" # "foo -= bar" # "foo ||= bar" # "foo &&= bar" :opassign, # Multiple assignment: # "foo, bar = 1, 2 :massign, ]
- ATTR_TTY =
"\e[%sm"
- ATTR_PLAIN =
""
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the current context of this irb session.
-
#scanner ⇒ Object
The lexer used by this irb session.
Instance Method Summary collapse
- #assignment_expression?(line) ⇒ Boolean
-
#eval_input ⇒ Object
Evaluates input for this session.
- #handle_exception(exc) ⇒ Object
-
#initialize(workspace = nil, input_method = nil) ⇒ Irb
constructor
Creates a new irb session.
-
#inspect ⇒ Object
Outputs the local variables to this current session, including #signal_status and #context, using IRB::Locale.
-
#output_value(omit = false) ⇒ Object
:nodoc:.
-
#prompt(prompt, ltype, indent, line_no) ⇒ Object
:nodoc:.
- #run(conf = IRB.conf) ⇒ Object
-
#signal_handle ⇒ Object
Handler for the signal SIGINT, see Kernel#trap for more information.
-
#signal_status(status) ⇒ Object
Evaluates the given block using the given
status
. -
#suspend_context(context) ⇒ Object
Evaluates the given block using the given
context
as the Context. -
#suspend_input_method(input_method) ⇒ Object
Evaluates the given block using the given
input_method
as the Context#io. -
#suspend_name(path = nil, name = nil) ⇒ Object
Evaluates the given block using the given
path
as the Context#irb_path andname
as the Context#irb_name. -
#suspend_workspace(workspace) ⇒ Object
Evaluates the given block using the given
workspace
as the Context#workspace.
Constructor Details
#initialize(workspace = nil, input_method = nil) ⇒ Irb
Creates a new irb session
455 456 457 458 459 460 |
# File 'lib/irb.rb', line 455 def initialize(workspace = nil, input_method = nil) @context = Context.new(self, workspace, input_method) @context.main.extend ExtendCommandBundle @signal_status = :IN_IRB @scanner = RubyLex.new end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the current context of this irb session
480 481 482 |
# File 'lib/irb.rb', line 480 def context @context end |
#scanner ⇒ Object
The lexer used by this irb session
482 483 484 |
# File 'lib/irb.rb', line 482 def scanner @scanner end |
Instance Method Details
#assignment_expression?(line) ⇒ Boolean
799 800 801 802 803 804 805 806 807 808 809 810 811 812 |
# File 'lib/irb.rb', line 799 def assignment_expression?(line) # Try to parse the line and check if the last of possibly multiple # expressions is an assignment type. # If the expression is invalid, Ripper.sexp should return nil which will # result in false being returned. Any valid expression should return an # s-expression where the second selement of the top level array is an # array of parsed expressions. The first element of each expression is the # expression's type. verbose, $VERBOSE = $VERBOSE, nil result = ASSIGNMENT_NODE_TYPES.include?(Ripper.sexp(line)&.dig(1,-1,0)) $VERBOSE = verbose result end |
#eval_input ⇒ Object
Evaluates input for this session.
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
# File 'lib/irb.rb', line 485 def eval_input exc = nil @scanner.set_prompt do |ltype, indent, continue, line_no| if ltype f = @context.prompt_s elsif continue f = @context.prompt_c elsif indent > 0 f = @context.prompt_n else f = @context.prompt_i end f = "" unless f if @context.prompting? @context.io.prompt = p = prompt(f, ltype, indent, line_no) else @context.io.prompt = p = "" end if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent) unless ltype prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size + indent * 2 - p.size ind += 2 if continue @context.io.prompt = p + " " * ind if ind > 0 end end @context.io.prompt end @scanner.set_input(@context.io) do signal_status(:IN_INPUT) do if l = @context.io.gets print l if @context.verbose? else if @context.ignore_eof? and @context.io.readable_after_eof? l = "\n" if @context.verbose? printf "Use \"exit\" to leave %s\n", @context.ap_name end else print "\n" end end l end end @scanner.set_auto_indent(@context) if @context.auto_indent_mode @scanner.each_top_level_statement do |line, line_no| signal_status(:IN_EVAL) do begin line.untaint if RUBY_VERSION < '2.7' @context.evaluate(line, line_no, exception: exc) if @context.echo? if assignment_expression?(line) if @context.echo_on_assignment? output_value(@context.echo_on_assignment? == :truncate) end else output_value end end rescue Interrupt => exc rescue SystemExit, SignalException raise rescue Exception => exc else exc = nil next end handle_exception(exc) end end end |
#handle_exception(exc) ⇒ Object
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 |
# File 'lib/irb.rb', line 564 def handle_exception(exc) if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ && !(SyntaxError === exc) && !(EncodingError === exc) # The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno. irb_bug = true else irb_bug = false end if STDOUT.tty? attr = ATTR_TTY print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n" else attr = ATTR_PLAIN end = [] lasts = [] levels = 0 if exc.backtrace count = 0 exc.backtrace.each do |m| m = @context.workspace.filter_backtrace(m) or next unless irb_bug count += 1 if attr == ATTR_TTY m = sprintf("%9d: from %s", count, m) else m = "\tfrom #{m}" end if .size < @context.back_trace_limit .push(m) elsif lasts.size < @context.back_trace_limit lasts.push(m).shift levels += 1 end end end if attr == ATTR_TTY unless lasts.empty? puts lasts.reverse printf "... %d levels...\n", levels if levels > 0 end puts .reverse end m = exc.to_s.split(/\n/) print "#{attr[1]}#{exc.class} (#{attr[4]}#{m.shift}#{attr[0, 1]})#{attr[]}\n" puts m.map {|s| "#{attr[1]}#{s}#{attr[]}\n"} if attr == ATTR_PLAIN puts unless lasts.empty? puts lasts printf "... %d levels...\n", levels if levels > 0 end end print "Maybe IRB bug!\n" if irb_bug end |
#inspect ⇒ Object
Outputs the local variables to this current session, including #signal_status and #context, using IRB::Locale.
784 785 786 787 788 789 790 791 792 793 794 795 796 797 |
# File 'lib/irb.rb', line 784 def inspect ary = [] for iv in instance_variables case (iv = iv.to_s) when "@signal_status" ary.push format("%s=:%s", iv, @signal_status.id2name) when "@context" ary.push format("%s=%s", iv, eval(iv).__to_s__) else ary.push format("%s=%s", iv, eval(iv)) end end format("#<%s: %s>", self.class, ary.join(", ")) end |
#output_value(omit = false) ⇒ Object
:nodoc:
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 |
# File 'lib/irb.rb', line 749 def output_value(omit = false) # :nodoc: str = @context.inspect_last_value multiline_p = str.include?("\n") if omit winwidth = @context.io.winsize.last if multiline_p first_line = str.split("\n").first result = @context.newline_before_multiline_output? ? (@context.return_format % first_line) : first_line output_width = Reline::Unicode.calculate_width(result, true) diff_size = output_width - Reline::Unicode.calculate_width(first_line, true) if diff_size.positive? and output_width > winwidth lines, _ = Reline::Unicode.split_by_width(first_line, winwidth - diff_size - 3) str = "%s...\e[0m" % lines.first multiline_p = false else str.gsub!(/(\A.*?\n).*/m, "\\1...") end else output_width = Reline::Unicode.calculate_width(@context.return_format % str, true) diff_size = output_width - Reline::Unicode.calculate_width(str, true) if diff_size.positive? and output_width > winwidth lines, _ = Reline::Unicode.split_by_width(str, winwidth - diff_size - 3) str = "%s...\e[0m" % lines.first end end end if multiline_p && @context.newline_before_multiline_output? printf @context.return_format, "\n#{str}" else printf @context.return_format, str end end |
#prompt(prompt, ltype, indent, line_no) ⇒ Object
:nodoc:
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 |
# File 'lib/irb.rb', line 710 def prompt(prompt, ltype, indent, line_no) # :nodoc: p = prompt.dup p.gsub!(/%([0-9]+)?([a-zA-Z])/) do case $2 when "N" @context.irb_name when "m" @context.main.to_s when "M" @context.main.inspect when "l" ltype when "i" if indent < 0 if $1 "-".rjust($1.to_i) else "-" end else if $1 format("%" + $1 + "d", indent) else indent.to_s end end when "n" if $1 format("%" + $1 + "d", line_no) else line_no.to_s end when "%" "%" end end p end |
#run(conf = IRB.conf) ⇒ Object
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
# File 'lib/irb.rb', line 462 def run(conf = IRB.conf) conf[:IRB_RC].call(context) if conf[:IRB_RC] conf[:MAIN_CONTEXT] = context trap("SIGINT") do signal_handle end begin catch(:IRB_EXIT) do eval_input end ensure conf[:AT_EXIT].each{|hook| hook.call} end end |
#signal_handle ⇒ Object
Handler for the signal SIGINT, see Kernel#trap for more information.
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 |
# File 'lib/irb.rb', line 676 def signal_handle unless @context.ignore_sigint? print "\nabort!\n" if @context.verbose? exit end case @signal_status when :IN_INPUT print "^C\n" raise RubyLex::TerminateLineInput when :IN_EVAL IRB.irb_abort(self) when :IN_LOAD IRB.irb_abort(self, LoadAbort) when :IN_IRB # ignore else # ignore other cases as well end end |
#signal_status(status) ⇒ Object
Evaluates the given block using the given status
.
698 699 700 701 702 703 704 705 706 707 708 |
# File 'lib/irb.rb', line 698 def signal_status(status) return yield if @signal_status == :IN_LOAD signal_status_back = @signal_status @signal_status = status begin yield ensure @signal_status = signal_status_back end end |
#suspend_context(context) ⇒ Object
Evaluates the given block using the given context
as the Context.
666 667 668 669 670 671 672 673 |
# File 'lib/irb.rb', line 666 def suspend_context(context) @context, back_context = context, @context begin yield back_context ensure @context = back_context end end |
#suspend_input_method(input_method) ⇒ Object
Evaluates the given block using the given input_method
as the Context#io.
Used by the irb commands source
and irb_load
, see IRB@IRB+Sessions for more information.
655 656 657 658 659 660 661 662 663 |
# File 'lib/irb.rb', line 655 def suspend_input_method(input_method) back_io = @context.io @context.instance_eval{@io = input_method} begin yield back_io ensure @context.instance_eval{@io = back_io} end end |
#suspend_name(path = nil, name = nil) ⇒ Object
Evaluates the given block using the given path
as the Context#irb_path and name
as the Context#irb_name.
Used by the irb command source
, see IRB@IRB+Sessions for more information.
625 626 627 628 629 630 631 632 633 634 |
# File 'lib/irb.rb', line 625 def suspend_name(path = nil, name = nil) @context.irb_path, back_path = path, @context.irb_path if path @context.irb_name, back_name = name, @context.irb_name if name begin yield back_path, back_name ensure @context.irb_path = back_path if path @context.irb_name = back_name if name end end |
#suspend_workspace(workspace) ⇒ Object
Evaluates the given block using the given workspace
as the Context#workspace.
Used by the irb command irb_load
, see IRB@IRB+Sessions for more information.
641 642 643 644 645 646 647 648 |
# File 'lib/irb.rb', line 641 def suspend_workspace(workspace) @context.workspace, back_workspace = workspace, @context.workspace begin yield back_workspace ensure @context.workspace = back_workspace end end |