From 0d273f39d8a6bedc2f628866b357625f1d615da9 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Sun, 16 Jun 2024 18:27:55 +0100 Subject: [PATCH] Introduce cd command It's essentially a combination of pushws and popws commands that are easier to use. Help message: ``` Usage: cd ([target]|..) When given an object, cd will move into that object, making it the current context. When given "..", cd will leave the current context, moving back to the previous context. When given no arguments, cd will move back to the top-level (main object) context. Examples: cd Foo cd Foo.new cd @ivar cd .. cd ``` --- lib/irb/command/cd.rb | 45 +++++++++++++++++++++++++ lib/irb/default_commands.rb | 3 ++ test/irb/command/test_cd.rb | 65 +++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 lib/irb/command/cd.rb create mode 100644 test/irb/command/test_cd.rb diff --git a/lib/irb/command/cd.rb b/lib/irb/command/cd.rb new file mode 100644 index 000000000..79a82f184 --- /dev/null +++ b/lib/irb/command/cd.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module IRB + module Command + class CD < Base + category "Workspace" + description "Move into the given object or leave the current context." + + help_message(<<~HELP) + Usage: cd ([target]|..) + + When given an object, cd will move into that object, making it the current context. + When given "..", cd will leave the current context, moving back to the previous context. + When given no arguments, cd will move back to the top-level (main object) context. + + Examples: + + cd Foo + cd Foo.new + cd @ivar + cd .. + cd + HELP + + def execute(arg) + case arg + when ".." + irb_context.pop_workspace + when "" + prev_workspace = irb_context.pop_workspace + while prev_workspace + prev_workspace = irb_context.pop_workspace + end + else + begin + obj = eval(arg, irb_context.workspace.binding) + irb_context.push_workspace(obj) + rescue StandardError => e + warn "Error: #{e}" + end + end + end + end + end +end diff --git a/lib/irb/default_commands.rb b/lib/irb/default_commands.rb index 91c6b2d04..e27a3d4e0 100644 --- a/lib/irb/default_commands.rb +++ b/lib/irb/default_commands.rb @@ -5,6 +5,7 @@ require_relative "command/backtrace" require_relative "command/break" require_relative "command/catch" +require_relative "command/cd" require_relative "command/chws" require_relative "command/context" require_relative "command/continue" @@ -240,6 +241,8 @@ def load_command(command) _register_with_aliases(:irb_disable_irb, Command::DisableIrb, [:disable_irb, NO_OVERRIDE] ) + + register(:cd, Command::CD) end ExtendCommand = Command diff --git a/test/irb/command/test_cd.rb b/test/irb/command/test_cd.rb new file mode 100644 index 000000000..4537286f7 --- /dev/null +++ b/test/irb/command/test_cd.rb @@ -0,0 +1,65 @@ +require "tempfile" +require_relative "../helper" + +module TestIRB + class CDTest < IntegrationTestCase + def setup + super + + write_ruby <<~'RUBY' + class Foo + class Bar + def bar + "this is bar" + end + end + + def foo + "this is foo" + end + end + + binding.irb + RUBY + end + + def test_cd + out = run_ruby_file do + type "cd Foo" + type "ls" + type "cd Bar" + type "ls" + type "cd .." + type "exit" + end + + assert_match(/irb\(Foo\):002>/, out) + assert_match(/Foo#methods: foo/, out) + assert_match(/irb\(Foo::Bar\):004>/, out) + assert_match(/Bar#methods: bar/, out) + assert_match(/irb\(Foo\):006>/, out) + end + + def test_cd_moves_top_level_with_no_args + out = run_ruby_file do + type "cd Foo" + type "cd Bar" + type "cd" + type "exit" + end + + assert_match(/irb\(Foo::Bar\):003>/, out) + assert_match(/irb\(main\):004>/, out) + end + + def test_cd_with_error + out = run_ruby_file do + type "cd Baz" + type "exit" + end + + assert_match(/Error: uninitialized constant Baz/, out) + assert_match(/irb\(main\):002>/, out) # the context should not change + end + end +end