diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb index 3e9704706..a78adef8d 100644 --- a/lib/irb/completion.rb +++ b/lib/irb/completion.rb @@ -12,26 +12,6 @@ class BaseCompletor # :nodoc: # Set of reserved words used by Ruby, you should not use these for # constants or variables - ReservedWords = %w[ - __ENCODING__ __LINE__ __FILE__ - BEGIN END - alias and - begin break - case class - def defined? do - else elsif end ensure - false for - if in - module - next nil not - or - redo rescue retry return - self super - then true - undef unless until - when while - yield - ] HELP_COMMAND_PREPOSING = /\Ahelp\s+/ @@ -459,12 +439,12 @@ def retrieve_completion_data(input, bind:, doc_namespace:) eval("#{perfect_match_var}.class.name", bind) rescue nil else candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s} - candidates |= ReservedWords + candidates |= RubyLex::RESERVED_WORDS.map(&:to_s) candidates.find{ |i| i == input } end else candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s} - candidates |= ReservedWords + candidates |= RubyLex::RESERVED_WORDS.map(&:to_s) candidates.grep(/^#{Regexp.quote(input)}/).sort end end diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb index 3abb53b4e..dd4a8d060 100644 --- a/lib/irb/ruby-lex.rb +++ b/lib/irb/ruby-lex.rb @@ -52,6 +52,27 @@ class RubyLex on_words_beg on_qwords_beg ] + RESERVED_WORDS = %i[ + __ENCODING__ __LINE__ __FILE__ + BEGIN END + alias and + begin break + case class + def defined? do + else elsif end ensure + false for + if in + module + next nil not + or + redo rescue retry return + self super + then true + undef unless until + when while + yield + ] + class TerminateLineInput < StandardError def initialize super("Terminate Line Input") @@ -77,6 +98,10 @@ def compile_with_errors_suppressed(code, line_no: 1) end def generate_local_variables_assign_code(local_variables) + # Some reserved words could be a local variable + # Example: def f(if: 1); binding.irb; end + # These reserved words should be removed from assignment code + local_variables -= RESERVED_WORDS "#{local_variables.join('=')}=nil;" unless local_variables.empty? end diff --git a/test/irb/test_color.rb b/test/irb/test_color.rb index 5529e2904..363f56977 100644 --- a/test/irb/test_color.rb +++ b/test/irb/test_color.rb @@ -167,8 +167,8 @@ def test_colorize_code_with_local_variables result_with_lvars = "a /(b +#{BLUE}#{BOLD}1#{CLEAR})/i" assert_equal_with_term(result_without_lvars, code) - assert_equal_with_term(result_with_lvar, code, local_variables: ['a']) - assert_equal_with_term(result_with_lvars, code, local_variables: ['a', 'b']) + assert_equal_with_term(result_with_lvar, code, local_variables: [:a]) + assert_equal_with_term(result_with_lvars, code, local_variables: [:a, :b]) end def test_colorize_code_complete_true diff --git a/test/irb/test_irb.rb b/test/irb/test_irb.rb index 617e9c961..d687ca9af 100644 --- a/test/irb/test_irb.rb +++ b/test/irb/test_irb.rb @@ -56,6 +56,20 @@ def test_underscore_stores_last_result assert_include output, "=> 12" end + def test_local_variable_handeld_correctly + write_ruby <<~'RUBY' + tap do |if:0, and:0, foo:100| + binding.irb + end + RUBY + + output = run_ruby_file do + type 'foo /4#/ do' + type 'exit!' + end + assert_include output, '=> 25' + end + def test_commands_dont_override_stored_last_result write_ruby <<~'RUBY' binding.irb diff --git a/test/irb/test_ruby_lex.rb b/test/irb/test_ruby_lex.rb index 9392b49fa..4e44ab44f 100644 --- a/test/irb/test_ruby_lex.rb +++ b/test/irb/test_ruby_lex.rb @@ -38,8 +38,16 @@ def test_local_variables_dependent_code lines = ["a /1#/ do", "2"] assert_indent_level(lines, 1) assert_code_block_open(lines, true) - assert_indent_level(lines, 0, local_variables: ['a']) - assert_code_block_open(lines, false, local_variables: ['a']) + assert_indent_level(lines, 0, local_variables: [:a]) + assert_code_block_open(lines, false, local_variables: [:a]) + end + + def test_keyword_local_variables + # Assuming `def f(if: 1, and: 2, ); binding.irb; end` + local_variables = [:if, :and] + lines = ['1 + 2'] + assert_indent_level(lines, 0, local_variables: local_variables) + assert_code_block_open(lines, false, local_variables: local_variables) end def test_literal_ends_with_space