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.
Files changed (64) hide show
  1. data/.gemspec +6 -7
  2. data/.rspec +2 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG.rdoc +1 -1
  5. data/README.md +144 -0
  6. data/README.rdoc +2 -2
  7. data/Upgrading.md +23 -0
  8. data/bin/boson +2 -2
  9. data/lib/boson.rb +44 -52
  10. data/lib/boson/bare_runner.rb +83 -0
  11. data/lib/boson/bin_runner.rb +114 -0
  12. data/lib/boson/command.rb +92 -132
  13. data/lib/boson/inspector.rb +49 -48
  14. data/lib/boson/library.rb +71 -120
  15. data/lib/boson/loader.rb +73 -84
  16. data/lib/boson/manager.rb +131 -135
  17. data/lib/boson/method_inspector.rb +112 -0
  18. data/lib/boson/option_command.rb +71 -154
  19. data/lib/boson/option_parser.rb +178 -173
  20. data/lib/boson/options.rb +46 -32
  21. data/lib/boson/runner.rb +58 -66
  22. data/lib/boson/runner_library.rb +31 -0
  23. data/lib/boson/scientist.rb +48 -81
  24. data/lib/boson/util.rb +46 -61
  25. data/lib/boson/version.rb +1 -1
  26. data/test/bin_runner_test.rb +53 -191
  27. data/test/command_test.rb +5 -9
  28. data/test/deps.rip +2 -2
  29. data/test/loader_test.rb +18 -216
  30. data/test/manager_test.rb +69 -79
  31. data/test/method_inspector_test.rb +12 -36
  32. data/test/option_parser_test.rb +45 -32
  33. data/test/runner_library_test.rb +10 -0
  34. data/test/runner_test.rb +158 -28
  35. data/test/scientist_test.rb +9 -147
  36. data/test/test_helper.rb +87 -52
  37. metadata +30 -72
  38. data/deps.rip +0 -2
  39. data/lib/boson/commands.rb +0 -7
  40. data/lib/boson/commands/core.rb +0 -77
  41. data/lib/boson/commands/web_core.rb +0 -153
  42. data/lib/boson/index.rb +0 -48
  43. data/lib/boson/inspectors/argument_inspector.rb +0 -97
  44. data/lib/boson/inspectors/comment_inspector.rb +0 -100
  45. data/lib/boson/inspectors/method_inspector.rb +0 -98
  46. data/lib/boson/libraries/file_library.rb +0 -144
  47. data/lib/boson/libraries/gem_library.rb +0 -30
  48. data/lib/boson/libraries/local_file_library.rb +0 -30
  49. data/lib/boson/libraries/module_library.rb +0 -37
  50. data/lib/boson/libraries/require_library.rb +0 -23
  51. data/lib/boson/namespace.rb +0 -31
  52. data/lib/boson/pipe.rb +0 -147
  53. data/lib/boson/pipes.rb +0 -75
  54. data/lib/boson/repo.rb +0 -107
  55. data/lib/boson/runners/bin_runner.rb +0 -208
  56. data/lib/boson/runners/console_runner.rb +0 -58
  57. data/lib/boson/view.rb +0 -95
  58. data/test/argument_inspector_test.rb +0 -62
  59. data/test/commands_test.rb +0 -22
  60. data/test/comment_inspector_test.rb +0 -126
  61. data/test/file_library_test.rb +0 -42
  62. data/test/pipes_test.rb +0 -65
  63. data/test/repo_index_test.rb +0 -122
  64. 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
- MethodInspector.current_module = Blah
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
- MethodInspector.store[:desc].empty?.should == true
11
- MethodInspector.store[:options].empty?.should == true
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
- MethodInspector.store.should == nil
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
- MethodInspector.store
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
@@ -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 "IndifferentAccessHash" do
15
+ describe "#indifferent_hash" do
16
16
  before {
17
- @hash = IndifferentAccessHash.new 'foo' => 'bar', 'baz' => 'bee'
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 "can set values indifferently" do
35
- @hash['foo'] = 'duh'
36
- @hash[:foo].should == 'duh'
37
- @hash[:baz] = 'wasp'
38
- @hash['baz'].should == 'wasp'
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
- it ":delete_invalid_opts deletes until - or --" do
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
@@ -0,0 +1,10 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "RunnerLibrary" do
4
+ before { reset }
5
+
6
+ it "creates a library with correct commands" do
7
+ Manager.load create_runner(:blah)
8
+ library('blarg').commands.should == ['blah']
9
+ end
10
+ end
data/test/runner_test.rb CHANGED
@@ -1,40 +1,170 @@
1
- require File.join(File.dirname(__FILE__), 'test_helper')
1
+ require File.dirname(__FILE__) + '/test_helper'
2
2
 
3
- describe "repl_runner" do
4
- def start(hash={})
5
- Hirb.stubs(:enable)
6
- Boson.start(hash.merge(:verbose=>false))
3
+ class MyRunner < Boson::Runner
4
+ desc "This is a small"
5
+ def small(*args)
6
+ p args
7
7
  end
8
8
 
9
- before_all { reset }
10
- before { ConsoleRunner.instance_eval("@initialized = false") }
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
- it "loads default libraries and libraries in :console_defaults config" do
13
- defaults = Runner.default_libraries + ['yo']
14
- with_config(:console_defaults=>['yo']) do
15
- Manager.expects(:load).with {|*args| args[0] == defaults }
16
- start
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
- it "doesn't call init twice" do
21
- capture_stderr { start }
22
- ConsoleRunner.expects(:init).never
23
- start
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 "loads multiple libraries with :libraries option" do
27
- ConsoleRunner.expects(:init)
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 "autoloader autoloads libraries" do
33
- start(:autoload_libraries=>true)
34
- Index.expects(:read)
35
- Index.expects(:find_library).with('blah').returns('blah')
36
- Manager.expects(:load).with('blah', anything)
37
- Boson.main_object.blah
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
- after_all { FileUtils.rm_r File.dirname(__FILE__)+'/config', :force=>true }
40
- end
170
+ end