Skip to content

Commit

Permalink
use "load" not "template_from_file" or "render_from_file" (#118)
Browse files Browse the repository at this point in the history
* use "load" not "template_from_file" or "render_from_file"

* dont deprecate; reorganize code
  • Loading branch information
jverzani authored Aug 27, 2020
1 parent 474e41c commit 07d4d44
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 111 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Mustache"
uuid = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70"
version = "1.0.4"
version = "1.0.5"

[deps]
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Expand Down
16 changes: 6 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,14 @@ The `render` function pieces things together. Like `print`, the first
argument is for an optional `IO` instance. In the above example, where
one is not provided, a string is returned.

The flow is a template is parsed into tokens by `Mustache.parse`. This can be called directly, indirectly through the non-standard string literal `mt`, or when loading a file with `Mustache.load`. The templates use tags comprised of matching mustaches (`{}`), either two or three, to
indicate a value to be substituted for. These tags may be adjusted when `parse` is called.
The `render` function takes tokens as its second argument. If this argument is a string, `parse` is called internally. The `render` function than reassambles the template, substituting values, as appropriate, from the "view" passed to it and writes the output to the specified `io` argument.

The second argument is a either a string or a mustache template. As
seen, templates can be made through the `mt` non-standard string
literal. The advantage of using `mt` is that the template will be
processed at compile time so its reuse will be faster.

The templates use tags comprised of matching mustaches (`{}`), either two or three, to
indicate a value to be substituted for.

The third argument is for a view to provide values to substitute into
the template. The above example used a dictionary. A Module may also
be used, such as `Main`:
The view used to provide values to substitute into the template can be
specified in a variety of ways. The above example used a dictionary. A
Module may also be used, such as `Main`:


```julia
Expand Down
94 changes: 1 addition & 93 deletions src/Mustache.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,101 +12,9 @@ include("tokens.jl")
include("context.jl")
include("writer.jl")
include("parse.jl")
include("render.jl")

export @mt_str, @mt_mstr, render, render_from_file



"""
mt"string"
Macro to parse tokens from a string. Useful when template is to be reused.
"""
macro mt_str(s)
parse(s)
end

macro mt_mstr(s)
parse(s)
end

"""
render([io], tokens, view)
Render a set of tokens with a view, using optional `io` object to print or store.
Arguments
---------
* `io::IO`: Optional `IO` object.
* `tokens`: Either Mustache tokens, or a string to parse into tokens
* `view`: A view provides a context to look up unresolved symbols
demarcated by mustache braces. A view may be specified by a
dictionary, a module, a composite type, a vector, a named tuple, a
data frame, a `Tables` object, or keyword arguments.
"""
function render(io::IO, tokens::MustacheTokens, view)
_writer = Writer()
render(io, _writer, tokens, view)
end
function render(io::IO, tokens::MustacheTokens; kwargs...)
render(io, tokens, kwargs)
end

render(tokens::MustacheTokens, view) = sprint(io -> render(io, tokens, view))
render(tokens::MustacheTokens; kwargs...) = sprint(io -> render(io, tokens, Dict(kwargs...)))

## Exported call without first parsing tokens via mt"literal"
##
## @param template a string containing the template for expansion
## @param view a Dict, Module, CompositeType, DataFrame holding variables for expansion
function render(io::IO, template::AbstractString, view; tags= ("{{", "}}"))
_writer = Writer()
render(io, _writer, parse(template, tags), view)
end
function render(io::IO, template::AbstractString; kwargs...)
_writer = Writer()
render(io, _writer, parse(template), Dict(kwargs...))
end
render(template::AbstractString, view; tags=("{{", "}}")) = sprint(io -> render(io, template, view, tags=tags))
render(template::AbstractString; kwargs...) = sprint(io -> render(io, template, Dict(kwargs...)))

## Dict for storing parsed templates
TEMPLATES = Dict{AbstractString, MustacheTokens}()

## Load template from file
function template_from_file(filepath)
f = open(x -> read(x, String), filepath)
tpl = parse(f)
return tpl
end

"""
Renders a template from `filepath` and `view`. If it has seen the file
before then it finds the compiled `MustacheTokens` in `TEMPLATES` rather
than calling `parse` a second time.
"""
function render_from_file(filepath, view)
if haskey(TEMPLATES, filepath)
render(TEMPLATES[filepath], view)
else
try
tpl = template_from_file(filepath)
TEMPLATES[filepath] = tpl
render(tpl, view)
catch
nothing
end
end
end
function render_from_file(filepath::AbstractString; kwargs...)
render_from_file(filepath, kwargs)
end

end
49 changes: 49 additions & 0 deletions src/parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,52 @@ function parse(template, tags = ("{{", "}}"))
out = nestTokens(tokens)
MustacheTokens(out)
end


"""
mt"string"
Macro to parse tokens from a string.
"""
macro mt_str(s)
parse(s)
end

macro mt_mstr(s)
parse(s)
end

## Dict for storing parsed templates
TEMPLATES = Dict{AbstractString, MustacheTokens}()


"""
Mustache.load(filepath, args...)
Load file specified through `filepath` and return the compiled tokens.
Tokens are memoized for efficiency,
Additional arguments are passed to `Mustache.parse` (for adjusting the tags).
"""
function load(filepath, args...)

isfile(filepath) || throw(ArgumentError("File $filepath not found"))

key = string(mtime(filepath)) * filepath * string(hash(args))
haskey(TEMPLATES,key) && return TEMPLATES[key]

open(filepath) do s
global tpl = parse(read(s, String), args...)
end

TEMPLATES[key] = tpl
tpl

end


# old names. To be deprecated?
const template_from_file = load


54 changes: 54 additions & 0 deletions src/render.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
render([io], tokens, view)
Render a set of tokens with a view, using optional `io` object to print or store.
Arguments
---------
* `io::IO`: Optional `IO` object.
* `tokens`: Either Mustache tokens, or a string to parse into tokens
* `view`: A view provides a context to look up unresolved symbols
demarcated by mustache braces. A view may be specified by a
dictionary, a module, a composite type, a vector, a named tuple, a
data frame, a `Tables` object, or keyword arguments.
"""
function render(io::IO, tokens::MustacheTokens, view)
_writer = Writer()
render(io, _writer, tokens, view)
end
function render(io::IO, tokens::MustacheTokens; kwargs...)
render(io, tokens, kwargs)
end

render(tokens::MustacheTokens, view) = sprint(io -> render(io, tokens, view))
render(tokens::MustacheTokens; kwargs...) = sprint(io -> render(io, tokens, Dict(kwargs...)))

## Exported call without first parsing tokens via mt"literal"
##
## @param template a string containing the template for expansion
## @param view a Dict, Module, CompositeType, DataFrame holding variables for expansion
function render(io::IO, template::AbstractString, view; tags= ("{{", "}}"))
_writer = Writer()
render(io, _writer, parse(template, tags), view)
end
function render(io::IO, template::AbstractString; kwargs...)
_writer = Writer()
render(io, _writer, parse(template), Dict(kwargs...))
end
render(template::AbstractString, view; tags=("{{", "}}")) = sprint(io -> render(io, template, view, tags=tags))
render(template::AbstractString; kwargs...) = sprint(io -> render(io, template, Dict(kwargs...)))


# Exported, but should be deprecated....
"""
render_from_file(filepath, view)
render_from_file(filepath; kwargs...)
Renders a template from `filepath` and `view`.
"""
render_from_file(filepath, view) = render(Mustache.load(filepath), view)
render_from_file(filepath::AbstractString; kwargs...) = render(Mustache.load(filepath); kwargs...)
17 changes: 10 additions & 7 deletions test/Mustache_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,21 @@ rt = [nt, nt, nt] # Tables.istable(rt) == true
expected = "eh and bee"^3
@test Mustache.render(tpl, NT=rt) == expected

## test render_from_file
## test load
filepath = joinpath(@__DIR__, "test.tpl")
expected = "Testing 1, 2, 3..."
@test render_from_file(joinpath(@__DIR__, "test.tpl"), (one="1", two="2", three="3")) == expected
@test render_from_file(joinpath(@__DIR__, "test.tpl"), one="1", two="2", three="3") == expected
@test render(Mustache.load(filepath), (one="1", two="2", three="3")) == expected
@test render(Mustache.load(filepath), one="1", two="2", three="3") == expected

filepath = joinpath(@__DIR__, "test-sections-lf.tpl")
@test Mustache.render_from_file(filepath, Dict("a"=>Dict("x"=>111,),)) == """ 111\n"""
@test Mustache.render_from_file(filepath, Dict("y"=>222,)) == " 222\n"
tokens = Mustache.load(filepath)
@test Mustache.render(tokens, Dict("a"=>Dict("x"=>111,),)) == """ 111\n"""
@test Mustache.render(tokens, Dict("y"=>222,)) == " 222\n"

filepath = joinpath(@__DIR__, "test-sections-crlf.tpl")
@test Mustache.render_from_file(filepath, Dict("a"=>Dict("x"=>111,),)) == " 111\r\n"
@test Mustache.render_from_file(filepath, Dict("y"=>222,)) == " 222\r\n"
tokens = Mustache.load(filepath)
@test Mustache.render(tokens, Dict("a"=>Dict("x"=>111,),)) == " 111\r\n"
@test Mustache.render(tokens, Dict("y"=>222,)) == " 222\r\n"

@testset "closed issues" begin

Expand Down

2 comments on commit 07d4d44

@jverzani
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/20384

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v1.0.5 -m "<description of version>" 07d4d4405616b9ef3ade5ce70bcd28f04801382b
git push origin v1.0.5

Please sign in to comment.