curly-templates 2.5.0 → 2.6.0

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +20 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +3 -0
  5. data/.yardopts +3 -0
  6. data/CHANGELOG.md +28 -0
  7. data/Gemfile +4 -2
  8. data/README.md +76 -3
  9. data/Rakefile +3 -116
  10. data/circle.yml +1 -1
  11. data/curly-templates.gemspec +6 -83
  12. data/lib/curly.rb +1 -1
  13. data/lib/curly/compiler.rb +2 -12
  14. data/lib/curly/component_compiler.rb +6 -3
  15. data/lib/curly/presenter.rb +32 -20
  16. data/lib/curly/presenter_name_error.rb +16 -0
  17. data/lib/curly/rspec.rb +16 -0
  18. data/lib/curly/version.rb +3 -0
  19. metadata +14 -72
  20. data/perf/compile_benchmark.rb +0 -71
  21. data/perf/compile_profile.rb +0 -64
  22. data/perf/component_benchmark.rb +0 -41
  23. data/spec/attribute_scanner_spec.rb +0 -44
  24. data/spec/collection_blocks_spec.rb +0 -78
  25. data/spec/compiler/collections_spec.rb +0 -230
  26. data/spec/compiler/context_blocks_spec.rb +0 -106
  27. data/spec/compiler_spec.rb +0 -192
  28. data/spec/component_compiler_spec.rb +0 -107
  29. data/spec/component_scanner_spec.rb +0 -36
  30. data/spec/components_spec.rb +0 -43
  31. data/spec/conditional_blocks_spec.rb +0 -40
  32. data/spec/dummy/.gitignore +0 -1
  33. data/spec/dummy/app/controllers/application_controller.rb +0 -2
  34. data/spec/dummy/app/controllers/dashboards_controller.rb +0 -14
  35. data/spec/dummy/app/helpers/application_helper.rb +0 -5
  36. data/spec/dummy/app/presenters/dashboards/collection_presenter.rb +0 -7
  37. data/spec/dummy/app/presenters/dashboards/item_presenter.rb +0 -23
  38. data/spec/dummy/app/presenters/dashboards/new_presenter.rb +0 -29
  39. data/spec/dummy/app/presenters/dashboards/partials_presenter.rb +0 -5
  40. data/spec/dummy/app/presenters/dashboards/show_presenter.rb +0 -12
  41. data/spec/dummy/app/presenters/layouts/application_presenter.rb +0 -21
  42. data/spec/dummy/app/views/dashboards/_item.html.curly +0 -1
  43. data/spec/dummy/app/views/dashboards/collection.html.curly +0 -8
  44. data/spec/dummy/app/views/dashboards/new.html.curly +0 -7
  45. data/spec/dummy/app/views/dashboards/partials.html.curly +0 -3
  46. data/spec/dummy/app/views/dashboards/show.html.curly +0 -3
  47. data/spec/dummy/app/views/layouts/application.html.curly +0 -11
  48. data/spec/dummy/config.ru +0 -4
  49. data/spec/dummy/config/application.rb +0 -12
  50. data/spec/dummy/config/boot.rb +0 -5
  51. data/spec/dummy/config/environment.rb +0 -5
  52. data/spec/dummy/config/environments/test.rb +0 -36
  53. data/spec/dummy/config/routes.rb +0 -6
  54. data/spec/generators/controller_generator_spec.rb +0 -34
  55. data/spec/integration/application_layout_spec.rb +0 -22
  56. data/spec/integration/collection_blocks_spec.rb +0 -37
  57. data/spec/integration/context_blocks_spec.rb +0 -27
  58. data/spec/integration/partials_spec.rb +0 -24
  59. data/spec/matchers/have_structure.rb +0 -29
  60. data/spec/parser_spec.rb +0 -92
  61. data/spec/presenter_spec.rb +0 -247
  62. data/spec/scanner_spec.rb +0 -124
  63. data/spec/spec_helper.rb +0 -45
  64. data/spec/syntax_error_spec.rb +0 -12
  65. data/spec/template_handler_spec.rb +0 -209
@@ -1,41 +0,0 @@
1
- require 'bundler/setup'
2
- require 'benchmark/ips'
3
-
4
- ENV["RAILS_ENV"] = "test"
5
-
6
- require_relative '../spec/dummy/config/environment'
7
-
8
- class TestPresenter < Curly::Presenter
9
- def hello_with_delegation
10
- some_helper
11
- end
12
-
13
- def hello_without_delegation
14
- not_some_helper
15
- end
16
-
17
- private
18
-
19
- def not_some_helper
20
- end
21
- end
22
-
23
- class TestContext
24
- def some_helper
25
- end
26
- end
27
-
28
- context = TestContext.new
29
- presenter = TestPresenter.new(context)
30
-
31
- Benchmark.ips do |x|
32
- x.report "presenter method that delegates to the view context" do
33
- presenter.hello_with_delegation
34
- end
35
-
36
- x.report "presenter method that doesn't delegate to the view context" do
37
- presenter.hello_without_delegation
38
- end
39
-
40
- x.compare!
41
- end
@@ -1,44 +0,0 @@
1
- describe Curly::AttributeScanner do
2
- it "scans attributes" do
3
- scan("width=10px height=20px").should == {
4
- "width" => "10px",
5
- "height" => "20px"
6
- }
7
- end
8
-
9
- it "scans single quoted values" do
10
- scan("title='hello world'").should == { "title" => "hello world" }
11
- end
12
-
13
- it "scans double quoted values" do
14
- scan('title="hello world"').should == { "title" => "hello world" }
15
- end
16
-
17
- it "scans mixed quotes" do
18
- scan(%[x=y q="foo's bar" v='bim " bum' t="foo ' bar"]).should == {
19
- "x" => "y",
20
- "q" => "foo's bar",
21
- "t" => "foo ' bar",
22
- "v" => 'bim " bum'
23
- }
24
- end
25
-
26
- it "deals with weird whitespace" do
27
- scan(" size=big ").should == { "size" => "big" }
28
- end
29
-
30
- it "scans empty attribute lists" do
31
- scan(nil).should == {}
32
- scan("").should == {}
33
- scan(" ").should == {}
34
- end
35
-
36
- it "fails when an invalid attribute list is passed" do
37
- expect { scan("foo") }.to raise_exception(Curly::AttributeError)
38
- expect { scan("foo=") }.to raise_exception(Curly::AttributeError)
39
- end
40
-
41
- def scan(str)
42
- described_class.scan(str)
43
- end
44
- end
@@ -1,78 +0,0 @@
1
- describe "Collection block components" do
2
- include CompilationSupport
3
-
4
- before do
5
- define_presenter "ItemPresenter" do
6
- presents :item
7
-
8
- def name
9
- @item
10
- end
11
- end
12
- end
13
-
14
- example "with neither identifier nor attributes" do
15
- define_presenter do
16
- def items
17
- ["one", "two", "three"]
18
- end
19
- end
20
-
21
- render("{{*items}}<{{name}}>{{/items}}").should == "<one><two><three>"
22
- end
23
-
24
- example "with an identifier" do
25
- define_presenter do
26
- def items(filter = nil)
27
- if filter == "even"
28
- ["two"]
29
- elsif filter == "odd"
30
- ["one", "three"]
31
- else
32
- ["one", "two", "three"]
33
- end
34
- end
35
- end
36
-
37
- render("{{*items.even}}<{{name}}>{{/items.even}}").should == "<two>"
38
- render("{{*items.odd}}<{{name}}>{{/items.odd}}").should == "<one><three>"
39
- render("{{*items}}<{{name}}>{{/items}}").should == "<one><two><three>"
40
- end
41
-
42
- example "with attributes" do
43
- define_presenter do
44
- def items(length: "1")
45
- ["x"] * length.to_i
46
- end
47
- end
48
-
49
- render("{{*items length=3}}<{{name}}>{{/items}}").should == "<x><x><x>"
50
- render("{{*items}}<{{name}}>{{/items}}").should == "<x>"
51
- end
52
-
53
- example "with nested collection blocks" do
54
- define_presenter do
55
- def items
56
- [{ parts: [1, 2] }, { parts: [3, 4] }]
57
- end
58
- end
59
-
60
- define_presenter "ItemPresenter" do
61
- presents :item
62
-
63
- def parts
64
- @item[:parts]
65
- end
66
- end
67
-
68
- define_presenter "PartPresenter" do
69
- presents :part
70
-
71
- def number
72
- @part
73
- end
74
- end
75
-
76
- render("{{*items}}<{{*parts}}[{{number}}]{{/parts}}>{{/items}}").should == "<[1][2]><[3][4]>"
77
- end
78
- end
@@ -1,230 +0,0 @@
1
- describe Curly::Compiler do
2
- include CompilationSupport
3
-
4
- context "normal rendering" do
5
- before do
6
- define_presenter "ItemPresenter" do
7
- presents :item
8
- delegate :name, to: :@item
9
- end
10
- end
11
-
12
- it "compiles collection blocks" do
13
- define_presenter do
14
- presents :items
15
- attr_reader :items
16
- end
17
-
18
- item1 = double("item1", name: "foo")
19
- item2 = double("item2", name: "bar")
20
-
21
- template = "<ul>{{*items}}<li>{{name}}</li>{{/items}}</ul>"
22
- expect(render(template, locals: { items: [item1, item2] })).
23
- to eql "<ul><li>foo</li><li>bar</li></ul>"
24
- end
25
-
26
- it "allows attributes on collection blocks" do
27
- define_presenter do
28
- presents :items
29
-
30
- def items(status: nil)
31
- if status
32
- @items.select {|item| item.status == status }
33
- else
34
- @items
35
- end
36
- end
37
- end
38
-
39
- item1 = double("item1", name: "foo", status: "active")
40
- item2 = double("item2", name: "bar", status: "inactive")
41
-
42
- template = "<ul>{{*items status=active}}<li>{{name}}</li>{{/items}}</ul>"
43
- expect(render(template, locals: { items: [item1, item2] })).
44
- to eql "<ul><li>foo</li></ul>"
45
- end
46
-
47
- it "fails if the component doesn't support enumeration" do
48
- template = "<ul>{{*numbers}}<li>{{name}}</li>{{/numbers}}</ul>"
49
- expect { render(template) }.to raise_exception(Curly::Error)
50
- end
51
-
52
- it "works even if the component method doesn't return an Array" do
53
- define_presenter do
54
- def companies
55
- "Arla"
56
- end
57
- end
58
-
59
- define_presenter "CompanyPresenter" do
60
- presents :company
61
-
62
- def name
63
- @company
64
- end
65
- end
66
-
67
- template = "<ul>{{*companies}}<li>{{name}}</li>{{/companies}}</ul>"
68
- expect(render(template)).to eql "<ul><li>Arla</li></ul>"
69
- end
70
-
71
- it "passes the index of the current item to the nested presenter" do
72
- define_presenter do
73
- presents :items
74
- attr_reader :items
75
- end
76
-
77
- define_presenter "ItemPresenter" do
78
- presents :item_counter
79
-
80
- def index
81
- @item_counter
82
- end
83
- end
84
-
85
- item1 = double("item1")
86
- item2 = double("item2")
87
-
88
- template = "<ul>{{*items}}<li>{{index}}</li>{{/items}}</ul>"
89
- expect(render(template, locals: { items: [item1, item2] })).
90
- to eql "<ul><li>1</li><li>2</li></ul>"
91
- end
92
-
93
- it "restores the previous scope after exiting the collection block" do
94
- define_presenter do
95
- presents :items
96
- attr_reader :items
97
-
98
- def title
99
- "Inventory"
100
- end
101
- end
102
-
103
- define_presenter "ItemPresenter" do
104
- presents :item
105
- delegate :name, :parts, to: :@item
106
- end
107
-
108
- define_presenter "PartPresenter" do
109
- presents :part
110
- delegate :identifier, to: :@part
111
- end
112
-
113
- part = double("part", identifier: "X")
114
- item = double("item", name: "foo", parts: [part])
115
-
116
- template = "{{*items}}{{*parts}}{{identifier}}{{/parts}}{{name}}{{/items}}{{title}}"
117
- expect(render(template, locals: { items: [item] })).
118
- to eql "XfooInventory"
119
- end
120
-
121
- it "passes the parent presenter's options to the nested presenter" do
122
- define_presenter do
123
- presents :items, :prefix
124
- attr_reader :items
125
- end
126
-
127
- define_presenter "ItemPresenter" do
128
- presents :item, :prefix
129
- delegate :name, to: :@item
130
- attr_reader :prefix
131
- end
132
-
133
- item1 = double(name: "foo")
134
- item2 = double(name: "bar")
135
-
136
- template = "{{*items}}{{prefix}}: {{name}}; {{/items}}"
137
- expect(render(template, locals: { prefix: "SKU", items: [item1, item2] })).
138
- to eql "SKU: foo; SKU: bar; "
139
- end
140
-
141
- it "compiles nested collection blocks" do
142
- define_presenter do
143
- presents :items
144
- attr_reader :items
145
- end
146
-
147
- define_presenter "ItemPresenter" do
148
- presents :item
149
- delegate :name, :parts, to: :@item
150
- end
151
-
152
- define_presenter "PartPresenter" do
153
- presents :part
154
- delegate :identifier, to: :@part
155
- end
156
-
157
- item1 = double("item1", name: "item1", parts: [double(identifier: "A"), double(identifier: "B")])
158
- item2 = double("item2", name: "item2", parts: [double(identifier: "C"), double(identifier: "D")])
159
-
160
- template = "{{*items}}{{name}}: {{*parts}}{{identifier}}{{/parts}}; {{/items}}"
161
- expect(render(template, locals: { items: [item1, item2] })).
162
- to eql "item1: AB; item2: CD; "
163
- end
164
- end
165
-
166
- context "re-using assign names" do
167
- before do
168
- define_presenter do
169
- presents :comment
170
-
171
- attr_reader :comment
172
-
173
- def comments
174
- ["yolo", "xoxo"]
175
- end
176
-
177
- def comment(&block)
178
- block.call("foo!")
179
- end
180
-
181
- def form(&block)
182
- block.call
183
- end
184
- end
185
-
186
- define_presenter "CommentPresenter" do
187
- presents :comment
188
- end
189
-
190
- define_presenter "FormPresenter" do
191
- presents :comment
192
- attr_reader :comment
193
- end
194
- end
195
-
196
- it "allows re-using assign names in collection blocks" do
197
- options = { "comment" => "first post!" }
198
- template = "{{*comments}}{{/comments}}{{@form}}{{comment}}{{/form}}"
199
- expect(render(template, locals: options)).to eql "first post!"
200
- end
201
-
202
- it "allows re-using assign names in context blocks" do
203
- options = { "comment" => "first post!" }
204
- template = "{{@comment}}{{/comment}}{{@form}}{{comment}}{{/form}}"
205
- expect(render(template, locals: options)).to eql "first post!"
206
- end
207
- end
208
-
209
- context "using namespaced names" do
210
- before do
211
- define_presenter "Layouts::ShowPresenter" do
212
- def comments
213
- ["hello", "world"]
214
- end
215
- end
216
-
217
- define_presenter "Layouts::ShowPresenter::CommentPresenter" do
218
- presents :comment
219
-
220
- attr_reader :comment
221
- end
222
- end
223
-
224
- it "renders correctly" do
225
- template = "{{*comments}}{{comment}} {{/comments}}"
226
- expect(render(template, presenter: "Layouts::ShowPresenter")).
227
- to eql "hello world "
228
- end
229
- end
230
- end
@@ -1,106 +0,0 @@
1
- describe Curly::Compiler do
2
- include CompilationSupport
3
-
4
- it "compiles context blocks" do
5
- define_presenter do
6
- def form(&block)
7
- "<form>".html_safe + block.call("yo") + "</form>".html_safe
8
- end
9
- end
10
-
11
- define_presenter "FormPresenter" do
12
- presents :form
13
-
14
- def text_field(&block)
15
- block.call(@form)
16
- end
17
- end
18
-
19
- define_presenter "TextFieldPresenter" do
20
- presents :text_field
21
-
22
- def field
23
- %(<input type="text" value="#{@text_field.upcase}">).html_safe
24
- end
25
-
26
- def value?
27
- true
28
- end
29
- end
30
-
31
- render('{{@form}}{{@text_field}}{{field}}{{/text_field}}{{/form}}').should == '<form><input type="text" value="YO"></form>'
32
- end
33
-
34
- it "compiles using the right presenter" do
35
- define_presenter "Layouts::SomePresenter" do
36
-
37
- def contents(&block)
38
- block.call("hello, world")
39
- end
40
- end
41
-
42
- define_presenter "Layouts::SomePresenter::ContentsPresenter" do
43
- presents :contents
44
-
45
- def contents
46
- @contents
47
- end
48
- end
49
-
50
- render("foo: {{@contents}}{{contents}}{{/contents}}", presenter: "Layouts::SomePresenter").should == 'foo: hello, world'
51
- end
52
-
53
- it "fails if the component is not a context block" do
54
- define_presenter do
55
- def form
56
- end
57
- end
58
-
59
- expect {
60
- render('{{@form}}{{/form}}')
61
- }.to raise_exception(Curly::Error)
62
- end
63
-
64
- it "fails if the component doesn't match a presenter class" do
65
- define_presenter do
66
- def dust(&block)
67
- end
68
- end
69
-
70
- expect {
71
- render('{{@dust}}{{/dust}}')
72
- }.to raise_exception(Curly::Error)
73
- end
74
-
75
- it "fails if the component is not a context block" do
76
- expect { render('{{@invalid}}yo{{/invalid}}') }.to raise_exception(Curly::Error)
77
- end
78
-
79
- it "compiles shorthand context components" do
80
- define_presenter do
81
- def tree(&block)
82
- yield
83
- end
84
- end
85
-
86
- define_presenter "TreePresenter" do
87
- def branch(&block)
88
- yield
89
- end
90
- end
91
-
92
- define_presenter "BranchPresenter" do
93
- def leaf
94
- "leaf"
95
- end
96
- end
97
-
98
- render('{{tree:branch:leaf}}').should == "leaf"
99
- end
100
-
101
- it "requires shorthand blocks to be closed with the same set of namespaces" do
102
- expect do
103
- render('{{#tree:branch}}{{/branch}}{{/tree}}')
104
- end.to raise_exception(Curly::IncorrectEndingError)
105
- end
106
- end