curly-templates 2.3.1 → 2.3.2
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 +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile +0 -1
- data/curly-templates.gemspec +2 -2
- data/lib/curly.rb +1 -1
- data/lib/curly/compiler.rb +5 -0
- data/spec/attribute_scanner_spec.rb +0 -2
- data/spec/collection_blocks_spec.rb +8 -18
- data/spec/compiler/collections_spec.rb +154 -105
- data/spec/compiler/context_blocks_spec.rb +22 -24
- data/spec/compiler_spec.rb +101 -99
- data/spec/component_compiler_spec.rb +0 -2
- data/spec/component_scanner_spec.rb +0 -2
- data/spec/components_spec.rb +5 -7
- data/spec/conditional_blocks_spec.rb +4 -6
- data/spec/dummy/config/environments/test.rb +1 -1
- data/spec/generators/controller_generator_spec.rb +0 -1
- data/spec/integration/application_layout_spec.rb +0 -2
- data/spec/integration/collection_blocks_spec.rb +0 -2
- data/spec/integration/context_blocks_spec.rb +0 -1
- data/spec/integration/partials_spec.rb +0 -2
- data/spec/parser_spec.rb +0 -3
- data/spec/presenter_spec.rb +0 -2
- data/spec/scanner_spec.rb +0 -2
- data/spec/spec_helper.rb +23 -31
- data/spec/syntax_error_spec.rb +0 -2
- data/spec/template_handler_spec.rb +0 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5d6cde1c07741229dc8ea78114e54af3f8203c1
|
4
|
+
data.tar.gz: c06295601f10d2b265334ef2e3a67255fd00b3f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bff53c1b1165f5fbbf2882a172ac47b274bae2b9a635c757870b226e0087ebaeab035b856c55c33cde288d74999d9d5d5dd034d272faecaba8eb0b5319a2b30c
|
7
|
+
data.tar.gz: 3907be2a2506af3b65c0d2cdb787b83472f2b35d60f3dcef649fb1234585d9eca08714875b7ab975c9bacd16ec17f7aabf80a1e795b57e75626d0b511d2ed0a6
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
### Unreleased
|
2
2
|
|
3
|
+
### Curly 2.3.2 (January 13, 2015)
|
4
|
+
|
5
|
+
* Fix an issue that caused presenter parameters to get mixed up.
|
6
|
+
|
7
|
+
*Cristian Planas*
|
8
|
+
|
9
|
+
* Clean up the testing code.
|
10
|
+
|
11
|
+
*Daniel Schierbeck*
|
12
|
+
|
3
13
|
### Curly 2.3.1 (January 7, 2015)
|
4
14
|
|
5
15
|
* Fix an issue with nested context blocks.
|
data/Gemfile
CHANGED
data/curly-templates.gemspec
CHANGED
@@ -4,8 +4,8 @@ Gem::Specification.new do |s|
|
|
4
4
|
s.rubygems_version = '1.3.5'
|
5
5
|
|
6
6
|
s.name = 'curly-templates'
|
7
|
-
s.version = '2.3.
|
8
|
-
s.date = '2015-01-
|
7
|
+
s.version = '2.3.2'
|
8
|
+
s.date = '2015-01-13'
|
9
9
|
|
10
10
|
s.summary = "Free your views!"
|
11
11
|
s.description = "A view layer for your Rails apps that separates structure and logic."
|
data/lib/curly.rb
CHANGED
data/lib/curly/compiler.rb
CHANGED
@@ -67,6 +67,7 @@ module Curly
|
|
67
67
|
buffer = ActiveSupport::SafeBuffer.new
|
68
68
|
buffers = []
|
69
69
|
presenters = []
|
70
|
+
options_stack = []
|
70
71
|
#{@parts.join("\n")}
|
71
72
|
buffer
|
72
73
|
RUBY
|
@@ -102,6 +103,7 @@ module Curly
|
|
102
103
|
|
103
104
|
output <<-RUBY
|
104
105
|
presenters << presenter
|
106
|
+
options_stack << options
|
105
107
|
items = Array(#{method_call})
|
106
108
|
items.each_with_index do |item, index|
|
107
109
|
options = options.merge("#{name}" => item, "#{counter}" => index + 1)
|
@@ -114,6 +116,7 @@ module Curly
|
|
114
116
|
|
115
117
|
output <<-RUBY
|
116
118
|
end
|
119
|
+
options = options_stack.pop
|
117
120
|
presenter = presenters.pop
|
118
121
|
RUBY
|
119
122
|
end
|
@@ -151,6 +154,7 @@ module Curly
|
|
151
154
|
end
|
152
155
|
|
153
156
|
output <<-RUBY
|
157
|
+
options_stack << options
|
154
158
|
presenters << presenter
|
155
159
|
buffers << buffer
|
156
160
|
buffer << #{method_call} do |item|
|
@@ -168,6 +172,7 @@ module Curly
|
|
168
172
|
end
|
169
173
|
buffer = buffers.pop
|
170
174
|
presenter = presenters.pop
|
175
|
+
options = options_stack.pop
|
171
176
|
RUBY
|
172
177
|
end
|
173
178
|
|
@@ -1,10 +1,8 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
describe "Collection block components" do
|
4
|
-
include
|
2
|
+
include CompilationSupport
|
5
3
|
|
6
4
|
before do
|
7
|
-
|
5
|
+
define_presenter "ItemPresenter" do
|
8
6
|
presents :item
|
9
7
|
|
10
8
|
def name
|
@@ -14,7 +12,7 @@ describe "Collection block components" do
|
|
14
12
|
end
|
15
13
|
|
16
14
|
example "with neither identifier nor attributes" do
|
17
|
-
|
15
|
+
define_presenter do
|
18
16
|
def items
|
19
17
|
["one", "two", "three"]
|
20
18
|
end
|
@@ -24,7 +22,7 @@ describe "Collection block components" do
|
|
24
22
|
end
|
25
23
|
|
26
24
|
example "with an identifier" do
|
27
|
-
|
25
|
+
define_presenter do
|
28
26
|
def items(filter = nil)
|
29
27
|
if filter == "even"
|
30
28
|
["two"]
|
@@ -42,7 +40,7 @@ describe "Collection block components" do
|
|
42
40
|
end
|
43
41
|
|
44
42
|
example "with attributes" do
|
45
|
-
|
43
|
+
define_presenter do
|
46
44
|
def items(length: "1")
|
47
45
|
["x"] * length.to_i
|
48
46
|
end
|
@@ -53,13 +51,13 @@ describe "Collection block components" do
|
|
53
51
|
end
|
54
52
|
|
55
53
|
example "with nested collection blocks" do
|
56
|
-
|
54
|
+
define_presenter do
|
57
55
|
def items
|
58
56
|
[{ parts: [1, 2] }, { parts: [3, 4] }]
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
62
|
-
|
60
|
+
define_presenter "ItemPresenter" do
|
63
61
|
presents :item
|
64
62
|
|
65
63
|
def parts
|
@@ -67,7 +65,7 @@ describe "Collection block components" do
|
|
67
65
|
end
|
68
66
|
end
|
69
67
|
|
70
|
-
|
68
|
+
define_presenter "PartPresenter" do
|
71
69
|
presents :part
|
72
70
|
|
73
71
|
def number
|
@@ -77,12 +75,4 @@ describe "Collection block components" do
|
|
77
75
|
|
78
76
|
render("{{*items}}<{{*parts}}[{{number}}]{{/parts}}>{{/items}}").should == "<[1][2]><[3][4]>"
|
79
77
|
end
|
80
|
-
|
81
|
-
def item_presenter(&block)
|
82
|
-
stub_const("ItemPresenter", Class.new(Curly::Presenter, &block))
|
83
|
-
end
|
84
|
-
|
85
|
-
def part_presenter(&block)
|
86
|
-
stub_const("ItemPresenter::PartPresenter", Class.new(Curly::Presenter, &block))
|
87
|
-
end
|
88
78
|
end
|
@@ -1,153 +1,202 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
describe Curly::Compiler do
|
4
2
|
include CompilationSupport
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@list.title
|
4
|
+
context "normal rendering" do
|
5
|
+
before do
|
6
|
+
define_presenter "ItemPresenter" do
|
7
|
+
presents :item
|
8
|
+
delegate :name, to: :@item
|
12
9
|
end
|
10
|
+
end
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
@list.items
|
19
|
-
end
|
12
|
+
it "compiles collection blocks" do
|
13
|
+
define_presenter do
|
14
|
+
presents :items
|
15
|
+
attr_reader :items
|
20
16
|
end
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
18
|
+
item1 = double("item1", name: "foo")
|
19
|
+
item2 = double("item2", name: "bar")
|
25
20
|
|
26
|
-
|
27
|
-
|
28
|
-
end
|
21
|
+
template = "<ul>{{*items}}<li>{{name}}</li>{{/items}}</ul>"
|
22
|
+
expect(render(template, items: [item1, item2])).to eql "<ul><li>foo</li><li>bar</li></ul>"
|
29
23
|
end
|
30
|
-
end
|
31
24
|
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
it "allows attributes on collection blocks" do
|
26
|
+
define_presenter do
|
27
|
+
presents :items
|
35
28
|
|
36
|
-
|
37
|
-
|
29
|
+
def items(status: nil)
|
30
|
+
if status
|
31
|
+
@items.select {|item| item.status == status }
|
32
|
+
else
|
33
|
+
@items
|
34
|
+
end
|
35
|
+
end
|
38
36
|
end
|
39
|
-
end
|
40
|
-
end
|
41
37
|
|
42
|
-
|
43
|
-
|
44
|
-
presents :item, :item_counter
|
45
|
-
presents :list, default: nil
|
38
|
+
item1 = double("item1", name: "foo", status: "active")
|
39
|
+
item2 = double("item2", name: "bar", status: "inactive")
|
46
40
|
|
47
|
-
|
41
|
+
template = "<ul>{{*items status=active}}<li>{{name}}</li>{{/items}}</ul>"
|
42
|
+
expect(render(template, items: [item1, item2])).to eql "<ul><li>foo</li></ul>"
|
43
|
+
end
|
48
44
|
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
it "fails if the component doesn't support enumeration" do
|
46
|
+
template = "<ul>{{*numbers}}<li>{{name}}</li>{{/numbers}}</ul>"
|
47
|
+
expect { render(template) }.to raise_exception(Curly::Error)
|
48
|
+
end
|
52
49
|
|
53
|
-
|
54
|
-
|
50
|
+
it "works even if the component method doesn't return an Array" do
|
51
|
+
define_presenter do
|
52
|
+
def companies
|
53
|
+
"Arla"
|
54
|
+
end
|
55
55
|
end
|
56
56
|
|
57
|
-
|
58
|
-
|
57
|
+
define_presenter "CompanyPresenter" do
|
58
|
+
presents :company
|
59
|
+
|
60
|
+
def name
|
61
|
+
@company
|
62
|
+
end
|
59
63
|
end
|
64
|
+
|
65
|
+
template = "<ul>{{*companies}}<li>{{name}}</li>{{/companies}}</ul>"
|
66
|
+
expect(render(template)).to eql "<ul><li>Arla</li></ul>"
|
60
67
|
end
|
61
|
-
end
|
62
68
|
|
63
|
-
|
64
|
-
|
65
|
-
|
69
|
+
it "passes the index of the current item to the nested presenter" do
|
70
|
+
define_presenter do
|
71
|
+
presents :items
|
72
|
+
attr_reader :items
|
73
|
+
end
|
74
|
+
|
75
|
+
define_presenter "ItemPresenter" do
|
76
|
+
presents :item_counter
|
66
77
|
|
67
|
-
|
68
|
-
|
78
|
+
def index
|
79
|
+
@item_counter
|
80
|
+
end
|
69
81
|
end
|
82
|
+
|
83
|
+
item1 = double("item1")
|
84
|
+
item2 = double("item2")
|
85
|
+
|
86
|
+
template = "<ul>{{*items}}<li>{{index}}</li>{{/items}}</ul>"
|
87
|
+
expect(render(template, items: [item1, item2])).to eql "<ul><li>1</li><li>2</li></ul>"
|
70
88
|
end
|
71
|
-
end
|
72
89
|
|
73
|
-
|
74
|
-
|
75
|
-
|
90
|
+
it "restores the previous scope after exiting the collection block" do
|
91
|
+
define_presenter do
|
92
|
+
presents :items
|
93
|
+
attr_reader :items
|
76
94
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
95
|
+
def title
|
96
|
+
"Inventory"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
define_presenter "ItemPresenter" do
|
101
|
+
presents :item
|
102
|
+
delegate :name, :parts, to: :@item
|
103
|
+
end
|
81
104
|
|
82
|
-
|
83
|
-
|
84
|
-
|
105
|
+
define_presenter "PartPresenter" do
|
106
|
+
presents :part
|
107
|
+
delegate :identifier, to: :@part
|
108
|
+
end
|
85
109
|
|
86
|
-
|
110
|
+
part = double("part", identifier: "X")
|
111
|
+
item = double("item", name: "foo", parts: [part])
|
87
112
|
|
88
|
-
|
89
|
-
|
90
|
-
|
113
|
+
template = "{{*items}}{{*parts}}{{identifier}}{{/parts}}{{name}}{{/items}}{{title}}"
|
114
|
+
expect(render(template, items: [item])).to eql "XfooInventory"
|
115
|
+
end
|
91
116
|
|
92
|
-
|
93
|
-
|
94
|
-
|
117
|
+
it "passes the parent presenter's options to the nested presenter" do
|
118
|
+
define_presenter do
|
119
|
+
presents :items, :prefix
|
120
|
+
attr_reader :items
|
121
|
+
end
|
95
122
|
|
96
|
-
|
123
|
+
define_presenter "ItemPresenter" do
|
124
|
+
presents :item, :prefix
|
125
|
+
delegate :name, to: :@item
|
126
|
+
attr_reader :prefix
|
127
|
+
end
|
97
128
|
|
98
|
-
|
99
|
-
|
100
|
-
end
|
129
|
+
item1 = double(name: "foo")
|
130
|
+
item2 = double(name: "bar")
|
101
131
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
132
|
+
template = "{{*items}}{{prefix}}: {{name}}; {{/items}}"
|
133
|
+
expect(render(template, prefix: "SKU", items: [item1, item2])).to eql "SKU: foo; SKU: bar; "
|
134
|
+
end
|
106
135
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
136
|
+
it "compiles nested collection blocks" do
|
137
|
+
define_presenter do
|
138
|
+
presents :items
|
139
|
+
attr_reader :items
|
140
|
+
end
|
111
141
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
142
|
+
define_presenter "ItemPresenter" do
|
143
|
+
presents :item
|
144
|
+
delegate :name, :parts, to: :@item
|
145
|
+
end
|
117
146
|
|
118
|
-
|
119
|
-
|
120
|
-
|
147
|
+
define_presenter "PartPresenter" do
|
148
|
+
presents :part
|
149
|
+
delegate :identifier, to: :@part
|
150
|
+
end
|
121
151
|
|
122
|
-
|
152
|
+
item1 = double("item1", name: "item1", parts: [double(identifier: "A"), double(identifier: "B")])
|
153
|
+
item2 = double("item2", name: "item2", parts: [double(identifier: "C"), double(identifier: "D")])
|
123
154
|
|
124
|
-
|
125
|
-
|
155
|
+
template = "{{*items}}{{name}}: {{*parts}}{{identifier}}{{/parts}}; {{/items}}"
|
156
|
+
expect(render(template, items: [item1, item2])).to eql "item1: AB; item2: CD; "
|
157
|
+
end
|
126
158
|
end
|
127
159
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
160
|
+
context "re-using assign names" do
|
161
|
+
before do
|
162
|
+
define_presenter do
|
163
|
+
presents :comment
|
132
164
|
|
133
|
-
|
134
|
-
expect(evaluate(template)).to eql "XfooInventory"
|
135
|
-
end
|
165
|
+
attr_reader :comment
|
136
166
|
|
137
|
-
|
138
|
-
|
167
|
+
def comments
|
168
|
+
["yolo", "xoxo"]
|
169
|
+
end
|
139
170
|
|
140
|
-
|
141
|
-
|
142
|
-
|
171
|
+
def comment(&block)
|
172
|
+
block.call("viagra!")
|
173
|
+
end
|
174
|
+
|
175
|
+
def form(&block)
|
176
|
+
block.call
|
177
|
+
end
|
178
|
+
end
|
143
179
|
|
144
|
-
|
145
|
-
|
146
|
-
|
180
|
+
define_presenter "CommentPresenter" do
|
181
|
+
presents :comment
|
182
|
+
end
|
147
183
|
|
148
|
-
|
184
|
+
define_presenter "FormPresenter" do
|
185
|
+
presents :comment
|
186
|
+
attr_reader :comment
|
187
|
+
end
|
188
|
+
end
|
149
189
|
|
150
|
-
|
151
|
-
|
190
|
+
it "allows re-using assign names in collection blocks" do
|
191
|
+
options = { "comment" => "first post!" }
|
192
|
+
template = "{{*comments}}{{/comments}}{{@form}}{{comment}}{{/form}}"
|
193
|
+
expect(render(template, options)).to eql "first post!"
|
194
|
+
end
|
195
|
+
|
196
|
+
it "allows re-using assign names in context blocks" do
|
197
|
+
options = { "comment" => "first post!" }
|
198
|
+
template = "{{@comment}}{{/comment}}{{@form}}{{comment}}{{/form}}"
|
199
|
+
expect(render(template, options)).to eql "first post!"
|
200
|
+
end
|
152
201
|
end
|
153
202
|
end
|
@@ -1,53 +1,51 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
describe Curly::Compiler do
|
4
2
|
include CompilationSupport
|
5
3
|
|
6
|
-
|
7
|
-
|
4
|
+
it "compiles context blocks" do
|
5
|
+
define_presenter do
|
8
6
|
def form(&block)
|
9
7
|
"<form>".html_safe + block.call("yo") + "</form>".html_safe
|
10
8
|
end
|
11
|
-
|
12
|
-
def invalid
|
13
|
-
"uh oh!"
|
14
|
-
end
|
15
9
|
end
|
16
|
-
end
|
17
10
|
|
18
|
-
|
19
|
-
Class.new(Curly::Presenter) do
|
11
|
+
define_presenter "FormPresenter" do
|
20
12
|
presents :form
|
21
13
|
|
22
14
|
def text_field(&block)
|
23
15
|
block.call(@form)
|
24
16
|
end
|
25
17
|
end
|
26
|
-
end
|
27
18
|
|
28
|
-
|
29
|
-
Class.new(Curly::Presenter) do
|
19
|
+
define_presenter "TextFieldPresenter" do
|
30
20
|
presents :text_field
|
31
21
|
|
32
22
|
def field
|
33
23
|
%(<input type="text" value="#{@text_field.upcase}">).html_safe
|
34
24
|
end
|
35
25
|
end
|
26
|
+
|
27
|
+
render('{{@form}}{{@text_field}}{{field}}{{/text_field}}{{/form}}').should == '<form><input type="text" value="YO"></form>'
|
36
28
|
end
|
37
29
|
|
38
|
-
|
39
|
-
|
30
|
+
it "fails if the component is not a context block" do
|
31
|
+
define_presenter do
|
32
|
+
def form
|
33
|
+
end
|
34
|
+
end
|
40
35
|
|
41
|
-
|
42
|
-
|
43
|
-
|
36
|
+
expect {
|
37
|
+
render('{{@form}}{{/form}}')
|
38
|
+
}.to raise_exception(Curly::Error)
|
44
39
|
end
|
45
40
|
|
46
|
-
it "
|
47
|
-
|
48
|
-
|
41
|
+
it "fails if the component doesn't match a presenter class" do
|
42
|
+
define_presenter do
|
43
|
+
def dust(&block)
|
44
|
+
end
|
45
|
+
end
|
49
46
|
|
50
|
-
|
51
|
-
|
47
|
+
expect {
|
48
|
+
render('{{@dust}}{{/dust}}')
|
49
|
+
}.to raise_exception(Curly::Error)
|
52
50
|
end
|
53
51
|
end
|
data/spec/compiler_spec.rb
CHANGED
@@ -1,69 +1,7 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
describe Curly::Compiler do
|
4
2
|
include CompilationSupport
|
5
3
|
|
6
|
-
let :presenter_class do
|
7
|
-
Class.new do
|
8
|
-
def foo
|
9
|
-
"FOO"
|
10
|
-
end
|
11
|
-
|
12
|
-
def high_yield
|
13
|
-
"#{yield}, motherfucker!"
|
14
|
-
end
|
15
|
-
|
16
|
-
def yield_value
|
17
|
-
"#{yield :foo}, please?"
|
18
|
-
end
|
19
|
-
|
20
|
-
def hello?(value)
|
21
|
-
value == "world"
|
22
|
-
end
|
23
|
-
|
24
|
-
def unicorns
|
25
|
-
"UNICORN"
|
26
|
-
end
|
27
|
-
|
28
|
-
def dirty
|
29
|
-
nil
|
30
|
-
end
|
31
|
-
|
32
|
-
def square?(width:, height:)
|
33
|
-
width.to_i == height.to_i
|
34
|
-
end
|
35
|
-
|
36
|
-
def false?
|
37
|
-
false
|
38
|
-
end
|
39
|
-
|
40
|
-
def true?
|
41
|
-
true
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.component_available?(method)
|
45
|
-
%w[foo high_yield yield_value dirty false? true? hello? square?].include?(method)
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.available_components
|
49
|
-
public_instance_methods
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def method_missing(*args)
|
55
|
-
"BAR"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
let(:presenter) { presenter_class.new }
|
61
|
-
|
62
4
|
describe ".compile" do
|
63
|
-
it "compiles Curly templates to Ruby code" do
|
64
|
-
evaluate("{{foo}}").should == "FOO"
|
65
|
-
end
|
66
|
-
|
67
5
|
it "raises ArgumentError if the presenter class is nil" do
|
68
6
|
expect do
|
69
7
|
Curly::Compiler.compile("foo", nil)
|
@@ -71,12 +9,12 @@ describe Curly::Compiler do
|
|
71
9
|
end
|
72
10
|
|
73
11
|
it "makes sure only public methods are called on the presenter object" do
|
74
|
-
expect {
|
12
|
+
expect { render("{{bar}}") }.to raise_exception(Curly::InvalidComponent)
|
75
13
|
end
|
76
14
|
|
77
15
|
it "includes the invalid component when failing to compile" do
|
78
16
|
begin
|
79
|
-
|
17
|
+
render("{{bar}}")
|
80
18
|
fail
|
81
19
|
rescue Curly::InvalidComponent => e
|
82
20
|
e.component.should == "bar"
|
@@ -84,107 +22,171 @@ describe Curly::Compiler do
|
|
84
22
|
end
|
85
23
|
|
86
24
|
it "propagates yields to the caller" do
|
87
|
-
|
25
|
+
define_presenter do
|
26
|
+
def i_want
|
27
|
+
"I want #{yield}!"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
render("{{i_want}}") { "$$$" }.should == "I want $$$!"
|
88
32
|
end
|
89
33
|
|
90
34
|
it "sends along arguments passed to yield" do
|
91
|
-
|
35
|
+
define_presenter do
|
36
|
+
def hello(&block)
|
37
|
+
"Hello, #{block.call('world')}!"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
render("{{hello}}") {|v| v.upcase }.should == "Hello, WORLD!"
|
92
42
|
end
|
93
43
|
|
94
44
|
it "escapes non HTML safe strings returned from the presenter" do
|
95
|
-
|
96
|
-
|
45
|
+
define_presenter do
|
46
|
+
def dirty
|
47
|
+
"<p>dirty</p>"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
render("{{dirty}}").should == "<p>dirty</p>"
|
97
52
|
end
|
98
53
|
|
99
54
|
it "does not escape HTML safe strings returned from the presenter" do
|
100
|
-
|
101
|
-
|
55
|
+
define_presenter do
|
56
|
+
def dirty
|
57
|
+
"<p>dirty</p>".html_safe
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
render("{{dirty}}").should == "<p>dirty</p>"
|
102
62
|
end
|
103
63
|
|
104
64
|
it "does not escape HTML in the template itself" do
|
105
|
-
|
65
|
+
render("<div>").should == "<div>"
|
106
66
|
end
|
107
67
|
|
108
68
|
it "treats all values returned from the presenter as strings" do
|
109
|
-
|
110
|
-
|
69
|
+
define_presenter do
|
70
|
+
def foo; 42; end
|
71
|
+
end
|
72
|
+
|
73
|
+
render("{{foo}}").should == "42"
|
111
74
|
end
|
112
75
|
|
113
76
|
it "removes comments from the output" do
|
114
|
-
|
77
|
+
render("hello{{! I'm a comment, yo }}world").should == "helloworld"
|
115
78
|
end
|
116
79
|
|
117
80
|
it "removes text in false blocks" do
|
118
|
-
|
81
|
+
define_presenter do
|
82
|
+
def false?
|
83
|
+
false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
render("{{#false?}}wut{{/false?}}").should == ""
|
119
88
|
end
|
120
89
|
|
121
90
|
it "keeps text in true blocks" do
|
122
|
-
|
91
|
+
define_presenter do
|
92
|
+
def true?
|
93
|
+
true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
render("{{#true?}}yello{{/true?}}").should == "yello"
|
123
98
|
end
|
124
99
|
|
125
100
|
it "removes text in inverse true blocks" do
|
126
|
-
|
101
|
+
define_presenter do
|
102
|
+
def true?
|
103
|
+
true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
render("{{^true?}}bar{{/true?}}").should == ""
|
127
108
|
end
|
128
109
|
|
129
|
-
it "keeps
|
130
|
-
|
110
|
+
it "keeps text in inverse false blocks" do
|
111
|
+
define_presenter do
|
112
|
+
def false?
|
113
|
+
false
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
render("{{^false?}}yeah!{{/false?}}").should == "yeah!"
|
131
118
|
end
|
132
119
|
|
133
120
|
it "passes an argument to blocks" do
|
134
|
-
|
121
|
+
define_presenter do
|
122
|
+
def hello?(value)
|
123
|
+
value == "world"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
render("{{#hello.world?}}foo{{/hello.world?}}").should == "foo"
|
128
|
+
render("{{#hello.mars?}}bar{{/hello.mars?}}").should == ""
|
135
129
|
end
|
136
130
|
|
137
131
|
it "passes attributes to blocks" do
|
138
|
-
|
139
|
-
|
132
|
+
define_presenter do
|
133
|
+
def square?(width:, height:)
|
134
|
+
width.to_i == height.to_i
|
135
|
+
end
|
136
|
+
end
|
140
137
|
|
141
|
-
|
142
|
-
expect do
|
143
|
-
evaluate("test{{#false?}}bar{{/true?}}")
|
144
|
-
end.to raise_exception(Curly::IncorrectEndingError)
|
138
|
+
render("{{#square? width=2 height=2}}yeah!{{/square?}}").should == "yeah!"
|
145
139
|
end
|
146
140
|
|
147
141
|
it "gives an error on incomplete blocks" do
|
148
142
|
expect do
|
149
|
-
|
143
|
+
render("{{#hello?}}")
|
150
144
|
end.to raise_exception(Curly::IncompleteBlockError)
|
151
145
|
end
|
152
146
|
|
147
|
+
it "gives an error when closing unopened blocks" do
|
148
|
+
expect do
|
149
|
+
render("{{/goodbye?}}")
|
150
|
+
end.to raise_exception(Curly::IncorrectEndingError)
|
151
|
+
end
|
152
|
+
|
153
153
|
it "gives an error on mismatching block ends" do
|
154
154
|
expect do
|
155
|
-
|
155
|
+
render("{{#x?}}{{#y?}}{{/x?}}{{/y?}}")
|
156
156
|
end.to raise_exception(Curly::IncorrectEndingError)
|
157
157
|
end
|
158
158
|
|
159
159
|
it "does not execute arbitrary Ruby code" do
|
160
|
-
|
160
|
+
render('#{foo}').should == '#{foo}'
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
164
164
|
describe ".valid?" do
|
165
165
|
it "returns true if only available methods are referenced" do
|
166
|
+
define_presenter do
|
167
|
+
def foo; end
|
168
|
+
end
|
169
|
+
|
166
170
|
validate("Hello, {{foo}}!").should == true
|
167
171
|
end
|
168
172
|
|
169
173
|
it "returns false if a missing method is referenced" do
|
174
|
+
define_presenter
|
170
175
|
validate("Hello, {{i_am_missing}}").should == false
|
171
176
|
end
|
172
177
|
|
173
178
|
it "returns false if an unavailable method is referenced" do
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
validate("Hello {{#true?}}world{{/true?}}").should == true
|
180
|
-
end
|
179
|
+
define_presenter do
|
180
|
+
def self.available_components
|
181
|
+
[]
|
182
|
+
end
|
183
|
+
end
|
181
184
|
|
182
|
-
|
183
|
-
validate("Hello {{#true?}}world").should == false
|
185
|
+
validate("Hello, {{inspect}}").should == false
|
184
186
|
end
|
185
187
|
|
186
188
|
def validate(template)
|
187
|
-
Curly.valid?(template,
|
189
|
+
Curly.valid?(template, ShowPresenter)
|
188
190
|
end
|
189
191
|
end
|
190
192
|
end
|
data/spec/components_spec.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
describe "Components" do
|
4
|
-
include
|
2
|
+
include CompilationSupport
|
5
3
|
|
6
4
|
example "with neither identifier nor attributes" do
|
7
|
-
|
5
|
+
define_presenter do
|
8
6
|
def title
|
9
7
|
"A Clockwork Orange"
|
10
8
|
end
|
@@ -14,7 +12,7 @@ describe "Components" do
|
|
14
12
|
end
|
15
13
|
|
16
14
|
example "with an identifier" do
|
17
|
-
|
15
|
+
define_presenter do
|
18
16
|
def reverse(str)
|
19
17
|
str.reverse
|
20
18
|
end
|
@@ -24,7 +22,7 @@ describe "Components" do
|
|
24
22
|
end
|
25
23
|
|
26
24
|
example "with attributes" do
|
27
|
-
|
25
|
+
define_presenter do
|
28
26
|
def double(number:)
|
29
27
|
number.to_i * 2
|
30
28
|
end
|
@@ -34,7 +32,7 @@ describe "Components" do
|
|
34
32
|
end
|
35
33
|
|
36
34
|
example "with both identifier and attributes" do
|
37
|
-
|
35
|
+
define_presenter do
|
38
36
|
def a(href:, title:)
|
39
37
|
content_tag :a, nil, href: href, title: title
|
40
38
|
end
|
@@ -1,10 +1,8 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
describe "Conditional block components" do
|
4
|
-
include
|
2
|
+
include CompilationSupport
|
5
3
|
|
6
4
|
example "with neither identifier nor attributes" do
|
7
|
-
|
5
|
+
define_presenter do
|
8
6
|
def high?
|
9
7
|
true
|
10
8
|
end
|
@@ -19,7 +17,7 @@ describe "Conditional block components" do
|
|
19
17
|
end
|
20
18
|
|
21
19
|
example "with an identifier" do
|
22
|
-
|
20
|
+
define_presenter do
|
23
21
|
def even?(number)
|
24
22
|
number.to_i % 2 == 0
|
25
23
|
end
|
@@ -30,7 +28,7 @@ describe "Conditional block components" do
|
|
30
28
|
end
|
31
29
|
|
32
30
|
example "with attributes" do
|
33
|
-
|
31
|
+
define_presenter do
|
34
32
|
def square?(width:, height:)
|
35
33
|
width.to_i == height.to_i
|
36
34
|
end
|
@@ -13,7 +13,7 @@ Rails.application.configure do
|
|
13
13
|
config.eager_load = false
|
14
14
|
|
15
15
|
# Configure static asset server for tests with Cache-Control for performance.
|
16
|
-
config.
|
16
|
+
config.serve_static_files = true
|
17
17
|
config.static_cache_control = 'public, max-age=3600'
|
18
18
|
|
19
19
|
# Show full error reports and disable caching.
|
data/spec/parser_spec.rb
CHANGED
data/spec/presenter_spec.rb
CHANGED
data/spec/scanner_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -3,44 +3,36 @@ ENV["RAILS_ENV"] = "test"
|
|
3
3
|
require 'dummy/config/environment'
|
4
4
|
require 'rspec/rails'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
require 'coveralls'
|
9
|
-
Coveralls.wear!
|
10
|
-
rescue LoadError
|
11
|
-
STDERR.puts "Failed to load Coveralls"
|
12
|
-
end
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.infer_spec_type_from_file_location!
|
13
8
|
end
|
14
9
|
|
15
|
-
module
|
16
|
-
def
|
17
|
-
|
10
|
+
module CompilationSupport
|
11
|
+
def define_presenter(name = "ShowPresenter", &block)
|
12
|
+
presenter_class = Class.new(Curly::Presenter, &block)
|
13
|
+
stub_const(name, presenter_class)
|
14
|
+
presenter_class
|
18
15
|
end
|
19
16
|
|
20
|
-
def render(source)
|
21
|
-
|
22
|
-
|
17
|
+
def render(source, locals = {}, presenter_class = nil, &block)
|
18
|
+
if presenter_class.nil?
|
19
|
+
unless defined?(ShowPresenter)
|
20
|
+
define_presenter("ShowPresenter")
|
21
|
+
end
|
22
|
+
|
23
|
+
presenter_class = ShowPresenter
|
24
|
+
end
|
25
|
+
|
26
|
+
identifier = "show"
|
23
27
|
handler = Curly::TemplateHandler
|
24
|
-
details = { virtual_path: '
|
28
|
+
details = { virtual_path: 'show' }
|
25
29
|
template = ActionView::Template.new(source, identifier, handler, details)
|
26
|
-
locals = {}
|
27
30
|
view = ActionView::Base.new
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def evaluate(template, options = {}, &block)
|
35
|
-
code = Curly::Compiler.compile(template, presenter_class)
|
36
|
-
context = double("context")
|
37
|
-
|
38
|
-
context.instance_eval(<<-RUBY)
|
39
|
-
def self.render(presenter, options)
|
40
|
-
#{code}
|
41
|
-
end
|
42
|
-
RUBY
|
43
|
-
|
44
|
-
context.render(presenter, options, &block)
|
32
|
+
begin
|
33
|
+
template.render(view, locals, &block)
|
34
|
+
rescue ActionView::Template::Error => e
|
35
|
+
raise e.original_exception
|
36
|
+
end
|
45
37
|
end
|
46
38
|
end
|
data/spec/syntax_error_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: curly-templates
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.
|
4
|
+
version: 2.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Schierbeck
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|