1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
require 'spec_helper'
require 'parslet'
describe Parslet::Transform do
include Parslet
let(:transform) { Parslet::Transform.new }
class A < Struct.new(:elt); end
class B < Struct.new(:elt); end
class C < Struct.new(:elt); end
class Bi < Struct.new(:a, :b); end
describe "delayed construction" do
context "given simple(:x) => A.new(x)" do
before(:each) do
transform.rule(simple(:x)) { |d| A.new(d[:x]) }
end
it "should transform 'a' into A.new('a')" do
transform.apply('a').should == A.new('a')
end
it "should transform ['a', 'b'] into [A.new('a'), A.new('b')]" do
transform.apply(['a', 'b']).should ==
[A.new('a'), A.new('b')]
end
end
context "given rules on {:a => simple(:x)} and {:b => :_x}" do
before(:each) do
transform.rule(:a => simple(:x)) { |d| A.new(d[:x]) }
transform.rule(:b => simple(:x)) { |d| B.new(d[:x]) }
end
it "should transform {:d=>{:b=>'c'}} into d => B('c')" do
transform.apply({:d=>{:b=>'c'}}).should == {:d => B.new('c')}
end
it "should transform {:a=>{:b=>'c'}} into A(B('c'))" do
transform.apply({:a=>{:b=>'c'}}).should == A.new(B.new('c'))
end
end
describe "pulling out subbranches" do
before(:each) do
transform.rule(:a => {:b => simple(:x)}, :d => {:e => simple(:y)}) { |d|
Bi.new(*d.values_at(:x, :y))
}
end
it "should yield Bi.new('c', 'f')" do
transform.apply(:a => {:b => 'c'}, :d => {:e => 'f'}).should ==
Bi.new('c', 'f')
end
end
end
describe "dsl construction" do
let(:transform) { Parslet::Transform.new do
rule(simple(:x)) { A.new(x) }
end
}
it "should still evaluate rules correctly" do
transform.apply('a').should == A.new('a')
end
end
describe "class construction" do
class OptimusPrime < Parslet::Transform
rule(:a => simple(:x)) { A.new(x) }
rule(:b => simple(:x)) { B.new(x) }
end
let(:transform) { OptimusPrime.new }
it "should evaluate rules" do
transform.apply(:a => 'a').should == A.new('a')
end
context "optionally raise when no match found" do
class BumbleBee < Parslet::Transform
def initialize(&block)
super(raise_on_unmatch: true, &block)
end
rule(:a => simple(:x)) { A.new(x) }
end
let(:transform) { BumbleBee.new }
it "should evaluate rules" do
transform.apply(:a => 'a').should == A.new('a')
end
it "should raise when no rules are matched" do
lambda {
transform.apply(:z => 'z')
}.should raise_error(NotImplementedError, /Failed to match/)
end
end
context "with inheritance" do
class OptimusPrimeJunior < OptimusPrime
rule(:b => simple(:x)) { B.new(x.upcase) }
rule(:c => simple(:x)) { C.new(x) }
end
let(:transform) { OptimusPrimeJunior.new }
it "should inherit rules from its parent" do
transform.apply(:a => 'a').should == A.new('a')
end
it "should be able to override rules from its parent" do
transform.apply(:b => 'b').should == B.new('B')
end
it "should be able to define new rules" do
transform.apply(:c => 'c').should == C.new('c')
end
end
end
describe "<- #call_on_match" do
let(:bindings) { { :foo => 'test' } }
context "when given a block of arity 1" do
it "should call the block" do
called = false
transform.call_on_match(bindings, lambda do |dict|
called = true
end)
called.should == true
end
it "should yield the bindings" do
transform.call_on_match(bindings, lambda do |dict|
dict.should == bindings
end)
end
it "should execute in the current context" do
foo = 'test'
transform.call_on_match(bindings, lambda do |dict|
foo.should == 'test'
end)
end
end
context "when given a block of arity 0" do
it "should call the block" do
called = false
transform.call_on_match(bindings, proc do
called = true
end)
called.should == true
end
it "should have bindings as local variables" do
transform.call_on_match(bindings, proc do
foo.should == 'test'
end)
end
it "should execute in its own context" do
@bar = 'test'
transform.call_on_match(bindings, proc do
if instance_variable_defined?("@bar")
instance_variable_get("@bar").should_not == 'test'
end
end)
end
end
end
context "various transformations (regression)" do
context "hashes" do
it "are matched completely" do
transform.rule(:a => simple(:x)) { fail }
transform.apply(:a => 'a', :b => 'b')
end
end
end
context "when not using the bindings as hash, but as local variables" do
it "should access the variables" do
transform.rule(simple(:x)) { A.new(x) }
transform.apply('a').should == A.new('a')
end
it "should allow context as local variable" do
transform.rule(simple(:x)) { foo }
transform.apply('a', :foo => 'bar').should == 'bar'
end
end
end
|