module Police::VmInfo
Public Class Methods
Executes Kernel.‘ without external interferences.
@private This is meant for internal use only.
@param {String} command the command to be executed @return {String} the command’s stdout
# File lib/police/vminfo/objects.rb, line 216 def self._kernel_backtick(command) if defined?(Bundler) Bundler.with_clean_env do Kernel.send :`, command end else Kernel.send :`, command end end
All loaded Ruby classes, obtained by querying ObjectSpace.
Querying ObjectSpace can be painfully slow, especially on non-MRI VMs. Note that all classes are modules, so this is a subset of all_modules.
@return [Array<Classes>] all the Ruby classes
# File lib/police/vminfo/objects.rb, line 60 def self.all_classes ObjectSpace.each_object(Class).to_a end
All methods defined in a class or module.
@param [Module] module_or_class a Class or Module instance @return [Array<UnboundMethod>] all the class and instance methods
defined by the given Class or Module
# File lib/police/vminfo/objects.rb, line 109 def self.all_methods(module_or_class) class_methods(module_or_class) + instance_methods(module_or_class) end
All loaded Ruby modules, obtained by querying ObjectSpace.
Querying ObjectSpace can be painfully slow, especially on non-MRI VMs.
@return [Array<Module>] all the Ruby modules
# File lib/police/vminfo/objects.rb, line 50 def self.all_modules ObjectSpace.each_object(Module).to_a end
All class methods defined in a class or module.
Note: the class methods of a class or module are the instance methods of the class or module’s meta-class.
@param [Module] module_or_class a Class or Module instance @return [Array<UnboundMethod>] all the instance methods defined by the
given Class or Module
# File lib/police/vminfo/objects.rb, line 133 def self.class_methods(module_or_class) # NOTE: this long-winded approach avoids creating new singleton classes method_names = module_or_class.singleton_methods return [] if method_names.empty? singleton_class = module_or_class.singleton_class method_names.tap do |array| array.map! { |name| singleton_class.instance_method name } array.select! { |method| method.owner == singleton_class } end end
Resolves the name of a constant into its value.
@param [String] name a constant name, potentially including the scope
operator ::
@return [Object] the value of the constant with the given name @raise [NameError] no constant with the given name is defined
# File lib/police/vminfo/objects.rb, line 195 def self.constantize(name) segments = name.split '::' value = Object segments.each do |segment| next if segment.empty? value = if value.const_defined? segment value.const_get segment else value.const_missing segment end end value end
The core class methods defined in a core class or module.
@param [Module] module_or_class the module or class whose class methods
will be retrieved; should be one of the core modules / classes in the Ruby VM
@return [Array<UnboundMethod>] the class methods defined by the Ruby VM
# File lib/police/vminfo/objects.rb, line 171 def self.core_class_methods(module_or_class) ruby = Gem.ruby output = _kernel_backtick( %Q|#{ruby} -e 'puts #{module_or_class}.singleton_methods.join("\n")'|) methods = [] method_names = output.split "\n" return [] if method_names.empty? singleton_class = module_or_class.singleton_class output.split("\n").each do |name| method = singleton_class.instance_method name.to_sym next unless method.owner == singleton_class # TODO(pwnall): consider checking for re-defined core methods methods << method end methods end
The classes making up the Ruby VM implementation.
Note that all classes are modules, so this is a subset of core_modules.
@return [Array<Class>] the classes that are present in a vanilla Ruby
environment
# File lib/police/vminfo/objects.rb, line 97 def self.core_classes return @core_classes if @core_classes @core_classes = core_modules.select { |m| m.kind_of? Class } @core_classes.freeze end
The core instance methods defined in a core class or module.
@param [Module] module_or_class the module or class whose instance methods
will be retrieved; should be one of the core modules / classes in the Ruby VM
@return [Array<UnboundMethod>] the instance methods defined by the Ruby VM
# File lib/police/vminfo/objects.rb, line 150 def self.core_instance_methods(module_or_class) ruby = Gem.ruby output = _kernel_backtick( %Q|#{ruby} -e 'puts #{module_or_class}.instance_methods.join("\n")'|) methods = [] output.split("\n").each do |name| method = module_or_class.instance_method name.to_sym next unless method.owner == module_or_class # TODO(pwnall): consider checking for re-defined core methods methods << method end methods end
The modules making up the Ruby VM implementation.
@return [Array<Module>] the modules that are present in a vanilla Ruby
environment
# File lib/police/vminfo/objects.rb, line 68 def self.core_modules return @core_modules if @core_modules ruby = Gem.ruby output = _kernel_backtick( %Q|#{ruby} -e 'puts ObjectSpace.each_object(Module).to_a.join("\n")'|) modules = [] output.split("\n").each do |name| next if name[0] == ?# begin mod = constantize name next unless mod.kind_of? Module modules << mod rescue NameError, LoadError # Delayed loading failure. next end end @core_modules = modules.freeze end
True if the given source code path belongs to a gem.
# File lib/police/vminfo/paths.rb, line 25 def self.gem_path?(path) Gem.default_path.any? { |gem_path| Paths.descendant? path, gem_path } end
All instance methods defined in a class or module.
@param [Module] module_or_class a Class or Module instance @return [Array<UnboundMethod>] all the instance methods defined by the
given Class or Module
# File lib/police/vminfo/objects.rb, line 118 def self.instance_methods(module_or_class) module_or_class.instance_methods.tap do |array| array.map! { |name| module_or_class.instance_method name } array.select! { |method| method.owner == module_or_class } end end
True if the given source code path belongs to the Ruby VM kernel.
# File lib/police/vminfo/paths.rb, line 46 def self.kernel_path?(path) !$LOAD_PATH.any? { |load_path| Paths.descendant? path, load_path } end
Classifies the path to a Ruby file based on its provenance.
@param [Method, UnboundMethod] method VM information about a method;
usually obtained by calling Object#method or Module#instance_method
@return [Symbol] :native for methods defined in a low-level language (C/C++
for MRI and Rubinius, Java for JRuby), :kernel for methods belonging to the core VM code (Rubinius and JRuby), :stdlib for methods in Ruby's standard library, :gem for methods that are implemented in a loaded Ruby gem, and :app for all other methods (presumably defined in the current application)
# File lib/police/vminfo/paths.rb, line 14 def self.method_source(method) location = method.source_location return :native if location.nil? code_path = location.first return :stdlib if stdlib_path?(code_path) return :gem if gem_path?(code_path) return :kernel if kernel_path?(code_path) :app end
All loaded Ruby classes, obtained by walking the constants graph.
Note that all classes are modules, so this is a subset of named_modules.
@return [Array<Module>] the Ruby classes that could be discovered by
searching the constants graph; this should include everything except for anonymous (not assigned to constants) classes
# File lib/police/vminfo/objects.rb, line 41 def self.named_classes named_modules.select { |m| m.kind_of? Class } end
All loaded Ruby modules, obtained by walking the constants graph.
@return [Array<Module>] the Ruby modules that could be discovered by
searching the constants graph; this should include everything except for anonymous (not assigned to constants) classes
# File lib/police/vminfo/objects.rb, line 9 def self.named_modules # NOTE: this is a Set, but we don't want to load the module. explored = { Object => true } left = [Object] until left.empty? namespace = left.pop namespace.constants.each do |const_name| begin const = if namespace.const_defined? const_name namespace.const_get const_name else namespace.const_missing const_name end rescue LoadError, NameError # Delayed loading failure. next end next if explored[const] || !const.kind_of?(Module) explored[const] = true left.push const end end explored.keys.sort_by!(&:name).freeze end
Fingerprint for the Ruby VM’s core and stdlib API.
@return [String] a string that contains the Ruby VM’s engine name and
core version; this should be representative of the
# File lib/police/vminfo/signature.rb, line 8 def self.signature Gem.ruby_engine + Gem.ruby_version.segments[0, 3].join('.') end
True if the given source code path belongs to the Ruby standard library.
# File lib/police/vminfo/paths.rb, line 30 def self.stdlib_path?(path) # NOTE: assuming the convention that all directories are prepended to the # load path throughout a program's execution load_paths = $LOAD_PATH last_gem_index = -1 (load_paths.length - 1).downto(0) do |index| if gem_path? load_paths[index] last_gem_index = index break end end stdlib_paths = load_paths[(last_gem_index + 1)..-1] stdlib_paths.any? { |stdlib_path| Paths.descendant? path, stdlib_path } end