optitron 0.0.11 → 0.1.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.
@@ -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