Skip to content

Instantly share code, notes, and snippets.

@wtaysom
Created September 23, 2011 08:57

Revisions

  1. wtaysom revised this gist Sep 23, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion where_is.rb
    Original file line number Diff line number Diff line change
    @@ -28,7 +28,7 @@ def is_class(klass)
    file_counts = file_groups.map do |file, sls|
    lines = sls.map{|sl| sl[1]}
    count = lines.size
    line = line.min
    line = lines.min
    {file: file, count: count, line: line}
    end
    file_counts.sort_by!{|fc| fc[:count]}
  2. wtaysom created this gist Sep 23, 2011.
    121 changes: 121 additions & 0 deletions where_is.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,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 = line.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