class Gotero

La principal funcion de gotero es ofrecer al usuario comprensión sobre los llamados realizados por la aplicación para ententer la interacción entre los objetos.

Para hacerlo la idea es ejecutar un bloque de código con un gotero, el cual pone luego a disposición un diagrama de secuencias.

Entonces lo primero va a ser definir una clase Gotero

Attributes

output[RW]

Por el momento, vamos a guardar el resultado como un string y lo vamos a hacer accesible, después vamos a ver como podemos guardar esta información de una forma más adaptada a nuestras necesidades.

Public Class Methods

new() click to toggle source

Inicialmente la secuencia va a estar vacía y nuestro primer objeto va a ser un sujeto ‘:t` (ya que se me ocurre que esto lo estamos corriendo como un test)

# File lib/gotero.rb, line 20
def initialize
  @output = ''
  @emiters = [:t]
end

Public Instance Methods

trace(&block) click to toggle source

La interface publica de gotero simplemente recibe un bloque y lo ejecuta con el gotero habilitado

# File lib/gotero.rb, line 27
def trace &block
  tracer.enable &block
end

Private Instance Methods

on_call(tracepoint) click to toggle source

Cuando se hace un llamado a un método necesitamos saber quien lo llamó y quien es el receptor, para guardamos la pila de emisores, el receptor de un mensaje siempre es el emisor del siguiente mensaje, excepto en el caso en que un mensaje vuelva.

Además de emisor y receptor, necesitamos saber el método que estamos llamando y, ya que estamos, los argumentos con los que se llama al método.

# File lib/gotero.rb, line 56
def on_call tracepoint
  current_emiter = @emiters.last
  receiver = tracepoint.defined_class
  subject = receiver.name.downcase
  method = tracepoint.method_id
  detached_method = receiver.instance_method(method)
  arguments = detached_method.parameters.map do |param|
    tracepoint.binding.local_variable_get param[1]
  end.join(', ')
  message_details = " #{ method } (#{ arguments })"
  self.output << "#{ current_emiter }->#{ subject }:#{ message_details }\n"
  @emiters << subject.to_sym
end
on_return(tracepoint) click to toggle source

En el caso del return el receptor es el que está pen-último en la pila, así que lo que hacemos es sacar el último de la pila (y dejarlo como emisor) y tomar como receptor al que queda último.

# File lib/gotero.rb, line 73
def on_return tracepoint
  emiter = @emiters.pop
  receiver = @emiters.last
  self.output << "#{ emiter }->#{ receiver }:\n"
end
tracer() click to toggle source

Para hacer el seguimiento, lo que vamos a usar es ‘TracePoint` al cual, si le pasamos un bloque ejecuta el bloque cada vez que un evento del tipo indicado se realiza.

Los eventos que nos interesan son ‘call` y `return`, o sea llamados a métodos y retornos de métodos.

# File lib/gotero.rb, line 40
def tracer
  TracePoint.new(:call, :return) do |tp|
    case tp.event
    when :call then on_call(tp)
    when :return then on_return(tp)
    end
  end
end