ri_for 0.3.0

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
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require 'jeweler'
2
+ Jeweler::Tasks.new do |s|
3
+ s.name = %q{ri_for}
4
+ s.authors = ["Roger Pack"]
5
+ s.description = s.summary = %q{ruby method describer to make it possible to inspect methods [rdoc, signature, etc.] at runtime, for example while debugging.}
6
+ s.email = ["rogerdpack@gmail.comm"]
7
+
8
+ s.homepage = %q{http://github.com/rogerdpack/method_describer}
9
+ s.add_dependency(%q<rdoc>, [">= 2.3"]) # for sane ri lookup times
10
+ s.add_dependency(%q<require_all>, [">= 1.1"]) # require_rel
11
+ s.add_dependency(%q<rdp-arguments>, [">= 0.6.4"])
12
+ s.add_dependency(%q<sane>, ['>= 0.1.2'])
13
+ s.add_dependency(%q<ParseTree>) # these next two for 1.8 only...
14
+ s.add_dependency(%q<ruby2ruby>)
15
+ s.add_development_dependency("rubydoctest")
16
+ end
17
+
data/TODO ADDED
@@ -0,0 +1 @@
1
+ see issues
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.0
@@ -0,0 +1,31 @@
1
+ require_rel 'method_ri'
2
+
3
+ class Class
4
+ # just runs ri against the class, outputs a big
5
+ def desc_class options = {}
6
+ # want_output = false, verbose = false
7
+ begin
8
+ puts "begin RI"
9
+ RDoc::RI::Driver.run [to_s, '--no-pager']
10
+ puts 'end ri'
11
+ rescue SystemExit
12
+ # not found
13
+ end
14
+
15
+ class_methods = methods(false)
16
+ for ancestor in ancestors[1..-1] # skip the first one, which is yourself
17
+ class_methods -= ancestor.methods(false)
18
+ end
19
+
20
+ doc = []
21
+ doc << to_s
22
+ doc += ["non inherited methods:", instance_methods(false).sort.join(", ")]
23
+ doc += ['non inherited class methods:', class_methods.sort.join(', ')]
24
+ doc += ["ancestors:", ancestors.join(', ')] if options[:verbose]
25
+ doc += ["Constants (possible sub classes):", constants.join(', ')] if constants.length > 0 && options[:verbose]
26
+ puts doc
27
+ doc if options[:want_output]
28
+ end
29
+
30
+ end
31
+
@@ -0,0 +1,20 @@
1
+ =begin rdoc
2
+ add method methods2 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 methods2 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,176 @@
1
+ require 'rubygems'
2
+ require 'rdoc'
3
+ require 'rdoc/ri/driver'
4
+ require 'sane'
5
+
6
+ if RUBY_VERSION < '1.9'
7
+ require 'ruby2ruby'
8
+ require 'parse_tree'
9
+ gem 'rdp-arguments' # TODO why is this necessary?
10
+ require 'arguments' # rogerdpack-arguments
11
+ end
12
+
13
+ module SourceLocationDesc
14
+
15
+ # add a Method#desc which spits out all it knows about that method
16
+ # ri, location, local ri, etc.
17
+ # TODO does this work with class methods?
18
+ def ri options = {}
19
+ want_just_summary = options[:want_just_summary]
20
+ want_the_description_returned = options[:want_the_description_returned]
21
+ doc = []
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} arity #{arity}"
59
+ sig = "sig: #{full_name} arity: #{arity}"
60
+ doc << sig
61
+ param_string = sig
62
+
63
+ # now gather up any other information we now about it, in case there are no rdocs, so we can see it early...
64
+
65
+ if !(respond_to? :source_location)
66
+ # pull out names for 1.8
67
+ begin
68
+ klass = eval(class_name)
69
+ # 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
70
+ if joiner == '#'
71
+ raw_code = ParseTree.new.parse_tree_for_method(klass, method_name)
72
+ else
73
+ raw_code = ParseTree.new.parse_tree_for_method(klass.singleton_class, method_name)
74
+ end
75
+ doc << Ruby2Ruby.new.process(ParseTree.new.process(raw_code))
76
+
77
+ args = Arguments.names(klass, method_name, false) rescue Arguments.names(klass.singleton_class, method_name, false)
78
+ out = []
79
+ args.each{|arg_pair|
80
+ out << arg_pair.join(' = ')
81
+ } if args
82
+ out = out.join(', ')
83
+ param_string = out
84
+ return out if want_just_summary
85
+
86
+ param_string = "Parameters: #{method_name}(" + out + ")"
87
+ doc << param_string unless want_the_description_returned
88
+ rescue Exception => e
89
+ doc << "appears to be a c method"
90
+ puts "fail to parse tree: #{class_name} #{e} #{e.backtrace}" if $VERBOSE
91
+ end
92
+ else
93
+ # 1.9.x
94
+ file, line = source_location
95
+ param_string = to_s
96
+ if file
97
+ # then it's a pure ruby method
98
+ all_lines = File.readlines(file)
99
+ head_and_sig = all_lines[0...line]
100
+ sig = head_and_sig[-1]
101
+ head = head_and_sig[0..-2]
102
+
103
+ doc << sig
104
+ head.reverse_each do |line|
105
+ break unless line =~ /^\s*#(.*)/
106
+ doc.unshift " " + $1.strip
107
+ end
108
+ doc.unshift " at #{file}:#{line}"
109
+
110
+ # now the real code will end with 'end' same whitespace as the first
111
+ sig_white_space = sig.scan(/\W+/)[0]
112
+ body = all_lines[line..-1]
113
+ body.each{|line|
114
+ doc << line
115
+ if line.start_with?(sig_white_space + "end")
116
+ break
117
+ end
118
+ }
119
+ already_got_ri = true
120
+ param_string = sig
121
+ return sig + "\n" + head[0] if want_just_summary
122
+ else
123
+ doc << 'appears to be a c method'
124
+ end
125
+ if respond_to? :parameters
126
+ doc << "Original code signature: %s" % sig.to_s.strip if sig
127
+ doc << "#parameters signature: %s( %p )" % [name, parameters]
128
+ end
129
+ end
130
+
131
+ puts doc # always output it since RI does currently [todo make optional I suppose, and non out-putty]
132
+
133
+
134
+ # now run default RI for it
135
+ begin
136
+ puts 'Searching ri for ' + full_name + "..."
137
+ RDoc::RI::Driver.run [full_name, '--no-pager'] unless want_just_summary
138
+ rescue *[StandardError, SystemExit]
139
+ # not found
140
+ ensure
141
+ puts '(end ri)'
142
+ end unless already_got_ri
143
+
144
+ if want_the_description_returned # give them something they can examine
145
+ doc
146
+ else
147
+ param_string # one liner
148
+ end
149
+ end
150
+
151
+ alias :desc :ri
152
+ end
153
+
154
+ class Method; include SourceLocationDesc; end
155
+ class UnboundMethod; include SourceLocationDesc; end
156
+
157
+ # TODO mixin from a separate module
158
+ class Object
159
+ # currently rather verbose, but will attempt to describe all it knows about a method
160
+ def ri_for name, options = {}
161
+ if self.is_a?(Class) || self.is_a?(Module)
162
+ # i.e. String.strip
163
+ begin
164
+ instance_method(name).ri(options)
165
+ rescue NameError => e #allows for Class.instance_method_name
166
+ puts e, e.backtrace
167
+ method(name).ri(options)
168
+ end
169
+ else
170
+ method(name).desc(options)
171
+ end
172
+ end
173
+ end
174
+
175
+ # attribution
176
+ # originally gleaned from http://p.ramaze.net/17901
data/lib/ri_for.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'sane'
2
+ require_rel 'ri_for'
@@ -0,0 +1,51 @@
1
+ # this comment should never be shown
2
+ module M
3
+ def go_here
4
+ 345
5
+ end
6
+ end
7
+
8
+ class A
9
+ def self.inspect
10
+ "A(id: integer, b: integer)"
11
+ end
12
+ # this should never be shown with go2
13
+ def go
14
+ 33
15
+ end
16
+ # some suh-weet rdoc
17
+ def self.go2
18
+ 34
19
+ end
20
+
21
+ include M
22
+ end
23
+
24
+
25
+
26
+ class B
27
+ def self.go2
28
+ 35
29
+ end
30
+ end
31
+
32
+ =begin
33
+ doctest: should parse funky inspect classes [railsy], too
34
+
35
+ doctest_require: '../lib/ri_for'
36
+ >> $VERBOSE = true
37
+ >> A.ri_for(:go, :want_the_description_returned => true).join('..')
38
+ >> A.ri_for(:go2, :want_the_description_returned => true).join('..')
39
+ >> B.ri_for(:go2, :want_the_description_returned => true).join('..').include?('35')
40
+ => true
41
+ >> RUBY_VERSION > '1.8' || A.ri_for(:go2, :want_the_description_returned => true).join('..').include?('suh-weet rdoc')
42
+ => true
43
+ >> A.ri_for(:go2, :want_the_description_returned => true).join('..').include? 'never be shown'
44
+ => false
45
+
46
+ # dual whammy... TODO do these test provide full coverage?
47
+
48
+ >> RUBY_VERSION > '1.8' || A.ri_for(:go_here, :want_the_description_returned => true).join('..').include?('345')
49
+ >> RUBY_VERSION > '1.8' || A.ri_for(:go_here, :want_the_description_returned => true).join('..').include?('345')
50
+
51
+ =end
@@ -0,0 +1,104 @@
1
+ require 'rubygems'
2
+ require 'ffi'
3
+
4
+ $VERBOSE = true
5
+
6
+ class A
7
+ # a suh-weet rdoc
8
+ def go(a=5)
9
+ a = 33
10
+ end
11
+
12
+ def self.go22(b=5)
13
+ b = 3
14
+ end
15
+ end
16
+
17
+ =begin
18
+ doctest_require: '../lib/ri_for'
19
+ >> $VERBOSE = true
20
+ >> output = A.ri_for(:go, :want_the_description_returned => true).join(' ')
21
+ >> output.include? 'a = 33'
22
+ => true
23
+ >> RUBY_VERSION < '1.9' || output.include?('suh-weet')
24
+ => true
25
+
26
+ >> output = A.new.ri_for(:go, :want_the_description_returned => true).join(' ')
27
+ >> output.include? 'a = 33'
28
+ => true
29
+ >> RUBY_VERSION < '1.9' || output.include?('suh-weet')
30
+ => true
31
+
32
+ >> output = A.ri_for(:go22, :want_the_description_returned => true).join(' ')
33
+ >> output.include? 'b = 3'
34
+ => true
35
+
36
+ it should return you something useful
37
+
38
+ >> A.ri_for(:go22) == nil
39
+ => false
40
+ >> A.ri_for(:go) == nil
41
+ => false
42
+
43
+ it should work with Module, too
44
+
45
+ >> FFI::Library.ri_for(:attach_function) == nil
46
+ => false
47
+
48
+ =end
49
+
50
+
51
+ =begin
52
+ doctest:
53
+
54
+ it should return true if you run it against a "real" class
55
+ >> String.desc_class(:want_output => true).length > 1
56
+ => true
57
+ >> class A; end
58
+ >> A.desc_class(:want_output => true).length > 1
59
+ => true
60
+
61
+ it shouldn't report itself as an ancestor of itself
62
+ >> A.desc_class(:want_output => true).grep(/ancestors/).include? '[A]'
63
+ => false
64
+
65
+ also lists constants
66
+ >> A.desc_class(:want_output => true, :verbose => true).grep(/constants/i)
67
+ => [] # should be none since we didn't add any constants to A
68
+ >> class A; B = 3; end
69
+ >> A.desc_class(:want_output => true, :verbose => true).grep(/constants/i).length
70
+ => 1 # should be none since we didn't add any constants to A
71
+
72
+ should work with sub methods
73
+ >> String.ri_for(:strip)
74
+
75
+ doctest_require: '../lib/ri_for'
76
+ =end
77
+
78
+ =begin
79
+ doctest:
80
+ >> require 'pathname'
81
+
82
+ it should display the name
83
+
84
+ >> Pathname.instance_method(:children).desc(:want_the_description_returned => true).grep(/children/).size > 0
85
+ => true # ["#<UnboundMethod: Pathname#children>"]
86
+
87
+ >> Pathname.instance_method(:children).desc(:want_the_description_returned => true).grep(/Dir.foreach/).size > 0
88
+ => true # the code itself
89
+
90
+ and arity
91
+ >> Pathname.instance_method(:children).desc(:want_the_description_returned => true).grep(/arity/)
92
+ => ["sig: Pathname#children arity -1 arity: -1"]
93
+
94
+ # todo: one that is guaranteed to exit you early [no docs at all ever]
95
+
96
+ wurx with class methods
97
+ >> class A; def self.go(a = 3); a=5; end; end
98
+ >> class A; def go2(a=4) a =7; end; end
99
+ >> A.ri_for(:go)
100
+ >> A.ri_for(:go2)
101
+
102
+ >> File.ri_for :delete
103
+
104
+ =end
data/todo ADDED
@@ -0,0 +1 @@
1
+ see issues
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ri_for
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Roger Pack
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-02 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: rdp-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.6.4
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: 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
+ - !ruby/object:Gem::Dependency
76
+ name: rubydoctest
77
+ type: :development
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ version:
85
+ description: ruby method describer to make it possible to inspect methods [rdoc, signature, etc.] at runtime, for example while debugging.
86
+ email:
87
+ - rogerdpack@gmail.comm
88
+ executables: []
89
+
90
+ extensions: []
91
+
92
+ extra_rdoc_files:
93
+ - README
94
+ - TODO
95
+ files:
96
+ - README
97
+ - Rakefile
98
+ - VERSION
99
+ - lib/ri_for.rb
100
+ - lib/ri_for/class_desc.rb
101
+ - lib/ri_for/kernel_new_methods_list.rb
102
+ - lib/ri_for/method_ri.rb
103
+ - test/test_big_name.rb
104
+ - test/test_method.rb
105
+ - todo
106
+ - TODO
107
+ has_rdoc: true
108
+ homepage: http://github.com/rogerdpack/method_describer
109
+ licenses: []
110
+
111
+ post_install_message:
112
+ rdoc_options:
113
+ - --charset=UTF-8
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: "0"
121
+ version:
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: "0"
127
+ version:
128
+ requirements: []
129
+
130
+ rubyforge_project:
131
+ rubygems_version: 1.3.5
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: ruby method describer to make it possible to inspect methods [rdoc, signature, etc.] at runtime, for example while debugging.
135
+ test_files:
136
+ - test/test_big_name.rb
137
+ - test/test_method.rb