[ruby/irb] Group class methods under `class << self`

(https://github.com/ruby/irb/pull/981)

https://github.com/ruby/irb/commit/cdaa356df2
This commit is contained in:
Stan Lo 2024-07-16 16:58:08 +01:00 коммит произвёл git
Родитель 4fe3082b63
Коммит 4a4e1bf357
11 изменённых файлов: 388 добавлений и 373 удалений

Просмотреть файл

@ -880,40 +880,42 @@ module IRB
# An exception raised by IRB.irb_abort # An exception raised by IRB.irb_abort
class Abort < Exception;end class Abort < Exception;end
# The current IRB::Context of the session, see IRB.conf class << self
# # The current IRB::Context of the session, see IRB.conf
# irb #
# irb(main):001:0> IRB.CurrentContext.irb_name = "foo" # irb
# foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo" # irb(main):001:0> IRB.CurrentContext.irb_name = "foo"
def IRB.CurrentContext # :nodoc: # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo"
IRB.conf[:MAIN_CONTEXT] def CurrentContext # :nodoc:
end conf[:MAIN_CONTEXT]
# Initializes IRB and creates a new Irb.irb object at the `TOPLEVEL_BINDING`
def IRB.start(ap_path = nil)
STDOUT.sync = true
$0 = File::basename(ap_path, ".rb") if ap_path
IRB.setup(ap_path)
if @CONF[:SCRIPT]
irb = Irb.new(nil, @CONF[:SCRIPT])
else
irb = Irb.new
end end
irb.run(@CONF)
end
# Quits irb # Initializes IRB and creates a new Irb.irb object at the `TOPLEVEL_BINDING`
def IRB.irb_exit(*) # :nodoc: def start(ap_path = nil)
throw :IRB_EXIT, false STDOUT.sync = true
end $0 = File::basename(ap_path, ".rb") if ap_path
# Aborts then interrupts irb. setup(ap_path)
#
# Will raise an Abort exception, or the given `exception`. if @CONF[:SCRIPT]
def IRB.irb_abort(irb, exception = Abort) # :nodoc: irb = Irb.new(nil, @CONF[:SCRIPT])
irb.context.thread.raise exception, "abort then interrupt!" else
irb = Irb.new
end
irb.run(@CONF)
end
# Quits irb
def irb_exit(*) # :nodoc:
throw :IRB_EXIT, false
end
# Aborts then interrupts irb.
#
# Will raise an Abort exception, or the given `exception`.
def irb_abort(irb, exception = Abort) # :nodoc:
irb.context.thread.raise exception, "abort then interrupt!"
end
end end
class Irb class Irb

Просмотреть файл

@ -10,8 +10,10 @@ module IRB
module Command module Command
class CommandArgumentError < StandardError; end class CommandArgumentError < StandardError; end
def self.extract_ruby_args(*args, **kwargs) class << self
throw :EXTRACT_RUBY_ARGS, [args, kwargs] def extract_ruby_args(*args, **kwargs)
throw :EXTRACT_RUBY_ARGS, [args, kwargs]
end
end end
class Base class Base
@ -31,6 +33,12 @@ module IRB
@help_message @help_message
end end
def execute(irb_context, arg)
new(irb_context).execute(arg)
rescue CommandArgumentError => e
puts e.message
end
private private
def highlight(text) def highlight(text)
@ -38,12 +46,6 @@ module IRB
end end
end end
def self.execute(irb_context, arg)
new(irb_context).execute(arg)
rescue CommandArgumentError => e
puts e.message
end
def initialize(irb_context) def initialize(irb_context)
@irb_context = irb_context @irb_context = irb_context
end end

Просмотреть файл

@ -58,13 +58,15 @@ module IRB
end end
class DebugCommand < Debug class DebugCommand < Debug
def self.category class << self
"Debugging" def category
end "Debugging"
end
def self.description def description
command_name = self.name.split("::").last.downcase command_name = self.name.split("::").last.downcase
"Start the debugger of debug.gem and run its `#{command_name}` command." "Start the debugger of debug.gem and run its `#{command_name}` command."
end
end end
end end
end end

Просмотреть файл

@ -259,10 +259,12 @@ module IRB
# Deprecated. Doesn't have any effect. # Deprecated. Doesn't have any effect.
@EXTEND_COMMANDS = [] @EXTEND_COMMANDS = []
# Drepcated. Use Command.regiser instead. class << self
def self.def_extend_command(cmd_name, cmd_class, _, *aliases) # Drepcated. Use Command.regiser instead.
Command._register_with_aliases(cmd_name, cmd_class, *aliases) def def_extend_command(cmd_name, cmd_class, _, *aliases)
Command.class_variable_set(:@@command_override_policies, nil) Command._register_with_aliases(cmd_name, cmd_class, *aliases)
Command.class_variable_set(:@@command_override_policies, nil)
end
end end
end end
end end

Просмотреть файл

@ -171,11 +171,13 @@ module IRB
end end
class ReadlineInputMethod < StdioInputMethod class ReadlineInputMethod < StdioInputMethod
def self.initialize_readline class << self
require "readline" def initialize_readline
rescue LoadError require "readline"
else rescue LoadError
include ::Readline else
include ::Readline
end
end end
include HistorySavingAbility include HistorySavingAbility

Просмотреть файл

@ -6,7 +6,6 @@
module IRB # :nodoc: module IRB # :nodoc:
# Convenience method to create a new Inspector, using the given +inspect+ # Convenience method to create a new Inspector, using the given +inspect+
# proc, and optional +init+ proc and passes them to Inspector.new # proc, and optional +init+ proc and passes them to Inspector.new
# #
@ -43,38 +42,40 @@ module IRB # :nodoc:
# +:marshal+:: Using Marshal.dump # +:marshal+:: Using Marshal.dump
INSPECTORS = {} INSPECTORS = {}
# Determines the inspector to use where +inspector+ is one of the keys passed class << self
# during inspector definition. # Determines the inspector to use where +inspector+ is one of the keys passed
def self.keys_with_inspector(inspector) # during inspector definition.
INSPECTORS.select{|k, v| v == inspector}.collect{|k, v| k} def keys_with_inspector(inspector)
end INSPECTORS.select{|k, v| v == inspector}.collect{|k, v| k}
# Example
#
# Inspector.def_inspector(key, init_p=nil){|v| v.inspect}
# Inspector.def_inspector([key1,..], init_p=nil){|v| v.inspect}
# Inspector.def_inspector(key, inspector)
# Inspector.def_inspector([key1,...], inspector)
def self.def_inspector(key, arg=nil, &block)
if block_given?
inspector = IRB::Inspector(block, arg)
else
inspector = arg
end end
case key # Example
when Array #
for k in key # Inspector.def_inspector(key, init_p=nil){|v| v.inspect}
def_inspector(k, inspector) # Inspector.def_inspector([key1,..], init_p=nil){|v| v.inspect}
# Inspector.def_inspector(key, inspector)
# Inspector.def_inspector([key1,...], inspector)
def def_inspector(key, arg=nil, &block)
if block_given?
inspector = IRB::Inspector(block, arg)
else
inspector = arg
end
case key
when Array
for k in key
def_inspector(k, inspector)
end
when Symbol
INSPECTORS[key] = inspector
INSPECTORS[key.to_s] = inspector
when String
INSPECTORS[key] = inspector
INSPECTORS[key.intern] = inspector
else
INSPECTORS[key] = inspector
end end
when Symbol
INSPECTORS[key] = inspector
INSPECTORS[key.to_s] = inspector
when String
INSPECTORS[key] = inspector
INSPECTORS[key.intern] = inspector
else
INSPECTORS[key] = inspector
end end
end end

Просмотреть файл

@ -3,235 +3,237 @@ module IRB
module NestingParser module NestingParser
IGNORE_TOKENS = %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end] IGNORE_TOKENS = %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end]
# Scan each token and call the given block with array of token and other information for parsing class << self
def self.scan_opens(tokens) # Scan each token and call the given block with array of token and other information for parsing
opens = [] def scan_opens(tokens)
pending_heredocs = [] opens = []
first_token_on_line = true pending_heredocs = []
tokens.each do |t| first_token_on_line = true
skip = false tokens.each do |t|
last_tok, state, args = opens.last skip = false
case state last_tok, state, args = opens.last
when :in_alias_undef case state
skip = t.event == :on_kw when :in_alias_undef
when :in_unquoted_symbol skip = t.event == :on_kw
unless IGNORE_TOKENS.include?(t.event) when :in_unquoted_symbol
opens.pop unless IGNORE_TOKENS.include?(t.event)
skip = true opens.pop
end skip = true
when :in_lambda_head end
opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do') when :in_lambda_head
when :in_method_head opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do')
unless IGNORE_TOKENS.include?(t.event) when :in_method_head
next_args = [] unless IGNORE_TOKENS.include?(t.event)
body = nil next_args = []
if args.include?(:receiver) body = nil
case t.event if args.include?(:receiver)
when :on_lparen, :on_ivar, :on_gvar, :on_cvar case t.event
# def (receiver). | def @ivar. | def $gvar. | def @@cvar. when :on_lparen, :on_ivar, :on_gvar, :on_cvar
next_args << :dot # def (receiver). | def @ivar. | def $gvar. | def @@cvar.
when :on_kw next_args << :dot
case t.tok when :on_kw
when 'self', 'true', 'false', 'nil' case t.tok
# def self(arg) | def self. when 'self', 'true', 'false', 'nil'
next_args.push(:arg, :dot) # def self(arg) | def self.
else next_args.push(:arg, :dot)
# def if(arg) else
# def if(arg)
skip = true
next_args << :arg
end
when :on_op, :on_backtick
# def +(arg)
skip = true skip = true
next_args << :arg next_args << :arg
when :on_ident, :on_const
# def a(arg) | def a.
next_args.push(:arg, :dot)
end end
when :on_op, :on_backtick
# def +(arg)
skip = true
next_args << :arg
when :on_ident, :on_const
# def a(arg) | def a.
next_args.push(:arg, :dot)
end end
end if args.include?(:dot)
if args.include?(:dot) # def receiver.name
# def receiver.name next_args << :name if t.event == :on_period || (t.event == :on_op && t.tok == '::')
next_args << :name if t.event == :on_period || (t.event == :on_op && t.tok == '::')
end
if args.include?(:name)
if %i[on_ident on_const on_op on_kw on_backtick].include?(t.event)
# def name(arg) | def receiver.name(arg)
next_args << :arg
skip = true
end end
end if args.include?(:name)
if args.include?(:arg) if %i[on_ident on_const on_op on_kw on_backtick].include?(t.event)
case t.event # def name(arg) | def receiver.name(arg)
when :on_nl, :on_semicolon next_args << :arg
# def receiver.f; skip = true
body = :normal end
when :on_lparen end
# def receiver.f() if args.include?(:arg)
next_args << :eq case t.event
else when :on_nl, :on_semicolon
# def receiver.f;
body = :normal
when :on_lparen
# def receiver.f()
next_args << :eq
else
if t.event == :on_op && t.tok == '='
# def receiver.f =
body = :oneliner
else
# def receiver.f arg
next_args << :arg_without_paren
end
end
end
if args.include?(:eq)
if t.event == :on_op && t.tok == '=' if t.event == :on_op && t.tok == '='
# def receiver.f =
body = :oneliner body = :oneliner
else else
# def receiver.f arg body = :normal
end
end
if args.include?(:arg_without_paren)
if %i[on_semicolon on_nl].include?(t.event)
# def f a;
body = :normal
else
# def f a, b
next_args << :arg_without_paren next_args << :arg_without_paren
end end
end end
end if body == :oneliner
if args.include?(:eq) opens.pop
if t.event == :on_op && t.tok == '=' elsif body
body = :oneliner opens[-1] = [last_tok, nil]
else else
body = :normal opens[-1] = [last_tok, :in_method_head, next_args]
end end
end end
if args.include?(:arg_without_paren) when :in_for_while_until_condition
if %i[on_semicolon on_nl].include?(t.event) if t.event == :on_semicolon || t.event == :on_nl || (t.event == :on_kw && t.tok == 'do')
# def f a; skip = true if t.event == :on_kw && t.tok == 'do'
body = :normal
else
# def f a, b
next_args << :arg_without_paren
end
end
if body == :oneliner
opens.pop
elsif body
opens[-1] = [last_tok, nil] opens[-1] = [last_tok, nil]
else
opens[-1] = [last_tok, :in_method_head, next_args]
end end
end end
when :in_for_while_until_condition
if t.event == :on_semicolon || t.event == :on_nl || (t.event == :on_kw && t.tok == 'do')
skip = true if t.event == :on_kw && t.tok == 'do'
opens[-1] = [last_tok, nil]
end
end
unless skip unless skip
case t.event case t.event
when :on_kw when :on_kw
case t.tok case t.tok
when 'begin', 'class', 'module', 'do', 'case' when 'begin', 'class', 'module', 'do', 'case'
opens << [t, nil]
when 'end'
opens.pop
when 'def'
opens << [t, :in_method_head, [:receiver, :name]]
when 'if', 'unless'
unless t.state.allbits?(Ripper::EXPR_LABEL)
opens << [t, nil] opens << [t, nil]
end when 'end'
when 'while', 'until' opens.pop
unless t.state.allbits?(Ripper::EXPR_LABEL) when 'def'
opens << [t, :in_method_head, [:receiver, :name]]
when 'if', 'unless'
unless t.state.allbits?(Ripper::EXPR_LABEL)
opens << [t, nil]
end
when 'while', 'until'
unless t.state.allbits?(Ripper::EXPR_LABEL)
opens << [t, :in_for_while_until_condition]
end
when 'ensure', 'rescue'
unless t.state.allbits?(Ripper::EXPR_LABEL)
opens.pop
opens << [t, nil]
end
when 'alias'
opens << [t, :in_alias_undef, 2]
when 'undef'
opens << [t, :in_alias_undef, 1]
when 'elsif', 'else', 'when'
opens.pop
opens << [t, nil]
when 'for'
opens << [t, :in_for_while_until_condition] opens << [t, :in_for_while_until_condition]
when 'in'
if last_tok&.event == :on_kw && %w[case in].include?(last_tok.tok) && first_token_on_line
opens.pop
opens << [t, nil]
end
end end
when 'ensure', 'rescue' when :on_tlambda
unless t.state.allbits?(Ripper::EXPR_LABEL) opens << [t, :in_lambda_head]
opens.pop when :on_lparen, :on_lbracket, :on_lbrace, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
opens << [t, nil] opens << [t, nil]
end when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end
when 'alias'
opens << [t, :in_alias_undef, 2]
when 'undef'
opens << [t, :in_alias_undef, 1]
when 'elsif', 'else', 'when'
opens.pop opens.pop
when :on_heredoc_beg
pending_heredocs << t
when :on_heredoc_end
opens.pop
when :on_backtick
opens << [t, nil] if t.state.allbits?(Ripper::EXPR_BEG)
when :on_tstring_beg, :on_words_beg, :on_qwords_beg, :on_symbols_beg, :on_qsymbols_beg, :on_regexp_beg
opens << [t, nil] opens << [t, nil]
when 'for' when :on_tstring_end, :on_regexp_end, :on_label_end
opens << [t, :in_for_while_until_condition] opens.pop
when 'in' when :on_symbeg
if last_tok&.event == :on_kw && %w[case in].include?(last_tok.tok) && first_token_on_line if t.tok == ':'
opens.pop opens << [t, :in_unquoted_symbol]
else
opens << [t, nil] opens << [t, nil]
end end
end end
when :on_tlambda end
opens << [t, :in_lambda_head] if t.event == :on_nl || t.event == :on_semicolon
when :on_lparen, :on_lbracket, :on_lbrace, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg first_token_on_line = true
opens << [t, nil] elsif t.event != :on_sp
when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end first_token_on_line = false
opens.pop end
when :on_heredoc_beg if pending_heredocs.any? && t.tok.include?("\n")
pending_heredocs << t pending_heredocs.reverse_each { |t| opens << [t, nil] }
when :on_heredoc_end pending_heredocs = []
opens.pop end
when :on_backtick if opens.last && opens.last[1] == :in_alias_undef && !IGNORE_TOKENS.include?(t.event) && t.event != :on_heredoc_end
opens << [t, nil] if t.state.allbits?(Ripper::EXPR_BEG) tok, state, arg = opens.pop
when :on_tstring_beg, :on_words_beg, :on_qwords_beg, :on_symbols_beg, :on_qsymbols_beg, :on_regexp_beg opens << [tok, state, arg - 1] if arg >= 1
opens << [t, nil] end
when :on_tstring_end, :on_regexp_end, :on_label_end yield t, opens if block_given?
opens.pop end
when :on_symbeg opens.map(&:first) + pending_heredocs.reverse
if t.tok == ':' end
opens << [t, :in_unquoted_symbol]
else def open_tokens(tokens)
opens << [t, nil] # scan_opens without block will return a list of open tokens at last token position
scan_opens(tokens)
end
# Calculates token information [line_tokens, prev_opens, next_opens, min_depth] for each line.
# Example code
# ["hello
# world"+(
# First line
# line_tokens: [[lbracket, '['], [tstring_beg, '"'], [tstring_content("hello\nworld"), "hello\n"]]
# prev_opens: []
# next_tokens: [lbracket, tstring_beg]
# min_depth: 0 (minimum at beginning of line)
# Second line
# line_tokens: [[tstring_content("hello\nworld"), "world"], [tstring_end, '"'], [op, '+'], [lparen, '(']]
# prev_opens: [lbracket, tstring_beg]
# next_tokens: [lbracket, lparen]
# min_depth: 1 (minimum just after tstring_end)
def parse_by_line(tokens)
line_tokens = []
prev_opens = []
min_depth = 0
output = []
last_opens = scan_opens(tokens) do |t, opens|
depth = t == opens.last&.first ? opens.size - 1 : opens.size
min_depth = depth if depth < min_depth
if t.tok.include?("\n")
t.tok.each_line do |line|
line_tokens << [t, line]
next if line[-1] != "\n"
next_opens = opens.map(&:first)
output << [line_tokens, prev_opens, next_opens, min_depth]
prev_opens = next_opens
min_depth = prev_opens.size
line_tokens = []
end end
else
line_tokens << [t, t.tok]
end end
end end
if t.event == :on_nl || t.event == :on_semicolon output << [line_tokens, prev_opens, last_opens, min_depth] if line_tokens.any?
first_token_on_line = true output
elsif t.event != :on_sp
first_token_on_line = false
end
if pending_heredocs.any? && t.tok.include?("\n")
pending_heredocs.reverse_each { |t| opens << [t, nil] }
pending_heredocs = []
end
if opens.last && opens.last[1] == :in_alias_undef && !IGNORE_TOKENS.include?(t.event) && t.event != :on_heredoc_end
tok, state, arg = opens.pop
opens << [tok, state, arg - 1] if arg >= 1
end
yield t, opens if block_given?
end end
opens.map(&:first) + pending_heredocs.reverse
end
def self.open_tokens(tokens)
# scan_opens without block will return a list of open tokens at last token position
scan_opens(tokens)
end
# Calculates token information [line_tokens, prev_opens, next_opens, min_depth] for each line.
# Example code
# ["hello
# world"+(
# First line
# line_tokens: [[lbracket, '['], [tstring_beg, '"'], [tstring_content("hello\nworld"), "hello\n"]]
# prev_opens: []
# next_tokens: [lbracket, tstring_beg]
# min_depth: 0 (minimum at beginning of line)
# Second line
# line_tokens: [[tstring_content("hello\nworld"), "world"], [tstring_end, '"'], [op, '+'], [lparen, '(']]
# prev_opens: [lbracket, tstring_beg]
# next_tokens: [lbracket, lparen]
# min_depth: 1 (minimum just after tstring_end)
def self.parse_by_line(tokens)
line_tokens = []
prev_opens = []
min_depth = 0
output = []
last_opens = scan_opens(tokens) do |t, opens|
depth = t == opens.last&.first ? opens.size - 1 : opens.size
min_depth = depth if depth < min_depth
if t.tok.include?("\n")
t.tok.each_line do |line|
line_tokens << [t, line]
next if line[-1] != "\n"
next_opens = opens.map(&:first)
output << [line_tokens, prev_opens, next_opens, min_depth]
prev_opens = next_opens
min_depth = prev_opens.size
line_tokens = []
end
else
line_tokens << [t, t.tok]
end
end
output << [line_tokens, prev_opens, last_opens, min_depth] if line_tokens.any?
output
end end
end end
end end

Просмотреть файл

@ -36,29 +36,6 @@ module IRB
:massign, :massign,
] ]
class TerminateLineInput < StandardError
def initialize
super("Terminate Line Input")
end
end
def self.compile_with_errors_suppressed(code, line_no: 1)
begin
result = yield code, line_no
rescue ArgumentError
# Ruby can issue an error for the code if there is an
# incomplete magic comment for encoding in it. Force an
# expression with a new line before the code in this
# case to prevent magic comment handling. To make sure
# line numbers in the lexed code remain the same,
# decrease the line number by one.
code = ";\n#{code}"
line_no -= 1
result = yield code, line_no
end
result
end
ERROR_TOKENS = [ ERROR_TOKENS = [
:on_parse_error, :on_parse_error,
:compile_error, :compile_error,
@ -68,70 +45,102 @@ module IRB
:on_param_error :on_param_error
] ]
def self.generate_local_variables_assign_code(local_variables) LTYPE_TOKENS = %i[
"#{local_variables.join('=')}=nil;" unless local_variables.empty? on_heredoc_beg on_tstring_beg
on_regexp_beg on_symbeg on_backtick
on_symbols_beg on_qsymbols_beg
on_words_beg on_qwords_beg
]
class TerminateLineInput < StandardError
def initialize
super("Terminate Line Input")
end
end end
# Some part of the code is not included in Ripper's token. class << self
# Example: DATA part, token after heredoc_beg when heredoc has unclosed embexpr. def compile_with_errors_suppressed(code, line_no: 1)
# With interpolated tokens, tokens.map(&:tok).join will be equal to code. begin
def self.interpolate_ripper_ignored_tokens(code, tokens) result = yield code, line_no
line_positions = [0] rescue ArgumentError
code.lines.each do |line| # Ruby can issue an error for the code if there is an
line_positions << line_positions.last + line.bytesize # incomplete magic comment for encoding in it. Force an
# expression with a new line before the code in this
# case to prevent magic comment handling. To make sure
# line numbers in the lexed code remain the same,
# decrease the line number by one.
code = ";\n#{code}"
line_no -= 1
result = yield code, line_no
end
result
end end
prev_byte_pos = 0
interpolated = [] def generate_local_variables_assign_code(local_variables)
prev_line = 1 "#{local_variables.join('=')}=nil;" unless local_variables.empty?
tokens.each do |t| end
line, col = t.pos
byte_pos = line_positions[line - 1] + col # Some part of the code is not included in Ripper's token.
if prev_byte_pos < byte_pos # Example: DATA part, token after heredoc_beg when heredoc has unclosed embexpr.
tok = code.byteslice(prev_byte_pos...byte_pos) # With interpolated tokens, tokens.map(&:tok).join will be equal to code.
def interpolate_ripper_ignored_tokens(code, tokens)
line_positions = [0]
code.lines.each do |line|
line_positions << line_positions.last + line.bytesize
end
prev_byte_pos = 0
interpolated = []
prev_line = 1
tokens.each do |t|
line, col = t.pos
byte_pos = line_positions[line - 1] + col
if prev_byte_pos < byte_pos
tok = code.byteslice(prev_byte_pos...byte_pos)
pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
prev_line += tok.count("\n")
end
interpolated << t
prev_byte_pos = byte_pos + t.tok.bytesize
prev_line += t.tok.count("\n")
end
if prev_byte_pos < code.bytesize
tok = code.byteslice(prev_byte_pos..)
pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]] pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0) interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
prev_line += tok.count("\n")
end end
interpolated << t interpolated
prev_byte_pos = byte_pos + t.tok.bytesize
prev_line += t.tok.count("\n")
end
if prev_byte_pos < code.bytesize
tok = code.byteslice(prev_byte_pos..)
pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
end
interpolated
end
def self.ripper_lex_without_warning(code, local_variables: [])
verbose, $VERBOSE = $VERBOSE, nil
lvars_code = generate_local_variables_assign_code(local_variables)
original_code = code
if lvars_code
code = "#{lvars_code}\n#{code}"
line_no = 0
else
line_no = 1
end end
compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no| def ripper_lex_without_warning(code, local_variables: [])
lexer = Ripper::Lexer.new(inner_code, '-', line_no) verbose, $VERBOSE = $VERBOSE, nil
tokens = [] lvars_code = generate_local_variables_assign_code(local_variables)
lexer.scan.each do |t| original_code = code
next if t.pos.first == 0 if lvars_code
prev_tk = tokens.last code = "#{lvars_code}\n#{code}"
position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize line_no = 0
if position_overlapped else
tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event) line_no = 1
else end
tokens << t
compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
lexer = Ripper::Lexer.new(inner_code, '-', line_no)
tokens = []
lexer.scan.each do |t|
next if t.pos.first == 0
prev_tk = tokens.last
position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
if position_overlapped
tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event)
else
tokens << t
end
end end
interpolate_ripper_ignored_tokens(original_code, tokens)
end end
interpolate_ripper_ignored_tokens(original_code, tokens) ensure
$VERBOSE = verbose
end end
ensure
$VERBOSE = verbose
end end
def check_code_state(code, local_variables:) def check_code_state(code, local_variables:)
@ -391,13 +400,6 @@ module IRB
end end
end end
LTYPE_TOKENS = %i[
on_heredoc_beg on_tstring_beg
on_regexp_beg on_symbeg on_backtick
on_symbols_beg on_qsymbols_beg
on_words_beg on_qwords_beg
]
def ltype_from_open_tokens(opens) def ltype_from_open_tokens(opens)
start_token = opens.reverse_each.find do |tok| start_token = opens.reverse_each.find do |tok|
LTYPE_TOKENS.include?(tok.event) LTYPE_TOKENS.include?(tok.event)

Просмотреть файл

@ -176,11 +176,13 @@ EOF
end end
module HelpersContainer module HelpersContainer
def self.install_helper_methods class << self
HelperMethod.helper_methods.each do |name, helper_method_class| def install_helper_methods
define_method name do |*args, **opts, &block| HelperMethod.helper_methods.each do |name, helper_method_class|
helper_method_class.instance.execute(*args, **opts, &block) define_method name do |*args, **opts, &block|
end unless method_defined?(name) helper_method_class.instance.execute(*args, **opts, &block)
end unless method_defined?(name)
end
end end
end end

Просмотреть файл

@ -28,7 +28,6 @@ module TestIRB
restore_encodings restore_encodings
end end
def test_eval_input def test_eval_input
verbose, $VERBOSE = $VERBOSE, nil verbose, $VERBOSE = $VERBOSE, nil
input = TestInputMethod.new([ input = TestInputMethod.new([

Просмотреть файл

@ -80,7 +80,6 @@ module TestIRB
assert_equal(nil, workspace.code_around_binding) assert_equal(nil, workspace.code_around_binding)
end end
def test_toplevel_binding_local_variables def test_toplevel_binding_local_variables
bug17623 = '[ruby-core:102468]' bug17623 = '[ruby-core:102468]'
bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []