class SystemNavigation
SystemNavigation
is a class that provides some introspection capabilities. It is based on a Smalltalk class with a similar name. This is the only public class in this library.
@api public @since 0.1.0
Constants
- VAR_TEMPLATE
- VERSION
- VERSION_FILE
The
VERSION
file must be in the root directory of the library.
Public Class Methods
Creates a new instance of SystemNavigation
. It is added for compatibility with Smalltalk users.
@example
require 'system_navigation' sn = SystemNavigation.default
# File lib/system_navigation.rb, line 48 def self.default self.new end
# File lib/system_navigation.rb, line 55 def initialize @environment = SystemNavigation::RubyEnvironment.new end
Public Instance Methods
Query methods for instance/global/class variables in descending (subclasses) and ascending (superclasses) fashion.
@note This is a very costly operation, if you don't provide the from
argument
@note This method does not perform global queries,
only relative to +from+
@example Global scope (start search from BasicObject)
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>]
@example Local scope
class A def initialize @foo = 1 end end class B attr_reader :foo end sn.all_accesses(to: :@foo, from: B) #=> [#<UnboundMethod: B#foo>]
@example 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#initialize>]
@example Only set invokations
class A def initialize @foo = 1 end end class B attr_reader :foo end sn.all_accesses(to: :@foo, only_set: true) #=> [#<UnboundMethod: A#initialize>]
@example Accesses to global variables
sn.all_accesses(to: :$DEBUG) #=> [#<UnboundMethod: Gem::Specification#inspect>, ...]
@example Accesses to class variables
sn.all_accesses(to: :@@required_attributes) #=> [#<UnboundMethod: Gem::Specification#validate>, ...]
@param to [Symbol] The name of the instance/global/class variable to search
for
@param from [Class] The class that limits the scope of the query. Optional.
If omitted, performs the query starting from the top of the object hierarchy (BasicObject)
@param only_get [Boolean] Limits the scope of the query only to methods that
write into the +var+. Optional. Mutually exclusive with +only_set+
@param only_set [Boolean] Limits the scope of the query only to methods that
read from the +var+. Optional. Mutually exclusive with +only_get+
@return [Array<UnboundMethod>] methods that access the var
according to
the given scope
@raise [ArgumentError] if both :only_get
and :only_set
were provided @raise [TypeError] if :from
is not a class @raise [ArgumentError] if :to
is not a Symbol representing either of
these: class variable, instance variable, global variable
# File lib/system_navigation.rb, line 147 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 unless to.match(VAR_TEMPLATE) fail ArgumentError, 'invalid argument for the `to:` attribute' end (from || BasicObject).with_all_sub_and_superclasses.flat_map do |klass| klass.select_methods_that_access(to, only_get, only_set) end end
Get all methods implemented in C.
@example
sn.all_c_methods #=> [#<UnboundMethod: #<Class:Etc>#getlogin>, ...]
@return [Array<UnboundMethod>] all methods that were implemented in C
# File lib/system_navigation.rb, line 394 def all_c_methods self.all_classes_and_modules.flat_map do |klassmod| klassmod.select_c_methods end end
Query methods for literals they call. The supported literals:
* Hashes (only simple Hashes that consist of literals itself) * Arrays (only simple Arrays that consist of literals itself) * +true+, +false+ and +nil+ * Integers (same Integers represented with different notations are treated as the same number) * Floats * Strings * Ranges
@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:
http://ruby-doc.org/core-2.2.2/doc/syntax/literals_rdoc.html
@example Global scope (every behaviour in this process)
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>]
@example Local scope
class A def foo :hello end end class B def bar :hello end end sn.all_calls(on: :hello, from: A) #=> [#<UnboundMethod: A#foo>]
@example Gem
sn.all_calls(on: :singleton, gem: 'system_navigation') #=> [...]
@param on [Boolean, Integer, Float, String, Symbol, Array, Hash, Range,
Regexp] The literal to search for
@param from [Class, Module] 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
@param gem [String] Limits the scope of the query only to methods
that are defined in the RubyGem +gem+ classes and modules. Optional.
@return [Array<UnboundMethod>] methods that call the given literal
@raise [ArgumentError] if both keys (from:
and gem:
) are given
# File lib/system_navigation.rb, line 226 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
Query gems for classes and modules they implement.
@note This method is not precise. If a class/method in the given gem does
not implement any methods, it won't be included in the result.
@example
sn.all_classes_and_modules_in_gem_named('pry-theme') #=> [PryTheme::Preview, ..., PryTheme::Color256]
@!macro [new] gem.param @return [Array<Class, Module>] classes and modules that were defined by
+gem+
# File lib/system_navigation.rb, line 330 def all_classes_and_modules_in_gem_named(gem) self.all_classes_and_modules.select { |klassmod| klassmod.belongs_to?(gem) } end
Query classes for methods they implement.
@example
sn.all_classes_implementing(:~) #=> [Regexp, Bignum, Fixnum]
@!macro [new] selector.param
@param selector [Symbol] the name of the method to be searched for
@return [Array<Class>] classes that implement selector
# File lib/system_navigation.rb, line 252 def all_classes_implementing(selector) self.all_classes.select { |klass| klass.includes_selector?(selector) } end
Query gems for classes they implement.
@note This method is not precise. If a class/method in the given gem does
not implement any methods, it won't be included in the result.
@example
sn.all_classes_in_gem_named('system_navigation') #=> [SystemNavigation::AncestorMethodFinder, ..., SystemNavigation]
@!macro [new] gem.param
@param gem [String] The name of the gem. Case sensitive
@return [Array<Class>] classes that were defined by gem
# File lib/system_navigation.rb, line 297 def all_classes_in_gem_named(gem) self.all_classes.select { |klass| klass.belongs_to?(gem) } end
Query classes and modules for the methods they implement.
@example
sn.all_implementors_of(:select) #=> [Enumerator::Lazy, IO, ..., #<Class:Kernel>]
@!macro selector.param @return [Array<Class, Module>] classes and modules that implement selector
# File lib/system_navigation.rb, line 278 def all_implementors_of(selector) self.all_classes_and_modules.select do |klass| klass.includes_selector?(selector) end end
Get all methods defined in the current Ruby process.
@example
sn.all_methods #=> [#<UnboundMethod: Gem::Dependency#name>, ...]
@return [Array<UnboundMethod>] all methods that exist
# File lib/system_navigation.rb, line 342 def all_methods self.all_classes_and_modules.map do |klassmod| klassmod.own_methods.as_array end.flatten end
Get all methods (public, private, protected) that are defined on behavior
.
@since 0.2.1 @example
sn.all_methods_in_behavior(System) #=> {:public => {:instance => [...], :singleton => [...]}, ...}
@param behavior [Module, Class] where to read methods from @return [Hash] a hash with UnboundMethods, divided into groups and scopes
# File lib/system_navigation.rb, line 454 def all_methods_in_behavior(behavior) behavior.own_methods.to_h end
Search for a string in all classes and modules including their comments and names.
@example
class A def foo :hello_hi end end class B def bar 'hello_hi' end end module M # hello_hi def baz end end sn.all_methods_with_source(string: 'hello_hi') #=> [#<UnboundMethod: B#bar>, #<UnboundMethod: A#foo>, #<UnboundMethod: M#foo>]
@param string [String] The string to be searched for @param match_case [Boolean] Whether to match case or not. Optional @return [Array<UnboundMethod>] methods that matched string
@note This is a very costly operation
# File lib/system_navigation.rb, line 378 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
Query modules for the methods they implement.
@example
sn.all_classes_implementing(:select) #=> [Enumerable, Kernel, #<Module:0x007f56daf92918>]
@!macro selector.param @return [Array<Class>] modules that implement selector
# File lib/system_navigation.rb, line 265 def all_modules_implementing(selector) self.all_modules.select { |mod| mod.includes_selector?(selector) } end
Query gems for modules they implement.
@note This method is not precise. If a class/method in the given gem does
not implement any methods, it won't be included in the result.
@example
sn.all_modules_in_gem_named('pry-theme') #=> [PryTheme::Theme::DefaultAttrs, ..., PryTheme]
@!macro [new] gem.param @return [Array<Class>] modules that were defined by gem
# File lib/system_navigation.rb, line 313 def all_modules_in_gem_named(gem) self.all_modules.select { |mod| mod.belongs_to?(gem) } end
Get all methods implemented in Ruby.
@example
sn.all_rb_methods #=> [#<UnboundMethod: Gem::Dependency#name>, ...]
@return [Array<UnboundMethod>] all methods that were implemented in Ruby
# File lib/system_navigation.rb, line 408 def all_rb_methods self.all_classes_and_modules.flat_map do |klassmod| klassmod.select_rb_methods end end
Get all methods that implement message
.
@example
sn.all_senders_of(:puts) #=> []
@param message [Symbol] The name of the method you're interested in @return [Array<UnboundMethod>] all methods that send +message
# File lib/system_navigation.rb, line 423 def all_senders_of(message) self.all_classes_and_modules.flat_map do |klassmod| klassmod.select_senders_of(message) end end
Get all messages that all methods send.
@example
sn.all_sent_messages #=> [:name, :hash, ..., :type]
@return [Array<Symbol>] all unique messages @note This is a very costly operation
# File lib/system_navigation.rb, line 438 def all_sent_messages self.all_classes_and_modules.flat_map do |klassmod| klassmod.all_messages.as_array end.uniq end