Skip to content

Commit 4a0e0e8

Browse files
authored
Introduce cd command (#971)
It's essentially a combination of pushws and popws commands that are easier to use. Help message: ``` Usage: cd ([target]|..) IRB uses a stack of workspaces to keep track of context(s), with `pushws` and `popws` commands to manipulate the stack. The `cd` command is an attempt to simplify the operation and will be subject to change. When given: - an object, cd will use that object as the new context by pushing it onto the workspace stack. - "..", cd will leave the current context by popping the top workspace off the stack. - no arguments, cd will move to the top workspace on the stack by popping off all workspaces. Examples: cd Foo cd Foo.new cd @ivar cd .. cd ```
1 parent 00603d4 commit 4a0e0e8

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed

lib/irb/command/cd.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# frozen_string_literal: true
2+
3+
module IRB
4+
module Command
5+
class CD < Base
6+
category "Workspace"
7+
description "Move into the given object or leave the current context."
8+
9+
help_message(<<~HELP)
10+
Usage: cd ([target]|..)
11+
12+
IRB uses a stack of workspaces to keep track of context(s), with `pushws` and `popws` commands to manipulate the stack.
13+
The `cd` command is an attempt to simplify the operation and will be subject to change.
14+
15+
When given:
16+
- an object, cd will use that object as the new context by pushing it onto the workspace stack.
17+
- "..", cd will leave the current context by popping the top workspace off the stack.
18+
- no arguments, cd will move to the top workspace on the stack by popping off all workspaces.
19+
20+
Examples:
21+
22+
cd Foo
23+
cd Foo.new
24+
cd @ivar
25+
cd ..
26+
cd
27+
HELP
28+
29+
def execute(arg)
30+
case arg
31+
when ".."
32+
irb_context.pop_workspace
33+
when ""
34+
# TODO: decide what workspace commands should be kept, and underlying APIs should look like,
35+
# and perhaps add a new API to clear the workspace stack.
36+
prev_workspace = irb_context.pop_workspace
37+
while prev_workspace
38+
prev_workspace = irb_context.pop_workspace
39+
end
40+
else
41+
begin
42+
obj = eval(arg, irb_context.workspace.binding)
43+
irb_context.push_workspace(obj)
44+
rescue StandardError => e
45+
warn "Error: #{e}"
46+
end
47+
end
48+
end
49+
end
50+
end
51+
end

lib/irb/default_commands.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
require_relative "command/backtrace"
66
require_relative "command/break"
77
require_relative "command/catch"
8+
require_relative "command/cd"
89
require_relative "command/chws"
910
require_relative "command/context"
1011
require_relative "command/continue"
@@ -240,6 +241,8 @@ def load_command(command)
240241
_register_with_aliases(:irb_disable_irb, Command::DisableIrb,
241242
[:disable_irb, NO_OVERRIDE]
242243
)
244+
245+
register(:cd, Command::CD)
243246
end
244247

245248
ExtendCommand = Command

test/irb/command/test_cd.rb

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require "tempfile"
2+
require_relative "../helper"
3+
4+
module TestIRB
5+
class CDTest < IntegrationTestCase
6+
def setup
7+
super
8+
9+
write_ruby <<~'RUBY'
10+
class Foo
11+
class Bar
12+
def bar
13+
"this is bar"
14+
end
15+
end
16+
17+
def foo
18+
"this is foo"
19+
end
20+
end
21+
22+
binding.irb
23+
RUBY
24+
end
25+
26+
def test_cd
27+
out = run_ruby_file do
28+
type "cd Foo"
29+
type "ls"
30+
type "cd Bar"
31+
type "ls"
32+
type "cd .."
33+
type "exit"
34+
end
35+
36+
assert_match(/irb\(Foo\):002>/, out)
37+
assert_match(/Foo#methods: foo/, out)
38+
assert_match(/irb\(Foo::Bar\):004>/, out)
39+
assert_match(/Bar#methods: bar/, out)
40+
assert_match(/irb\(Foo\):006>/, out)
41+
end
42+
43+
def test_cd_moves_top_level_with_no_args
44+
out = run_ruby_file do
45+
type "cd Foo"
46+
type "cd Bar"
47+
type "cd"
48+
type "exit"
49+
end
50+
51+
assert_match(/irb\(Foo::Bar\):003>/, out)
52+
assert_match(/irb\(main\):004>/, out)
53+
end
54+
55+
def test_cd_with_error
56+
out = run_ruby_file do
57+
type "cd Baz"
58+
type "exit"
59+
end
60+
61+
assert_match(/Error: uninitialized constant Baz/, out)
62+
assert_match(/irb\(main\):002>/, out) # the context should not change
63+
end
64+
end
65+
end

0 commit comments

Comments
 (0)