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

arguments() click to toggle source

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
block_argument() click to toggle source

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
bytecode() click to toggle source

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
comment() click to toggle source

@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
defining_class() click to toggle source

@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
file() click to toggle source

@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
iseq() click to toggle source

Returns the instruction sequence for the method (cached)

# File lib/mirrors/method_mirror.rb, line 131
def iseq
  @iseq ||= RubyVM::InstructionSequence.of(@subject)
end
line() click to toggle source

@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
name() click to toggle source
# File lib/mirrors/method_mirror.rb, line 158
def name
  @subject.name
end
native_code() click to toggle source

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
optional_arguments() click to toggle source

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
private?() click to toggle source
# File lib/mirrors/method_mirror.rb, line 96
def private?
  visibility?(:private)
end
protected?() click to toggle source
# File lib/mirrors/method_mirror.rb, line 88
def protected?
  visibility?(:protected)
end
public?() click to toggle source
# File lib/mirrors/method_mirror.rb, line 92
def public?
  visibility?(:public)
end
references() click to toggle source
# File lib/mirrors/method_mirror.rb, line 162
def references
  visitor = Mirrors::ReferencesVisitor.new
  visitor.call(self)
  visitor.markers
end
required_arguments() click to toggle source

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
selector() click to toggle source

@return [String] The method name

# File lib/mirrors/method_mirror.rb, line 33
def selector
  @subject.name.to_s
end
sexp() click to toggle source

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
source() click to toggle source

@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
splat_argument() click to toggle source

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
super_method() click to toggle source
# 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
visibility() click to toggle source

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

args(type) click to toggle source
# 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
source_location() click to toggle source
# File lib/mirrors/method_mirror.rb, line 181
def source_location
  @subject.send(:source_location)
end
unindent(str) click to toggle source
# 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
visibility?(type) click to toggle source
# 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