Module: Police::VmInfo
- Defined in:
- lib/police/vminfo/paths.rb,
lib/police/vminfo/objects.rb,
lib/police/vminfo/signature.rb
Defined Under Namespace
Modules: Paths
Class Method Summary collapse
-
._kernel_backtick(command) ⇒ String
Executes Kernel.‘ without external interferences.
-
.all_classes ⇒ Array<Classes>
All loaded Ruby classes, obtained by querying ObjectSpace.
-
.all_methods(module_or_class) ⇒ Array<UnboundMethod>
All methods defined in a class or module.
-
.all_modules ⇒ Array<Module>
All loaded Ruby modules, obtained by querying ObjectSpace.
-
.class_methods(module_or_class) ⇒ Array<UnboundMethod>
All class methods defined in a class or module.
-
.constantize(name) ⇒ Object
Resolves the name of a constant into its value.
-
.core_class_methods(module_or_class) ⇒ Array<UnboundMethod>
The core class methods defined in a core class or module.
-
.core_classes ⇒ Array<Class>
The classes making up the Ruby VM implementation.
-
.core_instance_methods(module_or_class) ⇒ Array<UnboundMethod>
The core instance methods defined in a core class or module.
-
.core_modules ⇒ Array<Module>
The modules making up the Ruby VM implementation.
-
.gem_path?(path) ⇒ Boolean
True if the given source code path belongs to a gem.
-
.instance_methods(module_or_class) ⇒ Array<UnboundMethod>
All instance methods defined in a class or module.
-
.kernel_path?(path) ⇒ Boolean
True if the given source code path belongs to the Ruby VM kernel.
-
.method_source(method) ⇒ Symbol
Classifies the path to a Ruby file based on its provenance.
-
.named_classes ⇒ Array<Module>
All loaded Ruby classes, obtained by walking the constants graph.
-
.named_modules ⇒ Array<Module>
All loaded Ruby modules, obtained by walking the constants graph.
-
.signature ⇒ String
Fingerprint for the Ruby VM’s core and stdlib API.
-
.stdlib_path?(path) ⇒ Boolean
True if the given source code path belongs to the Ruby standard library.
Class Method Details
._kernel_backtick(command) ⇒ String
Executes Kernel.‘ without external interferences.
This is meant for internal use only.
216 217 218 219 220 221 222 223 224 |
# 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_classes ⇒ Array<Classes>
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.
60 61 62 |
# File 'lib/police/vminfo/objects.rb', line 60 def self.all_classes ObjectSpace.each_object(Class).to_a end |
.all_methods(module_or_class) ⇒ Array<UnboundMethod>
All methods defined in a class or module.
109 110 111 |
# 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_modules ⇒ Array<Module>
All loaded Ruby modules, obtained by querying ObjectSpace.
Querying ObjectSpace can be painfully slow, especially on non-MRI VMs.
50 51 52 |
# File 'lib/police/vminfo/objects.rb', line 50 def self.all_modules ObjectSpace.each_object(Module).to_a end |
.class_methods(module_or_class) ⇒ Array<UnboundMethod>
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.
133 134 135 136 137 138 139 140 141 142 |
# 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 |
.constantize(name) ⇒ Object
Resolves the name of a constant into its value.
195 196 197 198 199 200 201 202 203 204 205 206 207 |
# 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 |
.core_class_methods(module_or_class) ⇒ Array<UnboundMethod>
The core class methods defined in a core class or module.
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# 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 |
.core_classes ⇒ Array<Class>
The classes making up the Ruby VM implementation.
Note that all classes are modules, so this is a subset of core_modules.
97 98 99 100 101 |
# 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 |
.core_instance_methods(module_or_class) ⇒ Array<UnboundMethod>
The core instance methods defined in a core class or module.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# 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 |
.core_modules ⇒ Array<Module>
The modules making up the Ruby VM implementation.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# 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 |
.gem_path?(path) ⇒ Boolean
True if the given source code path belongs to a gem.
25 26 27 |
# 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 |
.instance_methods(module_or_class) ⇒ Array<UnboundMethod>
All instance methods defined in a class or module.
118 119 120 121 122 123 |
# 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 |
.kernel_path?(path) ⇒ Boolean
True if the given source code path belongs to the Ruby VM kernel.
46 47 48 |
# File 'lib/police/vminfo/paths.rb', line 46 def self.kernel_path?(path) !$LOAD_PATH.any? { |load_path| Paths.descendant? path, load_path } end |
.method_source(method) ⇒ Symbol
Classifies the path to a Ruby file based on its provenance.
14 15 16 17 18 19 20 21 22 |
# 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 |
.named_classes ⇒ Array<Module>
All loaded Ruby classes, obtained by walking the constants graph.
Note that all classes are modules, so this is a subset of named_modules.
41 42 43 |
# File 'lib/police/vminfo/objects.rb', line 41 def self.named_classes named_modules.select { |m| m.kind_of? Class } end |
.named_modules ⇒ Array<Module>
All loaded Ruby modules, obtained by walking the constants graph.
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# 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 |
.signature ⇒ String
Fingerprint for the Ruby VM’s core and stdlib API.
8 9 10 |
# File 'lib/police/vminfo/signature.rb', line 8 def self.signature Gem.ruby_engine + Gem.ruby_version.segments[0, 3].join('.') end |
.stdlib_path?(path) ⇒ Boolean
True if the given source code path belongs to the Ruby standard library.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# 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 |