boson-more 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/.gemspec +22 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +97 -0
  4. data/Rakefile +35 -0
  5. data/deps.rip +1 -0
  6. data/lib/boson/alias.rb +75 -0
  7. data/lib/boson/argument_inspector.rb +90 -0
  8. data/lib/boson/commands/core.rb +67 -0
  9. data/lib/boson/commands/view_core.rb +19 -0
  10. data/lib/boson/commands/web_core.rb +153 -0
  11. data/lib/boson/comment_inspector.rb +100 -0
  12. data/lib/boson/console.rb +40 -0
  13. data/lib/boson/console_runner.rb +60 -0
  14. data/lib/boson/index.rb +48 -0
  15. data/lib/boson/libraries/file_library.rb +144 -0
  16. data/lib/boson/libraries/gem_library.rb +30 -0
  17. data/lib/boson/libraries/local_file_library.rb +30 -0
  18. data/lib/boson/libraries/module_library.rb +37 -0
  19. data/lib/boson/libraries/require_library.rb +23 -0
  20. data/lib/boson/libraries.rb +183 -0
  21. data/lib/boson/more/version.rb +5 -0
  22. data/lib/boson/more.rb +18 -0
  23. data/lib/boson/more_commands.rb +14 -0
  24. data/lib/boson/more_inspector.rb +42 -0
  25. data/lib/boson/more_manager.rb +34 -0
  26. data/lib/boson/more_method_inspector.rb +74 -0
  27. data/lib/boson/more_option_parser.rb +28 -0
  28. data/lib/boson/more_scientist.rb +68 -0
  29. data/lib/boson/more_util.rb +30 -0
  30. data/lib/boson/namespace.rb +31 -0
  31. data/lib/boson/namespacer.rb +117 -0
  32. data/lib/boson/pipe.rb +156 -0
  33. data/lib/boson/pipe_runner.rb +44 -0
  34. data/lib/boson/pipes.rb +75 -0
  35. data/lib/boson/repo.rb +96 -0
  36. data/lib/boson/repo_index.rb +135 -0
  37. data/lib/boson/runner_options.rb +88 -0
  38. data/lib/boson/save.rb +198 -0
  39. data/lib/boson/science.rb +273 -0
  40. data/lib/boson/view.rb +98 -0
  41. data/lib/boson/viewable.rb +48 -0
  42. data/test/alias_test.rb +55 -0
  43. data/test/argument_inspector_test.rb +40 -0
  44. data/test/command_test.rb +22 -0
  45. data/test/commands_test.rb +53 -0
  46. data/test/comment_inspector_test.rb +126 -0
  47. data/test/console_runner_test.rb +58 -0
  48. data/test/deps.rip +4 -0
  49. data/test/file_library_test.rb +41 -0
  50. data/test/gem_library_test.rb +40 -0
  51. data/test/libraries_test.rb +55 -0
  52. data/test/loader_test.rb +38 -0
  53. data/test/module_library_test.rb +30 -0
  54. data/test/more_manager_test.rb +29 -0
  55. data/test/more_method_inspector_test.rb +42 -0
  56. data/test/more_scientist_test.rb +10 -0
  57. data/test/namespacer_test.rb +61 -0
  58. data/test/pipes_test.rb +65 -0
  59. data/test/repo_index_test.rb +123 -0
  60. data/test/repo_test.rb +23 -0
  61. data/test/runner_options_test.rb +29 -0
  62. data/test/save_test.rb +86 -0
  63. data/test/science_test.rb +58 -0
  64. data/test/scientist_test.rb +195 -0
  65. data/test/test_helper.rb +165 -0
  66. data/test/web_test.rb +22 -0
  67. metadata +169 -0
data/lib/boson/save.rb ADDED
@@ -0,0 +1,198 @@
1
+ require 'boson/namespacer'
2
+ require 'boson/repo'
3
+ require 'boson/index'
4
+ require 'boson/repo_index'
5
+
6
+ module Boson
7
+ module Save
8
+ def config
9
+ repo.config
10
+ end
11
+
12
+ def config=(val)
13
+ repo.config = val
14
+ end
15
+
16
+ # The main required repository which defaults to ~/.boson.
17
+ def repo
18
+ @repo ||= Repo.new("#{ENV['BOSON_HOME'] || Dir.home}/.boson")
19
+ end
20
+
21
+ # An optional local repository which defaults to ./lib/boson or ./.boson.
22
+ def local_repo
23
+ @local_repo ||= begin
24
+ ignored_dirs = (config[:ignore_directories] || []).map {|e| File.expand_path(e) }
25
+ dir = ["lib/boson", ".boson"].find {|e| File.directory?(e) &&
26
+ File.expand_path(e) != repo.dir && !ignored_dirs.include?(File.expand_path('.')) }
27
+ Repo.new(dir) if dir
28
+ end
29
+ end
30
+
31
+ # The array of loaded repositories containing the main repo and possible local and global repos
32
+ def repos
33
+ @repos ||= [repo, local_repo, global_repo].compact
34
+ end
35
+
36
+ # Optional global repository at /etc/boson
37
+ def global_repo
38
+ File.exists?('/etc/boson') ? Repo.new('/etc/boson') : nil
39
+ end
40
+ end
41
+ extend Save
42
+
43
+ class BareRunner
44
+ module Save
45
+ def init
46
+ add_load_path
47
+ super
48
+ end
49
+
50
+ def autoload_command(cmd, opts={verbose: Boson.verbose})
51
+ Index.read
52
+ (lib = Index.find_library(cmd)) && Manager.load(lib, opts)
53
+ lib
54
+ end
55
+
56
+ def define_autoloader
57
+ class << ::Boson.main_object
58
+ def method_missing(method, *args, &block)
59
+ if BareRunner.autoload_command(method.to_s)
60
+ send(method, *args, &block) if respond_to?(method)
61
+ else
62
+ super
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ def default_libraries
69
+ Boson.repos.map {|e| e.config[:defaults] || [] }.flatten + super
70
+ end
71
+
72
+ # Libraries detected in repositories
73
+ def detected_libraries
74
+ Boson.repos.map {|e| e.detected_libraries }.flatten.uniq
75
+ end
76
+
77
+ # Libraries specified in config files and detected_libraries
78
+ def all_libraries
79
+ Boson.repos.map {|e| e.all_libraries }.flatten.uniq
80
+ end
81
+
82
+ def add_load_path
83
+ Boson.repos.each {|repo|
84
+ if repo.config[:add_load_path] || File.exists?(File.join(repo.dir, 'lib'))
85
+ $: << File.join(repo.dir, 'lib') unless $:.include? File.expand_path(File.join(repo.dir, 'lib'))
86
+ end
87
+ }
88
+ end
89
+ end
90
+ extend Save
91
+ end
92
+
93
+ # * All libraries can be configured by passing a hash of {library attributes}[link:classes/Boson/Library.html#M000077] under
94
+ # {the :libraries key}[link:classes/Boson/Repo.html#M000070] to the main config file ~/.boson/config/boson.yml.
95
+ # For most libraries this may be the only way to configure a library's commands.
96
+ # An example of a GemLibrary config:
97
+ # :libraries:
98
+ # httparty:
99
+ # :class_commands:
100
+ # delete: HTTParty.delete
101
+ # :commands:
102
+ # delete:
103
+ # :alias: d
104
+ # :desc: Http delete a given url
105
+ #
106
+ # When installing a third-party library, use the config file as a way to override default library and command attributes
107
+ # without modifying the library.
108
+ class Library
109
+ module Save
110
+ attr_accessor :repo_dir
111
+
112
+ def before_initialize
113
+ @repo_dir = set_repo.dir
114
+ end
115
+
116
+ def config
117
+ set_repo.config
118
+ end
119
+
120
+ def set_repo
121
+ Boson.repo
122
+ end
123
+
124
+ def marshal_dump
125
+ [@name, @commands, @gems, @module.to_s, @repo_dir, @indexed_namespace]
126
+ end
127
+
128
+ def marshal_load(ary)
129
+ @name, @commands, @gems, @module, @repo_dir, @indexed_namespace = ary
130
+ end
131
+ end
132
+ include Save
133
+ end
134
+
135
+ class Command
136
+ module Save
137
+ def marshal_dump
138
+ if @args && @args.any? {|e| e[1].is_a?(Module) }
139
+ @args.map! {|e| e.size == 2 ? [e[0], e[1].inspect] : e }
140
+ @file_parsed_args = true
141
+ end
142
+ [@name, @alias, @lib, @desc, @options, @render_options, @args, @default_option]
143
+ end
144
+
145
+ def marshal_load(ary)
146
+ @name, @alias, @lib, @desc, @options, @render_options, @args, @default_option = ary
147
+ end
148
+ end
149
+ include Save
150
+ end
151
+
152
+ if defined? BinRunner
153
+ # Any changes to your commands are immediately available from
154
+ # the commandline except for changes to the main config file. For those
155
+ # changes to take effect you need to explicitly load and index the libraries
156
+ # with --index. See RepoIndex to understand how Boson can immediately detect
157
+ # the latest commands.
158
+ class BinRunner
159
+ module Save
160
+ def autoload_command(cmd)
161
+ if !Boson.can_invoke?(cmd, false)
162
+ update_index
163
+ super(cmd, load_options)
164
+ end
165
+ end
166
+
167
+ def update_index
168
+ Index.update(verbose: verbose)
169
+ end
170
+
171
+ def execute_command(cmd, args)
172
+ @command = cmd # for external errors
173
+ autoload_command cmd
174
+ super
175
+ end
176
+
177
+ def command_not_found?(cmd)
178
+ super && (!(Index.read && Index.find_command(cmd[/\w+/])) || cmd.include?(NAMESPACE))
179
+ end
180
+
181
+ def command_name(cmd)
182
+ cmd.split(Boson::NAMESPACE)[-1]
183
+ end
184
+
185
+ def eval_execute_option(str)
186
+ define_autoloader
187
+ super
188
+ end
189
+
190
+ def default_libraries
191
+ super + Boson.repos.map {|e| e.config[:bin_defaults] || [] }.flatten +
192
+ Dir.glob('Bosonfile')
193
+ end
194
+ end
195
+ extend Save
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,273 @@
1
+ require 'boson/view'
2
+ require 'boson/pipe'
3
+ require 'boson/pipes'
4
+ require 'boson/more_scientist'
5
+
6
+ module Boson
7
+ class OptionCommand
8
+ BASIC_OPTIONS.update(
9
+ :delete_options=>{:type=>:array, :desc=>'Deletes global options starting with given strings' },
10
+ :usage_options=>{:type=>:string, :desc=>"Render options to pass to usage/help"},
11
+ :render=> {:type=>:boolean, :desc=>"Toggle a command's default rendering behavior"})
12
+ PIPE_OPTIONS = {
13
+ :sort=>{:type=>:string, :desc=>"Sort by given field"},
14
+ :reverse_sort=>{:type=>:boolean, :desc=>"Reverse a given sort"},
15
+ :query=>{:type=>:hash, :desc=>"Queries fields given field:search pairs"},
16
+ :pipes=>{:alias=>'P', :type=>:array, :desc=>"Pipe to commands sequentially"}
17
+ } #:nodoc:
18
+
19
+ RENDER_OPTIONS = {
20
+ :fields=>{:type=>:array, :desc=>"Displays fields in the order given"},
21
+ :class=>{:type=>:string, :desc=>"Hirb helper class which renders"},
22
+ :max_width=>{:type=>:numeric, :desc=>"Max width of a table"},
23
+ :vertical=>{:type=>:boolean, :desc=>"Display a vertical table"},
24
+ } #:nodoc:
25
+
26
+ # Adds render and pipe global options
27
+ # For more about pipe and render options see Pipe and View respectively.
28
+ # === Toggling Views With the Basic Global Option --render
29
+ # One of the more important global options is --render. This option toggles the rendering of a command's
30
+ # output done with View and Hirb[http://github.com/cldwalker/hirb].
31
+ #
32
+ # Here's a simple example of toggling Hirb's table view:
33
+ # # Defined in a library file:
34
+ # #@options {}
35
+ # def list(options={})
36
+ # [1,2,3]
37
+ # end
38
+ #
39
+ # Using it in irb:
40
+ # >> list
41
+ # => [1,2,3]
42
+ # >> list '-r' # or list --render
43
+ # +-------+
44
+ # | value |
45
+ # +-------+
46
+ # | 1 |
47
+ # | 2 |
48
+ # | 3 |
49
+ # +-------+
50
+ # 3 rows in set
51
+ # => true
52
+ # == Additional config keys for the main repo config
53
+ # [:render_options] Hash of render options available to all option commands to be passed to a Hirb view (see View). Since
54
+ # this merges with default render options, it's possible to override default render options.
55
+ # [:no_auto_render] When set, turns off commandline auto-rendering of a command's output. Default is false.
56
+ module ClassRender
57
+
58
+ def default_options
59
+ default_pipe_options.merge(default_render_options.merge(BASIC_OPTIONS))
60
+ end
61
+
62
+ def default_pipe_options
63
+ @default_pipe_options ||= PIPE_OPTIONS.merge Pipe.pipe_options
64
+ end
65
+
66
+ def default_render_options
67
+ @default_render_options ||= RENDER_OPTIONS.merge Boson.repo.config[:render_options] || {}
68
+ end
69
+
70
+ def delete_non_render_options(opt)
71
+ opt.delete_if {|k,v| BASIC_OPTIONS.keys.include?(k) }
72
+ end
73
+ end
74
+ extend ClassRender
75
+
76
+ module Render
77
+ def option_parser
78
+ @option_parser ||= @command.render_options ? OptionParser.new(all_global_options) :
79
+ self.class.default_option_parser
80
+ end
81
+
82
+ def all_global_options
83
+ OptionParser.make_mergeable! @command.render_options
84
+ render_opts = Util.recursive_hash_merge(@command.render_options, Util.deep_copy(self.class.default_render_options))
85
+ merged_opts = Util.recursive_hash_merge Util.deep_copy(self.class.default_pipe_options), render_opts
86
+ opts = Util.recursive_hash_merge merged_opts, Util.deep_copy(BASIC_OPTIONS)
87
+ set_global_option_defaults opts
88
+ end
89
+
90
+ def set_global_option_defaults(opts)
91
+ if !opts[:fields].key?(:values)
92
+ if opts[:fields][:default]
93
+ opts[:fields][:values] = opts[:fields][:default]
94
+ else
95
+ if opts[:change_fields] && (changed = opts[:change_fields][:default])
96
+ opts[:fields][:values] = changed.is_a?(Array) ? changed : changed.values
97
+ end
98
+ opts[:fields][:values] ||= opts[:headers][:default].keys if opts[:headers] && opts[:headers][:default]
99
+ end
100
+ opts[:fields][:enum] = false if opts[:fields][:values] && !opts[:fields].key?(:enum)
101
+ end
102
+ if opts[:fields][:values]
103
+ opts[:sort][:values] ||= opts[:fields][:values]
104
+ opts[:query][:keys] ||= opts[:fields][:values]
105
+ opts[:query][:default_keys] ||= "*"
106
+ end
107
+ opts
108
+ end
109
+ end
110
+ include Render
111
+ end
112
+
113
+ module Scientist
114
+ # * Before a method returns its value, it pipes its return value through pipe commands if pipe options are specified. See Pipe.
115
+ # * Methods can have any number of optional views associated with them via global render options (see View). Views can be toggled
116
+ # on/off with the global option --render (see OptionCommand).
117
+ module Render
118
+ attr_accessor :rendered, :render
119
+
120
+ def after_parse
121
+ (@global_options[:delete_options] || []).map {|e|
122
+ @global_options.keys.map {|k| k.to_s }.grep(/^#{e}/)
123
+ }.flatten.each {|e| @global_options.delete(e.to_sym) }
124
+ end
125
+
126
+ def process_result(result)
127
+ if (@rendered = can_render?)
128
+ if @global_options.key?(:class) || @global_options.key?(:method)
129
+ result = Pipe.scientist_process(result, @global_options, :config=>@command.config, :args=>@args, :options=>@current_options)
130
+ end
131
+ View.render(result, OptionCommand.delete_non_render_options(@global_options.dup), false)
132
+ else
133
+ Pipe.scientist_process(result, @global_options, :config=>@command.config, :args=>@args, :options=>@current_options)
134
+ end
135
+ rescue StandardError
136
+ raise Scientist::Error, $!.message, $!.backtrace
137
+ end
138
+
139
+ def can_render?
140
+ render.nil? ? command_renders? : render
141
+ end
142
+
143
+ def command_renders?
144
+ (!!@command.render_options ^ @global_options[:render]) && !Pipe.any_no_render_pipes?(@global_options)
145
+ end
146
+
147
+ def run_pretend_option(args)
148
+ super
149
+ @rendered = true if @global_options[:pretend]
150
+ end
151
+
152
+ def help_options
153
+ super.tap do |opts|
154
+ if @global_options[:usage_options]
155
+ opts << "--render_options=#{@global_options[:usage_options]}"
156
+ end
157
+ opts
158
+ end
159
+ end
160
+ end
161
+ extend Render
162
+ end
163
+
164
+ class Command
165
+ module ScienceClassMethods
166
+ attr_accessor :all_option_commands
167
+
168
+ def create(name, library)
169
+ super.tap do |obj|
170
+ if @all_option_commands && !%w{get method_missing}.include?(name)
171
+ obj.make_option_command(library)
172
+ end
173
+ end
174
+ end
175
+ end
176
+ extend ScienceClassMethods
177
+
178
+ module Science
179
+ # Option parser for command as defined by @render_options.
180
+ def render_option_parser
181
+ option_command? ? Boson::Scientist.option_command(self).option_parser : nil
182
+ end
183
+
184
+ def make_option_command(lib=library)
185
+ @option_command = true
186
+ @args = [['*args']] unless args(lib) || arg_size
187
+ end
188
+
189
+ def option_command?
190
+ super || render_options
191
+ end
192
+ end
193
+ include Science
194
+ end
195
+
196
+ # [*:render_options*] Hash of rendering options to pass to OptionParser. If the key :output_class is passed,
197
+ # that class's Hirb config will serve as defaults for this rendering hash.
198
+ class Command
199
+ attr_accessor :render_options
200
+
201
+ module Science
202
+ def after_initialize(hash)
203
+ if hash[:render_options] && (@render_options = hash.delete(:render_options))[:output_class]
204
+ @render_options = Util.recursive_hash_merge View.class_config(@render_options[:output_class]), @render_options
205
+ end
206
+ super
207
+ end
208
+ end
209
+ end
210
+
211
+ if defined? BinRunner
212
+ class BinRunner < BareRunner
213
+ GLOBAL_OPTIONS.update(
214
+ option_commands: {
215
+ :type=>:boolean,
216
+ :desc=>"Toggles on all commands to be defined as option commands"
217
+ },
218
+ render: {:type=>:boolean,
219
+ :desc=>"Renders a Hirb view from result of command without options"}
220
+ )
221
+
222
+ # [:render] Toggles the auto-rendering done for commands that don't have views. Doesn't affect commands that already have views.
223
+ # Default is false. Also see Auto Rendering section below.
224
+ #
225
+ # ==== Auto Rendering
226
+ # Commands that don't have views (defined via render_options) have their return value auto-rendered as a view as follows:
227
+ # * nil,false and true aren't rendered
228
+ # * arrays are rendered with Hirb's tables
229
+ # * non-arrays are printed with inspect()
230
+ # * Any of these cases can be toggled to render/not render with the global option :render
231
+ # To turn off auto-rendering by default, add a :no_auto_render: true entry to the main config.
232
+ module Science
233
+ def init
234
+ Command.all_option_commands = true if @options[:option_commands]
235
+ super
236
+ end
237
+
238
+ def render_output(output)
239
+ if (!Scientist.rendered && !View.silent_object?(output)) ^ @options[:render] ^
240
+ Boson.repo.config[:no_auto_render]
241
+ opts = output.is_a?(String) ? {:method=>'puts'} :
242
+ {:inspect=>!output.is_a?(Array) || (Scientist.global_options || {})[:render] }
243
+ View.render output, opts
244
+ end
245
+ end
246
+
247
+ def allowed_argument_error?(err, cmd, args)
248
+ err.class == OptionCommand::CommandArgumentError || super
249
+ end
250
+
251
+ def execute_command(cmd, args)
252
+ render_output super
253
+ end
254
+ end
255
+
256
+ class <<self
257
+ include Science
258
+ end
259
+ end
260
+ end
261
+
262
+ # Additional method attributes:
263
+ # * render_options: Hash to define an OptionParser object for a command's local/global render options (see View).
264
+ class MethodInspector
265
+ METHODS << :render_options
266
+ METHOD_CLASSES[:render_options] = Hash
267
+ SCRAPEABLE_METHODS << :render_options
268
+ end
269
+
270
+ module CommentInspector
271
+ EVAL_ATTRIBUTES << :render_options
272
+ end
273
+ end
data/lib/boson/view.rb ADDED
@@ -0,0 +1,98 @@
1
+ require 'hirb'
2
+ require 'boson/more_option_parser'
3
+
4
+ module Boson
5
+ # This module generates views for a command by handing it to {Hirb}[http://tagaholic.me/hirb/]. Since Hirb can be customized
6
+ # to generate any view, commands can have any views associated with them!
7
+ #
8
+ # === Views with Render Options
9
+ # To pass rendering options to a Hirb helper as command options, a command has to define the options with
10
+ # the render_options method attribute:
11
+ #
12
+ # # @render_options :fields=>[:a,:b]
13
+ # def list(options={})
14
+ # [{:a=>1, :b=>2}, {:a=>10,:b=>11}]
15
+ # end
16
+ #
17
+ # # To see that the render_options method attribute actually passes the :fields option by default:
18
+ # >> list '-p' # or list '--pretend'
19
+ # Arguments: []
20
+ # Global options: {:pretend=>true, :fields=>[:a, :b]}
21
+ #
22
+ # >> list
23
+ # +----+----+
24
+ # | a | b |
25
+ # +----+----+
26
+ # | 1 | 2 |
27
+ # | 10 | 11 |
28
+ # +----+----+
29
+ # 2 rows in set
30
+ #
31
+ # # To create a vertical table, we can pass --vertical, one of the default global render options.
32
+ # >> list '-V' # or list '--vertical'
33
+ # *** 1. row ***
34
+ # a: 1
35
+ # b: 2
36
+ # ...
37
+ #
38
+ # # To get the original return value use the global option --render
39
+ # >> list '-r' # or list '--render'
40
+ # => [{:a=>1, :b=>2}, {:a=>10,:b=>11}]
41
+ #
42
+ # === Boson and Hirb
43
+ # Since Boson uses {Hirb's auto table helper}[http://tagaholic.me/hirb/doc/classes/Hirb/Helpers/AutoTable.html]
44
+ # by default, you may want to read up on its many options. To use any of them in commands, define them locally
45
+ # with render_options or globally by adding them under the :render_options key of the main config.
46
+ # What if you want to use your own helper class? No problem. Simply pass it with the global :class option.
47
+ #
48
+ # When using the default helper, one of the most important options to define is :fields. Aside from controlling what fields
49
+ # are displayed, it's used to set :values option attributes for related options i.e. :sort and :query. This provides handy option
50
+ # value aliasing via OptionParser. If you don't set :fields, Boson will try to set its :values with field-related options i.e.
51
+ # :change_fields, :filters and :headers.
52
+ module View
53
+ extend self
54
+
55
+ # Enables hirb and reads a config file from the main repo's config/hirb.yml.
56
+ def enable
57
+ unless @enabled
58
+ Hirb::View.enable(:config_file=>File.join(Boson.repo.config_dir, 'hirb.yml'))
59
+ Hirb::Helpers::Table.filter_any = true
60
+ end
61
+ @enabled = true
62
+ end
63
+
64
+ # Renders any object via Hirb. Options are passed directly to
65
+ # {Hirb::Console.render_output}[http://tagaholic.me/hirb/doc/classes/Hirb/Console.html#M000011].
66
+ def render(object, options={}, return_obj=false)
67
+ if options[:inspect]
68
+ puts(object.inspect)
69
+ else
70
+ render_object(object, options, return_obj) unless silent_object?(object)
71
+ end
72
+ end
73
+
74
+ #:stopdoc:
75
+ def class_config(klass)
76
+ opts = (Hirb::View.formatter_config[klass] || {}).dup
77
+ opts.delete(:ancestor)
78
+ opts.merge!((opts.delete(:options) || {}).dup)
79
+ OptionParser.make_mergeable!(opts)
80
+ opts
81
+ end
82
+
83
+ def toggle_pager
84
+ Hirb::View.toggle_pager
85
+ end
86
+
87
+ def silent_object?(obj)
88
+ [nil,false,true].include?(obj)
89
+ end
90
+
91
+ def render_object(object, options={}, return_obj=false)
92
+ options[:class] ||= :auto_table
93
+ render_result = Hirb::Console.render_output(object, options)
94
+ return_obj ? object : render_result
95
+ end
96
+ #:startdoc:
97
+ end
98
+ end
@@ -0,0 +1,48 @@
1
+ require 'boson/view'
2
+
3
+ module Boson
4
+ if defined? BinRunner
5
+ class BinRunner
6
+ module Viewable
7
+ def print_usage_header
8
+ super
9
+ puts "GLOBAL OPTIONS"
10
+ View.enable
11
+ end
12
+ end
13
+ extend Viewable
14
+ end
15
+ end
16
+
17
+ class BareRunner
18
+ module Viewable
19
+ def init
20
+ View.enable
21
+ super
22
+ end
23
+ end
24
+ extend Viewable
25
+ end
26
+
27
+ class OptionParser
28
+ module Viewable
29
+ def get_fields_and_options(fields, options)
30
+ (fields << :default).uniq! if options.delete(:local) || options[:fields] == '*'
31
+ fields, opts = super(fields, options)
32
+ fields.delete(:default) if fields.include?(:default) && opts.all? {|e| e[:default].nil? }
33
+ [fields, opts]
34
+ end
35
+
36
+ def default_render_options #:nodoc:
37
+ {:header_filter=>:capitalize, :description=>false, :filter_any=>true,
38
+ :filter_classes=>{Array=>[:join, ',']}, :hide_empty=>true}
39
+ end
40
+
41
+ def render_table(fields, arr, options)
42
+ options = default_render_options.merge(:fields=>fields).merge(options)
43
+ View.render arr, options
44
+ end
45
+ end
46
+ include Viewable
47
+ end
48
+ end
@@ -0,0 +1,55 @@
1
+ # Add library_loaded? and with_config
2
+ describe "Manager" do
3
+ def load_library(hash)
4
+ new_attributes = {:name=>hash[:name], :commands=>[], :created_dependencies=>[], :loaded=>true}
5
+ [:module, :commands].each {|e| new_attributes[e] = hash.delete(e) if hash[e] }
6
+ Manager.expects(:call_load_action).returns(Library.new(new_attributes))
7
+ Manager.load([hash[:name]])
8
+ end
9
+
10
+ before { reset_boson }
11
+
12
+ describe "command aliases" do
13
+ before { eval %[module ::Aquateen; def frylock; end; end] }
14
+ after { Object.send(:remove_const, "Aquateen") }
15
+
16
+ it "created with command specific config" do
17
+ with_config(:command_aliases=>{'frylock'=>'fr'}) do
18
+ Manager.expects(:create_instance_aliases).with({"Aquateen"=>{"frylock"=>"fr"}})
19
+ load_library :name=>'aquateen', :commands=>['frylock'], :module=>Aquateen
20
+ library_loaded? 'aquateen'
21
+ end
22
+ end
23
+
24
+ it "created with config command_aliases" do
25
+ with_config(:command_aliases=>{"frylock"=>"fr"}) do
26
+ Manager.expects(:create_instance_aliases).with({"Aquateen"=>{"frylock"=>"fr"}})
27
+ load_library :name=>'aquateen', :commands=>['frylock'], :module=>Aquateen
28
+ library_loaded? 'aquateen'
29
+ end
30
+ end
31
+
32
+ it "not created and warns for commands with no module" do
33
+ with_config(:command_aliases=>{'frylock'=>'fr'}) do
34
+ capture_stderr {
35
+ load_library(:name=>'aquateen', :commands=>['frylock'])
36
+ }.should =~ /No aliases/
37
+ library_loaded? 'aquateen'
38
+ Aquateen.method_defined?(:fr).should == false
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "Loader" do
45
+ describe "load" do
46
+ before { reset }
47
+ it "loads a library and creates its class commands" do
48
+ with_config(:libraries=>{"blah"=>{:class_commands=>{"bling"=>"Blah.bling", "Blah"=>['hmm']}}}) do
49
+ load :blah, :file_string=>"module Blah; def self.bling; end; def self.hmm; end; end"
50
+ command_exists? 'bling'
51
+ command_exists? 'hmm'
52
+ end
53
+ end
54
+ end
55
+ end