temple 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.yardopts +2 -1
  2. data/CHANGES +63 -0
  3. data/EXPRESSIONS.md +250 -0
  4. data/README.md +24 -12
  5. data/lib/temple.rb +34 -18
  6. data/lib/temple/engine.rb +11 -7
  7. data/lib/temple/erb/engine.rb +5 -3
  8. data/lib/temple/erb/parser.rb +5 -2
  9. data/lib/temple/erb/template.rb +11 -0
  10. data/lib/temple/erb/trimming.rb +9 -1
  11. data/lib/temple/filter.rb +2 -0
  12. data/lib/temple/filters/control_flow.rb +43 -0
  13. data/lib/temple/filters/dynamic_inliner.rb +29 -32
  14. data/lib/temple/filters/eraser.rb +22 -0
  15. data/lib/temple/filters/escapable.rb +39 -0
  16. data/lib/temple/filters/multi_flattener.rb +4 -1
  17. data/lib/temple/filters/static_merger.rb +11 -10
  18. data/lib/temple/filters/validator.rb +15 -0
  19. data/lib/temple/generators.rb +41 -100
  20. data/lib/temple/grammar.rb +56 -0
  21. data/lib/temple/hash.rb +48 -0
  22. data/lib/temple/html/dispatcher.rb +10 -4
  23. data/lib/temple/html/fast.rb +50 -38
  24. data/lib/temple/html/filter.rb +8 -0
  25. data/lib/temple/html/pretty.rb +25 -14
  26. data/lib/temple/mixins/dispatcher.rb +103 -0
  27. data/lib/temple/{mixins.rb → mixins/engine_dsl.rb} +10 -95
  28. data/lib/temple/mixins/grammar_dsl.rb +166 -0
  29. data/lib/temple/mixins/options.rb +28 -0
  30. data/lib/temple/mixins/template.rb +25 -0
  31. data/lib/temple/templates.rb +2 -0
  32. data/lib/temple/utils.rb +11 -57
  33. data/lib/temple/version.rb +1 -1
  34. data/test/filters/test_control_flow.rb +92 -0
  35. data/test/filters/test_dynamic_inliner.rb +7 -7
  36. data/test/filters/test_eraser.rb +55 -0
  37. data/test/filters/{test_escape_html.rb → test_escapable.rb} +13 -6
  38. data/test/filters/test_multi_flattener.rb +1 -1
  39. data/test/filters/test_static_merger.rb +3 -3
  40. data/test/helper.rb +8 -0
  41. data/test/html/test_fast.rb +42 -57
  42. data/test/html/test_pretty.rb +10 -7
  43. data/test/mixins/test_dispatcher.rb +31 -0
  44. data/test/mixins/test_grammar_dsl.rb +86 -0
  45. data/test/test_engine.rb +73 -57
  46. data/test/test_erb.rb +0 -7
  47. data/test/test_filter.rb +26 -0
  48. data/test/test_generator.rb +57 -36
  49. data/test/test_grammar.rb +52 -0
  50. data/test/test_hash.rb +39 -0
  51. data/test/test_utils.rb +11 -38
  52. metadata +34 -10
  53. data/lib/temple/filters/debugger.rb +0 -26
  54. data/lib/temple/filters/escape_html.rb +0 -33
@@ -1,3 +1,3 @@
1
1
  module Temple
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -0,0 +1,92 @@
1
+ require 'helper'
2
+
3
+ describe Temple::Filters::ControlFlow do
4
+ before do
5
+ @filter = Temple::Filters::ControlFlow.new
6
+ end
7
+
8
+ it 'should process blocks' do
9
+ @filter.call([:block, 'loop do',
10
+ [:static, 'Hello']
11
+ ]).should.equal [:multi,
12
+ [:code, 'loop do'],
13
+ [:static, 'Hello'],
14
+ [:code, 'end']]
15
+ end
16
+
17
+ it 'should process if' do
18
+ @filter.call([:if, 'condition',
19
+ [:static, 'Hello']
20
+ ]).should.equal [:multi,
21
+ [:code, 'if condition'],
22
+ [:static, 'Hello'],
23
+ [:code, 'end']
24
+ ]
25
+ end
26
+
27
+ it 'should process if with else' do
28
+ @filter.call([:if, 'condition',
29
+ [:static, 'True'],
30
+ [:static, 'False']
31
+ ]).should.equal [:multi,
32
+ [:code, 'if condition'],
33
+ [:static, 'True'],
34
+ [:code, 'else'],
35
+ [:static, 'False'],
36
+ [:code, 'end']
37
+ ]
38
+ end
39
+
40
+ it 'should create elsif' do
41
+ @filter.call([:if, 'condition1',
42
+ [:static, '1'],
43
+ [:if, 'condition2',
44
+ [:static, '2'],
45
+ [:static, '3']]
46
+ ]).should.equal [:multi,
47
+ [:code, 'if condition1'],
48
+ [:static, '1'],
49
+ [:code, 'elsif condition2'],
50
+ [:static, '2'],
51
+ [:code, 'else'],
52
+ [:static, '3'],
53
+ [:code, 'end']
54
+ ]
55
+ end
56
+
57
+ it 'should process cond' do
58
+ @filter.call([:cond,
59
+ ['cond1', [:exp11], [:exp12]],
60
+ ['cond2', [:exp2]],
61
+ [:else, [:exp3]],
62
+ ]).should.equal [:multi,
63
+ [:code, 'case'],
64
+ [:code, 'when cond1'],
65
+ [:exp11],
66
+ [:exp12],
67
+ [:code, 'when cond2'],
68
+ [:exp2],
69
+ [:code, 'else'],
70
+ [:exp3],
71
+ [:code, 'end']
72
+ ]
73
+ end
74
+
75
+ it 'should process case' do
76
+ @filter.call([:case, 'var',
77
+ ['Array', [:exp11], [:exp12]],
78
+ ['String', [:exp2]],
79
+ [:else, [:exp3]],
80
+ ]).should.equal [:multi,
81
+ [:code, 'case (var)'],
82
+ [:code, 'when Array'],
83
+ [:exp11],
84
+ [:exp12],
85
+ [:code, 'when String'],
86
+ [:exp2],
87
+ [:code, 'else'],
88
+ [:exp3],
89
+ [:code, 'end']
90
+ ]
91
+ end
92
+ end
@@ -30,22 +30,22 @@ describe Temple::Filters::DynamicInliner do
30
30
  ]).should.equal [:multi, [:dynamic, '"Hello#{@world}#{@yeah}Nice"']]
31
31
  end
32
32
 
33
- it 'should merge statics and dynamics around a block' do
33
+ it 'should merge statics and dynamics around a code' do
34
34
  exp = @filter.call([:multi,
35
35
  [:static, "Hello "],
36
36
  [:dynamic, "@world"],
37
- [:block, "Oh yeah"],
37
+ [:code, "Oh yeah"],
38
38
  [:dynamic, "@yeah"],
39
39
  [:static, "Once more"]
40
40
  ]).should.equal [:multi,
41
41
  [:dynamic, '"Hello #{@world}"'],
42
- [:block, "Oh yeah"],
42
+ [:code, "Oh yeah"],
43
43
  [:dynamic, '"#{@yeah}Once more"']
44
44
  ]
45
45
  end
46
46
 
47
- it 'should keep blocks intact' do
48
- exp = [:multi, [:block, 'foo']]
47
+ it 'should keep codes intact' do
48
+ exp = [:multi, [:code, 'foo']]
49
49
  @filter.call(exp).should.equal exp
50
50
  end
51
51
 
@@ -90,11 +90,11 @@ describe Temple::Filters::DynamicInliner do
90
90
  @filter.call([:multi,
91
91
  [:static, "Hello \n"],
92
92
  [:newline],
93
- [:block, "world"]
93
+ [:code, "world"]
94
94
  ]).should.equal [:multi,
95
95
  [:static, "Hello \n"],
96
96
  [:newline],
97
- [:block, "world"]
97
+ [:code, "world"]
98
98
  ]
99
99
  end
100
100
  end
@@ -0,0 +1,55 @@
1
+ require 'helper'
2
+
3
+ describe Temple::Filters::Eraser do
4
+ it 'should respect keep' do
5
+ eraser = Temple::Filters::Eraser.new(:keep => [:a])
6
+ eraser.call([:multi,
7
+ [:a],
8
+ [:b],
9
+ [:c]
10
+ ]).should.equal [:multi,
11
+ [:a],
12
+ [:multi],
13
+ [:multi]
14
+ ]
15
+ end
16
+
17
+ it 'should respect erase' do
18
+ eraser = Temple::Filters::Eraser.new(:erase => [:a])
19
+ eraser.call([:multi,
20
+ [:a],
21
+ [:b],
22
+ [:c]
23
+ ]).should.equal [:multi,
24
+ [:multi],
25
+ [:b],
26
+ [:c]
27
+ ]
28
+ end
29
+
30
+ it 'should choose erase over keep' do
31
+ eraser = Temple::Filters::Eraser.new(:keep => [:a, :b], :erase => [:a])
32
+ eraser.call([:multi,
33
+ [:a],
34
+ [:b],
35
+ [:c]
36
+ ]).should.equal [:multi,
37
+ [:multi],
38
+ [:b],
39
+ [:multi]
40
+ ]
41
+ end
42
+
43
+ it 'should erase nested types' do
44
+ eraser = Temple::Filters::Eraser.new(:erase => [[:a, :b]])
45
+ eraser.call([:multi,
46
+ [:a, :a],
47
+ [:a, :b],
48
+ [:b]
49
+ ]).should.equal [:multi,
50
+ [:a, :a],
51
+ [:multi],
52
+ [:b]
53
+ ]
54
+ end
55
+ end
@@ -6,9 +6,9 @@ class HtmlSafeString < String
6
6
  end
7
7
  end
8
8
 
9
- describe Temple::Filters::EscapeHTML do
9
+ describe Temple::Filters::Escapable do
10
10
  before do
11
- @filter = Temple::Filters::EscapeHTML.new
11
+ @filter = Temple::Filters::Escapable.new
12
12
  end
13
13
 
14
14
  it 'should handle escape expressions' do
@@ -22,8 +22,8 @@ describe Temple::Filters::EscapeHTML do
22
22
  ]
23
23
  end
24
24
 
25
- it 'should keep blocks intact' do
26
- exp = [:multi, [:block, 'foo']]
25
+ it 'should keep codes intact' do
26
+ exp = [:multi, [:code, 'foo']]
27
27
  @filter.call(exp).should.equal exp
28
28
  end
29
29
 
@@ -38,9 +38,16 @@ describe Temple::Filters::EscapeHTML do
38
38
  end
39
39
 
40
40
  it 'should have use_html_safe option' do
41
- filter = Temple::Filters::EscapeHTML.new(:use_html_safe => true)
41
+ filter = Temple::Filters::Escapable.new(:use_html_safe => true)
42
42
  filter.call([:escape, true,
43
- [:static, HtmlSafeString.new("a < b")],
43
+ [:static, HtmlSafeString.new("a < b")]
44
44
  ]).should.equal [:static, "a < b"]
45
45
  end
46
+
47
+ it 'should support censoring' do
48
+ filter = Temple::Filters::Escapable.new(:escape_code => '(%s).gsub("Temple sucks", "Temple rocks")')
49
+ filter.call([:escape, true,
50
+ [:static, "~~ Temple sucks ~~"]
51
+ ]).should.equal [:static, "~~ Temple rocks ~~"]
52
+ end
46
53
  end
@@ -28,6 +28,6 @@ describe Temple::Filters::MultiFlattener do
28
28
  end
29
29
 
30
30
  it 'should return first element' do
31
- @filter.call([:multi, [:block, 'foo']]).should.equal [:block, 'foo']
31
+ @filter.call([:multi, [:code, 'foo']]).should.equal [:code, 'foo']
32
32
  end
33
33
  end
@@ -15,16 +15,16 @@ describe Temple::Filters::StaticMerger do
15
15
  ]
16
16
  end
17
17
 
18
- it 'should merge serveral statics around block' do
18
+ it 'should merge serveral statics around code' do
19
19
  @filter.call([:multi,
20
20
  [:static, "Hello "],
21
21
  [:static, "World!"],
22
- [:block, "123"],
22
+ [:code, "123"],
23
23
  [:static, "Good night, "],
24
24
  [:static, "everybody"]
25
25
  ]).should.equal [:multi,
26
26
  [:static, "Hello World!"],
27
- [:block, "123"],
27
+ [:code, "123"],
28
28
  [:static, "Good night, everybody"]
29
29
  ]
30
30
  end
data/test/helper.rb CHANGED
@@ -8,6 +8,14 @@ module TestHelper
8
8
  ensure
9
9
  String.send(:undef_method, :html_safe?) if String.method_defined?(:html_safe?)
10
10
  end
11
+
12
+ def grammar_validate(grammar, exp, message)
13
+ lambda { grammar.validate!(exp) }.should.raise(Temple::InvalidExpression).message.should.equal message
14
+ end
15
+
16
+ def erb(src, options = {})
17
+ Temple::ERB::Template.new(options) { src }.render
18
+ end
11
19
  end
12
20
 
13
21
  class Bacon::Context
@@ -17,44 +17,32 @@ describe Temple::HTML::Fast do
17
17
  end
18
18
 
19
19
  it 'should compile html comment' do
20
- @html.call([:html, :comment, 'test']).should.equal [:multi, [:static, "<!--"], "test", [:static, "-->"]]
20
+ @html.call([:html, :comment, [:static, 'test']]).should.equal [:multi, [:static, "<!--"], [:static, "test"], [:static, "-->"]]
21
21
  end
22
22
 
23
23
  it 'should compile autoclosed html tag' do
24
24
  @html.call([:html, :tag,
25
25
  'img', [:attrs],
26
- false, [:multi]
26
+ [:multi, [:newline]]
27
27
  ]).should.equal [:multi,
28
28
  [:static, "<img"],
29
29
  [:attrs],
30
- [:static, " /"],
31
- [:static, ">"], [:multi]]
30
+ [:static, " />"],
31
+ [:multi, [:newline]]]
32
32
  end
33
33
 
34
34
  it 'should compile explicitly closed html tag' do
35
35
  @html.call([:html, :tag,
36
- 'closed', [:attrs],
37
- true, [:multi]
36
+ 'closed', [:attrs]
38
37
  ]).should.equal [:multi,
39
38
  [:static, "<closed"],
40
39
  [:attrs],
41
- [:static, " /"],
42
- [:static, ">"], [:multi]]
43
- end
44
-
45
- it 'should raise error on closed tag with content' do
46
- lambda {
47
- @html.call([:html, :tag,
48
- 'img', [:attrs],
49
- false, [:content]
50
- ])
51
- }.should.raise(RuntimeError).message.should.equal 'Closed tag img has content'
40
+ [:static, " />"]]
52
41
  end
53
42
 
54
43
  it 'should compile html with content' do
55
44
  @html.call([:html, :tag,
56
- 'div', [:attrs],
57
- false, [:content]
45
+ 'div', [:attrs], [:content]
58
46
  ]).should.equal [:multi,
59
47
  [:static, "<div"],
60
48
  [:attrs],
@@ -66,31 +54,24 @@ describe Temple::HTML::Fast do
66
54
  it 'should compile html with static attrs' do
67
55
  @html.call([:html, :tag,
68
56
  'div',
69
- [:html, :staticattrs,
70
- ['id', [:static, 'test']],
71
- ['class', [:dynamic, 'block']]],
72
- false, [:content]
57
+ [:html, :attrs,
58
+ [:html, :attr, 'id', [:static, 'test']],
59
+ [:html, :attr, 'class', [:dynamic, 'block']]],
60
+ [:content]
73
61
  ]).should.equal [:multi,
74
62
  [:static,
75
63
  "<div"],
76
64
  [:multi,
77
65
  [:multi,
78
- [:capture, "_temple_htmlattr1",
66
+ [:capture, "_temple_html_fast1",
79
67
  [:dynamic, "block"]],
80
- [:block, "unless _temple_htmlattr1.empty?"],
81
- [:multi,
82
- [:static, " "],
83
- [:static, "class"],
84
- [:static, "="],
85
- [:static, "'"],
86
- [:dynamic, "_temple_htmlattr1"],
87
- [:static, "'"]],
88
- [:block, "end"]],
68
+ [:if, "!_temple_html_fast1.empty?",
69
+ [:multi,
70
+ [:static, " class='"],
71
+ [:dynamic, "_temple_html_fast1"],
72
+ [:static, "'"]]]],
89
73
  [:multi,
90
- [:static, " "],
91
- [:static, "id"],
92
- [:static, "="],
93
- [:static, "'"],
74
+ [:static, " id='"],
94
75
  [:static, "test"],
95
76
  [:static, "'"]]],
96
77
  [:static, ">"],
@@ -100,20 +81,22 @@ describe Temple::HTML::Fast do
100
81
 
101
82
  it 'should compile html with merged ids' do
102
83
  @html.call([:html, :tag,
103
- 'div', [:html, :staticattrs, ['id', [:static, 'a']], ['id', [:dynamic, 'b']]],
104
- false, [:content]
84
+ 'div',
85
+ [:html, :attrs, [:html, :attr, 'id', [:static, 'a']], [:html, :attr, 'id', [:dynamic, 'b']]],
86
+ [:content]
105
87
  ]).should.equal [:multi,
106
88
  [:static, "<div"],
107
89
  [:multi,
108
90
  [:multi,
109
- [:static, " "],
110
- [:static, "id"],
111
- [:static, "="],
112
- [:static, "'"],
91
+ [:static, " id='"],
113
92
  [:multi,
114
- [:static, 'a'],
115
- [:static, '_'],
116
- [:dynamic, 'b']],
93
+ [:static, "a"],
94
+ [:capture, "_temple_html_fast1",
95
+ [:dynamic, "b"]],
96
+ [:if, "!_temple_html_fast1.empty?",
97
+ [:multi,
98
+ [:static, "_"],
99
+ [:dynamic, "_temple_html_fast1"]]]],
117
100
  [:static, "'"]]],
118
101
  [:static, ">"],
119
102
  [:content],
@@ -122,28 +105,30 @@ describe Temple::HTML::Fast do
122
105
 
123
106
  it 'should compile html with merged classes' do
124
107
  @html.call([:html, :tag,
125
- 'div', [:html, :staticattrs, ['class', [:static, 'a']], ['class', [:dynamic, 'b']]],
126
- false, [:content]
108
+ 'div',
109
+ [:html, :attrs, [:html, :attr, 'class', [:static, 'a']], [:html, :attr, 'class', [:dynamic, 'b']]],
110
+ [:content]
127
111
  ]).should.equal [:multi,
128
112
  [:static, "<div"],
129
113
  [:multi,
130
114
  [:multi,
131
- [:static, " "],
132
- [:static, "class"],
133
- [:static, "="],
134
- [:static, "'"],
115
+ [:static, " class='"],
135
116
  [:multi,
136
- [:static, 'a'],
137
- [:static, ' '],
138
- [:dynamic, 'b']],
117
+ [:static, "a"],
118
+ [:capture, "_temple_html_fast1",
119
+ [:dynamic, "b"]],
120
+ [:if, "!_temple_html_fast1.empty?",
121
+ [:multi,
122
+ [:static, " "],
123
+ [:dynamic, "_temple_html_fast1"]]]],
139
124
  [:static, "'"]]],
140
125
  [:static, ">"],
141
126
  [:content],
142
127
  [:static, "</div>"]]
143
128
  end
144
129
 
145
- it 'should keep blocks intact' do
146
- exp = [:multi, [:block, 'foo']]
130
+ it 'should keep codes intact' do
131
+ exp = [:multi, [:code, 'foo']]
147
132
  @html.call(exp).should.equal exp
148
133
  end
149
134