flavour_saver 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|