Class: SexpBuilder

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/sexp_builder.rb,
lib/sexp_builder/context.rb,
lib/sexp_builder/query_builder.rb

Defined Under Namespace

Classes: Context, QueryBuilder

Constant Summary collapse

VERSION =
"0.1"

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSexpBuilder

Initializes the builder. If you redefine this in your subclass, it’s important to call super().



14
15
16
17
18
19
20
# File 'lib/sexp_builder.rb', line 14

def initialize
  @context = self.class.current_context
  @main = @context.main_context
  @scope = []
  @rewriters = {}
  @query_builders = {}
end

Class Attribute Details

.current_contextObject

The Context which this builder will process under.



69
70
71
# File 'lib/sexp_builder.rb', line 69

def current_context
  @current_context
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



10
11
12
# File 'lib/sexp_builder.rb', line 10

def context
  @context
end

#scopeObject (readonly)

Returns the value of attribute scope.



10
11
12
# File 'lib/sexp_builder.rb', line 10

def scope
  @scope
end

Class Method Details

.context_name(mod) ⇒ Object

Turns a module into a context name:

  • FooBar => foo_bar

  • FooBarContext => foo_bar

  • FooBarBuilder => foo_bar



87
88
89
90
91
92
# File 'lib/sexp_builder.rb', line 87

def context_name(mod)
  name = mod.name
  name = name.split("::").last
  name.gsub!(/(Context|Builder)$/, '')
  name.scan(/.[^A-Z]+/).map { |part| part.downcase }.join("_")
end

.inherited(mod) ⇒ Object

Sets up the current_context.



74
75
76
77
78
79
80
# File 'lib/sexp_builder.rb', line 74

def inherited(mod)
  if self == SexpBuilder
    mod.current_context = Context.new(mod)
  else
    mod.current_context = current_context.context(context_name(mod))
  end
end

.tmpidObject

Generates a temporary id.



95
96
97
98
# File 'lib/sexp_builder.rb', line 95

def tmpid
  @tmpid ||= 0
  @tmpid += 1
end

Instance Method Details

#process(sexp, options = {}) ⇒ Object

Process sexp under the current context.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/sexp_builder.rb', line 23

def process(sexp, options = {})
  @scope.unshift(sexp.sexp_type)

  rewriters.each do |query, method|
    if data = query.satisfy?(sexp, QueryBuilder::Data.new)
      return method.call(SexpPath::SexpResult.new(sexp, data))
    end
  end
  
  # If none of the rewriters matched, process the children:
  sexp.inject(Sexp.new) do |memo, exp|
    memo << if exp.is_a?(Sexp)
      process(exp)
    else
      exp
    end
  end
ensure
  @scope.shift     
end

#process_main(sexp, options = {}) ⇒ Object

Process sexp under the top context.



45
46
47
48
49
50
# File 'lib/sexp_builder.rb', line 45

def process_main(sexp, options = {})
  prev, @context = @context, @main
  process(sexp, options)
ensure
  @context = prev
end

#query_builder(context = @context) ⇒ Object

Returns the query builder for a given context.



62
63
64
# File 'lib/sexp_builder.rb', line 62

def query_builder(context = @context)
  @query_builders[context] ||= QueryBuilder.make(context, self)
end

#rewriters(context = @context) ⇒ Object

Returns an array in the format of:

[<SexpPath::Matcher> rule, <Method> rewriter]


55
56
57
58
59
# File 'lib/sexp_builder.rb', line 55

def rewriters(context = @context)
  @rewriters[context] ||= context.rewriters.map do |rule|
    [query_builder(context).send(rule), method("rewrite_#{rule}")]
  end
end