tobi / liquid

Liquid markup language. Save, customer facing template language for flexible web apps.

This URL has Read+Write access

liquid / lib / liquid / block.rb
100644 102 lines (85 sloc) 2.707 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
module Liquid
 
  class Block < Tag
    IsTag = /^#{TagStart}/
    IsVariable = /^#{VariableStart}/
    FullToken = /^#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}$/
    ContentOfVariable = /^#{VariableStart}(.*)#{VariableEnd}$/
 
    def parse(tokens)
      @nodelist ||= []
      @nodelist.clear
 
      while token = tokens.shift
 
        case token
        when IsTag
          if token =~ FullToken
 
            # if we found the proper block delimitor just end parsing here and let the outer block
            # proceed
            if block_delimiter == $1
              end_tag
              return
            end
 
            # fetch the tag from registered blocks
            if tag = Template.tags[$1]
              @nodelist << tag.new($1, $2, tokens)
            else
              # this tag is not registered with the system
              # pass it to the current block for special handling or error reporting
              unknown_tag($1, $2, tokens)
            end
          else
            raise SyntaxError, "Tag '#{token}' was not properly terminated with regexp: #{TagEnd.inspect} "
          end
        when IsVariable
          @nodelist << create_variable(token)
        when ''
          # pass
        else
          @nodelist << token
        end
      end
 
      # Make sure that its ok to end parsing in the current block.
      # Effectively this method will throw and exception unless the current block is
      # of type Document
      assert_missing_delimitation!
    end
 
    def end_tag
    end
 
    def unknown_tag(tag, params, tokens)
      case tag
      when 'else'
        raise SyntaxError, "#{block_name} tag does not expect else tag"
      when 'end'
        raise SyntaxError, "'end' is not a valid delimiter for #{block_name} tags. use #{block_delimiter}"
      else
        raise SyntaxError, "Unknown tag '#{tag}'"
      end
    end
 
    def block_delimiter
      "end#{block_name}"
    end
 
    def block_name
      @tag_name
    end
 
    def create_variable(token)
      token.scan(ContentOfVariable) do |content|
        return Variable.new(content.first)
      end
      raise SyntaxError.new("Variable '#{token}' was not properly terminated with regexp: #{VariableEnd.inspect} ")
    end
 
    def render(context)
      render_all(@nodelist, context)
    end
 
    protected
 
    def assert_missing_delimitation!
      raise SyntaxError.new("#{block_name} tag was never closed")
    end
 
    def render_all(list, context)
      list.collect do |token|
        begin
          token.respond_to?(:render) ? token.render(context) : token
        rescue Exception => e
          context.handle_error(e)
        end
      end
    end
  end
end