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,36 @@
|
|
1
|
+
module Boson::Commands::WebCore #:nodoc:
|
2
|
+
def self.config
|
3
|
+
descriptions = {
|
4
|
+
:install=>"Installs a library by url. Library should then be loaded with load_library.",
|
5
|
+
:browser=>"Opens urls in a browser", :get=>"Gets the body of a url" }
|
6
|
+
commands = descriptions.inject({}) {|h,(k,v)| h[k.to_s] = {:description=>v}; h}
|
7
|
+
commands['install'][:options] = {:name=>:string, :force=>:boolean}
|
8
|
+
{:library_file=>File.expand_path(__FILE__), :commands=>commands}
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(url)
|
12
|
+
%w{uri net/http}.each {|e| require e }
|
13
|
+
Net::HTTP.get(URI.parse(url))
|
14
|
+
rescue
|
15
|
+
raise "Error opening #{url}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def install(url, options={})
|
19
|
+
options[:name] ||= strip_name_from_url(url)
|
20
|
+
return puts("Please give a library name with this url.") unless options[:name]
|
21
|
+
filename = File.join Boson.repo.commands_dir, "#{options[:name]}.rb"
|
22
|
+
return puts("Library name #{options[:name]} already exists. Try a different name.") if File.exists?(filename) && !options[:force]
|
23
|
+
File.open(filename, 'w') {|f| f.write get(url) }
|
24
|
+
puts "Saved to #{filename}."
|
25
|
+
end
|
26
|
+
|
27
|
+
# non-mac users should override this with the launchy gem
|
28
|
+
def browser(*urls)
|
29
|
+
system('open', *urls)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def strip_name_from_url(url)
|
34
|
+
url[/\/([^\/.]+)(\.[a-z]+)?$/, 1]
|
35
|
+
end
|
36
|
+
end
|
data/lib/boson/index.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
module Boson
|
3
|
+
module Index
|
4
|
+
extend self
|
5
|
+
attr_reader :libraries, :commands
|
6
|
+
|
7
|
+
def read_and_transfer(ignored_libraries=[])
|
8
|
+
read
|
9
|
+
existing_libraries = (Boson.libraries.map {|e| e.name} + ignored_libraries).uniq
|
10
|
+
Boson.libraries += @libraries.select {|e| !existing_libraries.include?(e.name)}
|
11
|
+
existing_commands = Boson.commands.map {|e| e.name} #td: consider namespace
|
12
|
+
Boson.commands += @commands.select {|e| !existing_commands.include?(e.name) && !ignored_libraries.include?(e.lib)}
|
13
|
+
end
|
14
|
+
|
15
|
+
def update(options={})
|
16
|
+
options[:all] = true if !exists? && !options.key?(:all)
|
17
|
+
libraries_to_update = options[:all] ? Runner.all_libraries : changed_libraries
|
18
|
+
read_and_transfer(libraries_to_update)
|
19
|
+
if options[:verbose]
|
20
|
+
puts options[:all] ? "Generating index for all #{libraries_to_update.size} libraries. Patience ... is a bitch" :
|
21
|
+
(libraries_to_update.empty? ? "No libraries indexed" :
|
22
|
+
"Indexing the following libraries: #{libraries_to_update.join(', ')}")
|
23
|
+
end
|
24
|
+
Manager.load(libraries_to_update, options.merge(:index=>true)) unless libraries_to_update.empty?
|
25
|
+
write
|
26
|
+
end
|
27
|
+
|
28
|
+
def exists?
|
29
|
+
File.exists? marshal_file
|
30
|
+
end
|
31
|
+
|
32
|
+
def write
|
33
|
+
save_marshal_index Marshal.dump([Boson.libraries, Boson.commands, latest_hashes])
|
34
|
+
end
|
35
|
+
|
36
|
+
def save_marshal_index(marshal_string)
|
37
|
+
File.open(marshal_file, 'w') {|f| f.write marshal_string }
|
38
|
+
end
|
39
|
+
|
40
|
+
def read
|
41
|
+
return if @read
|
42
|
+
@libraries, @commands, @lib_hashes = exists? ? Marshal.load(File.read(marshal_file)) : [[], [], {}]
|
43
|
+
set_latest_namespaces
|
44
|
+
@read = true
|
45
|
+
end
|
46
|
+
|
47
|
+
# get latest namespaces from config files
|
48
|
+
def set_latest_namespaces
|
49
|
+
namespace_libs = Boson.repo.config[:auto_namespace] ? @libraries.map {|e| [e.name, {:namespace=>true}]} :
|
50
|
+
Boson.repo.config[:libraries].select {|k,v| v && v[:namespace] }
|
51
|
+
lib_commands = @commands.inject({}) {|t,e| (t[e.lib] ||= []) << e; t }
|
52
|
+
namespace_libs.each {|name, hash|
|
53
|
+
if (lib = @libraries.find {|l| l.name == name})
|
54
|
+
lib.namespace = (hash[:namespace] == true) ? lib.clean_name : hash[:namespace]
|
55
|
+
(lib_commands[lib.name] || []).each {|e| e.namespace = lib.namespace }
|
56
|
+
end
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def namespaces
|
61
|
+
@libraries.map {|e| e.namespace }.compact
|
62
|
+
end
|
63
|
+
|
64
|
+
def all_main_methods
|
65
|
+
@commands.reject {|e| e.namespace }.map {|e| [e.name, e.alias]}.flatten.compact + namespaces
|
66
|
+
end
|
67
|
+
|
68
|
+
def marshal_file
|
69
|
+
File.join(Boson.repo.config_dir, 'index.marshal')
|
70
|
+
end
|
71
|
+
|
72
|
+
def find_library(command)
|
73
|
+
read
|
74
|
+
namespace_command = command.split('.')[0]
|
75
|
+
if (lib = @libraries.find {|e| e.namespace == namespace_command })
|
76
|
+
lib.name
|
77
|
+
elsif (cmd = Command.find(command, @commands))
|
78
|
+
cmd.lib
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def changed_libraries
|
83
|
+
read
|
84
|
+
latest_hashes.select {|lib, hash| @lib_hashes[lib] != hash}.map {|e| e[0]}
|
85
|
+
end
|
86
|
+
|
87
|
+
def latest_hashes
|
88
|
+
Runner.all_libraries.inject({}) {|h, e|
|
89
|
+
lib_file = FileLibrary.library_file(e, Boson.repo.dir)
|
90
|
+
h[e] = Digest::MD5.hexdigest(File.read(lib_file)) if File.exists?(lib_file)
|
91
|
+
h
|
92
|
+
}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Boson
|
2
|
+
# Scrapes and processes method metadata with the inspectors (MethodInspector, CommentInspector
|
3
|
+
# and ArgumentInspector) and hands off the usable data to FileLibrary objects.
|
4
|
+
module Inspector
|
5
|
+
extend self
|
6
|
+
attr_reader :enabled
|
7
|
+
|
8
|
+
# Enable scraping by overridding method_added to snoop on a library while it's
|
9
|
+
# loading its methods.
|
10
|
+
def enable
|
11
|
+
@enabled = true
|
12
|
+
body = MethodInspector::METHODS.map {|e|
|
13
|
+
%[def #{e}(val)
|
14
|
+
Boson::MethodInspector.#{e}(self, val)
|
15
|
+
end]
|
16
|
+
}.join("\n") +
|
17
|
+
%[
|
18
|
+
def new_method_added(method)
|
19
|
+
Boson::MethodInspector.new_method_added(self, method)
|
20
|
+
end
|
21
|
+
|
22
|
+
alias_method :_old_method_added, :method_added
|
23
|
+
alias_method :method_added, :new_method_added
|
24
|
+
]
|
25
|
+
::Module.module_eval body
|
26
|
+
end
|
27
|
+
|
28
|
+
# Disable scraping method data.
|
29
|
+
def disable
|
30
|
+
::Module.module_eval %[
|
31
|
+
Boson::MethodInspector::METHODS.each {|e| remove_method e }
|
32
|
+
alias_method :method_added, :_old_method_added
|
33
|
+
]
|
34
|
+
@enabled = false
|
35
|
+
end
|
36
|
+
|
37
|
+
# Adds method data scraped for the library's module to the library's commands.
|
38
|
+
def add_method_data_to_library(library)
|
39
|
+
@commands_hash = library.commands_hash
|
40
|
+
@library_file = library.library_file
|
41
|
+
MethodInspector.current_module = library.module
|
42
|
+
@store = MethodInspector.store
|
43
|
+
add_method_scraped_data
|
44
|
+
add_comment_scraped_data
|
45
|
+
end
|
46
|
+
|
47
|
+
#:stopdoc:
|
48
|
+
def add_method_scraped_data
|
49
|
+
(MethodInspector::METHODS + [:method_args]).each do |e|
|
50
|
+
key = command_key(e)
|
51
|
+
(@store[e] || []).each do |cmd, val|
|
52
|
+
if no_command_config_for(cmd, key)
|
53
|
+
(@commands_hash[cmd] ||= {})[key] = val
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_comment_scraped_data
|
60
|
+
(@store[:method_locations] || []).select {|k,(f,l)| f == @library_file }.each do |cmd, (file, lineno)|
|
61
|
+
scraped = CommentInspector.scrape(FileLibrary.read_library_file(file), lineno, MethodInspector.current_module)
|
62
|
+
MethodInspector::METHODS.each do |e|
|
63
|
+
if no_command_config_for(cmd, e)
|
64
|
+
(@commands_hash[cmd] ||= {})[command_key(e)] = scraped[e]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# translates from inspector attribute name to command attribute name
|
71
|
+
def command_key(key)
|
72
|
+
{:method_args=>:args, :desc=>:description}[key] || key
|
73
|
+
end
|
74
|
+
|
75
|
+
def no_command_config_for(cmd, attribute)
|
76
|
+
!@commands_hash[cmd] || (@commands_hash[cmd] && !@commands_hash[cmd].key?(attribute))
|
77
|
+
end
|
78
|
+
#:startdoc:
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Extracts arguments and their default values from methods either by
|
2
|
+
# by scraping a method's text or with method_added and brute force eval (thanks to
|
3
|
+
# {eigenclass}[http://eigenclass.org/hiki/method+arguments+via+introspection]).
|
4
|
+
module Boson::ArgumentInspector
|
5
|
+
extend self
|
6
|
+
# Returns same argument arrays as scrape_with_eval but argument defaults haven't been evaluated.
|
7
|
+
def scrape_with_text(file_string, meth)
|
8
|
+
tabspace = "[ \t]"
|
9
|
+
if match = /^#{tabspace}*def#{tabspace}+#{meth}#{tabspace}*($|\(?\s*([^\)]+)\s*\)?\s*$)/.match(file_string)
|
10
|
+
(match.to_a[2] || '').split(/\s*,\s*/).map {|e| e.split(/\s*=\s*/)}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Max number of arguments extracted per method with scrape_with_eval
|
15
|
+
MAX_ARGS = 10
|
16
|
+
# Scrapes non-private methods for argument names and default values.
|
17
|
+
# Returns arguments as array of argument arrays with optional default value as a second element.
|
18
|
+
# ====Examples:
|
19
|
+
# def meth1(arg1, arg2='val', options={}) -> [['arg1'], ['arg2', 'val'], ['options', {}]]
|
20
|
+
# def meth2(*args) -> [['*args']]
|
21
|
+
def scrape_with_eval(meth, klass, object)
|
22
|
+
unless %w[initialize].include?(meth.to_s)
|
23
|
+
return if class << object; private_instance_methods(true) end.include?(meth.to_s)
|
24
|
+
end
|
25
|
+
params, values, arity, num_args = trace_method_args(meth, klass, object)
|
26
|
+
return if local_variables == params # nothing new found
|
27
|
+
format_arguments(params, values, arity, num_args)
|
28
|
+
rescue Exception
|
29
|
+
# puts "#{klass}.#{meth}: #{$!.message}"
|
30
|
+
ensure
|
31
|
+
set_trace_func(nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
# process params + values to return array of argument arrays
|
35
|
+
def format_arguments(params, values, arity, num_args) #:nodoc:
|
36
|
+
params ||= []
|
37
|
+
params = params[0,num_args]
|
38
|
+
params.inject([[], 0]) do |(a, i), x|
|
39
|
+
if Array === values[i]
|
40
|
+
[a << ["*#{x}"], i+1]
|
41
|
+
else
|
42
|
+
if arity < 0 && i >= arity.abs - 1
|
43
|
+
[a << [x, values[i]], i + 1]
|
44
|
+
else
|
45
|
+
[a << [x], i+1]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end.first
|
49
|
+
end
|
50
|
+
|
51
|
+
def trace_method_args(meth, klass, object) #:nodoc:
|
52
|
+
file = line = params = values = nil
|
53
|
+
arity = klass.instance_method(meth).arity
|
54
|
+
set_trace_func lambda{|event, file, line, id, binding, classname|
|
55
|
+
begin
|
56
|
+
if event[/call/] && classname == klass && id == meth
|
57
|
+
params = eval("local_variables", binding)
|
58
|
+
values = eval("local_variables.map{|x| eval(x)}", binding)
|
59
|
+
throw :done
|
60
|
+
end
|
61
|
+
rescue Exception
|
62
|
+
end
|
63
|
+
}
|
64
|
+
if arity >= 0
|
65
|
+
num_args = arity
|
66
|
+
catch(:done){ object.send(meth, *(0...arity)) }
|
67
|
+
else
|
68
|
+
num_args = 0
|
69
|
+
# determine number of args (including splat & block)
|
70
|
+
MAX_ARGS.downto(arity.abs - 1) do |i|
|
71
|
+
catch(:done) do
|
72
|
+
begin
|
73
|
+
object.send(meth, *(0...i))
|
74
|
+
rescue Exception
|
75
|
+
end
|
76
|
+
end
|
77
|
+
# all nils if there's no splat and we gave too many args
|
78
|
+
next if !values || values.compact.empty?
|
79
|
+
k = nil
|
80
|
+
values.each_with_index{|x,j| break (k = j) if Array === x}
|
81
|
+
num_args = k ? k+1 : i
|
82
|
+
break
|
83
|
+
end
|
84
|
+
args = (0...arity.abs-1).to_a
|
85
|
+
catch(:done) do
|
86
|
+
args.empty? ? object.send(meth) : object.send(meth, *args)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
set_trace_func(nil)
|
90
|
+
return [params, values, arity, num_args]
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Boson
|
2
|
+
# Scrapes comments right before a method for its metadata. Metadata attributes are the
|
3
|
+
# same as MethodInspector: desc, options, render_options. Attributes must begin with '@' i.e.:
|
4
|
+
#
|
5
|
+
# # @desc Does foo
|
6
|
+
# # @options :verbose=>true
|
7
|
+
# def foo(options={})
|
8
|
+
#
|
9
|
+
# Some rules about comment attributes:
|
10
|
+
# * Attribute definitions can span multiple lines. When a new attribute starts a line or the comments end
|
11
|
+
# then a definition ends.
|
12
|
+
# * If no @desc is found in the comment block, then the first comment line directly above the method
|
13
|
+
# is assumed to be the value for @desc. This means that no multi-line attribute definitions can occur
|
14
|
+
# without a description since the last line is assumed to be a description.
|
15
|
+
# * options and render_options attributes can take any valid ruby since they're evaled in their module's context.
|
16
|
+
# * desc attribute is not evaled and is simply text to be set as a string.
|
17
|
+
#
|
18
|
+
# This module was inspired by
|
19
|
+
# {pragdave}[http://github.com/pragdavespc/rake/commit/45231ac094854da9f4f2ac93465ed9b9ca67b2da].
|
20
|
+
module CommentInspector
|
21
|
+
extend self
|
22
|
+
EVAL_ATTRIBUTES = [:options, :render_options]
|
23
|
+
|
24
|
+
# Given a method's file string, line number and defining module, returns a hash
|
25
|
+
# of attributes defined for that method.
|
26
|
+
def scrape(file_string, line, mod, attribute=nil)
|
27
|
+
hash = scrape_file(file_string, line) || {}
|
28
|
+
hash.select {|k,v| v && (attribute.nil? || attribute == k) }.each do |k,v|
|
29
|
+
hash[k] = EVAL_ATTRIBUTES.include?(k) ? eval_comment(v.join(' '), mod) : v.join(' ')
|
30
|
+
end
|
31
|
+
attribute ? hash[attribute] : hash
|
32
|
+
end
|
33
|
+
|
34
|
+
#:stopdoc:
|
35
|
+
def eval_comment(value, mod)
|
36
|
+
value = "{#{value}}" if !value[/^\s*\{/] && value[/=>/]
|
37
|
+
begin mod.module_eval(value); rescue(Exception); nil end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Scrapes a given string for commented @keywords, starting with the line above the given line
|
41
|
+
def scrape_file(file_string, line)
|
42
|
+
lines = file_string.split("\n")
|
43
|
+
saved = []
|
44
|
+
i = line -2
|
45
|
+
while lines[i] =~ /^\s*#\s*(\S+)/ && i >= 0
|
46
|
+
saved << lines[i]
|
47
|
+
i -= 1
|
48
|
+
end
|
49
|
+
|
50
|
+
saved.empty? ? {} : splitter(saved.reverse)
|
51
|
+
end
|
52
|
+
|
53
|
+
def splitter(lines)
|
54
|
+
hash = {}
|
55
|
+
i = 0
|
56
|
+
# to magically make the last comment a description
|
57
|
+
unless lines.any? {|e| e =~ /^\s*#\s*@desc/ }
|
58
|
+
last_line = lines.pop
|
59
|
+
hash[:desc] = (last_line =~ /^\s*#\s*([^@\s].*)/) ? [$1] : nil
|
60
|
+
lines << last_line unless hash[:desc]
|
61
|
+
end
|
62
|
+
|
63
|
+
while i < lines.size
|
64
|
+
while lines[i] =~ /^\s*#\s*@(\w+)\s*(.*)/
|
65
|
+
key = $1.to_sym
|
66
|
+
hash[key] = [$2]
|
67
|
+
i += 1
|
68
|
+
while lines[i] =~ /^\s*#\s*([^@\s].*)/
|
69
|
+
hash[key] << $1
|
70
|
+
i+= 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
i += 1
|
74
|
+
end
|
75
|
+
hash
|
76
|
+
end
|
77
|
+
#:startdoc:
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Boson
|
2
|
+
# Allows for defining method metadata with new_method_added and the
|
3
|
+
# following Module methods:
|
4
|
+
# * desc: Defines a description for a method/command
|
5
|
+
# * options: Defines an OptionParser object for a method's options.
|
6
|
+
# * render_options: Defines an OptionParser object for a method's rendering options.
|
7
|
+
#
|
8
|
+
# These method calls must come immediately before a method i.e.:
|
9
|
+
#
|
10
|
+
# desc "Does foo"
|
11
|
+
# options :verbose=>:boolean
|
12
|
+
# def foo(options={})
|
13
|
+
#
|
14
|
+
# This module also allows for defining method metadata as comments. Although the actual
|
15
|
+
# scraping of comments is handled by CommentInspector, MethodInspector gather's the method
|
16
|
+
# location it needs with with find_method_locations().
|
17
|
+
module MethodInspector
|
18
|
+
extend self
|
19
|
+
attr_accessor :current_module
|
20
|
+
attr_reader :mod_store
|
21
|
+
@mod_store ||= {}
|
22
|
+
METHODS = [:desc, :options, :render_options]
|
23
|
+
|
24
|
+
# The method_added used while scraping method metadata.
|
25
|
+
def new_method_added(mod, meth)
|
26
|
+
return unless mod.name[/^Boson::Commands::/]
|
27
|
+
self.current_module = mod
|
28
|
+
store[:temp] ||= {}
|
29
|
+
METHODS.each do |e|
|
30
|
+
store[e][meth.to_s] = store[:temp][e] if store[:temp][e]
|
31
|
+
end
|
32
|
+
|
33
|
+
if store[:temp].size < METHODS.size
|
34
|
+
store[:method_locations] ||= {}
|
35
|
+
if (result = find_method_locations(caller))
|
36
|
+
store[:method_locations][meth.to_s] = result
|
37
|
+
end
|
38
|
+
end
|
39
|
+
store[:temp] = {}
|
40
|
+
scrape_arguments(meth) if has_inspector_method?(meth, :options) || has_inspector_method?(meth,:render_options)
|
41
|
+
end
|
42
|
+
|
43
|
+
METHODS.each do |e|
|
44
|
+
define_method(e) do |mod, val|
|
45
|
+
store(mod)[e] ||= {}
|
46
|
+
(store(mod)[:temp] ||= {})[e] = val
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Scrapes a method's arguments using ArgumentInspector.
|
51
|
+
def scrape_arguments(meth)
|
52
|
+
store[:method_args] ||= {}
|
53
|
+
|
54
|
+
o = Object.new
|
55
|
+
o.extend(@current_module)
|
56
|
+
# private methods return nil
|
57
|
+
if (val = ArgumentInspector.scrape_with_eval(meth, @current_module, o))
|
58
|
+
store[:method_args][meth.to_s] = val
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns an array of the file and line number at which a method starts using
|
63
|
+
# a caller array. Necessary information for CommentInspector to function.
|
64
|
+
def find_method_locations(stack)
|
65
|
+
if (line = stack.find {|e| e =~ /in `load_source'/ })
|
66
|
+
(line =~ /^(.*):(\d+)/) ? [$1, $2.to_i] : nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#:stopdoc:
|
71
|
+
# Hash of a module's method attributes i.e. descriptions, options by method and then attribute
|
72
|
+
def store(mod=@current_module)
|
73
|
+
@mod_store[mod]
|
74
|
+
end
|
75
|
+
|
76
|
+
def current_module=(mod)
|
77
|
+
@current_module = mod
|
78
|
+
@mod_store[mod] ||= {}
|
79
|
+
end
|
80
|
+
|
81
|
+
def has_inspector_method?(meth, inspector)
|
82
|
+
(store[inspector] && store[inspector].key?(meth.to_s)) || inspector_in_file?(meth.to_s, inspector)
|
83
|
+
end
|
84
|
+
|
85
|
+
def inspector_in_file?(meth, inspector_method)
|
86
|
+
return false if !(file_line = store[:method_locations] && store[:method_locations][meth])
|
87
|
+
if File.exists?(file_line[0]) && (options = CommentInspector.scrape(
|
88
|
+
FileLibrary.read_library_file(file_line[0]), file_line[1], @current_module, inspector_method) )
|
89
|
+
(store[inspector_method] ||= {})[meth] = options
|
90
|
+
end
|
91
|
+
end
|
92
|
+
#:startdoc:
|
93
|
+
end
|
94
|
+
end
|