visionmedia-commander 2.5.7 → 3.0.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.
@@ -11,19 +11,14 @@ module Commander
11
11
 
12
12
  module UI
13
13
 
14
- ##
15
- # Format used within #log.
16
-
17
- LOG_FORMAT = "%15s %s"
18
-
19
14
  ##
20
15
  # Ask the user for a password. Specify a custom
21
- # _msg_ other than 'Password: ' or override the
16
+ # +message+ other than 'Password: ' or override the
22
17
  # default +mask+ of '*'.
23
18
 
24
- def password msg = "Password: ", mask = '*'
25
- pass = ask(msg) { |q| q.echo = mask }
26
- pass = password msg, mask if pass.empty?
19
+ def password message = 'Password: ', mask = '*'
20
+ pass = ask(message) { |q| q.echo = mask }
21
+ pass = password message, mask if pass.empty?
27
22
  pass
28
23
  end
29
24
 
@@ -35,11 +30,9 @@ module Commander
35
30
  # remove path/to/old_file.rb
36
31
  # remove path/to/old_file2.rb
37
32
  #
38
- # To alter this format simply change the Commander::UI::LOG_FORMAT
39
- # constant to whatever you like.
40
33
 
41
34
  def log action, *args
42
- say LOG_FORMAT % [action, args.join(' ')]
35
+ say '%15s %s' % [action, args.join(' ')]
43
36
  end
44
37
 
45
38
  ##
@@ -48,33 +41,34 @@ module Commander
48
41
  # Terminal progress bar utility. In its most basic form
49
42
  # requires that the developer specifies when the bar should
50
43
  # be incremented. Note that a hash of tokens may be passed to
51
- # #increment, (or returned when using Kernel#progress).
44
+ # #increment, (or returned when using Object#progress).
52
45
  #
53
- # uris = %w(
54
- # http://vision-media.ca
55
- # http://yahoo.com
56
- # http://google.com
57
- # )
46
+ # uris = %w(
47
+ # http://vision-media.ca
48
+ # http://yahoo.com
49
+ # http://google.com
50
+ # )
51
+ #
52
+ # bar = Commander::UI::ProgressBar.new uris.length, options
53
+ # threads = []
54
+ # uris.each do |uri|
55
+ # threads << Thread.new do
56
+ # begin
57
+ # res = open uri
58
+ # bar.increment :uri => uri
59
+ # rescue Exception => e
60
+ # bar.increment :uri => "#{uri} failed"
61
+ # end
62
+ # end
63
+ # end
64
+ # threads.each { |t| t.join }
58
65
  #
59
- # bar = Commander::UI::ProgressBar.new uris.length, options
60
- # threads = []
61
- # uris.each do |uri|
62
- # threads << Thread.new do
63
- # begin
64
- # res = open uri
65
- # bar.increment :uri => uri
66
- # rescue Exception => e
67
- # bar.increment :uri => "#{uri} failed"
68
- # end
69
- # end
70
- # end
71
- # threads.each { |t| t.join }
66
+ # The Object method #progress is also available:
72
67
  #
73
- # The Kernel method #progress is also available:
74
- #
75
- # progress uris, :width => 10 do |uri|
76
- # res = open uri
77
- # end
68
+ # progress uris, :width => 10 do |uri|
69
+ # res = open uri
70
+ # { :uri => uri } # Can now use :uri within :format option
71
+ # end
78
72
  #
79
73
 
80
74
  class ProgressBar
@@ -171,14 +165,12 @@ module Commander
171
165
  # Output the progress bar.
172
166
 
173
167
  def show
174
- # TODO: shift steps stack instead
175
168
  unless finished?
176
169
  erase_line
177
170
  if completed?
178
- puts @complete_message.tokenize(generate_tokens) if @complete_message.is_a? String
171
+ $terminal.say @complete_message.tokenize(generate_tokens) if @complete_message.is_a? String
179
172
  else
180
- print @format.tokenize(generate_tokens)
181
- $stdout.flush
173
+ $terminal.say @format.tokenize(generate_tokens) << ' '
182
174
  end
183
175
  end
184
176
  end
@@ -211,7 +203,8 @@ module Commander
211
203
  # Erase previous terminal line.
212
204
 
213
205
  def erase_line
214
- print "\r\e[K"
206
+ # highline does not expose the output stream
207
+ $terminal.instance_variable_get('@output').print "\r\e[K"
215
208
  end
216
209
 
217
210
  ##
@@ -226,7 +219,8 @@ module Commander
226
219
  #
227
220
  # === See:
228
221
  #
229
- # * Kernel#progress
222
+ # * Object#progress
223
+ #
230
224
 
231
225
  def self.progress arr, options = {}, &block
232
226
  bar = ProgressBar.new arr.length, options
@@ -1,4 +1,4 @@
1
1
 
2
2
  module Commander
3
- VERSION = '2.5.7'
3
+ VERSION = '3.0.0'
4
4
  end
@@ -0,0 +1,128 @@
1
+
2
+ describe Commander::Command do
3
+
4
+ before :each do
5
+ mock_terminal
6
+ create_test_command
7
+ end
8
+
9
+ describe "#seperate_switches_from_description" do
10
+ it "should seperate switches and description returning both" do
11
+ switches, description = *@command.seperate_switches_from_description('-h', '--help', 'display help')
12
+ switches.should == ['-h', '--help']
13
+ description.should == 'display help'
14
+ end
15
+ end
16
+
17
+ describe "#option" do
18
+ it "should add options" do
19
+ lambda { @command.option '--recursive' }.should change(@command.options, :length).from(2).to(3)
20
+ end
21
+
22
+ it "should allow procs as option handlers" do
23
+ @command.option('--recursive') { |recursive| recursive.should be_true }
24
+ @command.run '--recursive'
25
+ end
26
+ end
27
+
28
+ describe "#options" do
29
+ it "should distinguish between switches and descriptions" do
30
+ @command.option '-t', '--trace', 'some description'
31
+ @command.options[2][:description].should == 'some description'
32
+ @command.options[2][:switches].should == ['-t', '--trace']
33
+ end
34
+ end
35
+
36
+ describe "#switch_to_sym" do
37
+ it "should return a symbol based on the switch name" do
38
+ @command.switch_to_sym('--trace').should == :trace
39
+ @command.switch_to_sym('--foo-bar').should == :foo_bar
40
+ @command.switch_to_sym('--[no-]feature"').should == :feature
41
+ @command.switch_to_sym('--[no-]feature ARG').should == :feature
42
+ @command.switch_to_sym('--file [ARG]').should == :file
43
+ @command.switch_to_sym('--colors colors').should == :colors
44
+ end
45
+ end
46
+
47
+ describe "#run" do
48
+ describe "should invoke #when_called" do
49
+ it "with arguments seperated from options" do
50
+ @command.when_called { |args, options| args.join(' ').should == 'just some args' }
51
+ @command.run '--trace', 'just', 'some', 'args'
52
+ end
53
+
54
+ it "calling the #call method by default when an object is called" do
55
+ object = mock 'Object'
56
+ object.should_receive(:call).with(an_instance_of(Array), an_instance_of(Commander::Command::Options)).once
57
+ @command.when_called object
58
+ @command.run 'foo'
59
+ end
60
+
61
+ it "calling an arbitrary method when an object is called" do
62
+ object = mock 'Object'
63
+ object.should_receive(:foo).with(an_instance_of(Array), an_instance_of(Commander::Command::Options)).once
64
+ @command.when_called object, :foo
65
+ @command.run 'foo'
66
+ end
67
+
68
+ it "should raise an error when no handler is present" do
69
+ lambda { @command.when_called }.should raise_error(ArgumentError)
70
+ end
71
+ end
72
+
73
+ describe "should populate options with" do
74
+ it "boolean values" do
75
+ @command.option '--[no-]toggle'
76
+ @command.when_called { |_, options| options.toggle.should be_true }
77
+ @command.run '--toggle'
78
+ @command.when_called { |_, options| options.toggle.should be_false }
79
+ @command.run '--no-toggle'
80
+ end
81
+
82
+ it "manditory arguments" do
83
+ @command.option '--file FILE'
84
+ @command.when_called { |_, options| options.file.should == 'foo' }
85
+ @command.run '--file', 'foo'
86
+ lambda { @command.run '--file' }.should raise_error(OptionParser::MissingArgument)
87
+ end
88
+
89
+ it "optional arguments" do
90
+ @command.option '--use-config [file] '
91
+ @command.when_called { |_, options| options.use_config.should == 'foo' }
92
+ @command.run '--use-config', 'foo'
93
+ @command.when_called { |_, options| options.use_config.should be_nil }
94
+ @command.run '--use-config'
95
+ @command.option '--interval N', Integer
96
+ @command.when_called { |_, options| options.interval.should == 5 }
97
+ @command.run '--interval', '5'
98
+ lambda { @command.run '--interval', 'invalid' }.should raise_error(OptionParser::InvalidArgument)
99
+ end
100
+
101
+ it "lists" do
102
+ @command.option '--fav COLORS', Array
103
+ @command.when_called { |_, options| options.fav.should == ['red', 'green', 'blue'] }
104
+ @command.run '--fav', 'red,green,blue'
105
+ end
106
+
107
+ it "lists with multi-word items" do
108
+ @command.option '--fav MOVIES', Array
109
+ @command.when_called { |_, options| options.fav.should == ['super\ bad', 'nightmare'] }
110
+ @command.run '--fav', 'super\ bad,nightmare'
111
+ end
112
+
113
+ it "defaults" do
114
+ @command.option '--files LIST', Array
115
+ @command.option '--interval N', Integer
116
+ @command.when_called do |_, options|
117
+ options.default \
118
+ :files => ['foo', 'bar'],
119
+ :interval => 5
120
+ options.files.should == ['foo', 'bar']
121
+ options.interval.should == 15
122
+ end
123
+ @command.run '--interval', '15'
124
+ end
125
+ end
126
+ end
127
+
128
+ end
@@ -0,0 +1,20 @@
1
+
2
+ describe Array do
3
+
4
+ describe "#delete_switches" do
5
+ it "should delete switches such as -h or --help, returning a new array" do
6
+ ['foo', '-h', 'bar', '--help'].delete_switches.should == ['foo', 'bar']
7
+ end
8
+ end
9
+
10
+ describe "#parse" do
11
+ it "should seperate a list of words into an array" do
12
+ Array.parse('just a test').should == ['just', 'a', 'test']
13
+ end
14
+
15
+ it "should preserve escaped whitespace" do
16
+ Array.parse('just a\ test').should == ['just', 'a test']
17
+ end
18
+ end
19
+
20
+ end
@@ -1,13 +1,20 @@
1
- describe Kernel do
1
+
2
+ describe Object do
2
3
 
4
+ describe "#get_binding" do
5
+ it "should return the objects binding" do
6
+ lambda {}.get_binding.should be_instance_of(Binding)
7
+ end
8
+ end
9
+
3
10
  describe "#method_missing" do
4
11
  it "should preserve its original behavior for missing methods" do
5
12
  lambda { i_am_a_missing_method() }.should raise_error(NoMethodError)
6
13
  end
7
-
14
+
8
15
  it "should preserve its original behavior for missing variables" do
9
16
  lambda { i_am_a_missing_variable }.should raise_error(NameError)
10
17
  end
11
18
  end
12
-
19
+
13
20
  end
@@ -2,30 +2,30 @@
2
2
  describe Commander::HelpFormatter do
3
3
 
4
4
  before :each do
5
- @input = StringIO.new
6
- @output = StringIO.new
7
- $terminal = HighLine.new @input, @output
5
+ mock_terminal
6
+ end
7
+
8
+ def run *args
9
+ new_command_runner *args do
10
+ program :help_formatter, Commander::HelpFormatter::Base
11
+ end.run!
12
+ @output.string
8
13
  end
9
14
 
10
15
  it "should display global help using --help switch" do
11
- new_command_runner '--help'
12
- program :help_formatter, Commander::HelpFormatter::Base
13
- command_runner.run!
14
- @output.string.should eql("Implement global help here\n")
16
+ run('--help').should == "Implement global help here\n"
15
17
  end
16
18
 
17
19
  it "should display global help using help command" do
18
- new_command_runner 'help'
19
- program :help_formatter, Commander::HelpFormatter::Base
20
- command_runner.run!
21
- @output.string.should eql("Implement global help here\n")
20
+ run('help').should == "Implement global help here\n"
22
21
  end
23
22
 
24
23
  it "should display command help" do
25
- new_command_runner 'help', 'test'
26
- program :help_formatter, Commander::HelpFormatter::Base
27
- command_runner.run!
28
- @output.string.should eql("Implement help for test here\n")
24
+ run('help', 'test').should == "Implement help for test here\n"
25
+ end
26
+
27
+ it "should display command help using --help switch" do
28
+ run('--help', 'test').should == "Implement help for test here\n"
29
29
  end
30
30
 
31
31
  end
@@ -0,0 +1,168 @@
1
+
2
+ describe Commander do
3
+
4
+ before :each do
5
+ mock_terminal
6
+ create_test_command
7
+ end
8
+
9
+ describe "#program" do
10
+ it "should set / get program information" do
11
+ program :name, 'test'
12
+ program(:name).should == 'test'
13
+ end
14
+
15
+ it "should allow arbitrary blocks of global help documentation" do
16
+ program :help, 'Copyright', 'TJ Holowaychuk'
17
+ program(:help)['Copyright'].should == 'TJ Holowaychuk'
18
+ end
19
+
20
+ it "should raise an error when required info has not been set" do
21
+ new_command_runner '--help'
22
+ program :name, ''
23
+ lambda { run! }.should raise_error(Commander::Runner::CommandError)
24
+ end
25
+ end
26
+
27
+ describe "#command" do
28
+ it "should return a command instance when only the name is passed" do
29
+ command(:test).should be_instance_of(Commander::Command)
30
+ end
31
+
32
+ it "should raise InvalidCommandError when the command does not exist" do
33
+ lambda { command(:im_not_real) }.should raise_error(Commander::Runner::InvalidCommandError)
34
+ end
35
+ end
36
+
37
+ describe "--version" do
38
+ it "should output program version" do
39
+ new_command_runner '--version' do
40
+ program :help_formatter, Commander::HelpFormatter::Base
41
+ end.run!
42
+ @output.string.should == "test 1.2.3\n"
43
+ end
44
+ end
45
+
46
+ describe "--help" do
47
+ it "should not output an invalid command message" do
48
+ new_command_runner('--help').run!
49
+ @output.string.should_not == "invalid command. Use --help for more information\n"
50
+ end
51
+ end
52
+
53
+ describe "with invalid options" do
54
+ it "should output an invalid option message" do
55
+ new_command_runner('test', '--invalid-option').run!
56
+ @output.string.should == "invalid option: --invalid-option\n"
57
+ end
58
+ end
59
+
60
+ describe "with invalid sub-command passed" do
61
+ it "should output an invalid command message" do
62
+ new_command_runner('foo').run!
63
+ @output.string.should == "invalid command. Use --help for more information\n"
64
+ end
65
+ end
66
+
67
+ describe "with invalid sub-command passed to help" do
68
+ it "should output an invalid command message" do
69
+ new_command_runner('help', 'does_not_exist').run!
70
+ @output.string.should == "invalid command. Use --help for more information\n"
71
+ end
72
+ end
73
+
74
+ describe "#valid_command_names_from" do
75
+ it "should return array of valid command names" do
76
+ command('foo bar') {}
77
+ command('foo bar foo') {}
78
+ command_runner.valid_command_names_from('foo', 'bar', 'foo').should == ['foo bar', 'foo bar foo']
79
+ end
80
+
81
+ it "should return empty array when no possible command names exist" do
82
+ command_runner.valid_command_names_from('fake', 'command', 'name').should == []
83
+ end
84
+ end
85
+
86
+ describe "#command_name_from_args" do
87
+ it "should locate command within arbitrary arguments passed" do
88
+ new_command_runner '--help', '--arbitrary', 'test'
89
+ command_runner.command_name_from_args.should == 'test'
90
+ end
91
+
92
+ it "should support multi-word commands" do
93
+ new_command_runner '--help', '--arbitrary', 'some', 'long', 'command', 'foo'
94
+ command('some long command') {}
95
+ command_runner.command_name_from_args.should == 'some long command'
96
+ end
97
+
98
+ it "should match the longest possible command" do
99
+ new_command_runner '--help', '--arbitrary', 'foo', 'bar', 'foo'
100
+ command('foo bar') {}
101
+ command('foo bar foo') {}
102
+ command_runner.command_name_from_args.should == 'foo bar foo'
103
+ end
104
+ end
105
+
106
+ describe "#active_command" do
107
+ it "should resolve the active command" do
108
+ new_command_runner '--help', 'test'
109
+ command_runner.active_command.should be_instance_of(Commander::Command)
110
+ end
111
+
112
+ it "should resolve active command when invalid options are passed" do
113
+ new_command_runner '--help', 'test', '--arbitrary'
114
+ command_runner.active_command.should be_instance_of(Commander::Command)
115
+ end
116
+
117
+ it "should raise invalid command error when the command is not found" do
118
+ new_command_runner 'foo'
119
+ lambda { command_runner.active_command }.should raise_error(Commander::Runner::InvalidCommandError)
120
+ end
121
+ end
122
+
123
+ describe "should function correctly" do
124
+ it "when options are passed before the command name" do
125
+ new_command_runner '--trace', 'test', 'foo', 'bar' do
126
+ @command.when_called do |args, options|
127
+ args.should == ['foo', 'bar']
128
+ options.trace.should be_true
129
+ end
130
+ end.run!
131
+ end
132
+
133
+ it "when options are passed after the command name" do
134
+ new_command_runner 'test', '--trace', 'foo', 'bar' do
135
+ @command.when_called do |args, options|
136
+ args.should == ['foo', 'bar']
137
+ options.trace.should be_true
138
+ end
139
+ end.run!
140
+ end
141
+
142
+ it "when an argument passed is the same name as the command" do
143
+ new_command_runner 'test', '--trace', 'foo', 'test', 'bar' do
144
+ @command.when_called do |args, options|
145
+ args.should == ['foo', 'test', 'bar']
146
+ options.trace.should be_true
147
+ end
148
+ end.run!
149
+ end
150
+
151
+ it "when using multi-word commands" do
152
+ new_command_runner '--trace', 'my', 'command', 'something', 'foo', 'bar' do
153
+ command('my command') {}
154
+ command_runner.command_name_from_args.should == 'my command'
155
+ command_runner.args_without_command_name.should == ['--trace', 'something', 'foo', 'bar']
156
+ end.run!
157
+ end
158
+
159
+ it "when using multi-word commands with parts of the command name as arguments" do
160
+ new_command_runner '--trace', 'my', 'command', 'something', 'my', 'command' do
161
+ command('my command') {}
162
+ command_runner.command_name_from_args.should == 'my command'
163
+ command_runner.args_without_command_name.should == ['--trace', 'something', 'my', 'command']
164
+ end.run!
165
+ end
166
+ end
167
+
168
+ end