rush2 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +86 -0
- data/README.rdoc +125 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/bin/rush +13 -0
- data/bin/rushd +7 -0
- data/lib/rush.rb +91 -0
- data/lib/rush/access.rb +121 -0
- data/lib/rush/array_ext.rb +19 -0
- data/lib/rush/box.rb +124 -0
- data/lib/rush/commands.rb +76 -0
- data/lib/rush/config.rb +147 -0
- data/lib/rush/dir.rb +166 -0
- data/lib/rush/embeddable_shell.rb +26 -0
- data/lib/rush/entry.rb +229 -0
- data/lib/rush/exceptions.rb +32 -0
- data/lib/rush/file.rb +94 -0
- data/lib/rush/find_by.rb +39 -0
- data/lib/rush/fixnum_ext.rb +18 -0
- data/lib/rush/head_tail.rb +11 -0
- data/lib/rush/local.rb +377 -0
- data/lib/rush/process.rb +59 -0
- data/lib/rush/process_set.rb +62 -0
- data/lib/rush/remote.rb +33 -0
- data/lib/rush/search_results.rb +71 -0
- data/lib/rush/shell.rb +111 -0
- data/lib/rush/shell/completion.rb +110 -0
- data/lib/rush/string_ext.rb +16 -0
- data/spec/access_spec.rb +134 -0
- data/spec/array_ext_spec.rb +15 -0
- data/spec/base.rb +22 -0
- data/spec/box_spec.rb +76 -0
- data/spec/commands_spec.rb +47 -0
- data/spec/config_spec.rb +108 -0
- data/spec/dir_spec.rb +163 -0
- data/spec/embeddable_shell_spec.rb +17 -0
- data/spec/entry_spec.rb +133 -0
- data/spec/file_spec.rb +83 -0
- data/spec/find_by_spec.rb +58 -0
- data/spec/fixnum_ext_spec.rb +19 -0
- data/spec/local_spec.rb +365 -0
- data/spec/process_set_spec.rb +50 -0
- data/spec/process_spec.rb +73 -0
- data/spec/remote_spec.rb +140 -0
- data/spec/rush_spec.rb +28 -0
- data/spec/search_results_spec.rb +44 -0
- data/spec/shell_spec.rb +35 -0
- data/spec/ssh_tunnel_spec.rb +122 -0
- data/spec/string_ext_spec.rb +23 -0
- metadata +209 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
describe Array do
|
4
|
+
it "mixes commands into array" do
|
5
|
+
[ 1,2,3 ].entries.should == [ 1, 2, 3 ]
|
6
|
+
end
|
7
|
+
|
8
|
+
it "can call head" do
|
9
|
+
[ 1,2,3 ].head(1).should == [ 1 ]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can call tail" do
|
13
|
+
[ 1,2,3 ].tail(1).should == [ 3 ]
|
14
|
+
end
|
15
|
+
end
|
data/spec/base.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
require_relative '../lib/rush'
|
4
|
+
|
5
|
+
def mock_config(&block)
|
6
|
+
mock_config_start
|
7
|
+
block.call(config)
|
8
|
+
mock_config_end
|
9
|
+
end
|
10
|
+
|
11
|
+
def mock_config_sandbox_dir
|
12
|
+
"/tmp/fake_config.#{Process.pid}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def mock_config_start
|
16
|
+
mock_config_cleanup
|
17
|
+
Rush::Config.new(mock_config_sandbox_dir)
|
18
|
+
end
|
19
|
+
|
20
|
+
def mock_config_cleanup
|
21
|
+
FileUtils.rm_rf(mock_config_sandbox_dir)
|
22
|
+
end
|
data/spec/box_spec.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
describe Rush::Box do
|
4
|
+
before do
|
5
|
+
@sandbox_dir = "/tmp/rush_spec.#{Process.pid}"
|
6
|
+
system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
|
7
|
+
|
8
|
+
@box = Rush::Box.new('localhost')
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
system "rm -rf #{@sandbox_dir}"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "looks up entries with [] syntax" do
|
16
|
+
@box['/'].should == Rush::Dir.new('/', @box)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "looks up processes" do
|
20
|
+
@box.connection.should_receive(:processes).and_return([ { :pid => 123 } ])
|
21
|
+
@box.processes.should == [ Rush::Process.new({ :pid => 123 }, @box) ]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "executes bash commands" do
|
25
|
+
@box.connection.should_receive(:bash).with('cmd', nil, false, false).and_return('output')
|
26
|
+
@box.bash('cmd').should == 'output'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "executes bash commands with an optional user" do
|
30
|
+
@box.connection.should_receive(:bash).with('cmd', 'user', false, false)
|
31
|
+
@box.bash('cmd', :user => 'user')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "executes bash commands in the background, returning a Rush::Process" do
|
35
|
+
@box.connection.should_receive(:bash).with('cmd', nil, true, false).and_return(123)
|
36
|
+
@box.stub(:processes).and_return([ double('ps', :pid => 123) ])
|
37
|
+
@box.bash('cmd', :background => true).pid.should == 123
|
38
|
+
end
|
39
|
+
|
40
|
+
it "builds a script of environment variables to prefix the bash command" do
|
41
|
+
@box.command_with_environment('cmd', { :a => 'b' }).should == "export a=\"b\"\ncmd"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "escapes quotes on environment variables" do
|
45
|
+
@box.command_with_environment('cmd', { :a => 'a"b' }).should == "export a=\"a\\\"b\"\ncmd"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "escapes backticks on environment variables" do
|
49
|
+
@box.command_with_environment('cmd', { :a => 'a`b' }).should == "export a=\"a\\\`b\"\ncmd"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "converts environment variables to_s" do
|
53
|
+
@box.command_with_environment('cmd', { :a => nil, :b => 123 }).should == "export a=\"\"\nexport b=\"123\"\ncmd"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "sets the environment variables from the provided hash" do
|
57
|
+
@box.connection.stub(:bash)
|
58
|
+
@box.should_receive(:command_with_environment).with('cmd', { 1 => 2 })
|
59
|
+
@box.bash('cmd', :env => { 1 => 2 })
|
60
|
+
end
|
61
|
+
|
62
|
+
it "checks the connection to determine if it is alive" do
|
63
|
+
@box.connection.should_receive(:alive?).and_return(true)
|
64
|
+
@box.should be_alive
|
65
|
+
end
|
66
|
+
|
67
|
+
it "establish_connection to set up the connection manually" do
|
68
|
+
@box.connection.should_receive(:ensure_tunnel)
|
69
|
+
@box.establish_connection
|
70
|
+
end
|
71
|
+
|
72
|
+
it "establish_connection can take a hash of options" do
|
73
|
+
@box.connection.should_receive(:ensure_tunnel).with(:timeout => :infinite)
|
74
|
+
@box.establish_connection(:timeout => :infinite)
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
describe Rush::Commands do
|
4
|
+
before do
|
5
|
+
@sandbox_dir = "/tmp/rush_spec.#{Process.pid}"
|
6
|
+
system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
|
7
|
+
|
8
|
+
@filename = "test_file"
|
9
|
+
system "echo thing_to_find > #{@sandbox_dir}/#{@filename}"
|
10
|
+
system "echo dont_find_me > #{@sandbox_dir}/some_other_file"
|
11
|
+
|
12
|
+
@dir = Rush::Dir.new(@sandbox_dir)
|
13
|
+
@array = @dir.files
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
system "rm -rf #{@sandbox_dir}"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "searches a list of files" do
|
21
|
+
results = @dir.files.search(/thing_to_find/)
|
22
|
+
results.should be_kind_of(Rush::SearchResults)
|
23
|
+
results.entries.should == [ @dir[@filename] ]
|
24
|
+
results.lines.should == [ "thing_to_find" ]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "searches a dir" do
|
28
|
+
@dir.search(/thing_to_find/).entries.should == [ @dir[@filename] ]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "searchs a dir's nested files" do
|
32
|
+
@dir.create_dir('sub').create_file('file').write('nested')
|
33
|
+
@dir['**'].search(/nested/).entries.should == [ @dir['sub/file'] ]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "search and replace contents on all files in the glob" do
|
37
|
+
@dir['1'].create.write('xax')
|
38
|
+
@dir['2'].create.write('-a-')
|
39
|
+
@dir.replace_contents!(/a/, 'b')
|
40
|
+
@dir['1'].contents.should == "xbx"
|
41
|
+
@dir['2'].contents.should == "-b-"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "counts lines of the contained files" do
|
45
|
+
@dir.files.line_count.should == 2
|
46
|
+
end
|
47
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
describe Rush::Config do
|
4
|
+
before do
|
5
|
+
@sandbox_dir = "/tmp/rush_config_spec.#{Process.pid}"
|
6
|
+
system "rm -rf #{@sandbox_dir}"
|
7
|
+
@config = Rush::Config.new(@sandbox_dir)
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
system "rm -rf #{@sandbox_dir}"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "creates the dir" do
|
15
|
+
expect(File.directory?(@sandbox_dir)).to eq(true)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can access the history file" do
|
19
|
+
expect(@config.history_file).to be_kind_of(Rush::File)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "saves the shell command history" do
|
23
|
+
@config.save_history(%w(1 2 3))
|
24
|
+
expect(@config.history_file.contents).to eq("1\n2\n3\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "loads the shell command history" do
|
28
|
+
@config.save_history(%w(1 2 3))
|
29
|
+
expect(@config.load_history).to eq(%w(1 2 3))
|
30
|
+
end
|
31
|
+
|
32
|
+
it "loads a blank history if no history file" do
|
33
|
+
expect(@config.load_history).to eq([])
|
34
|
+
end
|
35
|
+
|
36
|
+
it "loads the env file" do
|
37
|
+
@config.env_file.write('abc')
|
38
|
+
expect(@config.load_env).to eq('abc')
|
39
|
+
end
|
40
|
+
|
41
|
+
it "loads nothing if env file does not exist" do
|
42
|
+
expect(@config.load_env).to eq('')
|
43
|
+
end
|
44
|
+
|
45
|
+
it "loads the commands file" do
|
46
|
+
@config.commands_file.write('abc')
|
47
|
+
expect(@config.load_commands).to eq('abc')
|
48
|
+
end
|
49
|
+
|
50
|
+
it "loads nothing if commands file does not exist" do
|
51
|
+
expect(@config.load_commands).to eq('')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "loads usernames and password for rushd" do
|
55
|
+
system "echo 1:2 > #{@sandbox_dir}/passwords"
|
56
|
+
system "echo a:b >> #{@sandbox_dir}/passwords"
|
57
|
+
expect(@config.passwords).to eq({ '1' => '2', 'a' => 'b' })
|
58
|
+
end
|
59
|
+
|
60
|
+
it "loads blank hash if no passwords file" do
|
61
|
+
expect(@config.passwords).to eq({})
|
62
|
+
end
|
63
|
+
|
64
|
+
it "loads credentials for client connecting to server" do
|
65
|
+
system "echo user:pass > #{@sandbox_dir}/credentials"
|
66
|
+
expect(@config.credentials_user).to eq 'user'
|
67
|
+
expect(@config.credentials_password).to eq 'pass'
|
68
|
+
end
|
69
|
+
|
70
|
+
it "loads list of ssh tunnels" do
|
71
|
+
system "echo host.example.com:123 > #{@sandbox_dir}/tunnels"
|
72
|
+
expect(@config.tunnels).to eq({ 'host.example.com' => 123 })
|
73
|
+
end
|
74
|
+
|
75
|
+
it "returns an empty hash if tunnels file is blank" do
|
76
|
+
expect(@config.tunnels).to eq({})
|
77
|
+
end
|
78
|
+
|
79
|
+
it "saves a list of ssh tunnels" do
|
80
|
+
@config.save_tunnels({ 'my.example.com' => 4000 })
|
81
|
+
expect(@config.tunnels_file.contents).to eq "my.example.com:4000\n"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "ensure_credentials_exist doesn't do anything if credentials already exist" do
|
85
|
+
@config.credentials_file.write "dummy"
|
86
|
+
expect(@config).to receive(:generate_credentials).exactly(0).times
|
87
|
+
@config.ensure_credentials_exist
|
88
|
+
end
|
89
|
+
|
90
|
+
it "ensure_credentials_exist generates credentials file if they don't exist" do
|
91
|
+
expect(@config).to receive(:generate_credentials)
|
92
|
+
@config.ensure_credentials_exist
|
93
|
+
end
|
94
|
+
|
95
|
+
it "secret_characters returns valid characters for username or password" do
|
96
|
+
expect(@config.secret_characters).to be_kind_of(Array)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "generate_secret products a random string for use in username and password" do
|
100
|
+
expect(@config).to receive(:secret_characters).and_return(%w(a))
|
101
|
+
expect(@config.generate_secret(2, 2)).to eq "aa"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "generate_credentials saves credentials" do
|
105
|
+
@config.generate_credentials
|
106
|
+
expect(@config.credentials_file.contents).to match(/^.+:.+$/)
|
107
|
+
end
|
108
|
+
end
|
data/spec/dir_spec.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
describe Rush::Dir do
|
4
|
+
before do
|
5
|
+
@sandbox_dir = "/tmp/rush_spec.#{Process.pid}"
|
6
|
+
system "rm -rf #{@sandbox_dir}; mkdir -p #{@sandbox_dir}"
|
7
|
+
|
8
|
+
@dirname = "#{@sandbox_dir}/test_dir/"
|
9
|
+
system "mkdir -p #{@dirname}"
|
10
|
+
|
11
|
+
@dir = Rush::Dir.new(@dirname)
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
system "rm -rf #{@sandbox_dir}"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "is a child of Rush::Entry" do
|
19
|
+
expect(@dir).to be_kind_of(Rush::Entry)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "can create itself, returning itself" do
|
23
|
+
system "rm -rf #{@sandbox_dir}"
|
24
|
+
expect(@dir.create).to eq @dir
|
25
|
+
expect(File.directory?(@dir.full_path)).to eq(true)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "can create a new file" do
|
29
|
+
newfile = @dir.create_file('one.txt')
|
30
|
+
expect(newfile.name).to eq 'one.txt'
|
31
|
+
expect(newfile.parent).to eq @dir
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can create a new subdir" do
|
35
|
+
newfile = @dir['two/'].create
|
36
|
+
expect(newfile.name).to eq 'two'
|
37
|
+
expect(newfile.parent).to eq @dir
|
38
|
+
end
|
39
|
+
|
40
|
+
it "find_by_name finds a single entry in the contents" do
|
41
|
+
file = @dir.create_file('one.rb')
|
42
|
+
expect(@dir.find_by_name('one.rb')).to eq file
|
43
|
+
end
|
44
|
+
|
45
|
+
it "find_by_glob finds a list of entries by wildcard" do
|
46
|
+
file1 = @dir.create_file('one.rb')
|
47
|
+
file2 = @dir.create_file('two.txt')
|
48
|
+
expect(@dir.find_by_glob('*.rb')).to eq([file1])
|
49
|
+
end
|
50
|
+
|
51
|
+
it "lists files" do
|
52
|
+
@dir.create_file('a')
|
53
|
+
expect(@dir.files).to eq([Rush::File.new("#{@dirname}/a")])
|
54
|
+
end
|
55
|
+
|
56
|
+
it "lists dirs" do
|
57
|
+
system "mkdir -p #{@dir.full_path}/b"
|
58
|
+
expect(@dir.dirs).to eq([Rush::Dir.new("#{@dirname}/b")])
|
59
|
+
end
|
60
|
+
|
61
|
+
it "lists combined files and dirs" do
|
62
|
+
@dir['c'].create
|
63
|
+
@dir['d/'].create
|
64
|
+
expect(@dir.contents.size).to eq 2
|
65
|
+
end
|
66
|
+
|
67
|
+
it "fetches the entry_tree of all contents recursively" do
|
68
|
+
@dir['a/'].create['b/'].create['c'].create
|
69
|
+
expect(@dir.entries_tree).to eq @dir.make_entries(%w(a/ a/b/ a/b/c))
|
70
|
+
end
|
71
|
+
|
72
|
+
it "maps [] to find_by_name" do
|
73
|
+
expect(@dir).to receive(:find_by_name).once
|
74
|
+
@dir['one']
|
75
|
+
end
|
76
|
+
|
77
|
+
it "maps [] with a wildcard character to find_by_glob" do
|
78
|
+
expect(@dir).to receive(:find_by_glob).once
|
79
|
+
@dir['*']
|
80
|
+
end
|
81
|
+
|
82
|
+
it "can use symbols or strings for [] access" do
|
83
|
+
expect(@dir).to receive(:find_by_name).once.with('subdir')
|
84
|
+
@dir[:subdir]
|
85
|
+
end
|
86
|
+
|
87
|
+
it "[] can return a file that has yet to be created" do
|
88
|
+
expect(@dir['not_yet']).to be_kind_of Rush::File
|
89
|
+
end
|
90
|
+
|
91
|
+
it "makes a list of entries from an array of filenames" do
|
92
|
+
@dir['a'].create
|
93
|
+
@dir['b/c/'].create
|
94
|
+
expect(@dir.make_entries(%w(a b/c))).to eq([ @dir['a'], @dir['b/c'] ])
|
95
|
+
end
|
96
|
+
|
97
|
+
it "lists flattened files from all nested subdirectories" do
|
98
|
+
@dir['1'].create
|
99
|
+
@dir['2/3/'].create['4'].create
|
100
|
+
@dir['a/b/c/'].create['d'].create
|
101
|
+
expect(@dir.files_flattened).to eq @dir.make_entries(%w(1 2/3/4 a/b/c/d))
|
102
|
+
end
|
103
|
+
|
104
|
+
it "lists flattened dirs from all nested subdirectories" do
|
105
|
+
@dir.create_dir('1/2')
|
106
|
+
expect(@dir.dirs_flattened).to eq @dir.make_entries(%w(1/ 1/2/))
|
107
|
+
end
|
108
|
+
|
109
|
+
it "** as a shortcut to flattened_files" do
|
110
|
+
expect(@dir['**']).to eq @dir.files_flattened
|
111
|
+
end
|
112
|
+
|
113
|
+
it "**/ as a shortcut to flattened_files + regular globbing" do
|
114
|
+
@dir.create_file('1.rb')
|
115
|
+
@dir.create_file('ignore.txt')
|
116
|
+
@dir.create_dir('2').create_file('3.rb')
|
117
|
+
@dir.create_dir('a/b').create_file('c.rb')
|
118
|
+
expect(@dir['**/*.rb']).to eq @dir.make_entries(%w(1.rb 2/3.rb a/b/c.rb))
|
119
|
+
end
|
120
|
+
|
121
|
+
it "lists nonhidden files" do
|
122
|
+
@dir.create_file('show')
|
123
|
+
@dir.create_file('.dont_show')
|
124
|
+
expect(@dir.nonhidden_files).to eq @dir.make_entries(%(show))
|
125
|
+
end
|
126
|
+
|
127
|
+
it "lists nonhidden dirs" do
|
128
|
+
@dir.create_dir('show')
|
129
|
+
@dir.create_dir('.dont_show')
|
130
|
+
expect(@dir.nonhidden_dirs).to eq @dir.make_entries(%(show/))
|
131
|
+
end
|
132
|
+
|
133
|
+
if !RUBY_PLATFORM.match(/darwin/) # doesn't work on OS X 'cause du switches are different
|
134
|
+
it "knows its size in bytes, which includes its contents recursively" do
|
135
|
+
@dir.create_file('a').write('1234')
|
136
|
+
expect(@dir.size).to eq(4096 + 4)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "can destroy itself when empty" do
|
141
|
+
@dir.destroy
|
142
|
+
end
|
143
|
+
|
144
|
+
it "can destroy itself when not empty" do
|
145
|
+
@dir.create_dir('a').create_file('b').write('c')
|
146
|
+
@dir.destroy
|
147
|
+
end
|
148
|
+
|
149
|
+
it "can run a bash command within itself" do
|
150
|
+
system "echo test > #{@dir.full_path}/file"
|
151
|
+
expect(@dir.bash("cat file")).to eq "test\n"
|
152
|
+
end
|
153
|
+
|
154
|
+
it "can run bash within directories with spaces" do
|
155
|
+
@dir.create_dir('with space').create_file('file').write('test')
|
156
|
+
expect(@dir["with space/"].bash("cat file")).to eq "test"
|
157
|
+
end
|
158
|
+
|
159
|
+
it "passes bash options (e.g., :user) through to the box bash command" do
|
160
|
+
expect(@dir).to receive(:bash).with('cmd', :opt1 => 1, :opt2 => 2)
|
161
|
+
@dir.bash('cmd', :opt1 => 1, :opt2 => 2)
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
describe Rush::EmbeddableShell do
|
4
|
+
before do
|
5
|
+
@shell = Rush::EmbeddableShell.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should execute unknown methods against a Rush::Shell instance" do
|
9
|
+
@shell.root.class.should == Rush::Dir
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should executes a block as if it were inside the shell" do
|
13
|
+
@shell.execute_in_shell {
|
14
|
+
root.class.should == Rush::Dir
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|