boson 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +1 -2
- data/VERSION.yml +3 -2
- data/lib/boson.rb +7 -2
- data/lib/boson/command.rb +72 -27
- data/lib/boson/commands/core.rb +25 -18
- data/lib/boson/commands/web_core.rb +2 -2
- data/lib/boson/index.rb +9 -3
- data/lib/boson/inspector.rb +1 -1
- data/lib/boson/inspectors/argument_inspector.rb +2 -2
- data/lib/boson/inspectors/method_inspector.rb +7 -0
- data/lib/boson/libraries/file_library.rb +5 -9
- data/lib/boson/library.rb +7 -3
- data/lib/boson/namespace.rb +1 -20
- data/lib/boson/option_command.rb +34 -20
- data/lib/boson/option_parser.rb +62 -26
- data/lib/boson/options.rb +18 -8
- data/lib/boson/pipe.rb +2 -2
- data/lib/boson/repo.rb +1 -1
- data/lib/boson/repo_index.rb +6 -5
- data/lib/boson/runner.rb +27 -4
- data/lib/boson/runners/bin_runner.rb +28 -17
- data/lib/boson/scientist.rb +49 -24
- data/lib/boson/view.rb +8 -0
- data/test/argument_inspector_test.rb +4 -0
- data/test/bin_runner_test.rb +2 -2
- data/test/file_library_test.rb +4 -2
- data/test/loader_test.rb +4 -4
- data/test/option_parser_test.rb +29 -2
- data/test/runner_test.rb +1 -1
- data/test/scientist_test.rb +22 -17
- metadata +2 -3
- data/test/config/index.marshal +0 -0
data/lib/boson/option_command.rb
CHANGED
@@ -23,10 +23,11 @@ module Boson
|
|
23
23
|
# Global options: {:pretend=>true}
|
24
24
|
#
|
25
25
|
# If a global option conflicts with a local option, the local option takes precedence. You can get around
|
26
|
-
# this by passing
|
27
|
-
#
|
26
|
+
# this by passing global options after a '-'. For example, if the global option -f (--fields) conflicts with
|
27
|
+
# a local -f (--force):
|
28
|
+
# foo 'arg1 -v -f - -f=f1,f2'
|
28
29
|
# # is the same as
|
29
|
-
# foo ' -
|
30
|
+
# foo 'arg1 -v --fields=f1,f2 -f'
|
30
31
|
#
|
31
32
|
# === Toggling Views With the Basic Global Option --render
|
32
33
|
# One of the more important global options is --render. This option toggles the rendering of a command's
|
@@ -53,12 +54,15 @@ module Boson
|
|
53
54
|
# 3 rows in set
|
54
55
|
# => true
|
55
56
|
class OptionCommand
|
57
|
+
# ArgumentError specific to @command's arguments
|
58
|
+
class CommandArgumentError < ::ArgumentError; end
|
59
|
+
|
56
60
|
BASIC_OPTIONS = {
|
57
61
|
:help=>{:type=>:boolean, :desc=>"Display a command's help"},
|
58
62
|
:render=>{:type=>:boolean, :desc=>"Toggle a command's default rendering behavior"},
|
59
63
|
:verbose=>{:type=>:boolean, :desc=>"Increase verbosity for help, errors, etc."},
|
60
|
-
:global=>{:type=>:string, :desc=>"Pass a string of global options without the dashes"},
|
61
64
|
:pretend=>{:type=>:boolean, :desc=>"Display what a command would execute without executing it"},
|
65
|
+
:delete_options=>{:type=>:array, :desc=>'Deletes global options starting with given strings' }
|
62
66
|
} #:nodoc:
|
63
67
|
|
64
68
|
RENDER_OPTIONS = {
|
@@ -106,9 +110,9 @@ module Boson
|
|
106
110
|
global_opt, parsed_options, args = parse_options Shellwords.shellwords(args[0])
|
107
111
|
# last string argument interpreted as args + options
|
108
112
|
elsif args.size > 1 && args[-1].is_a?(String)
|
109
|
-
temp_args =
|
113
|
+
temp_args = Runner.in_shell? ? args : Shellwords.shellwords(args.pop)
|
110
114
|
global_opt, parsed_options, new_args = parse_options temp_args
|
111
|
-
args += new_args
|
115
|
+
Runner.in_shell? ? args = new_args : args += new_args
|
112
116
|
# add default options
|
113
117
|
elsif @command.options.to_s.empty? || (!@command.has_splat_args? &&
|
114
118
|
args.size <= (@command.arg_size - 1).abs) || (@command.has_splat_args? && !args[-1].is_a?(Hash))
|
@@ -124,14 +128,28 @@ module Boson
|
|
124
128
|
#:stopdoc:
|
125
129
|
def parse_options(args)
|
126
130
|
parsed_options = @command.option_parser.parse(args, :delete_invalid_opts=>true)
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
global_opts = Shellwords.shellwords(global_options[:global]).map {|str|
|
131
|
-
((str[/^(.*?)=/,1] || str).length > 1 ? "--" : "-") + str }
|
132
|
-
global_options.merge! option_parser.parse(global_opts)
|
133
|
-
end
|
131
|
+
trailing, unparseable = split_trailing
|
132
|
+
global_options = parse_global_options @command.option_parser.leading_non_opts + trailing
|
133
|
+
new_args = option_parser.non_opts.dup + unparseable
|
134
134
|
[global_options, parsed_options, new_args]
|
135
|
+
rescue OptionParser::Error
|
136
|
+
global_options = parse_global_options @command.option_parser.leading_non_opts + split_trailing[0]
|
137
|
+
global_options[:help] ? [global_options, nil, []] : raise
|
138
|
+
end
|
139
|
+
|
140
|
+
def split_trailing
|
141
|
+
trailing = @command.option_parser.trailing_non_opts
|
142
|
+
if trailing[0] == '--'
|
143
|
+
trailing.shift
|
144
|
+
[ [], trailing ]
|
145
|
+
else
|
146
|
+
trailing.shift if trailing[0] == '-'
|
147
|
+
[ trailing, [] ]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def parse_global_options(args)
|
152
|
+
option_parser.parse args
|
135
153
|
end
|
136
154
|
|
137
155
|
def option_parser
|
@@ -140,11 +158,7 @@ module Boson
|
|
140
158
|
end
|
141
159
|
|
142
160
|
def all_global_options
|
143
|
-
@command.render_options
|
144
|
-
if !v.is_a?(Hash) && !v.is_a?(Symbol)
|
145
|
-
@command.render_options[k] = {:default=>v}
|
146
|
-
end
|
147
|
-
}
|
161
|
+
OptionParser.make_mergeable! @command.render_options
|
148
162
|
render_opts = Util.recursive_hash_merge(@command.render_options, Util.deep_copy(self.class.default_render_options))
|
149
163
|
merged_opts = Util.recursive_hash_merge Util.deep_copy(self.class.default_pipe_options), render_opts
|
150
164
|
opts = Util.recursive_hash_merge merged_opts, Util.deep_copy(BASIC_OPTIONS)
|
@@ -171,7 +185,7 @@ module Boson
|
|
171
185
|
opts
|
172
186
|
end
|
173
187
|
|
174
|
-
def
|
188
|
+
def modify_args(args)
|
175
189
|
if @command.default_option && @command.arg_size <= 1 && !@command.has_splat_args? && args[0].to_s[/./] != '-'
|
176
190
|
args[0] = "--#{@command.default_option}=#{args[0]}" unless args.join.empty? || args[0].is_a?(Hash)
|
177
191
|
end
|
@@ -181,7 +195,7 @@ module Boson
|
|
181
195
|
if args.size != @command.arg_size && !@command.has_splat_args?
|
182
196
|
command_size, args_size = args.size > @command.arg_size ? [@command.arg_size, args.size] :
|
183
197
|
[@command.arg_size - 1, args.size - 1]
|
184
|
-
raise
|
198
|
+
raise CommandArgumentError, "wrong number of arguments (#{args_size} for #{command_size})"
|
185
199
|
end
|
186
200
|
end
|
187
201
|
|
data/lib/boson/option_parser.rb
CHANGED
@@ -3,7 +3,7 @@ module Boson
|
|
3
3
|
# merging should assume symbolic keys. Used by OptionParser.
|
4
4
|
class IndifferentAccessHash < ::Hash
|
5
5
|
#:stopdoc:
|
6
|
-
def initialize(hash)
|
6
|
+
def initialize(hash={})
|
7
7
|
super()
|
8
8
|
hash.each {|k,v| self[k] = v }
|
9
9
|
end
|
@@ -37,6 +37,7 @@ module Boson
|
|
37
37
|
# * Each option type can have attributes to enable more features (see OptionParser.new).
|
38
38
|
# * When options are parsed by parse(), an IndifferentAccessHash hash is returned.
|
39
39
|
# * Options are also called switches, parameters, flags etc.
|
40
|
+
# * Option parsing stops when it comes across a '--'.
|
40
41
|
#
|
41
42
|
# Default option types:
|
42
43
|
# [*:boolean*] This option has no passed value. To toogle a boolean, prepend with '--no-'.
|
@@ -79,10 +80,12 @@ module Boson
|
|
79
80
|
|
80
81
|
attr_reader :leading_non_opts, :trailing_non_opts, :opt_aliases
|
81
82
|
|
82
|
-
# Given options to pass to OptionParser.new, this method parses ARGV and returns
|
83
|
-
# parsed options. This is useful for scripts outside of Boson.
|
83
|
+
# Given options to pass to OptionParser.new, this method parses ARGV and returns the remaining arguments
|
84
|
+
# and a hash of parsed options. This is useful for scripts outside of Boson.
|
84
85
|
def self.parse(options, args=ARGV)
|
85
|
-
|
86
|
+
@opt_parser ||= new(options)
|
87
|
+
parsed_options = @opt_parser.parse(args)
|
88
|
+
[@opt_parser.non_opts, parsed_options]
|
86
89
|
end
|
87
90
|
|
88
91
|
# Usage string summarizing options defined in parse
|
@@ -90,6 +93,14 @@ module Boson
|
|
90
93
|
@opt_parser.to_s
|
91
94
|
end
|
92
95
|
|
96
|
+
def self.make_mergeable!(opts) #:nodoc:
|
97
|
+
opts.each {|k,v|
|
98
|
+
if !v.is_a?(Hash) && !v.is_a?(Symbol)
|
99
|
+
opts[k] = {:default=>v}
|
100
|
+
end
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
93
104
|
# Array of arguments left after defined options have been parsed out by parse.
|
94
105
|
def non_opts
|
95
106
|
leading_non_opts + trailing_non_opts
|
@@ -145,8 +156,11 @@ module Boson
|
|
145
156
|
# [*:split*] For :array and :hash options. A string or regular expression on which an array value splits
|
146
157
|
# to produce an array of values. Default is ','.
|
147
158
|
# [*:keys*] :hash option only. An array of values a hash option's keys can have. Keys can be aliased just like :values.
|
148
|
-
# [*:default_keys*] :hash option only. Default keys to assume when only a value is given. Multiple keys can be joined
|
149
|
-
#
|
159
|
+
# [*:default_keys*] For :hash option only. Default keys to assume when only a value is given. Multiple keys can be joined
|
160
|
+
# by the :split character. Defaults to first key of :keys if :keys given.
|
161
|
+
# [*:regexp*] For :array option with a :values attribute. Boolean indicating that each option value does a regular
|
162
|
+
# expression search of :values. If there are values that match, they replace the original option value. If none,
|
163
|
+
# then the original option value is used.
|
150
164
|
def initialize(opts)
|
151
165
|
@defaults = {}
|
152
166
|
@opt_aliases = {}
|
@@ -209,7 +223,8 @@ module Boson
|
|
209
223
|
# recognizes a valid option, it continues to parse until an non option argument is detected.
|
210
224
|
# Flags that can be passed to the parser:
|
211
225
|
# * :opts_before_args: When true options must come before arguments. Default is false.
|
212
|
-
# * :delete_invalid_opts: When true deletes any invalid options left after parsing.
|
226
|
+
# * :delete_invalid_opts: When true deletes any invalid options left after parsing. Will stop deleting if
|
227
|
+
# it comes across - or --. Default is false.
|
213
228
|
def parse(args, flags={})
|
214
229
|
@args = args
|
215
230
|
# start with defaults
|
@@ -217,7 +232,7 @@ module Boson
|
|
217
232
|
|
218
233
|
@leading_non_opts = []
|
219
234
|
unless flags[:opts_before_args]
|
220
|
-
@leading_non_opts << shift until current_is_option? || @args.empty?
|
235
|
+
@leading_non_opts << shift until current_is_option? || @args.empty? || peek == '--'
|
221
236
|
end
|
222
237
|
|
223
238
|
while current_is_option?
|
@@ -299,6 +314,29 @@ module Boson
|
|
299
314
|
(str.length > 1 ? "--" : "-") + str
|
300
315
|
end
|
301
316
|
|
317
|
+
# List of option types
|
318
|
+
def types
|
319
|
+
@opt_types.values
|
320
|
+
end
|
321
|
+
|
322
|
+
# List of option names
|
323
|
+
def names
|
324
|
+
@opt_types.keys.map {|e| undasherize e }
|
325
|
+
end
|
326
|
+
|
327
|
+
# List of option aliases
|
328
|
+
def aliases
|
329
|
+
@opt_aliases.keys.map {|e| undasherize e }
|
330
|
+
end
|
331
|
+
|
332
|
+
def option_type(opt)
|
333
|
+
if opt =~ /^--no-(\w+)$/
|
334
|
+
@opt_types[opt] || @opt_types[dasherize($1)] || @opt_types[original_no_opt($1)]
|
335
|
+
else
|
336
|
+
@opt_types[opt]
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
302
340
|
private
|
303
341
|
def determine_option_type(value)
|
304
342
|
return value if value.is_a?(Symbol)
|
@@ -327,8 +365,15 @@ module Boson
|
|
327
365
|
end
|
328
366
|
|
329
367
|
def auto_alias_value(values, possible_value)
|
330
|
-
values.find {|v| v.to_s =~ /^#{possible_value}/ }
|
331
|
-
|
368
|
+
values.find {|v| v.to_s =~ /^#{possible_value}/ } || possible_value
|
369
|
+
end
|
370
|
+
|
371
|
+
def validate_enum_values(values, possible_values)
|
372
|
+
if current_attributes[:enum]
|
373
|
+
Array(possible_values).each {|e|
|
374
|
+
raise(Error, "invalid value '#{e}' for option '#{@current_option}'") if !values.include?(e)
|
375
|
+
}
|
376
|
+
end
|
332
377
|
end
|
333
378
|
|
334
379
|
def validate_option_value(type)
|
@@ -340,13 +385,12 @@ module Boson
|
|
340
385
|
end
|
341
386
|
|
342
387
|
def delete_invalid_opts
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
end
|
388
|
+
@trailing_non_opts.delete_if {|e|
|
389
|
+
break if %w{- --}.include? e
|
390
|
+
invalid = e.to_s[/^-/]
|
391
|
+
$stderr.puts "Deleted invalid option '#{e}'" if invalid
|
392
|
+
invalid
|
393
|
+
}
|
350
394
|
end
|
351
395
|
|
352
396
|
def peek
|
@@ -367,7 +411,7 @@ module Boson
|
|
367
411
|
|
368
412
|
def valid?(arg)
|
369
413
|
if arg.to_s =~ /^--no-(\w+)$/
|
370
|
-
@opt_types.key?(arg) or (@opt_types[
|
414
|
+
@opt_types.key?(arg) or (@opt_types[dasherize($1)] == :boolean) or
|
371
415
|
(@opt_types[original_no_opt($1)] == :boolean)
|
372
416
|
else
|
373
417
|
@opt_types.key?(arg) or @opt_aliases.key?(arg)
|
@@ -387,14 +431,6 @@ module Boson
|
|
387
431
|
@opt_aliases.key?(opt) ? @opt_aliases[opt] : opt
|
388
432
|
end
|
389
433
|
|
390
|
-
def option_type(opt)
|
391
|
-
if opt =~ /^--no-(\w+)$/
|
392
|
-
@opt_types[opt] || @opt_types["--#{$1}"] || @opt_types[original_no_opt($1)]
|
393
|
-
else
|
394
|
-
@opt_types[opt]
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
434
|
def original_no_opt(opt)
|
399
435
|
@opt_aliases[dasherize(opt)]
|
400
436
|
end
|
data/lib/boson/options.rb
CHANGED
@@ -39,7 +39,8 @@ module Boson
|
|
39
39
|
# Parse/create methods
|
40
40
|
def create_string(value)
|
41
41
|
if (values = current_attributes[:values]) && (values = values.sort_by {|e| e.to_s})
|
42
|
-
|
42
|
+
value = auto_alias_value(values, value)
|
43
|
+
validate_enum_values(values, value)
|
43
44
|
end
|
44
45
|
value
|
45
46
|
end
|
@@ -61,10 +62,15 @@ module Boson
|
|
61
62
|
splitter = current_attributes[:split] || ','
|
62
63
|
array = value.split(splitter)
|
63
64
|
if (values = current_attributes[:values]) && (values = values.sort_by {|e| e.to_s })
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
if current_attributes[:regexp]
|
66
|
+
array = array.map {|e|
|
67
|
+
(new_values = values.grep(/#{e}/)).empty? ? e : new_values
|
68
|
+
}.compact.flatten.uniq
|
69
|
+
else
|
70
|
+
array.each {|e| array.delete(e) && array += values if e == '*'}
|
71
|
+
array.map! {|e| auto_alias_value(values, e) }
|
72
|
+
end
|
73
|
+
validate_enum_values(values, array)
|
68
74
|
end
|
69
75
|
array
|
70
76
|
end
|
@@ -79,9 +85,13 @@ module Boson
|
|
79
85
|
aoa = Hash[*value.split(/(?::)([^#{Regexp.quote(splitter)}]+)#{Regexp.quote(splitter)}?/)].to_a
|
80
86
|
aoa.each_with_index {|(k,v),i| aoa[i][0] = keys.join(splitter) if k == '*' } if keys
|
81
87
|
hash = aoa.inject({}) {|t,(k,v)| k.split(splitter).each {|e| t[e] = v }; t }
|
82
|
-
keys
|
83
|
-
|
84
|
-
|
88
|
+
if keys
|
89
|
+
hash = hash.inject({}) {|h,(k,v)|
|
90
|
+
h[auto_alias_value(keys, k)] = v; h
|
91
|
+
}
|
92
|
+
validate_enum_values(keys, hash.keys)
|
93
|
+
end
|
94
|
+
hash
|
85
95
|
end
|
86
96
|
|
87
97
|
# Validation methods
|
data/lib/boson/pipe.rb
CHANGED
@@ -23,8 +23,8 @@ module Boson
|
|
23
23
|
# # Searches commands in the full_name field for 'lib' and sorts results by that field.
|
24
24
|
# bash> boson commands -q=f:lib -s=f # or commands --query=full_name:lib --sort=full_name
|
25
25
|
#
|
26
|
-
# # Multiple fields can be searched if separated by a ','. This searches the full_name and
|
27
|
-
# bash> boson commands -q=f,d:web # or commands --query=full_name,
|
26
|
+
# # Multiple fields can be searched if separated by a ','. This searches the full_name and desc fields.
|
27
|
+
# bash> boson commands -q=f,d:web # or commands --query=full_name,desc:web
|
28
28
|
#
|
29
29
|
# # All fields can be queried using a '*'.
|
30
30
|
# # Searches all library fields and then reverse sorts on name field
|
data/lib/boson/repo.rb
CHANGED
@@ -46,7 +46,7 @@ module Boson
|
|
46
46
|
# Example:
|
47
47
|
# :command_aliases=>{'libraries'=>'lib', 'commands'=>'com'}
|
48
48
|
# [:defaults] Array of libraries to load at start up for commandline and irb. This is useful for extending boson i.e. adding your
|
49
|
-
# own option types. Default is no libraries.
|
49
|
+
# own option types since these are loaded before any other libraries. Default is no libraries.
|
50
50
|
# [:console_defaults] Array of libraries to load at start up when used in irb. Default is to load all library files and libraries
|
51
51
|
# defined in the config.
|
52
52
|
# [:bin_defaults] Array of libraries to load at start up when used from the commandline. Default is no libraries.
|
data/lib/boson/repo_index.rb
CHANGED
@@ -34,7 +34,8 @@ module Boson
|
|
34
34
|
# Reads and initializes index.
|
35
35
|
def read
|
36
36
|
return if @read
|
37
|
-
@libraries, @commands, @lib_hashes = exists? ?
|
37
|
+
@libraries, @commands, @lib_hashes = exists? ?
|
38
|
+
File.open( marshal_file, 'rb' ){|f| Marshal.load( f.read ) } : [[], [], {}]
|
38
39
|
delete_stale_libraries_and_commands
|
39
40
|
set_command_namespaces
|
40
41
|
@read = true
|
@@ -62,7 +63,7 @@ module Boson
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def save_marshal_index(marshal_string)
|
65
|
-
File.open(marshal_file, '
|
66
|
+
File.open(marshal_file, 'wb') {|f| f.write marshal_string }
|
66
67
|
end
|
67
68
|
|
68
69
|
def delete_stale_libraries_and_commands
|
@@ -96,13 +97,13 @@ module Boson
|
|
96
97
|
File.join(repo.config_dir, 'index.marshal')
|
97
98
|
end
|
98
99
|
|
99
|
-
def find_library(command)
|
100
|
+
def find_library(command, object=false)
|
100
101
|
read
|
101
102
|
namespace_command = command.split('.')[0]
|
102
103
|
if (lib = @libraries.find {|e| e.namespace == namespace_command })
|
103
|
-
lib.name
|
104
|
+
object ? lib : lib.name
|
104
105
|
elsif (cmd = Command.find(command, @commands))
|
105
|
-
cmd.lib
|
106
|
+
object ? @libraries.find {|e| e.name == cmd.lib} : cmd.lib
|
106
107
|
end
|
107
108
|
end
|
108
109
|
|
data/lib/boson/runner.rb
CHANGED
@@ -11,7 +11,7 @@ module Boson
|
|
11
11
|
|
12
12
|
# Libraries that come with Boson
|
13
13
|
def default_libraries
|
14
|
-
|
14
|
+
Boson.repos.map {|e| e.config[:defaults] || [] }.flatten + [Boson::Commands::Core, Boson::Commands::WebCore]
|
15
15
|
end
|
16
16
|
|
17
17
|
# Libraries detected in repositories
|
@@ -24,7 +24,26 @@ module Boson
|
|
24
24
|
Boson.repos.map {|e| e.all_libraries }.flatten.uniq
|
25
25
|
end
|
26
26
|
|
27
|
+
# Returns true if commands are being executed from a non-ruby shell i.e. bash. Returns false if
|
28
|
+
# in a ruby shell i.e. irb.
|
29
|
+
def in_shell?
|
30
|
+
!!@in_shell
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns true if in commandline with verbose flag or if set explicitly. Useful in plugins.
|
34
|
+
def verbose?
|
35
|
+
@verbose.nil? ? Boson.const_defined?(:BinRunner) && BinRunner.options[:verbose] : @verbose
|
36
|
+
end
|
37
|
+
|
27
38
|
#:stopdoc:
|
39
|
+
def verbose=(val)
|
40
|
+
@verbose = val
|
41
|
+
end
|
42
|
+
|
43
|
+
def in_shell=(val)
|
44
|
+
@in_shell = val
|
45
|
+
end
|
46
|
+
|
28
47
|
def add_load_path
|
29
48
|
Boson.repos.each {|repo|
|
30
49
|
if repo.config[:add_load_path] || File.exists?(File.join(repo.dir, 'lib'))
|
@@ -37,12 +56,16 @@ module Boson
|
|
37
56
|
{:verbose=>@options[:verbose]}
|
38
57
|
end
|
39
58
|
|
59
|
+
def autoload_command(cmd)
|
60
|
+
Index.read
|
61
|
+
(lib = Index.find_library(cmd)) && Manager.load(lib, :verbose=>verbose?)
|
62
|
+
lib
|
63
|
+
end
|
64
|
+
|
40
65
|
def define_autoloader
|
41
66
|
class << ::Boson.main_object
|
42
67
|
def method_missing(method, *args, &block)
|
43
|
-
|
44
|
-
if lib = Boson::Index.find_library(method.to_s)
|
45
|
-
Boson::Manager.load lib, :verbose=>true
|
68
|
+
if Runner.autoload_command(method.to_s)
|
46
69
|
send(method, *args, &block) if respond_to?(method)
|
47
70
|
else
|
48
71
|
super
|
@@ -32,25 +32,24 @@ module Boson
|
|
32
32
|
# * Any of these cases can be toggled to render/not render with the global option :render
|
33
33
|
# To turn off auto-rendering by default, add a :no_auto_render: true entry to the main config.
|
34
34
|
class BinRunner < Runner
|
35
|
-
def self.all_libraries #:nodoc:
|
36
|
-
@all_libraries ||= ((libs = super) + libs.map {|e| File.basename(e) }).uniq
|
37
|
-
end
|
38
|
-
|
39
35
|
GLOBAL_OPTIONS = {
|
40
|
-
:verbose=>{:type=>:boolean, :desc=>"Verbose description of loading libraries or help"},
|
36
|
+
:verbose=>{:type=>:boolean, :desc=>"Verbose description of loading libraries, errors or help"},
|
41
37
|
:index=>{:type=>:array, :desc=>"Libraries to index. Libraries must be passed with '='.",
|
42
|
-
:bool_default=>nil, :values=>all_libraries, :enum=>false},
|
38
|
+
:bool_default=>nil, :values=>all_libraries, :regexp=>true, :enum=>false},
|
43
39
|
:execute=>{:type=>:string, :desc=>"Executes given arguments as a one line script"},
|
44
40
|
:console=>{:type=>:boolean, :desc=>"Drops into irb with default and explicit libraries loaded"},
|
45
41
|
:help=>{:type=>:boolean, :desc=>"Displays this help message or a command's help if given a command"},
|
46
|
-
:load=>{:type=>:array, :values=>all_libraries,
|
47
|
-
:
|
42
|
+
:load=>{:type=>:array, :values=>all_libraries, :regexp=>true, :enum=>false,
|
43
|
+
:desc=>"A comma delimited array of libraries to load"},
|
44
|
+
:unload=>{:type=>:string, :desc=>"Acts as a regular expression to unload default libraries"},
|
48
45
|
:render=>{:type=>:boolean, :desc=>"Renders a Hirb view from result of command without options"},
|
49
|
-
:pager_toggle=>{:type=>:boolean, :desc=>"Toggles Hirb's pager"}
|
46
|
+
:pager_toggle=>{:type=>:boolean, :desc=>"Toggles Hirb's pager"},
|
47
|
+
:option_commands=>{:type=>:boolean, :desc=>"Toggles on all commands to be defined as option commands" }
|
50
48
|
} #:nodoc:
|
51
49
|
|
52
50
|
class <<self
|
53
51
|
attr_accessor :command
|
52
|
+
|
54
53
|
# Starts, processes and ends a commandline request.
|
55
54
|
def start(args=ARGV)
|
56
55
|
@command, @options, @args = parse_args(args)
|
@@ -75,6 +74,8 @@ module Boson
|
|
75
74
|
|
76
75
|
# Loads the given command.
|
77
76
|
def init
|
77
|
+
Runner.in_shell = true
|
78
|
+
Command.all_option_commands = true if @options[:option_commands]
|
78
79
|
super
|
79
80
|
Index.update(:verbose=>true, :libraries=>@options[:index]) if @options.key?(:index)
|
80
81
|
if @options[:load]
|
@@ -86,9 +87,14 @@ module Boson
|
|
86
87
|
end
|
87
88
|
end
|
88
89
|
|
90
|
+
# Hash of global options passed in from commandline
|
91
|
+
def options
|
92
|
+
@options ||= {}
|
93
|
+
end
|
94
|
+
|
89
95
|
#:stopdoc:
|
90
96
|
def print_error_message(message)
|
91
|
-
message += "\nOriginal error: #{$!}\n" + $!.backtrace.slice(0,10).map {|e| " " + e }.join("\n") if
|
97
|
+
message += "\nOriginal error: #{$!}\n" + $!.backtrace.slice(0,10).map {|e| " " + e }.join("\n") if options[:verbose]
|
92
98
|
$stderr.puts message
|
93
99
|
end
|
94
100
|
|
@@ -101,16 +107,21 @@ module Boson
|
|
101
107
|
end
|
102
108
|
|
103
109
|
def default_libraries
|
104
|
-
super + Boson.repos.map {|e| e.config[:bin_defaults] || [] }.flatten + Dir.glob('Bosonfile')
|
110
|
+
libs = super + Boson.repos.map {|e| e.config[:bin_defaults] || [] }.flatten + Dir.glob('Bosonfile')
|
111
|
+
@options[:unload] ? libs.select {|e| e !~ /#{@options[:unload]}/} : libs
|
105
112
|
end
|
106
113
|
|
107
114
|
def execute_command
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
115
|
+
begin
|
116
|
+
output = Boson.full_invoke(@command, @args)
|
117
|
+
rescue ArgumentError
|
118
|
+
# for the rare case it's raised outside of boson
|
119
|
+
raise unless $!.backtrace.first.include?('boson/')
|
120
|
+
print_error_message "'#{@command}' was called incorrectly."
|
121
|
+
Boson.invoke(:usage, @command)
|
122
|
+
return
|
123
|
+
end
|
124
|
+
render_output output
|
114
125
|
end
|
115
126
|
|
116
127
|
def parse_args(args)
|