Class: SystemNavigation

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/system_navigation.rb,
lib/system_navigation/method_hash.rb,
lib/system_navigation/method_query.rb,
lib/system_navigation/compiled_method.rb,
lib/system_navigation/expression_tree.rb,
lib/system_navigation/array_refinement.rb,
lib/system_navigation/ruby_environment.rb,
lib/system_navigation/module_refinement.rb,
lib/system_navigation/instruction_stream.rb,
lib/system_navigation/ancestor_method_finder.rb,
lib/system_navigation/instruction_stream/decoder.rb,
lib/system_navigation/instruction_stream/instruction.rb,
lib/system_navigation/instruction_stream/instruction/attr_instruction.rb

Defined Under Namespace

Modules: ArrayRefinement, ModuleRefinement Classes: AncestorMethodFinder, CompiledMethod, ExpressionTree, InstructionStream, MethodHash, MethodQuery, RubyEnvironment

Constant Summary collapse

VERSION_FILE =

The VERSION file must be in the root directory of the library.

File.expand_path('../../VERSION', __FILE__)
VERSION =
File.exist?(VERSION_FILE) ?
File.read(VERSION_FILE).chomp : '(could not find VERSION file)'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSystemNavigation

Returns a new instance of SystemNavigation.



38
39
40
# File 'lib/system_navigation.rb', line 38

def initialize
  @environment = SystemNavigation::RubyEnvironment.new
end

Class Method Details

.defaultObject



34
35
36
# File 'lib/system_navigation.rb', line 34

def self.default
  self.new
end

Instance Method Details

#all_accesses(to:, from: nil, only_get: nil, only_set: nil) ⇒ Array<UnboundMethod>

Note:

This is a very costly operation, if you don’t provide the from argument

Query methods for instance variables in descending (subclasses) and ascending (superclasses) fashion.

Examples:

Global

class A
  def initialize
    @foo = 1
  end
end

class B
  attr_reader :foo
end

sn.all_accesses(to: :@foo)
#=> [#<UnboundMethod: A#initialize>, #<UnboundMethod: B#foo>]

Local

class A
  def initialize
    @foo = 1
  end
end

class B
  attr_reader :foo
end

sn.all_accesses(to: :@foo, from: B)
#=> [#<UnboundMethod: B#foo>]

Only get invokations

class A
  def initialize
    @foo = 1
  end
end

class B
  attr_reader :foo
end

sn.all_accesses(to: :@foo, only_get: true)
#=> [#<UnboundMethod: B#foo>]

Parameters:

  • to (Symbol)

    The name of the instance variable to search for

  • from (Class) (defaults to: nil)

    The class that limits the scope of the query. Optional. If omitted, performs the query starting from the top of the object hierarchy (BasicObject)

  • only_get (Boolean) (defaults to: nil)

    Limits the scope of the query only to methods that write into the ivar. Optional. Mutually exclusive with only_set

  • only_set (Boolean) (defaults to: nil)

    Limits the scope of the query only to methods that read from the ivar. Optional. Mutually exclusive with only_get

Returns:

  • (Array<UnboundMethod>)

    methods that access the ivar according to the given scope



100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/system_navigation.rb', line 100

def all_accesses(to:, from: nil, only_get: nil, only_set: nil)
  if only_set && only_get
    fail ArgumentError, 'both only_get and only_set were provided'
  end

  if from && !from.instance_of?(Class)
    fail TypeError, "from must be a Class (#{from.class} given)"
  end

  (from || BasicObject).with_all_sub_and_superclasses.flat_map do |klass|
    klass.select_methods_that_access(to, only_get, only_set)
  end
end

#all_c_methodsArray<UnboundMethod>

Get all methods implemented in C.

Examples:

sn.all_c_methods
#=> [#<UnboundMethod: #<Class:Etc>#getlogin>, ...]

Returns:

  • (Array<UnboundMethod>)

    all methods that were implemented in C



325
326
327
328
329
# File 'lib/system_navigation.rb', line 325

def all_c_methods
  self.all_classes_and_modules.flat_map do |klassmod|
    klassmod.select_c_methods
  end
end

#all_calls(on:, from: nil, gem: nil) ⇒ Array<UnboundMethod>

Note:

This is a very costly operation, if you don’t provide the from argument

Note:

The list of supported literals can be found here: ruby-doc.org/core-2.2.2/doc/syntax/literals_rdoc.html

Query methods for literals they call.

Examples:

Global

class A
  def foo
    :hello
  end
end

class B
  def bar
    :hello
  end
end

sn.all_calls(on: :hello)
#=> [#<UnboundMethod: A#foo>, #<UnboundMethod: B#bar>]

Local

class A
  def foo
    :hello
  end
end

class B
  def bar
    :hello
  end
end

sn.all_calls(on: :hello, from: A)
#=> [#<UnboundMethod: A#foo>]

Gem

sn.all_calls(on: :singleton, gem: 'system_navigation')
#=> [...]

Parameters:

  • on (Boolean, Integer, Float, String, Symbol, Array, Hash, Range, Regexp)

    The literal to search for

  • from (Class, Module) (defaults to: nil)

    The behaviour that limits the scope of the query. If it’s present, the search will be performed from top to bottom (only subclasses). Optional

  • gem (String) (defaults to: nil)

    Limits the scope of the query only to methods that are defined in the RubyGem gem classes and modules. Optional.

Returns:

  • (Array<UnboundMethod>)

    methods that call the given literal



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/system_navigation.rb', line 165

def all_calls(on:, from: nil, gem: nil)
  if from && gem
    fail ArgumentError, 'both from and gem were provided'
  end

  subject = if from
              from.with_all_subclasses
            elsif gem
              self.all_classes_and_modules_in_gem_named(gem)
            else
              self.all_classes_and_modules
            end

  subject.flat_map { |behavior| behavior.select_methods_that_refer_to(on) }
end

#all_classes_and_modules_in_gem_named(gem) ⇒ Array<Class, Module>

Query gems for classes and modules they implement.

Examples:

sn.all_classes_and_modules_in_gem_named('pry-theme')
#=> [PryTheme::Preview, ..., PryTheme::Color256]

Returns:

  • (Array<Class, Module>)

    classes and modules that were defined by gem



260
261
262
# File 'lib/system_navigation.rb', line 260

def all_classes_and_modules_in_gem_named(gem)
  self.all_classes_and_modules.select { |klassmod| klassmod.belongs_to?(gem) }
end

#all_classes_implementing(selector) ⇒ Array<Class>

Query classes for the methods they implement.

Examples:

sn.all_classes_implementing(:~)
#=> [Regexp, Bignum, Fixnum]

Parameters:

  • selector (Symbol)

    the name of the method to be searched for

Returns:

  • (Array<Class>)

    classes that implement selector



191
192
193
# File 'lib/system_navigation.rb', line 191

def all_classes_implementing(selector)
  self.all_classes.select { |klass| klass.includes_selector?(selector) }
end

#all_classes_in_gem_named(gem) ⇒ Array<Class>

Query gems for classes they implement.

Examples:

sn.all_classes_in_gem_named('system_navigation')
#=> [SystemNavigation::AncestorMethodFinder, ..., SystemNavigation]

Parameters:

  • gem (String)

    The name of the gem. Case sensitive

Returns:

  • (Array<Class>)

    classes that were defined by gem



233
234
235
# File 'lib/system_navigation.rb', line 233

def all_classes_in_gem_named(gem)
  self.all_classes.select { |klass| klass.belongs_to?(gem) }
end

#all_implementors_of(selector) ⇒ Array<Class, Module>

Query classes and modules for the methods they implement.

Examples:

sn.all_implementors_of(:select)
#=> [Enumerator::Lazy, IO, ..., #<Class:Kernel>]

Parameters:

  • selector (Symbol)

    the name of the method to be searched for

Returns:

  • (Array<Class, Module>)

    classes and modules that implement selector



217
218
219
220
221
# File 'lib/system_navigation.rb', line 217

def all_implementors_of(selector)
  self.all_classes_and_modules.select do |klass|
    klass.includes_selector?(selector)
  end
end

#all_methodsArray<UnboundMethod>

Get all methods defined in current Ruby process.

Examples:

sn.all_methods
#=> [#<UnboundMethod: Gem::Dependency#name>, ...]

Returns:

  • (Array<UnboundMethod>)

    all methods that exist



272
273
274
275
276
# File 'lib/system_navigation.rb', line 272

def all_methods
  self.all_classes_and_modules.map do |klassmod|
    klassmod.own_methods.as_array
  end.flatten
end

#all_methods_with_source(string:, match_case: true) ⇒ Array<UnboundMethod>

Note:

This is a very costly operation

Search for a string in all classes and modules including their comments and names.

sn.all_methods_with_source(string: ‘hello_hi’) #=> [#<UnboundMethod: B#bar>, #<UnboundMethod: A#foo>, #<UnboundMethod: M#foo>]

Examples:

class A
  def foo
    :hello_hi
  end
end

class B
  def bar
    'hello_hi'
  end
end

module M
  # hello_hi
  def baz
  end
end

Parameters:

  • string (String)

    The string to be searched for

  • match_case (Boolean) (defaults to: true)

    Whether to match case or not. Optional

Returns:

  • (Array<UnboundMethod>)

    methods that matched string



309
310
311
312
313
314
315
# File 'lib/system_navigation.rb', line 309

def all_methods_with_source(string:, match_case: true)
  return [] if string.empty?

  self.all_classes_and_modules.flat_map do |klassmod|
    klassmod.select_matching_methods(string, match_case)
  end
end

#all_modules_implementing(selector) ⇒ Array<Class>

Query modules for the methods they implement.

Examples:

sn.all_classes_implementing(:select)
#=> [Enumerable, Kernel, #<Module:0x007f56daf92918>]

Parameters:

  • selector (Symbol)

    the name of the method to be searched for

Returns:

  • (Array<Class>)

    modules that implement selector



204
205
206
# File 'lib/system_navigation.rb', line 204

def all_modules_implementing(selector)
  self.all_modules.select { |mod| mod.includes_selector?(selector) }
end

#all_modules_in_gem_named(gem) ⇒ Array<Class>

Query gems for modules they implement.

Examples:

sn.all_modules_in_gem_named('pry-theme')
#=> [PryTheme::Theme::DefaultAttrs, ..., PryTheme]

Returns:

  • (Array<Class>)

    modules that were defined by gem



246
247
248
# File 'lib/system_navigation.rb', line 246

def all_modules_in_gem_named(gem)
  self.all_modules.select { |mod| mod.belongs_to?(gem) }
end

#all_rb_methodsArray<UnboundMethod>

Get all methods implemented in Ruby.

Examples:

sn.all_rb_methods
#=> [#<UnboundMethod: Gem::Dependency#name>, ...]

Returns:

  • (Array<UnboundMethod>)

    all methods that were implemented in Ruby



339
340
341
342
343
# File 'lib/system_navigation.rb', line 339

def all_rb_methods
  self.all_classes_and_modules.flat_map do |klassmod|
    klassmod.select_rb_methods
  end
end

#all_senders_of(message) ⇒ Array<UnboundMethod>

Get all methods that implement message.

Examples:

sn.all_senders_of(:puts)
#=> []

Parameters:

  • message (Symbol)

    The name of the method you’re interested in

Returns:

  • (Array<UnboundMethod>)

    all methods that send +message



354
355
356
357
358
# File 'lib/system_navigation.rb', line 354

def all_senders_of(message)
  self.all_classes_and_modules.flat_map do |klassmod|
    klassmod.select_senders_of(message)
  end
end

#all_sent_messagesArray<Symbol>

Note:

This is a very costly operation

Get all messages that all methods send.

Examples:

sn.all_sent_messages
#=> [:name, :hash, ..., :type]

Returns:

  • (Array<Symbol>)

    all unique messages



369
370
371
372
373
# File 'lib/system_navigation.rb', line 369

def all_sent_messages
  self.all_classes_and_modules.flat_map do |klassmod|
    klassmod.all_messages.as_array
  end.uniq
end