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,45 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module SimpleTemplates
|
4
|
+
class Parser
|
5
|
+
# A Base class for the Placeholders and Text parsers
|
6
|
+
class NodeParser
|
7
|
+
|
8
|
+
# The Base class doesn't accept any tokens for parsing, since it isn't
|
9
|
+
# supposed to be instantiated.
|
10
|
+
# @return [Set<Object>]
|
11
|
+
STARTING_TOKENS = Set[]
|
12
|
+
|
13
|
+
# Checks if the class is applicable for the first token in the list
|
14
|
+
# @param tokens <Array[SimpleTemplates::Lexer::Token]> a list of tokens
|
15
|
+
def self.applicable?(tokens)
|
16
|
+
tokens.any? && self::STARTING_TOKENS.include?(tokens.first.type)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Initializes a new NodeParser. Please note that this class is not
|
20
|
+
# supposed to be instantiated.
|
21
|
+
# Raises an error if it is not applicable.
|
22
|
+
# @param unescapes [SimpleTemplates::Unescapes] a Unescapes object
|
23
|
+
# @param tokens <Array[SimpleTemplates::Lexer::Token]> a list of tokens
|
24
|
+
# @param allowed_placeholders <Array[String]> a list of allowed placeholders
|
25
|
+
def initialize(unescapes, tokens, allowed_placeholders)
|
26
|
+
raise ArgumentError, "Invalid Parser for String!" unless self.class.applicable?(tokens)
|
27
|
+
|
28
|
+
@unescapes = unescapes.to_h.clone.freeze
|
29
|
+
@tokens = tokens.clone.freeze
|
30
|
+
|
31
|
+
# Placeholders to match are mapped to strings for our validity checks.
|
32
|
+
# This is because if we go the other way and convert all possible
|
33
|
+
# placeholder names to symbols before comparing to the whitelist, we
|
34
|
+
# could cause a memory leak by allocating an infinite amount of symbols
|
35
|
+
# that won't be garbage-collected.
|
36
|
+
@allowed_placeholders = allowed_placeholders &&
|
37
|
+
allowed_placeholders.map(&:to_s).freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_reader :tokens, :allowed_placeholders, :unescapes
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'simple_templates/parser/node_parser'
|
4
|
+
require 'simple_templates/AST/placeholder'
|
5
|
+
|
6
|
+
module SimpleTemplates
|
7
|
+
class Parser
|
8
|
+
# Recognizes a set of input tokens as a Placeholder.
|
9
|
+
class Placeholder < NodeParser
|
10
|
+
|
11
|
+
# The expected tag order for a valid placeholder.
|
12
|
+
EXPECTED_TAG_ORDER = [:ph_start, :ph_name, :ph_end]
|
13
|
+
|
14
|
+
# The starting token that the input must have
|
15
|
+
STARTING_TOKENS = Set[:ph_start]
|
16
|
+
|
17
|
+
# If this stream starts with a placeholder token, parse out the
|
18
|
+
# Placeholder, or a Result with errors indicating the syntax problem.
|
19
|
+
# @return <Array <Array[SimpleTemplates::AST::Placeholder]>,
|
20
|
+
# <Array[SimpleTemplates::Parser::Error]>,
|
21
|
+
# <Array[SimpleTemplates::Lexer::Token]>> an +Array+ with the
|
22
|
+
# AST::Placeholder as first element, a list of parser errors and a list
|
23
|
+
# of the remaining tokens.
|
24
|
+
def parse
|
25
|
+
errors = check_placeholder_syntax
|
26
|
+
|
27
|
+
remaining_tokens = []
|
28
|
+
|
29
|
+
placeholder_ast = if errors.empty?
|
30
|
+
remaining_tokens = tokens[3..-1] || []
|
31
|
+
|
32
|
+
allowed = allowed_placeholders.nil? ||
|
33
|
+
allowed_placeholders.include?(tag_name.content)
|
34
|
+
|
35
|
+
[AST::Placeholder.new(tag_name.content, tag_start.pos, allowed)]
|
36
|
+
else
|
37
|
+
[] # we don't have an AST portion to return if we encountered errors
|
38
|
+
end
|
39
|
+
|
40
|
+
[placeholder_ast, errors, remaining_tokens]
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def check_placeholder_syntax
|
46
|
+
expected_order_with_found_tokens = EXPECTED_TAG_ORDER.zip(tag_tokens)
|
47
|
+
|
48
|
+
errors = expected_order_with_found_tokens.
|
49
|
+
reduce([]) do |errs, (expected_type, found_tag)|
|
50
|
+
|
51
|
+
if found_tag.nil?
|
52
|
+
break errs << Parser::Error.new(
|
53
|
+
"Expected #{FRIENDLY_TAG_NAMES.fetch(expected_type)} token, but" +
|
54
|
+
" reached end of input.")
|
55
|
+
|
56
|
+
elsif expected_type != found_tag.type
|
57
|
+
break errs << Parser::Error.new(
|
58
|
+
"Expected #{FRIENDLY_TAG_NAMES.fetch(expected_type)} token at " +
|
59
|
+
"character position #{found_tag.pos}, but found a " +
|
60
|
+
"#{FRIENDLY_TAG_NAMES.fetch(found_tag.type)} token instead.")
|
61
|
+
|
62
|
+
else
|
63
|
+
# This token was expected at this point in the placeholder sequence,
|
64
|
+
# no need to add errors.
|
65
|
+
errs
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def tag_tokens
|
71
|
+
tokens[0..2].compact
|
72
|
+
end
|
73
|
+
|
74
|
+
def tag_start
|
75
|
+
tokens[0]
|
76
|
+
end
|
77
|
+
|
78
|
+
def tag_name
|
79
|
+
tokens[1]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'simple_templates/parser/node_parser'
|
4
|
+
require 'simple_templates/AST/text'
|
5
|
+
|
6
|
+
module SimpleTemplates
|
7
|
+
class Parser
|
8
|
+
#Recognizes a set of input tokens as a Text
|
9
|
+
class Text < NodeParser
|
10
|
+
|
11
|
+
# The starting tokens that the input can have
|
12
|
+
# @return [Set<Symbol>]
|
13
|
+
STARTING_TOKENS = Set[:quoted_ph_start, :quoted_ph_end, :text]
|
14
|
+
|
15
|
+
# A hash containing the method for a quoted placeholder start or end
|
16
|
+
# @return [Hash{ Symbol => Symbol }]
|
17
|
+
UNESCAPE_METHODS = {
|
18
|
+
quoted_ph_start: :start,
|
19
|
+
quoted_ph_end: :end
|
20
|
+
}
|
21
|
+
|
22
|
+
# It parses the stream, if it starts with a text node then it parses out
|
23
|
+
# the text until it is not applicable for the input anymore.
|
24
|
+
# @return <Array <Array[SimpleTemplates::AST::Text]>,
|
25
|
+
# <Array>,
|
26
|
+
# <Array[SimpleTemplates::Lexer::Token]>> an +Array+ with a list of
|
27
|
+
# AST::Text as first element, always an Empty list of Errors and the
|
28
|
+
# remaining unparsed tokens.
|
29
|
+
def parse
|
30
|
+
txt_node = nil
|
31
|
+
toks = tokens.dup
|
32
|
+
|
33
|
+
while self.class.applicable?(toks)
|
34
|
+
next_txt_token = toks.shift
|
35
|
+
|
36
|
+
this_txt_node =
|
37
|
+
AST::Text.new(unescape(next_txt_token), next_txt_token.pos, true)
|
38
|
+
|
39
|
+
txt_node = txt_node.nil? ? this_txt_node : txt_node + this_txt_node
|
40
|
+
end
|
41
|
+
|
42
|
+
[[txt_node], [], toks || []]
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def unescape(token)
|
48
|
+
unescapes[UNESCAPE_METHODS[token.type]] || token.content
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'simple_templates/AST/placeholder'
|
4
|
+
|
5
|
+
module SimpleTemplates
|
6
|
+
#
|
7
|
+
# A +Template+ is a renderable collection of SimpleTemplates::AST nodes.
|
8
|
+
#
|
9
|
+
# @!attribute [r] ast
|
10
|
+
# @return <Array[SimpleTemplates::AST::Node]> a list of renderable nodes
|
11
|
+
# @!attribute [r] errors
|
12
|
+
# @return <Array[SimpleTemplates::Parser::Error]> a list of errors found
|
13
|
+
# during parsing
|
14
|
+
# @!attribute [r] remaining_tokens
|
15
|
+
# @return <Array[SimpleTemplates::Lexer::Token]> a list of the remaining
|
16
|
+
# not parsed tokens
|
17
|
+
#
|
18
|
+
class Template
|
19
|
+
|
20
|
+
attr_reader :ast, :errors, :remaining_tokens
|
21
|
+
|
22
|
+
# Initializes a new Template
|
23
|
+
# @param ast <Array[SimpleTemplates::AST::Node]> list of AST nodes
|
24
|
+
# @param errors <Array[SimpleTemplates::Parser::Error]> a list of errors
|
25
|
+
# found during parsing
|
26
|
+
# @param remaining_tokens <Array[SimpleTemplates::Lexer::Token]> list of
|
27
|
+
# unparsed tokens from the input
|
28
|
+
def initialize(ast = [], errors = [], remaining_tokens = [])
|
29
|
+
@ast = ast.clone.freeze
|
30
|
+
@errors = errors.clone.freeze
|
31
|
+
@remaining_tokens = remaining_tokens.clone.freeze
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns all placeholder names used in the template.
|
35
|
+
# @return [Set<String>] Placeholders content
|
36
|
+
def placeholder_names
|
37
|
+
placeholders.map(&:contents).to_set
|
38
|
+
end
|
39
|
+
|
40
|
+
# Accepts a hash with the placeholder names as keys and the values for
|
41
|
+
# substitution
|
42
|
+
# @param substitutions [Hash{Symbol => String}] a hash with the placeholder
|
43
|
+
# name as the key and the substitution for that placeholder as value
|
44
|
+
# @return [String] The concatenated result of rendering the substitutions
|
45
|
+
def render(substitutions)
|
46
|
+
raise errors.map(&:message).join(", ") unless errors.empty?
|
47
|
+
ast.map { |node| node.render(substitutions) }.join
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns all the +SimpleTemplates::AST::Placeholder+ nodes in the +ast+
|
51
|
+
# list of the instance
|
52
|
+
# @return [Set<SimpleTemplates::AST::Placeholder>]
|
53
|
+
def placeholders
|
54
|
+
ast.select{ |node| SimpleTemplates::AST::Placeholder === node }.to_set
|
55
|
+
end
|
56
|
+
|
57
|
+
# Compares a +Template+ with another by comparing the +ast+, +errors+
|
58
|
+
# and the +remaining_tokens+ of each one
|
59
|
+
def ==(other)
|
60
|
+
ast == other.ast &&
|
61
|
+
errors == other.errors &&
|
62
|
+
remaining_tokens == other.remaining_tokens
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
|
4
|
+
require File.expand_path("../lib/simple_templates/version.rb", __FILE__)
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "simple_templates"
|
8
|
+
s.version = SimpleTemplates::VERSION
|
9
|
+
s.authors = ["Michal Papis"]
|
10
|
+
s.email = ["support@stackbuilders.com"]
|
11
|
+
s.homepage = "https://github.com/stackbuilders/simple_templates"
|
12
|
+
s.summary = "Minimalistic templates engine"
|
13
|
+
s.license = "MIT"
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.executables << "simple-template"
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.required_ruby_version = ">= 2.0.0"
|
18
|
+
%w{rake minitest simplecov coveralls guard-minitest yard}.each do |name|
|
19
|
+
s.add_development_dependency(name)
|
20
|
+
end
|
21
|
+
s.add_development_dependency("guard", ">=2.12.8", "<3")
|
22
|
+
# s.add_development_dependency("smf-gem")
|
23
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative "../../test_helper"
|
2
|
+
|
3
|
+
module SimpleTemplates
|
4
|
+
module AST
|
5
|
+
class TestNodeImpl < Node
|
6
|
+
def render(context)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe SimpleTemplates::AST::Node do
|
13
|
+
let(:target) {SimpleTemplates::AST::Node}
|
14
|
+
let(:allowed) {target.new("a", 0, true)}
|
15
|
+
let(:impl) {SimpleTemplates::AST::TestNodeImpl.new("a", 0, true)}
|
16
|
+
|
17
|
+
describe "==" do
|
18
|
+
it "is equal" do
|
19
|
+
allowed.must_equal target.new("a", 0, true)
|
20
|
+
end
|
21
|
+
it "isn't equal" do
|
22
|
+
allowed.wont_equal target.new("b", 0, true)
|
23
|
+
allowed.wont_equal target.new("a", 1, true)
|
24
|
+
allowed.wont_equal target.new("a", 0, false)
|
25
|
+
allowed.wont_equal target.new("b", 1, false)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "allowed?" do
|
30
|
+
it "is allowed?" do
|
31
|
+
allowed.allowed?.must_equal true
|
32
|
+
end
|
33
|
+
it "isn't allowed?" do
|
34
|
+
target.new("a", 0, false).allowed?.must_equal false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "render" do
|
39
|
+
let(:context) { {a: 1} }
|
40
|
+
it "fails" do
|
41
|
+
->(){
|
42
|
+
allowed.render(context)
|
43
|
+
}.must_raise NotImplementedError
|
44
|
+
end
|
45
|
+
it "succeeds" do
|
46
|
+
impl.render(context).must_be_nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative "../../test_helper"
|
2
|
+
|
3
|
+
describe SimpleTemplates::AST::Placeholder do
|
4
|
+
let(:target) {SimpleTemplates::AST::Placeholder}
|
5
|
+
|
6
|
+
describe "render" do
|
7
|
+
|
8
|
+
let(:substitutions) { { my_placeholder: 'result1' } }
|
9
|
+
|
10
|
+
it "fails when the placeholder name is not in the given Hash" do
|
11
|
+
->(){
|
12
|
+
target.new('not_in_substitutions', 0, true).render(substitutions)
|
13
|
+
}.must_raise KeyError
|
14
|
+
end
|
15
|
+
|
16
|
+
it "fails when the placeholder is marked as invalid" do
|
17
|
+
->(){
|
18
|
+
target.new('my_placeholder', 0, false).render(substitutions)
|
19
|
+
}.must_raise RuntimeError
|
20
|
+
end
|
21
|
+
|
22
|
+
it "succeeds" do
|
23
|
+
target.new('my_placeholder', 0, true).
|
24
|
+
render(substitutions).must_equal("result1")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative "../../test_helper"
|
2
|
+
|
3
|
+
describe SimpleTemplates::AST::Text do
|
4
|
+
let(:target) {SimpleTemplates::AST::Text}
|
5
|
+
let(:valid) {target.new("a", 0, true)}
|
6
|
+
let(:context) {Struct.new(:a).new("result1")}
|
7
|
+
|
8
|
+
describe "render" do
|
9
|
+
it "succeeds" do
|
10
|
+
valid.render(context).must_equal("a")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "+" do
|
15
|
+
it "adds valid" do
|
16
|
+
valid.+(target.new("b", 1, true)).must_equal target.new("ab", 0, true)
|
17
|
+
end
|
18
|
+
it "adds invalid" do
|
19
|
+
valid.+(target.new("b", 1, false)).must_equal target.new("ab", 0, false)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
describe SimpleTemplates::Lexer do
|
4
|
+
let(:delimiter) { SimpleTemplates::Delimiter.new(/\\</, /\\>/, /\</, /\>/) }
|
5
|
+
let(:token) { SimpleTemplates::Lexer::Token }
|
6
|
+
|
7
|
+
describe '#tokenize' do
|
8
|
+
it 'tokenizes a string with no placeholders' do
|
9
|
+
raw_input = 'string with no placeholders'
|
10
|
+
tokens = SimpleTemplates::Lexer.new(
|
11
|
+
delimiter,
|
12
|
+
raw_input
|
13
|
+
).tokenize
|
14
|
+
|
15
|
+
tokens.must_equal [
|
16
|
+
token.new(:text, 'string with no placeholders', 0)
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'tokenizes a string with placeholders' do
|
21
|
+
raw_input = 'string with <placeholder>'
|
22
|
+
tokens = SimpleTemplates::Lexer.new(
|
23
|
+
delimiter,
|
24
|
+
raw_input
|
25
|
+
).tokenize
|
26
|
+
|
27
|
+
tokens.must_equal [
|
28
|
+
token.new(:text, 'string with ', 0),
|
29
|
+
token.new(:ph_start, '<', 12),
|
30
|
+
token.new(:ph_name, 'placeholder', 13),
|
31
|
+
token.new(:ph_end, '>', 24)
|
32
|
+
]
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'tokenizes a string with invalid placeholders, containing a new line character' do
|
36
|
+
raw_input = "string with <foo\nbar> text"
|
37
|
+
tokens = SimpleTemplates::Lexer.new(
|
38
|
+
delimiter,
|
39
|
+
raw_input
|
40
|
+
).tokenize
|
41
|
+
|
42
|
+
tokens.must_equal [
|
43
|
+
token.new(:text, 'string with ', 0),
|
44
|
+
token.new(:ph_start, '<', 12),
|
45
|
+
token.new(:ph_name, 'foo', 13),
|
46
|
+
token.new(:text, "\nbar", 16),
|
47
|
+
token.new(:ph_end, '>', 20),
|
48
|
+
token.new(:text, ' text', 21)
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'tokenizes a string with invalid placeholders, contains leading and trailing space' do
|
53
|
+
raw_input = "string with < foobar > text"
|
54
|
+
tokens = SimpleTemplates::Lexer.new(
|
55
|
+
delimiter,
|
56
|
+
raw_input
|
57
|
+
).tokenize
|
58
|
+
|
59
|
+
tokens.must_equal [
|
60
|
+
token.new(:text, 'string with ', 0),
|
61
|
+
token.new(:ph_start, '<', 12),
|
62
|
+
token.new(:text, ' foobar ', 13),
|
63
|
+
token.new(:ph_end, '>', 21),
|
64
|
+
token.new(:text, ' text', 22)
|
65
|
+
]
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'tokenizes a string with placeholders and a newline character' do
|
69
|
+
raw_input = "string with <placeholder>\n Something else"
|
70
|
+
tokens = SimpleTemplates::Lexer.new(
|
71
|
+
delimiter,
|
72
|
+
raw_input
|
73
|
+
).tokenize
|
74
|
+
|
75
|
+
tokens.must_equal [
|
76
|
+
token.new(:text, 'string with ', 0),
|
77
|
+
token.new(:ph_start, '<', 12),
|
78
|
+
token.new(:ph_name, 'placeholder', 13),
|
79
|
+
token.new(:ph_end, '>', 24),
|
80
|
+
token.new(:text, "\n Something else", 25)
|
81
|
+
]
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'tokenizes a string with invalid placeholder and an empty placeholder name' do
|
85
|
+
raw_input = "string with <> text"
|
86
|
+
tokens = SimpleTemplates::Lexer.new(
|
87
|
+
delimiter,
|
88
|
+
raw_input
|
89
|
+
).tokenize
|
90
|
+
|
91
|
+
tokens.must_equal [
|
92
|
+
token.new(:text, 'string with ', 0),
|
93
|
+
token.new(:ph_start, '<', 12),
|
94
|
+
token.new(:ph_end, '>', 13),
|
95
|
+
token.new(:text, ' text', 14)
|
96
|
+
]
|
97
|
+
end
|
98
|
+
it 'tokenizes a string with placeholders having a new line character in the placeholder name' do
|
99
|
+
raw_input = "string with <placeholder\n> Something else"
|
100
|
+
tokens = SimpleTemplates::Lexer.new(
|
101
|
+
delimiter,
|
102
|
+
raw_input
|
103
|
+
).tokenize
|
104
|
+
|
105
|
+
tokens.must_equal [
|
106
|
+
token.new(:text, 'string with ', 0),
|
107
|
+
token.new(:ph_start, '<', 12),
|
108
|
+
token.new(:ph_name, 'placeholder', 13),
|
109
|
+
token.new(:text, "\n", 24),
|
110
|
+
token.new(:ph_end, '>', 25),
|
111
|
+
token.new(:text, " Something else", 26)
|
112
|
+
]
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'tokenizes a string with a placeholder containing numbers' do
|
116
|
+
raw_input = 'string with <1placeholder1>'
|
117
|
+
tokens = SimpleTemplates::Lexer.new(
|
118
|
+
delimiter,
|
119
|
+
raw_input
|
120
|
+
).tokenize
|
121
|
+
|
122
|
+
tokens.must_equal [
|
123
|
+
token.new(:text, 'string with ', 0),
|
124
|
+
token.new(:ph_start, '<', 12),
|
125
|
+
token.new(:ph_name, '1placeholder1', 13),
|
126
|
+
token.new(:ph_end, '>', 26),
|
127
|
+
]
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'tokenizes a string with a placeholder containing underscores' do
|
131
|
+
raw_input = 'string with <_place_holder_>'
|
132
|
+
tokens = SimpleTemplates::Lexer.new(
|
133
|
+
delimiter,
|
134
|
+
raw_input
|
135
|
+
).tokenize
|
136
|
+
|
137
|
+
tokens.must_equal [
|
138
|
+
token.new(:text, 'string with ', 0),
|
139
|
+
token.new(:ph_start, '<', 12),
|
140
|
+
token.new(:ph_name, '_place_holder_', 13),
|
141
|
+
token.new(:ph_end, '>', 27),
|
142
|
+
]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|