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
57
# File 'lib/ruby_parser/bm_sexp_processor.rb', line 44

def initialize
  @expected            = Sexp
  @processors = self.class.processors
  @context    = []
  @current_class = @current_module = @current_method = @visibility = nil

  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


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

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)

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

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

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

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