From 00603d470f259d4cb7d2860e4ca796cb2be5b3a2 Mon Sep 17 00:00:00 2001 From: tomoya ishida Date: Mon, 1 Jul 2024 02:13:22 +0900 Subject: [PATCH] Allow assigning and using local variable name conflicting with command (#961) --- lib/irb.rb | 8 +++++ test/irb/command/test_custom_command.rb | 45 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/lib/irb.rb b/lib/irb.rb index b3435c257..b417d9c2e 100644 --- a/lib/irb.rb +++ b/lib/irb.rb @@ -1138,6 +1138,8 @@ def build_statement(code) end end + ASSIGN_OPERATORS_REGEXP = Regexp.union(%w[= += -= *= /= %= **= &= |= &&= ||= ^= <<= >>=]) + def parse_command(code) command_name, arg = code.strip.split(/\s+/, 2) return unless code.lines.size == 1 && command_name @@ -1149,6 +1151,12 @@ def parse_command(code) return [alias_name, arg] end + # Assignment-like expression is not a command + return if arg.start_with?(ASSIGN_OPERATORS_REGEXP) && !arg.start_with?(/==|=~/) + + # Local variable have precedence over command + return if @context.local_variables.include?(command) + # Check visibility public_method = !!Kernel.instance_method(:public_method).bind_call(@context.main, command) rescue false private_method = !public_method && !!Kernel.instance_method(:method).bind_call(@context.main, command) rescue false diff --git a/test/irb/command/test_custom_command.rb b/test/irb/command/test_custom_command.rb index 3a3ad11d5..13f412c21 100644 --- a/test/irb/command/test_custom_command.rb +++ b/test/irb/command/test_custom_command.rb @@ -145,5 +145,50 @@ def execute(*) assert_include(output, "No description provided.") assert_not_include(output, "Maybe IRB bug") end + + def test_command_name_local_variable + write_ruby <<~RUBY + require "irb/command" + + class FooBarCommand < IRB::Command::Base + category 'CommandTest' + description 'test' + def execute(arg) + puts "arg=\#{arg.inspect}" + end + end + + IRB::Command.register(:foo_bar, FooBarCommand) + + binding.irb + RUBY + + output = run_ruby_file do + type "binding.irb" + type "foo_bar == 1 || 1" + type "foo_bar =~ /2/ || 2" + type "exit" + type "binding.irb" + type "foo_bar = '3'; foo_bar" + type "foo_bar == 4 || '4'" + type "foo_bar =~ /5/ || '5'" + type "exit" + type "binding.irb" + type "foo_bar ||= '6'; foo_bar" + type "foo_bar == 7 || '7'" + type "foo_bar =~ /8/ || '8'" + type "exit" + type "exit" + end + + assert_include(output, 'arg="== 1 || 1"') + assert_include(output, 'arg="=~ /2/ || 2"') + assert_include(output, '=> "3"') + assert_include(output, '=> "4"') + assert_include(output, '=> "5"') + assert_include(output, '=> "6"') + assert_include(output, '=> "7"') + assert_include(output, '=> "8"') + end end end