Skip to content

Latest commit

 

History

History
153 lines (115 loc) · 4.67 KB

README.md

File metadata and controls

153 lines (115 loc) · 4.67 KB

Solid

Build Status Module Version Hex Docs Total Download License Last Updated

Solid is an implementation in Elixir of the template language Liquid. It uses nimble_parsec to generate the parser.

Basic Usage

iex> template = "My name is {{ user.name }}"
iex> {:ok, template} = Solid.parse(template)
iex> Solid.render!(template, %{ "user" => %{ "name" => "José" } }) |> to_string
"My name is José"

Installation

The package can be installed with:

def deps do
  [{:solid, "~> 0.14"}]
end

Custom tags

To implement a new tag you need to create a new module that implements the Tag behaviour:

defmodule MyCustomTag do
  import NimbleParsec
  @behaviour Solid.Tag

  @impl true
  def spec(_parser) do
    space = Solid.Parser.Literal.whitespace(min: 0)

    ignore(string("{%"))
    |> ignore(space)
    |> ignore(string("my_tag"))
    |> ignore(space)
    |> ignore(string("%}"))
  end

  @impl true
  def render(tag, _context, _options) do
    [text: "my first tag"]
  end
end
  • spec defines how to parse your tag;
  • render defines how to render your tag.

Now we need to add the tag to the parser

defmodule MyParser do
  use Solid.Parser.Base, custom_tags: [MyCustomTag]
end

And finally pass the custom parser as an option:

"{% my_tag %}"
|> Solid.parse!(parser: MyParser)
|> Solid.render()

Custom filters

While calling Solid.render one can pass a module with custom filters:

defmodule MyCustomFilters do
  def add_one(x), do: x + 1
end

"{{ number | add_one }}"
|> Solid.parse!()
|> Solid.render(%{ "number" => 41}, custom_filters: MyCustomFilters)
|> IO.puts()
# 42

Extra options can be passed as last argument to custom filters if an extra argument is accepted:

defmodule MyCustomFilters do
  def asset_url(path, opts) do
    opts[:host] <> path
  end
end

opts = [custom_filters: MyCustomFilters, host: "http://example.com"]

"{{ file_path | asset_url }}"
|> Solid.parse!()
|> Solid.render(%{ "file_path" => "/styles/app.css"}, opts)
|> IO.puts()
# http://example.com/styles/app.css

Strict rendering

Solid.render/3 doesn't raise or return errors unless strict_variables: true or strict_filters: true are passed as options.

If there are any missing variables/filters Solid.render/3 returns {:error, errors, result} where errors is the list of collected errors and result is the rendered template.

Solid.render!/3 raises if strict_variables: true is passed and there are missing variables. Solid.render!/3 raises if strict_filters: true is passed and there are missing filters.

Contributing

When adding new functionality or fixing bugs consider adding a new test case here inside test/cases. These cases are tested against the Ruby gem so we can try to stay as close as possible to the original implementation.

TODO

  • Integration tests using Liquid gem to build fixtures; #3
  • All the standard filters #8
  • Support to custom filters #11
  • Tags (if, case, unless, etc)
    • for
      • else
      • break
      • continue
      • limit
      • offset
      • Range (3..5)
      • reversed
      • forloop object
    • raw #18
    • cycle #17
    • capture #19
    • increment #16
    • decrement #16
  • Boolean operators #2
  • Whitespace control #10

Copyright and License

Copyright (c) 2016-2022 Eduardo Gurgel Pinho

This work is free. You can redistribute it and/or modify it under the terms of the MIT License. See the LICENSE.md file for more details.