flavour_saver 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +81 -0
- data/Guardfile +12 -0
- data/LICENSE +22 -0
- data/README.md +339 -0
- data/Rakefile +2 -0
- data/flavour_saver.gemspec +28 -0
- data/lib/flavour_saver/helpers.rb +118 -0
- data/lib/flavour_saver/lexer.rb +127 -0
- data/lib/flavour_saver/nodes.rb +177 -0
- data/lib/flavour_saver/parser.rb +183 -0
- data/lib/flavour_saver/partial.rb +29 -0
- data/lib/flavour_saver/rails_partial.rb +10 -0
- data/lib/flavour_saver/runtime.rb +269 -0
- data/lib/flavour_saver/template.rb +19 -0
- data/lib/flavour_saver/version.rb +3 -0
- data/lib/flavour_saver.rb +78 -0
- data/spec/acceptance/backtrack_spec.rb +14 -0
- data/spec/acceptance/comment_spec.rb +12 -0
- data/spec/acceptance/custom_block_helper_spec.rb +35 -0
- data/spec/acceptance/custom_helper_spec.rb +15 -0
- data/spec/acceptance/ensure_no_rce_spec.rb +26 -0
- data/spec/acceptance/handlebars_qunit_spec.rb +911 -0
- data/spec/acceptance/if_else_spec.rb +17 -0
- data/spec/acceptance/multi_level_with_spec.rb +15 -0
- data/spec/acceptance/one_character_identifier_spec.rb +13 -0
- data/spec/acceptance/runtime_run_spec.rb +27 -0
- data/spec/acceptance/sections_spec.rb +25 -0
- data/spec/acceptance/segment_literals_spec.rb +26 -0
- data/spec/acceptance/simple_expression_spec.rb +13 -0
- data/spec/fixtures/backtrack.hbs +4 -0
- data/spec/fixtures/comment.hbs +1 -0
- data/spec/fixtures/custom_block_helper.hbs +3 -0
- data/spec/fixtures/custom_helper.hbs +1 -0
- data/spec/fixtures/if_else.hbs +5 -0
- data/spec/fixtures/multi_level_if.hbs +12 -0
- data/spec/fixtures/multi_level_with.hbs +11 -0
- data/spec/fixtures/one_character_identifier.hbs +1 -0
- data/spec/fixtures/sections.hbs +9 -0
- data/spec/fixtures/simple_expression.hbs +1 -0
- data/spec/lib/flavour_saver/lexer_spec.rb +187 -0
- data/spec/lib/flavour_saver/parser_spec.rb +277 -0
- data/spec/lib/flavour_saver/runtime_spec.rb +190 -0
- data/spec/lib/flavour_saver/template_spec.rb +5 -0
- metadata +243 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
require 'flavour_saver'
|
3
|
+
|
4
|
+
describe 'Fixture: if_else.hbs' do
|
5
|
+
subject { Tilt.new(template).render(context).gsub(/[\s\r\n]+/, ' ').strip }
|
6
|
+
let(:context) { Struct.new(:name).new }
|
7
|
+
let(:template) { File.expand_path('../../fixtures/if_else.hbs', __FILE__) }
|
8
|
+
|
9
|
+
it 'renders correctly when given a name' do
|
10
|
+
context.name = 'Alan'
|
11
|
+
subject.should == "Say hello to Alan."
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'renders correcrtly when not given a name' do
|
15
|
+
subject.should == "Nobody to say hi to."
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
require 'flavour_saver'
|
3
|
+
|
4
|
+
describe 'Fixture: multi_level_with.hbs' do
|
5
|
+
subject { Tilt.new(template).render(context).gsub(/[\s\r\n]+/, ' ').strip }
|
6
|
+
let(:template) { File.expand_path('../../fixtures/multi_level_with.hbs', __FILE__) }
|
7
|
+
let(:context) { Struct.new(:person,:company).new }
|
8
|
+
|
9
|
+
it 'renders correctly when person has a name' do
|
10
|
+
context.person = Struct.new(:name).new('Alan')
|
11
|
+
context.company = Struct.new(:name).new('Rad, Inc.')
|
12
|
+
subject.should == 'Alan - Rad, Inc.'
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
require 'flavour_saver'
|
3
|
+
|
4
|
+
describe 'Fixture: one_character_identifier.hbs' do
|
5
|
+
subject { Tilt.new(template).render(context).gsub(/[\s\r\n]+/, ' ').strip }
|
6
|
+
let(:template) { File.expand_path('../../fixtures/one_character_identifier.hbs', __FILE__) }
|
7
|
+
let(:context) { double(:context) }
|
8
|
+
|
9
|
+
it 'renders correctly' do
|
10
|
+
context.should_receive(:a).and_return('foo')
|
11
|
+
subject.should == "foo"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "flavour_saver"
|
2
|
+
|
3
|
+
describe FlavourSaver::Runtime do
|
4
|
+
describe ".run" do
|
5
|
+
subject do
|
6
|
+
FlavourSaver::Runtime.run(parsed_template, context, locals, helper_names)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:parsed_template) { FlavourSaver.parse(FlavourSaver.lex(template)) }
|
10
|
+
let(:context) { Object.new }
|
11
|
+
let(:locals) { {} }
|
12
|
+
let(:helper_names) { [] }
|
13
|
+
|
14
|
+
describe "with a local helper" do
|
15
|
+
let(:template) { "{{n}} is {{#is_even n}}even{{else}}odd{{/is_even}}" }
|
16
|
+
let(:context_class) { Struct.new(:n) }
|
17
|
+
let(:context) { context_class.new(24) }
|
18
|
+
|
19
|
+
it "uses the helper" do
|
20
|
+
is_even_helper = proc { |n| n % 2 == 0 }
|
21
|
+
|
22
|
+
locals[:is_even] = is_even_helper
|
23
|
+
subject.should == "24 is even"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
require 'flavour_saver'
|
3
|
+
|
4
|
+
describe 'Fixture: sections.hbs' do
|
5
|
+
subject { Tilt.new(template).render(context).gsub(/[\s\r\n]+/, ' ').strip }
|
6
|
+
let(:context) { Struct.new(:name, :names, :order).new }
|
7
|
+
let(:template) { File.expand_path('../../fixtures/sections.hbs', __FILE__) }
|
8
|
+
|
9
|
+
it 'renders correctly when given a name' do
|
10
|
+
context.name = 'Alan'
|
11
|
+
subject.should == "Say hello to Alan."
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'renders correctly when given a list of names' do
|
15
|
+
context.names = ['Foo', 'Bar']
|
16
|
+
subject.should == "* Foo * Bar"
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'renders correctly when given an order' do
|
20
|
+
class Order; def number; 1234; end; end
|
21
|
+
context.order = Order.new
|
22
|
+
subject.should == 'Number: 1234'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'flavour_saver'
|
2
|
+
|
3
|
+
describe FlavourSaver do
|
4
|
+
subject { FS.evaluate(template, context) }
|
5
|
+
|
6
|
+
let(:context) { double(:context) }
|
7
|
+
|
8
|
+
after do
|
9
|
+
FS.reset_helpers
|
10
|
+
FS.reset_partials
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'segment literal array access' do
|
14
|
+
let(:template) { '{{foos.[1].bar}}' }
|
15
|
+
|
16
|
+
it 'returns "two"' do
|
17
|
+
foos = []
|
18
|
+
foos << double(:foo)
|
19
|
+
foos << double(:foo)
|
20
|
+
foos[1].should_receive(:bar).and_return('two')
|
21
|
+
|
22
|
+
context.stub(:foos).and_return(foos)
|
23
|
+
subject.should == 'two'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
require 'flavour_saver'
|
3
|
+
|
4
|
+
describe 'Fixture: simple_expression.hbs' do
|
5
|
+
subject { Tilt.new(template).render(context).gsub(/[\s\r\n]+/, ' ').strip }
|
6
|
+
let(:template) { File.expand_path('../../fixtures/simple_expression.hbs', __FILE__) }
|
7
|
+
let(:context) { double(:context) }
|
8
|
+
|
9
|
+
it 'renders correctly' do
|
10
|
+
context.should_receive(:hello).and_return('hello world')
|
11
|
+
subject.should == "hello world"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
I am {{!not }}a very nice person!
|
@@ -0,0 +1 @@
|
|
1
|
+
{{say_what_again}}
|
@@ -0,0 +1 @@
|
|
1
|
+
{{a}}
|
@@ -0,0 +1 @@
|
|
1
|
+
{{hello}}
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'flavour_saver/lexer'
|
2
|
+
|
3
|
+
describe FlavourSaver::Lexer do
|
4
|
+
it 'is an RLTK lexer' do
|
5
|
+
subject.should be_a(RLTK::Lexer)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'Tokens' do
|
9
|
+
describe 'Expressions' do
|
10
|
+
describe '{{foo}}' do
|
11
|
+
subject { FlavourSaver::Lexer.lex "{{foo}}" }
|
12
|
+
|
13
|
+
it 'begins with an EXPRST' do
|
14
|
+
subject.first.type.should == :EXPRST
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'ends with an EXPRE' do
|
18
|
+
subject[-2].type.should == :EXPRE
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'contains only the identifier "foo"' do
|
22
|
+
subject[1..-3].size.should == 1
|
23
|
+
subject[1].type.should == :IDENT
|
24
|
+
subject[1].value.should == 'foo'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '{{foo bar}}' do
|
29
|
+
subject { FlavourSaver::Lexer.lex "{{foo bar}}" }
|
30
|
+
|
31
|
+
it 'has tokens in the correct order' do
|
32
|
+
subject.map(&:type).should == [ :EXPRST, :IDENT, :WHITE, :IDENT, :EXPRE, :EOS ]
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'has values in the correct order' do
|
36
|
+
subject.map(&:value).compact.should == [ 'foo', 'bar' ]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '{{foo "bar"}}' do
|
41
|
+
subject { FlavourSaver::Lexer.lex "{{foo \"bar\"}}" }
|
42
|
+
|
43
|
+
it 'has tokens in the correct order' do
|
44
|
+
subject.map(&:type).should == [ :EXPRST, :IDENT, :WHITE, :STRING, :EXPRE, :EOS ]
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'has values in the correct order' do
|
48
|
+
subject.map(&:value).compact.should == [ 'foo', 'bar' ]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '{{foo bar="baz" hello="goodbye"}}' do
|
53
|
+
subject { FlavourSaver::Lexer.lex '{{foo bar="baz" hello="goodbye"}}' }
|
54
|
+
|
55
|
+
it 'has tokens in the correct order' do
|
56
|
+
subject.map(&:type).should == [ :EXPRST, :IDENT, :WHITE, :IDENT, :EQ, :STRING, :WHITE, :IDENT, :EQ, :STRING, :EXPRE, :EOS ]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'has values in the correct order' do
|
60
|
+
subject.map(&:value).compact.should == [ 'foo', 'bar', 'baz', 'hello', 'goodbye' ]
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '{{else}}' do
|
67
|
+
subject { FlavourSaver::Lexer.lex '{{else}}' }
|
68
|
+
|
69
|
+
it 'has tokens in the correct order' do
|
70
|
+
subject.map(&:type).should == [ :EXPRST, :ELSE, :EXPRE, :EOS ]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'Object path expressions' do
|
75
|
+
describe '{{foo.bar}}' do
|
76
|
+
subject { FlavourSaver::Lexer.lex "{{foo.bar}}" }
|
77
|
+
|
78
|
+
it 'has tokens in the correct order' do
|
79
|
+
subject.map(&:type).should == [ :EXPRST, :IDENT, :DOT, :IDENT, :EXPRE, :EOS ]
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'has the correct values' do
|
83
|
+
subject.map(&:value).compact.should == ['foo', 'bar']
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '{{foo.[10].bar}}' do
|
88
|
+
subject { FlavourSaver::Lexer.lex "{{foo.[10].bar}}" }
|
89
|
+
|
90
|
+
it 'has tokens in the correct order' do
|
91
|
+
subject.map(&:type).should == [ :EXPRST, :IDENT, :DOT, :LITERAL, :DOT, :IDENT, :EXPRE, :EOS ]
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'has the correct values' do
|
95
|
+
subject.map(&:value).compact.should == ['foo', '10', 'bar']
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '{{foo.[he!@#$(&@klA)].bar}}' do
|
100
|
+
subject { FlavourSaver::Lexer.lex '{{foo.[he!@#$(&@klA)].bar}}' }
|
101
|
+
|
102
|
+
it 'has tokens in the correct order' do
|
103
|
+
subject.map(&:type).should == [ :EXPRST, :IDENT, :DOT, :LITERAL, :DOT, :IDENT, :EXPRE, :EOS ]
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'has the correct values' do
|
107
|
+
subject.map(&:value).compact.should == ['foo', 'he!@#$(&@klA)', 'bar']
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe 'Triple-stash expressions' do
|
113
|
+
subject { FlavourSaver::Lexer.lex "{{{foo}}}" }
|
114
|
+
|
115
|
+
it 'has tokens in the correct order' do
|
116
|
+
subject.map(&:type).should == [ :TEXPRST, :IDENT, :TEXPRE, :EOS ]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'Comment expressions' do
|
121
|
+
subject { FlavourSaver::Lexer.lex "{{! WAT}}" }
|
122
|
+
|
123
|
+
it 'has tokens in the correct order' do
|
124
|
+
subject.map(&:type).should == [ :EXPRST, :BANG, :COMMENT, :EXPRE, :EOS ]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe 'Backtrack expression' do
|
129
|
+
subject { FlavourSaver::Lexer.lex "{{../foo}}" }
|
130
|
+
|
131
|
+
it 'has tokens in the correct order' do
|
132
|
+
subject.map(&:type).should == [:EXPRST, :DOT, :DOT, :FWSL, :IDENT, :EXPRE, :EOS]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe 'Carriage-return and new-lines' do
|
137
|
+
subject { FlavourSaver::Lexer.lex "{{foo}}\n{{bar}}\r{{baz}}" }
|
138
|
+
|
139
|
+
it 'has tokens in the correct order' do
|
140
|
+
subject.map(&:type).should == [:EXPRST,:IDENT,:EXPRE,:OUT,:EXPRST,:IDENT,:EXPRE,:OUT,:EXPRST,:IDENT,:EXPRE,:EOS]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe 'Block Expressions' do
|
145
|
+
subject { FlavourSaver::Lexer.lex "{{#foo}}{{bar}}{{/foo}}" }
|
146
|
+
|
147
|
+
describe '{{#foo}}{{bar}}{{/foo}}' do
|
148
|
+
it 'has tokens in the correct order' do
|
149
|
+
subject.map(&:type).should == [
|
150
|
+
:EXPRST, :HASH, :IDENT, :EXPRE,
|
151
|
+
:EXPRST, :IDENT, :EXPRE,
|
152
|
+
:EXPRST, :FWSL, :IDENT, :EXPRE,
|
153
|
+
:EOS
|
154
|
+
]
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'has identifiers in the correct order' do
|
158
|
+
subject.map(&:value).compact.should == [ 'foo', 'bar', 'foo' ]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe 'Carriage return' do
|
164
|
+
subject { FlavourSaver::Lexer.lex "\r" }
|
165
|
+
|
166
|
+
it 'has tokens in the correct order' do
|
167
|
+
subject.map(&:type).should == [:OUT,:EOS]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe 'New line' do
|
172
|
+
subject { FlavourSaver::Lexer.lex "\n" }
|
173
|
+
|
174
|
+
it 'has tokens in the correct order' do
|
175
|
+
subject.map(&:type).should == [:OUT,:EOS]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe 'Single curly bracket' do
|
180
|
+
subject { FlavourSaver::Lexer.lex "{" }
|
181
|
+
|
182
|
+
it 'has tokens in the correct order' do
|
183
|
+
subject.map(&:type).should == [:OUT,:EOS]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,277 @@
|
|
1
|
+
require 'flavour_saver/parser'
|
2
|
+
require 'flavour_saver/lexer'
|
3
|
+
|
4
|
+
describe FlavourSaver::Parser do
|
5
|
+
let (:items) { subject.items }
|
6
|
+
|
7
|
+
it 'is a RLTK::Parser' do
|
8
|
+
subject.should be_a(RLTK::Parser)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'HTML template' do
|
12
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('<html><h1>Hello world!</h1></html>')) }
|
13
|
+
|
14
|
+
it 'is an output node' do
|
15
|
+
items.first.should be_a(FlavourSaver::OutputNode)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'has the correct contents' do
|
19
|
+
items.first.value.should == '<html><h1>Hello world!</h1></html>'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'HTML template containing a handlebars expression' do
|
24
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('<html>{{foo}}</html>')) }
|
25
|
+
|
26
|
+
it 'has template output either side of the expression' do
|
27
|
+
items.map(&:class).should == [FlavourSaver::OutputNode, FlavourSaver::ExpressionNode, FlavourSaver::OutputNode]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '{{foo}}' do
|
32
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo}}')) }
|
33
|
+
|
34
|
+
it 'contains an expression node' do
|
35
|
+
items.first.should be_an(FlavourSaver::ExpressionNode)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'calls the method "foo" with no arguments' do
|
39
|
+
items.first.method.should be_one
|
40
|
+
items.first.method.first.should be_a(FlavourSaver::CallNode)
|
41
|
+
items.first.method.first.name.should == 'foo'
|
42
|
+
items.first.method.first.arguments.should be_empty
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '{{foo.bar}}' do
|
47
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo.bar}}')) }
|
48
|
+
|
49
|
+
it 'calls two methods' do
|
50
|
+
items.first.method.size.should == 2
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'calls the method "foo" with no arguments first' do
|
54
|
+
items.first.method.first.should be_a(FlavourSaver::CallNode)
|
55
|
+
items.first.method.first.name.should == 'foo'
|
56
|
+
items.first.method.first.arguments.should be_empty
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'calls the method "bar" with no arguments second' do
|
60
|
+
items.first.method[1].should be_a(FlavourSaver::CallNode)
|
61
|
+
items.first.method[1].name.should == 'bar'
|
62
|
+
items.first.method[1].arguments.should be_empty
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '{{foo.[&@^$*].bar}}' do
|
67
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo.[&@^$*].bar}}')) }
|
68
|
+
|
69
|
+
it 'calls three methods' do
|
70
|
+
items.first.method.size.should == 3
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'calls the method "foo" with no arguments first' do
|
74
|
+
items.first.method.first.should be_a(FlavourSaver::CallNode)
|
75
|
+
items.first.method.first.name.should == 'foo'
|
76
|
+
items.first.method.first.arguments.should be_empty
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'calls the method "&@^$*" with no arguments second' do
|
80
|
+
items.first.method[1].should be_a(FlavourSaver::CallNode)
|
81
|
+
items.first.method[1].name.should == '&@^$*'
|
82
|
+
items.first.method[1].arguments.should be_empty
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'calls the method "bar" with no arguments third' do
|
86
|
+
items.first.method[2].should be_a(FlavourSaver::CallNode)
|
87
|
+
items.first.method[2].name.should == 'bar'
|
88
|
+
items.first.method[2].arguments.should be_empty
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '{{foo bar}}' do
|
93
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar}}')) }
|
94
|
+
|
95
|
+
it 'calls the method "foo" with a method argument of "bar"' do
|
96
|
+
items.first.method.should be_one
|
97
|
+
items.first.method.first.should be_a(FlavourSaver::CallNode)
|
98
|
+
items.first.method.first.name.should == 'foo'
|
99
|
+
items.first.method.first.arguments.should be_one
|
100
|
+
items.first.method.first.arguments.first.first.should be_a(FlavourSaver::CallNode)
|
101
|
+
items.first.method.first.arguments.first.first.name.should == 'bar'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '{{foo "bar" }}' do
|
106
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo "bar" }}')) }
|
107
|
+
|
108
|
+
it 'calls the method "foo" with a string argument of "bar"' do
|
109
|
+
items.first.method.should be_one
|
110
|
+
items.first.method.first.should be_a(FlavourSaver::CallNode)
|
111
|
+
items.first.method.first.name.should == 'foo'
|
112
|
+
items.first.method.first.arguments.should be_one
|
113
|
+
items.first.method.first.arguments.first.should be_a(FlavourSaver::StringNode)
|
114
|
+
items.first.method.first.arguments.first.value.should == 'bar'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '{{foo bar "baz" }}' do
|
119
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar "baz" }}')) }
|
120
|
+
|
121
|
+
it 'calls the method "foo"' do
|
122
|
+
items.first.method.should be_one
|
123
|
+
items.first.method.first.should be_a(FlavourSaver::CallNode)
|
124
|
+
items.first.method.first.name.should == 'foo'
|
125
|
+
end
|
126
|
+
|
127
|
+
describe 'with arguments' do
|
128
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar "baz" }}')).items.first.method.first.arguments }
|
129
|
+
|
130
|
+
describe '[0]' do
|
131
|
+
it 'is the method call "bar" with no arguments' do
|
132
|
+
subject.first.first.should be_a(FlavourSaver::CallNode)
|
133
|
+
subject.first.first.name.should == 'bar'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '[1]' do
|
138
|
+
it 'is the string "baz"' do
|
139
|
+
subject[1].should be_a(FlavourSaver::StringNode)
|
140
|
+
subject[1].value.should == 'baz'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '{{foo bar="baz"}}' do
|
147
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar="baz"}}')) }
|
148
|
+
|
149
|
+
it 'calls the method "foo" with the hash {:bar => "baz"} as arguments' do
|
150
|
+
items.first.method.first.should be_a(FlavourSaver::CallNode)
|
151
|
+
items.first.method.first.name.should == 'foo'
|
152
|
+
items.first.method.first.arguments.first.should be_a(Hash)
|
153
|
+
items.first.method.first.arguments.first.should == { :bar => FlavourSaver::StringNode.new('baz') }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe '{{foo bar="baz" fred="wilma"}}' do
|
158
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar="baz" fred="wilma"}}')) }
|
159
|
+
|
160
|
+
it 'calls the method "foo" with the hash {:bar => "baz", :fred => "wilma"} as arguments' do
|
161
|
+
items.first.method.first.should be_a(FlavourSaver::CallNode)
|
162
|
+
items.first.method.first.name.should == 'foo'
|
163
|
+
items.first.method.first.arguments.first.should be_a(Hash)
|
164
|
+
items.first.method.first.arguments.first.should == { :bar => FlavourSaver::StringNode.new('baz'), :fred => FlavourSaver::StringNode.new('wilma') }
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '{{foo bar="baz" fred "wilma"}}' do
|
169
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar="baz" fred "wilma"}}')) }
|
170
|
+
|
171
|
+
it 'raises an exception' do
|
172
|
+
-> { subject }.should raise_exception(RLTK::NotInLanguage)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe '{{{foo}}}' do
|
177
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{{foo}}}')) }
|
178
|
+
|
179
|
+
it 'returns a safe expression node' do
|
180
|
+
items.first.should be_a(FlavourSaver::SafeExpressionNode)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe '{{../foo}}' do
|
185
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{../foo}}')) }
|
186
|
+
|
187
|
+
it 'returns a parent call node' do
|
188
|
+
items.first.method.first.should be_a(FlavourSaver::ParentCallNode)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe '{{! comment}}' do
|
193
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{! comment}}')) }
|
194
|
+
|
195
|
+
it 'returns a comment node' do
|
196
|
+
items.first.should be_a(FlavourSaver::CommentNode)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe '{{#foo}}hello{{/foo}}' do
|
201
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{#foo}}hello{{/foo}}')) }
|
202
|
+
|
203
|
+
it 'has a block start and end' do
|
204
|
+
items.map(&:class).should == [ FlavourSaver::BlockExpressionNode ]
|
205
|
+
end
|
206
|
+
|
207
|
+
describe '#contents' do
|
208
|
+
it 'contains a single output node' do
|
209
|
+
items.first.contents.items.size.should == 1
|
210
|
+
items.first.contents.items.first.should be_a(FlavourSaver::OutputNode)
|
211
|
+
items.first.contents.items.first.value.should == 'hello'
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe '{{/foo}}' do
|
217
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{/foo}}')) }
|
218
|
+
|
219
|
+
it 'raises a syntax error' do
|
220
|
+
-> { subject }.should raise_error
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe '{{#foo}}' do
|
225
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{#foo}}')) }
|
226
|
+
|
227
|
+
it 'raises a syntax error' do
|
228
|
+
-> { subject }.should raise_error
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "{{foo}}\n" do
|
233
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex("{{foo}}\n")) }
|
234
|
+
|
235
|
+
it 'has a block start and end' do
|
236
|
+
items.map(&:class).should == [ FlavourSaver::ExpressionNode, FlavourSaver::OutputNode ]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe '{{#foo}}{{#bar}}{{/foo}}' do
|
241
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{#foo}}{{#bar}}{{/foo}}')) }
|
242
|
+
|
243
|
+
it 'raises a syntax error' do
|
244
|
+
-> { subject }.should raise_error
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe "{{#foo}}\n{{/foo}}" do
|
249
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex("{{#foo}}\n{{/foo}}")) }
|
250
|
+
|
251
|
+
it "doesn't throw a NotInLanguage exception" do
|
252
|
+
-> { subject }.should_not raise_error
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe "{{#foo}}{#foo}}{{/foo}}{{/foo}}" do
|
257
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{#foo}}{{#foo}}{{/foo}}{{/foo}}')) }
|
258
|
+
|
259
|
+
describe 'the outer block' do
|
260
|
+
let(:block) { subject.items.first }
|
261
|
+
|
262
|
+
it 'should contain another block' do
|
263
|
+
block.contents.items.size.should == 1
|
264
|
+
block.contents.items.first.should be_a(FlavourSaver::BlockExpressionNode)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe '' do
|
270
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('')) }
|
271
|
+
|
272
|
+
it 'returns an empty template' do
|
273
|
+
items.should be_empty
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|