boson 0.2.1 → 0.2.2

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.
@@ -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 a --global option which takes a string of options without their dashes. For example:
27
- # foo '-p --fields=f1,f2 -l=1'
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 ' -g "p fields=f1,f2" -l=1 '
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 = Boson.const_defined?(:BinRunner) ? args : Shellwords.shellwords(args.pop)
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
- global_options = option_parser.parse @command.option_parser.leading_non_opts
128
- new_args = option_parser.non_opts.dup + @command.option_parser.trailing_non_opts
129
- if global_options[:global]
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.each {|k,v|
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 prepend_default_option(args)
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 ArgumentError, "wrong number of arguments (#{args_size} for #{command_size})"
198
+ raise CommandArgumentError, "wrong number of arguments (#{args_size} for #{command_size})"
185
199
  end
186
200
  end
187
201
 
@@ -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 a hash of
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
- (@opt_parser ||= new(options)).parse(args)
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
- # by the :split character. Defaults to first key of :keys if :keys given.
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. Default is false.
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}/ } or (@option_attributes[@current_option][:enum] ?
331
- raise(Error, "invalid value '#{possible_value}' for option '#{@current_option}'") : possible_value)
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
- [@trailing_non_opts].each do |args|
344
- args.delete_if {|e|
345
- invalid = e.to_s[/^-/]
346
- $stderr.puts "Deleted invalid option '#{e}'" if invalid
347
- invalid
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["--#{$1}"] == :boolean) or
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
- (val = auto_alias_value(values, value)) && value = val
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
- array.each {|e| array.delete(e) && array += values if e == '*'}
65
- array.each_with_index {|e,i|
66
- (value = auto_alias_value(values, e)) && array[i] = value
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 ? hash.each {|k,v|
83
- (new_key = auto_alias_value(keys, k)) && hash[new_key] = hash.delete(k)
84
- } : hash
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 description fields.
27
- # bash> boson commands -q=f,d:web # or commands --query=full_name,description:web
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.
@@ -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? ? Marshal.load(File.read(marshal_file)) : [[], [], {}]
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, 'w') {|f| f.write marshal_string }
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
- [Boson::Commands::Core, Boson::Commands::WebCore] + Boson.repos.map {|e| e.config[:defaults] || [] }.flatten
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
- Boson::Index.read
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
- :enum=>false, :desc=>"A comma delimited array of libraries to load"},
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 @options && @options[:verbose]
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
- render_output Boson.full_invoke(@command, @args)
109
- rescue ArgumentError
110
- # for the rare case it's raise outside of boson
111
- raise unless $!.backtrace.first.include?('boson/')
112
- print_error_message "'#{@command}' was called incorrectly."
113
- Boson.invoke(:usage, @command)
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)