boson 0.0.1
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/LICENSE.txt +22 -0
- data/README.rdoc +133 -0
- data/Rakefile +52 -0
- data/VERSION.yml +4 -0
- data/bin/boson +6 -0
- data/lib/boson.rb +72 -0
- data/lib/boson/command.rb +117 -0
- data/lib/boson/commands.rb +7 -0
- data/lib/boson/commands/core.rb +66 -0
- data/lib/boson/commands/web_core.rb +36 -0
- data/lib/boson/index.rb +95 -0
- data/lib/boson/inspector.rb +80 -0
- data/lib/boson/inspectors/argument_inspector.rb +92 -0
- data/lib/boson/inspectors/comment_inspector.rb +79 -0
- data/lib/boson/inspectors/method_inspector.rb +94 -0
- data/lib/boson/libraries/file_library.rb +76 -0
- data/lib/boson/libraries/gem_library.rb +21 -0
- data/lib/boson/libraries/module_library.rb +17 -0
- data/lib/boson/libraries/require_library.rb +11 -0
- data/lib/boson/library.rb +108 -0
- data/lib/boson/loader.rb +103 -0
- data/lib/boson/manager.rb +184 -0
- data/lib/boson/namespace.rb +45 -0
- data/lib/boson/option_parser.rb +318 -0
- data/lib/boson/repo.rb +38 -0
- data/lib/boson/runner.rb +51 -0
- data/lib/boson/runners/bin_runner.rb +100 -0
- data/lib/boson/runners/repl_runner.rb +40 -0
- data/lib/boson/scientist.rb +168 -0
- data/lib/boson/util.rb +93 -0
- data/lib/boson/view.rb +31 -0
- data/test/argument_inspector_test.rb +62 -0
- data/test/bin_runner_test.rb +136 -0
- data/test/commands_test.rb +51 -0
- data/test/comment_inspector_test.rb +99 -0
- data/test/config/index.marshal +0 -0
- data/test/file_library_test.rb +50 -0
- data/test/index_test.rb +117 -0
- data/test/loader_test.rb +181 -0
- data/test/manager_test.rb +110 -0
- data/test/method_inspector_test.rb +64 -0
- data/test/option_parser_test.rb +365 -0
- data/test/repo_test.rb +22 -0
- data/test/runner_test.rb +43 -0
- data/test/scientist_test.rb +291 -0
- data/test/test_helper.rb +119 -0
- metadata +133 -0
data/test/loader_test.rb
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
module Boson
|
4
|
+
class LoaderTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def load_namespace_library
|
7
|
+
Manager.load([Boson::Commands::Namespace])
|
8
|
+
end
|
9
|
+
|
10
|
+
context "load" do
|
11
|
+
before(:each) { reset }
|
12
|
+
test "calls included hook" do
|
13
|
+
capture_stdout {
|
14
|
+
load :blah, :file_string=>"module Blah; def self.included(mod); puts 'included blah'; end; def blah; end; end"
|
15
|
+
}.should =~ /included blah/
|
16
|
+
end
|
17
|
+
|
18
|
+
test "calls methods in config init_methods" do
|
19
|
+
with_config(:libraries=>{"blah"=>{:init_methods=>['blah']}}) do
|
20
|
+
capture_stdout {
|
21
|
+
load :blah, :file_string=>"module Blah; def blah; puts 'yo'; end; end"
|
22
|
+
}.should == "yo\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
test "prints error and returns false for existing library" do
|
27
|
+
libs = create_library('blah', :loaded=>true)
|
28
|
+
Manager.stubs(:loader_create).returns(libs[0])
|
29
|
+
capture_stderr { load('blah', :no_mock=>true, :verbose=>true).should == false }.should =~ /already exists/
|
30
|
+
end
|
31
|
+
|
32
|
+
test "loads and strips aliases from a library's commands" do
|
33
|
+
with_config(:commands=>{"blah"=>{:alias=>'b'}}) do
|
34
|
+
load :blah, :file_string=>"module Blah; def blah; end; alias_method(:b, :blah); end"
|
35
|
+
library_loaded?('blah')
|
36
|
+
library('blah').commands.should == ['blah']
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
test "loads a library with dependencies" do
|
41
|
+
File.stubs(:exists?).returns(true)
|
42
|
+
File.stubs(:read).returns("module Water; def water; end; end", "module Oaks; def oaks; end; end")
|
43
|
+
with_config(:libraries=>{"water"=>{:dependencies=>"oaks"}}) do
|
44
|
+
load 'water', :no_mock=>true
|
45
|
+
library_has_module('water', "Boson::Commands::Water")
|
46
|
+
library_has_module('oaks', "Boson::Commands::Oaks")
|
47
|
+
command_exists?('water')
|
48
|
+
command_exists?('oaks')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
test "prints error for library with invalid dependencies" do
|
53
|
+
GemLibrary.stubs(:is_a_gem?).returns(true) #mock all as gem libs
|
54
|
+
Util.stubs(:safe_require).returns(true)
|
55
|
+
with_config(:libraries=>{"water"=>{:dependencies=>"fire"}, "fire"=>{:dependencies=>"man"}}) do
|
56
|
+
capture_stderr {
|
57
|
+
load('water', :no_mock=>true)
|
58
|
+
}.should == "Unable to load library fire. Reason: Can't load dependency man\nUnable to load"+
|
59
|
+
" library water. Reason: Can't load dependency fire\n"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
test "prints error for method conflicts with config error_method_conflicts" do
|
64
|
+
with_config(:error_method_conflicts=>true) do
|
65
|
+
load('blah', :file_string=>"module Blah; def chwhat; end; end")
|
66
|
+
capture_stderr {
|
67
|
+
load('chwhat', :file_string=>"module Chwhat; def chwhat; end; end")
|
68
|
+
}.should =~ /Unable to load library chwhat.*conflict.*chwhat/
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
test "namespaces a library that has a method conflict" do
|
73
|
+
load('blah', :file_string=>"module Blah; def chwhat; end; end")
|
74
|
+
capture_stderr {
|
75
|
+
load('chwhat2', :file_string=>"module Chwhat2; def chwhat; end; end")
|
76
|
+
}.should =~ /conflict.*chwhat.*chwhat2/
|
77
|
+
library_has_command('namespace', 'chwhat2')
|
78
|
+
library_has_command('chwhat2', 'chwhat')
|
79
|
+
end
|
80
|
+
|
81
|
+
context "module library" do
|
82
|
+
def mock_library(*args); end
|
83
|
+
|
84
|
+
test "loads a module library" do
|
85
|
+
eval %[module ::Harvey; def bird; end; end]
|
86
|
+
load ::Harvey, :no_mock=>true
|
87
|
+
library_has_module('harvey', "Harvey")
|
88
|
+
command_exists?('bird')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "gem library" do
|
93
|
+
def mock_library(lib, options={})
|
94
|
+
options[:file_string] ||= ''
|
95
|
+
File.stubs(:exists?).returns(false)
|
96
|
+
GemLibrary.expects(:is_a_gem?).returns(true)
|
97
|
+
Util.expects(:safe_require).with { eval options.delete(:file_string) || ''; true}.returns(true)
|
98
|
+
end
|
99
|
+
|
100
|
+
test "loads" do
|
101
|
+
with_config(:libraries=>{"dude"=>{:module=>'Dude'}}) do
|
102
|
+
load "dude", :file_string=>"module ::Dude; def blah; end; end"
|
103
|
+
library_has_module('dude', "Dude")
|
104
|
+
command_exists?("blah")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
test "with kernel methods loads" do
|
109
|
+
load "dude", :file_string=>"module ::Kernel; def dude; end; end"
|
110
|
+
library_loaded? 'dude'
|
111
|
+
library('dude').module.should == nil
|
112
|
+
command_exists?("dude")
|
113
|
+
end
|
114
|
+
|
115
|
+
test "prints error when nonexistent" do
|
116
|
+
capture_stderr { load('blah') }.should =~ /Unable.*load/
|
117
|
+
end
|
118
|
+
|
119
|
+
test "with invalid module prints error" do
|
120
|
+
with_config(:libraries=>{"coolio"=>{:module=>"Cool"}}) do
|
121
|
+
capture_stderr {
|
122
|
+
load('coolio', :file_string=>"module ::Coolio; def coolio; end; end")
|
123
|
+
}.should =~ /Unable.*coolio.*No module/
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context "library with namespace" do
|
130
|
+
before(:all) { reset_main_object }
|
131
|
+
before(:each) { reset_boson }
|
132
|
+
|
133
|
+
test "loads and defaults to library name" do
|
134
|
+
with_config(:libraries=>{'blang'=>{:namespace=>true}}) do
|
135
|
+
load 'blang', :file_string=>"module Blang; def bling; end; end"
|
136
|
+
library_has_command('blang', 'bling')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
test "loads with config namespace" do
|
141
|
+
with_config(:libraries=>{'blung'=>{:namespace=>'dope'}}) do
|
142
|
+
load 'blung', :file_string=>"module Blung; def bling; end; end"
|
143
|
+
library_has_command('blung', 'bling')
|
144
|
+
library('blung').commands.size.should == 1
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
test "loads with config except" do
|
149
|
+
with_config(:libraries=>{'blong'=>{:namespace=>true, :except=>['wrong']}}) do
|
150
|
+
load 'blong', :file_string=>"module Blong; def bling; end; def wrong; end; end"
|
151
|
+
library_has_command('blong', 'bling')
|
152
|
+
library_has_command('blong', 'wrong', false)
|
153
|
+
library('blong').commands.size.should == 1
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
test "prints error if namespace conflicts with existing commands" do
|
158
|
+
eval "module Conflict; def bleng; end; end"
|
159
|
+
load Conflict, :no_mock=>true
|
160
|
+
with_config(:libraries=>{'bleng'=>{:namespace=>true}}) do
|
161
|
+
capture_stderr {
|
162
|
+
load 'bleng', :file_string=>"module Bleng; def bling; end; end"
|
163
|
+
}.should =~ /conflict.*bleng/
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "reload" do
|
169
|
+
before(:each) { reset }
|
170
|
+
test "loads currently unloaded library" do
|
171
|
+
create_library('blah')
|
172
|
+
Manager.expects(:load).with('blah', anything)
|
173
|
+
Manager.reload('blah')
|
174
|
+
end
|
175
|
+
|
176
|
+
test "doesn't load nonexistent library" do
|
177
|
+
capture_stdout { Manager.reload('bling', :verbose=>true) }.should =~ /bling doesn't/
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
module Boson
|
4
|
+
class ManagerTest < Test::Unit::TestCase
|
5
|
+
context "after_load" do
|
6
|
+
def load_library(hash)
|
7
|
+
new_attributes = {:name=>hash.delete(:name), :commands=>[], :created_dependencies=>[], :loaded=>true}
|
8
|
+
[:module, :except, :commands].each {|e| new_attributes[e] = hash.delete(e) if hash[e] }
|
9
|
+
Manager.expects(:load_once).returns(Library.new(new_attributes))
|
10
|
+
Manager.load([hash[:name]])
|
11
|
+
end
|
12
|
+
|
13
|
+
before(:each) { reset_boson }
|
14
|
+
|
15
|
+
test "loads basic library" do
|
16
|
+
load_library :name=>'blah'
|
17
|
+
library_loaded? 'blah'
|
18
|
+
end
|
19
|
+
|
20
|
+
test "loads library with commands" do
|
21
|
+
load_library :name=>'blah', :commands=>['frylock','meatwad']
|
22
|
+
library_loaded? 'blah'
|
23
|
+
command_exists?('frylock')
|
24
|
+
command_exists?('meatwad')
|
25
|
+
end
|
26
|
+
|
27
|
+
test "loads library with commands and except option" do
|
28
|
+
Boson.main_object.instance_eval("class<<self;self;end").expects(:undef_method).with('frylock')
|
29
|
+
load_library :name=>'blah', :commands=>['frylock','meatwad'], :except=>['frylock']
|
30
|
+
library_loaded? 'blah'
|
31
|
+
command_exists?('frylock', false)
|
32
|
+
command_exists?('meatwad')
|
33
|
+
end
|
34
|
+
|
35
|
+
context "command aliases" do
|
36
|
+
before(:each) { eval %[module ::Aquateen; def frylock; end; end] }
|
37
|
+
after(:each) { Object.send(:remove_const, "Aquateen") }
|
38
|
+
|
39
|
+
test "created with command specific config" do
|
40
|
+
with_config(:commands=>{'frylock'=>{:alias=>'fr'}}) do
|
41
|
+
Manager.expects(:create_instance_aliases).with({"Aquateen"=>{"frylock"=>"fr"}})
|
42
|
+
load_library :name=>'aquateen', :commands=>['frylock'], :module=>Aquateen
|
43
|
+
library_loaded? 'aquateen'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
test "created with config command_aliases" do
|
48
|
+
with_config(:command_aliases=>{"frylock"=>"fr"}) do
|
49
|
+
Manager.expects(:create_instance_aliases).with({"Aquateen"=>{"frylock"=>"fr"}})
|
50
|
+
load_library :name=>'aquateen', :commands=>['frylock'], :module=>Aquateen
|
51
|
+
library_loaded? 'aquateen'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
test "not created and warns for commands with no module" do
|
56
|
+
with_config(:commands=>{'frylock'=>{:alias=>'fr'}}) do
|
57
|
+
capture_stderr {
|
58
|
+
load_library(:name=>'aquateen', :commands=>['frylock'])
|
59
|
+
}.should =~ /No aliases/
|
60
|
+
library_loaded? 'aquateen'
|
61
|
+
Aquateen.method_defined?(:fr).should == false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
test "merges with existing created library" do
|
67
|
+
create_library('blah')
|
68
|
+
load_library :name=>'blah'
|
69
|
+
library_loaded? 'blah'
|
70
|
+
Boson.libraries.size.should == 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "option commands without args" do
|
75
|
+
before(:all) {
|
76
|
+
reset_boson
|
77
|
+
@library = Library.new(:name=>'blah', :commands=>['foo', 'bar'])
|
78
|
+
Boson.libraries << @library
|
79
|
+
@foo = Command.new(:name=>'foo', :lib=>'blah', :options=>{:fool=>:string}, :args=>'*')
|
80
|
+
Boson.commands << @foo
|
81
|
+
Boson.commands << Command.new(:name=>'bar', :lib=>'blah', :options=>{:bah=>:string})
|
82
|
+
}
|
83
|
+
|
84
|
+
test "are deleted" do
|
85
|
+
Scientist.expects(:create_option_command).with(anything, @foo)
|
86
|
+
Manager.create_option_commands(@library, @library.commands)
|
87
|
+
end
|
88
|
+
|
89
|
+
test "are deleted and printed when verbose" do
|
90
|
+
Scientist.expects(:create_option_command).with(anything, @foo)
|
91
|
+
@library.instance_eval("@options = {:verbose=>true}")
|
92
|
+
capture_stdout { Manager.create_option_commands(@library, @library.commands) } =~ /options.*blah/
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "loaded" do
|
97
|
+
before(:each) { reset_libraries }
|
98
|
+
|
99
|
+
test "returns false when library isn't loaded" do
|
100
|
+
create_library('blah')
|
101
|
+
Manager.loaded?('blah').should be(false)
|
102
|
+
end
|
103
|
+
|
104
|
+
test "returns true when library is loaded" do
|
105
|
+
create_library('blah', :loaded=>true)
|
106
|
+
Manager.loaded?('blah').should be(true)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
module Boson
|
4
|
+
class InspectorTest < Test::Unit::TestCase
|
5
|
+
test "non commands module can't set anything" do
|
6
|
+
eval "module Blah; end"
|
7
|
+
MethodInspector.current_module = Blah
|
8
|
+
Inspector.enable
|
9
|
+
Blah.module_eval("desc 'test'; def test; end; options :a=>1; def test2; end")
|
10
|
+
Inspector.disable
|
11
|
+
MethodInspector.store[:desc].empty?.should == true
|
12
|
+
MethodInspector.store[:options].empty?.should == true
|
13
|
+
end
|
14
|
+
|
15
|
+
context "commands module with" do
|
16
|
+
def parse(string)
|
17
|
+
Inspector.enable
|
18
|
+
::Boson::Commands::Zzz.module_eval(string)
|
19
|
+
Inspector.disable
|
20
|
+
MethodInspector.store
|
21
|
+
end
|
22
|
+
|
23
|
+
before(:all) { eval "module ::Boson::Commands::Zzz; end" }
|
24
|
+
before(:each) { MethodInspector.mod_store[::Boson::Commands::Zzz] = {} }
|
25
|
+
|
26
|
+
test "desc sets descriptions" do
|
27
|
+
parsed = parse "desc 'test'; def m1; end; desc 'one'; desc 'more'; def m2; end"
|
28
|
+
parsed[:desc].should == {"m1"=>"test", "m2"=>"more"}
|
29
|
+
end
|
30
|
+
|
31
|
+
test "options sets options" do
|
32
|
+
parse("options :z=>'b'; def zee; end")[:options].should == {"zee"=>{:z=>'b'}}
|
33
|
+
end
|
34
|
+
|
35
|
+
test "render_options sets render_options" do
|
36
|
+
parse("render_options :z=>true; def zee; end")[:render_options].should == {"zee"=>{:z=>true}}
|
37
|
+
end
|
38
|
+
|
39
|
+
test "neither options or desc set, sets method_locations" do
|
40
|
+
MethodInspector.stubs(:find_method_locations).returns(["/some/path", 10])
|
41
|
+
parsed = parse "desc 'yo'; def yo; end; options :yep=>1; def yep; end; render_options :a=>1; desc 'z'; options :a=>1; def az; end"
|
42
|
+
parsed[:method_locations].key?('yo').should == true
|
43
|
+
parsed[:method_locations].key?('yep').should == true
|
44
|
+
parsed[:method_locations].key?('az').should == false
|
45
|
+
end
|
46
|
+
|
47
|
+
test "no find_method_locations doesn't set method_locations" do
|
48
|
+
MethodInspector.stubs(:find_method_locations).returns(nil)
|
49
|
+
parse("def bluh; end")[:method_locations].key?('bluh').should == false
|
50
|
+
end
|
51
|
+
|
52
|
+
test "options calls scrape_with_eval" do
|
53
|
+
ArgumentInspector.expects(:scrape_with_eval).returns([['arg1']])
|
54
|
+
parse("desc 'desc'; options :some=>:opts; def doy(arg1); end")[:method_args]['doy'].should == [['arg1']]
|
55
|
+
end
|
56
|
+
|
57
|
+
test "options in file calls scrape_with_eval" do
|
58
|
+
MethodInspector.expects(:inspector_in_file?).returns(true)
|
59
|
+
ArgumentInspector.expects(:scrape_with_eval).returns([['arg1']])
|
60
|
+
parse("desc 'desc'; def doz(arg1); end")[:method_args]['doz'].should == [['arg1']]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,365 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
module Boson
|
4
|
+
class OptionParserTest < Test::Unit::TestCase
|
5
|
+
def create(opts)
|
6
|
+
@opt = OptionParser.new(opts)
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse(*args)
|
10
|
+
@non_opts = []
|
11
|
+
@opt.parse(args.flatten)
|
12
|
+
end
|
13
|
+
|
14
|
+
context "IndifferentAccessHash" do
|
15
|
+
before(:each) {
|
16
|
+
@hash = IndifferentAccessHash.new 'foo' => 'bar', 'baz' => 'bee'
|
17
|
+
}
|
18
|
+
it "can access values indifferently" do
|
19
|
+
@hash['foo'].should == 'bar'
|
20
|
+
@hash[:foo].should == 'bar'
|
21
|
+
@hash.values_at(:foo, :baz).should == ['bar', 'bee']
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can be initialized with either strings or symbols and be equal" do
|
25
|
+
hash2 = IndifferentAccessHash.new :foo=>'bar', :baz=>'bee'
|
26
|
+
@hash.should == hash2
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns keys as symbols by default" do
|
30
|
+
@hash.should == {:foo=>'bar', :baz=>'bee'}
|
31
|
+
end
|
32
|
+
|
33
|
+
it "can set values indifferently" do
|
34
|
+
@hash['foo'] = 'duh'
|
35
|
+
@hash[:foo].should == 'duh'
|
36
|
+
@hash[:baz] = 'wasp'
|
37
|
+
@hash['baz'].should == 'wasp'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "naming" do
|
42
|
+
it "automatically aliases long options with their first letter" do
|
43
|
+
create "--foo" => true
|
44
|
+
parse("-f")["foo"].should == true
|
45
|
+
end
|
46
|
+
|
47
|
+
it "automatically aliases two options with same first letters by aliasing alphabetical first with lowercase and second with uppercase" do
|
48
|
+
create :verbose=>:boolean, :vertical=>:string, :verz=>:boolean
|
49
|
+
parse('-v', '-V','2').should == {:verbose=>true, :vertical=>'2'}
|
50
|
+
end
|
51
|
+
|
52
|
+
it "doesn't auto-alias options that have multiple names given" do
|
53
|
+
create ["--foo", "--bar"] => :boolean
|
54
|
+
parse("-f")["foo"].should == nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it "allows aliases to be symbols or strings" do
|
58
|
+
create [:foo, :bar, 'baz'] =>:string
|
59
|
+
parse("--foo", "12")[:foo].should == "12"
|
60
|
+
parse("--bar", "12")[:foo].should == "12"
|
61
|
+
parse("--baz", "12")[:foo].should == "12"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "allows multiple aliases for a given opt" do
|
65
|
+
create ["--foo", "--bar", "--baz"] => :string
|
66
|
+
parse("--foo", "12")["foo"].should == "12"
|
67
|
+
parse("--bar", "12")["foo"].should == "12"
|
68
|
+
parse("--baz", "12")["foo"].should == "12"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "allows custom short names" do
|
72
|
+
create "-f" => :string
|
73
|
+
parse("-f", "12").should == {:f => "12"}
|
74
|
+
end
|
75
|
+
|
76
|
+
it "allows capital short names" do
|
77
|
+
create :A => :boolean
|
78
|
+
parse("-A")[:A].should == true
|
79
|
+
end
|
80
|
+
|
81
|
+
it "allows capital short aliases" do
|
82
|
+
create [:awesome, :A] => :string
|
83
|
+
parse("--awesome", "bar")[:awesome].should == 'bar'
|
84
|
+
parse("-A", "bar")[:awesome].should == 'bar'
|
85
|
+
end
|
86
|
+
|
87
|
+
it "allows custom short aliases" do
|
88
|
+
create ["--bar", "-f"] => :string
|
89
|
+
parse("-f", "12").should == {:bar => "12"}
|
90
|
+
end
|
91
|
+
|
92
|
+
it "allows humanized opt name" do
|
93
|
+
create 'foo' => :string, :bar => :required
|
94
|
+
parse("-f", "1", "-b", "2").should == {:foo => "1", :bar => "2"}
|
95
|
+
end
|
96
|
+
|
97
|
+
it "allows humanized symbol opt name" do
|
98
|
+
create :foo=>:string
|
99
|
+
parse('-f','1').should == {:foo=>'1'}
|
100
|
+
end
|
101
|
+
|
102
|
+
it "doesn't allow alias to override another option" do
|
103
|
+
create :foo=>:string, [:bar, :foo]=>:boolean
|
104
|
+
parse("--foo", "boo")[:foo].should == 'boo'
|
105
|
+
end
|
106
|
+
|
107
|
+
it "doesn't recognize long opt format for a opt that is originally short" do
|
108
|
+
create 'f' => :string
|
109
|
+
parse("-f", "1").should == {:f => "1"}
|
110
|
+
parse("--f", "1").should == {}
|
111
|
+
end
|
112
|
+
|
113
|
+
it "accepts --[no-]opt variant for booleans, setting false for value" do
|
114
|
+
create "--foo" => :boolean
|
115
|
+
parse("--no-foo")["foo"].should == false
|
116
|
+
parse("--foo")["foo"].should == true
|
117
|
+
end
|
118
|
+
|
119
|
+
it "will prefer 'no-opt' variant over inverting 'opt' if explicitly set" do
|
120
|
+
create "--no-foo" => true
|
121
|
+
parse("--no-foo")["no-foo"].should == true
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
context "option values can be set with" do
|
127
|
+
it "a opt=<value> assignment" do
|
128
|
+
create "--foo" => :required
|
129
|
+
parse("--foo=12")["foo"].should == "12"
|
130
|
+
parse("-f=12")["foo"].should == "12"
|
131
|
+
parse("--foo=bar=baz")["foo"].should == "bar=baz"
|
132
|
+
parse("--foo=sentence with spaces")["foo"].should == "sentence with spaces"
|
133
|
+
end
|
134
|
+
|
135
|
+
it "a -nXY assignment" do
|
136
|
+
create "--num" => :required
|
137
|
+
parse("-n12")["num"].should == "12"
|
138
|
+
end
|
139
|
+
|
140
|
+
it "conjoined short options" do
|
141
|
+
create "--foo" => true, "--bar" => true, "--app" => true
|
142
|
+
opts = parse "-fba"
|
143
|
+
opts["foo"].should == true
|
144
|
+
opts["bar"].should == true
|
145
|
+
opts["app"].should == true
|
146
|
+
end
|
147
|
+
|
148
|
+
it "conjoined short options with argument" do
|
149
|
+
create "--foo" => true, "--bar" => true, "--app" => :required
|
150
|
+
opts = parse "-fba", "12"
|
151
|
+
opts["foo"].should == true
|
152
|
+
opts["bar"].should == true
|
153
|
+
opts["app"].should == "12"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context "parse" do
|
158
|
+
it "extracts non-option arguments" do
|
159
|
+
create "--foo" => :required, "--bar" => true
|
160
|
+
parse("foo", "bar", "--baz", "--foo", "12", "--bar", "-T", "bang").should == {
|
161
|
+
:foo => "12", :bar => true
|
162
|
+
}
|
163
|
+
@opt.leading_non_opts.should == ["foo", "bar", "--baz"]
|
164
|
+
@opt.trailing_non_opts.should == ["-T", "bang"]
|
165
|
+
@opt.non_opts.should == ["foo", "bar", "--baz", "-T", "bang"]
|
166
|
+
end
|
167
|
+
|
168
|
+
context "with parse flag" do
|
169
|
+
it ":delete_invalid_opts deletes and warns of invalid options" do
|
170
|
+
create(:foo=>:boolean)
|
171
|
+
capture_stderr {
|
172
|
+
@opt.parse(%w{-f -d ok}, :delete_invalid_opts=>true)
|
173
|
+
}.should =~ /Deleted invalid option '-d'/
|
174
|
+
@opt.non_opts.should == ['ok']
|
175
|
+
end
|
176
|
+
|
177
|
+
it ":opts_before_args only allows options before args" do
|
178
|
+
create(:foo=>:boolean)
|
179
|
+
@opt.parse(%w{ok -f}, :opts_before_args=>true).should == {}
|
180
|
+
@opt.parse(%w{-f ok}, :opts_before_args=>true).should == {:foo=>true}
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context "with no arguments" do
|
185
|
+
it "and no options returns an empty hash" do
|
186
|
+
create({})
|
187
|
+
parse.should == {}
|
188
|
+
end
|
189
|
+
|
190
|
+
it "and several options returns an empty hash" do
|
191
|
+
create "--foo" => :boolean, "--bar" => :string
|
192
|
+
parse.should == {}
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context "option hashes" do
|
198
|
+
it "make hash keys available as symbols as well" do
|
199
|
+
create "--foo" => :string
|
200
|
+
parse("--foo", "12")[:foo].should == "12"
|
201
|
+
end
|
202
|
+
|
203
|
+
it "don't set nonexistant options" do
|
204
|
+
create "--foo" => :boolean
|
205
|
+
parse("--foo")["bar"].should == nil
|
206
|
+
opts = parse
|
207
|
+
opts["foo"].should == nil
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
it ":required type raises an error if it isn't given" do
|
212
|
+
create "--foo" => :required, "--bar" => :string
|
213
|
+
assert_error(OptionParser::Error, 'no value.*required.*foo') { parse("--bar", "str") }
|
214
|
+
end
|
215
|
+
|
216
|
+
context ":string type" do
|
217
|
+
before :each do
|
218
|
+
create "--foo" => :string, "--bar" => :string
|
219
|
+
end
|
220
|
+
|
221
|
+
it "doesn't set nonexistant options" do
|
222
|
+
parse("--bling")[:bar].should == nil
|
223
|
+
end
|
224
|
+
|
225
|
+
it "sets values correctly" do
|
226
|
+
parse("--foo", "12")[:foo].should == "12"
|
227
|
+
parse("--bar", "12")[:bar].should == "12"
|
228
|
+
end
|
229
|
+
|
230
|
+
it "raises error if passed another valid option" do
|
231
|
+
assert_error(OptionParser::Error, "cannot pass.*'foo'") { parse("--foo", "--bar") }
|
232
|
+
end
|
233
|
+
|
234
|
+
it "raises error if not passed a value" do
|
235
|
+
assert_error(OptionParser::Error, "no value.*'foo'") { parse("--foo") }
|
236
|
+
end
|
237
|
+
|
238
|
+
it "overwrites earlier values with later values" do
|
239
|
+
parse("--foo", "12", "--foo", "13")[:foo].should == "13"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
context ":string type with :values attribute" do
|
244
|
+
before(:all ) { create :foo=>{:type=>:string, :values=>%w{angola abu abib}} }
|
245
|
+
it "auto aliases if a match exists" do
|
246
|
+
parse("-f", "an")[:foo].should == 'angola'
|
247
|
+
end
|
248
|
+
|
249
|
+
it "auto aliases first sorted match" do
|
250
|
+
parse("-f", "a")[:foo].should == 'abib'
|
251
|
+
end
|
252
|
+
|
253
|
+
it "raises error if option doesn't auto alias or match given values" do
|
254
|
+
assert_error(OptionParser::Error, "invalid.*'z'") { parse("-f", "z") }
|
255
|
+
end
|
256
|
+
|
257
|
+
it "doesn't raise error for a nonmatch if enum is false" do
|
258
|
+
create :foo=>{:type=>:string, :values=>%w{angola abu abib}, :enum=>false}
|
259
|
+
parse("-f", "z")[:foo].should == 'z'
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
context ":string type with default value" do
|
264
|
+
before(:each) do
|
265
|
+
create "--branch" => "master"
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should get the specified value" do
|
269
|
+
parse("--branch", "bugfix").should == { :branch => "bugfix" }
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should get the default value when not specified" do
|
273
|
+
parse.should == { :branch => "master" }
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context ":numeric type" do
|
278
|
+
before(:each) do
|
279
|
+
create "n" => :numeric, "m" => 5
|
280
|
+
end
|
281
|
+
|
282
|
+
it "supports numeric defaults" do
|
283
|
+
parse["m"].should == 5
|
284
|
+
end
|
285
|
+
|
286
|
+
it "converts values to numeric types" do
|
287
|
+
parse("-n", "3", "-m", ".5").should == {:n => 3, :m => 0.5}
|
288
|
+
end
|
289
|
+
|
290
|
+
it "raises error when value isn't numeric" do
|
291
|
+
assert_error(OptionParser::Error, "expected numeric value for.*'n'") { parse("-n", "foo") }
|
292
|
+
end
|
293
|
+
|
294
|
+
it "raises error when opt is present without value" do
|
295
|
+
assert_error(OptionParser::Error, "no value.*'n'") { parse("-n") }
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
context ":array type" do
|
300
|
+
before(:all) {
|
301
|
+
create :a=>:array, :b=>[1,2,3], :c=>{:type=>:array, :values=>%w{foo fa bar zebra}},
|
302
|
+
:d=>{:type=>:array, :split=>" "}
|
303
|
+
}
|
304
|
+
|
305
|
+
it "supports array defaults" do
|
306
|
+
parse[:b].should == [1,2,3]
|
307
|
+
end
|
308
|
+
|
309
|
+
it "converts comma delimited values to an array" do
|
310
|
+
parse("-a","1,2,5")[:a].should == %w{1 2 5}
|
311
|
+
end
|
312
|
+
|
313
|
+
it "raises error when option has no value" do
|
314
|
+
assert_error(OptionParser::Error, "no value.*'a'") { parse("-a") }
|
315
|
+
end
|
316
|
+
|
317
|
+
it "auto aliases :values attribute" do
|
318
|
+
parse("-c","f,b")[:c].should == %w{fa bar}
|
319
|
+
end
|
320
|
+
|
321
|
+
it "allows a configurable splitter" do
|
322
|
+
parse("-d", "yogi berra")[:d].should == %w{yogi berra}
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
context "option with attributes" do
|
327
|
+
it "can get type from :type" do
|
328
|
+
create :foo=>{:type=>:numeric}
|
329
|
+
parse("-f", '3')[:foo] == 3
|
330
|
+
end
|
331
|
+
|
332
|
+
it "can get type and default from :default" do
|
333
|
+
create :foo=>{:default=>[]}
|
334
|
+
parse("-f", "1")[:foo].should == ['1']
|
335
|
+
parse[:foo].should == []
|
336
|
+
end
|
337
|
+
|
338
|
+
it "assumes :boolean type if no type found" do
|
339
|
+
create :foo=>{:some=>'params'}
|
340
|
+
parse('-f')[:foo].should == true
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
context "#formatted_usage" do
|
345
|
+
def usage
|
346
|
+
@opt.formatted_usage.split(" ").sort
|
347
|
+
end
|
348
|
+
|
349
|
+
it "outputs string args with sample values" do
|
350
|
+
create "--repo" => :string, "--branch" => "bugfix", "-n" => 6
|
351
|
+
usage.should == %w([--branch=bugfix] [--repo=REPO] [-n=6])
|
352
|
+
end
|
353
|
+
|
354
|
+
it "outputs numeric args with 'N' as sample value" do
|
355
|
+
create "--iter" => :numeric
|
356
|
+
usage.should == ["[--iter=N]"]
|
357
|
+
end
|
358
|
+
|
359
|
+
it "outputs array args with sample value" do
|
360
|
+
create "--libs" => :array
|
361
|
+
usage.should == ["[--libs=A,B,C]"]
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|