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.

Constant Summary collapse

VERSION =
'CUSTOM'

Instance Attribute Summary collapse

Class Method 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



44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 44

def initialize
  @expected            = Sexp
  @processors = self.class.processors
  @context    = []

  if @processors.empty?
    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
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

Class Method Details

.processorsObject

Cache process methods per class



34
35
36
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 34

def self.processors
  @processors ||= {}
end

Instance Method Details

#in_context(type) ⇒ Object



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

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:

  • (SexpTypeError)


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

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
      result = self.send(meth, exp)
    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

#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


105
106
107
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 105

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