module Slim # Handle logic-less mode # This filter can be activated with the option "sections" # @api private class Sections < Filter set_default_options :dictionary => 'self', :sections => false, :dictionary_access => :wrapped # :symbol, :string, :wrapped def initialize(opts = {}) super unless [:string, :symbol, :wrapped].include?(options[:dictionary_access]) raise "Invalid dictionary access #{options[:dictionary_access].inspect}" end end def call(exp) if options[:sections] # Store the dictionary in the _slimdict variable dictionary = options[:dictionary] dictionary = "Slim::Wrapper.new(#{dictionary})" if options[:dictionary_access] == :wrapped [:multi, [:code, "_slimdict = #{dictionary}"], super] else exp end end # Interpret control blocks as sections or inverted sections def on_slim_control(name, content) if name =~ /\A!\s*(.*)/ on_slim_inverted_section($1, content) else on_slim_section(name, content) end end def on_slim_output(escape, name, content) raise 'Output statements with content are forbidden in sections mode' if !empty_exp?(content) [:slim, :output, escape, access(name), content] end def on_slim_attr(name, escape, value) [:slim, :attr, name, escape, access(value)] end def on_slim_splat(code) [:slim, :splat, access(code)] end def on_dynamic(code) raise 'Embedded code is forbidden in sections mode' end def on_code(code) raise 'Embedded code is forbidden in sections mode' end protected def on_slim_inverted_section(name, content) tmp = unique_name [:multi, [:code, "#{tmp} = #{access name}"], [:if, "!#{tmp} || #{tmp}.respond_to?(:empty) && #{tmp}.empty?", compile(content)]] end def on_slim_section(name, content) content = compile(content) tmp1, tmp2 = unique_name, unique_name [:if, "#{tmp1} = #{access name}", [:if, "#{tmp1} == true", content, [:multi, # Wrap map in array because maps implement each [:code, "#{tmp1} = [#{tmp1}] if #{tmp1}.respond_to?(:has_key?) || !#{tmp1}.respond_to?(:map)"], [:code, "#{tmp2} = _slimdict"], [:block, "#{tmp1}.each do |_slimdict|", content], [:code, "_slimdict = #{tmp2}"]]]] end private def access(name) return name if name == 'yield' case options[:dictionary_access] when :string "_slimdict[#{name.to_s.inspect}]" else "_slimdict[#{name.to_sym.inspect}]" end end end end