mustache 1.0.5 → 1.1.1
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 +5 -5
- data/Rakefile +1 -1
- data/lib/mustache/context.rb +4 -4
- data/lib/mustache/generator.rb +2 -2
- data/lib/mustache/parser.rb +5 -3
- data/lib/mustache/settings.rb +24 -0
- data/lib/mustache/version.rb +1 -1
- data/lib/mustache.rb +46 -18
- data/man/mustache.1.html +2 -2
- data/man/mustache.5.html +1 -1
- data/man/mustache.5.ron +1 -1
- data/test/mustache_test.rb +14 -1
- data/test/parser_test.rb +64 -0
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bfcec948b9e5fbd73d9c72e3ade21724d3fd73a1d2ee2ea58ab26bf7e1a341ba
|
4
|
+
data.tar.gz: 1a5d4d062ad29d4a4057a6489f6779d3e61bb7132ecf56fc1ab97a48bfcb926d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afd9888e324611b31fb9a6ac809393b2c42261befce363ab691d68719edb2687dda2129ba64a12367bd0f39d31b1fda861b209345f2abfc06debf67aa0e3ab99
|
7
|
+
data.tar.gz: c225773518109b0eeeecaf89d39faaec30b951361b10c16944f4e016aec6597fc41e75237920dc8c44e00956a00edfcf1b72f2e914ea4dc3f8b296f2436977dc
|
data/Rakefile
CHANGED
data/lib/mustache/context.rb
CHANGED
@@ -51,12 +51,12 @@ class Mustache
|
|
51
51
|
|
52
52
|
# Allows customization of how Mustache escapes things.
|
53
53
|
#
|
54
|
-
# @param [
|
54
|
+
# @param [Object] value Value to escape.
|
55
55
|
#
|
56
|
-
# @return [String] Escaped
|
56
|
+
# @return [String] Escaped string.
|
57
57
|
#
|
58
|
-
def
|
59
|
-
mustache_in_stack.
|
58
|
+
def escape(value)
|
59
|
+
mustache_in_stack.escape(value)
|
60
60
|
end
|
61
61
|
|
62
62
|
# Adds a new object to the context's internal stack.
|
data/lib/mustache/generator.rb
CHANGED
@@ -133,7 +133,7 @@ class Mustache
|
|
133
133
|
when Proc
|
134
134
|
#{proc_handling}
|
135
135
|
when Array, Enumerator, Mustache::Enumerable
|
136
|
-
v.map { |
|
136
|
+
v.map { |_| ctx.push(_); r = #{code}; ctx.pop; r }.join
|
137
137
|
else
|
138
138
|
ctx.push(v); r = #{code}; ctx.pop; r
|
139
139
|
end
|
@@ -182,7 +182,7 @@ class Mustache
|
|
182
182
|
if v.is_a?(Proc)
|
183
183
|
v = #{@option_static_lambdas ? 'v.call' : 'Mustache::Template.new(v.call.to_s).render(ctx.dup)'}
|
184
184
|
end
|
185
|
-
ctx.
|
185
|
+
ctx.escape(v)
|
186
186
|
compiled
|
187
187
|
end
|
188
188
|
|
data/lib/mustache/parser.rb
CHANGED
@@ -323,12 +323,14 @@ EOF
|
|
323
323
|
|
324
324
|
def scan_tag_close content, fetch, padding, pre_match_position
|
325
325
|
section, pos, result = @sections.pop
|
326
|
+
if section.nil?
|
327
|
+
error "Closing unopened #{content.inspect}"
|
328
|
+
end
|
329
|
+
|
326
330
|
raw = @scanner.pre_match[pos[3]...pre_match_position] + padding
|
327
331
|
(@result = result).last << raw << [self.otag, self.ctag]
|
328
332
|
|
329
|
-
if section
|
330
|
-
error "Closing unopened #{content.inspect}"
|
331
|
-
elsif section != content
|
333
|
+
if section != content
|
332
334
|
error "Unclosed section #{section.inspect}", pos
|
333
335
|
end
|
334
336
|
end
|
data/lib/mustache/settings.rb
CHANGED
@@ -2,6 +2,30 @@
|
|
2
2
|
# view class, or a single Mustache instance.
|
3
3
|
class Mustache
|
4
4
|
|
5
|
+
def initialize_settings
|
6
|
+
@template = nil
|
7
|
+
@template_path = nil
|
8
|
+
@template_extension = nil
|
9
|
+
@template_name = nil
|
10
|
+
@template_file = nil
|
11
|
+
@raise_on_context_miss = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.initialize_settings
|
15
|
+
@template = nil
|
16
|
+
@template_path = nil
|
17
|
+
@template_extension = nil
|
18
|
+
@template_name = nil
|
19
|
+
@template_file = nil
|
20
|
+
@raise_on_context_miss = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
initialize_settings
|
24
|
+
|
25
|
+
def self.inherited(subclass)
|
26
|
+
subclass.initialize_settings
|
27
|
+
end
|
28
|
+
|
5
29
|
#
|
6
30
|
# Template Path
|
7
31
|
#
|
data/lib/mustache/version.rb
CHANGED
data/lib/mustache.rb
CHANGED
@@ -74,10 +74,19 @@ require 'mustache/utils'
|
|
74
74
|
#
|
75
75
|
class Mustache
|
76
76
|
|
77
|
-
# Initialize a new
|
77
|
+
# Initialize a new Mustache instance.
|
78
|
+
#
|
78
79
|
# @param [Hash] options An options hash
|
80
|
+
# @option options [String] template_path
|
81
|
+
# @option options [String] template_extension
|
82
|
+
# @option options [String] template_file
|
83
|
+
# @option options [String] template
|
84
|
+
# @option options [String] view_namespace
|
85
|
+
# @option options [String] view_path
|
79
86
|
def initialize(options = {})
|
80
87
|
@options = options
|
88
|
+
|
89
|
+
initialize_settings
|
81
90
|
end
|
82
91
|
|
83
92
|
# Instantiates an instance of this class and calls `render` with
|
@@ -91,19 +100,18 @@ class Mustache
|
|
91
100
|
# Parses our fancy pants template file and returns normal file with
|
92
101
|
# all special {{tags}} and {{#sections}}replaced{{/sections}}.
|
93
102
|
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
# @view.render("Hi {{thing}}!", :thing => :world)
|
103
|
+
# @example Render view
|
104
|
+
# @view.render("Hi {{thing}}!", :thing => :world)
|
97
105
|
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
106
|
+
# @example Set view template and then render
|
107
|
+
# View.template = "Hi {{thing}}!"
|
108
|
+
# @view = View.new
|
109
|
+
# @view.render(:thing => :world)
|
101
110
|
#
|
102
111
|
# @param [String,Hash] data A String template or a Hash context.
|
103
112
|
# If a Hash is given, we'll try to figure
|
104
113
|
# out the template from the class.
|
105
114
|
# @param [Hash] ctx A Hash context if `data` is a String template.
|
106
|
-
#
|
107
115
|
# @return [String] Returns a rendered version of a template.
|
108
116
|
def render(data = template, ctx = {})
|
109
117
|
case data
|
@@ -134,11 +142,11 @@ class Mustache
|
|
134
142
|
|
135
143
|
# Context accessors.
|
136
144
|
#
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
140
|
-
#
|
141
|
-
#
|
145
|
+
# @example Context accessors
|
146
|
+
# view = Mustache.new
|
147
|
+
# view[:name] = "Jon"
|
148
|
+
# view.template = "Hi, {{name}}!"
|
149
|
+
# view.render # => "Hi, Jon!"
|
142
150
|
def [](key)
|
143
151
|
context[key.to_sym]
|
144
152
|
end
|
@@ -190,17 +198,36 @@ class Mustache
|
|
190
198
|
end
|
191
199
|
|
192
200
|
# Override this to provide custom escaping.
|
201
|
+
# By default it uses `CGI.escapeHTML`.
|
202
|
+
#
|
203
|
+
# @example Overriding #escape
|
204
|
+
# class PersonView < Mustache
|
205
|
+
# def escape(value)
|
206
|
+
# my_html_escape_method(value.to_s)
|
207
|
+
# end
|
208
|
+
# end
|
193
209
|
#
|
194
|
-
#
|
210
|
+
# @param [Object] value Value to escape.
|
211
|
+
# @return [String] Escaped content.
|
212
|
+
def escape(value)
|
213
|
+
self.escapeHTML(value.to_s)
|
214
|
+
end
|
215
|
+
|
216
|
+
# Override this to provide custom escaping.
|
195
217
|
#
|
218
|
+
# @example Overriding #escapeHTML
|
196
219
|
# class PersonView < Mustache
|
197
220
|
# def escapeHTML(str)
|
198
221
|
# my_html_escape_method(str)
|
199
222
|
# end
|
200
223
|
# end
|
201
224
|
#
|
202
|
-
# @
|
225
|
+
# @deprecated Use {#escape} instead.
|
203
226
|
#
|
227
|
+
# Note that {#escape} can receive any kind of object.
|
228
|
+
# If your override logic is expecting a string, you will
|
229
|
+
# have to call to_s on it yourself.
|
230
|
+
# @param [String] str String to escape.
|
204
231
|
# @return [String] Escaped HTML.
|
205
232
|
def escapeHTML(str)
|
206
233
|
CGI.escapeHTML(str)
|
@@ -217,7 +244,8 @@ class Mustache
|
|
217
244
|
|
218
245
|
# When given a symbol or string representing a class, will try to produce an
|
219
246
|
# appropriate view class.
|
220
|
-
#
|
247
|
+
#
|
248
|
+
# @example
|
221
249
|
# Mustache.view_namespace = Hurl::Views
|
222
250
|
# Mustache.view_class(:Partial) # => Hurl::Views::Partial
|
223
251
|
def self.view_class(name)
|
@@ -244,7 +272,7 @@ class Mustache
|
|
244
272
|
file_name = underscore(name)
|
245
273
|
file_path = "#{view_path}/#{file_name}.rb"
|
246
274
|
|
247
|
-
return Mustache unless File.
|
275
|
+
return Mustache unless File.exist?(file_path)
|
248
276
|
|
249
277
|
require file_path.chomp('.rb')
|
250
278
|
rescued_const_get(name)
|
@@ -263,7 +291,7 @@ class Mustache
|
|
263
291
|
Mustache::Utils::String.new(underscored).classify
|
264
292
|
end
|
265
293
|
|
266
|
-
#
|
294
|
+
# TemplatePartial => template_partial
|
267
295
|
# Template::Partial => template/partial
|
268
296
|
# Takes a string but defaults to using the current class' name.
|
269
297
|
def self.underscore(classified = name)
|
data/man/mustache.1.html
CHANGED
@@ -102,7 +102,7 @@ names: [ {name: chris}, {name: mark}, {name: scott} ]
|
|
102
102
|
should work fine.</p>
|
103
103
|
|
104
104
|
<p>After the frontmatter should come any valid Mustache template. See
|
105
|
-
<a class="man-ref" href="mustache.5.
|
105
|
+
<a class="man-ref" href="mustache.5.ronn.html">mustache<span class="s">(5)</span></a> for an overview of Mustache templates.</p>
|
106
106
|
|
107
107
|
<p>For example:</p>
|
108
108
|
|
@@ -198,7 +198,7 @@ data
|
|
198
198
|
|
199
199
|
<h2 id="SEE-ALSO">SEE ALSO</h2>
|
200
200
|
|
201
|
-
<p><a class="man-ref" href="mustache.5.
|
201
|
+
<p><a class="man-ref" href="mustache.5.ronn.html">mustache<span class="s">(5)</span></a>, <span class="man-ref">gem<span class="s">(1)</span></span>,
|
202
202
|
<a href="http://mustache.github.io/" data-bare-link="true">http://mustache.github.io/</a></p>
|
203
203
|
|
204
204
|
|
data/man/mustache.5.html
CHANGED
@@ -409,7 +409,7 @@ markup."</p>
|
|
409
409
|
|
410
410
|
<h2 id="SEE-ALSO">SEE ALSO</h2>
|
411
411
|
|
412
|
-
<p><a class="man-ref" href="mustache.1.
|
412
|
+
<p><a class="man-ref" href="mustache.1.ronn.html">mustache<span class="s">(1)</span></a>,
|
413
413
|
<a href="http://mustache.github.io/" data-bare-link="true">http://mustache.github.io/</a></p>
|
414
414
|
|
415
415
|
|
data/man/mustache.5.ron
CHANGED
data/test/mustache_test.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require_relative 'helper'
|
3
|
+
require 'json'
|
3
4
|
|
4
5
|
class MustacheTest < Minitest::Test
|
5
6
|
def test_instance_render
|
@@ -659,7 +660,7 @@ template
|
|
659
660
|
assert_equal('[ 0 1 2 3 4 5 6 7 8 9 10 ]', MethodMissing.render)
|
660
661
|
end
|
661
662
|
|
662
|
-
def
|
663
|
+
def test_custom_html_escaping
|
663
664
|
view = Class.new(Mustache) do
|
664
665
|
def escapeHTML(str)
|
665
666
|
"pong"
|
@@ -670,6 +671,17 @@ template
|
|
670
671
|
assert_equal 'nothing', Mustache.render("{{thing}}", :thing => "nothing")
|
671
672
|
end
|
672
673
|
|
674
|
+
def test_custom_escaping
|
675
|
+
view = Class.new(Mustache) do
|
676
|
+
def escape(str)
|
677
|
+
JSON.dump(str)
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
assert_equal '{ "key": "a\"b" }', view.render('{ "key": {{thing}} }', :thing => 'a"b')
|
682
|
+
assert_equal 'nothing', Mustache.render("{{thing}}", :thing => "nothing")
|
683
|
+
end
|
684
|
+
|
673
685
|
def test_implicit_iterator
|
674
686
|
view = Mustache.new
|
675
687
|
view.template = "{{#people}}* {{.}}\n{{/people}}"
|
@@ -820,6 +832,7 @@ template
|
|
820
832
|
def test_instance_with_initialize_render
|
821
833
|
klass = Class.new(Mustache) do
|
822
834
|
def initialize(name)
|
835
|
+
super
|
823
836
|
@name = name
|
824
837
|
end
|
825
838
|
attr_reader :name
|
data/test/parser_test.rb
CHANGED
@@ -94,4 +94,68 @@ EOF
|
|
94
94
|
|
95
95
|
assert_equal expected, tokens
|
96
96
|
end
|
97
|
+
|
98
|
+
def test_unclosed_section
|
99
|
+
lexer = Mustache::Parser.new
|
100
|
+
exception = assert_raises Mustache::Parser::SyntaxError do
|
101
|
+
lexer.compile("{{#list}}")
|
102
|
+
end
|
103
|
+
|
104
|
+
expected = <<-EOF
|
105
|
+
Unclosed section "list"
|
106
|
+
Line 1
|
107
|
+
{{#list}}
|
108
|
+
^
|
109
|
+
EOF
|
110
|
+
|
111
|
+
assert_equal expected, exception.message
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_closing_unopened
|
115
|
+
lexer = Mustache::Parser.new
|
116
|
+
exception = assert_raises Mustache::Parser::SyntaxError do
|
117
|
+
lexer.compile("{{/list}}")
|
118
|
+
end
|
119
|
+
|
120
|
+
expected = <<-EOF
|
121
|
+
Closing unopened "list"
|
122
|
+
Line 1
|
123
|
+
{{/list}}
|
124
|
+
^
|
125
|
+
EOF
|
126
|
+
|
127
|
+
assert_equal expected, exception.message
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_unclosed_tag
|
131
|
+
lexer = Mustache::Parser.new
|
132
|
+
exception = assert_raises Mustache::Parser::SyntaxError do
|
133
|
+
lexer.compile("{{list")
|
134
|
+
end
|
135
|
+
|
136
|
+
expected = <<-EOF
|
137
|
+
Unclosed tag
|
138
|
+
Line 1
|
139
|
+
{{list
|
140
|
+
^
|
141
|
+
EOF
|
142
|
+
|
143
|
+
assert_equal expected, exception.message
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_illegal_content
|
147
|
+
lexer = Mustache::Parser.new
|
148
|
+
exception = assert_raises Mustache::Parser::SyntaxError do
|
149
|
+
lexer.compile("{{")
|
150
|
+
end
|
151
|
+
|
152
|
+
expected = <<-EOF
|
153
|
+
Illegal content in tag
|
154
|
+
Line 1
|
155
|
+
{{
|
156
|
+
^
|
157
|
+
EOF
|
158
|
+
|
159
|
+
assert_equal expected, exception.message
|
160
|
+
end
|
97
161
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mustache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Wanstrath
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2019-12-03 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -219,8 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
219
|
- !ruby/object:Gem::Version
|
220
220
|
version: '0'
|
221
221
|
requirements: []
|
222
|
-
|
223
|
-
rubygems_version: 2.6.8
|
222
|
+
rubygems_version: 3.0.3
|
224
223
|
signing_key:
|
225
224
|
specification_version: 4
|
226
225
|
summary: Mustache is a framework-agnostic way to render logic-free views.
|