1 # A little Ruby module for finding the source location where class and methods are defined.
2 # https://gist.github.com/wtaysom/1236979
9 def is_method(klass, method_name)
10 source_location(klass.method(method_name))
13 def is_instance_method(klass, method_name)
14 source_location(klass.instance_method(method_name))
17 def are_methods(klass, method_name)
18 are_via_extractor(:method, klass, method_name)
21 def are_instance_methods(klass, method_name)
22 are_via_extractor(:method, klass, method_name)
26 methods = defined_methods(klass)
27 file_groups = methods.group_by{|sl| sl[0]}
28 file_counts = file_groups.map do |file, sls|
29 lines = sls.map{|sl| sl[1]}
32 {file: file, count: count, line: line}
34 file_counts.sort_by!{|fc| fc[:count]}
35 source_locations = file_counts.map{|fc| [fc[:file], fc[:line]]}
39 # Raises ArgumentError if klass does not have any Ruby methods defined in it.
40 def is_class_primarily(klass)
41 source_locations = is_class(klass)
42 if source_locations.empty?
43 methods = defined_methods(klass)
44 raise ArgumentError, (methods.empty? ?
45 "#{klass} has no methods" :
46 "#{klass} only has built-in methods (#{methods.size} in total)"
53 unless location.kind_of?(Array)
55 "only accepts a [file, line_number] array"
62 def source_location(method)
63 method.source_location || (
64 method.to_s =~ /: (.*)>/
69 def are_via_extractor(extractor, klass, method_name)
70 methods = klass.ancestors.map do |ancestor|
71 method = ancestor.send(extractor, method_name)
72 if method.owner == ancestor
73 source_location(method)
82 def defined_methods(klass)
83 methods = klass.methods(false).map{|m| klass.method(m)} +
84 klass.instance_methods(false).map{|m| klass.instance_method(m)}
85 methods.map!(&:source_location)
92 def where_is(klass, method = nil)
97 Where.is_instance_method(klass, method)
99 Where.is_method(klass, method)
102 Where.is_class_primarily(klass)