boson 0.0.1
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.
- data/LICENSE.txt +22 -0
- data/README.rdoc +133 -0
- data/Rakefile +52 -0
- data/VERSION.yml +4 -0
- data/bin/boson +6 -0
- data/lib/boson.rb +72 -0
- data/lib/boson/command.rb +117 -0
- data/lib/boson/commands.rb +7 -0
- data/lib/boson/commands/core.rb +66 -0
- data/lib/boson/commands/web_core.rb +36 -0
- data/lib/boson/index.rb +95 -0
- data/lib/boson/inspector.rb +80 -0
- data/lib/boson/inspectors/argument_inspector.rb +92 -0
- data/lib/boson/inspectors/comment_inspector.rb +79 -0
- data/lib/boson/inspectors/method_inspector.rb +94 -0
- data/lib/boson/libraries/file_library.rb +76 -0
- data/lib/boson/libraries/gem_library.rb +21 -0
- data/lib/boson/libraries/module_library.rb +17 -0
- data/lib/boson/libraries/require_library.rb +11 -0
- data/lib/boson/library.rb +108 -0
- data/lib/boson/loader.rb +103 -0
- data/lib/boson/manager.rb +184 -0
- data/lib/boson/namespace.rb +45 -0
- data/lib/boson/option_parser.rb +318 -0
- data/lib/boson/repo.rb +38 -0
- data/lib/boson/runner.rb +51 -0
- data/lib/boson/runners/bin_runner.rb +100 -0
- data/lib/boson/runners/repl_runner.rb +40 -0
- data/lib/boson/scientist.rb +168 -0
- data/lib/boson/util.rb +93 -0
- data/lib/boson/view.rb +31 -0
- data/test/argument_inspector_test.rb +62 -0
- data/test/bin_runner_test.rb +136 -0
- data/test/commands_test.rb +51 -0
- data/test/comment_inspector_test.rb +99 -0
- data/test/config/index.marshal +0 -0
- data/test/file_library_test.rb +50 -0
- data/test/index_test.rb +117 -0
- data/test/loader_test.rb +181 -0
- data/test/manager_test.rb +110 -0
- data/test/method_inspector_test.rb +64 -0
- data/test/option_parser_test.rb +365 -0
- data/test/repo_test.rb +22 -0
- data/test/runner_test.rb +43 -0
- data/test/scientist_test.rb +291 -0
- data/test/test_helper.rb +119 -0
- metadata +133 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
module Boson
|
2
|
+
class BinRunner < Runner
|
3
|
+
GLOBAL_OPTIONS = {
|
4
|
+
:verbose=>{:type=>:boolean, :desc=>"Verbose description of loading libraries or help"},
|
5
|
+
:index=>{:type=>:boolean, :desc=>"Updates index"},
|
6
|
+
: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"},
|
8
|
+
: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
|
+
}
|
11
|
+
|
12
|
+
class <<self
|
13
|
+
attr_accessor :command
|
14
|
+
def start(args=ARGV)
|
15
|
+
@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]
|
18
|
+
init
|
19
|
+
|
20
|
+
if @options[:help]
|
21
|
+
print_command_help
|
22
|
+
elsif @options[:execute]
|
23
|
+
Boson.main_object.instance_eval @options[:execute]
|
24
|
+
else
|
25
|
+
execute_command
|
26
|
+
end
|
27
|
+
rescue Exception
|
28
|
+
message = (@command && !Boson.can_invoke?(@command)) ?
|
29
|
+
"Error: Command '#{@command}' not found" : "Error: #{$!.message}"
|
30
|
+
message += "\nActual error: #{$!}\n" + $!.backtrace.inspect if @options && @options[:verbose]
|
31
|
+
$stderr.puts message
|
32
|
+
end
|
33
|
+
|
34
|
+
def init
|
35
|
+
super
|
36
|
+
Index.update(:verbose=>true) if @options[:index]
|
37
|
+
if @options[:load]
|
38
|
+
Manager.load @options[:load], load_options
|
39
|
+
elsif @options[:execute]
|
40
|
+
define_autoloader
|
41
|
+
else
|
42
|
+
load_command_by_index
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_command_by_index
|
47
|
+
Index.update(:verbose=>@options[:verbose]) if !@options[:index] && Boson.can_invoke?(@command) && !@options[:help]
|
48
|
+
if !Boson.can_invoke?(@command) && ((lib = Index.find_library(@command)) ||
|
49
|
+
(Index.update(:verbose=>@options[:verbose]) && (lib = Index.find_library(@command))))
|
50
|
+
Manager.load lib, load_options
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_libraries
|
55
|
+
super + (Boson.repo.config[:bin_defaults] || [])
|
56
|
+
end
|
57
|
+
|
58
|
+
def execute_command
|
59
|
+
command, subcommand = @command.include?('.') ? @command.split('.', 2) : [@command, nil]
|
60
|
+
dispatcher = subcommand ? Boson.invoke(command) : Boson.main_object
|
61
|
+
@args = @args.join(" ") if ((com = Boson::Command.find(@command)) && com.option_command?)
|
62
|
+
render_output dispatcher.send(subcommand || command, *@args)
|
63
|
+
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])
|
70
|
+
end
|
71
|
+
|
72
|
+
def parse_args(args)
|
73
|
+
@option_parser = OptionParser.new(GLOBAL_OPTIONS)
|
74
|
+
options = @option_parser.parse(args.dup, :opts_before_args=>true)
|
75
|
+
new_args = @option_parser.non_opts
|
76
|
+
[new_args.shift, options, new_args]
|
77
|
+
end
|
78
|
+
|
79
|
+
def render_output(output)
|
80
|
+
if Scientist.global_options
|
81
|
+
puts output.inspect unless Scientist.rendered
|
82
|
+
else
|
83
|
+
View.render(output)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def print_usage
|
88
|
+
puts "boson [GLOBAL OPTIONS] [COMMAND] [ARGS] [COMMAND OPTIONS]\n\n"
|
89
|
+
puts "GLOBAL OPTIONS"
|
90
|
+
View.enable
|
91
|
+
@option_parser.print_usage_table
|
92
|
+
if @options[:verbose]
|
93
|
+
Manager.load [Boson::Commands::Core]
|
94
|
+
puts "\n\nDEFAULT COMMANDS"
|
95
|
+
Boson.invoke :commands, "", :fields=>["name", "usage", "description"], :description=>false
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Boson
|
2
|
+
class ReplRunner < Runner
|
3
|
+
class <<self
|
4
|
+
def start(options={})
|
5
|
+
@options = options
|
6
|
+
init unless @initialized
|
7
|
+
Manager.load(@options[:libraries], load_options) if @options[:libraries]
|
8
|
+
end
|
9
|
+
|
10
|
+
def init
|
11
|
+
super
|
12
|
+
define_autoloader if @options[:autoload_libraries]
|
13
|
+
@initialized = true
|
14
|
+
end
|
15
|
+
|
16
|
+
def bin_start(repl, libraries)
|
17
|
+
start :no_defaults=>true, :libraries=>libraries
|
18
|
+
repl = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb' unless repl.is_a?(String)
|
19
|
+
unless repl.index('/') == 0 || (repl = Util.which(repl))
|
20
|
+
$stderr.puts "Repl not found. Please specify full path of repl."
|
21
|
+
return
|
22
|
+
end
|
23
|
+
ARGV.replace ['-f']
|
24
|
+
Kernel.load $0 = repl
|
25
|
+
end
|
26
|
+
|
27
|
+
def default_libraries
|
28
|
+
defaults = super
|
29
|
+
unless @options[:no_defaults]
|
30
|
+
new_defaults = Boson.repos.map {|e| e.config[:defaults] }.flatten
|
31
|
+
new_defaults = detected_libraries if new_defaults.empty?
|
32
|
+
defaults += new_defaults
|
33
|
+
defaults.uniq!
|
34
|
+
end
|
35
|
+
defaults
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
module Boson
|
3
|
+
module Scientist
|
4
|
+
extend self
|
5
|
+
class Error < StandardError; end
|
6
|
+
class EscapeGlobalOption < StandardError; end
|
7
|
+
attr_reader :global_options, :rendered
|
8
|
+
@no_option_commands ||= []
|
9
|
+
GLOBAL_OPTIONS = {
|
10
|
+
:help=>{:type=>:boolean, :desc=>"Display a command's help"},
|
11
|
+
:render=>{:type=>:boolean, :desc=>"Toggle a command's default render behavior"},
|
12
|
+
:verbose=>{:type=>:boolean, :desc=>"Increase verbosity for help, errors, etc."},
|
13
|
+
:global=>{:type=>:string, :desc=>"Pass a string of global options without the dashes i.e. '-p -f=f1,f2' -> 'p f=f1,f2'"},
|
14
|
+
:pretend=>{:type=>:boolean, :desc=>"Display what a command would execute without executing it"}
|
15
|
+
}
|
16
|
+
RENDER_OPTIONS = {
|
17
|
+
:fields=>{:type=>:array, :desc=>"Displays fields in the order given"},
|
18
|
+
:sort=>{:type=>:string, :desc=>"Sort by given field"},
|
19
|
+
:as=>{:type=>:string, :desc=>"Hirb helper class which renders"},
|
20
|
+
:reverse_sort=>{:type=>:boolean, :desc=>"Reverse a given sort"},
|
21
|
+
:max_width=>{:type=>:numeric, :desc=>"Max width of a table"},
|
22
|
+
:vertical=>{:type=>:boolean, :desc=>"Display a vertical table"}
|
23
|
+
}
|
24
|
+
|
25
|
+
def create_option_command(obj, command)
|
26
|
+
cmd_block = create_option_command_block(obj, command)
|
27
|
+
@no_option_commands << command if command.options.nil?
|
28
|
+
[command.name, command.alias].compact.each {|e|
|
29
|
+
obj.instance_eval("class<<self;self;end").send(:define_method, e, cmd_block)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_option_command_block(obj, command)
|
34
|
+
lambda {|*args|
|
35
|
+
Boson::Scientist.translate_and_render(obj, command, args) {|args| super(*args) }
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def translate_and_render(obj, command, args)
|
40
|
+
@global_options = {}
|
41
|
+
args = translate_args(obj, command, args)
|
42
|
+
if @global_options[:verbose] || @global_options[:pretend]
|
43
|
+
puts "Arguments: #{args.inspect}", "Global options: #{@global_options.inspect}"
|
44
|
+
end
|
45
|
+
return @rendered = true if @global_options[:pretend]
|
46
|
+
render_or_raw yield(args)
|
47
|
+
rescue EscapeGlobalOption
|
48
|
+
Boson.invoke(:usage, command.name, :verbose=>@global_options[:verbose]) if @global_options[:help]
|
49
|
+
rescue OptionParser::Error, Error
|
50
|
+
$stderr.puts "Error: " + $!.message
|
51
|
+
end
|
52
|
+
|
53
|
+
def translate_args(obj, command, args)
|
54
|
+
@obj, @command, @args = obj, command, args
|
55
|
+
@command.options ||= {}
|
56
|
+
if parsed_options = command_options
|
57
|
+
add_default_args(@args)
|
58
|
+
return @args if @no_option_commands.include?(@command)
|
59
|
+
@args << parsed_options
|
60
|
+
if @args.size != command.arg_size && !command.has_splat_args?
|
61
|
+
command_size = @args.size > command.arg_size ? command.arg_size : command.arg_size - 1
|
62
|
+
if @args.size - 1 == command_size
|
63
|
+
raise Error, "Arguments are misaligned. Possible causes are incorrect argument "+
|
64
|
+
"size or no argument for this method's options."
|
65
|
+
else
|
66
|
+
raise ArgumentError, "wrong number of arguments (#{@args.size - 1} for #{command_size})"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
@args
|
71
|
+
rescue Error, ArgumentError, EscapeGlobalOption
|
72
|
+
raise
|
73
|
+
rescue Exception
|
74
|
+
message = @global_options[:verbose] ? "#{$!}\n#{$!.backtrace.inspect}" : $!.message
|
75
|
+
raise Error, message
|
76
|
+
end
|
77
|
+
|
78
|
+
def render_or_raw(result)
|
79
|
+
(@rendered = render?) ? View.render(result, global_render_options) : result
|
80
|
+
rescue Exception
|
81
|
+
message = @global_options[:verbose] ? "#{$!}\n#{$!.backtrace.inspect}" : $!.message
|
82
|
+
raise Error, message
|
83
|
+
end
|
84
|
+
|
85
|
+
def option_parser
|
86
|
+
@command.render_options ? command_option_parser : default_option_parser
|
87
|
+
end
|
88
|
+
|
89
|
+
def command_option_parser
|
90
|
+
(@option_parsers ||= {})[@command] ||= OptionParser.new render_options.merge(GLOBAL_OPTIONS)
|
91
|
+
end
|
92
|
+
|
93
|
+
def render_option_parser(cmd)
|
94
|
+
@command = cmd
|
95
|
+
option_parser
|
96
|
+
end
|
97
|
+
|
98
|
+
def default_option_parser
|
99
|
+
@default_option_parser ||= OptionParser.new RENDER_OPTIONS.merge(GLOBAL_OPTIONS)
|
100
|
+
end
|
101
|
+
|
102
|
+
def render_options
|
103
|
+
@command.render_options ? command_render_options : RENDER_OPTIONS
|
104
|
+
end
|
105
|
+
|
106
|
+
def command_render_options
|
107
|
+
(@command_render_options ||= {})[@command] ||= begin
|
108
|
+
@command.render_options.each {|k,v|
|
109
|
+
if !v.is_a?(Hash) && !v.is_a?(Symbol) && RENDER_OPTIONS.keys.include?(k)
|
110
|
+
@command.render_options[k] = {:default=>v}
|
111
|
+
end
|
112
|
+
}
|
113
|
+
opts = Util.recursive_hash_merge(@command.render_options, RENDER_OPTIONS)
|
114
|
+
opts[:sort][:values] ||= opts[:fields][:values] if opts[:fields][:values]
|
115
|
+
opts
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def global_render_options
|
120
|
+
@global_options.dup.delete_if {|k,v| !render_options.keys.include?(k) }
|
121
|
+
end
|
122
|
+
|
123
|
+
def render?
|
124
|
+
(@command.render_options && !@global_options[:render]) || (!@command.render_options && @global_options[:render])
|
125
|
+
end
|
126
|
+
|
127
|
+
def command_options
|
128
|
+
if @args.size == 1 && @args[0].is_a?(String)
|
129
|
+
parsed_options, @args = parse_options Shellwords.shellwords(@args[0])
|
130
|
+
# last string argument interpreted as args + options
|
131
|
+
elsif @args.size > 1 && @args[-1].is_a?(String)
|
132
|
+
parsed_options, new_args = parse_options @args.pop.split(/\s+/)
|
133
|
+
@args += new_args
|
134
|
+
# default options
|
135
|
+
elsif (@args.size <= @command.arg_size - 1) || (@command.has_splat_args? && !@args[-1].is_a?(Hash))
|
136
|
+
parsed_options = parse_options([])[0]
|
137
|
+
end
|
138
|
+
parsed_options
|
139
|
+
end
|
140
|
+
|
141
|
+
def parse_options(args)
|
142
|
+
parsed_options = @command.option_parser.parse(args, :delete_invalid_opts=>true)
|
143
|
+
@global_options = option_parser.parse @command.option_parser.leading_non_opts
|
144
|
+
new_args = option_parser.non_opts.dup + @command.option_parser.trailing_non_opts
|
145
|
+
if @global_options[:global]
|
146
|
+
global_opts = Shellwords.shellwords(@global_options[:global]).map {|str| (str.length > 1 ? "--" : "-") + str }
|
147
|
+
@global_options.merge! option_parser.parse(global_opts)
|
148
|
+
end
|
149
|
+
raise EscapeGlobalOption if @global_options[:help]
|
150
|
+
[parsed_options, new_args]
|
151
|
+
end
|
152
|
+
|
153
|
+
def add_default_args(args)
|
154
|
+
if @command.args && args.size < @command.args.size - 1
|
155
|
+
# leave off last arg since its an option
|
156
|
+
@command.args.slice(0..-2).each_with_index {|arr,i|
|
157
|
+
next if args.size >= i + 1 # only fill in once args run out
|
158
|
+
break if arr.size != 2 # a default arg value must exist
|
159
|
+
begin
|
160
|
+
args[i] = @command.file_parsed_args? ? @obj.instance_eval(arr[1]) : arr[1]
|
161
|
+
rescue Exception
|
162
|
+
raise Error, "Unable to set default argument at position #{i+1}.\nReason: #{$!.message}"
|
163
|
+
end
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/lib/boson/util.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module Boson
|
2
|
+
module Util
|
3
|
+
extend self
|
4
|
+
#From Rails ActiveSupport
|
5
|
+
def underscore(camel_cased_word)
|
6
|
+
camel_cased_word.to_s.gsub(/::/, '/').
|
7
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
8
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
9
|
+
tr("-", "_").
|
10
|
+
downcase
|
11
|
+
end
|
12
|
+
|
13
|
+
# from Rails ActiveSupport
|
14
|
+
def camelize(string)
|
15
|
+
string.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
16
|
+
end
|
17
|
+
|
18
|
+
def constantize(string)
|
19
|
+
any_const_get(camelize(string))
|
20
|
+
end
|
21
|
+
|
22
|
+
def symbolize_keys(hash)
|
23
|
+
hash.inject({}) {|options, (key, value)|
|
24
|
+
options[key.to_sym] = value; options
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a constant like const_get() no matter what namespace it's nested in.
|
29
|
+
# Returns nil if the constant is not found.
|
30
|
+
def any_const_get(name)
|
31
|
+
return name if name.is_a?(Module)
|
32
|
+
begin
|
33
|
+
klass = Object
|
34
|
+
name.split('::').each {|e|
|
35
|
+
klass = klass.const_get(e)
|
36
|
+
}
|
37
|
+
klass
|
38
|
+
rescue
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def detect(options={}, &block)
|
44
|
+
options = {:methods=>true, :object_methods=>true}.merge!(options)
|
45
|
+
original_gems = Gem.loaded_specs.keys if Object.const_defined? :Gem
|
46
|
+
original_object_methods = Object.instance_methods
|
47
|
+
original_instance_methods = class << Boson.main_object; instance_methods end
|
48
|
+
original_modules = modules if options[:modules]
|
49
|
+
block.call
|
50
|
+
detected = {}
|
51
|
+
detected[:methods] = options[:methods] ? (class << Boson.main_object; instance_methods end -
|
52
|
+
original_instance_methods) : []
|
53
|
+
detected[:methods] -= (Object.instance_methods - original_object_methods) unless options[:object_methods]
|
54
|
+
detected[:gems] = Gem.loaded_specs.keys - original_gems if Object.const_defined? :Gem
|
55
|
+
detected[:modules] = modules - original_modules if options[:modules]
|
56
|
+
detected
|
57
|
+
end
|
58
|
+
|
59
|
+
def safe_require(lib)
|
60
|
+
begin
|
61
|
+
require lib
|
62
|
+
rescue LoadError
|
63
|
+
false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def modules
|
68
|
+
all_modules = []
|
69
|
+
ObjectSpace.each_object(Module) {|e| all_modules << e}
|
70
|
+
all_modules
|
71
|
+
end
|
72
|
+
|
73
|
+
def common_instance_methods(module1, module2)
|
74
|
+
(module1.instance_methods + module1.private_instance_methods) & (module2.instance_methods + module2.private_instance_methods)
|
75
|
+
end
|
76
|
+
|
77
|
+
def create_module(base_module, name)
|
78
|
+
desired_class = camelize(name)
|
79
|
+
if (suffix = ([""] + (1..10).to_a).find {|e| !base_module.const_defined?(desired_class+e)})
|
80
|
+
base_module.const_set(desired_class+suffix, Module.new)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def which(command)
|
85
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).map {|e| File.join(e, command) }.find {|e| File.exists?(e) }
|
86
|
+
end
|
87
|
+
|
88
|
+
# Recursively merge hash1 with hash2.
|
89
|
+
def recursive_hash_merge(hash1, hash2)
|
90
|
+
hash1.merge(hash2) {|k,o,n| (o.is_a?(Hash)) ? recursive_hash_merge(o,n) : n}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/lib/boson/view.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Boson
|
2
|
+
module View
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def enable
|
6
|
+
Hirb::View.enable(:config_file=>File.join(Boson.repo.config_dir, 'hirb.yml')) unless @enabled
|
7
|
+
@enabled = true
|
8
|
+
end
|
9
|
+
|
10
|
+
def render(object, options={})
|
11
|
+
[nil,false,true].include?(object) ? puts(object.inspect) : render_object(object, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_object(object, options={})
|
15
|
+
options[:class] = options.delete(:as) || :auto_table
|
16
|
+
if object.is_a?(Array) && object.size > 0 && (sort = options.delete(:sort))
|
17
|
+
begin
|
18
|
+
sort_lambda = object[0].is_a?(Hash) ? (object[0][sort].respond_to?(:<=>) ?
|
19
|
+
lambda {|e| e[sort] } : lambda {|e| e[sort].to_s }) :
|
20
|
+
(object[0].send(sort).respond_to?(:<=>) ? lambda {|e| e.send(sort)} :
|
21
|
+
lambda {|e| e.send(sort).to_s })
|
22
|
+
object = object.sort_by &sort_lambda
|
23
|
+
object = object.reverse if options[:reverse_sort]
|
24
|
+
rescue NoMethodError, ArgumentError
|
25
|
+
$stderr.puts "Sort failed with nonexistant method '#{sort}'"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
Hirb::Console.render_output(object, options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
module Boson
|
4
|
+
class ArgumentInspectorTest < Test::Unit::TestCase
|
5
|
+
context "scrape_with_text" do
|
6
|
+
def args_from(file_string)
|
7
|
+
ArgumentInspector.scrape_with_text(file_string, "blah")
|
8
|
+
end
|
9
|
+
|
10
|
+
test "parses arguments with no spacing" do
|
11
|
+
args_from("def bong; end\ndef blah(arg1,arg2='val2')\nend").should == [["arg1"], ['arg2', "'val2'"]]
|
12
|
+
end
|
13
|
+
|
14
|
+
test "parses arguments with spacing" do
|
15
|
+
args_from("\t def blah( arg1=val1, arg2 = val2)").should == [["arg1","val1"], ["arg2", "val2"]]
|
16
|
+
end
|
17
|
+
|
18
|
+
test "parses arguments without parenthesis" do
|
19
|
+
args_from(" def blah arg1, arg2, arg3={}").should == [['arg1'], ['arg2'], ['arg3','{}']]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "scrape_with_eval" do
|
24
|
+
def args_from(string)
|
25
|
+
# methods need options to have their args parsed with ArgumentInspector
|
26
|
+
string.gsub!(/(def blah)/, 'options :a=>1; \1')
|
27
|
+
Inspector.enable
|
28
|
+
::Boson::Commands::Aaa.module_eval(string)
|
29
|
+
Inspector.disable
|
30
|
+
MethodInspector.store[:method_args]['blah']
|
31
|
+
end
|
32
|
+
|
33
|
+
before(:all) { eval "module ::Boson::Commands::Aaa; end"; }
|
34
|
+
before(:each) { MethodInspector.mod_store[::Boson::Commands::Aaa] = {} }
|
35
|
+
|
36
|
+
test "determines arguments with literal defaults" do
|
37
|
+
args_from("def blah(arg1,arg2='val2'); end").should == [['arg1'], ['arg2','val2']]
|
38
|
+
end
|
39
|
+
|
40
|
+
test "determines splat arguments" do
|
41
|
+
args_from("def blah(arg1, *args); end").should == [['arg1'], ["*args"]]
|
42
|
+
end
|
43
|
+
|
44
|
+
test "determines arguments with local values before a method" do
|
45
|
+
body = "AWESOME='awesome'; def sweet; 'ok'; end; def blah(arg1=AWESOME, arg2=sweet); end"
|
46
|
+
args_from(body).should == [['arg1', 'awesome'], ['arg2', 'ok']]
|
47
|
+
end
|
48
|
+
|
49
|
+
test "doesn't get arguments with local values after a method" do
|
50
|
+
args_from("def blah(arg1=nope) end; def nope; 'nope'; end").should == nil
|
51
|
+
end
|
52
|
+
|
53
|
+
test "doesn't determine arguments of a private method" do
|
54
|
+
args_from("private; def blah(arg1,arg2); end").should == nil
|
55
|
+
end
|
56
|
+
|
57
|
+
test "doesn't determine arguments if an error occurs" do
|
58
|
+
args_from("def blah(arg1,arg2=raise); end").should == nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|