boson 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +29 -12
- data/Rakefile +2 -2
- data/VERSION.yml +2 -2
- data/lib/boson.rb +4 -3
- data/lib/boson/command.rb +11 -1
- data/lib/boson/commands/core.rb +6 -6
- data/lib/boson/commands/web_core.rb +17 -4
- data/lib/boson/index.rb +30 -15
- data/lib/boson/inspector.rb +2 -2
- data/lib/boson/inspectors/argument_inspector.rb +4 -4
- data/lib/boson/inspectors/comment_inspector.rb +2 -2
- data/lib/boson/inspectors/method_inspector.rb +8 -6
- data/lib/boson/libraries/file_library.rb +60 -3
- data/lib/boson/libraries/module_library.rb +1 -1
- data/lib/boson/library.rb +23 -2
- data/lib/boson/loader.rb +2 -2
- data/lib/boson/manager.rb +3 -2
- data/lib/boson/namespace.rb +18 -13
- data/lib/boson/option_parser.rb +63 -18
- data/lib/boson/repo.rb +29 -10
- data/lib/boson/runner.rb +19 -13
- data/lib/boson/runners/bin_runner.rb +42 -21
- data/lib/boson/runners/console_runner.rb +54 -0
- data/lib/boson/scientist.rb +92 -17
- data/lib/boson/util.rb +22 -3
- data/lib/boson/view.rb +15 -3
- data/test/bin_runner_test.rb +18 -8
- data/test/loader_test.rb +1 -1
- data/test/manager_test.rb +2 -2
- data/test/repo_test.rb +1 -1
- data/test/runner_test.rb +7 -7
- data/test/scientist_test.rb +8 -7
- data/test/test_helper.rb +14 -3
- metadata +5 -6
- data/lib/boson/runners/repl_runner.rb +0 -40
- data/test/config/index.marshal +0 -0
data/lib/boson/library.rb
CHANGED
@@ -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].
|
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)
|
data/lib/boson/loader.rb
CHANGED
@@ -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
|
|
data/lib/boson/manager.rb
CHANGED
@@ -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
|
107
|
+
lib_class[0].new(@options.merge(:name=>source))
|
107
108
|
end
|
108
109
|
|
109
110
|
def after_load
|
data/lib/boson/namespace.rb
CHANGED
@@ -1,25 +1,29 @@
|
|
1
1
|
module Boson
|
2
|
+
# Used in all things namespace.
|
2
3
|
class Namespace
|
3
|
-
|
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
|
data/lib/boson/option_parser.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
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
|
-
#
|
52
|
-
#
|
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
|
-
#
|
87
|
+
# Here are the available option attributes:
|
55
88
|
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
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) } }
|
data/lib/boson/repo.rb
CHANGED
@@ -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
|
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 ||=
|
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
|
-
#
|
24
|
-
#
|
25
|
-
# [:
|
26
|
-
#
|
27
|
-
#
|
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 = {:
|
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
|
data/lib/boson/runner.rb
CHANGED
@@ -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
|
-
|
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
|
-
:
|
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[:
|
17
|
-
return
|
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
|
-
|
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
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
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
|
82
|
-
|
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
|