# frozen_string_literal: true

# = Yajl
#
# Yajl Template implementation
#
# Yajl is a fast JSON parsing and encoding library for Ruby
#
# The template source is evaluated as a Ruby string,
# and the result is converted #to_json.
#
# === Example
#
#    # This is a template example.
#    # The template can contain any Ruby statement.
#    tpl <<-EOS
#      @counter = 0
#
#      # The json variable represents the buffer
#      # and holds the data to be serialized into json.
#      # It defaults to an empty hash, but you can override it at any time.
#      json = {
#        :"user#{@counter += 1}" => { :name => "Joshua Peek", :id => @counter },
#        :"user#{@counter += 1}" => { :name => "Ryan Tomayko", :id => @counter },
#        :"user#{@counter += 1}" => { :name => "Simone Carletti", :id => @counter },
#      }
#
#      # Since the json variable is a Hash,
#      # you can use conditional statements or any other Ruby statement
#      # to populate it.
#      json[:"user#{@counter += 1}"] = { :name => "Unknown" } if 1 == 2
#
#      # The last line doesn't affect the returned value.
#      nil
#    EOS
#
#    template = Tilt::YajlTemplate.new { tpl }
#    template.render(self)
#
# === See also
#
# * https://github.com/brianmario/yajl-ruby
#
# === Related module
#
# * Tilt::YajlTemplate

require_relative 'template'
require 'yajl'

module Tilt
  class YajlTemplate < Template
    self.default_mime_type = 'application/json'

    def evaluate(scope, locals, &block)
      decorate(super)
    end

    def precompiled_preamble(locals)
      return super if locals.include? :json
      "json = {}\n#{super}"
    end

    def precompiled_postamble(locals)
      "Yajl::Encoder.new.encode(json)"
    end

    def precompiled_template(locals)
      @data.to_str
    end

    # Decorates the +json+ input according to given +options+.
    #
    # json    - The json String to decorate.
    # options - The option Hash to customize the behavior.
    #
    # Returns the decorated String.
    def decorate(json)
      callback, variable = @options[:callback], @options[:variable]
      if callback && variable
        "var #{variable} = #{json}; #{callback}(#{variable});"
      elsif variable
        "var #{variable} = #{json};"
      elsif callback
        "#{callback}(#{json});"
      else
        json
      end
    end
  end
end
