Class: Brakeman::SexpProcessor

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_parser/bm_sexp_processor.rb

Overview

SexpProcessor provides a uniform interface to process Sexps.

In order to create your own SexpProcessor subclass you’ll need to call super in the initialize method, then set any of the Sexp flags you want to be different from the defaults.

SexpProcessor uses a Sexp’s type to determine which process method to call in the subclass. For Sexp s(:lit, 1) SexpProcessor will call #process_lit, if it is defined.

Direct Known Subclasses

AliasProcessor, BaseCheck, BaseProcessor

Defined Under Namespace

Classes: Environment

Constant Summary collapse

VERSION =
'CUSTOM'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSexpProcessor

Creates a new SexpProcessor. Use super to invoke this initializer from SexpProcessor subclasses, then use the attributes above to customize the functionality of the SexpProcessor



38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 38

def initialize
  @expected            = Sexp

  # we do this on an instance basis so we can subclass it for
  # different processors.
  @processors = {}
  @context    = []

  public_methods.each do |name|
    if name.to_s.start_with? "process_" then
      @processors[name[8..-1].to_sym] = name.to_sym
    end
  end
end

Instance Attribute Details

#contextObject (readonly)

Return a stack of contexts. Most recent node is first.



20
21
22
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 20

def context
  @context
end

#envObject (readonly)

A scoped environment to make you happy.



30
31
32
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 30

def env
  @env
end

#expectedObject

Expected result class



25
26
27
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 25

def expected
  @expected
end

Instance Method Details

#error_handler(type, exp = nil) ⇒ Object

:nodoc:



88
89
90
91
92
93
94
95
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 88

def error_handler(type, exp=nil) # :nodoc:
  begin
    return yield
  rescue => err
    warn "#{err.class} Exception thrown while processing #{type} for sexp #{exp.inspect} #{caller.inspect}" if $DEBUG
    raise
  end
end

#in_context(type) ⇒ Object



141
142
143
144
145
146
147
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 141

def in_context type
  self.context.unshift type

  yield

  self.context.shift
end

#process(exp) ⇒ Object

Default Sexp processor. Invokes process_<type> methods matching the Sexp type given. Performs additional checks as specified by the initializer.

Raises:



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 58

def process(exp)
  return nil if exp.nil?

  result = nil

  type = exp.first
  raise "Type should be a Symbol, not: #{exp.first.inspect} in #{exp.inspect}" unless Symbol === type

  in_context type do
    # now do a pass with the real processor (or generic)
    meth = @processors[type]
    if meth then
      if $DEBUG
        result = error_handler(type) do
          self.send(meth, exp)
        end
      else
        result = self.send(meth, exp)
      end

    else
      result = self.process_default(exp)
    end
  end
  
  raise SexpTypeError, "Result must be a #{@expected}, was #{result.class}:#{result.inspect}" unless @expected === result
  
  result
end

#process_dummy(exp) ⇒ Object

A fairly generic processor for a dummy node. Dummy nodes are used when your processor is doing a complicated rewrite that replaces the current sexp with multiple sexps.

Bogus Example:

def process_something(exp)
  return s(:dummy, process(exp), s(:extra, 42))
end


108
109
110
111
112
113
114
115
116
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 108

def process_dummy(exp)
  result = @expected.new(:dummy) rescue @expected.new

  until exp.empty? do
    result << self.process(exp.shift)
  end

  result
end

#scope(&block) ⇒ Object

Add a scope level to the current env. Eg:

def process_defn exp
  name = exp.shift
  args = process(exp.shift)
  scope do
    body = process(exp.shift)
    # ...
  end
end

env[:x] = 42
scope do
  env[:x]       # => 42
  env[:y] = 24
end
env[:y]         # => nil


137
138
139
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 137

def scope &block
  env.scope(&block)
end