boson 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|