M kethel/lib/bricks.ex => kethel/lib/bricks.ex +2 -3
@@ 8,10 8,9 @@ defmodule Bricks do
@typedoc "A valid mustache template"
@type mustache() :: binary()
- @spec collect(relative_path()) :: [ { brick_name(), mustache() } ]
+ @spec collect(relative_path()) :: %{ brick_name() => mustache() }
def collect(folder) do
Path.wildcard(folder <> "/bricks/*.thtml")
- |> Enum.map(fn brick -> { brick, File.read!(brick) } end)
- |> Enum.map(fn { brick, contents } -> { FileX.trimmed_filename(brick), contents } end) # "../bricks/base_header.html" would beccome just "base_header"
+ |> Map.new(fn x -> { FileX.trimmed_filename(x), File.read!(x) } end)
end
end
A kethel/lib/common.ex => kethel/lib/common.ex +3 -0
@@ 0,0 1,3 @@
+defmodule Context do
+ defstruct project_root: "/", bricks: %{}, fxg: "fxg"
+end
D kethel/lib/compilers.ex => kethel/lib/compilers.ex +0 -12
@@ 1,12 0,0 @@
-defmodule Compilers do
- # TODO
- @doc "Creates a random file in /tmp/kethel-TIME/, which functions as a pipe writing the given `data`"
- @spec tempdata(binary()) :: binary()
- defp tempdata(data) do
- end
-
-
- @doc "Invokes the fxg compiler on `data`. provides the output as a binary"
- def fxg(path) do
- end
-end
D kethel/lib/kernelx.ex => kethel/lib/kernelx.ex +0 -8
@@ 1,8 0,0 @@
-defmodule KernelX do
-
- @doc "Returns all bytes from `binary`, excluding those before `from`"
- @spec binary_slice_from(binary(), pos_integer()) :: binary()
- def binary_slice_from(binary, from) do
- binary_part(binary, from, byte_size(binary) - from)
- end
-end
M kethel/lib/pages.ex => kethel/lib/pages.ex +44 -3
@@ 1,8 1,49 @@
+require Rambo
+
defmodule Pages do
+ defstruct [ :source_files, :main_template, :project_root, :bricks ]
+
+ def trim_abs_path(path, context) do
+ begin = byte_size(context.project_root) + byte_size("pages/") # ROOT + pages/
+ binary_part(path, begin, byte_size(path) - begin - byte_size(".fxg")) # remove extension
+ end
+
+ @spec collect(%Context{}) :: %Pages{}
def collect(context) do
pages_root = context.project_root <> "/pages"
- pages = Path.wildcard(pages_root <> "/**/*.fxg")
- |> Enum.map(fn path -> { path, File.read!(path) } end)
- |> Enum.map(fn { path, data } -> { KernelX.binary_slice_from(path, byte_size(pages_root)), data } end)
+ %Pages{
+ project_root: context.project_root,
+ source_files: Path.wildcard(pages_root <> "/**/*.fxg")
+ |> Enum.map(fn path -> { path, File.read!(path) } end)
+ |> Enum.map(fn { path, data } -> { trim_abs_path(path, context), data } end),
+ main_template: File.read!(context.project_root <> "/templates/base.thtml"),
+ bricks: context.bricks,
+ }
+ end
+
+ @spec compile(%Pages{}) :: none()
+ def compile(pages) do
+ Task.async_stream(pages.source_files, fn page -> compile_file(pages, page) end) |> Enum.to_list()
+ end
+
+ defp compile_file(pages, { page_path, page_data }) do
+ output_path = "#{pages.project_root}/build#{page_path}.html"
+ IO.puts("#{pages.project_root}/pages#{page_path}.fxg -> #{output_path}")
+ # check for a custom template
+ custom_template_path = "#{pages.project_root}/templates/pages#{page_path}.thtml"
+ template = case File.read(custom_template_path) do
+ {:ok, custom_template} -> custom_template
+ {:error, :enoent} -> pages.main_template
+ {:error, err } -> raise err
+ end
+ mustache_context = Map.merge(%{fxg_content: invoke_fxg(page_data), location: page_path}, pages.bricks)
+ page_rendered = Mustache.render(template, mustache_context)
+ File.write!(output_path, page_rendered)
+ end
+
+ # TODO: switch this to Rambo
+ defp invoke_fxg(data) do
+ {:ok, res} = Rambo.run("fxg", ["-"], in: data)
+ res.out
end
end
M kethel/main.exs => kethel/main.exs +10 -3
@@ 4,11 4,18 @@ folder = Enum.at(args, 1)
if folder != nil do
project_root = Path.expand(folder)
- context = %{
- project_root: project_root,
- bricks: Bricks.collect(project_root)
+ context = %Context{
+ project_root: project_root,
+ bricks: Bricks.collect(project_root),
+ fxg: System.find_executable("fxg")
}
+
+ File.rm_rf!("#{project_root}/build")
+ File.mkdir_p("#{project_root}/build")
+
pages = Pages.collect(context)
+
+ Pages.compile(pages)
else
IO.puts(:stderr, "The root project folder should be provided on the command line")
end
M kethel/mix.exs => kethel/mix.exs +2 -2
@@ 13,8 13,8 @@ defmodule Kethel.MixProject do
defp deps do
[
- { :tzdata, "~> 1.1" },
- { :mustache, "~> 0.5.0" }
+ { :mustache, "~> 0.5.0" },
+ {:rambo, "~> 0.3.4" },
]
end
end
M kethel/mix.lock => kethel/mix.lock +1 -0
@@ 6,6 6,7 @@
"mimerl": {:hex, :mimerl, "1.4.0", "3882a5ca67fbbe7117ba8947f27643557adec38fa2307490c4c4207624cb213b", [:rebar3], [], "hexpm", "13af15f9f68c65884ecca3a3891d50a7b57d82152792f3e19d88650aa126b144"},
"mustache": {:hex, :mustache, "0.5.1", "1bfee8a68a8e72d47616541a93a632ae1684c1abc17c9eb5f7bfecb78d7496e5", [:mix], [], "hexpm", "524c9bbb6080a52d7b6806436b4e269e0224c785a228faf3293ef30a75016bfa"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
+ "rambo": {:hex, :rambo, "0.3.4", "8962ac3bd1a633ee9d0e8b44373c7913e3ce3d875b4151dcd060886092d2dce7", [:mix], [], "hexpm", "0cc54ed089fbbc84b65f4b8a774224ebfe60e5c80186fafc7910b3e379ad58f1"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"tzdata": {:hex, :tzdata, "1.1.3", "b1cef7bb6de1de90d4ddc25d33892b32830f907e7fc2fccd1e7e22778ab7dfbc", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "d4ca85575a064d29d4e94253ee95912edfb165938743dbf002acdf0dcecb0c28"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"},