public
Last active

A little Ruby module for finding the source location where class and methods are defined.

  • Download Gist
where_is.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
module Where
class <<self
attr_accessor :editor
def is_proc(proc)
source_location(proc)
end
def is_method(klass, method_name)
source_location(klass.method(method_name))
end
def is_instance_method(klass, method_name)
source_location(klass.instance_method(method_name))
end
def are_methods(klass, method_name)
are_via_extractor(:method, klass, method_name)
end
def are_instance_methods(klass, method_name)
are_via_extractor(:method, klass, method_name)
end
def is_class(klass)
methods = defined_methods(klass)
file_groups = methods.group_by{|sl| sl[0]}
file_counts = file_groups.map do |file, sls|
lines = sls.map{|sl| sl[1]}
count = lines.size
line = lines.min
{file: file, count: count, line: line}
end
file_counts.sort_by!{|fc| fc[:count]}
source_locations = file_counts.map{|fc| [fc[:file], fc[:line]]}
source_locations
end
# Raises ArgumentError if klass does not have any Ruby methods defined in it.
def is_class_primarily(klass)
source_locations = is_class(klass)
if source_locations.empty?
methods = defined_methods(klass)
raise ArgumentError, (methods.empty? ?
"#{klass} has no methods" :
"#{klass} only has built-in methods (#{methods.size} in total)"
)
end
source_locations[0]
end
def edit(location)
unless location.kind_of?(Array)
raise TypeError,
"only accepts a [file, line_number] array"
end
editor[*location]
location
end
private
def source_location(method)
method.source_location || (
method.to_s =~ /: (.*)>/
$1
)
end
def are_via_extractor(extractor, klass, method_name)
methods = klass.ancestors.map do |ancestor|
method = ancestor.send(extractor, method_name)
if method.owner == ancestor
source_location(method)
else
nil
end
end
methods.compact!
methods
end
def defined_methods(klass)
methods = klass.methods(false).map{|m| klass.method(m)} +
klass.instance_methods(false).map{|m| klass.instance_method(m)}
methods.map!(&:source_location)
methods.compact!
methods
end
end
TextMateEditor = lambda do |file, line|
`mate "#{file}" -l #{line}`
end
NoEditor = lambda do |file, line|
end
@editor = TextMateEditor
end
 
def where_is(klass, method = nil)
Where.edit(if method
begin
Where.is_instance_method(klass, method)
rescue NameError
Where.is_method(klass, method)
end
else
Where.is_class_primarily(klass)
end)
end
 
if __FILE__ == $0
class World
def self.carmen
end
end
where_is(World, :carmen)
end

Nice. Really helped when the class I was investigating had its own 'method' method.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.