Packages
mazurka
0.1.2
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.3.39
0.3.38
0.3.37
0.3.36
0.3.35
0.3.34
0.3.33
0.3.32
0.3.31
0.3.30
0.3.29
0.3.28
0.3.27
0.3.26
0.3.25
0.3.24
0.3.23
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
hypermedia api toolkit
Current section
Files
Jump to
Current section
Files
lib/mazurka/compiler/resource.ex
defmodule Mazurka.Compiler.Resource do
alias Mazurka.Compiler.Utils
def compile(ast, src, _opts \\ []) do
## TODO set default sections if they don't exist
mod = ast[:name]
{sections, mediatypes} = Enum.reduce(ast[:children], {%{}, []}, &(gather_sections(mod, &1, src, &2)))
quoted = Enum.map(sections, &compile_section/1)
out = quote do
defmodule unquote(mod) do
@file unquote(src)
@moduledoc unquote(ast[:docs])
unquote_splicing(quoted)
end
end
[{mod, Utils.quoted_to_beam(out, src), :main} | mediatypes]
end
defp compile_section({name, section}) do
exec = "#{name}_exec" |> String.to_atom
{quoted, _} = Enum.map_reduce(section, true, &(compile_mediatype(exec, &1, &2)))
quote do
@doc unquote(compile_docs(name, section))
def unquote(name)(context, resolve, accepts \\ [])
def unquote(name)(context, resolve, []) do
unquote(exec)("*", "*", %{}, context, resolve)
end
def unquote(name)(context, resolve, [{_, {type, subtype, params}} | accepts]) do
case unquote(exec)(type, subtype, params, context, resolve) do
{:error, :unacceptable} ->
unquote(name)(context, resolve, accepts)
res ->
res
end
end
def unquote(name)(context, resolve, [{type, subtype, params} | accepts]) do
case unquote(exec)(type, subtype, params, context, resolve) do
{:error, :unacceptable} ->
unquote(name)(context, resolve, accepts)
res ->
res
end
end
defp unquote(exec)(type, subtype, params, context, resolve)
unquote_splicing(quoted)
defp unquote(exec)(_, _, _, _, _) do
{:error, :unacceptable}
end
end
end
defp compile_mediatype(exec, {{type, subtype, _params}, conf}, is_first) do
exec_module = Keyword.get(conf, :module)
serialize_module = Keyword.get(conf, :serialize)
## TODO append params
mediatype = "#{type}/#{subtype}"
{quote do
defp unquote(exec)(unquote(type), unquote(subtype), _params, context, resolve) do
case unquote(exec_module).exec(context, resolve) do
{out, context} ->
{:ok, unquote(serialize_module).serialize(out), context, unquote(mediatype)}
## TODO check if there is an error handler for this resource and render that
error ->
error
end
end
unquote(if is_first do
quote do
defp unquote(exec)(unquote(type), "*", _params, context, resolve) do
case unquote(exec_module).exec(context, resolve) do
{out, context} ->
{:ok, unquote(serialize_module).serialize(out), context, unquote(mediatype)}
## TODO check if there is an error handler for this resource and render that
error ->
error
end
end
defp unquote(exec)("*", "*", _params, context, resolve) do
case unquote(exec_module).exec(context, resolve) do
{out, context} ->
{:ok, unquote(serialize_module).serialize(out), context, unquote(mediatype)}
## TODO check if there is an error handler for this resource and render that
error ->
error
end
end
end
end)
end, false}
end
def gather_sections(mod, mediatype, src, acc) do
types = mediatype[:types]
parsed_types = Enum.map(types, &parse_type/1)
mediatype[:children]
|> Enum.reduce(acc, &(gather_section(&1, mod, src, types, parsed_types, &2)))
end
def gather_section(section, mod, src, types, parsed_types, {confs, mediatypes}) do
name = section[:name]
parser = section[:parser] && [section[:parser]] || []
parsers = parser ++ types
line = Dict.get(section, :line, 1)
{:ok, ast, serialize_module} = Mazurka.Mediatype.parse(line, src, section[:code], parsers)
[chosen | _] = parsers
## TODO replace unsafe characters here
exec_module = "#{mod}_#{chosen}_#{name}" |> String.to_atom
conf = [module: exec_module,
serialize: serialize_module,
docs: section[:docs]]
confs = Enum.reduce(parsed_types, confs, fn(type, acc) ->
section = Dict.get(acc, name, []) ++ [{type, conf}]
Dict.put(acc, name, section)
end)
{confs, [{exec_module, lazy_compile(exec_module, ast, src), "#{chosen} #{name}"} | mediatypes]}
end
def lazy_compile(exec_module, ast, src) do
fn(opts) ->
case Etude.compile(exec_module, ast, [file: src, function: :exec] ++ opts) do
{:ok, _, _, beam} ->
{exec_module, beam}
error ->
error
end
end
end
def compile_docs(name, section) do
type_docs = section
|> Enum.map(fn({type, section}) ->
"""
### #{format_type(type)}
* [IANA](http://www.iana.org/assignments/media-types/#{format_type(type, false)})
#{section[:docs]}
"""
end)
|> Enum.join("\n")
"""
#{name} handler
## Provided Media Types
#{type_docs}
"""
end
defp parse_type(type) do
{:ok, [out]} = :mimetype_parser.parse(type)
out
end
defp format_type(type_tuple, include_params \\ true)
defp format_type({type, subtype, params}, include_params) when params == %{} or not include_params do
"#{type}/#{subtype}"
end
defp format_type({type, subtype, params}, _) do
p = params
|> Enum.map(fn({key, value}) ->
"#{key}=#{value}"
end)
|> Enum.join(", ")
"#{type}/#{subtype};#{p}"
end
end