system_navigation 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +6 -0
- data/LICENCE.txt +19 -0
- data/README.md +70 -0
- data/VERSION +1 -0
- data/lib/system_navigation.rb +374 -0
- data/lib/system_navigation/ancestor_method_finder.rb +44 -0
- data/lib/system_navigation/array_refinement.rb +21 -0
- data/lib/system_navigation/compiled_method.rb +94 -0
- data/lib/system_navigation/expression_tree.rb +95 -0
- data/lib/system_navigation/instruction_stream.rb +33 -0
- data/lib/system_navigation/instruction_stream/decoder.rb +91 -0
- data/lib/system_navigation/instruction_stream/instruction.rb +180 -0
- data/lib/system_navigation/instruction_stream/instruction/attr_instruction.rb +90 -0
- data/lib/system_navigation/method_hash.rb +49 -0
- data/lib/system_navigation/method_query.rb +98 -0
- data/lib/system_navigation/module_refinement.rb +226 -0
- data/lib/system_navigation/ruby_environment.rb +75 -0
- metadata +117 -0
| @@ -0,0 +1,90 @@ | |
| 1 | 
            +
            class SystemNavigation
         | 
| 2 | 
            +
              class InstructionStream
         | 
| 3 | 
            +
                class Instruction
         | 
| 4 | 
            +
                  class AttrInstruction < Instruction
         | 
| 5 | 
            +
                    def self.parse(method, sym)
         | 
| 6 | 
            +
                      instr = self.new(method)
         | 
| 7 | 
            +
                      self.attrreaderinstr(instr, sym) || self.attrwriterinstr(instr, sym)
         | 
| 8 | 
            +
                    end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    def self.attrreaderinstr(instr, sym)
         | 
| 11 | 
            +
                      instr.accept(AttrReaderInstruction.new(sym)) && instr.parse
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    def self.attrwriterinstr(instr, sym)
         | 
| 15 | 
            +
                      instr.accept(AttrWriterInstruction.new(sym)) && instr.parse
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    attr_accessor :visitor
         | 
| 19 | 
            +
                    attr_reader :method
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    def initialize(method)
         | 
| 22 | 
            +
                      @method = method
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    def accept(visitor)
         | 
| 26 | 
            +
                      visitor.visit(self)
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    def parse
         | 
| 30 | 
            +
                      [self.visitor]
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    private
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    def convert_accessor_to_name(sym)
         | 
| 36 | 
            +
                      sym.to_s.tr('@', '').downcase
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  class AttrReaderInstruction < AttrInstruction
         | 
| 41 | 
            +
                    def initialize(sym)
         | 
| 42 | 
            +
                      @sym = sym
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                    def visit(obj)
         | 
| 46 | 
            +
                      matched = obj.method.original_name.to_s == convert_accessor_to_name(@sym)
         | 
| 47 | 
            +
                      obj.visitor = self if matched
         | 
| 48 | 
            +
                      matched
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    def reads_ivar?(_sym)
         | 
| 52 | 
            +
                      true
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    def writes_ivar?(_sym)
         | 
| 56 | 
            +
                      false
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    def putobjects?(sym)
         | 
| 60 | 
            +
                      @sym == sym
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  class AttrWriterInstruction < AttrInstruction
         | 
| 65 | 
            +
                    def initialize(sym)
         | 
| 66 | 
            +
                      @sym = sym
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    def visit(obj)
         | 
| 70 | 
            +
                      name = obj.method.original_name.to_s
         | 
| 71 | 
            +
                      matched = (name[-1] == '=') && (name[0..-2] == convert_accessor_to_name(@sym))
         | 
| 72 | 
            +
                      obj.visitor = self if matched
         | 
| 73 | 
            +
                      matched
         | 
| 74 | 
            +
                    end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                    def reads_ivar?(_sym)
         | 
| 77 | 
            +
                      false
         | 
| 78 | 
            +
                    end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                    def writes_ivar?(_sym)
         | 
| 81 | 
            +
                      true
         | 
| 82 | 
            +
                    end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    def putobjects?(sym)
         | 
| 85 | 
            +
                      @sym == sym
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
            end
         | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            class SystemNavigation
         | 
| 2 | 
            +
              class MethodHash < Hash
         | 
| 3 | 
            +
                def self.create(**args)
         | 
| 4 | 
            +
                  self.new(args)
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize(based_on: nil, include_super: nil)
         | 
| 9 | 
            +
                  @hash = super()
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  if based_on
         | 
| 12 | 
            +
                    @hash.merge!({
         | 
| 13 | 
            +
                      public: {
         | 
| 14 | 
            +
                        instance: based_on.public_instance_methods(include_super),
         | 
| 15 | 
            +
                        singleton: based_on.singleton_class.public_instance_methods(include_super)
         | 
| 16 | 
            +
                      },
         | 
| 17 | 
            +
                      private: {
         | 
| 18 | 
            +
                        instance: based_on.private_instance_methods(include_super),
         | 
| 19 | 
            +
                        singleton: based_on.singleton_class.private_instance_methods(include_super)
         | 
| 20 | 
            +
                      },
         | 
| 21 | 
            +
                      protected: {
         | 
| 22 | 
            +
                        instance: based_on.protected_instance_methods(include_super),
         | 
| 23 | 
            +
                        singleton: based_on.singleton_class.protected_instance_methods(include_super)
         | 
| 24 | 
            +
                      }
         | 
| 25 | 
            +
                    })
         | 
| 26 | 
            +
                  else
         | 
| 27 | 
            +
                    @hash.merge!(empty_hash)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def as_array
         | 
| 32 | 
            +
                  self.values.map { |h| h[:instance] + h[:singleton] }.flatten.compact
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def empty?
         | 
| 36 | 
            +
                  self == empty_hash
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                protected
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def empty_hash
         | 
| 42 | 
            +
                  {
         | 
| 43 | 
            +
                    public: {instance: [], singleton: []},
         | 
| 44 | 
            +
                    private: {instance: [], singleton: []},
         | 
| 45 | 
            +
                    protected: {instance: [], singleton: []}
         | 
| 46 | 
            +
                  }
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
            end
         | 
| @@ -0,0 +1,98 @@ | |
| 1 | 
            +
            class SystemNavigation
         | 
| 2 | 
            +
              class MethodQuery
         | 
| 3 | 
            +
                def self.execute(collection:, query:, behavior: nil, **rest)
         | 
| 4 | 
            +
                  args = [query]
         | 
| 5 | 
            +
                  args << rest unless rest.empty?
         | 
| 6 | 
            +
                  self.new(collection, behavior).__send__(*args)
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize(collection, behavior)
         | 
| 10 | 
            +
                  @collection = collection
         | 
| 11 | 
            +
                  @behavior = behavior
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def convert_to_methods
         | 
| 15 | 
            +
                  self.instance_and_singleton_do(
         | 
| 16 | 
            +
                    for_instance: proc { |_scope, _selectors, selector|
         | 
| 17 | 
            +
                      @behavior.instance_method(selector)
         | 
| 18 | 
            +
                    },
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    for_singleton: proc { |_scope, _selectors, selector|
         | 
| 21 | 
            +
                      @behavior.singleton_class.instance_method(selector)
         | 
| 22 | 
            +
                    }
         | 
| 23 | 
            +
                  )
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def tupleize
         | 
| 27 | 
            +
                  self.instance_and_singleton_do(
         | 
| 28 | 
            +
                    for_all: proc { |_scope, _selectors, method| [method.name, method] }
         | 
| 29 | 
            +
                  )
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def find_literal(literal:)
         | 
| 33 | 
            +
                  self.instance_and_singleton_do(
         | 
| 34 | 
            +
                    for_all: proc { |_scope, _selectors, method|
         | 
| 35 | 
            +
                      compiled_method = CompiledMethod.compile(method)
         | 
| 36 | 
            +
                      compiled_method.unwrap if compiled_method.has_literal?(literal)
         | 
| 37 | 
            +
                    }
         | 
| 38 | 
            +
                  )
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def all_in_the_same_file?
         | 
| 42 | 
            +
                  self.instance_and_singleton_do(
         | 
| 43 | 
            +
                    for_all: proc { |_scope, _selectors, method| method.source_location[0] }
         | 
| 44 | 
            +
                  ).as_array.uniq.count == 1
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def find_accessing_methods(ivar:, only_set:, only_get:)
         | 
| 48 | 
            +
                  self.instance_and_singleton_do(
         | 
| 49 | 
            +
                    for_all: proc { |_scope, _selectors, method|
         | 
| 50 | 
            +
                      compiled_method = CompiledMethod.compile(method)
         | 
| 51 | 
            +
                      if only_set
         | 
| 52 | 
            +
                        compiled_method.unwrap if compiled_method.writes_field?(ivar)
         | 
| 53 | 
            +
                      elsif only_get
         | 
| 54 | 
            +
                        compiled_method.unwrap if compiled_method.reads_field?(ivar)
         | 
| 55 | 
            +
                      else
         | 
| 56 | 
            +
                        if compiled_method.reads_field?(ivar) ||
         | 
| 57 | 
            +
                           compiled_method.writes_field?(ivar)
         | 
| 58 | 
            +
                          compiled_method.unwrap
         | 
| 59 | 
            +
                        end
         | 
| 60 | 
            +
                      end
         | 
| 61 | 
            +
                    }
         | 
| 62 | 
            +
                  )
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def select_sent_messages
         | 
| 66 | 
            +
                  self.instance_and_singleton_do(
         | 
| 67 | 
            +
                    for_all: proc { |_scope, _selectors, method|
         | 
| 68 | 
            +
                      compiled_method = CompiledMethod.compile(method)
         | 
| 69 | 
            +
                      compiled_method.sent_messages.uniq.map(&:to_sym)
         | 
| 70 | 
            +
                    }
         | 
| 71 | 
            +
                  )
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                protected
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                def instance_and_singleton_do(for_instance: nil, for_singleton: nil, for_all: nil)
         | 
| 77 | 
            +
                  for_instance = for_all && for_singleton = for_all if for_all
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  @collection.inject(MethodHash.new) do |h, (scope, selectors)|
         | 
| 80 | 
            +
                    self.evaluate(callable: for_instance, group: :instance, hash: h,
         | 
| 81 | 
            +
                                  scope: scope, selectors: selectors)
         | 
| 82 | 
            +
                    self.evaluate(callable: for_singleton, group: :singleton, hash: h,
         | 
| 83 | 
            +
                                  scope: scope, selectors: selectors)
         | 
| 84 | 
            +
                    h
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                def evaluate(callable:, group:, hash:, scope:, selectors:)
         | 
| 89 | 
            +
                  return if callable.nil?
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  result = selectors[group].map do |selector|
         | 
| 92 | 
            +
                    callable.call(scope, selectors, selector)
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  hash[scope][group].concat(result)
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
            end
         | 
| @@ -0,0 +1,226 @@ | |
| 1 | 
            +
            class SystemNavigation
         | 
| 2 | 
            +
              module ModuleRefinement
         | 
| 3 | 
            +
                refine Module do
         | 
| 4 | 
            +
                  def with_all_sub_and_superclasses
         | 
| 5 | 
            +
                    Enumerator.new do |y|
         | 
| 6 | 
            +
                      self.with_all_subclasses.each { |klass| y << klass }
         | 
| 7 | 
            +
                      self.with_all_superclasses.each { |klass| y << klass }
         | 
| 8 | 
            +
                    end
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def with_all_subclasses
         | 
| 12 | 
            +
                    Enumerator.new do |y|
         | 
| 13 | 
            +
                      self.all_subclasses.push(self).each { |subclass| y << subclass }
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def all_subclasses
         | 
| 18 | 
            +
                    all_subclasses = []
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    ObjectSpace.each_object(self.singleton_class) do |klass|
         | 
| 21 | 
            +
                      all_subclasses.unshift(klass) if klass != self
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    all_subclasses
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def with_all_superclasses
         | 
| 28 | 
            +
                    if self.superclass
         | 
| 29 | 
            +
                      Enumerator.new do |y|
         | 
| 30 | 
            +
                        y.yield self.superclass
         | 
| 31 | 
            +
                        self.superclass.with_all_superclasses.each { |klass| y << klass }
         | 
| 32 | 
            +
                      end
         | 
| 33 | 
            +
                    else
         | 
| 34 | 
            +
                      []
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def select_methods_that_access(ivar, only_get, only_set)
         | 
| 39 | 
            +
                    own_methods = self.own_methods
         | 
| 40 | 
            +
                    if ancestor_methods.any?
         | 
| 41 | 
            +
                      ancestor_methods.each do |methods|
         | 
| 42 | 
            +
                        own_methods.merge!(methods) do |_group, old_h, new_h|
         | 
| 43 | 
            +
                          old_h.merge!(new_h) { |_key, oldval, newval| oldval | newval }
         | 
| 44 | 
            +
                        end
         | 
| 45 | 
            +
                      end
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    MethodQuery.execute(
         | 
| 49 | 
            +
                      collection: own_methods,
         | 
| 50 | 
            +
                      query: :find_accessing_methods,
         | 
| 51 | 
            +
                      ivar: ivar,
         | 
| 52 | 
            +
                      only_get: only_get,
         | 
| 53 | 
            +
                      only_set: only_set,
         | 
| 54 | 
            +
                      behavior: self).as_array
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def select_methods_that_refer_to(literal)
         | 
| 58 | 
            +
                    MethodQuery.execute(
         | 
| 59 | 
            +
                      collection: self.own_methods,
         | 
| 60 | 
            +
                      query: :find_literal,
         | 
| 61 | 
            +
                      literal: literal,
         | 
| 62 | 
            +
                      behavior: self).as_array
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  def reachable_selectors
         | 
| 66 | 
            +
                    MethodHash.create(based_on: self, include_super: true)
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  def own_selectors
         | 
| 70 | 
            +
                    MethodHash.create(based_on: self, include_super: false)
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  def reachable_methods
         | 
| 74 | 
            +
                    MethodQuery.execute(
         | 
| 75 | 
            +
                      collection: self.reachable_selectors,
         | 
| 76 | 
            +
                      query: :convert_to_methods,
         | 
| 77 | 
            +
                      behavior: self)
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  def own_methods
         | 
| 81 | 
            +
                    MethodQuery.execute(
         | 
| 82 | 
            +
                      collection: self.own_selectors,
         | 
| 83 | 
            +
                      query: :convert_to_methods,
         | 
| 84 | 
            +
                      behavior: self)
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  def reachable_method_hash
         | 
| 88 | 
            +
                    MethodQuery.execute(
         | 
| 89 | 
            +
                      collection: self.reachable_methods,
         | 
| 90 | 
            +
                      query: :tupleize)
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  def own_method_hash
         | 
| 94 | 
            +
                    MethodQuery.execute(
         | 
| 95 | 
            +
                      collection: self.own_methods,
         | 
| 96 | 
            +
                      query: :tupleize)
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  def which_global_selectors_refer_to(literal)
         | 
| 100 | 
            +
                    who = []
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                    self.own_selectors_and_methods do |selector, method|
         | 
| 103 | 
            +
                      if method.has_literal?(literal)
         | 
| 104 | 
            +
                        who << selector
         | 
| 105 | 
            +
                      end
         | 
| 106 | 
            +
                    end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                    who
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  def belongs_to?(gem_name)
         | 
| 112 | 
            +
                    gemspec = Gem::Specification.find_all_by_name(gem_name).last
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                    return false if gemspec.nil? || self.own_selectors.empty?
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                    pattern = %r{(?:/gems/#{gem_name}-#{gemspec.version}/)|(?:/lib/ruby/[[0-9]\.]+/#{gem_name}/)}
         | 
| 117 | 
            +
                    match_location = proc { |locations|
         | 
| 118 | 
            +
                      !!locations.max_by { |_k, value| value }[0].match(pattern)
         | 
| 119 | 
            +
                    }
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                    if self.contains_only_rb_methods?
         | 
| 122 | 
            +
                      if self.all_neighbour_methods?
         | 
| 123 | 
            +
                        self.own_methods.as_array.all? do |method|
         | 
| 124 | 
            +
                          method.source_location.first.match(pattern)
         | 
| 125 | 
            +
                        end
         | 
| 126 | 
            +
                      else
         | 
| 127 | 
            +
                        grouped_locations = self.group_locations_by_path
         | 
| 128 | 
            +
                        return false if grouped_locations.empty?
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                        if grouped_locations.all? { |l| l[0].match(pattern) }
         | 
| 131 | 
            +
                          true
         | 
| 132 | 
            +
                        else
         | 
| 133 | 
            +
                          match_location.call(grouped_locations)
         | 
| 134 | 
            +
                        end
         | 
| 135 | 
            +
                      end
         | 
| 136 | 
            +
                    else
         | 
| 137 | 
            +
                      grouped_locations = self.group_locations_by_path
         | 
| 138 | 
            +
                      grouped_locations.delete_if { |k, v| k.nil? }
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                      if grouped_locations.empty?
         | 
| 141 | 
            +
                        false
         | 
| 142 | 
            +
                      else
         | 
| 143 | 
            +
                        match_location.call(grouped_locations)
         | 
| 144 | 
            +
                      end
         | 
| 145 | 
            +
                    end
         | 
| 146 | 
            +
                  end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  def contains_only_rb_methods?
         | 
| 149 | 
            +
                    self.own_methods.as_array.all? { |method| method.source_location }
         | 
| 150 | 
            +
                  end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                  def all_neighbour_methods?
         | 
| 153 | 
            +
                    MethodQuery.execute(
         | 
| 154 | 
            +
                      collection: self.own_methods,
         | 
| 155 | 
            +
                      query: :all_in_the_same_file?)
         | 
| 156 | 
            +
                  end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                  def group_locations_by_path
         | 
| 159 | 
            +
                    Hash[
         | 
| 160 | 
            +
                      self.own_methods.as_array.map do |method|
         | 
| 161 | 
            +
                        method.source_location && method.source_location.first || nil
         | 
| 162 | 
            +
                      end.group_by(&:itself).map do |key, value|
         | 
| 163 | 
            +
                        [key, value.count]
         | 
| 164 | 
            +
                      end.reject { |k, _v| k.nil? }
         | 
| 165 | 
            +
                    ]
         | 
| 166 | 
            +
                  end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                  def select_matching_methods(string, match_case)
         | 
| 169 | 
            +
                    self.own_methods.as_array.select do |method|
         | 
| 170 | 
            +
                      compiled_method = CompiledMethod.compile(method)
         | 
| 171 | 
            +
                      if compiled_method.source_contains?(string, match_case)
         | 
| 172 | 
            +
                        compiled_method.unwrap
         | 
| 173 | 
            +
                      end
         | 
| 174 | 
            +
                    end
         | 
| 175 | 
            +
                  end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                  def select_c_methods
         | 
| 178 | 
            +
                    self.own_methods.as_array.select do |method|
         | 
| 179 | 
            +
                      compiled_method = CompiledMethod.compile(method)
         | 
| 180 | 
            +
                      if compiled_method.c_method?
         | 
| 181 | 
            +
                        compiled_method.unwrap
         | 
| 182 | 
            +
                      end
         | 
| 183 | 
            +
                    end
         | 
| 184 | 
            +
                  end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                  def select_rb_methods
         | 
| 187 | 
            +
                    self.own_methods.as_array.select do |method|
         | 
| 188 | 
            +
                      compiled_method = CompiledMethod.compile(method)
         | 
| 189 | 
            +
                      if compiled_method.rb_method?
         | 
| 190 | 
            +
                        compiled_method.unwrap
         | 
| 191 | 
            +
                      end
         | 
| 192 | 
            +
                    end
         | 
| 193 | 
            +
                  end
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                  def select_senders_of(message)
         | 
| 196 | 
            +
                    self.own_methods.as_array.select do |method|
         | 
| 197 | 
            +
                      compiled_method = CompiledMethod.compile(method)
         | 
| 198 | 
            +
                      if compiled_method.sends_message?(message)
         | 
| 199 | 
            +
                        compiled_method.unwrap
         | 
| 200 | 
            +
                      end
         | 
| 201 | 
            +
                    end
         | 
| 202 | 
            +
                  end
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                  def all_messages
         | 
| 205 | 
            +
                    MethodQuery.execute(
         | 
| 206 | 
            +
                      collection: self.own_methods,
         | 
| 207 | 
            +
                      query: :select_sent_messages)
         | 
| 208 | 
            +
                  end
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                  def which_selectors_store_into(ivar)
         | 
| 211 | 
            +
                    self.selectors.select do |sel|
         | 
| 212 | 
            +
                      meth = self.instance_method(sel)
         | 
| 213 | 
            +
                      meth.writes_field?(ivar)
         | 
| 214 | 
            +
                    end
         | 
| 215 | 
            +
                  end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                  def ancestor_methods
         | 
| 218 | 
            +
                    AncestorMethodFinder.find_all_ancestors(of: self)
         | 
| 219 | 
            +
                  end
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                  def includes_selector?(selector)
         | 
| 222 | 
            +
                    self.own_selectors.as_array.include?(selector)
         | 
| 223 | 
            +
                  end
         | 
| 224 | 
            +
                end
         | 
| 225 | 
            +
              end
         | 
| 226 | 
            +
            end
         |