simple_templates 0.8.7
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 +6 -0
- data/Gemfile +5 -0
- data/Guardfile +30 -0
- data/LICENSE +21 -0
- data/README.md +62 -0
- data/Rakefile +20 -0
- data/bin/simple-template +13 -0
- data/lib/simple_templates.rb +38 -0
- data/lib/simple_templates/AST/node.rb +59 -0
- data/lib/simple_templates/AST/placeholder.rb +25 -0
- data/lib/simple_templates/AST/text.rb +28 -0
- data/lib/simple_templates/delimiter.rb +6 -0
- data/lib/simple_templates/lexer.rb +73 -0
- data/lib/simple_templates/parser.rb +111 -0
- data/lib/simple_templates/parser/error.rb +6 -0
- data/lib/simple_templates/parser/node_parser.rb +45 -0
- data/lib/simple_templates/parser/placeholder.rb +83 -0
- data/lib/simple_templates/parser/text.rb +52 -0
- data/lib/simple_templates/template.rb +65 -0
- data/lib/simple_templates/unescapes.rb +5 -0
- data/lib/simple_templates/version.rb +3 -0
- data/simple_templates.gemspec +23 -0
- data/test/simple_templates/AST/node_test.rb +50 -0
- data/test/simple_templates/AST/placeholder_test.rb +28 -0
- data/test/simple_templates/AST/text_test.rb +23 -0
- data/test/simple_templates/lexer_test.rb +145 -0
- data/test/simple_templates/parser/node_parser_test.rb +38 -0
- data/test/simple_templates/parser/placeholder_test.rb +105 -0
- data/test/simple_templates/parser/text_test.rb +118 -0
- data/test/simple_templates/parser_test.rb +184 -0
- data/test/simple_templates/template_test.rb +58 -0
- data/test/test_helper.rb +21 -0
- metadata +192 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative "../../test_helper"
|
2
|
+
|
3
|
+
module SimpleTemplates
|
4
|
+
class Parser
|
5
|
+
class TestNodeParserImpl < NodeParser
|
6
|
+
STARTING_TOKENS = [:text]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe SimpleTemplates::Parser::NodeParser do
|
12
|
+
let(:target) {SimpleTemplates::Parser::NodeParser}
|
13
|
+
let(:impl) {SimpleTemplates::Parser::TestNodeParserImpl}
|
14
|
+
let(:example) {SimpleTemplates::Lexer::Token.new(:text, 'a', 0)}
|
15
|
+
|
16
|
+
describe "#initialize" do
|
17
|
+
it 'raises an error if the input is not valid' do
|
18
|
+
-> {
|
19
|
+
impl.new( SimpleTemplates::Unescapes.new('<'),
|
20
|
+
[SimpleTemplates::Lexer::Token.new(:ph_start, '<', 0)],
|
21
|
+
['name'])
|
22
|
+
}.must_raise ArgumentError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#applicable?" do
|
27
|
+
it "ignores missing" do
|
28
|
+
impl.applicable?([]).must_equal false
|
29
|
+
end
|
30
|
+
it "can be applied" do
|
31
|
+
impl.applicable?([example]).must_equal true
|
32
|
+
end
|
33
|
+
it "can't be applied" do
|
34
|
+
target.applicable?([example]).must_equal false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
|
3
|
+
describe SimpleTemplates::Parser::Placeholder do
|
4
|
+
describe '#parse' do
|
5
|
+
let(:delimiter) { SimpleTemplates::Delimiter.new(/\\</, /\\>/, /\</, /\>/) }
|
6
|
+
let(:unescapes) { SimpleTemplates::Unescapes.new('<', '>') }
|
7
|
+
let(:target) { SimpleTemplates::Parser::Placeholder }
|
8
|
+
let(:ast_ph) { SimpleTemplates::AST::Placeholder }
|
9
|
+
let(:lexer_token) { SimpleTemplates::Lexer::Token }
|
10
|
+
let(:parse_error) { SimpleTemplates::Parser::Error }
|
11
|
+
let(:valid_phs) { ['name'] }
|
12
|
+
let (:ph_tokens) do
|
13
|
+
[
|
14
|
+
lexer_token.new(:ph_start, '<', 0),
|
15
|
+
lexer_token.new(:ph_name, 'name', 1),
|
16
|
+
lexer_token.new(:ph_end, '>', 9),
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'with a placeholder as the first part of the input' do
|
21
|
+
let(:tokens) { ph_tokens << lexer_token.new(:text, ' some text', 10) }
|
22
|
+
|
23
|
+
it 'returns no errors' do
|
24
|
+
_, errors, _ = target.new(unescapes, tokens, valid_phs).parse
|
25
|
+
errors.must_be_empty
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns the remaining tokens after the placeholder' do
|
29
|
+
_, _, remaining_tokens = target.new(unescapes, tokens, valid_phs).parse
|
30
|
+
remaining_tokens.must_equal [lexer_token.new(:text, ' some text', 10)]
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns a AST placeholder' do
|
34
|
+
placeholder_ast, _, _ = target.new(unescapes, tokens, valid_phs).parse
|
35
|
+
placeholder_ast.must_equal [ast_ph.new('name', 0, true)]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'with no placeholder as the first part of the input' do
|
40
|
+
let(:tokens) { ph_tokens.unshift(lexer_token.new(:text, 'hello ', 0)) }
|
41
|
+
|
42
|
+
it 'raises an error' do
|
43
|
+
-> {
|
44
|
+
target.new(unescapes, tokens, valid_phs)
|
45
|
+
}.must_raise ArgumentError
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'with an empty placeholder' do
|
50
|
+
let(:tokens) do
|
51
|
+
[
|
52
|
+
lexer_token.new(:ph_start, '<', 0),
|
53
|
+
lexer_token.new(:ph_end, '>', 1),
|
54
|
+
lexer_token.new(:text, ' some text', 2)
|
55
|
+
]
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns an error about not finding the placeholder' do
|
59
|
+
_, errors, _ = target.new(unescapes, tokens, valid_phs).parse
|
60
|
+
errors.must_equal [
|
61
|
+
parse_error.new('Expected placeholder name token at character position 1, but found a placeholder end token instead.')
|
62
|
+
]
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns an empty Array as the remaining tokens' do
|
66
|
+
_, _, remaining_tokens = target.new(unescapes, tokens, valid_phs).parse
|
67
|
+
remaining_tokens.must_be_empty
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'returns an empty list of AST placeholders' do
|
71
|
+
placeholder_ast, _, _ = target.new(unescapes, tokens, valid_phs).parse
|
72
|
+
placeholder_ast.must_be_empty
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'with an invalid placeholder name' do
|
77
|
+
let(:tokens) do
|
78
|
+
[
|
79
|
+
lexer_token.new(:ph_start, '<', 0),
|
80
|
+
lexer_token.new(:ph_name, 'name', 1),
|
81
|
+
lexer_token.new(:text, '-', 5),
|
82
|
+
lexer_token.new(:ph_end, '>', 6),
|
83
|
+
lexer_token.new(:text, ' some text', 7),
|
84
|
+
]
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'returns an error about not finding the placeholder' do
|
88
|
+
_, errors, _ = target.new(unescapes, tokens, valid_phs).parse
|
89
|
+
errors.must_equal [
|
90
|
+
parse_error.new('Expected placeholder end token at character position 5, but found a text token instead.')
|
91
|
+
]
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'returns an empty Array of remaining tokens' do
|
95
|
+
_, _, remaining_tokens = target.new(unescapes, tokens, valid_phs).parse
|
96
|
+
remaining_tokens.must_be_empty
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns an empty Array of AST placeholders' do
|
100
|
+
placeholder_ast, _, _ = target.new(unescapes, tokens, valid_phs).parse
|
101
|
+
placeholder_ast.must_be_empty
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
|
3
|
+
describe SimpleTemplates::Parser::Text do
|
4
|
+
describe '#parse' do
|
5
|
+
let(:delimiter) { SimpleTemplates::Delimiter.new(/\\</, /\\>/, /\</, /\>/) }
|
6
|
+
let(:unescapes) { SimpleTemplates::Unescapes.new('<', '>') }
|
7
|
+
let(:ast_text) { SimpleTemplates::AST::Text }
|
8
|
+
let(:lexer_token) { SimpleTemplates::Lexer::Token }
|
9
|
+
let(:target) { SimpleTemplates::Parser::Text }
|
10
|
+
let(:valid_phs) { ['name'] }
|
11
|
+
let(:ph_tokens) do
|
12
|
+
[
|
13
|
+
lexer_token.new(:ph_start, '<', 6),
|
14
|
+
lexer_token.new(:ph_name, 'name', 7),
|
15
|
+
lexer_token.new(:ph_end, '>', 15)
|
16
|
+
]
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'with a valid input' do
|
20
|
+
let(:tokens) { [lexer_token.new(:text, 'hello ', 0)].concat(ph_tokens) }
|
21
|
+
|
22
|
+
it 'returns a list with only the text before the placeholder' do
|
23
|
+
txt_nodes, _, _ = target.new(unescapes, tokens, valid_phs).parse
|
24
|
+
txt_nodes.must_equal [ast_text.new('hello ', 0, true)]
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns no errors' do
|
28
|
+
_, errors_list, _ = target.new(unescapes, tokens, valid_phs).parse
|
29
|
+
errors_list.must_be_empty
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'returns the remaining tokens containing only the placeholder part' do
|
33
|
+
_, _, remaining_tokens = target.new(unescapes, tokens, valid_phs).parse
|
34
|
+
remaining_tokens.must_equal ph_tokens
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'with a new line in the placeholder name' do
|
39
|
+
let(:other_tokens) do
|
40
|
+
[
|
41
|
+
lexer_token.new(:ph_start, '<', 6),
|
42
|
+
lexer_token.new(:ph_name, 'na', 7),
|
43
|
+
lexer_token.new(:text, "\nme", 9),
|
44
|
+
lexer_token.new(:ph_end, '>', 12)
|
45
|
+
]
|
46
|
+
end
|
47
|
+
let(:tokens) { [lexer_token.new(:text, 'hello ', 0)].concat(other_tokens) }
|
48
|
+
|
49
|
+
it 'returns the remainin tokens with a new line as text in the placeholder' do
|
50
|
+
_, _, remaining_tokens = target.new(unescapes, tokens, valid_phs).parse
|
51
|
+
remaining_tokens.must_equal other_tokens
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns no errors' do
|
55
|
+
_, errors_list, _ = target.new(unescapes, tokens, valid_phs).parse
|
56
|
+
errors_list.must_be_empty
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns the text nodes' do
|
60
|
+
txt_nodes, _, _ = target.new(unescapes, tokens, valid_phs).parse
|
61
|
+
txt_nodes.must_equal [ast_text.new('hello ', 0, true)]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'with leading and trailing whitespaces' do
|
66
|
+
let(:tokens) { [lexer_token.new(:text, 'hello ', 0)].concat(ph_tokens) }
|
67
|
+
|
68
|
+
it 'returns the remaining tokens with no placeholder name' do
|
69
|
+
_, _, remaining_tokens = target.new(unescapes, tokens, valid_phs ).parse
|
70
|
+
remaining_tokens.must_equal ph_tokens
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'returns the text nodes' do
|
74
|
+
txt_nodes, _, _ = target.new(unescapes, tokens, valid_phs ).parse
|
75
|
+
txt_nodes.must_equal [ast_text.new('hello ', 0, true)]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'with a newline after the placeholder' do
|
80
|
+
let(:other_tokens) { ph_tokens << lexer_token.new(:text, "\n world", 12) }
|
81
|
+
let(:tokens) { [lexer_token.new(:text, 'hello ', 0)].concat(other_tokens) }
|
82
|
+
|
83
|
+
it 'returns a list with remaining tokens with the placeholder and followed by text' do
|
84
|
+
_, _, remaining_tokens = target.new(unescapes, tokens, valid_phs ).parse
|
85
|
+
remaining_tokens.must_equal other_tokens
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns no errors' do
|
89
|
+
_, errors_list, _ = target.new(unescapes, tokens, valid_phs).parse
|
90
|
+
errors_list.must_be_empty
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns the text nodes' do
|
94
|
+
txt_nodes, _, _ = target.new(unescapes, tokens, valid_phs ).parse
|
95
|
+
txt_nodes.must_equal [ast_text.new('hello ', 0, true)]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'with a new line character before the placeholder' do
|
100
|
+
let(:tokens) { [lexer_token.new(:text, "hello \n", 0)].concat(ph_tokens) }
|
101
|
+
|
102
|
+
it 'returns remaining tokens with the placeholder' do
|
103
|
+
_, _, remaining_tokens = target.new(unescapes, tokens, valid_phs ).parse
|
104
|
+
remaining_tokens.must_equal ph_tokens
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns no errors' do
|
108
|
+
_, errors_list, _ = target.new(unescapes, tokens, valid_phs).parse
|
109
|
+
errors_list.must_be_empty
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'returns the text nodes' do
|
113
|
+
txt_nodes, _, _ = target.new(unescapes, tokens, valid_phs ).parse
|
114
|
+
txt_nodes.must_equal [ast_text.new("hello \n", 0, true)]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
describe SimpleTemplates::Parser do
|
6
|
+
describe "#parse" do
|
7
|
+
it "parses a simple valid template" do
|
8
|
+
pholder = SimpleTemplates::AST::Placeholder.new('bar', 4, true)
|
9
|
+
|
10
|
+
SimpleTemplates.parse('foo <bar>', ['bar']).must_equal SimpleTemplates::Template.new(
|
11
|
+
[SimpleTemplates::AST::Text.new('foo ', 0, true), pholder],
|
12
|
+
[],
|
13
|
+
[]
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "parses a two-byte unicode character" do
|
18
|
+
SimpleTemplates.parse('Ford® Flex').must_equal SimpleTemplates::Template.new(
|
19
|
+
[SimpleTemplates::AST::Text.new('Ford® Flex', 0, true)],
|
20
|
+
[],
|
21
|
+
[]
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "marks all nodes as allowed and returns no errors if the allowed_placeholders is nil" do
|
26
|
+
pholder = SimpleTemplates::AST::Placeholder.new('bar', 4, true)
|
27
|
+
|
28
|
+
SimpleTemplates.parse('foo <bar>', nil).must_equal SimpleTemplates::Template.new(
|
29
|
+
[SimpleTemplates::AST::Text.new('foo ', 0, true), pholder],
|
30
|
+
[],
|
31
|
+
[]
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "marks all nodes as disallowed and returns errors if the allowed_placeholders is empty" do
|
36
|
+
pholder = SimpleTemplates::AST::Placeholder.new('bar', 4, false)
|
37
|
+
|
38
|
+
SimpleTemplates.parse('foo <bar>', []).must_equal SimpleTemplates::Template.new(
|
39
|
+
[SimpleTemplates::AST::Text.new('foo ', 0, true), pholder],
|
40
|
+
[SimpleTemplates::Parser::Error.new("Invalid Placeholder with contents, 'bar' found starting at position 4.")],
|
41
|
+
[]
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "compresses adjacent text nodes after unescaping" do
|
46
|
+
pholder = SimpleTemplates::AST::Placeholder.new('bar', 7, true)
|
47
|
+
|
48
|
+
SimpleTemplates.parse('foo \< <bar>', ['bar']).ast.must_equal [
|
49
|
+
SimpleTemplates::AST::Text.new('foo < ', 0, true), pholder
|
50
|
+
]
|
51
|
+
end
|
52
|
+
|
53
|
+
it "allows text after placeholders" do
|
54
|
+
pholder = SimpleTemplates::AST::Placeholder.new('bar', 7, true)
|
55
|
+
pholder2 = SimpleTemplates::AST::Placeholder.new('baz', 13, true)
|
56
|
+
|
57
|
+
SimpleTemplates.parse('foo \< <bar> <baz>', [:bar, :baz]).
|
58
|
+
must_equal SimpleTemplates::Template.new(
|
59
|
+
[
|
60
|
+
SimpleTemplates::AST::Text.new('foo < ', 0, true),
|
61
|
+
pholder,
|
62
|
+
SimpleTemplates::AST::Text.new(' ', 12, true),
|
63
|
+
pholder2
|
64
|
+
],
|
65
|
+
[],
|
66
|
+
[]
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "allows templates starting with placeholders" do
|
71
|
+
pholder = SimpleTemplates::AST::Placeholder.new('foo', 0, true)
|
72
|
+
|
73
|
+
SimpleTemplates.parse('<foo> bar', ['foo']).ast.must_equal [
|
74
|
+
pholder,
|
75
|
+
SimpleTemplates::AST::Text.new(' bar', 5, true)
|
76
|
+
]
|
77
|
+
end
|
78
|
+
|
79
|
+
it "allows templates with placeholders that contain underscores" do
|
80
|
+
pholder = SimpleTemplates::AST::Placeholder.new('some_name', 0, true)
|
81
|
+
|
82
|
+
SimpleTemplates.parse('<some_name> bar', [:some_name]).ast.must_equal [
|
83
|
+
pholder,
|
84
|
+
SimpleTemplates::AST::Text.new(' bar', 11, true)
|
85
|
+
]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "parses other placeholder types by changing the delimiter Struct" do
|
89
|
+
pholder = SimpleTemplates::AST::Placeholder.new('foo', 0, true)
|
90
|
+
|
91
|
+
delim = SimpleTemplates::Delimiter.new(/\\\[\\\[/, /\\\]\\\]/, /\[\[/, /\]\]/)
|
92
|
+
|
93
|
+
ast, errors, remaining_tokens =
|
94
|
+
SimpleTemplates::Template.new(
|
95
|
+
*SimpleTemplates::Parser.new(
|
96
|
+
SimpleTemplates::Unescapes.new('[[', ']]'),
|
97
|
+
SimpleTemplates::Lexer.new(delim, '[[foo]] \[\[ bar').tokenize,
|
98
|
+
['foo']
|
99
|
+
).parse
|
100
|
+
)
|
101
|
+
|
102
|
+
ast.ast.must_equal [
|
103
|
+
pholder,
|
104
|
+
SimpleTemplates::AST::Text.new(' [[ bar', 7, true)
|
105
|
+
]
|
106
|
+
end
|
107
|
+
|
108
|
+
it "returns an error when an opening bracket is found without a closing bracket" do
|
109
|
+
SimpleTemplates.parse('foo < <bar>', [:bar]).errors.must_equal [
|
110
|
+
SimpleTemplates::Parser::Error.new("Expected placeholder name token at character position 5, but found a text token instead.")
|
111
|
+
]
|
112
|
+
end
|
113
|
+
|
114
|
+
it "returns an error when a closing bracket is found before an opening bracket" do
|
115
|
+
SimpleTemplates.parse('foo > <bar>', [:bar]).errors.must_equal [
|
116
|
+
SimpleTemplates::Parser::Error.new('Encountered unexpected token in stream (placeholder end), but expected to see one of the following types: placeholder start, quoted placeholder start, quoted placeholder end, text.')
|
117
|
+
]
|
118
|
+
end
|
119
|
+
|
120
|
+
it "returns errors about invalid placeholders encountered before a syntactical error" do
|
121
|
+
SimpleTemplates.parse('foo <baz> >', []).errors.must_equal [
|
122
|
+
SimpleTemplates::Parser::Error.new('Encountered unexpected token in stream (placeholder end), but expected to see one of the following types: placeholder start, quoted placeholder start, quoted placeholder end, text.'),
|
123
|
+
SimpleTemplates::Parser::Error.new('Invalid Placeholder with contents, \'baz\' found starting at position 4.')
|
124
|
+
]
|
125
|
+
end
|
126
|
+
|
127
|
+
it "returns an error when an invalid placeholder name is found" do
|
128
|
+
SimpleTemplates.parse('foo <baz>', [:bar]).errors.must_equal [
|
129
|
+
SimpleTemplates::Parser::Error.
|
130
|
+
new("Invalid Placeholder with contents, 'baz' found starting at position 4.")]
|
131
|
+
end
|
132
|
+
|
133
|
+
it "returns an error when a placeholder with newlines is found" do
|
134
|
+
SimpleTemplates.parse("foo <ba\nr>", ["ba\nr"]).errors.must_equal [
|
135
|
+
SimpleTemplates::Parser::Error.new("Expected placeholder end token at character position 7, but found a text token instead.")]
|
136
|
+
end
|
137
|
+
|
138
|
+
it "returns an error when a placeholder with spaces is found" do
|
139
|
+
SimpleTemplates.parse("foo <ba r>", ['ba r']).errors.must_equal [
|
140
|
+
SimpleTemplates::Parser::Error.
|
141
|
+
new("Expected placeholder end token at character position 7, but found a text token instead.")]
|
142
|
+
end
|
143
|
+
|
144
|
+
it "returns an error when a placeholder with tabs is found" do
|
145
|
+
SimpleTemplates.parse("foo <ba\tr>", ["ba\tr"]).errors.must_equal [
|
146
|
+
SimpleTemplates::Parser::Error.new("Expected placeholder end token at character position 7, but found a text token instead.")]
|
147
|
+
end
|
148
|
+
|
149
|
+
it "returns an error when a placeholder with other characters is found" do
|
150
|
+
SimpleTemplates.parse("foo <ba-r>", ['ba-r']).errors.must_equal [
|
151
|
+
SimpleTemplates::Parser::Error.new("Expected placeholder end token at character position 7, but found a text token instead.")]
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
it "returns an multiple errors when there are multiple non-whitelisted placeholders" do
|
156
|
+
SimpleTemplates.parse('foo <baz> <buz>', []).errors.must_equal [
|
157
|
+
SimpleTemplates::Parser::Error.new("Invalid Placeholder with contents, 'baz' found starting at position 4."),
|
158
|
+
SimpleTemplates::Parser::Error.new("Invalid Placeholder with contents, 'buz' found starting at position 10.")
|
159
|
+
]
|
160
|
+
end
|
161
|
+
|
162
|
+
it "returns an error when multiple opening brackets are found" do
|
163
|
+
SimpleTemplates.parse('foo <<baz>', ['bar']).errors.must_equal [
|
164
|
+
SimpleTemplates::Parser::Error.new("Expected placeholder name token at character position 5, but found a placeholder start token instead.")]
|
165
|
+
end
|
166
|
+
|
167
|
+
it "returns an error when empty placeholder is found" do
|
168
|
+
SimpleTemplates.parse('foo <>', ['bar']).errors.must_equal [
|
169
|
+
SimpleTemplates::Parser::Error.new("Expected placeholder name token at character position 5, but found a placeholder end token instead.")]
|
170
|
+
end
|
171
|
+
|
172
|
+
it "returns an error when a closing tag is expected, but an opening tag is found" do
|
173
|
+
SimpleTemplates.parse('foo <bar<>', ['bar']).errors.must_equal [
|
174
|
+
SimpleTemplates::Parser::Error.new("Expected placeholder end token at character position 8, but found a placeholder start token instead.")
|
175
|
+
]
|
176
|
+
end
|
177
|
+
|
178
|
+
it "returns an error when a tag is not closed before the end of the input" do
|
179
|
+
SimpleTemplates.parse('foo <bar', ['bar']).errors.must_equal [
|
180
|
+
SimpleTemplates::Parser::Error.new("Expected placeholder end token, but reached end of input.")
|
181
|
+
]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
describe SimpleTemplates::Template do
|
6
|
+
describe "#placeholder_names" do
|
7
|
+
it "should return a set of the placeholder names in the template" do
|
8
|
+
SimpleTemplates.parse('foo <bar> <baz>', [:bar, :baz]).
|
9
|
+
placeholder_names.must_equal ['bar', 'baz'].to_set
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#render" do
|
14
|
+
it "processes an empty template" do
|
15
|
+
SimpleTemplates.parse('', []).render(
|
16
|
+
{bar: 'baz'}
|
17
|
+
).must_equal ''
|
18
|
+
end
|
19
|
+
|
20
|
+
it "interpolates a simple, valid template" do
|
21
|
+
SimpleTemplates.parse('foo <bar>', [:bar]).render(
|
22
|
+
{bar: 'baz'}
|
23
|
+
).must_equal 'foo baz'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "interpolates a template containing an escaped '>'" do
|
27
|
+
SimpleTemplates.parse("foo <bar> \\>", [:bar]).render(
|
28
|
+
{bar: 'baz'}
|
29
|
+
).must_equal "foo baz \>"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "interpolates a template containing an escaped '<'" do
|
33
|
+
SimpleTemplates.parse("foo <bar> \\<", [:bar]).render(
|
34
|
+
{bar: 'baz'}
|
35
|
+
).must_equal "foo baz \<"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "interpolates a template containing an escaped escape character" do
|
39
|
+
SimpleTemplates.parse("foo <bar> \\", [:bar]).render(
|
40
|
+
{bar: 'baz'}
|
41
|
+
).must_equal "foo baz \\"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#==" do
|
46
|
+
it "compares the ast" do
|
47
|
+
SimpleTemplates::Template.new([:ast_a], [], []).wont_equal SimpleTemplates::Template.new([:ast_b], [], [])
|
48
|
+
end
|
49
|
+
|
50
|
+
it "compares the errors" do
|
51
|
+
SimpleTemplates::Template.new([], [:error_a], []).wont_equal SimpleTemplates::Template.new([], [:error_b], [])
|
52
|
+
end
|
53
|
+
|
54
|
+
it "compares the remaining tokens" do
|
55
|
+
SimpleTemplates::Template.new([], [], [:remaining_tokens_a]).wont_equal SimpleTemplates::Template.new([], [], [:remaining_tokens_b])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|