boson 0.4.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
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
|
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
|
15
|
+
# From ActiveSupport, does the reverse of underscore:
|
16
16
|
# 'boson/method_inspector' -> 'Boson::MethodInspector'
|
17
17
|
def camelize(string)
|
18
|
-
|
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
|
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
|
-
|
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
|
34
|
-
# Returns a hash of what's detected.
|
35
|
-
#
|
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 = {:
|
38
|
-
original_gems =
|
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 =
|
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] ?
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
70
|
-
#
|
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
|
75
|
-
!
|
76
|
-
|
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|
|
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
data/test/bin_runner_test.rb
CHANGED
@@ -1,223 +1,85 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
-
require 'boson/
|
2
|
+
require 'boson/bin_runner'
|
3
3
|
BinRunner = Boson::BinRunner
|
4
4
|
|
5
5
|
describe "BinRunner" do
|
6
|
-
def
|
7
|
-
|
8
|
-
|
6
|
+
def aborts_with(regex)
|
7
|
+
BinRunner.expects(:abort).with {|e| e[regex] }
|
8
|
+
yield
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
18
|
-
|
16
|
+
it "prints usage with no arguments" do
|
17
|
+
boson
|
18
|
+
stdout.should =~ /^boson/
|
19
19
|
end
|
20
20
|
|
21
|
-
it "
|
22
|
-
|
23
|
-
|
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
|
150
|
-
|
151
|
-
|
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 "
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
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
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
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 "
|
195
|
-
|
196
|
-
|
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 "
|
200
|
-
[
|
201
|
-
|
202
|
-
|
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
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
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
|
-
|
214
|
-
|
215
|
-
|
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
|
221
|
-
BinRunner.parse_args
|
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
|