ronin 1.4.1 → 1.5.0.rc1

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.
Files changed (66) hide show
  1. data/.document +1 -0
  2. data/.gitignore +1 -0
  3. data/ChangeLog.md +38 -1
  4. data/Gemfile +10 -10
  5. data/README.md +1 -1
  6. data/Rakefile +13 -2
  7. data/bin/ronin-net-proxy +25 -0
  8. data/gemspec.yml +21 -2
  9. data/lib/bond/completions/ronin.rb +16 -5
  10. data/lib/ronin/arch.rb +5 -5
  11. data/lib/ronin/auto_load.rb +22 -1
  12. data/lib/ronin/campaign.rb +1 -1
  13. data/lib/ronin/database/database.rb +36 -25
  14. data/lib/ronin/installation.rb +2 -2
  15. data/lib/ronin/model/model.rb +5 -6
  16. data/lib/ronin/model/types/description.rb +0 -3
  17. data/lib/ronin/os.rb +2 -2
  18. data/lib/ronin/password.rb +1 -1
  19. data/lib/ronin/repository.rb +6 -6
  20. data/lib/ronin/script/path.rb +1 -2
  21. data/lib/ronin/spec/database.rb +16 -4
  22. data/lib/ronin/ui/cli/cli.rb +1 -1
  23. data/lib/ronin/ui/cli/command.rb +50 -7
  24. data/lib/ronin/ui/cli/commands/console.rb +15 -6
  25. data/lib/ronin/ui/cli/commands/creds.rb +1 -1
  26. data/lib/ronin/ui/cli/commands/database.rb +41 -29
  27. data/lib/ronin/ui/cli/commands/emails.rb +20 -15
  28. data/lib/ronin/ui/cli/commands/help.rb +18 -5
  29. data/lib/ronin/ui/cli/commands/hosts.rb +34 -27
  30. data/lib/ronin/ui/cli/commands/install.rb +21 -4
  31. data/lib/ronin/ui/cli/commands/ips.rb +34 -23
  32. data/lib/ronin/ui/cli/commands/net/proxy.rb +403 -0
  33. data/lib/ronin/ui/cli/commands/repos.rb +4 -4
  34. data/lib/ronin/ui/cli/commands/uninstall.rb +10 -0
  35. data/lib/ronin/ui/cli/commands/update.rb +11 -1
  36. data/lib/ronin/ui/cli/commands/urls.rb +39 -30
  37. data/lib/ronin/ui/cli/commands/wordlist.rb +11 -1
  38. data/lib/ronin/ui/console.rb +1 -0
  39. data/lib/ronin/ui/console/commands.rb +16 -98
  40. data/lib/ronin/ui/console/shell.rb +184 -0
  41. data/lib/ronin/url.rb +3 -3
  42. data/lib/ronin/url_scheme.rb +3 -3
  43. data/lib/ronin/version.rb +1 -1
  44. data/man/ronin-campaigns.1.md +78 -0
  45. data/man/ronin-console.1.md +72 -0
  46. data/man/ronin-creds.1.md +66 -0
  47. data/man/ronin-database.1.md +82 -0
  48. data/man/ronin-emails.1.md +72 -0
  49. data/man/ronin-exec.1.md +49 -0
  50. data/man/ronin-help.1.md +34 -0
  51. data/man/ronin-hosts.1.md +78 -0
  52. data/man/ronin-install.1.md +79 -0
  53. data/man/ronin-ips.1.md +81 -0
  54. data/man/ronin-net-proxy.1.md +86 -0
  55. data/man/ronin-repos.1.md +77 -0
  56. data/man/ronin-uninstall.1.md +67 -0
  57. data/man/ronin-update.1.md +67 -0
  58. data/man/ronin-urls.1.md +84 -0
  59. data/man/ronin-wordlist.1.md +53 -0
  60. data/man/ronin.1.md +26 -0
  61. data/ronin.gemspec +38 -109
  62. data/spec/installation_spec.rb +2 -1
  63. data/spec/spec_helper.rb +2 -0
  64. data/spec/ui/cli/classes/test_command.rb +7 -0
  65. data/spec/ui/cli/command_spec.rb +235 -7
  66. metadata +217 -96
@@ -0,0 +1,67 @@
1
+ # ronin-update 1 "April 2012" Ronin "User Manuals"
2
+
3
+ ## SYNOPSIS
4
+
5
+ `ronin update` [*options*] [*REPO*]
6
+
7
+ ## DESCRIPTION
8
+
9
+ Updates Ronin Repositories.
10
+
11
+ ## ARGUMENTS
12
+
13
+ *REPO*
14
+ The name of the Repository to update.
15
+
16
+ ## OPTIONS
17
+
18
+ `-v`, `--[no-]verbose`
19
+ Enable verbose output.
20
+
21
+ `-q`, `--[no-]quiet`
22
+ Disable verbose output.
23
+
24
+ `--[no-]silent`
25
+ Silence all output.
26
+
27
+ `--[no-]color`
28
+ Enables color output.
29
+
30
+ ## EXAMPLES
31
+
32
+ `ronin update repo`
33
+ Updates the repository with with the name `repo`.
34
+
35
+ `ronin update repo@github.com`
36
+ Updates the repository with the name `repo` and from `github.com`.
37
+
38
+ ## FILES
39
+
40
+ *~/.ronin/*
41
+ Ronin configuration directory.
42
+
43
+ *~/.ronin/repos*
44
+ Installation directory for Ronin Repositories.
45
+
46
+ *~/.ronin/database.log*
47
+ Database log.
48
+
49
+ *~/.ronin/database.sqlite3*
50
+ The default sqlite3 Database file.
51
+
52
+ *~/.ronin/database.yml*
53
+ Optional Database configuration.
54
+
55
+ ## ENVIRONMENT
56
+
57
+ HOME
58
+ Specifies the home directory of the user. Ronin will search for the `.ronin`
59
+ configuration directory within the home directory.
60
+
61
+ ## AUTHOR
62
+
63
+ Postmodern <postmodern.mod3@gmail.com>
64
+
65
+ ## SEE ALSO
66
+
67
+ ronin-install(1) ronin-repos(1) ronin-uninstall(1)
@@ -0,0 +1,84 @@
1
+ # ronin-urls 1 "April 2012" Ronin "User Manuals"
2
+
3
+ ## SYNOPSIS
4
+
5
+ `ronin urls` [*options*]
6
+
7
+ ## DESCRIPTION
8
+
9
+ Manages URLs.
10
+
11
+ ## OPTIONS
12
+
13
+ `-v`, `--[no-]verbose`
14
+ Enable verbose output.
15
+
16
+ `-q`, `--[no-]quiet`
17
+ Disable verbose output.
18
+
19
+ `--[no-]silent`
20
+ Silence all output.
21
+
22
+ `--[no-]color`
23
+ Enables color output.
24
+
25
+ `-D`, `--database` *URI*
26
+ The database to URI (`mysql://user:password@host/ronin`).
27
+
28
+ `--[no-]csv`
29
+ CSV output.
30
+
31
+ `--[no-]xml`
32
+ XML output.
33
+
34
+ `--[no-]yaml`
35
+ YAML output.
36
+
37
+ `--[no-]json`
38
+ JSON output.
39
+
40
+ `-i`, `--import` *FILE*
41
+ Imports HostNames from the FILE.
42
+
43
+ `--[no-]http`
44
+ Searches for `http://` URLs.
45
+
46
+ `--[no-]https`
47
+ Searches for `https://` URLs.
48
+
49
+ `-H`, `--hosts` *HOST* [...]
50
+ Searches for URLs with the given HOST name(s).
51
+
52
+ `-p`, `--with-ports` *PORT* [...]
53
+ Searches for URLs associated with the PORT(s).
54
+
55
+ `-d`, `--directory` *DIRECTORY*
56
+ Searches for URLs sharing the DIRECTORY.
57
+
58
+ `-q`, `--with-query-param` *NAME* [...]
59
+ Searches for URLs containing the query-param NAME.
60
+
61
+ `-Q`, `--with-query-value` *VALUE* [...]
62
+ Searches for URLs containing the query-param VALUE.
63
+
64
+ `-l`, `--[no-]list`
65
+ Lists the HostNames.
66
+
67
+ ## FILES
68
+
69
+ *~/.ronin/*
70
+ Ronin configuration directory.
71
+
72
+ *~/.ronin/database.log*
73
+ Database log.
74
+
75
+ *~/.ronin/database.sqlite3*
76
+ The default sqlite3 Database file.
77
+
78
+ *~/.ronin/database.yml*
79
+ Optional Database configuration.
80
+
81
+ ## AUTHOR
82
+
83
+ Postmodern <postmodern.mod3@gmail.com>
84
+
@@ -0,0 +1,53 @@
1
+ # ronin-wordlist 1 "April 2012" Ronin "User Manuals"
2
+
3
+ ## SYNOPSIS
4
+
5
+ `ronin wordlist` [*options*] [*TEMPLATE*]
6
+
7
+ ## DESCRIPTION
8
+
9
+ Builds and/or mutates Wordlists.
10
+
11
+ ## ARGUMENTS
12
+
13
+ *TEMPLATE*
14
+ Options word template to generate the wordlist with (`alpha:7 numeric:1-3`).
15
+
16
+ ## OPTIONS
17
+
18
+ `-v`, `--[no-]verbose`
19
+ Enable verbose output.
20
+
21
+ `-q`, `--[no-]quiet`
22
+ Disable verbose output.
23
+
24
+ `--[no-]silent`
25
+ Silence all output.
26
+
27
+ `--[no-]color`
28
+ Enables color output.
29
+
30
+ `-i`, `--input` *FILE*
31
+ The input text FILE to parse.
32
+
33
+ `-o`, `--output` *PATH*
34
+ The output PATH to write the wordlist to.
35
+
36
+ `-m`, `--mutations` *STRING*:*SUBSTITUTE*
37
+ Mutations to apply to the words. If STRING is found within a word, it will be
38
+ replaced with SUBSTITUTE.
39
+
40
+ ## EXAMPLES
41
+
42
+ `ronin wordlist alpha:7 numeric:1-3`
43
+ Enumerates through every possible word, with each word beginning with seven
44
+ alphabetic characters and ending in 1-3 numeric characters.
45
+
46
+ `ronin wordlist --input text.txt -m e:3 -m a:@ -m o:0`
47
+ Builds a wordlist from a text file, applying basic "leet-speak" mutation rules
48
+ to each word.
49
+
50
+ ## AUTHOR
51
+
52
+ Postmodern <postmodern.mod3@gmail.com>
53
+
@@ -0,0 +1,26 @@
1
+ # ronin 1 "April 2012" Ronin "User Manuals"
2
+
3
+ ## SYNOPSIS
4
+
5
+ `ronin` [*COMMAND*] [*options*]
6
+
7
+ ## DESCRIPTION
8
+
9
+ Runs a Ronin COMMAND or the starts Ronin Console.
10
+
11
+ ## ARGUMENTS
12
+
13
+ *COMMAND*
14
+ The Ronin command to execute.
15
+
16
+ ## OPTIONS
17
+
18
+ Additional options for the COMMAND or the Ronin Console.
19
+
20
+ ## AUTHOR
21
+
22
+ Postmodern <postmodern.mod3@gmail.com>
23
+
24
+ ## SEE ALSO
25
+
26
+ ronin-console(1)
@@ -2,130 +2,59 @@
2
2
 
3
3
  require 'yaml'
4
4
 
5
- Gem::Specification.new do |gemspec|
6
- root = File.dirname(__FILE__)
7
- lib_dir = File.join(root,'lib')
8
- files = if File.directory?('.git')
9
- `git ls-files`.split($/)
10
- elsif File.directory?('.hg')
11
- `hg manifest`.split($/)
12
- elsif File.directory?('.svn')
13
- `svn ls -R`.split($/).select { |path| File.file?(path) }
14
- else
15
- Dir['{**/}{.*,*}'].select { |path| File.file?(path) }
16
- end
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
17
7
 
18
- filter_files = lambda { |paths|
19
- case paths
20
- when Array
21
- (files & paths)
22
- when String
23
- (files & Dir[paths])
24
- end
25
- }
26
-
27
- version = {
28
- :file => 'ronin/version',
29
- :constant => 'Ronin::VERSION'
30
- }
31
-
32
- defaults = {
33
- 'name' => File.basename(root),
34
- 'files' => files,
35
- 'executables' => filter_files['bin/*'].map { |path| File.basename(path) },
36
- 'test_files' => filter_files['{test/{**/}*_test.rb,spec/{**/}*_spec.rb}'],
37
- 'extra_doc_files' => filter_files['*.{txt,rdoc,md,markdown,tt,textile}'],
38
- }
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
39
12
 
40
- metadata = defaults.merge(YAML.load_file('gemspec.yml'))
13
+ require 'ronin/version'
14
+ Ronin::VERSION
15
+ end
41
16
 
42
- gemspec.name = metadata.fetch('name',defaults[:name])
43
- gemspec.version = if metadata['version']
44
- metadata['version']
45
- else
46
- $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
47
23
 
48
- require version[:file]
49
- eval(version[:constant])
50
- end
24
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
51
25
 
52
- gemspec.summary = metadata.fetch('summary',metadata['description'])
53
- gemspec.description = metadata.fetch('description',metadata['summary'])
26
+ gem.files = `git ls-files`.split($/)
27
+ gem.files = glob[gemspec['files']] if gemspec['files']
54
28
 
55
- case metadata['license']
56
- when Array
57
- gemspec.licenses = metadata['license']
58
- when String
59
- gemspec.license = metadata['license']
29
+ gem.executables = gemspec.fetch('executables') do
30
+ glob['bin/*'].map { |path| File.basename(path) }
60
31
  end
32
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
61
33
 
62
- case metadata['authors']
63
- when Array
64
- gemspec.authors = metadata['authors']
65
- when String
66
- gemspec.author = metadata['authors']
67
- end
68
-
69
- gemspec.email = metadata['email']
70
- gemspec.homepage = metadata['homepage']
34
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
35
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
36
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
71
37
 
72
- case metadata['require_paths']
73
- when Array
74
- gemspec.require_paths = metadata['require_paths']
75
- when String
76
- gemspec.require_path = metadata['require_paths']
77
- end
38
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
39
+ %w[ext lib].select { |dir| File.directory?(dir) }
40
+ })
78
41
 
79
- gemspec.files = filter_files[metadata['files']]
42
+ gem.requirements = gemspec['requirements']
43
+ gem.required_ruby_version = gemspec['required_ruby_version']
44
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
45
+ gem.post_install_message = gemspec['post_install_message']
80
46
 
81
- gemspec.executables = metadata['executables']
82
- gemspec.extensions = metadata['extensions']
83
-
84
- if Gem::VERSION < '1.7.'
85
- gemspec.default_executable = gemspec.executables.first
86
- end
87
-
88
- gemspec.test_files = filter_files[metadata['test_files']]
89
-
90
- unless gemspec.files.include?('.document')
91
- gemspec.extra_rdoc_files = metadata['extra_doc_files']
92
- end
93
-
94
- gemspec.post_install_message = metadata['post_install_message']
95
- gemspec.requirements = metadata['requirements']
96
-
97
- if gemspec.respond_to?(:required_ruby_version=)
98
- gemspec.required_ruby_version = metadata['required_ruby_version']
99
- end
100
-
101
- if gemspec.respond_to?(:required_rubygems_version=)
102
- gemspec.required_rubygems_version = metadata['required_rubygems_version']
103
- end
104
-
105
- parse_versions = lambda { |versions|
106
- case versions
107
- when Array
108
- versions.map { |v| v.to_s }
109
- when String
110
- versions.split(/,\s*/)
111
- end
112
- }
113
-
114
- if metadata['dependencies']
115
- metadata['dependencies'].each do |name,versions|
116
- gemspec.add_dependency(name,parse_versions[versions])
117
- end
118
- end
47
+ split = lambda { |string| string.split(/,\s*/) }
119
48
 
120
- if metadata['runtime_dependencies']
121
- metadata['runtime_dependencies'].each do |name,versions|
122
- gemspec.add_runtime_dependency(name,parse_versions[versions])
49
+ if gemspec['dependencies']
50
+ gemspec['dependencies'].each do |name,versions|
51
+ gem.add_dependency(name,split[versions])
123
52
  end
124
53
  end
125
54
 
126
- if metadata['development_dependencies']
127
- metadata['development_dependencies'].each do |name,versions|
128
- gemspec.add_development_dependency(name,parse_versions[versions])
55
+ if gemspec['development_dependencies']
56
+ gemspec['development_dependencies'].each do |name,versions|
57
+ gem.add_development_dependency(name,split[versions])
129
58
  end
130
59
  end
131
60
  end
@@ -23,6 +23,7 @@ describe Installation do
23
23
  hosts.rb
24
24
  install.rb
25
25
  ips.rb
26
+ net/proxy.rb
26
27
  repos.rb
27
28
  update.rb
28
29
  urls.rb
@@ -32,7 +33,7 @@ describe Installation do
32
33
  }
33
34
 
34
35
  describe "each_file" do
35
- let(:pattern) { File.join(directory,'*.rb') }
36
+ let(:pattern) { File.join(directory,'**','*.rb') }
36
37
  let(:expected) { files.map { |name| File.join(directory,name) } }
37
38
 
38
39
  it "should enumerate over the files which match a glob pattern" do
@@ -6,9 +6,11 @@ require 'model/models/described_model'
6
6
  require 'model/models/licensed_model'
7
7
  require 'model/models/named_model'
8
8
  require 'model/models/titled_model'
9
+ require 'classes/my_script'
9
10
  require 'helpers/repositories'
10
11
 
11
12
  require 'ronin/spec/database'
13
+ require 'ronin/spec/ui/output'
12
14
 
13
15
  include Ronin
14
16
 
@@ -4,6 +4,13 @@ class TestCommand < Ronin::UI::CLI::Command
4
4
 
5
5
  summary 'Tests the default task'
6
6
 
7
+ usage '[options] PATH FILE [..]'
8
+
9
+ examples [
10
+ 'test_command --foo PATH',
11
+ 'test_command --foo PATH FILE ...'
12
+ ]
13
+
7
14
  option :foo
8
15
 
9
16
  argument :path
@@ -6,8 +6,241 @@ require 'ui/cli/classes/test_command'
6
6
  describe UI::CLI::Command do
7
7
  subject { TestCommand }
8
8
 
9
- it "should have a command name" do
10
- subject.command_name.should == 'test_command'
9
+ describe "command_name" do
10
+ it "should be derived from the Class name" do
11
+ subject.command_name.should == 'test_command'
12
+ end
13
+ end
14
+
15
+ describe "usage" do
16
+ context "without an argument" do
17
+ it "should return the set usage" do
18
+ subject.usage.should == '[options] PATH FILE [..]'
19
+ end
20
+ end
21
+
22
+ context "with an argument" do
23
+ let(:expected) { 'FOO' }
24
+
25
+ subject { Class.new(described_class) }
26
+ before { subject.usage expected }
27
+
28
+ it "should set the usage" do
29
+ subject.usage.should == expected
30
+ end
31
+ end
32
+
33
+ context "default" do
34
+ subject { Class.new(described_class).usage }
35
+
36
+ it { should == '[options]' }
37
+ end
38
+
39
+ context "inherited" do
40
+ let(:superclass) { TestCommand }
41
+
42
+ subject { Class.new(superclass).usage }
43
+
44
+ it "should default to the usage of the superclass" do
45
+ subject.should == superclass.usage
46
+ end
47
+ end
48
+ end
49
+
50
+ describe "summary" do
51
+ context "without an argument" do
52
+ it "should return the set summary" do
53
+ subject.summary.should == 'Tests the default task'
54
+ end
55
+ end
56
+
57
+ context "with an argument" do
58
+ let(:expected) { 'Performs foo' }
59
+
60
+ subject { Class.new(described_class) }
61
+ before { subject.summary expected }
62
+
63
+ it "should set the usage" do
64
+ subject.summary.should == expected
65
+ end
66
+ end
67
+
68
+ context "default" do
69
+ subject { Class.new(described_class).summary }
70
+
71
+ it { should == nil }
72
+ end
73
+
74
+ context "inherited" do
75
+ let(:superclass) { TestCommand }
76
+
77
+ subject { Class.new(superclass).summary }
78
+
79
+ it "should default to the summary of the superclass" do
80
+ subject.should == superclass.summary
81
+ end
82
+ end
83
+ end
84
+
85
+ describe "examples" do
86
+ context "without an argument" do
87
+ it "should return the set summary" do
88
+ # subject.example.should == 'Tests the default task'
89
+ end
90
+ end
91
+
92
+ context "with an argument" do
93
+ let(:expected) do
94
+ ['test_command --foo PATH', 'test_command --foo PATH FILE ...']
95
+ end
96
+
97
+ subject { Class.new(described_class) }
98
+ before { subject.examples expected }
99
+
100
+ it "should set the usage" do
101
+ subject.examples.should == expected
102
+ end
103
+ end
104
+
105
+ context "default" do
106
+ subject { Class.new(described_class).examples }
107
+
108
+ it { should == [] }
109
+ end
110
+
111
+ context "inherited" do
112
+ let(:superclass) { TestCommand }
113
+
114
+ subject { Class.new(superclass).examples }
115
+
116
+ it "should default to the examples of the superclass" do
117
+ subject.should == superclass.examples
118
+ end
119
+ end
120
+ end
121
+
122
+ describe "options" do
123
+ subject { Class.new(described_class).options }
124
+
125
+ context "inherited" do
126
+ it "should be {} by default" do
127
+ subject.should == {}
128
+ end
129
+ end
130
+
131
+ context described_class do
132
+ subject { described_class.options }
133
+
134
+ it "should have a :verbose option" do
135
+ subject.should have_key(:verbose)
136
+ end
137
+
138
+ it "should have a :quiet option" do
139
+ subject.should have_key(:quiet)
140
+ end
141
+
142
+ it "should have a :silent option" do
143
+ subject.should have_key(:silent)
144
+ end
145
+
146
+ it "should have a :color option" do
147
+ subject.should have_key(:color)
148
+ end
149
+
150
+ describe "color option" do
151
+ subject { described_class.new.color }
152
+
153
+ context "when $stdout is a TTY" do
154
+ it { should be_true }
155
+ end
156
+
157
+ context "when $stdout is not a TTY" do
158
+ before do
159
+ @old_stdout = $stdout
160
+ $stdout = StringIO.new
161
+ end
162
+
163
+ it { should be_false }
164
+
165
+ after do
166
+ $stdout = @old_stdout
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ describe "option" do
174
+ let(:name) { :foo }
175
+
176
+ it "should define an option" do
177
+ subject.options[name].should be_kind_of(Hash)
178
+ end
179
+
180
+ it "should define a parameter" do
181
+ subject.should have_param(name)
182
+ end
183
+ end
184
+
185
+ describe "each_option" do
186
+ let(:expected) { [:verbose, :quiet, :silent, :color, :foo] }
187
+
188
+ it "should iterate over each option" do
189
+ names = []
190
+
191
+ subject.each_option do |name,options|
192
+ names << name
193
+ end
194
+
195
+ names.should =~ expected
196
+ end
197
+ end
198
+
199
+ describe "options?" do
200
+ it "should test if there are any defined options" do
201
+ subject.options?.should be_true
202
+ end
203
+ end
204
+
205
+ describe "arguments" do
206
+ context "inherited" do
207
+ subject { Class.new(described_class).arguments }
208
+
209
+ it { should == [] }
210
+ end
211
+ end
212
+
213
+ describe "argument" do
214
+ let(:name) { :foo }
215
+
216
+ subject { Class.new(described_class) }
217
+ before { subject.argument name }
218
+
219
+ it "should add to arguments" do
220
+ subject.arguments.should include(name)
221
+ end
222
+
223
+ it "should define a parameter" do
224
+ subject.should have_param(name)
225
+ end
226
+ end
227
+
228
+ describe "each_argument" do
229
+ let(:expected) { [:path, :files] }
230
+
231
+ it "should iterate over each option" do
232
+ names = []
233
+
234
+ subject.each_argument { |name| names << name }
235
+
236
+ names.should =~ expected
237
+ end
238
+ end
239
+
240
+ describe "arguments?" do
241
+ it "should test if there are any defined arguments" do
242
+ subject.arguments?.should be_true
243
+ end
11
244
  end
12
245
 
13
246
  describe "#run" do
@@ -51,9 +284,4 @@ describe UI::CLI::Command do
51
284
  subject.files.should == files
52
285
  end
53
286
  end
54
-
55
- it "should have zero indentation by default" do
56
- command = subject.new
57
- command.instance_variable_get('@indent').should == 0
58
- end
59
287
  end