boson 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
data/lib/boson/util.rb CHANGED
@@ -2,7 +2,7 @@ module Boson
2
2
  # Collection of utility methods used throughout Boson.
3
3
  module Util
4
4
  extend self
5
- # From Rails ActiveSupport, converts a camelcased string to an underscored string:
5
+ # From ActiveSupport, converts a camelcased string to an underscored string:
6
6
  # 'Boson::MethodInspector' -> 'boson/method_inspector'
7
7
  def underscore(camel_cased_word)
8
8
  camel_cased_word.to_s.gsub(/::/, '/').
@@ -12,10 +12,11 @@ module Boson
12
12
  downcase
13
13
  end
14
14
 
15
- # From Rails ActiveSupport, does the reverse of underscore:
15
+ # From ActiveSupport, does the reverse of underscore:
16
16
  # 'boson/method_inspector' -> 'Boson::MethodInspector'
17
17
  def camelize(string)
18
- Hirb::Util.camelize(string)
18
+ string.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.
19
+ gsub(/(?:^|_)(.)/) { $1.upcase }
19
20
  end
20
21
 
21
22
  # Converts a module/class string to the actual constant.
@@ -24,41 +25,43 @@ module Boson
24
25
  any_const_get(camelize(string))
25
26
  end
26
27
 
27
- # Returns a constant like const_get() no matter what namespace it's nested in.
28
- # Returns nil if the constant is not found.
28
+ # Returns a constant like const_get() no matter what namespace it's nested
29
+ # in. Returns nil if the constant is not found.
29
30
  def any_const_get(name)
30
- Hirb::Util.any_const_get(name)
31
+ return name if name.is_a?(Module)
32
+ klass = Object
33
+ name.split('::').each {|e|
34
+ klass = klass.const_get(e)
35
+ }
36
+ klass
37
+ rescue
38
+ nil
31
39
  end
32
40
 
33
- # Detects new object/kernel methods, gems and modules created within a block.
34
- # Returns a hash of what's detected.
35
- # Valid options and possible returned keys are :methods, :object_methods, :modules, :gems.
41
+ # Detects new object/kernel methods, gems and modules created within a
42
+ # block. Returns a hash of what's detected. Valid options and possible
43
+ # returned keys are :methods, :object_methods, :modules, :gems.
36
44
  def detect(options={}, &block)
37
- options = {:methods=>true, :object_methods=>true}.merge!(options)
38
- original_gems = Object.const_defined?(:Gem) ? Gem.loaded_specs.keys : []
45
+ options = {methods: true}.merge!(options)
46
+ original_gems = defined?(Gem) ? Gem.loaded_specs.keys : []
39
47
  original_object_methods = Object.instance_methods
40
- original_instance_methods = class << Boson.main_object; instance_methods end
48
+ original_instance_methods = Boson.main_object.singleton_class.instance_methods
41
49
  original_modules = modules if options[:modules]
50
+
42
51
  block.call
52
+
43
53
  detected = {}
44
- detected[:methods] = options[:methods] ? (class << Boson.main_object; instance_methods end -
45
- original_instance_methods) : []
46
- detected[:methods] -= (Object.instance_methods - original_object_methods) unless options[:object_methods]
47
- detected[:gems] = Gem.loaded_specs.keys - original_gems if Object.const_defined? :Gem
54
+ detected[:methods] = options[:methods] ?
55
+ (Boson.main_object.singleton_class.instance_methods -
56
+ original_instance_methods) : []
57
+ unless options[:object_methods]
58
+ detected[:methods] -= (Object.instance_methods - original_object_methods)
59
+ end
60
+ detected[:gems] = Gem.loaded_specs.keys - original_gems if defined? Gem
48
61
  detected[:modules] = modules - original_modules if options[:modules]
49
62
  detected
50
63
  end
51
64
 
52
- # Safely calls require, returning false if LoadError occurs.
53
- def safe_require(lib)
54
- begin
55
- require lib
56
- true
57
- rescue LoadError
58
- false
59
- end
60
- end
61
-
62
65
  # Returns all modules that currently exist.
63
66
  def modules
64
67
  all_modules = []
@@ -66,51 +69,23 @@ module Boson
66
69
  all_modules
67
70
  end
68
71
 
69
- # Creates a module under a given base module and possible name. If the module already exists or conflicts
70
- # per top_level_class_conflict, it attempts to create one with a number appended to the name.
72
+ # Creates a module under a given base module and possible name. If the
73
+ # module already exists, it attempts to create one with a number appended to
74
+ # the name.
71
75
  def create_module(base_module, name)
72
76
  desired_class = camelize(name)
73
77
  possible_suffixes = [''] + %w{1 2 3 4 5 6 7 8 9 10}
74
- if (suffix = possible_suffixes.find {|e| !base_module.const_defined?(desired_class+e) &&
75
- !top_level_class_conflict(base_module, "#{base_module}::#{desired_class}#{e}") })
76
- base_module.const_set(desired_class+suffix, Module.new)
78
+ if suffix = possible_suffixes.find {|e|
79
+ !base_module.const_defined?(desired_class+e) }
80
+ base_module.const_set(desired_class+suffix, Module.new)
77
81
  end
78
82
  end
79
83
 
80
- # Behaves just like the unix which command, returning the full path to an executable based on ENV['PATH'].
81
- def which(command)
82
- ENV['PATH'].split(File::PATH_SEPARATOR).map {|e| File.join(e, command) }.find {|e| File.exists?(e) }
83
- end
84
-
85
- # Deep copies any object if it can be marshaled. Useful for deep hashes.
86
- def deep_copy(obj)
87
- Marshal::load(Marshal::dump(obj))
88
- end
89
-
90
84
  # Recursively merge hash1 with hash2.
91
85
  def recursive_hash_merge(hash1, hash2)
92
86
  hash1.merge(hash2) {|k,o,n| (o.is_a?(Hash)) ? recursive_hash_merge(o,n) : n}
93
87
  end
94
88
 
95
- # From Rubygems, determine a user's home.
96
- def find_home
97
- Hirb::Util.find_home
98
- end
99
-
100
- # Returns name of top level class that conflicts if it exists. For example, for base module Boson::Commands,
101
- # Boson::Commands::Alias conflicts with Alias if Alias exists.
102
- def top_level_class_conflict(base_module, conflicting_module)
103
- (conflicting_module =~ /^#{base_module}.*::([^:]+)/) && Object.const_defined?($1) && $1
104
- end
105
-
106
- # Splits array into array of arrays with given element
107
- def split_array_by(arr, divider)
108
- arr.inject([[]]) {|results, element|
109
- (divider == element) ? (results << []) : (results.last << element)
110
- results
111
- }
112
- end
113
-
114
89
  # Regular expression search of a list with underscore anchoring of words.
115
90
  # For example 'some_dang_long_word' can be specified as 's_d_l_w'.
116
91
  def underscore_search(input, list, first_match=false)
@@ -118,12 +93,22 @@ module Boson
118
93
  return (first_match ? input : [input]) if list.include?(input)
119
94
  input = input.to_s
120
95
  if input.include?("_")
121
- underscore_regex = input.split('_').map {|e| Regexp.escape(e) }.join("([^_]+)?_")
96
+ underscore_regex = input.split('_').map {|e|
97
+ Regexp.escape(e) }.join("([^_]+)?_")
122
98
  list.send(meth) {|e| e.to_s =~ /^#{underscore_regex}/ }
123
99
  else
124
100
  escaped_input = Regexp.escape(input)
125
101
  list.send(meth) {|e| e.to_s =~ /^#{escaped_input}/ }
126
102
  end
127
103
  end
104
+
105
+ def format_table(arr_of_arr)
106
+ name_max = arr_of_arr.map {|arr| arr[0].length }.max
107
+ desc_max = arr_of_arr.map {|arr| arr[1].length }.max
108
+
109
+ arr_of_arr.map do |name, desc|
110
+ (" %-*s %-*s" % [name_max, name, desc_max, desc]).rstrip
111
+ end
112
+ end
128
113
  end
129
114
  end
data/lib/boson/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Boson
2
- VERSION = '0.4.0'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -1,223 +1,85 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper')
2
- require 'boson/runners/bin_runner'
2
+ require 'boson/bin_runner'
3
3
  BinRunner = Boson::BinRunner
4
4
 
5
5
  describe "BinRunner" do
6
- def start(*args)
7
- Hirb.stubs(:enable)
8
- BinRunner.start(args)
6
+ def aborts_with(regex)
7
+ BinRunner.expects(:abort).with {|e| e[regex] }
8
+ yield
9
9
  end
10
10
 
11
- before {|e|
12
- BinRunner.instance_variables.each {|e| BinRunner.instance_variable_set(e, nil)}
13
- }
14
- describe "at commandline" do
15
- before_all { reset }
11
+ unless ENV['FAST'] ||
12
+ # disable rubinius until Open3.spawn defined in Bahia
13
+ # disable jruby until Open3.spawn works with ENV in Bahia
14
+ RUBY_DESCRIPTION.include?('rubinius') || RUBY_PLATFORM[/java/]
16
15
 
17
- it "no arguments prints usage" do
18
- capture_stdout { start }.should =~ /^boson/
16
+ it "prints usage with no arguments" do
17
+ boson
18
+ stdout.should =~ /^boson/
19
19
  end
20
20
 
21
- it "invalid option value prints error" do
22
- aborts_with(/Error: no value/) { start("-l") }
23
- end
24
-
25
- it "help option but no arguments prints usage" do
26
- capture_stdout { start '-h' }.should =~ /^boson/
27
- end
28
-
29
- it "help option and command prints help" do
30
- capture_stdout { start('-h', 'commands') }.should =~ /^commands/
31
- end
32
-
33
- it "load option loads libraries" do
34
- Manager.expects(:load).with {|*args| args[0][0].is_a?(Module) ? true : args[0][0] == 'blah'}.times(2)
35
- BinRunner.stubs(:execute_command)
36
- start('-l', 'blah', 'libraries')
37
- end
38
-
39
- it "console option starts irb" do
40
- ConsoleRunner.expects(:start)
41
- Util.expects(:which).returns("/usr/bin/irb")
42
- ConsoleRunner.expects(:load_repl).with("/usr/bin/irb")
43
- start("--console")
44
- end
45
-
46
- it "console option but no irb found prints error" do
47
- ConsoleRunner.expects(:start)
48
- Util.expects(:which).returns(nil)
49
- ConsoleRunner.expects(:abort).with {|arg| arg[/Console not found/] }
50
- start '--console'
51
- end
52
-
53
- it "execute option executes string" do
54
- BinRunner.expects(:define_autoloader)
55
- capture_stdout { start("-e", "p 1 + 1") }.should == "2\n"
56
- end
57
-
58
- it "global option takes value with whitespace" do
59
- View.expects(:render).with {|*args| args[1][:fields] = %w{f1 f2} }
60
- start('commands', '-f', 'f1, f2')
61
- end
62
-
63
- it "debug option sets Runner.debug" do
64
- View.expects(:render)
65
- start('-d', 'commands')
66
- Runner.debug.should == true
67
- Runner.debug = nil
68
- end
69
-
70
- it "ruby_debug option sets $DEBUG" do
71
- View.expects(:render)
72
- start('-D', 'commands')
73
- $DEBUG.should == true
74
- $DEBUG = nil
75
- end
76
-
77
- it "execute option errors are caught" do
78
- aborts_with(/^Error:/) { start("-e", "raise 'blah'") }
79
- end
80
-
81
- it "option command and too many arguments prints error" do
82
- capture_stdout {
83
- aborts_with(/'commands'.*incorrect/) { start('commands','1','2','3') }
84
- }
85
- end
86
-
87
- it "normal command and too many arguments prints error" do
88
- capture_stdout {
89
- aborts_with(/'render'.*incorrect/) { start('render') }
90
- }
91
- end
92
-
93
- it "failed subcommand prints error and not command not found" do
94
- BinRunner.expects(:execute_command).raises("bling")
95
- aborts_with(/Error: bling/) { start("commands.to_s") }
96
- end
97
-
98
- it "nonexistant subcommand prints command not found" do
99
- aborts_with(/'to_s.bling' not found/) { start("to_s.bling") }
100
- end
101
-
102
- it "undiscovered command prints error" do
103
- BinRunner.expects(:autoload_command).returns(false)
104
- aborts_with(/Error.*not found/) { start 'blah' }
105
- end
106
-
107
- it "with backtrace option prints backtrace" do
108
- BinRunner.expects(:autoload_command).returns(false)
109
- aborts_with(/not found\nOriginal.*runner\.rb:/m) { start("--backtrace", "blah") }
110
- end
111
-
112
- it "basic command executes" do
113
- BinRunner.expects(:init).returns(true)
114
- BinRunner.stubs(:render_output)
115
- Boson.main_object.expects(:send).with('kick','it')
116
- start 'kick','it'
117
- end
118
-
119
- it "sub command executes" do
120
- obj = Object.new
121
- Boson.main_object.extend Module.new { def phone; Struct.new(:home).new('done'); end }
122
- BinRunner.expects(:init).returns(true)
123
- BinRunner.expects(:render_output).with('done')
124
- start 'phone.home'
125
- end
126
-
127
- it "bin_defaults config loads by default" do
128
- defaults = Runner.default_libraries + ['yo']
129
- with_config(:bin_defaults=>['yo']) do
130
- Manager.expects(:load).with {|*args| args[0] == defaults }
131
- aborts_with(/blah/) { start 'blah' }
21
+ it "prints usage with --help" do
22
+ %w{-h --help}.each do |option|
23
+ boson option
24
+ stdout.should =~ /^boson/
132
25
  end
133
26
  end
134
- end
135
-
136
- describe "autoload_command" do
137
- def index(options={})
138
- Manager.expects(:load).with {|*args| args[0][0].is_a?(Module) ? true : args[0] == options[:load]
139
- }.at_least(1).returns(!options[:fails])
140
- Index.indexes[0].expects(:write)
141
- end
142
-
143
- it "with index option, no existing index and core command updates index and prints index message" do
144
- index :load=>Runner.all_libraries
145
- Index.indexes[0].stubs(:exists?).returns(false)
146
- capture_stdout { start("--index", "libraries") }.should =~ /Generating index/
147
- end
148
27
 
149
- it "with index option, existing index and core command updates incremental index" do
150
- index :load=>['changed']
151
- Index.indexes[0].stubs(:exists?).returns(true)
152
- capture_stdout { start("--index=changed", "libraries")}.should =~ /Indexing.*changed/
28
+ it 'prints version with --version' do
29
+ boson '--version'
30
+ stdout.chomp.should == "boson #{Boson::VERSION}"
153
31
  end
154
32
 
155
- it "with index option, failed indexing prints error" do
156
- index :load=>['changed'], :fails=>true
157
- Index.indexes[0].stubs(:exists?).returns(true)
158
- Manager.stubs(:failed_libraries).returns(['changed'])
159
- capture_stderr {
160
- capture_stdout { start("--index=changed", "libraries")}.should =~ /Indexing.*changed/
161
- }.should =~ /Error:.*failed.*changed/
162
- end
163
-
164
- it "with core command updates index and doesn't print index message" do
165
- Index.indexes[0].expects(:write)
166
- Boson.main_object.expects(:send).with('libraries')
167
- capture_stdout { start 'libraries'}.should.not =~ /index/i
168
- end
169
-
170
- it "with non-core command not finding library, does update index" do
171
- Index.expects(:find_library).returns(nil, 'sweet_lib')
172
- Manager.expects(:load).with {|*args| args[0].is_a?(String) ? args[0] == 'sweet_lib' : true}.at_least(1)
173
- Index.indexes[0].expects(:update).returns(true)
174
- aborts_with(/sweet/) { start 'sweet' }
33
+ it "executes string with --execute" do
34
+ %w{--execute -e}.each do |option|
35
+ boson "#{option} 'print 1 + 1'"
36
+ stdout.should == '2'
37
+ end
175
38
  end
176
- end
177
39
 
178
- describe "render_output" do
179
- before { Scientist.rendered = false; BinRunner.instance_eval "@options = {}" }
180
-
181
- it "doesn't render when nil, false or true" do
182
- View.expects(:render).never
183
- [nil, false, true].each do |e|
184
- BinRunner.render_output e
40
+ it "sets $DEBUG with --ruby-debug" do
41
+ %w{--ruby_debug -D}.each do |option|
42
+ boson "#{option} -e 'print $DEBUG'"
43
+ stdout.should == 'true'
185
44
  end
186
45
  end
187
46
 
188
- it "doesn't render when rendered with Scientist" do
189
- Scientist.rendered = true
190
- View.expects(:render).never
191
- BinRunner.render_output 'blah'
47
+ # TODO: test actual uses of Runner.debug
48
+ it "sets Boson.debug with --debug" do
49
+ boson "--debug -e 'print Boson.debug'"
50
+ stdout.should == 'true'
192
51
  end
193
52
 
194
- it "render with puts when non-string" do
195
- View.expects(:render).with('dude', {:method => 'puts'})
196
- BinRunner.render_output 'dude'
53
+ it "prepends to $: with --load_path" do
54
+ %w{--load_path -I}.each do |option|
55
+ boson "#{option}=lib -e 'print $:[0]'"
56
+ stdout.should == 'lib'
57
+ end
197
58
  end
198
59
 
199
- it "renders with inspect when non-array and non-string" do
200
- [{:a=>true}, :ok].each do |e|
201
- View.expects(:puts).with(e.inspect)
202
- BinRunner.render_output e
203
- end
60
+ it "prints error for unexpected error" do
61
+ boson %[-e 'raise "blarg"']
62
+ stderr.chomp.should == "Error: blarg"
63
+ process.success?.should == false
204
64
  end
205
65
 
206
- it "renders with inspect when Scientist rendering toggled off with :render" do
207
- Scientist.global_options = {:render=>true}
208
- View.expects(:puts).with([1,2].inspect)
209
- BinRunner.render_output [1,2]
210
- Scientist.global_options = nil
66
+ # TODO: enable once bin runner's fate is decided
67
+ xit "prints error for too many arguments" do
68
+ boson "commands 1 2 3"
69
+ stderr.should =~ /^'commands' was called incorrectly/
70
+ process.success?.should == false
211
71
  end
212
72
 
213
- it "renders with hirb when array" do
214
- View.expects(:render_object)
215
- BinRunner.render_output [1,2,3]
73
+ # TODO: possible error with persistance extraction
74
+ xit "prints error for invalid command" do
75
+ boson 'blarg'
76
+ stderr.chomp.should == "Error: Command 'blarg' not found"
77
+ process.success?.should == false
216
78
  end
217
79
  end
218
80
 
219
- it "parse_args only translates options before command" do
220
- BinRunner.parse_args(['-v', 'com', '-v']).should == ["com", {:verbose=>true}, ['-v']]
221
- BinRunner.parse_args(['com', '-v']).should == ["com", {}, ['-v']]
81
+ it ".parse_args only translates options before command" do
82
+ BinRunner.send(:parse_args, ['-d', 'com', '-v']).should == ["com", {debug: true}, ['-v']]
83
+ BinRunner.send(:parse_args, ['com', '-v']).should == ["com", {}, ['-v']]
222
84
  end
223
85
  end