class MethodBasedSexpProcessor

A simple subclass of SexpProcessor that tracks method and class stacks for you. Use method_name, klass_name, or signature to refer to where you're at in processing. If you have to subclass process_(class|module|defn|defs) you must call super.

Attributes

class_stack[R]

A stack of the classes/modules that are being processed

method_locations[R]

A lookup table of all the method locations that have been processed so far.

method_stack[R]

A stack of the methods that are being processed. You'd think it'd only ever be 1 deep, but you'd be wrong. People do terrible things in/to ruby.

sclass[R]

A stack of the singleton classes that are being processed.

Public Instance Methods

in_klass(name) { || ... } click to toggle source

Adds name to the class stack, for the duration of the block

# File lib/sexp_processor.rb, line 521
def in_klass name
  if Sexp === name then
    name = case name.sexp_type
           when :colon2 then
             name = name.flatten
             name.delete :const
             name.delete :colon2
             name.join("::")
           when :colon3 then
             name.last.to_s
           else
             raise "unknown type #{name.inspect}"
           end
  end

  @class_stack.unshift name

  with_new_method_stack do
    yield
  end
ensure
  @class_stack.shift
end
in_method(name, file, line, line_max = nil) { || ... } click to toggle source

Adds name to the method stack, for the duration of the block

# File lib/sexp_processor.rb, line 548
def in_method name, file, line, line_max = nil
  method_name = Regexp === name ? name.inspect : name.to_s
  @method_stack.unshift method_name
  line_max = "-#{line_max}" if line_max
  @method_locations[signature] = "#{file}:#{line}#{line_max}"
  yield
ensure
  @method_stack.shift
end
in_sklass() { || ... } click to toggle source

Tracks whether we're in a singleton class or not. Doesn't track actual receiver.

# File lib/sexp_processor.rb, line 562
def in_sklass
  @sclass.push true

  with_new_method_stack do
    yield
  end
ensure
  @sclass.pop
end
klass_name() click to toggle source

Returns the first class in the list, or @@no_class if there are none.

# File lib/sexp_processor.rb, line 576
def klass_name
  name = @class_stack.first

  raise "you shouldn't see me" if Sexp === name

  if @class_stack.any?
    @class_stack.reverse.join("::").sub(/\([^\)]+\)$/, "")
  else
    @@no_class
  end
end
method_name() click to toggle source

Returns the first method in the list, or “#none” if there are none.

# File lib/sexp_processor.rb, line 592
def method_name
  m = @method_stack.first || @@no_method
  m = "##{m}" unless m =~ /::/
  m
end
process_class(exp) { || ... } click to toggle source

Process a class node until empty. Tracks all nesting. If you have to subclass and override this method, you can call super with a block.

# File lib/sexp_processor.rb, line 603
def process_class exp
  exp.shift unless auto_shift_type # node type
  in_klass exp.shift do
    if block_given? then
      yield
    else
      process_until_empty exp
    end
  end
  s()
end
process_defn(exp) { || ... } click to toggle source

Process a method node until empty. Tracks your location. If you have to subclass and override this method, you can clall super with a block.

# File lib/sexp_processor.rb, line 620
def process_defn exp
  exp.shift unless auto_shift_type # node type
  name = @sclass.empty? ? exp.shift : "::#{exp.shift}"

  in_method name, exp.file, exp.line, exp.line_max do
    if block_given? then
      yield
    else
      process_until_empty exp
    end
  end
  s()
end
process_defs(exp) { || ... } click to toggle source

Process a singleton method node until empty. Tracks your location. If you have to subclass and override this method, you can clall super with a block.

# File lib/sexp_processor.rb, line 639
def process_defs exp
  exp.shift unless auto_shift_type # node type
  process exp.shift # recv
  in_method "::#{exp.shift}", exp.file, exp.line, exp.line_max do
    if block_given? then
      yield
    else
      process_until_empty exp
    end
  end
  s()
end
process_module(exp) { || ... } click to toggle source

Process a module node until empty. Tracks all nesting. If you have to subclass and override this method, you can clall super with a block.

# File lib/sexp_processor.rb, line 657
def process_module exp
  exp.shift unless auto_shift_type # node type
  in_klass exp.shift do
    if block_given? then
      yield
    else
      process_until_empty exp
    end
  end
  s()
end
process_sclass(exp) { || ... } click to toggle source

Process a singleton class node until empty. Tracks all nesting. If you have to subclass and override this method, you can clall super with a block.

# File lib/sexp_processor.rb, line 674
def process_sclass exp
  exp.shift unless auto_shift_type # node type
  in_sklass do
    if block_given? then
      yield
    else
      process_until_empty exp
    end
  end
  s()
end
process_until_empty(exp) click to toggle source

Process each element of exp in turn.

# File lib/sexp_processor.rb, line 689
def process_until_empty exp
  until exp.empty?
    sexp = exp.shift
    process sexp if Sexp === sexp
  end
end
signature() click to toggle source

Returns the method signature for the current method.

# File lib/sexp_processor.rb, line 699
def signature
  "#{klass_name}#{method_name}"
end
with_new_method_stack() { || ... } click to toggle source

Reset the method stack for the duration of the block. Used for class scoping.

# File lib/sexp_processor.rb, line 707
def with_new_method_stack
  old_method_stack, @method_stack = @method_stack, []

  yield
ensure
  @method_stack = old_method_stack
end