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
- #convert_invalid_byte_sequence(str) ⇒ Object
-
#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
464 465 466 467 468 469 |
# File 'lib/irb.rb', line 464 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
490 491 492 |
# File 'lib/irb.rb', line 490 def context @context end |
#scanner ⇒ Object
The lexer used by this irb session
492 493 494 |
# File 'lib/irb.rb', line 492 def scanner @scanner end |
Instance Method Details
#assignment_expression?(line) ⇒ Boolean
846 847 848 849 850 851 852 853 854 855 856 857 858 859 |
# File 'lib/irb.rb', line 846 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 |
#convert_invalid_byte_sequence(str) ⇒ Object
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
# File 'lib/irb.rb', line 593 def convert_invalid_byte_sequence(str) str = str.force_encoding(Encoding::ASCII_8BIT) conv = Encoding::Converter.new(Encoding::ASCII_8BIT, Encoding::UTF_8) dst = String.new begin ret = conv.primitive_convert(str, dst) case ret when :invalid_byte_sequence conv.insert_output(conf.primitive_errinfo[3].dump[1..-2]) redo when :undefined_conversion c = conv.primitive_errinfo[3].dup.force_encoding(conv.primitive_errinfo[1]) conv.insert_output(c.dump[1..-2]) redo when :incomplete_input conv.insert_output(conv.primitive_errinfo[3].dump[1..-2]) when :finished end break end while nil dst end |
#eval_input ⇒ Object
Evaluates input for this session.
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 563 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 |
# File 'lib/irb.rb', line 495 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" if @context.prompting? 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' if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty? IRB.set_measure_callback end if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty? result = nil last_proc = proc{ result = @context.evaluate(line, line_no, exception: exc) } IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) { |chain, item| _name, callback, arg = item proc { callback.(@context, line, line_no, arg, exception: exc) do chain.call end } }.call @context.set_last_value(result) else @context.evaluate(line, line_no, exception: exc) end 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) @context.workspace.local_variable_set(:_, exc) exc = nil end end end |
#handle_exception(exc) ⇒ Object
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 |
# File 'lib/irb.rb', line 616 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 exc.backtrace order = nil if '2.5.0' == RUBY_VERSION # Exception#full_message doesn't have keyword arguments. = exc. # the same of (highlight: true, order: bottom) order = :bottom elsif '2.5.1' <= RUBY_VERSION && RUBY_VERSION < '3.0.0' if STDOUT.tty? = exc.(order: :bottom) order = :bottom else = exc.(order: :top) order = :top end else # '3.0.0' <= RUBY_VERSION = exc.(order: :top) order = :top end = convert_invalid_byte_sequence() = .gsub(/((?:^\t.+$\n)+)/) { |m| case order when :top lines = m.split("\n") when :bottom lines = m.split("\n").reverse end unless irb_bug lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact if lines.size > @context.back_trace_limit omit = lines.size - @context.back_trace_limit lines = lines[0..(@context.back_trace_limit - 1)] lines << "\t... %d levels..." % omit end end lines = lines.reverse if order == :bottom lines.map{ |l| l + "\n" }.join } puts 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.
831 832 833 834 835 836 837 838 839 840 841 842 843 844 |
# File 'lib/irb.rb', line 831 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:
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 |
# File 'lib/irb.rb', line 796 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 = 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:
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 |
# File 'lib/irb.rb', line 757 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
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
# File 'lib/irb.rb', line 471 def run(conf = IRB.conf) conf[:IRB_RC].call(context) if conf[:IRB_RC] conf[:MAIN_CONTEXT] = context prev_trap = trap("SIGINT") do signal_handle end begin catch(:IRB_EXIT) do eval_input end ensure trap("SIGINT", prev_trap) conf[:AT_EXIT].each{|hook| hook.call} end end |
#signal_handle ⇒ Object
Handler for the signal SIGINT, see Kernel#trap for more information.
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 |
# File 'lib/irb.rb', line 723 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
.
745 746 747 748 749 750 751 752 753 754 755 |
# File 'lib/irb.rb', line 745 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.
713 714 715 716 717 718 719 720 |
# File 'lib/irb.rb', line 713 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.
702 703 704 705 706 707 708 709 710 |
# File 'lib/irb.rb', line 702 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.
672 673 674 675 676 677 678 679 680 681 |
# File 'lib/irb.rb', line 672 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.
688 689 690 691 692 693 694 695 |
# File 'lib/irb.rb', line 688 def suspend_workspace(workspace) @context.workspace, back_workspace = workspace, @context.workspace begin yield back_workspace ensure @context.workspace = back_workspace end end |