slim 1.3.0 → 1.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.
Files changed (52) hide show
  1. data/.travis.yml +9 -5
  2. data/CHANGES +23 -0
  3. data/Gemfile +13 -2
  4. data/README.md +346 -105
  5. data/Rakefile +21 -9
  6. data/lib/slim.rb +3 -3
  7. data/lib/slim/boolean_attributes.rb +67 -0
  8. data/lib/slim/command.rb +23 -23
  9. data/lib/slim/control_structures.rb +57 -0
  10. data/lib/slim/embedded_engine.rb +80 -43
  11. data/lib/slim/end_inserter.rb +1 -1
  12. data/lib/slim/engine.rb +21 -15
  13. data/lib/slim/filter.rb +0 -6
  14. data/lib/slim/grammar.rb +2 -7
  15. data/lib/slim/interpolation.rb +1 -1
  16. data/lib/slim/logic_less/filter.rb +8 -8
  17. data/lib/slim/logic_less/wrapper.rb +1 -1
  18. data/lib/slim/parser.rb +51 -52
  19. data/lib/slim/splat_attributes.rb +112 -0
  20. data/lib/slim/translator.rb +13 -12
  21. data/lib/slim/version.rb +1 -1
  22. data/slim.gemspec +1 -1
  23. data/test/{slim → core}/helper.rb +3 -7
  24. data/test/{slim → core}/test_code_blocks.rb +0 -0
  25. data/test/{slim → core}/test_code_escaping.rb +4 -4
  26. data/test/{slim → core}/test_code_evaluation.rb +3 -112
  27. data/test/{slim → core}/test_code_output.rb +0 -0
  28. data/test/{slim → core}/test_code_structure.rb +0 -0
  29. data/test/{slim → core}/test_embedded_engines.rb +8 -3
  30. data/test/{slim → core}/test_encoding.rb +0 -0
  31. data/test/core/test_html_attributes.rb +218 -0
  32. data/test/{slim → core}/test_html_escaping.rb +17 -0
  33. data/test/{slim → core}/test_html_structure.rb +13 -98
  34. data/test/{slim → core}/test_parser_errors.rb +24 -15
  35. data/test/{slim → core}/test_pretty.rb +0 -0
  36. data/test/{slim → core}/test_ruby_errors.rb +7 -0
  37. data/test/{slim → core}/test_slim_template.rb +0 -0
  38. data/test/{slim → core}/test_text_interpolation.rb +2 -2
  39. data/test/core/test_thread_options.rb +18 -0
  40. data/test/{slim/logic_less → logic_less}/test_logic_less.rb +21 -0
  41. data/test/{slim/logic_less → logic_less}/test_wrapper.rb +3 -3
  42. data/test/rails/app/controllers/slim_controller.rb +4 -2
  43. data/test/rails/app/views/parents/_form.html.slim +1 -0
  44. data/test/rails/app/views/parents/edit.html.slim +2 -1
  45. data/test/rails/app/views/parents/new.html.slim +2 -1
  46. data/test/rails/app/views/slim/thread_options.html.slim +1 -0
  47. data/test/rails/test/test_slim.rb +6 -4
  48. data/test/{slim/translator → translator}/test_translator.rb +0 -0
  49. metadata +44 -82
  50. data/lib/slim/compiler.rb +0 -194
  51. data/test/rails/app/views/slim/nil.html.slim +0 -1
  52. data/test/slim/test_chain_manipulation.rb +0 -42
@@ -37,4 +37,21 @@ p class="#{x}" test #{content}
37
37
  }
38
38
  assert_html 'Hello World from @env escaped & Hello World from @env', source
39
39
  end
40
+
41
+ def test_html_quoted_attr_escape
42
+ source = %q{
43
+ p id="&" class=="&"
44
+ }
45
+
46
+ assert_html '<p class="&amp;" id="&"></p>', source
47
+ assert_html '<p class="&amp;" id="&amp;"></p>', source, :escape_quoted_attrs => true
48
+ end
49
+
50
+ def test_html_ruby_attr_escape
51
+ source = %q{
52
+ p id=('&'.to_s) class==('&amp;'.to_s)
53
+ }
54
+
55
+ assert_html '<p class="&amp;" id="&amp;"></p>', source
56
+ end
40
57
  end
@@ -293,10 +293,10 @@ p(id="marvin" class="" data-info="Illudium Q-36")= output_number
293
293
 
294
294
  def test_dynamic_empty_attribute
295
295
  source = %q{
296
- p(id="marvin" class=nil other_empty=("".to_s) data-info="Illudium Q-36")= output_number
296
+ p(id="marvin" class=nil nonempty=("".to_s) data-info="Illudium Q-36")= output_number
297
297
  }
298
298
 
299
- assert_html '<p data-info="Illudium Q-36" id="marvin">1337</p>', source
299
+ assert_html '<p data-info="Illudium Q-36" id="marvin" nonempty="">1337</p>', source
300
300
  end
301
301
 
302
302
  def test_closed_tag
@@ -478,102 +478,17 @@ input[value=succ_x]
478
478
  assert_html %{<input value="1" /><input value="2" />}, source
479
479
  end
480
480
 
481
- def test_shortcut_splat
481
+ def test_html_line_indicator
482
482
  source = %q{
483
- *hash This is my title
484
- }
485
-
486
- assert_html '<div a="The letter a" b="The letter b">This is my title</div>', source
487
- end
488
-
489
- def test_splat
490
- source = %q{
491
- h1 *hash This is my title
492
- }
493
-
494
- assert_html '<h1 a="The letter a" b="The letter b">This is my title</h1>', source
495
- end
496
-
497
- def test_splat_tag_name
498
- source = %q{
499
- *{:tag => 'h1', :id => 'title'} This is my title
500
- }
501
-
502
- assert_html '<h1 id="title">This is my title</h1>', source
503
- end
504
-
505
-
506
- def test_splat_empty_tag_name
507
- source = %q{
508
- *{:tag => '', :id => 'test'} This is my title
509
- }
510
-
511
- assert_html '<div id="test">This is my title</div>', source, :remove_empty_attrs => true
512
- assert_html '<div id="test">This is my title</div>', source, :remove_empty_attrs => false
513
- end
514
-
515
- def test_closed_splat_tag
516
- source = %q{
517
- *hash / This is my title
518
- }
519
-
520
- assert_html '<div a="The letter a" b="The letter b"/>', source
521
- end
522
-
523
- def test_splat_with_id_shortcut
524
- source = %q{
525
- #myid*hash This is my title
526
- }
527
-
528
- assert_html '<div a="The letter a" b="The letter b" id="myid">This is my title</div>', source
529
- end
530
-
531
- def test_splat_with_class_shortcut
532
- source = %q{
533
- .myclass*hash This is my title
534
- }
535
-
536
- assert_html '<div a="The letter a" b="The letter b" class="myclass">This is my title</div>', source
537
- end
538
-
539
- def test_splat_with_id_and_class_shortcuts
540
- source = %q{
541
- #myid.myclass*hash This is my title
542
- }
543
-
544
- assert_html '<div a="The letter a" b="The letter b" class="myclass" id="myid">This is my title</div>', source
545
- end
546
-
547
- def test_splat_with_class_merging
548
- source = %q{
549
- #myid.myclass *{:class => [:secondclass, %w(x y z)]} *hash This is my title
550
- }
551
-
552
- assert_html '<div a="The letter a" b="The letter b" class="myclass secondclass x y z" id="myid">This is my title</div>', source
553
- end
554
-
555
- def test_splat_with_boolean_attribute
556
- source = %q{
557
- *{:disabled => true, :empty1 => false, :empty2 => '', :empty3 => nil} This is my title
558
- }
559
-
560
- assert_html '<div disabled="disabled">This is my title</div>', source
561
- assert_html '<div disabled="disabled" empty1="" empty2="" empty3="">This is my title</div>', source, :remove_empty_attrs => false
562
- end
563
-
564
- def test_splat_merging_with_arrays
565
- source = %q{
566
- *{:a => 1, :b => 2} *[[:c, 3], [:d, 4]] *[[:e, 5], [:f, 6]] This is my title
567
- }
568
-
569
- assert_html '<div a="1" b="2" c="3" d="4" e="5" f="6">This is my title</div>', source
570
- end
571
-
572
- def test_splat_with_other_attributes
573
- source = %q{
574
- h1 data-id="123" *hash This is my title
575
- }
576
-
577
- assert_html '<h1 a="The letter a" b="The letter b" data-id="123">This is my title</h1>', source
483
+ <html>
484
+ head
485
+ meta name="keywords" content=hello_world
486
+ - if true
487
+ <p>#{hello_world}</p>
488
+ span = hello_world
489
+ </html>
490
+ }
491
+
492
+ assert_html '<html><head><meta content="Hello World from @env" name="keywords" /></head><p>Hello World from @env</p><span>Hello World from @env</span></html>', source
578
493
  end
579
494
  end
@@ -7,7 +7,7 @@ doctype 5
7
7
  div Invalid
8
8
  }
9
9
 
10
- assert_syntax_error "Unexpected indentation\n test.slim, Line 3\n div Invalid\n ^\n", source, :file => 'test.slim'
10
+ assert_syntax_error "Unexpected indentation\n test.slim, Line 3, Column 2\n div Invalid\n ^\n", source, :file => 'test.slim'
11
11
  end
12
12
 
13
13
  def test_unexpected_indentation
@@ -16,7 +16,7 @@ doctype 5
16
16
  div Invalid
17
17
  }
18
18
 
19
- assert_syntax_error "Unexpected indentation\n (__TEMPLATE__), Line 3\n div Invalid\n ^\n", source
19
+ assert_syntax_error "Unexpected indentation\n (__TEMPLATE__), Line 3, Column 2\n div Invalid\n ^\n", source
20
20
  end
21
21
 
22
22
  def test_unexpected_text_indentation
@@ -26,7 +26,7 @@ p
26
26
  text
27
27
  }
28
28
 
29
- assert_syntax_error "Text line not indented deep enough.\nThe first text line defines the necessary text indentation.\n (__TEMPLATE__), Line 4\n text\n ^\n", source
29
+ assert_syntax_error "Text line not indented deep enough.\nThe first text line defines the necessary text indentation.\n (__TEMPLATE__), Line 4, Column 3\n text\n ^\n", source
30
30
  end
31
31
 
32
32
  def test_unexpected_text_indentation_in_tag
@@ -42,7 +42,7 @@ ul
42
42
  li b
43
43
  }
44
44
 
45
- assert_syntax_error "Text line not indented deep enough.\nThe first text line defines the necessary text indentation.\nAre you trying to nest a child tag in a tag containing text? Use | for the text block!\n (__TEMPLATE__), Line 4\n ul\n ^\n", source
45
+ assert_syntax_error "Text line not indented deep enough.\nThe first text line defines the necessary text indentation.\nAre you trying to nest a child tag in a tag containing text? Use | for the text block!\n (__TEMPLATE__), Line 4, Column 4\n ul\n ^\n", source
46
46
  end
47
47
 
48
48
  def test_malformed_indentation
@@ -52,7 +52,7 @@ p
52
52
  div Invalid
53
53
  }
54
54
 
55
- assert_syntax_error "Malformed indentation\n (__TEMPLATE__), Line 4\n div Invalid\n ^\n", source
55
+ assert_syntax_error "Malformed indentation\n (__TEMPLATE__), Line 4, Column 1\n div Invalid\n ^\n", source
56
56
  end
57
57
 
58
58
  def test_unknown_line_indicator
@@ -64,7 +64,7 @@ p
64
64
  ?invalid
65
65
  }
66
66
 
67
- assert_syntax_error "Unknown line indicator\n (__TEMPLATE__), Line 6\n ?invalid\n ^\n", source
67
+ assert_syntax_error "Unknown line indicator\n (__TEMPLATE__), Line 6, Column 2\n ?invalid\n ^\n", source
68
68
  end
69
69
 
70
70
  def test_expected_closing_delimiter
@@ -73,7 +73,16 @@ p
73
73
  img(src="img.jpg" title={title}
74
74
  }
75
75
 
76
- assert_syntax_error "Expected closing delimiter )\n (__TEMPLATE__), Line 3\n img(src=\"img.jpg\" title={title}\n ^\n", source
76
+ assert_syntax_error "Expected closing delimiter )\n (__TEMPLATE__), Line 3, Column 33\n img(src=\"img.jpg\" title={title}\n ^\n", source
77
+ end
78
+
79
+ def test_expected_closing_quote
80
+ source = %q{
81
+ p
82
+ img(src="img.jpg
83
+ }
84
+
85
+ assert_syntax_error "Expected closing quote \"\n (__TEMPLATE__), Line 3, Column 18\n img(src=\"img.jpg\n ^\n", source
77
86
  end
78
87
 
79
88
  def test_expected_closing_attribute_delimiter
@@ -82,7 +91,7 @@ p
82
91
  img src=[hash[1] + hash[2]
83
92
  }
84
93
 
85
- assert_syntax_error "Expected closing delimiter ]\n (__TEMPLATE__), Line 3\n img src=[hash[1] + hash[2]\n ^\n", source
94
+ assert_syntax_error "Expected closing delimiter ]\n (__TEMPLATE__), Line 3, Column 28\n img src=[hash[1] + hash[2]\n ^\n", source
86
95
  end
87
96
 
88
97
  def test_expected_attribute
@@ -91,7 +100,7 @@ p
91
100
  img(src='img.png' whatsthis?!)
92
101
  }
93
102
 
94
- assert_syntax_error "Expected attribute\n (__TEMPLATE__), Line 3\n img(src='img.png' whatsthis?!)\n ^\n", source
103
+ assert_syntax_error "Expected attribute\n (__TEMPLATE__), Line 3, Column 20\n img(src='img.png' whatsthis?!)\n ^\n", source
95
104
  end
96
105
 
97
106
  def test_invalid_empty_attribute
@@ -100,7 +109,7 @@ p
100
109
  img{src= }
101
110
  }
102
111
 
103
- assert_syntax_error "Invalid empty attribute\n (__TEMPLATE__), Line 3\n img{src= }\n ^\n", source
112
+ assert_syntax_error "Invalid empty attribute\n (__TEMPLATE__), Line 3, Column 10\n img{src= }\n ^\n", source
104
113
  end
105
114
 
106
115
  def test_invalid_empty_attribute2
@@ -109,7 +118,7 @@ p
109
118
  img{src=}
110
119
  }
111
120
 
112
- assert_syntax_error "Invalid empty attribute\n (__TEMPLATE__), Line 3\n img{src=}\n ^\n", source
121
+ assert_syntax_error "Invalid empty attribute\n (__TEMPLATE__), Line 3, Column 10\n img{src=}\n ^\n", source
113
122
  end
114
123
 
115
124
  def test_invalid_empty_attribute3
@@ -118,7 +127,7 @@ p
118
127
  img src=
119
128
  }
120
129
 
121
- assert_syntax_error "Invalid empty attribute\n (__TEMPLATE__), Line 3\n img src=\n ^\n", source
130
+ assert_syntax_error "Invalid empty attribute\n (__TEMPLATE__), Line 3, Column 10\n img src=\n ^\n", source
122
131
  end
123
132
 
124
133
  def test_missing_tag_in_block_expansion
@@ -126,18 +135,18 @@ p
126
135
  html: body:
127
136
  }
128
137
 
129
- assert_syntax_error "Expected tag\n (__TEMPLATE__), Line 2\n html: body:\n ^\n", source
138
+ assert_syntax_error "Expected tag\n (__TEMPLATE__), Line 2, Column 11\n html: body:\n ^\n", source
130
139
  end
131
140
 
132
141
  def test_invalid_tag_in_block_expansion
133
142
  source = %{
134
143
  html: body: /comment
135
144
  }
136
- assert_syntax_error "Expected tag\n (__TEMPLATE__), Line 2\n html: body: /comment\n ^\n", source
145
+ assert_syntax_error "Expected tag\n (__TEMPLATE__), Line 2, Column 12\n html: body: /comment\n ^\n", source
137
146
 
138
147
  source = %{
139
148
  html: body:/comment
140
149
  }
141
- assert_syntax_error "Expected tag\n (__TEMPLATE__), Line 2\n html: body:/comment\n ^\n", source
150
+ assert_syntax_error "Expected tag\n (__TEMPLATE__), Line 2, Column 11\n html: body:/comment\n ^\n", source
142
151
  end
143
152
  end
File without changes
@@ -207,4 +207,11 @@ div
207
207
  }
208
208
  assert_runtime_error 'Multiple id attributes specified', source
209
209
  end
210
+
211
+ # def test_invalid_option
212
+ # render('', :foobar => 42)
213
+ # raise Exception, 'ArgumentError expected'
214
+ # rescue ArgumentError => ex
215
+ # assert_equal 'Option :foobar is not supported by Slim::Engine', ex.message
216
+ # end
210
217
  end
@@ -59,7 +59,7 @@ p Message: #{message('hello', "user #{output_number}")}
59
59
  | #{evil_method}
60
60
  }
61
61
 
62
- assert_html '&lt;script&gt;do_something_evil();&lt;&#47;script&gt;', source
62
+ assert_html '&lt;script&gt;do_something_evil();&lt;/script&gt;', source
63
63
  end
64
64
 
65
65
  def test_interpolation_without_escaping
@@ -74,6 +74,6 @@ p Message: #{message('hello', "user #{output_number}")}
74
74
  source = %q{
75
75
  | #{(evil_method)}
76
76
  }
77
- assert_html '&lt;script&gt;do_something_evil();&lt;&#47;script&gt;', source
77
+ assert_html '&lt;script&gt;do_something_evil();&lt;/script&gt;', source
78
78
  end
79
79
  end
@@ -0,0 +1,18 @@
1
+ require 'helper'
2
+
3
+ class TestSlimThreadOptions < TestSlim
4
+ def test_thread_options
5
+ source = %q{p.test}
6
+
7
+ assert_html '<p class="test"></p>', source
8
+ assert_html "<p class='test'></p>", source, :attr_wrapper => "'"
9
+
10
+ Slim::Engine.with_options(:attr_wrapper => "'") do
11
+ assert_html "<p class='test'></p>", source
12
+ assert_html '<p class="test"></p>', source, :attr_wrapper => '"'
13
+ end
14
+
15
+ assert_html '<p class="test"></p>', source
16
+ assert_html "<p class='test'></p>", source, :attr_wrapper => "'"
17
+ end
18
+ end
@@ -2,6 +2,17 @@ require 'helper'
2
2
  require 'slim/logic_less'
3
3
 
4
4
  class TestSlimLogicLess < TestSlim
5
+ class Scope
6
+ def initialize
7
+ @hash = {
8
+ :person => [
9
+ { :name => 'Joe', },
10
+ { :name => 'Jack', }
11
+ ]
12
+ }
13
+ end
14
+ end
15
+
5
16
  def test_symbol_access
6
17
  source = %q{
7
18
  p
@@ -19,6 +30,16 @@ p
19
30
  assert_html '<p><div class="name">Joe</div><div class="name">Jack</div></p>', source, :scope => hash, :dictionary_access => :symbol
20
31
  end
21
32
 
33
+ def test_dictionary_option
34
+ source = %q{
35
+ p
36
+ - person
37
+ .name = name
38
+ }
39
+
40
+ assert_html '<p><div class="name">Joe</div><div class="name">Jack</div></p>', source, :scope => Scope.new, :dictionary => '@hash', :dictionary_access => :symbol
41
+ end
42
+
22
43
  def test_string_access
23
44
  source = %q{
24
45
  p
@@ -8,7 +8,7 @@ p
8
8
  - person
9
9
  .name = name
10
10
  }
11
- assert_html '<p><div class="name">Joe</div><div class="name">Jack</div></p>', source, :sections => true, :dictionary => 'ViewEnv.new'
11
+ assert_html '<p><div class="name">Joe</div><div class="name">Jack</div></p>', source, :dictionary => 'ViewEnv.new'
12
12
  end
13
13
 
14
14
  def test_with_array
@@ -18,14 +18,14 @@ ul
18
18
  li = name
19
19
  li = city
20
20
  }
21
- assert_html '<ul><li>Andy</li><li>Atlanta</li><li>Fred</li><li>Melbourne</li><li>Daniel</li><li>Karlsruhe</li></ul>', source, :sections => true, :dictionary => 'ViewEnv.new'
21
+ assert_html '<ul><li>Andy</li><li>Atlanta</li><li>Fred</li><li>Melbourne</li><li>Daniel</li><li>Karlsruhe</li></ul>', source, :dictionary => 'ViewEnv.new'
22
22
  end
23
23
 
24
24
  def test_method
25
25
  source = %q{
26
26
  a href=output_number Link
27
27
  }
28
- assert_html '<a href="1337">Link</a>', source, :sections => true, :dictionary => 'ViewEnv.new'
28
+ assert_html '<a href="1337">Link</a>', source, :dictionary => 'ViewEnv.new'
29
29
  end
30
30
 
31
31
  end
@@ -22,8 +22,10 @@ class SlimController < ApplicationController
22
22
  @integer = 1337
23
23
  end
24
24
 
25
- def nil
26
- @nil = nil
25
+ def thread_options
26
+ Slim::Engine.with_options(:shortcut => {'@' => "div #{params[:attr]}"}) do
27
+ render
28
+ end
27
29
  end
28
30
 
29
31
  def content_for
@@ -1,3 +1,4 @@
1
+ h2 Form
1
2
  = form_for @parent, :html => {:multipart => true} do |f|
2
3
  h1 Parent
3
4
  = f.text_field :name
@@ -1 +1,2 @@
1
- = render "form"
1
+ h1 Edit
2
+ = render "form"
@@ -1 +1,2 @@
1
- = render "form"
1
+ h1 New
2
+ = render "form"
@@ -45,9 +45,11 @@ class TestSlim < ActionDispatch::IntegrationTest
45
45
  assert_html "<p>1337</p>"
46
46
  end
47
47
 
48
- test "render nil" do
49
- get "slim/nil"
50
- assert_html "<p></p>"
48
+ test "render thread_options" do
49
+ get "slim/thread_options", :attr => 'role'
50
+ assert_html '<p role="empty">Test</p>'
51
+ get "slim/thread_options", :attr => 'id' # Overwriting doesn't work because of caching
52
+ assert_html '<p role="empty">Test</p>'
51
53
  end
52
54
 
53
55
  test "content_for" do
@@ -59,7 +61,7 @@ class TestSlim < ActionDispatch::IntegrationTest
59
61
  post "parents", 'parent[name]' => "p1", 'parent[children_attributes][0][name]' => "c1"
60
62
  get "parents/1/edit"
61
63
 
62
- assert_match(%r{<form accept-charset="UTF-8" action="/parents/1" class="edit_parent" enctype="multipart/form-data" id="edit_parent_1" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="_method" type="hidden" value="[^"]+" /></div><h1>Parent</h1><input id="parent_name" name="parent\[name\]" size="30" type="text" value="p1" /><h2>Children</h2><ul><li><input id="parent_children_attributes_0_name" name="parent\[children_attributes\]\[0\]\[name\]" size="30" type="text" value="c1" /></li><input id="parent_children_attributes_0_id" name="parent\[children_attributes\]\[0\]\[id\]" type="hidden" value="1" /></ul></form>}, @response.body)
64
+ assert_match(%r{<div class="content"><h1>Edit</h1><h2>Form</h2><form accept-charset="UTF-8" action="/parents/1" class="edit_parent" enctype="multipart/form-data" id="edit_parent_1" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="_method" type="hidden" value="[^"]+" /></div><h1>Parent</h1><input id="parent_name" name="parent\[name\]" size="30" type="text" value="p1" /><h2>Children</h2><ul><li><input id="parent_children_attributes_0_name" name="parent\[children_attributes\]\[0\]\[name\]" size="30" type="text" value="c1" /></li><input id="parent_children_attributes_0_id" name="parent\[children_attributes\]\[0\]\[id\]" type="hidden" value="1" /></ul></form></div>}, @response.body)
63
65
  end
64
66
 
65
67
  protected