curlybars 0.9.13

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 (77) hide show
  1. checksums.yaml +7 -0
  2. data/lib/curlybars.rb +108 -0
  3. data/lib/curlybars/configuration.rb +41 -0
  4. data/lib/curlybars/dependency_tracker.rb +8 -0
  5. data/lib/curlybars/error/base.rb +18 -0
  6. data/lib/curlybars/error/compile.rb +11 -0
  7. data/lib/curlybars/error/lex.rb +22 -0
  8. data/lib/curlybars/error/parse.rb +41 -0
  9. data/lib/curlybars/error/presenter/not_found.rb +23 -0
  10. data/lib/curlybars/error/render.rb +11 -0
  11. data/lib/curlybars/error/validate.rb +18 -0
  12. data/lib/curlybars/lexer.rb +60 -0
  13. data/lib/curlybars/method_whitelist.rb +69 -0
  14. data/lib/curlybars/node/block_helper_else.rb +108 -0
  15. data/lib/curlybars/node/boolean.rb +24 -0
  16. data/lib/curlybars/node/each_else.rb +69 -0
  17. data/lib/curlybars/node/if_else.rb +33 -0
  18. data/lib/curlybars/node/item.rb +31 -0
  19. data/lib/curlybars/node/literal.rb +28 -0
  20. data/lib/curlybars/node/option.rb +25 -0
  21. data/lib/curlybars/node/output.rb +24 -0
  22. data/lib/curlybars/node/partial.rb +24 -0
  23. data/lib/curlybars/node/path.rb +137 -0
  24. data/lib/curlybars/node/root.rb +29 -0
  25. data/lib/curlybars/node/string.rb +24 -0
  26. data/lib/curlybars/node/template.rb +32 -0
  27. data/lib/curlybars/node/text.rb +24 -0
  28. data/lib/curlybars/node/unless_else.rb +33 -0
  29. data/lib/curlybars/node/variable.rb +34 -0
  30. data/lib/curlybars/node/with_else.rb +54 -0
  31. data/lib/curlybars/parser.rb +183 -0
  32. data/lib/curlybars/position.rb +7 -0
  33. data/lib/curlybars/presenter.rb +288 -0
  34. data/lib/curlybars/processor/tilde.rb +31 -0
  35. data/lib/curlybars/processor/token_factory.rb +9 -0
  36. data/lib/curlybars/railtie.rb +18 -0
  37. data/lib/curlybars/rendering_support.rb +222 -0
  38. data/lib/curlybars/safe_buffer.rb +11 -0
  39. data/lib/curlybars/template_handler.rb +93 -0
  40. data/lib/curlybars/version.rb +3 -0
  41. data/spec/acceptance/application_layout_spec.rb +60 -0
  42. data/spec/acceptance/collection_blocks_spec.rb +28 -0
  43. data/spec/acceptance/global_helper_spec.rb +25 -0
  44. data/spec/curlybars/configuration_spec.rb +57 -0
  45. data/spec/curlybars/error/base_spec.rb +41 -0
  46. data/spec/curlybars/error/compile_spec.rb +19 -0
  47. data/spec/curlybars/error/lex_spec.rb +25 -0
  48. data/spec/curlybars/error/parse_spec.rb +74 -0
  49. data/spec/curlybars/error/render_spec.rb +19 -0
  50. data/spec/curlybars/error/validate_spec.rb +19 -0
  51. data/spec/curlybars/lexer_spec.rb +466 -0
  52. data/spec/curlybars/method_whitelist_spec.rb +168 -0
  53. data/spec/curlybars/processor/tilde_spec.rb +60 -0
  54. data/spec/curlybars/rendering_support_spec.rb +426 -0
  55. data/spec/curlybars/safe_buffer_spec.rb +46 -0
  56. data/spec/curlybars/template_handler_spec.rb +222 -0
  57. data/spec/integration/cache_spec.rb +124 -0
  58. data/spec/integration/comment_spec.rb +60 -0
  59. data/spec/integration/exception_spec.rb +31 -0
  60. data/spec/integration/node/block_helper_else_spec.rb +422 -0
  61. data/spec/integration/node/each_else_spec.rb +204 -0
  62. data/spec/integration/node/each_spec.rb +291 -0
  63. data/spec/integration/node/escape_spec.rb +27 -0
  64. data/spec/integration/node/helper_spec.rb +176 -0
  65. data/spec/integration/node/if_else_spec.rb +129 -0
  66. data/spec/integration/node/if_spec.rb +143 -0
  67. data/spec/integration/node/output_spec.rb +68 -0
  68. data/spec/integration/node/partial_spec.rb +66 -0
  69. data/spec/integration/node/path_spec.rb +286 -0
  70. data/spec/integration/node/root_spec.rb +15 -0
  71. data/spec/integration/node/template_spec.rb +86 -0
  72. data/spec/integration/node/unless_else_spec.rb +129 -0
  73. data/spec/integration/node/unless_spec.rb +130 -0
  74. data/spec/integration/node/with_spec.rb +116 -0
  75. data/spec/integration/processor/tilde_spec.rb +38 -0
  76. data/spec/integration/processors_spec.rb +30 -0
  77. metadata +358 -0
@@ -0,0 +1,27 @@
1
+ describe '`\` as an escaping character' do
2
+ let(:post) { double("post") }
3
+ let(:presenter) { IntegrationTest::Presenter.new(double("view_context"), post: post) }
4
+ let(:global_helpers_providers) { [] }
5
+
6
+ it "escapes `{`" do
7
+ template = Curlybars.compile(<<-HBS)
8
+ text \\{{! text
9
+ HBS
10
+
11
+ expect(eval(template)).to resemble('text {{! text')
12
+ end
13
+
14
+ it "escapes `\\`" do
15
+ template = Curlybars.compile(<<-HBS)
16
+ text \\ text
17
+ HBS
18
+
19
+ expect(eval(template)).to resemble('text \\ text')
20
+ end
21
+
22
+ it "escapes `\\` at the end of the string" do
23
+ template = Curlybars.compile('text \\')
24
+
25
+ expect(eval(template)).to resemble('text \\')
26
+ end
27
+ end
@@ -0,0 +1,176 @@
1
+ describe "{{helper context key=value}}" do
2
+ let(:global_helpers_providers) { [] }
3
+
4
+ describe "#compile" do
5
+ let(:post) { double("post") }
6
+ let(:presenter) { IntegrationTest::Presenter.new(double("view_context"), post: post) }
7
+
8
+ it "passes two arguments" do
9
+ template = Curlybars.compile(<<-HBS)
10
+ {{print_args_and_options 'first' 'second'}}
11
+ HBS
12
+
13
+ expect(eval(template)).to resemble(<<-HTML)
14
+ first, second, key=
15
+ HTML
16
+ end
17
+
18
+ it "passes two arguments and options" do
19
+ template = Curlybars.compile(<<-HBS)
20
+ {{print_args_and_options 'first' 'second' key='value'}}
21
+ HBS
22
+
23
+ expect(eval(template)).to resemble(<<-HTML)
24
+ first, second, key=value
25
+ HTML
26
+ end
27
+
28
+ it "renders a helper with expression and options" do
29
+ template = Curlybars.compile(<<-HBS)
30
+ {{date user.created_at class='metadata'}}
31
+ HBS
32
+
33
+ expect(eval(template)).to resemble(<<-HTML)
34
+ <time datetime="2015-02-03T13:25:06Z" class="metadata">
35
+ February 3, 2015 13:25
36
+ </time>
37
+ HTML
38
+ end
39
+
40
+ it "renders a helper with only expression" do
41
+ template = Curlybars.compile(<<-HBS)
42
+ <script src="{{asset "jquery_plugin.js"}}"></script>
43
+ HBS
44
+
45
+ expect(eval(template)).to resemble(<<-HTML)
46
+ <script src="http://cdn.example.com/jquery_plugin.js"></script>
47
+ HTML
48
+ end
49
+
50
+ it "renders a helper with only options" do
51
+ template = Curlybars.compile(<<-HBS)
52
+ {{#with new_comment_form}}
53
+ {{input title class="form-control"}}
54
+ {{/with}}
55
+ HBS
56
+
57
+ expect(eval(template)).to resemble(<<-HTML)
58
+ <input name="community_post[title]"
59
+ id="community_post_title"
60
+ type="text"
61
+ class="form-control"
62
+ value="some value persisted in the DB">
63
+ HTML
64
+ end
65
+
66
+ it "renders correctly a return type of integer" do
67
+ template = Curlybars.compile(<<-HBS)
68
+ {{integer 'ignored'}}
69
+ HBS
70
+
71
+ expect(eval(template)).to resemble(<<-HTML)
72
+ 0
73
+ HTML
74
+ end
75
+
76
+ it "renders correctly a return type of boolean" do
77
+ template = Curlybars.compile(<<-HBS)
78
+ {{boolean 'ignored'}}
79
+ HBS
80
+
81
+ expect(eval(template)).to resemble(<<-HTML)
82
+ true
83
+ HTML
84
+ end
85
+
86
+ it "handles correctly a method that invokes `yield`, returning empty string" do
87
+ template = Curlybars.compile(<<-HBS)
88
+ {{this_method_yields}}
89
+ HBS
90
+
91
+ expect(eval(template)).to resemble("")
92
+ end
93
+
94
+ it "doesn't render if the path returns a presenter" do
95
+ template = Curlybars.compile(<<-HBS)
96
+ {{user}}
97
+ HBS
98
+
99
+ expect(eval(template)).to resemble("")
100
+ end
101
+
102
+ it "doesn't render if the path returns a collection of presenters" do
103
+ template = Curlybars.compile(<<-HBS)
104
+ {{array_of_users}}
105
+ HBS
106
+
107
+ expect(eval(template)).to resemble("")
108
+ end
109
+ end
110
+
111
+ describe "#validate" do
112
+ let(:presenter_class) { double(:presenter_class) }
113
+
114
+ it "with errors" do
115
+ dependency_tree = {}
116
+
117
+ source = <<-HBS
118
+ {{helper}}
119
+ HBS
120
+
121
+ errors = Curlybars.validate(dependency_tree, source)
122
+
123
+ expect(errors).not_to be_empty
124
+ end
125
+
126
+ it "raises when using a partial as an helper" do
127
+ dependency_tree = { partial: :partial }
128
+
129
+ source = <<-HBS
130
+ {{partial}}
131
+ HBS
132
+
133
+ errors = Curlybars.validate(dependency_tree, source)
134
+
135
+ expect(errors).not_to be_empty
136
+ end
137
+
138
+ it "without errors" do
139
+ dependency_tree = { helper: :helper }
140
+
141
+ source = <<-HBS
142
+ {{helper}}
143
+ HBS
144
+
145
+ errors = Curlybars.validate(dependency_tree, source)
146
+
147
+ expect(errors).to be_empty
148
+ end
149
+
150
+ it "validates {{helper.invoked_on_nil}} with errors" do
151
+ dependency_tree = { helper: :helper }
152
+
153
+ source = <<-HBS
154
+ {{helper.invoked_on_nil}}
155
+ HBS
156
+
157
+ errors = Curlybars.validate(dependency_tree, source)
158
+
159
+ expect(errors).not_to be_empty
160
+ end
161
+
162
+ describe "with context" do
163
+ it "without errors in block_helper" do
164
+ dependency_tree = { helper: :helper, context: nil }
165
+
166
+ source = <<-HBS
167
+ {{helper context}}
168
+ HBS
169
+
170
+ errors = Curlybars.validate(dependency_tree, source)
171
+
172
+ expect(errors).to be_empty
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,129 @@
1
+ describe "{{#if}}...{{else}}...{{/if}}" do
2
+ let(:global_helpers_providers) { [] }
3
+
4
+ describe "#compile" do
5
+ let(:post) { double("post") }
6
+ let(:presenter) { IntegrationTest::Presenter.new(double("view_context"), post: post) }
7
+
8
+ it "renders the if_template" do
9
+ allow(IntegrationTest::Presenter).to receive(:allows_method?).with(:return_true) { true }
10
+ allow(presenter).to receive(:return_true) { true }
11
+
12
+ template = Curlybars.compile(<<-HBS)
13
+ {{#if return_true}}
14
+ if_template
15
+ {{else}}
16
+ else_template
17
+ {{/if}}
18
+ HBS
19
+
20
+ expect(eval(template)).to resemble(<<-HTML)
21
+ if_template
22
+ HTML
23
+ end
24
+
25
+ it "renders the else_template" do
26
+ allow(IntegrationTest::Presenter).to receive(:allows_method?).with(:return_false) { true }
27
+ allow(presenter).to receive(:return_false) { false }
28
+
29
+ template = Curlybars.compile(<<-HBS)
30
+ {{#if return_false}}
31
+ if_template
32
+ {{else}}
33
+ else_template
34
+ {{/if}}
35
+ HBS
36
+
37
+ expect(eval(template)).to resemble(<<-HTML)
38
+ else_template
39
+ HTML
40
+ end
41
+
42
+ it "allows empty if_template" do
43
+ allow(IntegrationTest::Presenter).to receive(:allows_method?).with(:valid) { true }
44
+ allow(presenter).to receive(:valid) { false }
45
+
46
+ template = Curlybars.compile(<<-HBS)
47
+ {{#if valid}}{{else}}
48
+ else_template
49
+ {{/if}}
50
+ HBS
51
+
52
+ expect(eval(template)).to resemble(<<-HTML)
53
+ else_template
54
+ HTML
55
+ end
56
+
57
+ it "allows empty else_template" do
58
+ allow(IntegrationTest::Presenter).to receive(:allows_method?).with(:valid) { true }
59
+ allow(presenter).to receive(:valid) { true }
60
+
61
+ template = Curlybars.compile(<<-HBS)
62
+ {{#if valid}}
63
+ if_template
64
+ {{else}}{{/if}}
65
+ HBS
66
+
67
+ expect(eval(template)).to resemble(<<-HTML)
68
+ if_template
69
+ HTML
70
+ end
71
+
72
+ it "allows empty if_template and else_template" do
73
+ allow(IntegrationTest::Presenter).to receive(:allows_method?).with(:valid) { true }
74
+ allow(presenter).to receive(:valid) { true }
75
+
76
+ template = Curlybars.compile(<<-HBS)
77
+ {{#if valid}}{{else}}{{/if}}
78
+ HBS
79
+
80
+ expect(eval(template)).to resemble("")
81
+ end
82
+ end
83
+
84
+ describe "#validate" do
85
+ let(:presenter_class) { double(:presenter_class) }
86
+
87
+ it "validates with errors the condition" do
88
+ dependency_tree = {}
89
+
90
+ source = <<-HBS
91
+ {{#if condition}}{{else}}{{/if}}
92
+ HBS
93
+
94
+ errors = Curlybars.validate(dependency_tree, source)
95
+
96
+ expect(errors).not_to be_empty
97
+ end
98
+
99
+ it "validates with errors the nested if_template" do
100
+ dependency_tree = { condition: nil }
101
+
102
+ source = <<-HBS
103
+ {{#if condition}}
104
+ {{unallowed_method}}
105
+ {{else}}
106
+ {{/if}}
107
+ HBS
108
+
109
+ errors = Curlybars.validate(dependency_tree, source)
110
+
111
+ expect(errors).not_to be_empty
112
+ end
113
+
114
+ it "validates with errors the nested else_template" do
115
+ dependency_tree = { condition: nil }
116
+
117
+ source = <<-HBS
118
+ {{#if condition}}
119
+ {{else}}
120
+ {{unallowed_method}}
121
+ {{/if}}
122
+ HBS
123
+
124
+ errors = Curlybars.validate(dependency_tree, source)
125
+
126
+ expect(errors).not_to be_empty
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,143 @@
1
+ describe "{{#if}}...{{/if}}" do
2
+ let(:global_helpers_providers) { [] }
3
+
4
+ describe "#compile" do
5
+ let(:post) { double("post") }
6
+ let(:presenter) { IntegrationTest::Presenter.new(double("view_context"), post: post) }
7
+
8
+ it "returns positive branch when condition is true" do
9
+ allow(presenter).to receive(:allows_method?).with(:valid) { true }
10
+ allow(presenter).to receive(:valid) { true }
11
+
12
+ template = Curlybars.compile(<<-HBS)
13
+ {{#if valid}}
14
+ if_template
15
+ {{/if}}
16
+ HBS
17
+
18
+ expect(eval(template)).to resemble(<<-HTML)
19
+ if_template
20
+ HTML
21
+ end
22
+
23
+ it "doesn't return positive branch when condition is false" do
24
+ allow(presenter).to receive(:allows_method?).with(:valid) { true }
25
+ allow(presenter).to receive(:valid) { false }
26
+
27
+ template = Curlybars.compile(<<-HBS)
28
+ {{#if valid}}
29
+ if_template
30
+ {{/if}}
31
+ HBS
32
+
33
+ expect(eval(template)).to resemble("")
34
+ end
35
+
36
+ it "doesn't return positive branch when condition is empty array" do
37
+ allow(presenter).to receive(:allows_method?).with(:collection) { true }
38
+ allow(presenter).to receive(:collection) { [] }
39
+
40
+ template = Curlybars.compile(<<-HBS)
41
+ {{#if collection}}
42
+ if_template
43
+ {{/if}}
44
+ HBS
45
+
46
+ expect(eval(template)).to resemble("")
47
+ end
48
+
49
+ it "works with nested `if blocks` (double positive)" do
50
+ allow(presenter).to receive(:allows_method?).with(:valid) { true }
51
+ allow(presenter).to receive(:allows_method?).with(:visible) { true }
52
+ allow(presenter).to receive(:valid) { true }
53
+ allow(presenter).to receive(:visible) { true }
54
+
55
+ template = Curlybars.compile(<<-HBS)
56
+ {{#if valid}}
57
+ {{#if visible}}
58
+ inner_if_template
59
+ {{/if}}
60
+ outer_if_template
61
+ {{/if}}
62
+ HBS
63
+
64
+ expect(eval(template)).to resemble(<<-HTML)
65
+ inner_if_template
66
+ outer_if_template
67
+ HTML
68
+ end
69
+
70
+ it "works with nested `if blocks` (positive and negative)" do
71
+ allow(presenter).to receive(:allows_method?).with(:valid) { true }
72
+ allow(presenter).to receive(:allows_method?).with(:visible) { true }
73
+ allow(presenter).to receive(:valid) { true }
74
+ allow(presenter).to receive(:visible) { false }
75
+
76
+ template = Curlybars.compile(<<-HBS)
77
+ {{#if valid}}
78
+ {{#if visible}}
79
+ inner_if_template
80
+ {{/if}}
81
+ outer_if_template
82
+ {{/if}}
83
+ HBS
84
+
85
+ expect(eval(template)).to resemble(<<-HTML)
86
+ outer_if_template
87
+ HTML
88
+ end
89
+
90
+ it "allows empty if_template" do
91
+ allow(presenter).to receive(:allows_method?).with(:valid) { true }
92
+ allow(presenter).to receive(:valid) { true }
93
+
94
+ template = Curlybars.compile(<<-HBS)
95
+ {{#if valid}}{{/if}}
96
+ HBS
97
+
98
+ expect(eval(template)).to resemble("")
99
+ end
100
+
101
+ it "allows usage of variables in condition" do
102
+ template = Curlybars.compile(<<-HBS)
103
+ {{#each two_elements}}
104
+ {{#if @first}}I am the first!{{/if}}
105
+ {{/each}}
106
+ HBS
107
+
108
+ expect(eval(template)).to resemble(<<-HTML)
109
+ I am the first!
110
+ HTML
111
+ end
112
+ end
113
+
114
+ describe "#validate" do
115
+ let(:presenter_class) { double(:presenter_class) }
116
+
117
+ it "validates with errors the condition" do
118
+ dependency_tree = {}
119
+
120
+ source = <<-HBS
121
+ {{#if condition}}{{/if}}
122
+ HBS
123
+
124
+ errors = Curlybars.validate(dependency_tree, source)
125
+
126
+ expect(errors).not_to be_empty
127
+ end
128
+
129
+ it "validates with errors the nested template" do
130
+ dependency_tree = { condition: nil }
131
+
132
+ source = <<-HBS
133
+ {{#if condition}}
134
+ {{unallowed_method}}
135
+ {{/if}}
136
+ HBS
137
+
138
+ errors = Curlybars.validate(dependency_tree, source)
139
+
140
+ expect(errors).not_to be_empty
141
+ end
142
+ end
143
+ end