desc_method 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'sane'
3
+ require_rel 'method_describer'
@@ -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
+