desc_method 0.1.5
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 +101 -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 +186 -0
- metadata +119 -0
data/README
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
A "run time RI for ruby methods", this gem allows you to query for information about objects' methods at runtime--for example within irb or ruby-debug. It reveals everything known about the method. This includes source, ri, arity, rdoc comments (1.9 only), etc.
|
2
|
+
|
3
|
+
For me it has proved quite useful, and I wouldn't do a ruby-debug session without it--you might really like it.
|
4
|
+
|
5
|
+
Examples:
|
6
|
+
|
7
|
+
>> class A;
|
8
|
+
def go(a); end;
|
9
|
+
end
|
10
|
+
|
11
|
+
>> A.desc_method :go
|
12
|
+
#<UnboundMethod: A#go> arity: 1
|
13
|
+
ri for A#go
|
14
|
+
Nothing known about A
|
15
|
+
(end ri)
|
16
|
+
def go(a)
|
17
|
+
# do nothing
|
18
|
+
end
|
19
|
+
Parameters: go(a)
|
20
|
+
|
21
|
+
>> File.desc_method :delete
|
22
|
+
ri for File.delete
|
23
|
+
----------------------------------------------------------- File::delete
|
24
|
+
File.delete(file_name, ...) => integer
|
25
|
+
File.unlink(file_name, ...) => integer
|
26
|
+
|
27
|
+
From Ruby 1.9.1
|
28
|
+
------------------------------------------------------------------------
|
29
|
+
Deletes the named files, returning the number of names passed as
|
30
|
+
arguments. Raises an exception on any error. See also +Dir::rmdir+.
|
31
|
+
|
32
|
+
(end ri)
|
33
|
+
#<Method: File.delete> arity: -1
|
34
|
+
appears to be a c method
|
35
|
+
#parameters signature: delete( [[:rest]] )
|
36
|
+
|
37
|
+
Or (my favorite) a debug session:
|
38
|
+
|
39
|
+
(rdb:1) l=
|
40
|
+
...
|
41
|
+
74 assert(assigns['order'].order_line_items.map(:unit_price).min >= -5)
|
42
|
+
...
|
43
|
+
(rdb:1) desc_method :assert
|
44
|
+
#<Method: StoreControllerTest(Test::Unit::Assertions)#assert> arity: -2
|
45
|
+
ri for Test::Unit::Assertions#assert
|
46
|
+
------------------------------------------ Test::Unit::Assertions#assert
|
47
|
+
assert(boolean, message=nil)
|
48
|
+
|
49
|
+
From gem test-unit-2.0.1
|
50
|
+
------------------------------------------------------------------------
|
51
|
+
Asserts that +boolean+ is not false or nil.
|
52
|
+
|
53
|
+
Example:
|
54
|
+
|
55
|
+
assert [1, 2].include?(5)
|
56
|
+
|
57
|
+
(end ri)
|
58
|
+
def assert(boolean, message = nil)
|
59
|
+
_wrap_assertion do
|
60
|
+
assert_block("assert should not be called with a block.") do
|
61
|
+
(not block_given?)
|
62
|
+
end
|
63
|
+
assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
Parameters: assert(boolean, message = nil)
|
67
|
+
|
68
|
+
Thus, you can look at methods' source/rdocs without having to step into them. Deftly convenient.
|
69
|
+
|
70
|
+
========= How to Install=====
|
71
|
+
$ gem install rogerdpack-desc_method
|
72
|
+
or
|
73
|
+
$ gem install rogerdpack-desc_method --source http://gems.github.com
|
74
|
+
if you don't have gems.github.com as a gem source.
|
75
|
+
|
76
|
+
Usage:
|
77
|
+
>> require 'desc_method'
|
78
|
+
>> Class.desc_method :method_name # class or instance method name
|
79
|
+
...
|
80
|
+
>> some_instance.desc_method :method_name
|
81
|
+
|
82
|
+
Other goodies included:
|
83
|
+
|
84
|
+
Class#desc_class method
|
85
|
+
|
86
|
+
An example:
|
87
|
+
>> Object.desc_class
|
88
|
+
# outputs descriptive info about that class--RI, method list, etc.
|
89
|
+
>> Object.desc_class :verbose => true
|
90
|
+
# outputs RI, method lists including inherited methods, ancestors, all constants etc.
|
91
|
+
|
92
|
+
Kernel#methods has been monkey patched to output a "separator" between its inherited and non inherited methods--i.e.
|
93
|
+
>> instance.methods
|
94
|
+
=> [:first, :second, :after_this_are_inherited>>>>>, :some_inherited_method, :another_inherited_method] # adds in that separator
|
95
|
+
|
96
|
+
I'll probably remove that in a future release since it turns out you can just run Kernel#methods(false) for about much.
|
97
|
+
|
98
|
+
=== Thanks ===
|
99
|
+
This gem wraps for convenience the functionality of Method#source_location, ruby2ruby, et al, and also contains some code inspiration from manvenu, SourceRef (MBARI), and Python's Method#desc. It also wouldn't be useful without irb and the ruby-debug folks. Thanks!
|
100
|
+
|
101
|
+
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,186 @@
|
|
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
|
+
#_dbg
|
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).get_cc_processor>"
|
26
|
+
# or "#<Method: Order(id: integer, order_number: integer)(ActiveRecord::Base).get_cc_processor>"
|
27
|
+
|
28
|
+
string = to_s
|
29
|
+
|
30
|
+
# derive class_name
|
31
|
+
parenthese_count = string.count '('
|
32
|
+
|
33
|
+
if parenthese_count== 1
|
34
|
+
# case #<Method: GiftCertsControllerTest(Test::Unit::TestCase)#get>
|
35
|
+
# case #<Method: Order(id: integer, order_number: integer).get_cc_processor>
|
36
|
+
if string.include? "id: " # TODO huh?
|
37
|
+
string =~ /Method: (.+)\(/
|
38
|
+
else
|
39
|
+
string =~ /\(([^\(]+)\)[\.#]/ # extract out what is between last parentheses
|
40
|
+
end
|
41
|
+
class_name = $1
|
42
|
+
elsif parenthese_count == 0
|
43
|
+
# case "#<Method: A.go>"
|
44
|
+
string =~ /Method: ([^#\.]+)/
|
45
|
+
class_name = $1
|
46
|
+
elsif parenthese_count == 2
|
47
|
+
# case "#<Method: Order(id: integer, order_number: integer)(ActiveRecord::Base).get_cc_processor>"
|
48
|
+
string =~ /\(([^\(]+)\)[\.#]/
|
49
|
+
class_name = $1
|
50
|
+
else
|
51
|
+
raise 'bad ' + string
|
52
|
+
end
|
53
|
+
|
54
|
+
# now get method name, type
|
55
|
+
string =~ /Method: .*([#\.])(.*)>/ # include the # or .
|
56
|
+
joiner = $1
|
57
|
+
method_name = $2
|
58
|
+
full_name = "#{class_name}#{joiner}#{method_name}"
|
59
|
+
puts "sig: #{to_s} arity: #{arity}"
|
60
|
+
# TODO add to doc, I want it before ri for now though, and only once, so not there yet :)
|
61
|
+
|
62
|
+
# now run default RI for it
|
63
|
+
begin
|
64
|
+
puts 'searching ri for ' + full_name + "..."
|
65
|
+
RDoc::RI::Driver.run [full_name, '--no-pager'] unless want_just_summary
|
66
|
+
rescue *[StandardError, SystemExit]
|
67
|
+
# not found
|
68
|
+
end
|
69
|
+
puts '(end ri)'
|
70
|
+
|
71
|
+
# now gather up any other information we now about it, in case there are no rdocs
|
72
|
+
|
73
|
+
if !(respond_to? :source_location)
|
74
|
+
# pull out names for 1.8
|
75
|
+
begin
|
76
|
+
klass = eval(class_name)
|
77
|
+
# 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
|
78
|
+
if joiner == '#'
|
79
|
+
doc << RubyToRuby.new.process(ParseTree.translate(klass, method_name))
|
80
|
+
else
|
81
|
+
doc << RubyToRuby.new.process(ParseTree.translate(klass.singleton_class, method_name))
|
82
|
+
end
|
83
|
+
args = Arguments.names( klass, method_name) rescue Arguments.names(klass.singleton_class, method_name)
|
84
|
+
out = []
|
85
|
+
args.each{|arg_pair|
|
86
|
+
out << arg_pair.join(' = ')
|
87
|
+
} if args
|
88
|
+
out = out.join(', ')
|
89
|
+
return out if want_just_summary
|
90
|
+
|
91
|
+
param_string = "Parameters: #{method_name}(" + out + ")"
|
92
|
+
doc << param_string unless want_the_description_returned
|
93
|
+
rescue Exception => e
|
94
|
+
|
95
|
+
puts "fail to parse tree: #{class_name} #{e} #{e.backtrace}" if $VERBOSE
|
96
|
+
end
|
97
|
+
else
|
98
|
+
# 1.9.x
|
99
|
+
file, line = source_location
|
100
|
+
if file
|
101
|
+
# then it's a pure ruby method
|
102
|
+
doc << "at #{file}:#{line}"
|
103
|
+
all_lines = File.readlines(file)
|
104
|
+
head_and_sig = all_lines[0...line]
|
105
|
+
sig = head_and_sig[-1]
|
106
|
+
head = head_and_sig[0..-2]
|
107
|
+
|
108
|
+
doc << sig
|
109
|
+
head.reverse_each do |line|
|
110
|
+
break unless line =~ /^\s*#(.*)/
|
111
|
+
doc.unshift " " + $1.strip
|
112
|
+
end
|
113
|
+
|
114
|
+
# now the real code will end with 'end' same whitespace as the first
|
115
|
+
sig_white_space = sig.scan(/\W+/)[0]
|
116
|
+
body = all_lines[line..-1]
|
117
|
+
body.each{|line|
|
118
|
+
doc << line
|
119
|
+
if line.start_with?(sig_white_space + "end")
|
120
|
+
break
|
121
|
+
end
|
122
|
+
}
|
123
|
+
# how do I get the rest now?
|
124
|
+
return sig + "\n" + head[0] if want_just_summary
|
125
|
+
else
|
126
|
+
doc << 'appears to be a c method'
|
127
|
+
end
|
128
|
+
param_string = to_s
|
129
|
+
if respond_to? :parameters
|
130
|
+
doc << "Original code signature: %s" % sig.to_s.strip if sig
|
131
|
+
doc << "#parameters signature: %s( %p )" % [name, parameters]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
puts doc # always output it since RI does currently [todo make optional I suppose, and non out-putty]
|
136
|
+
|
137
|
+
if want_the_description_returned # give them something they can examine
|
138
|
+
doc
|
139
|
+
else
|
140
|
+
param_string
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
named_args_for :desc # just for fun, tests use it too, plus it should actually wurk without interfering...I think
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
class Method; include SourceLocationDesc; end
|
149
|
+
class UnboundMethod; include SourceLocationDesc; end
|
150
|
+
|
151
|
+
# TODO mixin from a separate module
|
152
|
+
class Object
|
153
|
+
# currently rather verbose, but will attempt to describe all it knows about a method
|
154
|
+
def desc_method name, options = {}
|
155
|
+
if self.is_a? Class
|
156
|
+
# i.e. String.strip
|
157
|
+
instance_method(name).desc(options) rescue method(name).desc(options) # rescue allows for Class.instance_method_name
|
158
|
+
else
|
159
|
+
method(name).desc(options)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
=begin
|
166
|
+
doctest:
|
167
|
+
>> require 'pathname'
|
168
|
+
it should display the name
|
169
|
+
>> Pathname.instance_method(:children).desc(:want_the_description_returned => true).grep(/children/).size > 0
|
170
|
+
=> true # ["#<UnboundMethod: Pathname#children>"]
|
171
|
+
|
172
|
+
and arity
|
173
|
+
>> Pathname.instance_method(:children).desc(:want_the_description_returned => true).grep(/arity/)
|
174
|
+
=> ["#<UnboundMethod: Pathname#children> arity: -1"]
|
175
|
+
|
176
|
+
# todo: one that is guaranteed to exit you early [no docs at all ever]
|
177
|
+
|
178
|
+
wurx with class methods
|
179
|
+
>> class A; def self.go(a = 3); a=5; end; end
|
180
|
+
>> class A; def go2(a=4) a =7; end; end
|
181
|
+
>> A.desc_method(:go)
|
182
|
+
>> A.desc_method(:go2)
|
183
|
+
|
184
|
+
>> File.desc_method :delete
|
185
|
+
|
186
|
+
=end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: desc_method
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Roger Pack
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-29 00:00:00 -06: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: true
|
91
|
+
homepage: http://github.com/rogerdpack/method_describer
|
92
|
+
licenses: []
|
93
|
+
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: "0"
|
104
|
+
version:
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: "0"
|
110
|
+
version:
|
111
|
+
requirements: []
|
112
|
+
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.3.5
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: ruby method describer to make it possible to inspect methods [rdoc, signature, etc.] at runtime, for example while debugging.
|
118
|
+
test_files: []
|
119
|
+
|