class Slim::Compiler

@api private

Public Instance Methods

call(exp) click to toggle source
# File lib/slim/compiler.rb, line 4
def call(exp)
  @attr_delimiter, @splat_used = unique_name, false
  exp = compile(exp)
  if @splat_used
    [:multi, [:code, "#{@attr_delimiter} = #{@options[:attr_delimiter].inspect}"], exp]
  else
    exp
  end
end
on_slim_attr(name, escape, code) click to toggle source

Handle attribute expression `[:slim, :attr, escape, code]`

@param [Boolean] escape Escape html @param [String] code Ruby code @return [Array] Compiled temple expression

# File lib/slim/compiler.rb, line 122
def on_slim_attr(name, escape, code)
  value = case code
  when 'true'
    [:static, name]
  when 'false', 'nil'
    [:multi]
  else
    tmp = unique_name
    [:multi,
     [:code, "#{tmp} = #{code}"],
     [:case, tmp,
      ['true', [:static, name]],
      ['false, nil', [:multi]],
      [:else,
       [:escape, escape, [:dynamic,
        if delimiter = options[:attr_delimiter][name]
          "#{tmp}.respond_to?(:join) ? #{tmp}.flatten.compact.join(#{delimiter.inspect}) : #{tmp}"
        else
          tmp
        end
       ]]]]]
  end
  [:html, :attr, name, value]
end
on_slim_attrs(*attrs) click to toggle source

Handle attributes expression `[:slim, :attrs, *attrs]`

@param [Array] *attrs Array of temple expressions @return [Array] Compiled temple expression

# File lib/slim/compiler.rb, line 108
def on_slim_attrs(*attrs)
  if attrs.any? {|attr| attr[1] == :splat}
    hash, merger, formatter = splat_attributes(attrs)
    [:multi, merger, formatter]
  else
    [:html, :attrs, *attrs.map {|a| compile(a) }]
  end
end
on_slim_condcomment(condition, content) click to toggle source

Handle conditional comment expression `[:slim, :conditional_comment, conditional, content]`

@param [Array] content Temple expression @return [Array] Compiled temple expression

# File lib/slim/compiler.rb, line 30
def on_slim_condcomment(condition, content)
  [:html, :comment,
   [:multi,
    [:static, "[#{condition}]>"],
    compile(content),
    [:static, '<![endif]']]]
end
on_slim_control(code, content) click to toggle source

Handle control expression `[:slim, :control, code, content]`

@param [String] ruby code @param [Array] content Temple expression @return [Array] Compiled temple expression

# File lib/slim/compiler.rb, line 19
def on_slim_control(code, content)
  [:multi,
    [:code, code],
    compile(content)]
end
on_slim_output(escape, code, content) click to toggle source

Handle output expression `[:slim, :output, escape, code, content]`

@param [Boolean] escape Escape html @param [String] code Ruby code @param [Array] content Temple expression @return [Array] Compiled temple expression

# File lib/slim/compiler.rb, line 44
def on_slim_output(escape, code, content)
  if empty_exp?(content)
    [:multi, [:escape, escape, [:dynamic, code]], content]
  else
    tmp = unique_name

    [:multi,
     # Capture the result of the code in a variable. We can't do
     # `[:dynamic, code]` because it's probably not a complete
     # expression (which is a requirement for Temple).
     [:block, "#{tmp} = #{code}",

      # Capture the content of a block in a separate buffer. This means
      # that `yield` will not output the content to the current buffer,
      # but rather return the output.
      #
      # The capturing can be disabled with the option :disable_capture.
      # Output code in the block writes directly to the output buffer then.
      # Rails handles this by replacing the output buffer for helpers.
      options[:disable_capture] ? compile(content) : [:capture, unique_name, compile(content)]],

     # Output the content.
     [:escape, escape, [:dynamic, tmp]]]
  end
end
on_slim_tag(name, attrs, content = nil) click to toggle source

Handle tag expression `[:slim, :tag, name, attrs, content]`

@param [String] name Tag name @param [Array] attrs Temple expression @param [Array] content Temple expression @return [Array] Compiled temple expression

# File lib/slim/compiler.rb, line 76
def on_slim_tag(name, attrs, content = nil)
  if name == '*'
    hash, merger, formatter = splat_attributes(attrs[2..-1])
    tmp = unique_name
    tag = [:multi,
           merger,
           [:code, "#{tmp} = #{hash}.delete('tag').to_s"],
           [:if, "#{tmp}.empty?",
            [:code, "#{tmp} = #{@options[:default_tag].inspect}"]],
           [:static, '<'],
           [:dynamic, "#{tmp}"],
           formatter]
    tag << if content
             [:multi,
              [:static, '>'],
              compile(content),
              [:static, '</'],
              [:dynamic, "#{tmp}"],
              [:static, '>']]
           else
             [:static, '/>']
           end
  else
    tag = [:html, :tag, name, compile(attrs)]
    content ? (tag << compile(content)) : tag
  end
end

Protected Instance Methods

splat_attributes(attrs) click to toggle source
# File lib/slim/compiler.rb, line 149
def splat_attributes(attrs)
  @splat_used = true

  hash, name, value, tmp = unique_name, unique_name, unique_name, unique_name

  merger = [:multi, [:code, "#{hash} = {}"]]
  attrs.each do |attr|
    merger << if attr[0] == :html && attr[1] == :attr
      [:multi,
       [:capture, tmp, compile(attr[3])],
       [:code, "(#{hash}[#{attr[2].inspect}] ||= []) << #{tmp}"]]
    elsif attr[0] == :slim
      if attr[1] == :attr
        [:code, "(#{hash}[#{attr[2].inspect}] ||= []) << (#{attr[4]})"]
      elsif attr[1] == :splat
        [:code, "(#{attr[2]}).each {|#{name},#{value}| (#{hash}[#{name}.to_s] ||= []) << (#{value}) }"]
      else
        attr
      end
    else
      attr
    end
  end

  merger << [:block, "#{hash}.keys.each do |#{name}|",
             [:multi,
              [:code, "#{value} = #{hash}[#{name}]"],
              [:code, "#{value}.flatten!"],
              [:block, "#{value}.map! do |#{tmp}|",
               [:case, tmp,
                ['true', [:code, name]],
                ['false, nil', [:multi]],
                [:else, [:code, tmp]]]],
              [:if, "#{value}.size > 1 && !#{@attr_delimiter}[#{name}]",
               [:code, "raise(\"Multiple #\{#{name}\} attributes specified\")"]],
              [:code, "#{hash}[#{name}] = #{value}.compact.join(#{@attr_delimiter}[#{name}].to_s)"]]]

  attr = [:multi,
          [:static, ' '],
          [:dynamic, name],
          [:static, "=#{options[:attr_wrapper]}"],
          [:escape, true, [:dynamic, value]],
          [:static, options[:attr_wrapper]]]
  attr = [:if, "!#{value}.empty?", attr] if options[:remove_empty_attrs]
  enumerator = options[:sort_attrs] ? "#{hash}.sort_by {|#{name},#{value}| #{name} }" : hash
  formatter = [:block, "#{enumerator}.each do |#{name},#{value}|", attr]

  return hash, merger, formatter
end