optitron 0.0.8 → 0.0.9
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.
- data/README.rdoc +45 -28
- data/lib/optitron.rb +1 -0
- data/lib/optitron/class_dsl.rb +82 -0
- data/lib/optitron/dsl.rb +28 -10
- data/lib/optitron/help.rb +1 -1
- data/lib/optitron/option.rb +34 -3
- data/lib/optitron/parser.rb +1 -1
- data/lib/optitron/response.rb +1 -2
- data/lib/optitron/tokenizer.rb +5 -5
- data/lib/optitron/version.rb +1 -1
- data/spec/option_spec.rb +2 -2
- metadata +5 -4
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
|
-
|
100
|
+
Unknown command
|
100
101
|
|
101
|
-
|
102
|
-
|
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
|
-
|
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
|
-
|
115
|
+
class Runner
|
116
|
+
include Optitron::ClassDsl
|
112
117
|
|
113
|
-
|
114
|
-
|
118
|
+
class_opt 'verbose'
|
119
|
+
use_help
|
115
120
|
|
116
|
-
|
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
|
-
|
120
|
-
|
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
|
130
|
-
|
131
|
-
|
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
|
138
|
-
installing file with {"verbose"=>
|
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
@@ -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
|
-
|
7
|
-
|
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
|
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
|
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}]"
|
10
|
+
opt_line << "=[#{opt.type.to_s.upcase}]" unless opt.boolean?
|
11
11
|
[opt_line, opt.desc]
|
12
12
|
end
|
13
13
|
|
data/lib/optitron/option.rb
CHANGED
@@ -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
|
-
@
|
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
|
|
data/lib/optitron/parser.rb
CHANGED
@@ -20,7 +20,7 @@ class Optitron
|
|
20
20
|
response = Response.new(self, tokens)
|
21
21
|
options = @options
|
22
22
|
args = @args
|
23
|
-
|
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)
|
data/lib/optitron/response.rb
CHANGED
@@ -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
|
data/lib/optitron/tokenizer.rb
CHANGED
@@ -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 /^-(.*)/
|
20
|
-
else
|
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] &&
|
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
|
data/lib/optitron/version.rb
CHANGED
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 '-
|
83
|
-
@parser.parse(%w(-
|
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:
|
4
|
+
hash: 13
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
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-
|
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
|