optitron 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -5,6 +5,7 @@
5
5
  You can specify lots of different commands with options
6
6
 
7
7
  @parser = Optitron.new {
8
+ help
8
9
  opt 'verbose', "Be very loud"
9
10
  cmd "install", "This installs things" do
10
11
  arg "file", "The file to install"
@@ -96,43 +97,59 @@ To use this in a file, create a parser, and tell it to dispatch to your favourit
96
97
  Now, try running it.
97
98
 
98
99
  crapbook-pro:optitron joshua$ ruby test.rb
99
- Commands
100
+ Unknown command
100
101
 
101
- show [first] <second> # This shows things
102
- install [file] # This installs things
103
- kill # This kills things
104
- -p/--pids=[ARRAY] # A list of pids to kill
105
- -P/--pid=[NUMERIC] # A pid to kill
106
- -n/--names=[HASH] # Some sort of hash
107
- join [thing1 thing2 ...] # This joins things
102
+ crapbook-pro:optitron joshua$ ruby test.rb install
103
+ File is required
108
104
 
109
- Global options
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'
110
114
 
111
- -v/--verbose # Be very loud
115
+ class Runner
116
+ include Optitron::ClassDsl
112
117
 
113
- Errors:
114
- Unknown command
118
+ class_opt 'verbose'
119
+ use_help
115
120
 
116
- crapbook-pro:optitron joshua$ ruby test.rb install
121
+ desc "Install stuff"
122
+ opt 'force'
123
+ arg 'file'
124
+ arg 'source', :required => false
125
+ def install(file, source)
126
+ puts "install some things #{file} from #{source.inspect} #{params.inspect}"
127
+ end
128
+ end
129
+
130
+ Runner.dispatch
131
+
132
+ Running this gives you
133
+
134
+ crapbook-pro:optitron joshua$ ruby ideal.rb --help
117
135
  Commands
118
136
 
119
- show [first] <second> # This shows things
120
- install [file] # This installs things
121
- kill # This kills things
122
- -p/--pids=[ARRAY] # A list of pids to kill
123
- -P/--pid=[NUMERIC] # A pid to kill
124
- -n/--names=[HASH] # Some sort of hash
125
- join [thing1 thing2 ...] # This joins things
137
+ install [file] <source> # Install stuff
138
+ -f/--force
126
139
 
127
140
  Global options
128
141
 
129
- -v/--verbose # Be very loud
130
-
131
- Errors:
142
+ -v/--verbose
143
+ -?/--help # Print help message
144
+
145
+ crapbook-pro:optitron joshua$ ruby ideal.rb install
132
146
  File is required
133
-
134
- crapbook-pro:optitron joshua$ ruby test.rb install file
135
- installing file with {"verbose"=>false}!
136
147
 
137
- crapbook-pro:optitron joshua$ ruby test.rb install file --verbose
138
- installing file with {"verbose"=>true}!
148
+ crapbook-pro:optitron joshua$ ruby ideal.rb install file
149
+ installing file from yourmom with params: {"help"=>false, "force"=>false, "verbose"=>false}
150
+
151
+ crapbook-pro:optitron joshua$ ruby ideal.rb install file yourdad
152
+ installing file from yourdad with params: {"help"=>false, "force"=>false, "verbose"=>false}
153
+
154
+ crapbook-pro:optitron joshua$ ruby ideal.rb install file yourdad -v
155
+ installing file from yourdad with params: {"help"=>false, "force"=>false, "verbose"=>true}
data/lib/optitron.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  class Optitron
2
2
  autoload :Dsl, 'optitron/dsl'
3
+ autoload :ClassDsl, 'optitron/class_dsl'
3
4
  autoload :Tokenizer, 'optitron/tokenizer'
4
5
  autoload :Parser, 'optitron/parser'
5
6
  autoload :Response, 'optitron/response'
@@ -0,0 +1,82 @@
1
+ class Optitron
2
+ module ClassDsl
3
+
4
+ def self.included(o)
5
+ o.module_eval "
6
+ @@optitron_parser = Optitron::Parser.new
7
+ @@optitron_dsl = Optitron::Dsl.new(@@optitron_parser)
8
+ attr_accessor :params
9
+ class << self;
10
+ include ClassMethods
11
+ end"
12
+ end
13
+
14
+
15
+ module ClassMethods
16
+ def method_added(m)
17
+ last_opts = @opts
18
+ @cmds ||= []
19
+ @cmds << [m.to_s, @last_desc, @args.dup || [], @opts.dup || []]
20
+ @opts.clear if @opts
21
+ @args.clear if @args
22
+ end
23
+
24
+ def optitron_dsl
25
+ self.send(:class_variable_get, :@@optitron_dsl)
26
+ end
27
+
28
+ def optitron_parser
29
+ self.send(:class_variable_get, :@@optitron_parser)
30
+ end
31
+
32
+ def class_opt(name, desc = nil, opts = nil)
33
+ optitron_dsl.root.opt(name, desc, opts)
34
+ end
35
+
36
+ def use_help
37
+ optitron_dsl.root.help
38
+ end
39
+
40
+ def desc(desc)
41
+ @last_desc = desc
42
+ end
43
+
44
+ def arg(name, desc = nil, opts = nil)
45
+ @args ||= []
46
+ @args << [name, desc, opts]
47
+ end
48
+
49
+ def opt(name, desc = nil, opts = nil)
50
+ @opts ||= []
51
+ @opts << [name, desc, opts]
52
+ end
53
+
54
+ def build
55
+ @cmds.each do |(cmd_name, cmd_desc, args, opts)|
56
+ arity = instance_method(cmd_name).arity
57
+ optitron_dsl.root.cmd(cmd_name, cmd_desc) do
58
+ opts.each { |o| opt *o }
59
+ args.each { |a| arg *a }
60
+ end
61
+ end
62
+ optitron_dsl.configure_options
63
+ end
64
+
65
+ def dispatch
66
+ build
67
+ optitron_parser.target = new
68
+ response = optitron_parser.parse(ARGV)
69
+ if response.valid?
70
+ optitron_parser.target.params = response.params
71
+ args = response.args
72
+ while (args.size < optitron_parser.commands[response.command].args.size)
73
+ args << optitron_parser.commands[response.command].args[args.size].default
74
+ end
75
+ optitron_parser.target.send(response.command.to_sym, *response.args)
76
+ else
77
+ puts response.error_messages.join("\n")
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
data/lib/optitron/dsl.rb CHANGED
@@ -1,23 +1,30 @@
1
1
  class Optitron
2
2
  class Dsl
3
+ attr_reader :root
3
4
 
4
5
  def initialize(parser, &blk)
5
- root = RootParserDsl.new(parser)
6
- root.configure_with(blk)
7
- root.unclaimed_opts.each do |opt_option|
6
+ @root = RootParserDsl.new(parser)
7
+ if blk
8
+ @root.configure_with(&blk)
9
+ configure_options
10
+ end
11
+ end
12
+
13
+ def configure_options
14
+ @root.unclaimed_opts.each do |opt_option|
8
15
  name = opt_option.name
9
- if !root.short_opts.key?(name[0].chr)
16
+ if !@root.short_opts.key?(name[0].chr)
10
17
  opt_option.short_name = name[0].chr
11
- root.short_opts[name[0].chr] = opt_option
12
- elsif !root.short_opts.key?(name.upcase[0].chr)
18
+ @root.short_opts[name[0].chr] = opt_option
19
+ elsif !@root.short_opts.key?(name.upcase[0].chr)
13
20
  opt_option.short_name = name.upcase[0].chr
14
- root.short_opts[name.upcase[0].chr] = opt_option
21
+ @root.short_opts[name.upcase[0].chr] = opt_option
15
22
  end
16
23
  end
17
24
  end
18
-
25
+
19
26
  class AbstractDsl
20
- def configure_with(block)
27
+ def configure_with(&block)
21
28
  instance_eval(&block)
22
29
  end
23
30
 
@@ -63,13 +70,24 @@ class Optitron
63
70
  @unclaimed_opts = []
64
71
  end
65
72
 
73
+ def help(desc = "Print help message")
74
+ configure_with {
75
+ opt 'help', desc, :short_name => '?', :run => proc{ |value, response|
76
+ if value
77
+ puts @target.help
78
+ exit(0)
79
+ end
80
+ }
81
+ }
82
+ end
83
+
66
84
  def short_opts
67
85
  @target.short_opts
68
86
  end
69
87
 
70
88
  def cmd(name, description = nil, opts = nil, &blk)
71
89
  command_option = Option::Cmd.new(name, description, opts)
72
- CmdParserDsl.new(self, command_option).configure_with(blk) if blk
90
+ CmdParserDsl.new(self, command_option).configure_with(&blk) if blk
73
91
  @target.commands[name] = command_option
74
92
  end
75
93
  end
data/lib/optitron/help.rb CHANGED
@@ -7,7 +7,7 @@ class Optitron
7
7
  def help_line_for_opt(opt)
8
8
  opt_line = ''
9
9
  opt_line << [opt.short_name ? "-#{opt.short_name}" : nil, "--#{opt.name}"].compact.join('/')
10
- opt_line << "=[#{opt.type.to_s.upcase}]" if opt.type != :boolean
10
+ opt_line << "=[#{opt.type.to_s.upcase}]" unless opt.boolean?
11
11
  [opt_line, opt.desc]
12
12
  end
13
13
 
@@ -35,6 +35,34 @@ class Optitron
35
35
  end
36
36
  end
37
37
 
38
+ def boolean?
39
+ @type == :boolean
40
+ end
41
+
42
+ def numeric?
43
+ @type == :numeric
44
+ end
45
+
46
+ def array?
47
+ @type == :array
48
+ end
49
+
50
+ def string?
51
+ @type == :string
52
+ end
53
+
54
+ def hash?
55
+ @type == :hash
56
+ end
57
+
58
+ def greedy?
59
+ @type == :greedy
60
+ end
61
+
62
+ def any?
63
+ @type.nil?
64
+ end
65
+
38
66
  def validate(val)
39
67
  validated_type = case @type
40
68
  when :boolean
@@ -61,7 +89,7 @@ class Optitron
61
89
  end
62
90
 
63
91
  class Opt < Option
64
- attr_accessor :short_name
92
+ attr_accessor :short_name, :run
65
93
  def initialize(name, desc = nil, opts = nil)
66
94
  if desc.is_a?(Hash)
67
95
  desc, opts = nil, desc
@@ -69,6 +97,7 @@ class Optitron
69
97
  @name, @desc = name, desc
70
98
  @type = opts && opts[:type] || :boolean
71
99
  self.short_name = opts[:short_name] if opts && opts[:short_name]
100
+ self.run = opts[:run] if opts && opts[:run]
72
101
  self.inclusion_test = opts[:in] if opts && opts[:in]
73
102
  self.default = opts && opts.key?(:default) ? opts[:default] : (@type == :boolean ? false : nil)
74
103
  end
@@ -137,12 +166,13 @@ class Optitron
137
166
  end
138
167
 
139
168
  class Cmd < Option
140
- attr_reader :options, :args
169
+ attr_reader :options, :args, :run
141
170
  def initialize(name, desc = nil, opts = nil)
142
171
  if desc.is_a?(Hash)
143
172
  desc, opts = nil, desc
144
173
  end
145
174
  @name, @desc = name, desc
175
+ @run = opts[:run] if opts && opts[:run]
146
176
  @options = []
147
177
  @args = []
148
178
  end
@@ -157,7 +187,8 @@ class Optitron
157
187
  end
158
188
  @name, @desc = name, desc
159
189
  self.inclusion_test = opts[:in] if opts && opts[:in]
160
- @required = opts && opts.key?(:required) ? opts[:required] : true
190
+ @default = opts && opts[:default]
191
+ @required = opts && opts.key?(:required) ? opts[:required] : @default.nil?
161
192
  @type = opts && opts[:type]
162
193
  end
163
194
 
@@ -20,7 +20,7 @@ class Optitron
20
20
  response = Response.new(self, tokens)
21
21
  options = @options
22
22
  args = @args
23
- if !@commands.empty?
23
+ unless @commands.empty?
24
24
  potential_cmd_toks = tokens.select { |t| t.respond_to?(:lit) }
25
25
  if cmd_tok = potential_cmd_toks.find { |t| @commands[t.lit] }
26
26
  tokens.delete(cmd_tok)
@@ -33,6 +33,7 @@ class Optitron
33
33
 
34
34
  def validate
35
35
  compile_params
36
+ @params_array.each { |(key, value)| key.run.call(params[key.name], self) if key.run }
36
37
  @args = @args_with_tokens.map { |(arg, tok)|
37
38
  begin
38
39
  tok.is_a?(Array) ? tok.map{ |t| arg.validate(t.lit) } : arg.validate(tok.lit)
@@ -62,8 +63,6 @@ class Optitron
62
63
  dispatch_args = params.empty? ? args : args + [params]
63
64
  @parser.target.send(command.to_sym, *dispatch_args)
64
65
  else
65
- puts @parser.help
66
- puts "\nErrors:"
67
66
  puts error_messages.join("\n")
68
67
  end
69
68
  end
@@ -14,10 +14,10 @@ class Optitron
14
14
  unless @tokens
15
15
  @tokens = @opts.map {|t|
16
16
  case t
17
- when /^--([^=]+)=([^=]+)$/ then NamedWithValue.new($1, $2)
18
- when /^--([^=]+)$/ then NamedWithValue.new($1, nil)
19
- when /^-(.*)/ then find_names_values($1)
20
- else Value.new(t)
17
+ when /^--([^-][^=]+)=([^=]+)$/ then NamedWithValue.new($1, $2)
18
+ when /^--([^-][^=]+)$/ then NamedWithValue.new($1, nil)
19
+ when /^-(.*)/ then find_names_values($1)
20
+ else Value.new(t)
21
21
  end
22
22
  }
23
23
  @tokens.flatten!
@@ -30,7 +30,7 @@ class Optitron
30
30
  while !letters.empty?
31
31
  let = letters.shift
32
32
  toks << Named.new(let)
33
- if @parser.short_opts[let] && @parser.short_opts[let].type != :boolean && !letters.empty?
33
+ if @parser.short_opts[let] && !@parser.short_opts[let].boolean? && !letters.empty?
34
34
  toks << Value.new(letters.join)
35
35
  letters.clear
36
36
  end
@@ -1,3 +1,3 @@
1
1
  class Optitron
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
data/spec/option_spec.rb CHANGED
@@ -79,8 +79,8 @@ describe "Optitron::Parser options" do
79
79
  }
80
80
  end
81
81
 
82
- it "should parse '-otest'" do
83
- @parser.parse(%w(-otest)).params.should == {'option' => 'test', '1' => false, '2' => false, '3' => false}
82
+ it "should parse '-123otest'" do
83
+ @parser.parse(%w(-123otest)).params.should == {'option' => 'test', '1' => true, '2' => true, '3' => true}
84
84
  end
85
85
 
86
86
  it "should parse '-123o test'" do
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: 15
4
+ hash: 13
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 8
10
- version: 0.0.8
9
+ - 9
10
+ version: 0.0.9
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-17 00:00:00 -07:00
18
+ date: 2010-08-18 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -51,6 +51,7 @@ files:
51
51
  - README.rdoc
52
52
  - Rakefile
53
53
  - lib/optitron.rb
54
+ - lib/optitron/class_dsl.rb
54
55
  - lib/optitron/dsl.rb
55
56
  - lib/optitron/help.rb
56
57
  - lib/optitron/option.rb