slim 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/slim/filter.rb CHANGED
@@ -6,28 +6,25 @@ module Slim
6
6
  # of the expression.
7
7
  #
8
8
  # @api private
9
- class Filter < Temple::Filter
10
- # Dispatch on_slim_*
11
- temple_dispatch :slim
9
+ class Filter < Temple::HTML::Filter
10
+ # Pass-through handler
11
+ def on_slim_embedded(type, content)
12
+ [:slim, :embedded, code, compile(content)]
13
+ end
12
14
 
15
+ # Pass-through handler
13
16
  def on_slim_control(code, content)
14
17
  [:slim, :control, code, compile(content)]
15
18
  end
16
19
 
17
- def on_slim_comment(content)
18
- [:slim, :comment, compile(content)]
20
+ # Pass-through handler
21
+ def on_slim_condcomment(condition, content)
22
+ [:slim, :condcomment, condition, compile(content)]
19
23
  end
20
24
 
25
+ # Pass-through handler
21
26
  def on_slim_output(code, escape, content)
22
27
  [:slim, :output, code, escape, compile(content)]
23
28
  end
24
-
25
- def on_slim_tag(name, attrs, closed, content)
26
- [:slim, :tag, name, compile(attrs), closed, compile(content)]
27
- end
28
-
29
- def on_slim_attrs(*attrs)
30
- [:slim, :attrs, *attrs.map {|k, v| [k, compile(v)] }]
31
- end
32
29
  end
33
30
  end
@@ -0,0 +1,19 @@
1
+ module Slim
2
+ # Slim expression grammar
3
+ # @api private
4
+ module Grammar
5
+ extend Temple::Grammar
6
+
7
+ Expression <<
8
+ [:slim, :control, String, Expression] |
9
+ [:slim, :condcomment, String, Expression] |
10
+ [:slim, :output, Bool, String, Expression] |
11
+ [:slim, :interpolate, String] |
12
+ [:slim, :embedded, String, Expression] |
13
+ [:slim, :directive, Value('doctype'), String]
14
+
15
+ HTMLAttr <<
16
+ [:slim, :attr, String, Bool, String]
17
+
18
+ end
19
+ end
@@ -1,14 +1,14 @@
1
1
  module Slim
2
2
  # Perform interpolation of #{var_name} in the
3
- # expressions `[:slim, :text, string]`.
3
+ # expressions `[:slim, :interpolate, string]`.
4
4
  #
5
5
  # @api private
6
6
  class Interpolation < Filter
7
- # Handle text expression `[:slim, :text, string]`
7
+ # Handle interpolate expression `[:slim, :interpolate, string]`
8
8
  #
9
- # @param [String] string Static text
9
+ # @param [String] string Static interpolate
10
10
  # @return [Array] Compiled temple expression
11
- def on_slim_text(string)
11
+ def on_slim_interpolate(string)
12
12
  # Interpolate variables in text (#{variable}).
13
13
  # Split the text into multiple dynamic and static parts.
14
14
  block = [:multi]
@@ -22,7 +22,7 @@ module Slim
22
22
  # Interpolation
23
23
  string, code = parse_expression($')
24
24
  escape = code !~ /^\{.*\}$/
25
- block << [:slim, :output, escape, escape ? code : code[1..-2], [:multi]]
25
+ block << [:escape, escape, [:dynamic, escape ? code : code[1..-2]]]
26
26
  when /^([^#]+|#)/
27
27
  # Static text
28
28
  block << [:static, $&]
@@ -32,6 +32,8 @@ module Slim
32
32
  block
33
33
  end
34
34
 
35
+ protected
36
+
35
37
  def parse_expression(string)
36
38
  stack, code = [], ''
37
39
 
data/lib/slim/parser.rb CHANGED
@@ -37,7 +37,14 @@ module Slim
37
37
  # @param [String] str Slim code
38
38
  # @return [Array] Temple expression representing the code
39
39
  def call(str)
40
- str.force_encoding(options[:encoding]) if options[:encoding] && str.respond_to?(:force_encoding)
40
+ # Set string encoding if option is set
41
+ if options[:encoding] && str.respond_to?(:encoding)
42
+ old = str.encoding
43
+ str = str.dup if str.frozen?
44
+ str.force_encoding(options[:encoding])
45
+ # Fall back to old encoding if new encoding is invalid
46
+ str.force_encoding(old_enc) unless str.valid_encoding?
47
+ end
41
48
 
42
49
  lineno = 0
43
50
  result = [:multi]
@@ -110,7 +117,7 @@ module Slim
110
117
  # This line happens to be indented deeper (or equal) than the block start character (|, ', /).
111
118
  # This means that it's a part of the block.
112
119
 
113
- if !in_comment
120
+ unless in_comment
114
121
  # The indentation of first line of the text block determines the text base indentation.
115
122
  newline = text_indent ? "\n" : ''
116
123
  text_indent ||= indent
@@ -120,7 +127,7 @@ module Slim
120
127
  syntax_error! 'Unexpected text indentation', line, lineno if offset < 0
121
128
 
122
129
  # Generate the additional spaces in front.
123
- stacks.last << [:slim, :text, newline + (' ' * offset) + line]
130
+ stacks.last << [:slim, :interpolate, newline + (' ' * offset) + line]
124
131
  end
125
132
 
126
133
  stacks.last << [:newline]
@@ -166,29 +173,36 @@ module Slim
166
173
  end
167
174
 
168
175
  case line[0]
169
- when ?|, ?', ?/
170
- # Found a block.
171
- ch = line.slice!(0)
172
-
173
- # We're now expecting the next line to be indented, so we'll need
174
- # to push a block to the stack.
176
+ when ?/
177
+ # Found a comment block.
175
178
  block = [:multi]
176
- stacks.last << if ch == ?'
177
- # Additional whitespace in front
178
- [:multi, block, [:slim, :text, ' ']]
179
- elsif ch == ?/ && line[0] == ?!
179
+ stacks.last << if line =~ %r{^/!( ?)(.*)$}
180
180
  # HTML comment
181
- line.slice!(0)
182
- [:slim, :comment, block]
181
+ block_indent = indent
182
+ text_indent = block_indent + ($1 ? 2 : 1)
183
+ block << [:slim, :interpolate, $2] if $2
184
+ [:html, :comment, block]
185
+ elsif line =~ %r{^/\[\s*(.*?)\s*\]\s*$}
186
+ # HTML conditional comment
187
+ [:slim, :condcomment, $1, block]
183
188
  else
184
- in_comment = ch == ?/
189
+ # Slim comment
190
+ block_indent = indent
191
+ in_comment = true
185
192
  block
186
193
  end
187
194
  stacks << block
195
+ when ?|, ?'
196
+ # Found a text block.
197
+ # We're now expecting the next line to be indented, so we'll need
198
+ # to push a block to the stack.
199
+ block = [:multi]
188
200
  block_indent = indent
189
-
190
- if !in_comment && !line.strip.empty?
191
- block << [:slim, :text, line.sub(/^( )/, '')]
201
+ stacks.last << (line.slice!(0) == ?' ?
202
+ [:multi, block, [:static, ' ']] : block)
203
+ stacks << block
204
+ unless line.strip.empty?
205
+ block << [:slim, :interpolate, line.sub(/^( )/, '')]
192
206
  text_indent = block_indent + ($1 ? 2 : 1)
193
207
  end
194
208
  when ?-
@@ -213,8 +227,8 @@ module Slim
213
227
  else
214
228
  if line =~ /^(\w+):\s*$/
215
229
  # Embedded template detected. It is treated as block.
216
- block = [:slim, :embedded, $1]
217
- stacks.last << [:newline] << block
230
+ block = [:multi]
231
+ stacks.last << [:newline] << [:slim, :embedded, $1, block]
218
232
  stacks << block
219
233
  block_indent = indent
220
234
  next
@@ -276,13 +290,13 @@ module Slim
276
290
  # Now we'll have to find all the attributes. We'll store these in an
277
291
  # nested array: [[name, value], [name2, value2]]. The value is a piece
278
292
  # of Ruby code.
279
- attributes = [:slim, :attrs]
293
+ attributes = [:html, :attrs]
280
294
 
281
295
  # Find any literal class/id attributes
282
296
  while line =~ CLASS_ID_REGEX
283
297
  # The class/id attribute is :static instead of :slim :text,
284
298
  # because we don't want text interpolation in .class or #id shortcut
285
- attributes << [ATTR_SHORTHAND[$1], [:static, $2]]
299
+ attributes << [:html, :attr, ATTR_SHORTHAND[$1], [:static, $2]]
286
300
  line = $'
287
301
  end
288
302
 
@@ -296,21 +310,22 @@ module Slim
296
310
 
297
311
  # Parse attributes
298
312
  while line =~ ATTR_REGEX
299
- key = $1
313
+ name = $1
300
314
  line = $'
301
315
  if line =~ QUOTED_VALUE_REGEX
302
316
  # Value is quoted (static)
303
317
  line = $'
304
- attributes << [key, [:slim, :text, $1[1..-2]]]
318
+ attributes << [:html, :attr, name, [:slim, :interpolate, $1[1..-2]]]
305
319
  else
306
320
  # Value is ruby code
307
- line, value = parse_ruby_attribute(orig_line, line, lineno, delimiter)
308
- attributes << [key, [:slim, :output, true, value, [:multi]]]
321
+ escape = line[0] != ?=
322
+ line, code = parse_ruby_attribute(orig_line, escape ? line : line[1..-1], lineno, delimiter)
323
+ attributes << [:slim, :attr, name, escape, code]
309
324
  end
310
325
  end
311
326
 
312
327
  # Find ending delimiter
313
- if !delimiter.empty?
328
+ unless delimiter.empty?
314
329
  if line =~ /^\s*#{Regexp.escape delimiter}/
315
330
  line = $'
316
331
  else
@@ -319,7 +334,7 @@ module Slim
319
334
  end
320
335
 
321
336
  content = [:multi]
322
- tag = [:slim, :tag, tag, attributes, false, content]
337
+ tag = [:html, :tag, tag, attributes, content]
323
338
 
324
339
  if line =~ /^\s*=(=?)/
325
340
  # Handle output code
@@ -329,14 +344,14 @@ module Slim
329
344
  [tag, block, broken_line, nil]
330
345
  elsif line =~ /^\s*\//
331
346
  # Closed tag
332
- tag[4] = true
347
+ tag.pop
333
348
  [tag, block, nil, nil]
334
349
  elsif line =~ /^\s*$/
335
350
  # Empty line
336
351
  [tag, content, nil, nil]
337
352
  else
338
353
  # Handle text content
339
- content << [:slim, :text, line.sub(/^( )/, '')]
354
+ content << [:slim, :interpolate, line.sub(/^( )/, '')]
340
355
  [tag, content, nil, orig_line.size - line.size + ($1 ? 1 : 0)]
341
356
  end
342
357
  end
@@ -371,7 +386,7 @@ module Slim
371
386
  end
372
387
  end
373
388
 
374
- syntax_error! "Expected closing attribute delimiter #{stack.last}", orig_line, lineno if !stack.empty?
389
+ syntax_error! "Expected closing attribute delimiter #{stack.last}", orig_line, lineno unless stack.empty?
375
390
  syntax_error! 'Invalid empty attribute', orig_line, lineno if value.empty?
376
391
 
377
392
  # Remove attribute wrapper which doesn't belong to the ruby code
@@ -381,7 +396,7 @@ module Slim
381
396
  return line, value
382
397
  end
383
398
 
384
- # A little helper for raising exceptions.
399
+ # Helper for raising exceptions
385
400
  def syntax_error!(message, *args)
386
401
  raise SyntaxError.new(message, options[:file], *args)
387
402
  end
data/lib/slim/sections.rb CHANGED
@@ -20,7 +20,7 @@ module Slim
20
20
  dictionary = options[:dictionary]
21
21
  dictionary = "Slim::Wrapper.new(#{dictionary})" if options[:dictionary_access] == :wrapped
22
22
  [:multi,
23
- [:block, "_slimdict = #{dictionary}"],
23
+ [:code, "_slimdict = #{dictionary}"],
24
24
  super]
25
25
  else
26
26
  exp
@@ -36,38 +36,34 @@ module Slim
36
36
  end
37
37
  end
38
38
 
39
+ def on_slim_output(escape, name, content)
40
+ raise 'Output statements with content are forbidden in sections mode' if !empty_exp?(content)
41
+ [:slim, :output, escape, access(name), content]
42
+ end
43
+
44
+ protected
45
+
39
46
  def on_slim_inverted_section(name, content)
40
- tmp = tmp_var(:section)
47
+ tmp = unique_name
41
48
  [:multi,
42
- [:block, "#{tmp} = #{access name}"],
43
- [:block, "if !#{tmp} || #{tmp}.respond_to?(:empty) && #{tmp}.empty?"],
44
- compile(content),
45
- [:block, 'end']]
49
+ [:code, "#{tmp} = #{access name}"],
50
+ [:if, "!#{tmp} || #{tmp}.respond_to?(:empty) && #{tmp}.empty?",
51
+ compile(content)]]
46
52
  end
47
53
 
48
54
  def on_slim_section(name, content)
49
55
  content = compile(content)
50
- tmp1, tmp2 = tmp_var(:dict), tmp_var(:dict)
56
+ tmp1, tmp2 = unique_name, unique_name
51
57
 
52
- [:multi,
53
- [:block, "if #{tmp1} = #{access name}"],
54
- [:block, "if #{tmp1} == true"],
55
- content,
56
- [:block, 'else'],
57
- # Wrap map in array because maps implement each
58
- [:block, "#{tmp1} = [#{tmp1}] if #{tmp1}.respond_to?(:has_key?) || !#{tmp1}.respond_to?(:map)"],
59
- [:block, "#{tmp2} = _slimdict"],
60
- [:block, "#{tmp1}.each do |_slimdict|"],
61
- content,
62
- [:block, 'end'],
63
- [:block, "_slimdict = #{tmp2}"],
64
- [:block, 'end'],
65
- [:block, 'end']]
66
- end
67
-
68
- def on_slim_output(escape, name, content)
69
- raise 'Output statements with content are forbidden in sections mode' if !empty_exp?(content)
70
- [:slim, :output, escape, access(name), content]
58
+ [:if, "#{tmp1} = #{access name}",
59
+ [:if, "#{tmp1} == true",
60
+ content,
61
+ [:multi,
62
+ # Wrap map in array because maps implement each
63
+ [:code, "#{tmp1} = [#{tmp1}] if #{tmp1}.respond_to?(:has_key?) || !#{tmp1}.respond_to?(:map)"],
64
+ [:code, "#{tmp2} = _slimdict"],
65
+ [:block, "#{tmp1}.each do |_slimdict|", content],
66
+ [:code, "_slimdict = #{tmp2}"]]]]
71
67
  end
72
68
 
73
69
  private
data/lib/slim/template.rb CHANGED
@@ -6,12 +6,12 @@ module Slim
6
6
  if Object.const_defined?(:Rails)
7
7
  # Rails template implementation for Slim
8
8
  # @api public
9
- RailsTemplate = Temple::Templates::Rails(Slim::Engine, :register_as => :slim)
10
-
11
- # Use rails-specific generator. This is necessary
12
- # to support block capturing. Disable the internal slim capturing.
13
- # Rails takes care of the capturing by itself.
14
- RailsTemplate.set_default_options :generator => Temple::Generators::RailsOutputBuffer,
15
- :disable_capture => true
9
+ RailsTemplate = Temple::Templates::Rails(Slim::Engine,
10
+ :register_as => :slim,
11
+ # Use rails-specific generator. This is necessary
12
+ # to support block capturing. Disable the internal slim capturing.
13
+ # Rails takes care of the capturing by itself.
14
+ :generator => Temple::Generators::RailsOutputBuffer,
15
+ :disable_capture => true)
16
16
  end
17
17
  end
data/lib/slim/version.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  module Slim
2
- VERSION = '0.9.2'
2
+ # Slim version string
3
+ # @api public
4
+ VERSION = '0.9.3'
3
5
  end
data/lib/slim/wrapper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  module Slim
2
2
  # For logic-less mode, objects can be encased in the Wrapper class.
3
+ # @api private
3
4
  class Wrapper
4
5
  attr_reader :value, :parent
5
6
 
data/slim.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.dirname(__FILE__) + '/lib/slim/version'
3
+ require 'date'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'slim'
7
+ s.version = Slim::VERSION
8
+ s.date = Date.today.to_s
9
+ s.authors = ['Andrew Stone', 'Fred Wu', 'Daniel Mendler']
10
+ s.email = ['andy@stonean.com', 'ifredwu@gmail.com', 'mail@daniel-mendler.de']
11
+ s.summary = 'Slim is a template language.'
12
+ s.description = 'Slim is a template language whose goal is reduce the syntax to the essential parts without becoming cryptic.'
13
+ s.homepage = 'http://github.com/stonean/slim'
14
+ s.extra_rdoc_files = %w(README.md)
15
+ s.rdoc_options = %w(--charset=UTF-8)
16
+ s.rubyforge_project = s.name
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = %w(lib)
21
+
22
+ s.add_runtime_dependency('temple', ['~> 0.3.0']) unless ENV['SLIM_USE_TEMPLE']
23
+ s.add_runtime_dependency('tilt', ['~> 1.2'])
24
+
25
+ s.add_development_dependency('rake', ['>= 0.8.7'])
26
+ s.add_development_dependency('haml', ['>= 3.1.0'])
27
+ s.add_development_dependency('sass', ['>= 3.1.0'])
28
+ s.add_development_dependency('minitest', ['>= 0'])
29
+ s.add_development_dependency('rcov', ['>= 0'])
30
+ s.add_development_dependency('rdiscount', ['>= 0'])
31
+ s.add_development_dependency('liquid', ['>= 0'])
32
+ s.add_development_dependency('yard', ['>= 0'])
33
+ s.add_development_dependency('creole', ['>= 0'])
34
+ end
data/test/helper.rb CHANGED
@@ -3,13 +3,17 @@
3
3
  require 'rubygems'
4
4
  require 'minitest/unit'
5
5
  require 'slim'
6
+ require 'slim/grammar'
6
7
 
7
8
  MiniTest::Unit.autorun
8
9
 
10
+ Slim::Engine.after Slim::Parser, Temple::Filters::Validator, :grammar => Slim::Grammar
11
+ Slim::Engine.before Slim::Compiler, Temple::Filters::Validator, :grammar => Slim::Grammar
12
+ Slim::Engine.before Temple::HTML::Pretty, Temple::Filters::Validator
13
+
9
14
  class TestSlim < MiniTest::Unit::TestCase
10
15
  def setup
11
16
  @env = Env.new
12
- # Slim::Engine.set_default_options :debug => true
13
17
  end
14
18
 
15
19
  def teardown
@@ -33,7 +33,7 @@ p = HtmlSafeString.new("<strong>Hello World\\n, meet \\"Slim\\"</strong>.")
33
33
  assert_html "<p><strong>Hello World\n, meet \"Slim\"</strong>.</p>", source, :use_html_safe => true
34
34
  end
35
35
 
36
- def test_render_with_auto_escape_true
36
+ def test_render_with_disable_escape_false
37
37
  source = %q{
38
38
  = "<p>Hello</p>"
39
39
  == "<p>World</p>"
@@ -42,12 +42,12 @@ p = HtmlSafeString.new("<strong>Hello World\\n, meet \\"Slim\\"</strong>.")
42
42
  assert_html "&lt;p&gt;Hello&lt;&#47;p&gt;<p>World</p>", source
43
43
  end
44
44
 
45
- def test_render_with_auto_escape_false
45
+ def test_render_with_disable_escape_true
46
46
  source = %q{
47
47
  = "<p>Hello</p>"
48
48
  == "<p>World</p>"
49
49
  }
50
50
 
51
- assert_html "<p>Hello</p><p>World</p>", source, :auto_escape => false
51
+ assert_html "<p>Hello</p><p>World</p>", source, :disable_escape => true
52
52
  end
53
53
  end