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
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
|