diff --git a/lib/irb.rb b/lib/irb.rb index fd0bfe35c..d5e00b7e1 100644 --- a/lib/irb.rb +++ b/lib/irb.rb @@ -40,9 +40,11 @@ def CurrentContext # :nodoc: end # Initializes IRB and creates a new Irb.irb object at the `TOPLEVEL_BINDING` - def start(ap_path = nil) + def start(ap_path = nil, **options) STDOUT.sync = true $0 = File::basename(ap_path, ".rb") if ap_path + pre_cmds = options[:pre]&.rstrip + do_cmds = options[:do]&.rstrip setup(ap_path) @@ -51,7 +53,7 @@ def start(ap_path = nil) else irb = Irb.new end - irb.run(@CONF) + irb.run(@CONF, pre_cmds: pre_cmds, do_cmds: do_cmds) end # Quits irb @@ -146,7 +148,7 @@ def debug_readline(binding) input end - def run(conf = IRB.conf) + def run(conf = IRB.conf, pre_cmds: nil, do_cmds: nil) in_nested_session = !!conf[:MAIN_CONTEXT] conf[:IRB_RC].call(context) if conf[:IRB_RC] prev_context = conf[:MAIN_CONTEXT] @@ -169,6 +171,13 @@ def run(conf = IRB.conf) RubyVM.keep_script_lines = true end + if pre_cmds + context.evaluate(parse_input(pre_cmds), @line_no) + elsif do_cmds + context.evaluate(parse_input(do_cmds), @line_no) + return + end + forced_exit = catch(:IRB_EXIT) do eval_input end @@ -703,7 +712,7 @@ class Binding # Cooked potato: true # # See IRB for more information. - def irb(show_code: true) + def irb(show_code: true, **options) # Setup IRB with the current file's path and no command line arguments IRB.setup(source_location[0], argv: []) unless IRB.initialized? # Create a new workspace using the current binding @@ -714,6 +723,8 @@ def irb(show_code: true) debugger_irb = IRB.instance_variable_get(:@debugger_irb) irb_path = File.expand_path(source_location[0]) + pre_cmds = options[:pre]&.rstrip + do_cmds = options[:do]&.rstrip if debugger_irb # If we're already in a debugger session, set the workspace and irb_path for the original IRB instance @@ -722,14 +733,14 @@ def irb(show_code: true) # If we've started a debugger session and hit another binding.irb, we don't want # to start an IRB session instead, we want to resume the irb:rdbg session. IRB::Debug.setup(debugger_irb) - IRB::Debug.insert_debug_break + IRB::Debug.insert_debug_break(pre_cmds: pre_cmds, do_cmds: do_cmds) debugger_irb.debug_break else # If we're not in a debugger session, create a new IRB instance with the current # workspace binding_irb = IRB::Irb.new(workspace, from_binding: true) binding_irb.context.irb_path = irb_path - binding_irb.run(IRB.conf) + binding_irb.run(IRB.conf, pre_cmds: pre_cmds, do_cmds: do_cmds) binding_irb.debug_break end end diff --git a/test/irb/test_debugger_integration.rb b/test/irb/test_debugger_integration.rb index 45ffb2a52..32edbaa29 100644 --- a/test/irb/test_debugger_integration.rb +++ b/test/irb/test_debugger_integration.rb @@ -378,7 +378,7 @@ def test_irb_command_can_check_local_variables type "show_source + 'Bar'" type "continue" end - assert_include(output, "def start(ap_path = nil)") + assert_include(output, "def start(ap_path = nil, **options)") assert_include(output, '"FooBar"') end diff --git a/test/irb/test_irb.rb b/test/irb/test_irb.rb index d687ca9af..c14e98c08 100644 --- a/test/irb/test_irb.rb +++ b/test/irb/test_irb.rb @@ -947,4 +947,59 @@ def bar end end end + + class ArgumentTest < TestIRB::IntegrationTestCase + def test_pre_commands + write_ruby <<~'RUBY' + ninty_nine = "It's a #{100 - 1}" + ninty_eight = "It's a #{100 - 2}" + + require 'irb' # need to pass an argument to binding.irb(see also: https://github.com/ruby/ruby/pull/12796) + binding.irb(pre: 'p ninty_nine ;; p ninty_eight') + RUBY + + output = run_ruby_file do + type "exit" + end + + assert_include output, "It's a 98" + assert_include output, "It's a 99" + end + + def test_do_cmds + @envs['IRB_COPY_COMMAND'] = "#{EnvUtil.rubybin} -e \"puts 'foo' + STDIN.read\"" + + write_ruby <<~'RUBY' + ninty_nine = "It's a #{100 - 1}" + + require 'irb' # need to pass an argument to binding.irb(see also: https://github.com/ruby/ruby/pull/12796) + binding.irb(do: 'copy "foo"') + puts ninty_nine + RUBY + + output = run_ruby_file {} + + assert_match("foo", output) + assert_match(/Copied to system clipboard/, output) + assert_match("It's a 99", output) + end + + def test_pre_commands_takes_priority_over_do_commands + @envs['IRB_COPY_COMMAND'] = "#{EnvUtil.rubybin} -e \"puts 'foo' + STDIN.read\"" + + write_ruby <<~'RUBY' + ninty_nine = "It's a #{100 - 1}" + + require 'irb' # need to pass an argument to binding.irb(see also: https://github.com/ruby/ruby/pull/12796) + binding.irb(pre: 'p ninty_nine', do: 'copy ninty_nine') + RUBY + + output = run_ruby_file do + type "exit" + end + + assert_not_match(/Copied to system clipboard/, output) + assert_match("It's a 99", output) + end + end end