Class: SexpBuilder::Context
- Inherits:
-
Object
- Object
- SexpBuilder::Context
- Defined in:
- lib/sexp_builder/context.rb
Instance Attribute Summary collapse
-
#builder ⇒ Object
readonly
Returns the value of attribute builder.
-
#contexts ⇒ Object
readonly
Returns the value of attribute contexts.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#query_scope ⇒ Object
readonly
Returns the value of attribute query_scope.
-
#rewriters ⇒ Object
readonly
Returns the value of attribute rewriters.
Instance Method Summary collapse
-
#context(name, &blk) ⇒ Object
Defines or finds a sub-context, and evalutes the block under it.
-
#initialize(builder, parent = nil) ⇒ Context
constructor
A new instance of Context.
-
#main_context ⇒ Object
Returns the top-most context.
-
#matcher(name, &blk) ⇒ Object
Defines a matcher.
-
#rewrite(*rules, &blk) ⇒ Object
Defines a rewriter.
-
#rule(name, &blk) ⇒ Object
Defines a rule.
Constructor Details
#initialize(builder, parent = nil) ⇒ Context
Returns a new instance of Context.
5 6 7 8 9 10 11 12 13 14 15 |
# File 'lib/sexp_builder/context.rb', line 5 def initialize(builder, parent = nil) @builder = builder @parent = parent @contexts = {} @rewriters = [] @query_scope = Module.new do include parent.query_scope if parent end end |
Instance Attribute Details
#builder ⇒ Object (readonly)
Returns the value of attribute builder.
3 4 5 |
# File 'lib/sexp_builder/context.rb', line 3 def builder @builder end |
#contexts ⇒ Object (readonly)
Returns the value of attribute contexts.
3 4 5 |
# File 'lib/sexp_builder/context.rb', line 3 def contexts @contexts end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
3 4 5 |
# File 'lib/sexp_builder/context.rb', line 3 def parent @parent end |
#query_scope ⇒ Object (readonly)
Returns the value of attribute query_scope.
3 4 5 |
# File 'lib/sexp_builder/context.rb', line 3 def query_scope @query_scope end |
#rewriters ⇒ Object (readonly)
Returns the value of attribute rewriters.
3 4 5 |
# File 'lib/sexp_builder/context.rb', line 3 def rewriters @rewriters end |
Instance Method Details
#context(name, &blk) ⇒ Object
Defines or finds a sub-context, and evalutes the block under it. If you want to process something under this context, you would have to call process_{name}
.
29 30 31 32 33 |
# File 'lib/sexp_builder/context.rb', line 29 def context(name, &blk) context = define_context(name.to_sym) context.instance_eval(&blk) if blk context end |
#main_context ⇒ Object
Returns the top-most context.
18 19 20 21 22 23 24 |
# File 'lib/sexp_builder/context.rb', line 18 def main_context if @parent @parent.main_context else self end end |
#matcher(name, &blk) ⇒ Object
Defines a matcher. A matcher is a bit of Ruby code which can be used in your rules. The expression it should match is passed in, and it should return a true-ish value if it matches. The matcher will be evaluated under the instatiated processor, so you can use other instance methods and instance variables too.
matcher :five_arguments do |exp|
self # => the instance of Example
exp.length == 6 # the first will always be :arglist
end
Under the hood, this will define:
-
The block as
matcher_five_arguments
on the builder. -
five_arguments
, which will invoke the matcher, on the query scope.
50 51 52 53 54 55 56 57 58 59 |
# File 'lib/sexp_builder/context.rb', line 50 def matcher(name, &blk) method_name = "matcher_#{name}" define(method_name, &blk) define_query_scope(name) do block do |exp| instance.send(method_name, exp) end end end |
#rewrite(*rules, &blk) ⇒ Object
Defines a rewriter. Rewriters take one or more rules and defines replacements when they match. The data-object from SexpPath is given as an argument. If you want some of the sub-expressions matched too, you’ll have to call process() yourself.
rewrite :plus_sequence do |data|
# sum the numbers
sum = data[:number].inject { |all, one| all + one }
# return a new number
s(:lit, sum)
end
Under the hood, this will define:
-
The block as
rewrite_plus_sequence
. -
And @rewriters will now include :plus_sequence.
You can also give this several rules, or none if you want it to match every single Sexp.
Context shortcut
rewrite :foo, :in => :bar do
...
end
Is the same as:
context :bar do
rewrite :foo do
...
end
end
129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/sexp_builder/context.rb', line 129 def rewrite(*rules, &blk) = rules.last.is_a?(Hash) ? rules.pop : {} rules << :wild if rules.empty? return context([:in]).rewrite(*rules, &blk) if [:in] rules.each do |rule| @rewriters << rule define("rewrite_#{rule}", &blk) end end |
#rule(name, &blk) ⇒ Object
Defines a rule. Rules are simply snippets of SexpPath which can refer to each other and itself. They can also take arguments too.
# Matches any number.
rule :number do |capture_as|
# Doesn't make very much sense to take an argument here,
# it's just an example
s(:lit, _ % capture_as)
end
# Matches a sequence of plusses: 1 + 2 + 3
rule :plus_sequence do
s(:call, # a method call
number(:number) | # the receiver can be a number
plus_sequence, # or a sequence
:+,
s(:arglist,
number(:number) | # the argument can be a number
plus_sequence # or a sequence
end
Under the hood, this will define:
-
The blocks as
real_number
andreal_plus_sequence
on the query_scope. -
number
andplus_sequence
which wraps the methods above as QueryBuilder::Deferred.
88 89 90 91 92 93 94 |
# File 'lib/sexp_builder/context.rb', line 88 def rule(name, &blk) real_name = "real_#{name}" define_query_scope(real_name, &blk) define_query_scope(name) do |*args| QueryBuilder::Deferred.new(self, real_name, args, name) end end |