defmodule Fermo.MiddlemanImporter do @args_options [source: :string, destination: :string] def run(args) do {source, destination} = parse_args(args) ensure_directory(destination) sources = sources(source) |> to_relative(source) Enum.each(sources, &(import_slim(&1, source, destination))) end defp parse_args(args) do {opts, arguments, invalid} = OptionParser.parse(args, strict: @args_options) if arguments != [] do raise "Unexpected arguments found: #{inspect(arguments)}" end if invalid != [] do raise "Invalid options found: #{inspect(invalid)}" end source = opts[:source] destination = opts[:destination] if !File.dir?(source) do raise "Source directory '#{source}' does not exist" end {source, destination} end defp sources(source) do Path.wildcard(source <> "/**/*.slim") end defp to_relative(sources, source) do Enum.map(sources, &(Path.relative_to(&1, source))) end defp import_slim(pathname, source, destination) do source_pathname = Path.join(source, pathname) raw = File.read!(source_pathname) converted = convert(raw) destination_pathname = Path.join(destination, pathname) destination_directory = Path.dirname(destination_pathname) ensure_directory(destination_directory) File.write!(destination_pathname, converted, [:write]) end defp convert(raw) do raw |> ifs |> eachs |> partial_params |> ts |> counts |> presents end @if_match ~r<(\s*)-\s*if(.*)>x defp ifs(raw) do String.replace(raw, @if_match, "\\1= if\\2 do") end # Match ` - foos.each do |foo|` @each_match ~r< (\s*) -\s* # SLIM code escape ([\w_\.]+) # a Ruby variable .each\s* # each do\s* # do \|([\w_]+)\| # block parameters >x defp eachs(raw) do String.replace(raw, @each_match, "\\1= Enum.map \\2, fn \\3 ->") end # Match `= partial "foo", locals: {bar: "baz"}` @partial_params_match ~r< (\s*) =\s* partial\s+ ['"] ([\w\/\-\ "']+) ['"] ,\s* locals:\s* { ([^}]+) } >x defp partial_params(raw) do String.replace(raw, @partial_params_match, ~s<\\1= partial "\\2", %{\\3}>) end # Match `t("teh.label")` @translation_match ~r< \bt # t \( # ( ['"] # ' or " ([\w_\.\-]+) # localized string identifier ['"] # ' or " \) # ) >x defp ts(raw) do String.replace(raw, @translation_match, ~s) end # Match `foos.count` @count_match ~r< \b([\w_\.]+) # a Ruby variable \.count # `.count` >x defp counts(raw) do String.replace(raw, @count_match, ~s) end # Match `foo.present?` @present_match ~r< \b([\w_\.]+) # a Ruby variable \.present\? # `.present?` >x defp presents(raw) do String.replace(raw, @present_match, ~s<\\1>) end defp ensure_directory(path) do if !File.dir?(path) do File.mkdir_p!(path) end end end