optitron 0.0.9 → 0.0.10

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.
@@ -0,0 +1,34 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ optitron (0.0.9)
5
+ callsite (= 0.0.4)
6
+ ruby2ruby (= 1.2.4)
7
+ ruby_parser (>= 2.0)
8
+ sexp_processor (= 3.0.4)
9
+
10
+ GEM
11
+ remote: http://rubygems.org/
12
+ specs:
13
+ callsite (0.0.4)
14
+ rake (0.8.7)
15
+ rspec (1.3.0)
16
+ ruby2ruby (1.2.4)
17
+ ruby_parser (~> 2.0)
18
+ sexp_processor (~> 3.0)
19
+ ruby_parser (2.0.4)
20
+ sexp_processor (~> 3.0)
21
+ sexp_processor (3.0.4)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ bundler (>= 1.0.0.rc.3)
28
+ callsite (= 0.0.4)
29
+ optitron!
30
+ rake
31
+ rspec
32
+ ruby2ruby (= 1.2.4)
33
+ ruby_parser (>= 2.0)
34
+ sexp_processor (= 3.0.4)
@@ -112,16 +112,13 @@ Now, try running it.
112
112
 
113
113
  require 'optitron'
114
114
 
115
- class Runner
116
- include Optitron::ClassDsl
115
+ class Runner < Optitron::CLI
117
116
 
118
117
  class_opt 'verbose'
119
118
  use_help
120
119
 
121
120
  desc "Install stuff"
122
121
  opt 'force'
123
- arg 'file'
124
- arg 'source', :required => false
125
122
  def install(file, source)
126
123
  puts "install some things #{file} from #{source.inspect} #{params.inspect}"
127
124
  end
@@ -6,6 +6,7 @@ class Optitron
6
6
  autoload :Response, 'optitron/response'
7
7
  autoload :Option, 'optitron/option'
8
8
  autoload :Help, 'optitron/help'
9
+ autoload :CLI, 'optitron/cli'
9
10
 
10
11
  InvalidParser = Class.new(RuntimeError)
11
12
 
@@ -1,10 +1,66 @@
1
+ require 'callsite'
2
+ require 'ruby2ruby'
3
+ require 'ruby_parser'
4
+ require 'sexp_processor'
5
+
1
6
  class Optitron
7
+
8
+ class MethodArgs < SexpProcessor
9
+ attr_reader :method_map
10
+ def initialize(cls)
11
+ @cls = cls
12
+ @method_map = {}
13
+ super()
14
+ end
15
+
16
+ def process_class(exp)
17
+ exp.shift
18
+ @current_class = exp.first.to_sym
19
+ process(exp)
20
+ exp.clear
21
+ exp
22
+ end
23
+
24
+ def process_defn(exp)
25
+ exp.shift
26
+ @current_method = exp.shift
27
+ @ruby2ruby = Ruby2Ruby.new
28
+ process_args(exp.shift)
29
+ scope = exp.shift
30
+ exp
31
+ end
32
+
33
+ def process_args(exp)
34
+ exp.shift
35
+ arg_list = []
36
+ while !exp.empty?
37
+ t = exp.shift
38
+ case t
39
+ when Symbol
40
+ arg_list << if t.to_s[0] == ?*
41
+ [t.to_s[1, t.to_s.size].to_sym, :greedy]
42
+ else
43
+ [t, :required]
44
+ end
45
+ when Sexp
46
+ case t.shift
47
+ when :block
48
+ lasgn = t.shift
49
+ lasgn.shift
50
+ arg_list[-1].shift
51
+ arg_list[-1] << :optional
52
+ arg_list[-1] << @ruby2ruby.process(lasgn.last)
53
+ end
54
+ end
55
+ end
56
+ @method_map[@current_method] = arg_list if @cls.name.to_sym == @current_class
57
+ end
58
+ end
59
+
2
60
  module ClassDsl
3
61
 
4
62
  def self.included(o)
5
- o.module_eval "
6
- @@optitron_parser = Optitron::Parser.new
7
- @@optitron_dsl = Optitron::Dsl.new(@@optitron_parser)
63
+ o.class_eval "
8
64
  attr_accessor :params
9
65
  class << self;
10
66
  include ClassMethods
@@ -14,58 +70,86 @@ class Optitron
14
70
 
15
71
  module ClassMethods
16
72
  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
73
+ if @last_desc
74
+ last_opts = @opts
75
+ @cmds ||= []
76
+ @cmds << [m.to_s, @last_desc, @opts ? @opts.dup : []]
77
+ @opts.clear if @opts
78
+ @args.clear if @args
79
+ end
22
80
  end
23
-
81
+ def optitron_parser
82
+ send(:class_variable_set, :@@optitron_parser, Optitron::Parser.new) unless send(:class_variable_defined?, :@@optitron_parser)
83
+ send(:class_variable_get, :@@optitron_parser)
84
+ end
85
+
24
86
  def optitron_dsl
25
- self.send(:class_variable_get, :@@optitron_dsl)
87
+ send(:class_variable_set, :@@optitron_dsl, Optitron::Dsl.new(optitron_parser)) unless send(:class_variable_defined?, :@@optitron_dsl)
88
+ send(:class_variable_get, :@@optitron_dsl)
26
89
  end
27
90
 
28
- def optitron_parser
29
- self.send(:class_variable_get, :@@optitron_parser)
91
+ def method_args
92
+ send(:class_variable_get, :@@method_args)
93
+ end
94
+
95
+ def build_method_args(file)
96
+ unless self.send(:class_variable_defined?, :@@method_args)
97
+ parser = RubyParser.new
98
+ sexp = parser.process(File.read(file))
99
+ method_args = MethodArgs.new(self)
100
+ method_args.process(sexp)
101
+ self.send(:class_variable_set, :@@method_args, method_args.method_map)
102
+ end
103
+ send(:class_variable_get, :@@method_args)
30
104
  end
31
105
 
32
106
  def class_opt(name, desc = nil, opts = nil)
33
107
  optitron_dsl.root.opt(name, desc, opts)
34
108
  end
35
109
 
36
- def use_help
110
+ def dont_use_help
37
111
  optitron_dsl.root.help
38
112
  end
39
113
 
40
114
  def desc(desc)
115
+ build_method_args(Callsite.parse(caller.first).filename)
41
116
  @last_desc = desc
42
117
  end
43
118
 
44
- def arg(name, desc = nil, opts = nil)
45
- @args ||= []
46
- @args << [name, desc, opts]
47
- end
48
-
49
119
  def opt(name, desc = nil, opts = nil)
50
120
  @opts ||= []
51
121
  @opts << [name, desc, opts]
52
122
  end
53
123
 
54
124
  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 }
125
+ unless @built
126
+ optitron_dsl.root.help
127
+ @cmds.each do |(cmd_name, cmd_desc, opts)|
128
+ args = method_args[cmd_name.to_sym]
129
+ arity = instance_method(cmd_name).arity
130
+ optitron_dsl.root.cmd(cmd_name, cmd_desc) do
131
+ opts.each { |o| opt *o }
132
+ args.each do |(arg_name, arg_type, arg_default)|
133
+ case arg_type
134
+ when :required
135
+ arg arg_name.to_s, :default => arg_default && eval(arg_default)
136
+ when :optional
137
+ arg arg_name.to_s, :default => arg_default && eval(arg_default), :required => false
138
+ when :greedy
139
+ arg arg_name.to_s, :default => arg_default && eval(arg_default), :type => :greedy
140
+ end
141
+ end
142
+ end
60
143
  end
144
+ optitron_dsl.configure_options
145
+ @built = true
61
146
  end
62
- optitron_dsl.configure_options
63
147
  end
64
148
 
65
- def dispatch
149
+ def dispatch(args = ARGV, &blk)
66
150
  build
67
- optitron_parser.target = new
68
- response = optitron_parser.parse(ARGV)
151
+ optitron_parser.target = blk ? blk.call : new
152
+ response = optitron_parser.parse(args)
69
153
  if response.valid?
70
154
  optitron_parser.target.params = response.params
71
155
  args = response.args
@@ -0,0 +1,6 @@
1
+ class Optitron
2
+ class CLI
3
+ include ClassDsl
4
+ end
5
+ end
6
+
@@ -35,8 +35,8 @@ class Optitron
35
35
  else
36
36
  unclaimed_opts << opt_option
37
37
  end
38
-
39
38
  @target.options << opt_option
39
+ opt_option
40
40
  end
41
41
 
42
42
  def arg(name, description = nil, opts = nil)
@@ -61,6 +61,18 @@ class Optitron
61
61
  @root_dsl = root_dsl
62
62
  @target = command
63
63
  end
64
+
65
+ def opt(name, description = nil, opts = nil)
66
+ o = super
67
+ o.parent_cmd = @target
68
+ o
69
+ end
70
+
71
+ def arg(name, description = nil, opts = nil)
72
+ a = super
73
+ a.parent_cmd = @target
74
+ a
75
+ end
64
76
  end
65
77
 
66
78
  class RootParserDsl < AbstractDsl
@@ -19,6 +19,9 @@ class Optitron
19
19
  else
20
20
  arg_line << arg.name
21
21
  end
22
+ if arg.default
23
+ arg_line << "=#{arg.default.inspect}"
24
+ end
22
25
  arg_line << (arg.required? ? ']' : '>')
23
26
  arg_line
24
27
  end
@@ -89,7 +89,7 @@ class Optitron
89
89
  end
90
90
 
91
91
  class Opt < Option
92
- attr_accessor :short_name, :run
92
+ attr_accessor :short_name, :run, :parent_cmd
93
93
  def initialize(name, desc = nil, opts = nil)
94
94
  if desc.is_a?(Hash)
95
95
  desc, opts = nil, desc
@@ -179,7 +179,7 @@ class Optitron
179
179
  end
180
180
 
181
181
  class Arg < Option
182
- attr_accessor :greedy, :inclusion_test
182
+ attr_accessor :greedy, :inclusion_test, :parent_cmd
183
183
  alias_method :greedy?, :greedy
184
184
  def initialize(name = nil, desc = nil, opts = nil)
185
185
  if desc.is_a?(Hash)
@@ -1,3 +1,3 @@
1
1
  class Optitron
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
@@ -15,7 +15,13 @@ Gem::Specification.new do |s|
15
15
  s.required_rubygems_version = ">= 1.3.6"
16
16
  s.rubyforge_project = "optitron"
17
17
 
18
+ s.add_dependency "ruby_parser", ">= 2.0"
19
+ s.add_dependency "callsite", "= 0.0.4"
20
+ s.add_dependency "ruby2ruby", "= 1.2.4"
21
+ s.add_dependency "sexp_processor", "= 3.0.4"
18
22
  s.add_development_dependency "bundler", ">= 1.0.0.rc.3"
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "rspec"
19
25
 
20
26
  s.files = `git ls-files`.split("\n")
21
27
  s.require_path = 'lib'
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ class CLIExample < Optitron::CLI
4
+
5
+ def a_method_we_didnt_describe
6
+ end
7
+
8
+ class_opt 'verbose'
9
+
10
+ desc "Use this"
11
+ opt 'use_opt'
12
+ def use
13
+ puts "using this"
14
+ end
15
+
16
+ desc "Use this too"
17
+ opt 'another_opt'
18
+ def use_too(one, two = 'three')
19
+ end
20
+
21
+ desc "Use this three"
22
+ opt 'another_opt_as_well', :default => 123
23
+ def use_greedy(one, *two)
24
+ end
25
+ end
26
+
27
+ class AnotherCLIExample < Optitron::CLI
28
+
29
+ def initialize(env)
30
+ @env = env
31
+ end
32
+
33
+ class_opt 'verbose'
34
+
35
+ desc "Use this too"
36
+ opt 'another_opt'
37
+ def use_too(one, two = 'three')
38
+ puts "using this too #{one} #{two} #{params['another_opt']} #{@env}"
39
+ end
40
+ end
41
+
42
+
43
+ describe "Optitron::Parser defaults" do
44
+ it "should generate the correct help" do
45
+ CLIExample.build
46
+ CLIExample.optitron_parser.help.strip.should == "Commands\n\nuse_greedy [one] [two1 two2 ...] # Use this three\n -A/--another_opt_as_well=[NUMERIC] \nuse_too [one] <required=\"three\"> # Use this too\n -a/--another_opt \nuse # Use this\n -u/--use_opt \n\nGlobal options\n\n-v/--verbose \n-?/--help # Print help message"
47
+ end
48
+
49
+ it "should dispatch" do
50
+ capture(:stdout) { CLIExample.dispatch(%w(use))}.should == "using this\n"
51
+ end
52
+
53
+ it "should generate the correct help" do
54
+ AnotherCLIExample.build
55
+ AnotherCLIExample.optitron_parser.help.strip.should == "Commands\n\nuse_too [one] <required=\"three\"> # Use this too\n -a/--another_opt \n\nGlobal options\n\n-v/--verbose \n-?/--help # Print help message"
56
+ end
57
+
58
+ it "should dispatch with a custom initer" do
59
+ capture(:stdout) { AnotherCLIExample.dispatch(%w(use_too three four --another_opt)) { AnotherCLIExample.new("test") } }.should == "using this too three four true test\n"
60
+ end
61
+ end
@@ -65,7 +65,32 @@ describe "Optitron::Parser options" do
65
65
  it "should parse '-Vv --vicious=what'" do
66
66
  response = @parser.parse(%w(-Vv --vicious=what))
67
67
  response.valid?.should be_true
68
- response.params
68
+ response.params.should == {"vicious"=>"what", "vendetta"=>true, "verbose"=>true}
69
+ end
70
+ end
71
+
72
+ context "auto assingment of short names in cmd parsers" do
73
+ before(:each) do
74
+ @parser = Optitron.new {
75
+ cmd "one" do
76
+ opt "verbose"
77
+ end
78
+ cmd "two" do
79
+ opt "verbose"
80
+ end
81
+ }
82
+ end
83
+
84
+ it "should parse 'one -v'" do
85
+ response = @parser.parse(%w(one -v))
86
+ response.valid?.should be_true
87
+ response.params.should == {'verbose' => true}
88
+ end
89
+
90
+ it "should parse 'two -V'" do
91
+ response = @parser.parse(%w(two -V))
92
+ response.valid?.should be_true
93
+ response.params.should == {'verbose' => true}
69
94
  end
70
95
  end
71
96
 
@@ -1,2 +1,16 @@
1
1
  $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
2
- require 'optitron'
2
+ require 'optitron'
3
+
4
+ class Object
5
+ def capture(stream)
6
+ begin
7
+ stream = stream.to_s
8
+ eval "$#{stream} = StringIO.new"
9
+ yield
10
+ result = eval("$#{stream}").string
11
+ ensure
12
+ eval("$#{stream} = #{stream.upcase}")
13
+ end
14
+ result
15
+ end
16
+ 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: 13
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 9
10
- version: 0.0.9
9
+ - 10
10
+ version: 0.0.10
11
11
  platform: ruby
12
12
  authors:
13
13
  - Joshua Hull
@@ -15,13 +15,76 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-08-18 00:00:00 -07:00
18
+ date: 2010-08-19 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: bundler
22
+ name: ruby_parser
23
23
  prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 2
32
+ - 0
33
+ version: "2.0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: callsite
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - "="
43
+ - !ruby/object:Gem::Version
44
+ hash: 23
45
+ segments:
46
+ - 0
47
+ - 0
48
+ - 4
49
+ version: 0.0.4
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: ruby2ruby
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - "="
59
+ - !ruby/object:Gem::Version
60
+ hash: 23
61
+ segments:
62
+ - 1
63
+ - 2
64
+ - 4
65
+ version: 1.2.4
66
+ type: :runtime
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: sexp_processor
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - "="
75
+ - !ruby/object:Gem::Version
76
+ hash: 15
77
+ segments:
78
+ - 3
79
+ - 0
80
+ - 4
81
+ version: 3.0.4
82
+ type: :runtime
83
+ version_requirements: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ name: bundler
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
25
88
  none: false
26
89
  requirements:
27
90
  - - ">="
@@ -35,7 +98,35 @@ dependencies:
35
98
  - 3
36
99
  version: 1.0.0.rc.3
37
100
  type: :development
38
- version_requirements: *id001
101
+ version_requirements: *id005
102
+ - !ruby/object:Gem::Dependency
103
+ name: rake
104
+ prerelease: false
105
+ requirement: &id006 !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ hash: 3
111
+ segments:
112
+ - 0
113
+ version: "0"
114
+ type: :development
115
+ version_requirements: *id006
116
+ - !ruby/object:Gem::Dependency
117
+ name: rspec
118
+ prerelease: false
119
+ requirement: &id007 !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ hash: 3
125
+ segments:
126
+ - 0
127
+ version: "0"
128
+ type: :development
129
+ version_requirements: *id007
39
130
  description: Sensible options parsing
40
131
  email:
41
132
  - joshbuddy@gmail.com
@@ -48,10 +139,12 @@ extra_rdoc_files: []
48
139
  files:
49
140
  - .gitignore
50
141
  - Gemfile
142
+ - Gemfile.lock
51
143
  - README.rdoc
52
144
  - Rakefile
53
145
  - lib/optitron.rb
54
146
  - lib/optitron/class_dsl.rb
147
+ - lib/optitron/cli.rb
55
148
  - lib/optitron/dsl.rb
56
149
  - lib/optitron/help.rb
57
150
  - lib/optitron/option.rb
@@ -61,6 +154,7 @@ files:
61
154
  - lib/optitron/version.rb
62
155
  - optitron.gemspec
63
156
  - spec/arg_spec.rb
157
+ - spec/cli_spec.rb
64
158
  - spec/default_spec.rb
65
159
  - spec/dispatch_spec.rb
66
160
  - spec/errors_spec.rb