lib/temple/filters/dynamic_inliner.rb



module Temple
  module Filters
    # Inlines several static/dynamic into a single dynamic.
    class DynamicInliner < Filter
      def on_multi(*exps)
        res = [:multi]
        curr = nil
        prev = []
        state = :looking

        # We add a noop because we need to do some cleanup at the end too.
        (exps + [:noop]).each do |exp|
          head, arg = exp

          case head
          when :newline
            case state
            when :looking
              # We haven't found any static/dynamic, so let's just add it
              res << exp
            when :single, :several
              # We've found something, so let's make sure the generated
              # dynamic contains a newline by escaping a newline and
              # starting a new string:
              #
              # "Hello "\
              # "#{@world}"
              prev << exp
              curr[1] << "\"\\\n\""
            end
          when :dynamic, :static
            case state
            when :looking
              # Found a single static/dynamic.  We don't want to turn this
              # into a dynamic yet.  Instead we store it, and if we find
              # another one, we add both then.
              state = :single
              prev = [exp]
              curr = [:dynamic, '"' + send(head, arg)]
            when :single
              # Yes! We found another one.  Append the content to the current
              # dynamic and add it to the result.
              curr[1] << send(head, arg)
              res << curr
              state = :several
            when :several
              # Yet another dynamic/single.  Just add it now.
              curr[1] << send(head, arg)
            end
          else
            # We need to add the closing quote.
            curr[1] << '"' unless state == :looking
            # If we found a single exp last time, let's add it.
            res.concat(prev) if state == :single
            # Compile the current exp (unless it's the noop)
            res << compile(exp) unless head == :noop
            # Now we're looking for more!
            state = :looking
          end
        end

        res
      end

      def static(str)
        str.inspect[1..-2]
      end

      def dynamic(str)
        '#{%s}' % str
      end
    end
  end
end