boson 0.0.1 → 0.1.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.
@@ -1,5 +1,5 @@
1
1
  module Boson
2
- # A library which takes a module as a library's name. Reload for this library
2
+ # This library takes a module as a library's name. Reload for this library
3
3
  # subclass is disabled.
4
4
  class ModuleLibrary < Library
5
5
  #:stopdoc:
@@ -24,9 +24,31 @@ module Boson
24
24
  attr_reader :except, :no_alias_creation, :new_module, :new_commands
25
25
  # Optional namespace name for a library. When enabled defaults to a library's name.
26
26
  attr_writer :namespace
27
+
27
28
  # Creates a library object with a hash of attributes which must include a :name attribute.
28
29
  # Each hash pair maps directly to an instance variable and value. Defaults for attributes
29
- # are read from config[:libraries][@library_name]. See Boson::Repo.config for more details.
30
+ # are read from config[:libraries][@library_name][@attribute].
31
+ #
32
+ # Attributes that can be configured:
33
+ # * *:dependencies*: An array of libraries that this library depends on. A library won't load
34
+ # unless its dependencies are loaded first.
35
+ # * *:commands*: A hash or array of commands that belong to this library. A hash configures command attributes
36
+ # for the given commands with command names pointing to their configs. See Command.new for a
37
+ # command's configurable attributes. If an array, the commands are set for the given library,
38
+ # overidding default command detection.
39
+ # Example:
40
+ # :commands=>{'commands'=>{:description=>'Lists commands', :alias=>'com'}}
41
+ # * *:class_commands*: A hash of commands to create. Hash should map command names to any string of ruby code
42
+ # that ends with a method call.
43
+ # Example:
44
+ # :class_commands=>{'spy'=>'Bond.spy', 'create'=>'Alias.manager.create'}
45
+ # * *:force*: Boolean which forces a library to ignore when a library's methods are overriding existing ones.
46
+ # Use with caution. Default is false.
47
+ # * *:object_methods*: Boolean which detects any Object/Kernel methods created when loading a library and automatically
48
+ # adds them to a library's commands. Default is true.
49
+ # * *:namespace*: Boolean or string which namespaces a library. When true, the library is automatically namespaced
50
+ # to the library's name. When a string, the library is namespaced to the string. Default is nil. To control the
51
+ # namespacing of all libraries see Boson::Repo.config.
30
52
  def initialize(hash)
31
53
  @name = set_name hash.delete(:name)
32
54
  @loaded = false
@@ -35,7 +57,6 @@ module Boson
35
57
  @commands_hash = {}
36
58
  @commands = []
37
59
  set_config (repo.config[:libraries][@name] || {}).merge(hash)
38
- @commands_hash = repo.config[:commands].merge @commands_hash
39
60
  set_command_aliases(repo.config[:command_aliases])
40
61
  @namespace = true if Boson.repo.config[:auto_namespace] && @namespace.nil? &&
41
62
  !Boson::Runner.default_libraries.include?(@module)
@@ -4,7 +4,7 @@ module Boson
4
4
 
5
5
  # This module is mixed into Library to give it load() and reload() functionality.
6
6
  # When creating your own Library subclass, you should override load_source_and_set_module and
7
- # reload_source_and_set_module. You can override other methods in this module as needed.
7
+ # reload_source_and_set_module . You can override other methods in this module as needed.
8
8
  module Loader
9
9
  # Loads a library and its dependencies and returns true if library loads correctly.
10
10
  def load
@@ -64,7 +64,7 @@ module Boson
64
64
  options[:object_methods] = @object_methods if !@object_methods.nil?
65
65
  detected = Util.detect(options, &block)
66
66
  @gems += detected[:gems] if detected[:gems]
67
- @commands += detected[:methods]
67
+ @commands += detected[:methods].map {|e| e.to_s }
68
68
  detected
69
69
  end
70
70
 
@@ -4,6 +4,7 @@ module Boson
4
4
  # Raised when a library's append_features returns false.
5
5
  class AppendFeaturesFalseError < StandardError; end
6
6
 
7
+ # Handles loading and reloading of libraries and commands.
7
8
  class Manager
8
9
  class <<self
9
10
  # Loads a library or an array of libraries with options. Manager loads the first library subclass
@@ -62,7 +63,7 @@ module Boson
62
63
  rescue Exception=>e
63
64
  FileLibrary.reset_file_cache(library.to_s)
64
65
  print_error_message "Unable to #{load_method} library #{library}. Reason: #{$!}" + "\n" +
65
- e.backtrace.slice(0,3).join("\n")
66
+ e.backtrace.slice(0,3).map {|e| " " + e }.join("\n")
66
67
  ensure
67
68
  Inspector.disable if Inspector.enabled
68
69
  end
@@ -103,7 +104,7 @@ module Boson
103
104
 
104
105
  def loader_create(source)
105
106
  lib_class = Library.handle_blocks.find {|k,v| v.call(source) } or raise(LoaderError, "Library #{source} not found.")
106
- lib_class[0].new(:name=>source, :index=>@options[:index])
107
+ lib_class[0].new(@options.merge(:name=>source))
107
108
  end
108
109
 
109
110
  def after_load
@@ -1,25 +1,29 @@
1
1
  module Boson
2
+ # Used in all things namespace.
2
3
  class Namespace
3
- def self.create_object_namespace(name, library)
4
- obj = library.namespace_object
5
- obj.instance_eval("class<<self;self;end").send(:define_method, :boson_commands) {
6
- self.class.instance_methods(false) }
7
- obj.instance_eval("class<<self;self;end").send(:define_method, :object_delegate?) { true }
8
- namespaces[name.to_s] = obj
9
- end
10
-
4
+ # Hash of created namespace names to namespace objects
11
5
  def self.namespaces
12
6
  @namespaces ||= {}
13
7
  end
14
8
 
9
+ # Creates a namespace given its name and the library it belongs to.
15
10
  def self.create(name, library)
16
- if library.object_namespace && library.module.instance_methods.include?(name)
11
+ if library.object_namespace && library.module.instance_methods.map {|e| e.to_s}.include?(name)
17
12
  library.include_in_universe
18
13
  create_object_namespace(name, library)
19
14
  else
20
15
  create_basic_namespace(name, library)
21
16
  end
22
17
  end
18
+ #:stopdoc:
19
+
20
+ def self.create_object_namespace(name, library)
21
+ obj = library.namespace_object
22
+ obj.instance_eval("class<<self;self;end").send(:define_method, :boson_commands) {
23
+ self.class.instance_methods(false) }
24
+ obj.instance_eval("class<<self;self;end").send(:define_method, :object_delegate?) { true }
25
+ namespaces[name.to_s] = obj
26
+ end
23
27
 
24
28
  def self.create_basic_namespace(name, library)
25
29
  namespaces[name.to_s] = new(name, library)
@@ -32,14 +36,15 @@ module Boson
32
36
  class <<self; self end.send :include, @library.module
33
37
  end
34
38
 
35
- def boson_commands
36
- @library.module.instance_methods
37
- end
38
-
39
39
  def object_delegate?; false; end
40
40
 
41
41
  def method_missing(method, *args, &block)
42
42
  Boson.can_invoke?(method) ? Boson.invoke(method, *args, &block) : super
43
43
  end
44
+ #:startdoc:
45
+ # List of subcommands for the namespace.
46
+ def boson_commands
47
+ @library.module.instance_methods.map {|e| e.to_s }
48
+ end
44
49
  end
45
50
  end
@@ -1,9 +1,9 @@
1
1
  module Boson
2
- # Simple Hash with indifferent access
3
- class IndifferentAccessHash < ::Hash
2
+ # Simple Hash with indifferent access. Used by OptionParser.
3
+ class IndifferentAccessHash < ::Hash #:nodoc:
4
4
  def initialize(hash)
5
5
  super()
6
- update hash.each {|k,v| hash[convert_key(k)] = hash.delete(k) }
6
+ hash.each {|k,v| self[k] = v }
7
7
  end
8
8
 
9
9
  def [](key)
@@ -24,9 +24,21 @@ module Boson
24
24
  end
25
25
  end
26
26
 
27
+ # This class provides option parsing for boolean, string, numeric and array
28
+ # values given a simple hash of options. Setting option values should be straightforward for
29
+ # *nix people. By option type:
30
+ # * *:boolean*: These don't have values i.e. '--debug'. To toogle a boolean, prepend with --no- i.e. '--no-debug'.
31
+ # Multiple booleans can be joined together i.e. '-d -f -t' == '-dft'.
32
+ # * *:string*: Separate name from value with space or '=' i.e. '--color red' or '--color=red'.
33
+ # * *:numeric*: Receives values as :string does or by appending number right after name i.e.
34
+ # '-N3' == '-N=3'.
35
+ # * *:array*: Receives values as :string does. Multiple values are split by ',' i.e.
36
+ # '--fields 1,2,3' -> ['1','2','3']. The split character can be configured as explained at
37
+ # OptionParser.new .
27
38
  # This is a modified version of Yehuda Katz's Thor::Options class which is a modified version
28
- # of Daniel Berger's Getopt::Long class, licensed under Ruby's license.
39
+ # of Daniel Berger's Getopt::Long class (licensed under Ruby's license).
29
40
  class OptionParser
41
+ # Raised for all OptionParser errors
30
42
  class Error < StandardError; end
31
43
 
32
44
  NUMERIC = /(\d*\.\d+|\d+)/
@@ -37,28 +49,54 @@ module Boson
37
49
  SHORT_NUM = /^(-[a-zA-Z])#{NUMERIC}$/i
38
50
 
39
51
  attr_reader :leading_non_opts, :trailing_non_opts, :opt_aliases
40
-
52
+
53
+ # Array of arguments left after defined options have been parsed out by parse.
41
54
  def non_opts
42
55
  leading_non_opts + trailing_non_opts
43
56
  end
44
57
 
45
- # Takes an array of options. Each array consists of up to three
46
- # elements that indicate the name and type of option. Returns a hash
47
- # containing each option name, minus the '-', as a key. The value
48
- # for each key depends on the type of option and/or the value provided
49
- # by the user.
58
+ # Takes a hash of options. Each option, a key-value pair, must provide the option's
59
+ # name and type. Names longer than one character are accessed with '--' while
60
+ # one character names are accessed with '-'. Names can be symbols, strings
61
+ # or even dasherized strings:
62
+ #
63
+ # Boson::OptionParser.new :debug=>:boolean, 'level'=>:numeric,
64
+ # '--fields'=>:array
65
+ #
66
+ # Options can have default values and implicit types simply by changing the
67
+ # option type for the default value:
68
+ #
69
+ # Boson::OptionParser.new :debug=>true, 'level'=>3.1, :fields=>%w{f1 f2}
70
+ #
71
+ # By default every option name longer than one character is given an alias,
72
+ # the first character from its name. For example, the --fields option
73
+ # has -f as its alias. You can override the default alias by providing your own
74
+ # option aliases as an array in the option's key.
75
+ #
76
+ # Boson::OptionParser.new [:debug, :damnit, :D]=>true
77
+ #
78
+ # Note that aliases are accessed the same way as option names. For the above,
79
+ # --debug, --damnit and -D all refer to the same option.
50
80
  #
51
- # The long option _must_ be provided. The short option defaults to the
52
- # first letter of the option. The default type is :boolean.
81
+ # Options can have additional attributes by passing a hash to the option value instead of
82
+ # a type or default:
83
+ #
84
+ # Boson::OptionParser.new :fields=>{:type=>:array, :values=>%w{f1 f2 f3},
85
+ # :enum=>false}
53
86
  #
54
- # Example:
87
+ # Here are the available option attributes:
55
88
  #
56
- # opts = Boson::OptionParser.new(
57
- # "--debug" => true,
58
- # ["--verbose", "-v"] => true,
59
- # ["--level", "-l"] => :numeric
60
- # ).parse(args)
89
+ # * *:type*: This or :default is required. Available types are :string, :boolean, :array, :numeric.
90
+ # * *:default*: This or :type is required. This is the default value an option has when not passed.
91
+ # * *:values*: An array of values an option can have. Available for :array and :string options. Values here
92
+ # can be aliased by typing a unique string it starts with. For example:
93
+ #
94
+ # For values foo, odd, optional: f refers to foo, o to odd and op to optional.
61
95
  #
96
+ # * *:enum*: Boolean indicating if an option enforces values in :values. Default is true. Available for
97
+ # :array and :string options.
98
+ # * *:split*: Only for :array options. A string or regular expression on which an array value splits
99
+ # to produce an array of values. Default is ','.
62
100
  def initialize(opts)
63
101
  @defaults = {}
64
102
  @opt_aliases = {}
@@ -114,6 +152,11 @@ module Boson
114
152
  }
115
153
  end
116
154
 
155
+ # Parses an array of arguments for defined options to return a hash. Once the parser
156
+ # recognizes a valid option, it continues to parse until an non option argument is detected.
157
+ # Flags that can be passed to the parser:
158
+ # * :opts_before_args: When true options must come before arguments. Default is false.
159
+ # * :delete_invalid_opts: When true deletes any invalid options left after parsing. Default is false.
117
160
  def parse(args, flags={})
118
161
  @args = args
119
162
  # start with defaults
@@ -151,6 +194,7 @@ module Boson
151
194
  hash
152
195
  end
153
196
 
197
+ # One-line option usage
154
198
  def formatted_usage
155
199
  return "" if @opt_types.empty?
156
200
  @opt_types.map do |opt, type|
@@ -173,6 +217,7 @@ module Boson
173
217
 
174
218
  alias :to_s :formatted_usage
175
219
 
220
+ # More verbose option help in the form of a table.
176
221
  def print_usage_table(render_options={})
177
222
  aliases = @opt_aliases.invert
178
223
  additional = [:desc, :values].select {|e| (@option_attributes || {}).values.any? {|f| f.key?(e) } }
@@ -1,35 +1,54 @@
1
1
  %w{yaml fileutils}.each {|e| require e }
2
2
  module Boson
3
+ # A class for repositories. A repository has a root directory with required subdirectories config/ and
4
+ # commands/ and optional subdirectory lib/. Each repository has a primary config file at config/boson.yml.
3
5
  class Repo
4
- def self.commands_dir(dir)
6
+ def self.commands_dir(dir) #:nodoc:
5
7
  File.join(dir, 'commands')
6
8
  end
7
9
 
8
10
  attr_accessor :dir, :config
11
+ # Creates a repository given a root directory.
9
12
  def initialize(dir)
10
13
  @dir = dir
11
14
  end
12
15
 
16
+ # Points to the config/ subdirectory and is automatically created when called. Used for config files.
13
17
  def config_dir
14
- @config_dir ||= FileUtils.mkdir_p File.join(dir, 'config')
18
+ @config_dir ||= FileUtils.mkdir_p("#{dir}/config") && "#{dir}/config"
15
19
  end
16
20
 
21
+ # Points to the commands/ subdirectory and is automatically created when called. Used for command libraries.
17
22
  def commands_dir
18
- @commands_dir ||= FileUtils.mkdir_p self.class.commands_dir(@dir)
23
+ @commands_dir ||= (cdir = self.class.commands_dir(@dir)) && FileUtils.mkdir_p(cdir) && cdir
19
24
  end
20
25
 
26
+ # A hash read from the YAML config file at config/boson.yml.
27
+ # {See here}[http://github.com/cldwalker/irbfiles/blob/master/boson/config/boson.yml] for an example config file.
21
28
  # ==== Valid config keys:
22
- # [:libraries] Hash of libraries mapping their name to attribute hashes.
23
- # [:commands] Hash of commands mapping their name to attribute hashes.
24
- # [:defaults] Array of libraries to load at start up.
25
- # [:add_load_path] Boolean specifying whether to add a load path pointing to the lib under boson's directory. Defaults to false if
26
- # the lib directory isn't defined in the boson directory. Default is false.
27
- # [:error_method_conflicts] Boolean specifying library loading behavior when one of its methods conflicts with existing methods in
29
+ # [:libraries] Hash of libraries mapping their name to attribute hashes. See Library.new for configurable attributes.
30
+ # Example:
31
+ # :libraries=>{'completion'=>{:namespace=>true}}
32
+ # [:command_aliases] Hash of commands names and their aliases. Since this is global it will be read by _all_ libraries.
33
+ # This is useful for quickly creating aliases without having to worry about placing them under
34
+ # the correct library config. For non-global aliasing, aliases should be placed under the :command_aliases
35
+ # key of a library entry in :libraries.
36
+ # Example:
37
+ # :command_aliases=>{'libraries'=>'lib', 'commands'=>'com'}
38
+ # [:console_defaults] Array of libraries to load at start up when used in irb. Default is to load all library files and libraries defined
39
+ # in the config.
40
+ # [:bin_defaults] Array of libraries to load at start up when used from the commandline. Default is no libraries.
41
+ # [:add_load_path] Boolean specifying whether to add a load path pointing to the lib subdirectory/. This is useful in sharing
42
+ # classes between libraries without resorting to packaging them as gems. Defaults to false if the lib
43
+ # subdirectory doesn't exist in the boson directory.
44
+ # [:error_method_conflicts] Boolean specifying library loading behavior when its methods conflicts with existing methods in
28
45
  # the global namespace. When set to false, Boson automatically puts the library in its own namespace.
29
46
  # When set to true, the library fails to load explicitly. Default is false.
47
+ # [:console] Console to load when using --console from commandline. Default is irb.
48
+ # [:auto_namespace] Boolean which automatically namespaces all user-defined libraries. Default is false.
30
49
  def config(reload=false)
31
50
  if reload || @config.nil?
32
- default = {:commands=>{}, :libraries=>{}, :command_aliases=>{}, :defaults=>[]}
51
+ default = {:libraries=>{}, :command_aliases=>{}, :console_defaults=>[]}
33
52
  @config = default.merge(YAML::load_file(config_dir + '/boson.yml')) rescue default
34
53
  end
35
54
  @config
@@ -1,37 +1,43 @@
1
1
  module Boson
2
+ # Base class for runners.
2
3
  class Runner
3
4
  class<<self
5
+ # Enables view, adds local load path and loads default_libraries
4
6
  def init
5
7
  View.enable
6
8
  add_load_path
7
9
  Manager.load default_libraries, load_options
8
10
  end
9
11
 
10
- def add_load_path
11
- Boson.repos.each {|repo|
12
- if repo.config[:add_load_path] || File.exists?(File.join(repo.dir, 'lib'))
13
- $: << File.join(repo.dir, 'lib') unless $:.include? File.expand_path(File.join(repo.dir, 'lib'))
14
- end
15
- }
16
- end
17
-
18
- def load_options
19
- {:verbose=>@options[:verbose]}
20
- end
21
-
12
+ # Libraries that come with Boson
22
13
  def default_libraries
23
14
  [Boson::Commands::Core, Boson::Commands::WebCore]
24
15
  end
25
16
 
17
+ # Libraries detected in repositories
26
18
  def detected_libraries
27
19
  Boson.repos.map {|repo| Dir[File.join(repo.commands_dir, '**/*.rb')].
28
20
  map {|e| e.gsub(/.*commands\//,'').gsub('.rb','') } }.flatten
29
21
  end
30
22
 
23
+ # Libraries specified in config files and detected_libraries
31
24
  def all_libraries
32
25
  (detected_libraries + Boson.repos.map {|e| e.config[:libraries].keys}.flatten).uniq
33
26
  end
34
27
 
28
+ #:stopdoc:
29
+ def add_load_path
30
+ Boson.repos.each {|repo|
31
+ if repo.config[:add_load_path] || File.exists?(File.join(repo.dir, 'lib'))
32
+ $: << File.join(repo.dir, 'lib') unless $:.include? File.expand_path(File.join(repo.dir, 'lib'))
33
+ end
34
+ }
35
+ end
36
+
37
+ def load_options
38
+ {:verbose=>@options[:verbose]}
39
+ end
40
+
35
41
  def define_autoloader
36
42
  class << ::Boson.main_object
37
43
  def method_missing(method, *args, &block)
@@ -45,7 +51,7 @@ module Boson
45
51
  end
46
52
  end
47
53
  end
48
-
54
+ #:startdoc:
49
55
  end
50
56
  end
51
57
  end
@@ -1,36 +1,53 @@
1
1
  module Boson
2
+ # Runs Boson from the commandline. Usage for the boson shell command looks like this:
3
+ # boson [GLOBAL OPTIONS] [COMMAND] [ARGS] [COMMAND OPTIONS]
4
+ #
5
+ # The boson executable comes with these global options:
6
+ # [:help] Gives a basic help of global options. When a command is given the help shifts to a command's help.
7
+ # [:verbose] Using this along with :help option shows more help. Also gives verbosity to other actions i.e. loading.
8
+ # [:index] Updates index. This should be called in the unusual case that Boson doesn't detect new commands
9
+ # and libraries.
10
+ # [:execute] Like ruby -e, this executes a string of ruby code. However, this has the advantage that all
11
+ # commands are available as normal methods, automatically loading as needed. This is a good
12
+ # way to call commands that take non-string arguments.
13
+ # [:console] This drops Boson into irb after having loaded default commands and any explict libraries with
14
+ # :load option. This is a good way to start irb with only certain libraries loaded.
15
+ # [:load] Explicitly loads a list of libraries separated by commas. Most useful when used with :console option.
16
+ # Can also be used to explicitly load libraries that aren't being detected automatically.
17
+ # [:render] Pretty formats the results of commands without options. Handy for commands that return arrays.
2
18
  class BinRunner < Runner
3
19
  GLOBAL_OPTIONS = {
4
20
  :verbose=>{:type=>:boolean, :desc=>"Verbose description of loading libraries or help"},
5
- :index=>{:type=>:boolean, :desc=>"Updates index"},
21
+ :index=>{:type=>:boolean, :desc=>"Updates index for libraries and commands"},
6
22
  :execute=>{:type=>:string, :desc=>"Executes given arguments as a one line script"},
7
- :repl=>{:type=>:boolean, :desc=>"Drops into irb or another given repl/shell with default and explicit libraries loaded"},
23
+ :console=>{:type=>:boolean, :desc=>"Drops into irb with default and explicit libraries loaded"},
8
24
  :help=>{:type=>:boolean, :desc=>"Displays this help message or a command's help if given a command"},
9
- :load=>{:type=>:array, :values=>all_libraries, :enum=>false, :desc=>"A comma delimited array of libraries to load"}
10
- }
25
+ :load=>{:type=>:array, :values=>all_libraries, :enum=>false, :desc=>"A comma delimited array of libraries to load"},
26
+ :render=>{:type=>:boolean, :desc=>"Renders a Hirb view from result of command without options"}
27
+ } #:nodoc:
11
28
 
12
29
  class <<self
13
30
  attr_accessor :command
31
+ # Starts, processes and ends a commandline request.
14
32
  def start(args=ARGV)
15
33
  @command, @options, @args = parse_args(args)
16
- return print_usage if args.empty? || (@command.nil? && !@options[:repl] && !@options[:execute])
17
- return ReplRunner.bin_start(@options[:repl], @options[:load]) if @options[:repl]
34
+ return print_usage if args.empty? || (@command.nil? && !@options[:console] && !@options[:execute])
35
+ return ConsoleRunner.bin_start(@options[:console], @options[:load]) if @options[:console]
18
36
  init
19
37
 
20
38
  if @options[:help]
21
- print_command_help
39
+ Boson.invoke(:usage, @command, :verbose=>@options[:verbose])
22
40
  elsif @options[:execute]
23
41
  Boson.main_object.instance_eval @options[:execute]
24
42
  else
25
43
  execute_command
26
44
  end
27
45
  rescue Exception
28
- message = (@command && !Boson.can_invoke?(@command)) ?
46
+ print_error_message (@command && !Boson.can_invoke?(@command[/\w+/])) ?
29
47
  "Error: Command '#{@command}' not found" : "Error: #{$!.message}"
30
- message += "\nActual error: #{$!}\n" + $!.backtrace.inspect if @options && @options[:verbose]
31
- $stderr.puts message
32
48
  end
33
49
 
50
+ # Loads the given command.
34
51
  def init
35
52
  super
36
53
  Index.update(:verbose=>true) if @options[:index]
@@ -43,6 +60,12 @@ module Boson
43
60
  end
44
61
  end
45
62
 
63
+ #:stopdoc:
64
+ def print_error_message(message)
65
+ message += "\nActual error: #{$!}\n" + $!.backtrace.inspect if @options && @options[:verbose]
66
+ $stderr.puts message
67
+ end
68
+
46
69
  def load_command_by_index
47
70
  Index.update(:verbose=>@options[:verbose]) if !@options[:index] && Boson.can_invoke?(@command) && !@options[:help]
48
71
  if !Boson.can_invoke?(@command) && ((lib = Index.find_library(@command)) ||
@@ -58,15 +81,12 @@ module Boson
58
81
  def execute_command
59
82
  command, subcommand = @command.include?('.') ? @command.split('.', 2) : [@command, nil]
60
83
  dispatcher = subcommand ? Boson.invoke(command) : Boson.main_object
61
- @args = @args.join(" ") if ((com = Boson::Command.find(@command)) && com.option_command?)
62
84
  render_output dispatcher.send(subcommand || command, *@args)
63
85
  rescue ArgumentError
64
- puts "Wrong number of arguments for #{@command}\n\n"
65
- print_command_help
66
- end
67
-
68
- def print_command_help
69
- Boson.invoke(:usage, @command, :verbose=>@options[:verbose])
86
+ # for the rare case it's raise outside of boson
87
+ raise unless $!.backtrace.first.include?('boson/')
88
+ print_error_message "'#{@command}' was called incorrectly."
89
+ Boson.invoke(:usage, @command)
70
90
  end
71
91
 
72
92
  def parse_args(args)
@@ -77,10 +97,10 @@ module Boson
77
97
  end
78
98
 
79
99
  def render_output(output)
80
- if Scientist.global_options
81
- puts output.inspect unless Scientist.rendered
82
- else
83
- View.render(output)
100
+ if Scientist.global_options && !Scientist.rendered && !View.silent_object?(output)
101
+ puts output.inspect
102
+ elsif !Scientist.global_options && @options[:render]
103
+ View.render(output, :silence_booleans=>true)
84
104
  end
85
105
  end
86
106
 
@@ -95,6 +115,7 @@ module Boson
95
115
  Boson.invoke :commands, "", :fields=>["name", "usage", "description"], :description=>false
96
116
  end
97
117
  end
118
+ #:startdoc:
98
119
  end
99
120
  end
100
121
  end