curlybars 0.9.13

Sign up to get free protection for your applications and to get access to all the features.
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