module ECR
  # Defines a `to_s(io)` method whose body is the ECR contained
  # in *filename*, translated to Crystal code.
  #
  # ```text
  # # greeting.ecr
  # Hello <%= @name %>!
  # ```
  #
  # ```
  # require "ecr/macros"
  #
  # class Greeting
  #   def initialize(@name : String)
  #   end
  #
  #   ECR.def_to_s "greeting.ecr"
  # end
  #
  # Greeting.new("World").to_s # => "Hello World!"
  # ```
  #
  # The macro basically translates the text inside the given file
  # to Crystal code that appends to the IO:
  #
  # ```
  # class Greeting
  #   def to_s(io)
  #     io << "Hello "
  #     io << @name
  #     io << '!'
  #   end
  # end
  # ```
  macro def_to_s(filename)
    def to_s(__io__ : IO) : Nil
      ::ECR.embed {{filename}}, "__io__"
    end
  end

  # Embeds an ECR file *filename* into the program and appends the content to
  # an IO in the variable *io_name*.
  #
  # The generated code is the result of translating the contents of
  # the ECR file to Crystal, a program that appends to an IO.
  #
  # ```text
  # # greeting.ecr
  # Hello <%= name %>!
  # ```
  #
  # ```
  # require "ecr/macros"
  #
  # name = "World"
  #
  # io = IO::Memory.new
  # ECR.embed "greeting.ecr", io
  # io.to_s # => "Hello World!"
  # ```
  #
  # The `ECR.embed` line basically generates this Crystal code:
  #
  # ```
  # io << "Hello "
  # io << name
  # io << '!'
  # ```
  macro embed(filename, io_name)
    \{{ run("ecr/process", {{filename}}, {{io_name.id.stringify}}) }}
  end

  # Embeds an ECR file *filename* into the program and renders it to a string.
  #
  # The generated code is the result of translating the contents of
  # the ECR file to Crystal, a program that appends to an IO and returns a string.
  #
  # ```text
  # # greeting.ecr
  # Hello <%= name %>!
  # ```
  #
  # ```
  # require "ecr/macros"
  #
  # name = "World"
  #
  # rendered = ECR.render "greeting.ecr"
  # rendered # => "Hello World!"
  # ```
  #
  # The `ECR.render` basically generates this Crystal code:
  #
  # ```
  # String.build do |io|
  #   io << "Hello "
  #   io << name
  #   io << '!'
  # end
  # ```
  macro render(filename)
    ::String.build do |%io|
      ::ECR.embed({{filename}}, %io)
    end
  end
end
