optitron 0.0.11 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- optitron (0.0.10)
4
+ optitron (0.0.11)
5
5
  callsite (= 0.0.4)
6
6
  ruby2ruby (= 1.2.4)
7
7
  ruby_parser (>= 2.0)
@@ -2,7 +2,108 @@
2
2
 
3
3
  == Sensible options parsing
4
4
 
5
- You can specify lots of different commands with options
5
+ Optitron strives to be simple, minimal and to do the "right thing" most of the time. The structure is simple, you have global options, a list of commands, and each of those commands takes a number of arguments and options.
6
+
7
+ == Usage
8
+
9
+ To create an Optitron CLI, start with a class you want to wire up as a CLI. In our example, we'll use the class Runner, which we want to work as a CLI.
10
+
11
+ class Runner
12
+ def start
13
+ # ... starts
14
+ end
15
+
16
+ def stop
17
+ # ... stops
18
+ end
19
+
20
+ def status
21
+ # ... reports status
22
+ end
23
+ end
24
+
25
+ To make this class suitable for use as a CLI, either extend <tt>Optitron::CLI</tt> or include <tt>Optitron::ClassDsl</tt>. Then, describe each argument as follows:
26
+
27
+ class Runner < Optitron::CLI
28
+ desc "Starts the process"
29
+ def start
30
+ # ... starts
31
+ end
32
+
33
+ desc "Stops the process"
34
+ def stop
35
+ # ... stops
36
+ end
37
+
38
+ desc "Report the status"
39
+ def status
40
+ # ... reports status
41
+ end
42
+ end
43
+
44
+ Only methods described will be available to the CLI. If you have a method that needs arguments, simply include them as method arguments. It will respect splats and defaults. Options are specified with the +opt+ method in your class, as follows:
45
+
46
+ class Runner < Optitron::CLI
47
+ desc "Starts the process"
48
+ opt "verbose"
49
+ opt "environment", :in => ['development', 'production', 'staging', 'test']
50
+ def start
51
+ # ... starts
52
+ end
53
+
54
+ # .. more methods
55
+
56
+ end
57
+
58
+
59
+ If you need an option available for all methods, use +class_opt+ to specify it.
60
+
61
+ class Runner < Optitron::CLI
62
+ class_opt "verbose", "Be loud"
63
+
64
+ # ... your methods
65
+ end
66
+
67
+ The last line in your runner has to be the class name and dispatch. This will parse <tt>ARGV</tt> and execute normal dispatching on it.
68
+
69
+ class Runner < Optitron::CLI
70
+ # ... your methods
71
+ end
72
+ Runner.dispatch
73
+
74
+ As well, help is added by default, but, if you don't want to use this, include the command +dont_use_help+ in your class.
75
+
76
+ == How to configure options
77
+
78
+ Options can have defaults, types and inclusion checks. Here are all the options available on an opt:
79
+
80
+ === <tt>:default</tt>
81
+
82
+ This allows you to specify a default value. The type of value is used to infer the type required for this option. This can be over-ridden with <tt>:type</tt>.
83
+
84
+ === <tt>:short_name</tt>
85
+
86
+ This allows you to set a short name for the option, though, one will be assigned automatically from the short names available.
87
+
88
+ === <tt>:run</tt>
89
+
90
+ This allows you to run an arbitrary block for an option. The proc will be called with the value, and the response object.
91
+
92
+ === <tt>:in</tt>
93
+
94
+ This allows you to test for inclusion in a range or array (or anything that responds to <tt>#include?</tt> and <tt>#first</tt>). The first item in the object will be used to infer the type. This can be over-ridden with <tt>:type</tt>.
95
+
96
+ === <tt>:required</tt>
97
+
98
+ This allows you to force an option to be required. False by default.
99
+
100
+ ==== <tt>:type</tt>
101
+
102
+ This allows you to specify the type. Acceptable options are <tt>:numeric</tt>, <tt>:array</tt>, <tt>:hash</tt>, <tt>:string</tt> or <tt>:boolean</tt>.
103
+
104
+ == Stand alone usage
105
+
106
+ You can create parsers and parse using them.
6
107
 
7
108
  @parser = Optitron.new {
8
109
  help
@@ -24,11 +125,11 @@ You can specify lots of different commands with options
24
125
  end
25
126
  }
26
127
 
27
- Want to see the help?
128
+ To generate help, use the <tt>#help</tt> method.
28
129
 
29
130
  @parser.help
30
131
 
31
- Will output:
132
+ Which returns,
32
133
 
33
134
  Commands
34
135
 
@@ -44,7 +145,7 @@ Will output:
44
145
 
45
146
  -v/--verbose # Be very loud
46
147
 
47
- And <tt>@parser.parse(%w(-v install file))</tt> gives back:
148
+ The parse method can parse a list of arguments. For example, <tt>@parser.parse(%w(-v install file))</tt> gives back:
48
149
 
49
150
  response = @parser.parse(%w(-v install file))
50
151
  response.command
@@ -54,7 +155,7 @@ And <tt>@parser.parse(%w(-v install file))</tt> gives back:
54
155
  response.params
55
156
  => {"verbose" => true}
56
157
 
57
- If you try parsing invalid parameters, get back friendly error messages
158
+ If you try parsing invalid parameters, you can get back friendly error messages using <tt>#error_messages</tt>.
58
159
 
59
160
  @parser.parse(%w()).error_messages
60
161
  => ["Unknown command"]
@@ -64,88 +165,3 @@ If you try parsing invalid parameters, get back friendly error messages
64
165
  => ["File is required"]
65
166
  @parser.parse(%w(kill --pid=something)).error_messages
66
167
  => ["Pid is invalid"]
67
-
68
- == Usage in a binary
69
-
70
- To use this in a file, create a parser, and tell it to dispatch to your favourite object. For instance, save this down to <tt>test.rb</tt>
71
-
72
- class Runner
73
- def install(file, opts)
74
- puts "installing #{file} with #{opts}!"
75
- end
76
- end
77
-
78
- Optitron.dispatch(Runner.new) {
79
- opt 'verbose', "Be very loud"
80
- cmd "install", "This installs things" do
81
- arg "file", "The file to install"
82
- end
83
- cmd "show", "This shows things" do
84
- arg "first", "The first thing to show"
85
- arg "second", "The second optional thing to show", :required => false
86
- end
87
- cmd "kill", "This kills things" do
88
- opt "pids", "A list of pids to kill", :type => :array
89
- opt "pid", "A pid to kill", :type => :numeric
90
- opt "names", "Some sort of hash", :type => :hash
91
- end
92
- cmd "join", "This joins things" do
93
- arg "thing", "Stuff to join", :type => :greedy
94
- end
95
- }
96
-
97
- Now, try running it.
98
-
99
- crapbook-pro:optitron joshua$ ruby test.rb
100
- Unknown command
101
-
102
- crapbook-pro:optitron joshua$ ruby test.rb install
103
- File is required
104
-
105
- crapbook-pro:optitron joshua$ ruby test.rb install file
106
- installing file with {"verbose"=>false}!
107
-
108
- crapbook-pro:optitron joshua$ ruby test.rb install file --verbose
109
- installing file with {"verbose"=>true}!
110
-
111
- == Usage in a class
112
-
113
- require 'optitron'
114
-
115
- class Runner < Optitron::CLI
116
-
117
- class_opt 'verbose'
118
-
119
- desc "Install stuff"
120
- opt 'force'
121
- def install(file, source)
122
- puts "install some things #{file} from #{source.inspect} #{params.inspect}"
123
- end
124
- end
125
-
126
- Runner.dispatch
127
-
128
- Running this gives you
129
-
130
- crapbook-pro:optitron joshua$ ruby ideal.rb --help
131
- Commands
132
-
133
- install [file] <required="yourmom"> # Install stuff
134
- -f/--force
135
-
136
- Global options
137
-
138
- -v/--verbose
139
- -?/--help # Print help message
140
-
141
- crapbook-pro:optitron joshua$ ruby ideal.rb install
142
- File is required
143
-
144
- crapbook-pro:optitron joshua$ ruby ideal.rb install file
145
- installing file from yourmom with params: {"help"=>false, "force"=>false, "verbose"=>false}
146
-
147
- crapbook-pro:optitron joshua$ ruby ideal.rb install file yourdad
148
- installing file from yourdad with params: {"help"=>false, "force"=>false, "verbose"=>false}
149
-
150
- crapbook-pro:optitron joshua$ ruby ideal.rb install file yourdad -v
151
- installing file from yourdad with params: {"help"=>false, "force"=>false, "verbose"=>true}
@@ -25,12 +25,6 @@ class Optitron
25
25
  Optitron.new(&blk).parse(args)
26
26
  end
27
27
 
28
- def self.dispatch(target = nil, args = ARGV, &blk)
29
- optitron = Optitron.new(&blk)
30
- optitron.parser.target = target
31
- optitron.parser.parse(args).dispatch
32
- end
33
-
34
28
  def help
35
29
  @parser.help
36
30
  end
@@ -96,12 +96,12 @@ class Optitron
96
96
  end
97
97
 
98
98
  def build_method_args(file)
99
- unless self.send(:class_variable_defined?, :@@method_args)
99
+ unless send(:class_variable_defined?, :@@method_args)
100
100
  parser = RubyParser.new
101
101
  sexp = parser.process(File.read(file))
102
102
  method_args = MethodArgs.new(self)
103
103
  method_args.process(sexp)
104
- self.send(:class_variable_set, :@@method_args, method_args.method_map)
104
+ send(:class_variable_set, :@@method_args, method_args.method_map)
105
105
  end
106
106
  send(:class_variable_get, :@@method_args)
107
107
  end
@@ -111,7 +111,7 @@ class Optitron
111
111
  end
112
112
 
113
113
  def dont_use_help
114
- optitron_dsl.root.help
114
+ send(:class_variable_set, :@@suppress_help, true)
115
115
  end
116
116
 
117
117
  def desc(desc)
@@ -126,7 +126,7 @@ class Optitron
126
126
 
127
127
  def build
128
128
  unless @built
129
- optitron_dsl.root.help
129
+ optitron_dsl.root.help# if send(:class_variable_defined?, :@@suppress_help)
130
130
  @cmds.each do |(cmd_name, cmd_desc, opts)|
131
131
  args = method_args[cmd_name.to_sym]
132
132
  arity = instance_method(cmd_name).arity
@@ -156,8 +156,8 @@ class Optitron
156
156
  if response.valid?
157
157
  optitron_parser.target.params = response.params
158
158
  args = response.args
159
- while (args.size < optitron_parser.commands[response.command].args.size)
160
- args << optitron_parser.commands[response.command].args[args.size].default
159
+ while (args.size < optitron_parser.commands.assoc(response.command).last.args.size)
160
+ args << optitron_parser.commandsassoc(response.command).last.args[args.size].default
161
161
  end
162
162
  optitron_parser.target.send(response.command.to_sym, *response.args)
163
163
  else
@@ -40,8 +40,8 @@ class Optitron
40
40
  end
41
41
 
42
42
  def arg(name, description = nil, opts = nil)
43
- arg_option = Option::Arg.new(name, description, opts)
44
- raise InvalidParser.new if @target.args.last and !@target.args.last.required? and arg_option.required?
43
+ arg_option = Option::Arg.new(name, description, opts)
44
+ raise InvalidParser.new if @target.args.last and !@target.args.last.required? and arg_option.required? and arg_option.type != :greedy
45
45
  raise InvalidParser.new if @target.args.last and @target.args.last.type == :greedy
46
46
  @target.args << arg_option
47
47
  arg_option
@@ -100,7 +100,7 @@ class Optitron
100
100
  def cmd(name, description = nil, opts = nil, &blk)
101
101
  command_option = Option::Cmd.new(name, description, opts)
102
102
  CmdParserDsl.new(self, command_option).configure_with(&blk) if blk
103
- @target.commands[name] = command_option
103
+ @target.commands << [name, command_option]
104
104
  end
105
105
  end
106
106
  end
@@ -4,10 +4,23 @@ class Optitron
4
4
  @parser = parser
5
5
  end
6
6
 
7
+ def help_line_for_opt_value(opt)
8
+ if opt.inclusion_test
9
+ case opt.inclusion_test
10
+ when Array
11
+ opt.inclusion_test.join(', ')
12
+ else
13
+ opt.inclusion_test.inspect
14
+ end
15
+ else
16
+ opt.type.to_s.upcase
17
+ end
18
+ end
19
+
7
20
  def help_line_for_opt(opt)
8
21
  opt_line = ''
9
22
  opt_line << [opt.short_name ? "-#{opt.short_name}" : nil, "--#{opt.name}"].compact.join('/')
10
- opt_line << "=[#{opt.type.to_s.upcase}]" unless opt.boolean?
23
+ opt_line << "=[#{help_line_for_opt_value(opt)}]" unless opt.boolean?
11
24
  [opt_line, opt.desc]
12
25
  end
13
26
 
@@ -27,15 +40,15 @@ class Optitron
27
40
  end
28
41
 
29
42
  def generate
30
- cmds = {}
31
- @parser.commands.each do |cmd_name, cmd|
43
+ cmds = []
44
+ @parser.commands.each do |(cmd_name, cmd)|
32
45
  cmd_line = "#{cmd_name}"
33
46
  cmd.args.each do |arg|
34
47
  cmd_line << " " << help_line_for_arg(arg)
35
48
  end
36
- cmds[cmd_line] = [cmd.desc]
49
+ cmds << [cmd_line, cmd.desc]
37
50
  cmd.options.each do |opt|
38
- cmds[cmd_line] << help_line_for_opt(opt)
51
+ cmds.assoc(cmd_line) << help_line_for_opt(opt)
39
52
  end
40
53
  end
41
54
  opts_lines = @parser.options.map do |opt|
@@ -45,7 +58,7 @@ class Optitron
45
58
  args_lines = @parser.args.empty? ? nil : [@parser.args.map{|arg| help_line_for_arg(arg)}.join(' '), @parser.args.map{|arg| arg.desc}.join(', ')]
46
59
 
47
60
  longest_line = 0
48
- longest_line = [longest_line, cmds.keys.map{|k| k.size}.max].max unless cmds.empty?
61
+ longest_line = [longest_line, cmds.map{|cmd| cmd.first.size}.max].max unless cmds.empty?
49
62
  opt_lines = cmds.map{|k,v| k.size + 2}.flatten
50
63
  longest_line = [longest_line, args_lines.first.size].max if args_lines
51
64
  longest_line = [longest_line, opt_lines.max].max unless opt_lines.empty?
@@ -53,7 +66,7 @@ class Optitron
53
66
  help_output = []
54
67
 
55
68
  unless cmds.empty?
56
- help_output << "Commands\n\n" + cmds.map do |cmd, opts|
69
+ help_output << "Commands\n\n" + cmds.map do |(cmd, *opts)|
57
70
  cmd_text = ""
58
71
  cmd_text << "%-#{longest_line}s " % cmd
59
72
  cmd_desc = opts.shift
@@ -1,5 +1,6 @@
1
1
  class Optitron
2
2
  class Option
3
+ attr_reader :inclusion_test
3
4
  attr_accessor :required, :name, :default, :parameterize, :type, :desc, :has_default
4
5
  alias_method :required?, :required
5
6
  alias_method :has_default?, :has_default
@@ -89,16 +90,18 @@ class Optitron
89
90
  end
90
91
 
91
92
  class Opt < Option
92
- attr_accessor :short_name, :run, :parent_cmd
93
+ attr_accessor :short_name, :run, :parent_cmd, :include_in_params
94
+ alias_method :include_in_params?, :include_in_params
93
95
  def initialize(name, desc = nil, opts = nil)
94
96
  if desc.is_a?(Hash)
95
97
  desc, opts = nil, desc
96
98
  end
97
99
  @name, @desc = name, desc
98
- @type = opts && opts[:type] || :boolean
100
+ self.type = opts && opts[:type] || :boolean
99
101
  self.short_name = opts[:short_name] if opts && opts[:short_name]
100
102
  self.run = opts[:run] if opts && opts[:run]
101
103
  self.inclusion_test = opts[:in] if opts && opts[:in]
104
+ self.required = opts && opts.key?(:required) ? opts[:required] : false
102
105
  self.default = opts && opts.key?(:default) ? opts[:default] : (@type == :boolean ? false : nil)
103
106
  end
104
107
 
@@ -180,16 +183,15 @@ class Optitron
180
183
 
181
184
  class Arg < Option
182
185
  attr_accessor :greedy, :inclusion_test, :parent_cmd
183
- alias_method :greedy?, :greedy
184
186
  def initialize(name = nil, desc = nil, opts = nil)
185
187
  if desc.is_a?(Hash)
186
188
  desc, opts = nil, desc
187
189
  end
188
190
  @name, @desc = name, desc
189
191
  self.inclusion_test = opts[:in] if opts && opts[:in]
190
- @default = opts && opts[:default]
191
- @required = opts && opts.key?(:required) ? opts[:required] : @default.nil?
192
- @type = opts && opts[:type]
192
+ self.default = opts && opts[:default]
193
+ self.type = opts && opts[:type]
194
+ self.required = opts && opts.key?(:required) ? opts[:required] : (@default.nil? and !greedy?)
193
195
  end
194
196
 
195
197
  def consume(response, tokens)
@@ -199,7 +201,7 @@ class Optitron
199
201
  while !arg_tokens.size.zero?
200
202
  arg_tok = arg_tokens.shift
201
203
  tokens.delete_at(tokens.index(arg_tok))
202
- response.args_with_tokens.last.last << arg_tok
204
+ response.args_with_tokens.last.last << arg_tok.lit
203
205
  end
204
206
  if required? and response.args_with_tokens.last.last.size.zero?
205
207
  response.add_error("required", name)
@@ -210,7 +212,9 @@ class Optitron
210
212
  elsif !arg_tokens.size.zero?
211
213
  arg_tok = arg_tokens.shift
212
214
  tokens.delete_at(tokens.index(arg_tok))
213
- response.args_with_tokens << [self, arg_tok]
215
+ response.args_with_tokens << [self, arg_tok.lit]
216
+ elsif has_default
217
+ response.args_with_tokens << [self, default]
214
218
  end
215
219
  end
216
220
  end
@@ -5,7 +5,7 @@ class Optitron
5
5
 
6
6
  def initialize
7
7
  @options = []
8
- @commands = {}
8
+ @commands = []
9
9
  @args = []
10
10
  @short_opts = {}
11
11
  @help = Help.new(self)
@@ -22,11 +22,11 @@ class Optitron
22
22
  args = @args
23
23
  unless @commands.empty?
24
24
  potential_cmd_toks = tokens.select { |t| t.respond_to?(:lit) }
25
- if cmd_tok = potential_cmd_toks.find { |t| @commands[t.lit] }
25
+ if cmd_tok = potential_cmd_toks.find { |t| @commands.assoc(t.lit) }
26
26
  tokens.delete(cmd_tok)
27
27
  response.command = cmd_tok.lit
28
- options += @commands[cmd_tok.lit].options
29
- args = @commands[cmd_tok.lit].args
28
+ options += @commands.assoc(cmd_tok.lit).last.options
29
+ args = @commands.assoc(cmd_tok.lit).last.args
30
30
  else
31
31
  potential_cmd_toks.first ?
32
32
  response.add_error('an unknown command', potential_cmd_toks.first.lit) :
@@ -45,12 +45,14 @@ class Optitron
45
45
  if opt_tok = tokens.find { |tok| opt.match?(tok) }
46
46
  opt_tok_index = tokens.index(opt_tok)
47
47
  opt.consume(response, tokens)
48
+ elsif opt.required?
49
+ response.add_error("required", opt.name)
48
50
  end
49
51
  end
50
52
  end
51
53
 
52
54
  def parse_args(tokens, args, response)
53
- args.each { |arg| arg.consume(response, tokens) } if args
55
+ args.each { |arg| arg.consume(response, tokens) }
54
56
  end
55
57
  end
56
58
  end
@@ -1,6 +1,6 @@
1
1
  class Optitron
2
2
  class Response
3
- attr_reader :params_array, :args, :params, :args_with_tokens, :errors
3
+ attr_reader :params_array, :args, :params, :args_with_tokens, :errors, :args_hash
4
4
  attr_accessor :command
5
5
  def initialize(parser, tokens)
6
6
  @parser, @tokens = parser, tokens
@@ -34,15 +34,17 @@ class Optitron
34
34
  def validate
35
35
  compile_params
36
36
  @params_array.each { |(key, value)| key.run.call(params[key.name], self) if key.run }
37
- @args = @args_with_tokens.map { |(arg, tok)|
37
+ @args_array = @args_with_tokens.map { |(arg, val)|
38
38
  begin
39
- tok.is_a?(Array) ? tok.map{ |t| arg.validate(t.lit) } : arg.validate(tok.lit)
39
+ [arg, arg.validate(val)]
40
40
  rescue
41
41
  add_error('invalid', arg.name)
42
- tok.is_a?(Array) ? tok.map{ |t| t.lit } : tok.lit
42
+ [arg, val]
43
43
  end
44
44
  }
45
- @args.flatten!
45
+ @args_hash = Hash[@args_array.map{|(arg, val)| [arg.name, val]}]
46
+
47
+ @args = @args_array.inject([]) {|args, (arg, val)| arg.greedy? ? args.concat(val) : args.push(val); args}
46
48
  unless @tokens.empty?
47
49
  @tokens.select{|t| t.respond_to?(:name)}.each do |named_token|
48
50
  @tokens.delete(named_token)
@@ -57,16 +59,6 @@ class Optitron
57
59
  end
58
60
  end
59
61
 
60
- def dispatch
61
- raise unless @parser.target
62
- if valid?
63
- dispatch_args = params.empty? ? args : args + [params]
64
- @parser.target.send(command.to_sym, *dispatch_args)
65
- else
66
- puts error_messages.join("\n")
67
- end
68
- end
69
-
70
62
  def valid?
71
63
  @errors.empty?
72
64
  end
@@ -1,3 +1,3 @@
1
1
  class Optitron
2
- VERSION = "0.0.11"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -90,11 +90,11 @@ describe "Optitron::Parser arg spec" do
90
90
  end
91
91
  end
92
92
 
93
- context "one greedy arg" do
93
+ context "one required greedy arg" do
94
94
  before(:each) {
95
95
  @parser = Optitron.new {
96
96
  cmd "install" do
97
- arg "files", :type => :greedy
97
+ arg "files", :type => :greedy, :required => true
98
98
  end
99
99
  }
100
100
  }
@@ -120,6 +120,25 @@ describe "Optitron::Parser arg spec" do
120
120
  end
121
121
  end
122
122
 
123
+ context "one optional + one greedy arg" do
124
+ before(:each) {
125
+ @parser = Optitron.new {
126
+ cmd "install" do
127
+ arg "values", :default => [1,2,3]
128
+ arg "files", :type => :greedy
129
+ end
130
+ }
131
+ }
132
+
133
+ it "should parse 'install'" do
134
+ response = @parser.parse(%w(install))
135
+ response.command.should == 'install'
136
+ response.args.should == [[1,2,3]]
137
+ response.valid?.should be_true
138
+ end
139
+
140
+ end
141
+
123
142
  context "invalid parsers" do
124
143
  it "shouldn't allow a required arg after an optional arg" do
125
144
  proc {
@@ -43,11 +43,24 @@ class AnotherCLIExample < Optitron::CLI
43
43
  end
44
44
  end
45
45
 
46
+ class NoHelpExample < Optitron::CLI
47
+
48
+ dont_use_help
49
+
50
+ class_opt 'verbose'
51
+
52
+ desc "Use this too"
53
+ opt 'another_opt'
54
+ def use_too(one, two = 'three')
55
+ puts "using this too #{one} #{two} #{params['another_opt']} #{@env}"
56
+ end
57
+ end
58
+
46
59
 
47
60
  describe "Optitron::Parser defaults" do
48
61
  it "should generate the correct help" do
49
62
  CLIExample.build
50
- CLIExample.optitron_parser.help.strip.should == "Commands\n\nuse_greedy [one] [two1 two2 ...] # Use this three\n -A/--another_opt_as_well=[NUMERIC] \nuse # Use this\n -u/--use_opt \nwith_array <ary=[1, 2, 3]> # something with an array\nuse_too [one] <two=\"three\"> # Use this too\n -a/--another_opt \n\nGlobal options\n\n-v/--verbose \n-?/--help # Print help message"
63
+ CLIExample.optitron_parser.help.strip.should == "Commands\n\nuse # Use this\n -u/--use_opt \nuse_too [one] <two=\"three\"> # Use this too\n -a/--another_opt \nuse_greedy [one] <two1 two2 ...> # Use this three\n -A/--another_opt_as_well=[NUMERIC] \nwith_array <ary=[1, 2, 3]> # something with an array\n\nGlobal options\n\n-v/--verbose \n-?/--help # Print help message"
51
64
  end
52
65
 
53
66
  it "should dispatch" do
@@ -62,4 +75,8 @@ describe "Optitron::Parser defaults" do
62
75
  it "should dispatch with a custom initer" do
63
76
  capture(:stdout) { AnotherCLIExample.dispatch(%w(use_too three four --another_opt)) { AnotherCLIExample.new("test") } }.should == "using this too three four true test\n"
64
77
  end
78
+
79
+ it "should be able to suppress help" do
80
+ capture(:stdout) { NoHelpExample.dispatch(%w(--help)) }.should == "Unknown command\nHelp is unrecognized\n"
81
+ end
65
82
  end
@@ -17,10 +17,10 @@ describe "Optitron::Parser help" do
17
17
  opt "names", "Some sort of hash", :type => :hash
18
18
  end
19
19
  cmd "join", "This joins things" do
20
- arg "thing", "Stuff to join", :type => :greedy
20
+ arg "thing", "Stuff to join", :type => :greedy, :required => true
21
21
  end
22
22
  }
23
- @parser.help.should == "Commands\n\nshow [first] <second> # This shows things\ninstall [file] # This installs things\nkill # This kills things\n -p/--pids=[ARRAY] # A list of pids to kill\n -P/--pid=[NUMERIC] # A pid to kill\n -n/--names=[HASH] # Some sort of hash\njoin [thing1 thing2 ...] # This joins things\n\nGlobal options\n\n-v/--verbose # Be very loud"
23
+ @parser.help.should == "Commands\n\ninstall [file] # This installs things\nshow [first] <second> # This shows things\nkill # This kills things\n -p/--pids=[ARRAY] # A list of pids to kill\n -P/--pid=[NUMERIC] # A pid to kill\n -n/--names=[HASH] # Some sort of hash\njoin [thing1 thing2 ...] # This joins things\n\nGlobal options\n\n-v/--verbose # Be very loud"
24
24
  end
25
25
 
26
26
  it "generate help for non-command parsers" do
@@ -112,4 +112,25 @@ describe "Optitron::Parser options" do
112
112
  @parser.parse(%w(-123o test)).params.should == {'option' => 'test', '1' => true, '2' => true, '3' => true}
113
113
  end
114
114
  end
115
+
116
+ context "required options" do
117
+ before(:each) do
118
+ @parser = Optitron.new {
119
+ cmd "install" do
120
+ opt "environment", :type => :string, :required => true
121
+ end
122
+ }
123
+ end
124
+
125
+ it "shouldn't parse 'install'" do
126
+ @parser.parse(%w(install)).valid?.should be_false
127
+ end
128
+
129
+ it "should parse 'install -esomething'" do
130
+ response = @parser.parse(%w(install -esomething))
131
+ response.valid?.should be_true
132
+ response.params.should == {'environment' => 'something'}
133
+ end
134
+ end
135
+
115
136
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: optitron
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
+ - 1
8
9
  - 0
9
- - 11
10
- version: 0.0.11
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Joshua Hull
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-08-19 00:00:00 -07:00
18
+ date: 2010-08-20 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -156,7 +156,6 @@ files:
156
156
  - spec/arg_spec.rb
157
157
  - spec/cli_spec.rb
158
158
  - spec/default_spec.rb
159
- - spec/dispatch_spec.rb
160
159
  - spec/errors_spec.rb
161
160
  - spec/help_spec.rb
162
161
  - spec/option_spec.rb
@@ -1,32 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Optitron::Parser dispatching" do
4
- it "should dispatch 'install'" do
5
- m = mock('mock')
6
- m.should_receive('install').with()
7
- Optitron.dispatch(m, %w(install)) {
8
- cmd "install"
9
- }
10
- end
11
-
12
- it "should dispatch 'install file'" do
13
- m = mock('mock')
14
- m.should_receive('install').with('file.rb')
15
- Optitron.dispatch(m, %w(install file.rb)) {
16
- cmd "install" do
17
- arg "file"
18
- end
19
- }
20
- end
21
-
22
- it "should dispatch 'install file --noop'" do
23
- m = mock('mock')
24
- m.should_receive('install').with('file.rb', {'noop' => true})
25
- Optitron.dispatch(m, %w(install file.rb --noop)) {
26
- cmd "install" do
27
- opt 'noop'
28
- arg "file"
29
- end
30
- }
31
- end
32
- end