class Mirrors::MethodMirror
A MethodMirror
should reflect on methods, but in a more general sense than the Method and UnboundMethod classes in Ruby are able to offer.
In actual execution, a method is pretty much every chunk of code, even loading a file triggers a process not unlike compiling a method (if only for the side-effects). Method mirrors should allow access to the runtime objects, but also to their static representations (bytecode, source, …), their debugging information and statistical information
Public Instance Methods
Queries the method for it's arguments and returns a list of mirrors that hold name and value information.
@return [Array<String>]
# File lib/mirrors/method_mirror.rb, line 75 def arguments @subject.send(:parameters).map { |_, a| a.to_s } end
Return the value the block argument, or nil
@return [String, nil]
# File lib/mirrors/method_mirror.rb, line 45 def block_argument args(:block).first end
Returns the disassembled code if available.
@return [String, nil] human-readable bytedcode dump
# File lib/mirrors/method_mirror.rb, line 138 def bytecode @bytecode ||= iseq.disasm if iseq @bytecode end
@return [String,nil] The pre-definition comment of this method
# File lib/mirrors/method_mirror.rb, line 124 def comment @subject.send(:comment) rescue MethodSource::SourceNotFoundError nil end
@return [ClassMirror] The class this method was originally defined in
# File lib/mirrors/method_mirror.rb, line 38 def defining_class Mirrors.reflect @subject.send(:owner) end
@return [String, nil] The filename, if available
# File lib/mirrors/method_mirror.rb, line 21 def file sl = source_location sl ? sl.first : nil end
Returns the instruction sequence for the method (cached)
# File lib/mirrors/method_mirror.rb, line 131 def iseq @iseq ||= RubyVM::InstructionSequence.of(@subject) end
@return [Fixnum, nil] The source line, if available
# File lib/mirrors/method_mirror.rb, line 27 def line sl = source_location sl && sl.last ? sl.last - 1 : nil end
# File lib/mirrors/method_mirror.rb, line 158 def name @subject.name end
Returns the compiled code if available.
@return [RubyVM::InstructionSequence, nil] native code
# File lib/mirrors/method_mirror.rb, line 154 def native_code RubyVM::InstructionSequence.of(@subject) end
Returns names and values of the optional arguments.
@return [Array<String>, nil]
# File lib/mirrors/method_mirror.rb, line 60 def optional_arguments args(:opt) end
# File lib/mirrors/method_mirror.rb, line 96 def private? visibility?(:private) end
# File lib/mirrors/method_mirror.rb, line 88 def protected? visibility?(:protected) end
# File lib/mirrors/method_mirror.rb, line 92 def public? visibility?(:public) end
# File lib/mirrors/method_mirror.rb, line 162 def references visitor = Mirrors::ReferencesVisitor.new visitor.call(self) visitor.markers end
Returns the name and possibly values of the required arguments
@return [Array<String>]
# File lib/mirrors/method_mirror.rb, line 67 def required_arguments args(:req) end
@return [String] The method name
# File lib/mirrors/method_mirror.rb, line 33 def selector @subject.name.to_s end
Returns the parse tree if available
@return [String, nil] prettified AST
# File lib/mirrors/method_mirror.rb, line 146 def sexp src = source src ? Ripper.sexp(src).pretty_inspect : nil end
@return [String,nil] The source code of this method
# File lib/mirrors/method_mirror.rb, line 117 def source @source ||= unindent(@subject.send(:source)) rescue MethodSource::SourceNotFoundError nil end
Returns a field mirror with name and possibly value of the splat argument, or nil, if there is none to this method.
@return [String, nil]
# File lib/mirrors/method_mirror.rb, line 53 def splat_argument args(:rest).first end
# File lib/mirrors/method_mirror.rb, line 100 def super_method owner = @subject.send(:owner) if owner.is_a?(Class) meth = Mirrors .class_singleton_method(:allocate) .bind(instance) .super_method .unbind else meth = @subject.bind(owner).super_method.unbind end meth ? Mirrors.reflect(meth) : nil end
Is the method :public, :private, or :protected?
@return [String]
# File lib/mirrors/method_mirror.rb, line 82 def visibility return :public if visibility?(:public) return :private if visibility?(:private) :protected end
Private Instance Methods
# File lib/mirrors/method_mirror.rb, line 175 def args(type) args = [] @subject.send(:parameters).select { |t, n| args << n.to_s if t == type } args end
# File lib/mirrors/method_mirror.rb, line 181 def source_location @subject.send(:source_location) end
# File lib/mirrors/method_mirror.rb, line 185 def unindent(str) lines = str.split("\n") return str if lines.empty? indents = lines.map do |line| if line =~ /\S/ line.start_with?(" ") ? line.match(/^ +/).offset(0)[1] : 0 end end indents.compact! if indents.empty? # No lines had any non-whitespace characters. return ([""] * lines.size).join "\n" end min_indent = indents.min return str if min_indent.zero? lines.map { |line| line =~ /\S/ ? line.gsub(/^ {#{min_indent}}/, "") : line }.join("\n") end
# File lib/mirrors/method_mirror.rb, line 170 def visibility?(type) list = @subject.send(:owner).send("#{type}_instance_methods") list.any? { |m| m.to_s == selector } end