boson 0.4.0 → 1.0.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.
- data/.gemspec +6 -7
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.rdoc +1 -1
- data/README.md +144 -0
- data/README.rdoc +2 -2
- data/Upgrading.md +23 -0
- data/bin/boson +2 -2
- data/lib/boson.rb +44 -52
- data/lib/boson/bare_runner.rb +83 -0
- data/lib/boson/bin_runner.rb +114 -0
- data/lib/boson/command.rb +92 -132
- data/lib/boson/inspector.rb +49 -48
- data/lib/boson/library.rb +71 -120
- data/lib/boson/loader.rb +73 -84
- data/lib/boson/manager.rb +131 -135
- data/lib/boson/method_inspector.rb +112 -0
- data/lib/boson/option_command.rb +71 -154
- data/lib/boson/option_parser.rb +178 -173
- data/lib/boson/options.rb +46 -32
- data/lib/boson/runner.rb +58 -66
- data/lib/boson/runner_library.rb +31 -0
- data/lib/boson/scientist.rb +48 -81
- data/lib/boson/util.rb +46 -61
- data/lib/boson/version.rb +1 -1
- data/test/bin_runner_test.rb +53 -191
- data/test/command_test.rb +5 -9
- data/test/deps.rip +2 -2
- data/test/loader_test.rb +18 -216
- data/test/manager_test.rb +69 -79
- data/test/method_inspector_test.rb +12 -36
- data/test/option_parser_test.rb +45 -32
- data/test/runner_library_test.rb +10 -0
- data/test/runner_test.rb +158 -28
- data/test/scientist_test.rb +9 -147
- data/test/test_helper.rb +87 -52
- metadata +30 -72
- data/deps.rip +0 -2
- data/lib/boson/commands.rb +0 -7
- data/lib/boson/commands/core.rb +0 -77
- data/lib/boson/commands/web_core.rb +0 -153
- data/lib/boson/index.rb +0 -48
- data/lib/boson/inspectors/argument_inspector.rb +0 -97
- data/lib/boson/inspectors/comment_inspector.rb +0 -100
- data/lib/boson/inspectors/method_inspector.rb +0 -98
- data/lib/boson/libraries/file_library.rb +0 -144
- data/lib/boson/libraries/gem_library.rb +0 -30
- data/lib/boson/libraries/local_file_library.rb +0 -30
- data/lib/boson/libraries/module_library.rb +0 -37
- data/lib/boson/libraries/require_library.rb +0 -23
- data/lib/boson/namespace.rb +0 -31
- data/lib/boson/pipe.rb +0 -147
- data/lib/boson/pipes.rb +0 -75
- data/lib/boson/repo.rb +0 -107
- data/lib/boson/runners/bin_runner.rb +0 -208
- data/lib/boson/runners/console_runner.rb +0 -58
- data/lib/boson/view.rb +0 -95
- data/test/argument_inspector_test.rb +0 -62
- data/test/commands_test.rb +0 -22
- data/test/comment_inspector_test.rb +0 -126
- data/test/file_library_test.rb +0 -42
- data/test/pipes_test.rb +0 -65
- data/test/repo_index_test.rb +0 -122
- data/test/repo_test.rb +0 -23
@@ -1,22 +1,28 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
2
|
|
3
3
|
describe "MethodInspector" do
|
4
|
+
before { MethodInspector.instance = nil }
|
5
|
+
|
6
|
+
def method_inspector
|
7
|
+
MethodInspector.instance
|
8
|
+
end
|
9
|
+
|
4
10
|
it "non commands module can't set anything" do
|
11
|
+
remove_constant :Blah
|
5
12
|
eval "module Blah; end"
|
6
|
-
|
13
|
+
method_inspector.current_module = Blah
|
7
14
|
Inspector.enable
|
8
15
|
Blah.module_eval("desc 'test'; def test; end; options :a=>1; def test2; end")
|
9
16
|
Inspector.disable
|
10
|
-
|
11
|
-
|
17
|
+
method_inspector.store[:desc].empty?.should == true
|
18
|
+
method_inspector.store[:options].empty?.should == true
|
12
19
|
end
|
13
20
|
|
14
21
|
it "handles anonymous classes" do
|
15
|
-
MethodInspector.mod_store = {}
|
16
22
|
Inspector.enable
|
17
23
|
Class.new.module_eval "def blah; end"
|
18
24
|
Inspector.disable
|
19
|
-
|
25
|
+
method_inspector.store.should == nil
|
20
26
|
end
|
21
27
|
|
22
28
|
describe "commands module with" do
|
@@ -24,11 +30,10 @@ describe "MethodInspector" do
|
|
24
30
|
Inspector.enable
|
25
31
|
::Boson::Commands::Zzz.module_eval(string)
|
26
32
|
Inspector.disable
|
27
|
-
|
33
|
+
method_inspector.store
|
28
34
|
end
|
29
35
|
|
30
36
|
before_all { eval "module ::Boson::Commands::Zzz; end" }
|
31
|
-
before { MethodInspector.mod_store.delete(::Boson::Commands::Zzz) }
|
32
37
|
|
33
38
|
it "desc sets descriptions" do
|
34
39
|
parsed = parse "desc 'test'; def m1; end; desc 'one'; desc 'more'; def m2; end"
|
@@ -54,37 +59,8 @@ describe "MethodInspector" do
|
|
54
59
|
{"zee"=>{:z=>:string}}
|
55
60
|
end
|
56
61
|
|
57
|
-
it "render_options sets render_options" do
|
58
|
-
parse("render_options :z=>true; def zee; end")[:render_options].should == {"zee"=>{:z=>true}}
|
59
|
-
end
|
60
|
-
|
61
62
|
it "config sets config" do
|
62
63
|
parse("config :z=>true; def zee; end")[:config].should == {"zee"=>{:z=>true}}
|
63
64
|
end
|
64
|
-
|
65
|
-
it "not all method attributes set causes method_locations to be set" do
|
66
|
-
MethodInspector.stubs(:find_method_locations).returns(["/some/path", 10])
|
67
|
-
parsed = parse "desc 'yo'; def yo; end; options :yep=>1; def yep; end; " +
|
68
|
-
"option :b, :boolean; render_options :a=>1; config :a=>1; desc 'z'; options :a=>1; def az; end"
|
69
|
-
parsed[:method_locations].key?('yo').should == true
|
70
|
-
parsed[:method_locations].key?('yep').should == true
|
71
|
-
parsed[:method_locations].key?('az').should == false
|
72
|
-
end
|
73
|
-
|
74
|
-
it "no find_method_locations doesn't set method_locations" do
|
75
|
-
MethodInspector.stubs(:find_method_locations).returns(nil)
|
76
|
-
parse("def bluh; end")[:method_locations].key?('bluh').should == false
|
77
|
-
end
|
78
|
-
|
79
|
-
it "options calls scrape_with_eval" do
|
80
|
-
ArgumentInspector.expects(:scrape_with_eval).returns([['arg1']])
|
81
|
-
parse("desc 'desc'; options :some=>:opts; def doy(arg1); end")[:args]['doy'].should == [['arg1']]
|
82
|
-
end
|
83
|
-
|
84
|
-
it "options in file calls scrape_with_eval" do
|
85
|
-
MethodInspector.expects(:inspector_in_file?).returns(true)
|
86
|
-
ArgumentInspector.expects(:scrape_with_eval).returns([['arg1']])
|
87
|
-
parse("desc 'desc'; def doz(arg1); end")[:args]['doz'].should == [['arg1']]
|
88
|
-
end
|
89
65
|
end
|
90
66
|
end
|
data/test/option_parser_test.rb
CHANGED
@@ -6,36 +6,28 @@ describe "OptionParser" do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def opt; @opt; end
|
9
|
-
|
9
|
+
|
10
10
|
def parse(*args)
|
11
11
|
@non_opts = []
|
12
12
|
opt.parse(args.flatten)
|
13
13
|
end
|
14
14
|
|
15
|
-
describe "
|
15
|
+
describe "#indifferent_hash" do
|
16
16
|
before {
|
17
|
-
@hash =
|
17
|
+
@hash = OptionParser.new({}).indifferent_hash
|
18
|
+
@hash.update foo: 'bar'
|
18
19
|
}
|
20
|
+
|
19
21
|
it "can access values indifferently" do
|
20
22
|
@hash['foo'].should == 'bar'
|
21
23
|
@hash[:foo].should == 'bar'
|
22
|
-
@hash.values_at(:foo, :baz).should == ['bar', 'bee']
|
23
|
-
end
|
24
|
-
|
25
|
-
it "can be initialized with either strings or symbols and be equal" do
|
26
|
-
hash2 = IndifferentAccessHash.new :foo=>'bar', :baz=>'bee'
|
27
|
-
@hash.should == hash2
|
28
|
-
end
|
29
|
-
|
30
|
-
it "returns keys as symbols by default" do
|
31
|
-
@hash.should == {:foo=>'bar', :baz=>'bee'}
|
32
24
|
end
|
33
25
|
|
34
|
-
it "
|
35
|
-
@hash['foo'] = '
|
36
|
-
@hash[
|
37
|
-
@hash[:
|
38
|
-
@hash[
|
26
|
+
it "cannot set values indifferently" do
|
27
|
+
@hash['foo'] = 'barred'
|
28
|
+
@hash['foo'].should == 'barred'
|
29
|
+
@hash[:foo].should_not == 'barred'
|
30
|
+
@hash[:foo].should == 'bar'
|
39
31
|
end
|
40
32
|
end
|
41
33
|
|
@@ -49,7 +41,7 @@ describe "OptionParser" do
|
|
49
41
|
create :verbose=>:boolean, :vertical=>:string, :verz=>:boolean
|
50
42
|
parse('-v', '-V','2').should == {:verbose=>true, :vertical=>'2'}
|
51
43
|
end
|
52
|
-
|
44
|
+
|
53
45
|
it "doesn't auto-alias options that have multiple names given" do
|
54
46
|
create ["--foo", "--bar"] => :boolean
|
55
47
|
parse("-f")["foo"].should == nil
|
@@ -61,14 +53,14 @@ describe "OptionParser" do
|
|
61
53
|
parse("--bar", "12")[:foo].should == "12"
|
62
54
|
parse("--baz", "12")[:foo].should == "12"
|
63
55
|
end
|
64
|
-
|
56
|
+
|
65
57
|
it "allows multiple aliases for a given opt" do
|
66
58
|
create ["--foo", "--bar", "--baz"] => :string
|
67
59
|
parse("--foo", "12")["foo"].should == "12"
|
68
60
|
parse("--bar", "12")["foo"].should == "12"
|
69
61
|
parse("--baz", "12")["foo"].should == "12"
|
70
62
|
end
|
71
|
-
|
63
|
+
|
72
64
|
it "allows custom short names" do
|
73
65
|
create "-f" => :string
|
74
66
|
parse("-f", "12").should == {:f => "12"}
|
@@ -89,7 +81,7 @@ describe "OptionParser" do
|
|
89
81
|
create ["--bar", "-f"] => :string
|
90
82
|
parse("-f", "12").should == {:bar => "12"}
|
91
83
|
end
|
92
|
-
|
84
|
+
|
93
85
|
it "allows humanized opt name" do
|
94
86
|
create 'foo' => :string, :bar => :string
|
95
87
|
parse("-f", "1", "-b", "2").should == {:foo => "1", :bar => "2"}
|
@@ -110,7 +102,7 @@ describe "OptionParser" do
|
|
110
102
|
parse("-f", "1").should == {:f => "1"}
|
111
103
|
parse("--f", "1").should == {}
|
112
104
|
end
|
113
|
-
|
105
|
+
|
114
106
|
it "accepts --[no-]opt variant for booleans, setting false for value" do
|
115
107
|
create "--foo" => :boolean
|
116
108
|
parse("--no-foo")["foo"].should == false
|
@@ -127,7 +119,7 @@ describe "OptionParser" do
|
|
127
119
|
create "--no-foo" => true
|
128
120
|
parse("--no-foo")["no-foo"].should == true
|
129
121
|
end
|
130
|
-
|
122
|
+
|
131
123
|
end
|
132
124
|
|
133
125
|
describe "option values can be set with" do
|
@@ -138,12 +130,12 @@ describe "OptionParser" do
|
|
138
130
|
parse("--foo=bar=baz")["foo"].should == "bar=baz"
|
139
131
|
parse("--foo=sentence with spaces")["foo"].should == "sentence with spaces"
|
140
132
|
end
|
141
|
-
|
133
|
+
|
142
134
|
it "a -nXY assignment" do
|
143
135
|
create "--num" => :numeric
|
144
136
|
parse("-n12")["num"].should == 12
|
145
137
|
end
|
146
|
-
|
138
|
+
|
147
139
|
it "conjoined short options" do
|
148
140
|
create "--foo" => true, "--bar" => true, "--app" => true
|
149
141
|
opts = parse "-fba"
|
@@ -151,7 +143,7 @@ describe "OptionParser" do
|
|
151
143
|
opts["bar"].should == true
|
152
144
|
opts["app"].should == true
|
153
145
|
end
|
154
|
-
|
146
|
+
|
155
147
|
it "conjoined short options with argument" do
|
156
148
|
create "--foo" => true, "--bar" => true, "--app" => :numeric
|
157
149
|
opts = parse "-fba", "12"
|
@@ -161,7 +153,7 @@ describe "OptionParser" do
|
|
161
153
|
end
|
162
154
|
end
|
163
155
|
|
164
|
-
describe "parse" do
|
156
|
+
describe "#parse" do
|
165
157
|
it "extracts non-option arguments" do
|
166
158
|
create "--foo" => :string, "--bar" => true
|
167
159
|
parse("foo", "bar", "--baz", "--foo", "12", "--bar", "-T", "bang").should == {
|
@@ -188,7 +180,8 @@ describe "OptionParser" do
|
|
188
180
|
opt.non_opts.should == ['ok']
|
189
181
|
end
|
190
182
|
|
191
|
-
|
183
|
+
# TODO: Fix for 1.9.3
|
184
|
+
xit ":delete_invalid_opts deletes until - or --" do
|
192
185
|
create(:foo=>:boolean, :bar=>:boolean)
|
193
186
|
%w{- --}.each do |stop_char|
|
194
187
|
capture_stderr {
|
@@ -295,7 +288,7 @@ describe "OptionParser" do
|
|
295
288
|
parse('-f')[:foo].should == true
|
296
289
|
end
|
297
290
|
end
|
298
|
-
|
291
|
+
|
299
292
|
def usage
|
300
293
|
opt.formatted_usage.split(" ").sort
|
301
294
|
end
|
@@ -305,7 +298,7 @@ describe "OptionParser" do
|
|
305
298
|
create "--repo" => :string, "--branch" => "bugfix", "-n" => 6
|
306
299
|
usage.should == %w([--branch=bugfix] [--repo=REPO] [-n=6])
|
307
300
|
end
|
308
|
-
|
301
|
+
|
309
302
|
it "outputs numeric args with 'N' as sample value" do
|
310
303
|
create "--iter" => :numeric
|
311
304
|
usage.should == ["[--iter=N]"]
|
@@ -322,6 +315,26 @@ describe "OptionParser" do
|
|
322
315
|
end
|
323
316
|
end
|
324
317
|
|
318
|
+
describe "#render_table" do
|
319
|
+
it "renders normal options with desc correctly" do
|
320
|
+
create regexp: {type: :string, desc: 'A regex, ya know'},
|
321
|
+
all: {type: :boolean, desc: 'Search all fields'}
|
322
|
+
capture_stdout { opt.print_usage_table no_headers: true }.should == <<-STR
|
323
|
+
-a, --all Search all fields
|
324
|
+
-r, --regexp A regex, ya know
|
325
|
+
STR
|
326
|
+
end
|
327
|
+
|
328
|
+
it "renders an option without an alias correctly" do
|
329
|
+
create regexp: :string, reverse_sort: :boolean, reload: :boolean
|
330
|
+
capture_stdout { opt.print_usage_table no_headers: true }.should == <<-STR
|
331
|
+
-r, --regexp
|
332
|
+
-R, --reload
|
333
|
+
--reverse_sort
|
334
|
+
STR
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
325
338
|
describe "user defined option class" do
|
326
339
|
before_all {
|
327
340
|
::FooBoo = Struct.new(:name)
|
@@ -364,4 +377,4 @@ describe "OptionParser" do
|
|
364
377
|
assert_error(OptionParser::Error, "invalid.*:blah_blah") { parse("-c", 'ok') }
|
365
378
|
end
|
366
379
|
end
|
367
|
-
end
|
380
|
+
end
|
data/test/runner_test.rb
CHANGED
@@ -1,40 +1,170 @@
|
|
1
|
-
require File.
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
class MyRunner < Boson::Runner
|
4
|
+
desc "This is a small"
|
5
|
+
def small(*args)
|
6
|
+
p args
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
option :spicy, type: :boolean, desc: 'hot'
|
10
|
+
desc "This is a medium"
|
11
|
+
def medium(arg=nil, opts={})
|
12
|
+
p [arg, opts]
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "This is a mini"
|
16
|
+
def mini(me)
|
17
|
+
end
|
18
|
+
|
19
|
+
def quiet
|
20
|
+
end
|
21
|
+
|
22
|
+
def boom
|
23
|
+
nil.boom
|
24
|
+
end
|
11
25
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
26
|
+
def broken
|
27
|
+
raise ArgumentError
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def no_run
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "Runner" do
|
36
|
+
before_all { $0 = 'my_command'; reset }
|
37
|
+
|
38
|
+
def my_command(cmd='')
|
39
|
+
capture_stdout do
|
40
|
+
MyRunner.start cmd.split(/\s+/)
|
17
41
|
end
|
18
42
|
end
|
19
43
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
44
|
+
def default_usage
|
45
|
+
<<-STR
|
46
|
+
Usage: my_command COMMAND [ARGS]
|
47
|
+
|
48
|
+
Available commands:
|
49
|
+
boom
|
50
|
+
broken
|
51
|
+
medium This is a medium
|
52
|
+
mini This is a mini
|
53
|
+
quiet
|
54
|
+
small This is a small
|
55
|
+
|
56
|
+
For help on a command: my_command COMMAND -h
|
57
|
+
STR
|
24
58
|
end
|
25
59
|
|
26
|
-
it "
|
27
|
-
|
28
|
-
Manager.expects(:load).with([:lib1,:lib2], anything)
|
29
|
-
start(:libraries=>[:lib1, :lib2])
|
60
|
+
it "prints sorted commands by default" do
|
61
|
+
my_command.should == default_usage
|
30
62
|
end
|
31
63
|
|
32
|
-
it "
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
64
|
+
it "prints default usage for -h and --help" do
|
65
|
+
my_command('-h').should == default_usage
|
66
|
+
my_command('--help').should == default_usage
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "for COMMAND -h" do
|
70
|
+
it "prints help for descriptionless command" do
|
71
|
+
my_command('quiet -h').should == <<-STR
|
72
|
+
Usage: my_command quiet
|
73
|
+
|
74
|
+
Description:
|
75
|
+
TODO
|
76
|
+
STR
|
77
|
+
end
|
78
|
+
|
79
|
+
it "prints help for optionless command with splat args" do
|
80
|
+
my_command('small -h').should == <<-STR
|
81
|
+
Usage: my_command small *ARGS
|
82
|
+
|
83
|
+
Description:
|
84
|
+
This is a small
|
85
|
+
STR
|
86
|
+
end
|
87
|
+
|
88
|
+
it "prints help for optionless command with required args" do
|
89
|
+
my_command('mini -h').should == <<-STR
|
90
|
+
Usage: my_command mini ME
|
91
|
+
|
92
|
+
Description:
|
93
|
+
This is a mini
|
94
|
+
STR
|
95
|
+
end
|
96
|
+
|
97
|
+
it "prints help for command with options and optional args" do
|
98
|
+
my_command('medium -h').should == <<-STR
|
99
|
+
Usage: my_command medium [ARG]
|
100
|
+
|
101
|
+
Options:
|
102
|
+
-s, --spicy hot
|
103
|
+
|
104
|
+
Description:
|
105
|
+
This is a medium
|
106
|
+
STR
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "handles command with default arguments correctly" do
|
111
|
+
my_command('medium').chomp.should == '[nil, {}]'
|
112
|
+
end
|
113
|
+
|
114
|
+
it "calls command with options correctly" do
|
115
|
+
my_command('medium 1 --spicy').chomp.should == '["1", {:spicy=>true}]'
|
116
|
+
end
|
117
|
+
|
118
|
+
it "calls optionless command correctly" do
|
119
|
+
my_command('small 1 2').chomp.should == '["1", "2"]'
|
120
|
+
end
|
121
|
+
|
122
|
+
it "calls command with too many args" do
|
123
|
+
MyRunner.expects(:abort).with <<-STR.chomp
|
124
|
+
'medium' was called incorrectly.
|
125
|
+
Usage: medium [ARG]
|
126
|
+
STR
|
127
|
+
my_command('medium 1 2 3')
|
128
|
+
end
|
129
|
+
|
130
|
+
it "prints error message for internal public method" do
|
131
|
+
MyRunner.expects(:abort).with %[Could not find command "to_s"]
|
132
|
+
my_command('to_s').should == ''
|
133
|
+
end
|
134
|
+
|
135
|
+
it "prints error message for nonexistant command" do
|
136
|
+
MyRunner.expects(:abort).with %[Could not find command "blarg"]
|
137
|
+
my_command('blarg').should == ''
|
138
|
+
end
|
139
|
+
|
140
|
+
it "allows no method error in command" do
|
141
|
+
assert_error(NoMethodError) { my_command('boom') }
|
142
|
+
end
|
143
|
+
|
144
|
+
it "allows no method error in command" do
|
145
|
+
assert_error(ArgumentError) { my_command('broken') }
|
146
|
+
end
|
147
|
+
|
148
|
+
it "prints error message for private method" do
|
149
|
+
MyRunner.expects(:abort).with %[Could not find command "no_run"]
|
150
|
+
my_command('no_run').should == ''
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "$BOSONRC" do
|
154
|
+
before { ENV.delete('BOSONRC') }
|
155
|
+
|
156
|
+
it "is not loaded by default" do
|
157
|
+
MyRunner.expects(:load).never
|
158
|
+
my_command('quiet').should == ''
|
159
|
+
end
|
160
|
+
|
161
|
+
it "is loaded if set" do
|
162
|
+
ENV['BOSONRC'] = 'whoop'
|
163
|
+
File.expects(:exists?).returns(true)
|
164
|
+
MyRunner.expects(:load).with('whoop')
|
165
|
+
my_command('quiet')
|
166
|
+
end
|
167
|
+
|
168
|
+
after_all { ENV['BOSONRC'] = File.dirname(__FILE__) + '/.bosonrc' }
|
38
169
|
end
|
39
|
-
|
40
|
-
end
|
170
|
+
end
|