rogerdpack-desc_method 0.1.2
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/README +63 -0
- data/lib/desc_method.rb +3 -0
- data/lib/method_describer/class_desc.rb +56 -0
- data/lib/method_describer/kernel_new_methods_list.rb +20 -0
- data/lib/method_describer/method_desc.rb +170 -0
- metadata +118 -0
data/README
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
A "ruby method describer"--this gem allows you to introspect methods while within irb or ruby-debug. It reveals everything conceivably known about that method. This includes source, ri, arity, rdoc comments (on 1.9), etc. etc.
|
|
2
|
+
|
|
3
|
+
For me it has proved quite useful, and I wouldn't leave home without it [try it--you might really like it].
|
|
4
|
+
|
|
5
|
+
Examples:
|
|
6
|
+
>>
|
|
7
|
+
class A;
|
|
8
|
+
def go(a); end;
|
|
9
|
+
end
|
|
10
|
+
>> A.desc_method :go
|
|
11
|
+
# it outputs everything it knows about it...arity, source, RI, etc.
|
|
12
|
+
ri for A#go
|
|
13
|
+
Nothing known about A
|
|
14
|
+
(end ri)
|
|
15
|
+
#<UnboundMethod: A#go> arity: 1
|
|
16
|
+
A#go a
|
|
17
|
+
proc { |a|
|
|
18
|
+
# do nothing
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
an example in 1.9:
|
|
22
|
+
>> File.desc_method :delete
|
|
23
|
+
ri for File.delete
|
|
24
|
+
----------------------------------------------------------- File::delete
|
|
25
|
+
File.delete(file_name, ...) => integer
|
|
26
|
+
File.unlink(file_name, ...) => integer
|
|
27
|
+
|
|
28
|
+
From Ruby 1.9.1
|
|
29
|
+
------------------------------------------------------------------------
|
|
30
|
+
Deletes the named files, returning the number of names passed as
|
|
31
|
+
arguments. Raises an exception on any error. See also +Dir::rmdir+.
|
|
32
|
+
|
|
33
|
+
(end ri)
|
|
34
|
+
#<Method: File.delete> arity: -1
|
|
35
|
+
appears to be a c method
|
|
36
|
+
#parameters signature: delete( [[:rest]] )
|
|
37
|
+
|
|
38
|
+
========= Installation/usage:=====
|
|
39
|
+
Installation:
|
|
40
|
+
$ gem install rogerdpack-desc_method
|
|
41
|
+
Usage:
|
|
42
|
+
>> require 'desc_method'
|
|
43
|
+
>> Class.desc_method :method_name # class or instance method name
|
|
44
|
+
...
|
|
45
|
+
>> instance.desc_method :instance_method_name
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
other goodies also included:
|
|
49
|
+
Class.desc_class method # outputs descriptive information about that class--ex:
|
|
50
|
+
>> Object.desc_class
|
|
51
|
+
# outputs RI, methods, etc.
|
|
52
|
+
or
|
|
53
|
+
>> Object.desc_class :verbose => true
|
|
54
|
+
# outputs RI, method lists including inherited methods, ancestors, constants
|
|
55
|
+
|
|
56
|
+
Kernel#method is monkey patched to output a "separator" between its inherited and non inherited methods--i.e.
|
|
57
|
+
>> method
|
|
58
|
+
=> [:first, :second, :after_this_are_inherited>>>>>, :some_inherited_method, :another_inherited_method] # adds in the separator
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
This gem wraps (in a very convenient way) functionality provided by Method#source_location, ruby2ruby, etc. Also thanks to manvenu for some original code inspiration, SourceRef (MBARI), and ruby-debug, who made this possible. Thanks guys!
|
|
62
|
+
|
|
63
|
+
Comments/suggestions welcome rogerdpack on gmail or github
|
data/lib/desc_method.rb
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require_rel 'method_desc'
|
|
2
|
+
class Class
|
|
3
|
+
# just runs ri against the class, outputs a big
|
|
4
|
+
def desc_class options = {}
|
|
5
|
+
# want_output = false, verbose = false
|
|
6
|
+
begin
|
|
7
|
+
puts "begin RI"
|
|
8
|
+
RDoc::RI::Driver.run [to_s, '--no-pager']
|
|
9
|
+
puts 'end ri'
|
|
10
|
+
rescue SystemExit
|
|
11
|
+
# not found
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class_methods = methods(false)
|
|
15
|
+
for ancestor in ancestors[1..-1] # skip the first one, which is yourself
|
|
16
|
+
class_methods -= ancestor.methods(false)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
doc = []
|
|
20
|
+
doc << to_s
|
|
21
|
+
doc += ["non inherited methods:", instance_methods(false).sort.join(", ")]
|
|
22
|
+
doc += ['non inherited class methods:', class_methods.sort.join(', ')]
|
|
23
|
+
doc += ["ancestors:", ancestors.join(', ')] if options[:verbose]
|
|
24
|
+
doc += ["Constants (possible sub classes):", constants.join(', ')] if constants.length > 0 && options[:verbose]
|
|
25
|
+
puts doc
|
|
26
|
+
doc if options[:want_output]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
=begin
|
|
32
|
+
doctest:
|
|
33
|
+
|
|
34
|
+
it should return true if you run it against a "real" class
|
|
35
|
+
>> String.desc_class(:want_output => true).length > 1
|
|
36
|
+
=> true
|
|
37
|
+
>> class A; end
|
|
38
|
+
>> A.desc_class(:want_output => true).length > 1
|
|
39
|
+
=> true
|
|
40
|
+
|
|
41
|
+
it shouldn't report itself as an ancestor of itself
|
|
42
|
+
>> A.desc_class(:want_output => true).grep(/ancestors/).include? '[A]'
|
|
43
|
+
=> false
|
|
44
|
+
|
|
45
|
+
also lists constants
|
|
46
|
+
>> A.desc_class(:want_output => true, :verbose => true).grep(/constants/i)
|
|
47
|
+
=> [] # should be none since we didn't add any constants to A
|
|
48
|
+
>> class A; B = 3; end
|
|
49
|
+
>> A.desc_class(:want_output => true, :verbose => true).grep(/constants/i).length
|
|
50
|
+
=> 1 # should be none since we didn't add any constants to A
|
|
51
|
+
|
|
52
|
+
should work with sub methods
|
|
53
|
+
>> String.desc_method(:strip)
|
|
54
|
+
|
|
55
|
+
doctest_require: '../method_desc'
|
|
56
|
+
=end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
=begin rdoc
|
|
2
|
+
Supplement [monkey patch] Kernel#methods so that it returns lists that are split into two kind of [adds a marker where the inherited methods begin].
|
|
3
|
+
=end
|
|
4
|
+
module Kernel
|
|
5
|
+
alias :methods_old :methods
|
|
6
|
+
def methods all = true
|
|
7
|
+
if all
|
|
8
|
+
# give some marker designating when the inherited methods start
|
|
9
|
+
(public_methods(false) << :"inherited methods after this point >>") + (public_methods(true) - public_methods(false))
|
|
10
|
+
else
|
|
11
|
+
public_methods(false)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if $0 == __FILE__
|
|
17
|
+
class A; end
|
|
18
|
+
puts 'A.methods', A.methods(true).inspect, A.methods(false).inspect
|
|
19
|
+
puts 'A.new.methods', A.new.methods.inspect
|
|
20
|
+
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# originally gleaned from http://p.ramaze.net/17901
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
require 'rdoc'
|
|
4
|
+
require 'rdoc/ri/driver'
|
|
5
|
+
require 'sane'
|
|
6
|
+
begin
|
|
7
|
+
gem 'arguments' # TODO why is this necessary?
|
|
8
|
+
require 'arguments' # rogerdpack-arguments
|
|
9
|
+
rescue LoadError
|
|
10
|
+
require 'arguments' # 1.9
|
|
11
|
+
end
|
|
12
|
+
require 'ruby2ruby'
|
|
13
|
+
|
|
14
|
+
module SourceLocationDesc
|
|
15
|
+
|
|
16
|
+
# add a Method#desc which spits out all it knows about that method
|
|
17
|
+
# ri, location, local ri, etc.
|
|
18
|
+
# TODO does this work with class methods?
|
|
19
|
+
def desc want_just_summary = false, want_the_description_returned = false
|
|
20
|
+
doc = []
|
|
21
|
+
|
|
22
|
+
# to_s is something like "#<Method: String#strip>"
|
|
23
|
+
# or #<Method: GiftCertsControllerTest(Test::Unit::TestCase)#get>
|
|
24
|
+
# or "#<Method: A.go>"
|
|
25
|
+
# or "#<Method: Order(id: integer, order_number: integer, created_on: datetime, shipped_on: datetime, order_user_id: integer, order_status_code_id: integer, notes: text, referer: string, order_shipping_type_id: integer, product_cost: float, shipping_cost: float, tax: float, auth_transaction_id: string, promotion_id: integer, shipping_address_id: integer, billing_address_id: integer, order_account_id: integer).get_cc_processor>"
|
|
26
|
+
|
|
27
|
+
string = to_s
|
|
28
|
+
|
|
29
|
+
if string.include? ')#'
|
|
30
|
+
# case #<Method: GiftCertsControllerTest(Test::Unit::TestCase)#get>
|
|
31
|
+
string =~ /\((.*)\)/ # extract out what is between parentheses for the classname
|
|
32
|
+
class_name = $1
|
|
33
|
+
elsif string.include?( '(' ) && string.include?( ').' )
|
|
34
|
+
# case "Method: Order(id:...).class_method"
|
|
35
|
+
string =~ /Method: (.*)\(/
|
|
36
|
+
class_name = $1
|
|
37
|
+
elsif string =~ /Method: (.*)\..*>/
|
|
38
|
+
# case "#<Method: A.go>"
|
|
39
|
+
class_name = $1
|
|
40
|
+
else
|
|
41
|
+
# case "#<Method: String#strip>"
|
|
42
|
+
string =~ /Method: (.*)#.*/
|
|
43
|
+
class_name = $1
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# now get method name, type
|
|
47
|
+
string =~ /Method: .*([#\.])(.*)>/ # include the # or .
|
|
48
|
+
joiner = $1
|
|
49
|
+
method_name = $2
|
|
50
|
+
full_name = "#{class_name}#{joiner}#{method_name}"
|
|
51
|
+
puts "#{to_s} arity: #{arity}" # TODO add to doc, I want it before ri for now though :)
|
|
52
|
+
|
|
53
|
+
# now run default RI for it
|
|
54
|
+
begin
|
|
55
|
+
puts 'ri for ' + full_name
|
|
56
|
+
RDoc::RI::Driver.run [full_name, '--no-pager'] unless want_just_summary
|
|
57
|
+
rescue *[StandardError, SystemExit]
|
|
58
|
+
# not found
|
|
59
|
+
end
|
|
60
|
+
puts '(end ri)'
|
|
61
|
+
|
|
62
|
+
# now gather up any other information we now about it, in case there are no rdocs
|
|
63
|
+
|
|
64
|
+
if !(respond_to? :source_location)
|
|
65
|
+
# pull out names for 1.8
|
|
66
|
+
begin
|
|
67
|
+
klass = eval(class_name)
|
|
68
|
+
# we don't call to_ruby to overcome ruby2ruby bug http://rubyforge.org/tracker/index.php?func=detail&aid=26891&group_id=1513&atid=5921
|
|
69
|
+
if joiner == '#'
|
|
70
|
+
doc << RubyToRuby.new.process(ParseTree.translate(klass, method_name))
|
|
71
|
+
else
|
|
72
|
+
doc << RubyToRuby.new.process(ParseTree.translate(klass.singleton_class, method_name))
|
|
73
|
+
end
|
|
74
|
+
args = Arguments.names( klass, method_name) rescue Arguments.names(klass.singleton_class, method_name)
|
|
75
|
+
out = []
|
|
76
|
+
args.each{|arg_pair|
|
|
77
|
+
out << arg_pair.join(' = ')
|
|
78
|
+
}
|
|
79
|
+
out = out.join(', ')
|
|
80
|
+
return out if want_just_summary
|
|
81
|
+
|
|
82
|
+
doc << "Parameters: #{method_name}(" + out + ")"
|
|
83
|
+
rescue Exception => e
|
|
84
|
+
puts "fail to parse tree: #{class_name} #{e} #{e.backtrace}" if $VERBOSE
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
# 1.9.x
|
|
88
|
+
file, line = source_location
|
|
89
|
+
if file
|
|
90
|
+
# then it's a pure ruby method
|
|
91
|
+
doc << "at #{file}:#{line}"
|
|
92
|
+
all_lines = File.readlines(file)
|
|
93
|
+
head_and_sig = all_lines[0...line]
|
|
94
|
+
sig = head_and_sig[-1]
|
|
95
|
+
head = head_and_sig[0..-2]
|
|
96
|
+
|
|
97
|
+
doc << sig
|
|
98
|
+
head.reverse_each do |line|
|
|
99
|
+
break unless line =~ /^\s*#(.*)/
|
|
100
|
+
doc.unshift " " + $1.strip
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# now the real code will end with 'end' same whitespace as the first
|
|
104
|
+
sig_white_space = sig.scan(/\W+/)[0]
|
|
105
|
+
body = all_lines[line..-1]
|
|
106
|
+
body.each{|line|
|
|
107
|
+
doc << line
|
|
108
|
+
if line.start_with?(sig_white_space + "end")
|
|
109
|
+
break
|
|
110
|
+
end
|
|
111
|
+
}
|
|
112
|
+
# how do I get the rest now?
|
|
113
|
+
return sig + "\n" + head[0] if want_just_summary
|
|
114
|
+
else
|
|
115
|
+
doc << 'appears to be a c method'
|
|
116
|
+
end
|
|
117
|
+
if respond_to? :parameters
|
|
118
|
+
doc << "Original code signature: %s" % sig.to_s.strip if sig
|
|
119
|
+
doc << "#parameters signature: %s( %p )" % [name, parameters]
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
puts doc # always output it since RI does currently [todo make optional I suppose, and non out-putty]
|
|
124
|
+
|
|
125
|
+
doc if want_the_description_returned # give them something they can examine
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
named_args_for :desc # just for fun, tests use it too, plus it should actually wurk without interfering...I think
|
|
129
|
+
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
class Method; include SourceLocationDesc; end
|
|
133
|
+
class UnboundMethod; include SourceLocationDesc; end
|
|
134
|
+
|
|
135
|
+
# TODO mixin from a separate module
|
|
136
|
+
class Object
|
|
137
|
+
# currently rather verbose, but will attempt to describe all it knows about a method
|
|
138
|
+
def desc_method name, options = {}
|
|
139
|
+
if self.is_a? Class
|
|
140
|
+
# i.e. String.strip
|
|
141
|
+
instance_method(name).desc(options) rescue method(name).desc(options) # rescue allows for Class.instance_method_name
|
|
142
|
+
else
|
|
143
|
+
method(name).desc(options)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
=begin
|
|
150
|
+
doctest:
|
|
151
|
+
>> require 'pathname'
|
|
152
|
+
it should display the name
|
|
153
|
+
>> Pathname.instance_method(:children).desc(:want_the_description_returned => true).grep(/children/).size > 0
|
|
154
|
+
=> true # ["#<UnboundMethod: Pathname#children>"]
|
|
155
|
+
|
|
156
|
+
and arity
|
|
157
|
+
>> Pathname.instance_method(:children).desc(:want_the_description_returned => true).grep(/arity/)
|
|
158
|
+
=> ["#<UnboundMethod: Pathname#children> arity: -1"]
|
|
159
|
+
|
|
160
|
+
# todo: one that is guaranteed to exit you early [no docs at all ever]
|
|
161
|
+
|
|
162
|
+
wurx with class methods
|
|
163
|
+
>> class A; def self.go(a = 3); a=5; end; end
|
|
164
|
+
>> class A; def go2(a=4) a =7; end; end
|
|
165
|
+
>> A.desc_method(:go)
|
|
166
|
+
>> A.desc_method(:go2)
|
|
167
|
+
|
|
168
|
+
>> File.desc_method :delete
|
|
169
|
+
|
|
170
|
+
=end
|
metadata
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rogerdpack-desc_method
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.2
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Roger Pack
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-05-16 00:00:00 -07:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: rdoc
|
|
17
|
+
type: :runtime
|
|
18
|
+
version_requirement:
|
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: "2.3"
|
|
24
|
+
version:
|
|
25
|
+
- !ruby/object:Gem::Dependency
|
|
26
|
+
name: require_all
|
|
27
|
+
type: :runtime
|
|
28
|
+
version_requirement:
|
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: "1.1"
|
|
34
|
+
version:
|
|
35
|
+
- !ruby/object:Gem::Dependency
|
|
36
|
+
name: rogerdpack-arguments
|
|
37
|
+
type: :runtime
|
|
38
|
+
version_requirement:
|
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: "0"
|
|
44
|
+
version:
|
|
45
|
+
- !ruby/object:Gem::Dependency
|
|
46
|
+
name: rogerdpack-sane
|
|
47
|
+
type: :runtime
|
|
48
|
+
version_requirement:
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 0.1.2
|
|
54
|
+
version:
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: ParseTree
|
|
57
|
+
type: :runtime
|
|
58
|
+
version_requirement:
|
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: "0"
|
|
64
|
+
version:
|
|
65
|
+
- !ruby/object:Gem::Dependency
|
|
66
|
+
name: ruby2ruby
|
|
67
|
+
type: :runtime
|
|
68
|
+
version_requirement:
|
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: "0"
|
|
74
|
+
version:
|
|
75
|
+
description: ruby method describer to make it possible to inspect methods [rdoc, signature, etc.] at runtime, for example while debugging.
|
|
76
|
+
email:
|
|
77
|
+
- rogerdpack@gmail.comm
|
|
78
|
+
executables: []
|
|
79
|
+
|
|
80
|
+
extensions: []
|
|
81
|
+
|
|
82
|
+
extra_rdoc_files: []
|
|
83
|
+
|
|
84
|
+
files:
|
|
85
|
+
- README
|
|
86
|
+
- lib/desc_method.rb
|
|
87
|
+
- lib/method_describer/class_desc.rb
|
|
88
|
+
- lib/method_describer/kernel_new_methods_list.rb
|
|
89
|
+
- lib/method_describer/method_desc.rb
|
|
90
|
+
has_rdoc: false
|
|
91
|
+
homepage: http://github.com/rogerdpack/method_describer
|
|
92
|
+
licenses:
|
|
93
|
+
post_install_message:
|
|
94
|
+
rdoc_options: []
|
|
95
|
+
|
|
96
|
+
require_paths:
|
|
97
|
+
- lib
|
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: "0"
|
|
103
|
+
version:
|
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
|
+
requirements:
|
|
106
|
+
- - ">="
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: "0"
|
|
109
|
+
version:
|
|
110
|
+
requirements: []
|
|
111
|
+
|
|
112
|
+
rubyforge_project:
|
|
113
|
+
rubygems_version: 1.3.5
|
|
114
|
+
signing_key:
|
|
115
|
+
specification_version: 2
|
|
116
|
+
summary: ruby method describer to make it possible to inspect methods [rdoc, signature, etc.] at runtime, for example while debugging.
|
|
117
|
+
test_files: []
|
|
118
|
+
|