slim 1.3.0 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -2,8 +2,9 @@ require 'slim'
2
2
 
3
3
  module Slim
4
4
  class Translator < Filter
5
- set_default_options :tr_mode => :dynamic,
6
- :tr_fn => '_'
5
+ define_options :tr_mode => :dynamic,
6
+ :tr_fn => '_',
7
+ :tr => false
7
8
 
8
9
  if Object.const_defined?(:I18n)
9
10
  set_default_options :tr_fn => '::Slim::Translator.i18n_text',
@@ -30,22 +31,18 @@ module Slim
30
31
  end
31
32
 
32
33
  def call(exp)
33
- if options[:tr]
34
- super
35
- else
36
- exp
37
- end
34
+ options[:tr] ? super : exp
38
35
  end
39
36
 
40
- def initialize(opts)
37
+ def initialize(opts = {})
41
38
  super
42
39
  case options[:tr_mode]
43
40
  when :static
44
- @translator = StaticTranslator.new(options)
41
+ @translator = StaticTranslator.new(:tr_fn => options[:tr_fn])
45
42
  when :dynamic
46
- @translator = DynamicTranslator.new(options)
43
+ @translator = DynamicTranslator.new(:tr_fn => options[:tr_fn])
47
44
  else
48
- raise "Invalid translator mode #{options[:tr_mode].inspect}"
45
+ raise ArgumentError, "Invalid translator mode #{options[:tr_mode].inspect}"
49
46
  end
50
47
  end
51
48
 
@@ -56,7 +53,9 @@ module Slim
56
53
  private
57
54
 
58
55
  class StaticTranslator < Filter
59
- def initialize(opts)
56
+ define_options :tr_fn
57
+
58
+ def initialize(opts = {})
60
59
  super
61
60
  @translate = eval("proc {|string| #{options[:tr_fn]}(string) }")
62
61
  end
@@ -86,6 +85,8 @@ module Slim
86
85
  end
87
86
 
88
87
  class DynamicTranslator < Filter
88
+ define_options :tr_fn
89
+
89
90
  def call(exp)
90
91
  @captures_count, @captures_var, @text = 0, unique_name, ''
91
92
 
@@ -1,5 +1,5 @@
1
1
  module Slim
2
2
  # Slim version string
3
3
  # @api public
4
- VERSION = '1.3.0'
4
+ VERSION = '1.3.2'
5
5
  end
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = %w(lib)
21
21
 
22
- s.add_runtime_dependency('temple', ['~> 0.4.1'])
22
+ s.add_runtime_dependency('temple', ['~> 0.5.0'])
23
23
  s.add_runtime_dependency('tilt', ['~> 1.3.3'])
24
24
 
25
25
  s.add_development_dependency('rake', ['>= 0.8.7'])
@@ -7,8 +7,7 @@ require 'slim/grammar'
7
7
  MiniTest::Unit.autorun
8
8
 
9
9
  Slim::Engine.after Slim::Parser, Temple::Filters::Validator, :grammar => Slim::Grammar
10
- Slim::Engine.before Slim::Compiler, Temple::Filters::Validator, :grammar => Slim::Grammar
11
- Slim::Engine.before :AttributeMerger, Temple::Filters::Validator
10
+ Slim::Engine.before :Pretty, Temple::Filters::Validator
12
11
 
13
12
  class TestSlim < MiniTest::Unit::TestCase
14
13
  def setup
@@ -16,7 +15,8 @@ class TestSlim < MiniTest::Unit::TestCase
16
15
  end
17
16
 
18
17
  def render(source, options = {}, &block)
19
- Slim::Template.new(options[:file], options) { source }.render(options[:scope] || @env, &block)
18
+ scope = options.delete(:scope)
19
+ Slim::Template.new(options[:file], options) { source }.render(scope || @env, &block)
20
20
  end
21
21
 
22
22
  def assert_html(expected, source, options = {}, &block)
@@ -133,10 +133,6 @@ class Env
133
133
  "<script>do_something_evil();</script>"
134
134
  end
135
135
 
136
- def method_which_returns_true
137
- true
138
- end
139
-
140
136
  def output_number
141
137
  1337
142
138
  end
File without changes
@@ -6,7 +6,7 @@ class TestSlimCodeEscaping < TestSlim
6
6
  p = evil_method
7
7
  }
8
8
 
9
- assert_html '<p>&lt;script&gt;do_something_evil();&lt;&#47;script&gt;</p>', source
9
+ assert_html '<p>&lt;script&gt;do_something_evil();&lt;/script&gt;</p>', source
10
10
  end
11
11
 
12
12
  def test_render_without_html_safe
@@ -14,7 +14,7 @@ p = evil_method
14
14
  p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
15
15
  }
16
16
 
17
- assert_html "<p>&lt;strong&gt;Hello World\n, meet \&quot;Slim\&quot;&lt;&#47;strong&gt;.</p>", source
17
+ assert_html "<p>&lt;strong&gt;Hello World\n, meet \&quot;Slim\&quot;&lt;/strong&gt;.</p>", source
18
18
  end
19
19
 
20
20
  def test_render_with_html_safe_false
@@ -22,7 +22,7 @@ p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
22
22
  p = HtmlUnsafeString.new("<strong>Hello World\\n, meet \\"Slim\\"</strong>.")
23
23
  }
24
24
 
25
- assert_html "<p>&lt;strong&gt;Hello World\n, meet \&quot;Slim\&quot;&lt;&#47;strong&gt;.</p>", source, :use_html_safe => true
25
+ assert_html "<p>&lt;strong&gt;Hello World\n, meet \&quot;Slim\&quot;&lt;/strong&gt;.</p>", source, :use_html_safe => true
26
26
  end
27
27
 
28
28
  def test_render_with_html_safe_true
@@ -39,7 +39,7 @@ p = HtmlSafeString.new("<strong>Hello World\\n, meet \\"Slim\\"</strong>.")
39
39
  == "<p>World</p>"
40
40
  }
41
41
 
42
- assert_html "&lt;p&gt;Hello&lt;&#47;p&gt;<p>World</p>", source
42
+ assert_html "&lt;p&gt;Hello&lt;/p&gt;<p>World</p>", source
43
43
  end
44
44
 
45
45
  def test_render_with_disable_escape_true
@@ -71,7 +71,7 @@ p id=@var
71
71
  form action=action_path(:page, :save) method='post'
72
72
  }
73
73
 
74
- assert_html '<form action="&#47;action-page-save" method="post"></form>', source
74
+ assert_html '<form action="/action-page-save" method="post"></form>', source
75
75
  end
76
76
 
77
77
  def test_ruby_attribute_with_unbalanced_delimiters
@@ -79,7 +79,7 @@ form action=action_path(:page, :save) method='post'
79
79
  div crazy=action_path('[') id="crazy_delimiters"
80
80
  }
81
81
 
82
- assert_html '<div crazy="&#47;action-[" id="crazy_delimiters"></div>', source
82
+ assert_html '<div crazy="/action-[" id="crazy_delimiters"></div>', source
83
83
  end
84
84
 
85
85
  def test_method_call_in_delimited_attribute_without_quotes
@@ -87,20 +87,12 @@ div crazy=action_path('[') id="crazy_delimiters"
87
87
  form(action=action_path(:page, :save) method='post')
88
88
  }
89
89
 
90
- assert_html '<form action="&#47;action-page-save" method="post"></form>', source
90
+ assert_html '<form action="/action-page-save" method="post"></form>', source
91
91
  end
92
92
 
93
93
  def test_method_call_in_delimited_attribute_without_quotes2
94
94
  source = %q{
95
95
  form(method='post' action=action_path(:page, :save))
96
- }
97
-
98
- assert_html '<form action="&#47;action-page-save" method="post"></form>', source
99
- end
100
-
101
- def test_bypassing_escape_in_attribute
102
- source = %q{
103
- form action==action_path(:page, :save) method='post'
104
96
  }
105
97
 
106
98
  assert_html '<form action="/action-page-save" method="post"></form>', source
@@ -185,105 +177,4 @@ p = output_number
185
177
 
186
178
  assert_html '<p>1337</p>', source
187
179
  end
188
-
189
- def test_ternary_operation_in_attribute
190
- source = %q{
191
- p id="#{(false ? 'notshown' : 'shown')}" = output_number
192
- }
193
-
194
- assert_html '<p id="shown">1337</p>', source
195
- end
196
-
197
- def test_ternary_operation_in_attribute_2
198
- source = %q{
199
- p id=(false ? 'notshown' : 'shown') = output_number
200
- }
201
-
202
- assert_html '<p id="shown">1337</p>', source
203
- end
204
-
205
- def test_class_attribute_merging
206
- source = %{
207
- .alpha class="beta" Test it
208
- }
209
- assert_html '<div class="alpha beta">Test it</div>', source
210
- end
211
-
212
- def test_class_attribute_merging_with_nil
213
- source = %{
214
- .alpha class="beta" class=nil class="gamma" Test it
215
- }
216
- assert_html '<div class="alpha beta gamma">Test it</div>', source
217
- end
218
-
219
- def test_id_attribute_merging
220
- source = %{
221
- #alpha id="beta" Test it
222
- }
223
- assert_html '<div id="alpha_beta">Test it</div>', source, :attr_delimiter => {'class' => ' ', 'id' => '_' }
224
- end
225
-
226
- def test_id_attribute_merging2
227
- source = %{
228
- #alpha id="beta" Test it
229
- }
230
- assert_html '<div id="alpha-beta">Test it</div>', source, :attr_delimiter => {'class' => ' ', 'id' => '-' }
231
- end
232
-
233
- def test_boolean_attribute_false
234
- source = %{
235
- option selected=false Text
236
- }
237
-
238
- assert_html '<option>Text</option>', source
239
- end
240
-
241
- def test_boolean_attribute_true
242
- source = %{
243
- option selected=true Text
244
- }
245
-
246
- assert_html '<option selected="selected">Text</option>', source
247
- end
248
-
249
- def test_boolean_attribute_dynamic
250
- source = %{
251
- option selected=method_which_returns_true Text
252
- }
253
-
254
- assert_html '<option selected="selected">Text</option>', source
255
- end
256
-
257
- def test_boolean_attribute_nil
258
- source = %{
259
- option selected=nil Text
260
- }
261
-
262
- assert_html '<option>Text</option>', source
263
- end
264
-
265
- def test_boolean_attribute_string2
266
- source = %{
267
- option selected="selected" Text
268
- }
269
-
270
- assert_html '<option selected="selected">Text</option>', source
271
- end
272
-
273
- def test_boolean_attribute_shortcut
274
- source = %{
275
- option(class="clazz" selected) Text
276
- option(selected class="clazz") Text
277
- }
278
-
279
- assert_html '<option class="clazz" selected="selected">Text</option><option class="clazz" selected="selected">Text</option>', source
280
- end
281
-
282
- def test_array_attribute
283
- source = %{
284
- .alpha class="beta" class=[:gamma, nil, :delta, [true, false]]
285
- }
286
-
287
- assert_html '<div class="alpha beta gamma delta true false"></div>', source
288
- end
289
180
  end
File without changes
@@ -27,9 +27,9 @@ markdown:
27
27
  }
28
28
  assert_html "<h1 id=\"header\">Header</h1>\n<p>Hello from Markdown!</p>\n\n<p>3</p>\n\n<ul>\n <li>one</li>\n <li>two</li>\n</ul>\n", source
29
29
 
30
- Slim::EmbeddedEngine.default_options[:markdown] = {:auto_ids => false}
31
- assert_html "<h1>Header</h1>\n<p>Hello from Markdown!</p>\n\n<p>3</p>\n\n<ul>\n <li>one</li>\n <li>two</li>\n</ul>\n", source
32
- Slim::EmbeddedEngine.default_options[:markdown] = nil
30
+ Slim::EmbeddedEngine.with_options(:markdown => {:auto_ids => false}) do
31
+ assert_html "<h1>Header</h1>\n<p>Hello from Markdown!</p>\n\n<p>3</p>\n\n<ul>\n <li>one</li>\n <li>two</li>\n</ul>\n", source
32
+ end
33
33
 
34
34
  assert_html "<h1 id=\"header\">Header</h1>\n<p>Hello from Markdown!</p>\n\n<p>3</p>\n\n<ul>\n <li>one</li>\n <li>two</li>\n</ul>\n", source
35
35
  end
@@ -114,18 +114,21 @@ scss:
114
114
  ruby:
115
115
  Embedded Ruby
116
116
  }
117
+ assert_runtime_error 'Embedded engine ruby is disabled', source, :enable_engines => [:javascript]
117
118
  assert_runtime_error 'Embedded engine ruby is disabled', source, :enable_engines => %w(javascript)
118
119
 
119
120
  source = %{
120
121
  ruby:
121
122
  Embedded Ruby
122
123
  }
124
+ assert_runtime_error 'Embedded engine ruby is disabled', source, :enable_engines => [:javascript]
123
125
  assert_runtime_error 'Embedded engine ruby is disabled', source, :enable_engines => %w(javascript)
124
126
 
125
127
  source = %{
126
128
  ruby:
127
129
  Embedded Ruby
128
130
  }
131
+ assert_runtime_error 'Embedded engine ruby is disabled', source, :disable_engines => [:ruby]
129
132
  assert_runtime_error 'Embedded engine ruby is disabled', source, :disable_engines => %w(ruby)
130
133
  end
131
134
 
@@ -134,12 +137,14 @@ ruby:
134
137
  javascript:
135
138
  $(function() {});
136
139
  }
140
+ assert_html '<script type="text/javascript">$(function() {});</script>', source, :disable_engines => [:ruby]
137
141
  assert_html '<script type="text/javascript">$(function() {});</script>', source, :disable_engines => %w(ruby)
138
142
 
139
143
  source = %q{
140
144
  javascript:
141
145
  $(function() {});
142
146
  }
147
+ assert_html '<script type="text/javascript">$(function() {});</script>', source, :enable_engines => [:javascript]
143
148
  assert_html '<script type="text/javascript">$(function() {});</script>', source, :enable_engines => %w(javascript)
144
149
  end
145
150
  end
File without changes
@@ -0,0 +1,218 @@
1
+ require 'helper'
2
+
3
+ class TestSlimHTMLAttributes < TestSlim
4
+ def test_ternary_operation_in_attribute
5
+ source = %q{
6
+ p id="#{(false ? 'notshown' : 'shown')}" = output_number
7
+ }
8
+
9
+ assert_html '<p id="shown">1337</p>', source
10
+ end
11
+
12
+ def test_ternary_operation_in_attribute_2
13
+ source = %q{
14
+ p id=(false ? 'notshown' : 'shown') = output_number
15
+ }
16
+
17
+ assert_html '<p id="shown">1337</p>', source
18
+ end
19
+
20
+ def test_class_attribute_merging
21
+ source = %{
22
+ .alpha class="beta" Test it
23
+ }
24
+ assert_html '<div class="alpha beta">Test it</div>', source
25
+ end
26
+
27
+ def test_class_attribute_merging_with_nil
28
+ source = %{
29
+ .alpha class="beta" class=nil class="gamma" Test it
30
+ }
31
+ assert_html '<div class="alpha beta gamma">Test it</div>', source
32
+ end
33
+
34
+ def test_class_attribute_merging_with_empty_static
35
+ source = %{
36
+ .alpha class="beta" class="" class="gamma" Test it
37
+ }
38
+ assert_html '<div class="alpha beta gamma">Test it</div>', source
39
+ end
40
+
41
+ def test_id_attribute_merging
42
+ source = %{
43
+ #alpha id="beta" Test it
44
+ }
45
+ assert_html '<div id="alpha_beta">Test it</div>', source, :attr_delimiter => {'class' => ' ', 'id' => '_' }
46
+ end
47
+
48
+ def test_id_attribute_merging2
49
+ source = %{
50
+ #alpha id="beta" Test it
51
+ }
52
+ assert_html '<div id="alpha-beta">Test it</div>', source, :attr_delimiter => {'class' => ' ', 'id' => '-' }
53
+ end
54
+
55
+ def test_boolean_attribute_false
56
+ source = %{
57
+ - cond=false
58
+ option selected=false Text
59
+ option selected=cond Text2
60
+ }
61
+
62
+ assert_html '<option>Text</option><option>Text2</option>', source
63
+ end
64
+
65
+ def test_boolean_attribute_true
66
+ source = %{
67
+ - cond=true
68
+ option selected=true Text
69
+ option selected=cond Text2
70
+ }
71
+
72
+ assert_html '<option selected="selected">Text</option><option selected="selected">Text2</option>', source
73
+ end
74
+
75
+ def test_boolean_attribute_nil
76
+ source = %{
77
+ - cond=nil
78
+ option selected=nil Text
79
+ option selected=cond Text2
80
+ }
81
+
82
+ assert_html '<option>Text</option><option>Text2</option>', source
83
+ end
84
+
85
+ def test_boolean_attribute_string2
86
+ source = %{
87
+ option selected="selected" Text
88
+ }
89
+
90
+ assert_html '<option selected="selected">Text</option>', source
91
+ end
92
+
93
+ def test_boolean_attribute_shortcut
94
+ source = %{
95
+ option(class="clazz" selected) Text
96
+ option(selected class="clazz") Text
97
+ }
98
+
99
+ assert_html '<option class="clazz" selected="selected">Text</option><option class="clazz" selected="selected">Text</option>', source
100
+ end
101
+
102
+ def test_array_attribute
103
+ source = %{
104
+ .alpha class="beta" class=[:gamma, nil, :delta, [true, false]]
105
+ }
106
+
107
+ assert_html '<div class="alpha beta gamma delta true false"></div>', source
108
+ end
109
+
110
+
111
+ def test_shortcut_splat
112
+ source = %q{
113
+ *hash This is my title
114
+ }
115
+
116
+ assert_html '<div a="The letter a" b="The letter b">This is my title</div>', source
117
+ end
118
+
119
+ def test_splat
120
+ source = %q{
121
+ h1 *hash This is my title
122
+ }
123
+
124
+ assert_html '<h1 a="The letter a" b="The letter b">This is my title</h1>', source
125
+ end
126
+
127
+ def test_splat_tag_name
128
+ source = %q{
129
+ *{:tag => 'h1', :id => 'title'} This is my title
130
+ }
131
+
132
+ assert_html '<h1 id="title">This is my title</h1>', source
133
+ end
134
+
135
+
136
+ def test_splat_empty_tag_name
137
+ source = %q{
138
+ *{:tag => '', :id => 'test'} This is my title
139
+ }
140
+
141
+ assert_html '<div id="test">This is my title</div>', source
142
+ end
143
+
144
+ def test_closed_splat_tag
145
+ source = %q{
146
+ *hash / This is my title
147
+ }
148
+
149
+ assert_html '<div a="The letter a" b="The letter b"/>', source
150
+ end
151
+
152
+ def test_splat_with_id_shortcut
153
+ source = %q{
154
+ #myid*hash This is my title
155
+ }
156
+
157
+ assert_html '<div a="The letter a" b="The letter b" id="myid">This is my title</div>', source
158
+ end
159
+
160
+ def test_splat_with_class_shortcut
161
+ source = %q{
162
+ .myclass*hash This is my title
163
+ }
164
+
165
+ assert_html '<div a="The letter a" b="The letter b" class="myclass">This is my title</div>', source
166
+ end
167
+
168
+ def test_splat_with_id_and_class_shortcuts
169
+ source = %q{
170
+ #myid.myclass*hash This is my title
171
+ }
172
+
173
+ assert_html '<div a="The letter a" b="The letter b" class="myclass" id="myid">This is my title</div>', source
174
+ end
175
+
176
+ def test_splat_with_class_merging
177
+ source = %q{
178
+ #myid.myclass *{:class => [:secondclass, %w(x y z)]} *hash This is my title
179
+ }
180
+
181
+ 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
182
+ end
183
+
184
+ def test_splat_with_boolean_attribute
185
+ source = %q{
186
+ *{:disabled => true, :empty1 => false, :nonempty => '', :empty2 => nil} This is my title
187
+ }
188
+
189
+ assert_html '<div disabled="disabled" nonempty="">This is my title</div>', source
190
+ end
191
+
192
+ def test_splat_merging_with_arrays
193
+ source = %q{
194
+ *{:a => 1, :b => 2} *[[:c, 3], [:d, 4]] *[[:e, 5], [:f, 6]] This is my title
195
+ }
196
+
197
+ assert_html '<div a="1" b="2" c="3" d="4" e="5" f="6">This is my title</div>', source
198
+ end
199
+
200
+ def test_splat_with_other_attributes
201
+ source = %q{
202
+ h1 data-id="123" *hash This is my title
203
+ }
204
+
205
+ assert_html '<h1 a="The letter a" b="The letter b" data-id="123">This is my title</h1>', source
206
+ end
207
+
208
+ def test_attribute_merging
209
+ source = %q{
210
+ a class=true class=false
211
+ a class=false *{:class=>true}
212
+ a class=true
213
+ a class=false
214
+ }
215
+
216
+ assert_html '<a class="true false"></a><a class="false true"></a><a class="class"></a><a></a>', source
217
+ end
218
+ end