Current section
Files
Jump to
Current section
Files
lib/mix/tasks/dialup.new.ex
defmodule Mix.Tasks.Dialup.New do
@moduledoc """
Creates a new Dialup project.
It expects the path of the project as an argument.
mix dialup.new PATH [--app APP_NAME] [--module MODULE_NAME]
A project at the given PATH will be created with:
* lib/APP_NAME.ex - Application entry point
* lib/root.html.heex - HTML shell (customize <head>, hooks, analytics)
* lib/app/layout.ex / layout.css - Root layout
* lib/app/page.ex / page.css - Home page at /
* lib/app/error.ex / error.css - Error page (404, 500)
* priv/static/ - Static assets directory (images, fonts, favicon)
* mix.exs - Mix project configuration
* README.md - Project documentation
* .gitignore - Git ignore patterns
## Options
* `--app APP_NAME` - The OTP application name (defaults to PATH basename)
* `--module MODULE_NAME` - The base module name (defaults to camelized PATH)
## Examples
mix dialup.new hello_world
mix dialup.new my_app --app my_custom_app
mix dialup.new my_app --module MyCustomModule
## Installation
Install this generator globally via:
mix archive.install hex dialup_new
"""
use Mix.Task
@dialup_version "0.1"
@switches [
app: :string,
module: :string
]
@impl Mix.Task
def run(args) do
case OptionParser.parse!(args, strict: @switches) do
{opts, [path]} ->
generate(path, opts)
{_opts, []} ->
Mix.raise("""
mix dialup.new expects a path to be given.
Examples:
mix dialup.new hello_world
mix dialup.new my_app --app my_custom_app
""")
{_opts, _} ->
Mix.raise("""
mix dialup.new expects a single path argument.
If you want to pass multiple arguments, use --app or --module options.
""")
end
end
defp generate(path, opts) do
target_dir = Path.expand(path)
if File.exists?(target_dir) and not Enum.empty?(File.ls!(target_dir)) do
Mix.raise("""
The target directory "#{target_dir}" already exists and is not empty.
Please choose a different path or delete the existing directory first.
""")
end
app =
opts[:app] ||
Path.basename(target_dir)
|> String.downcase()
|> String.replace(~r/[^a-z0-9_]/, "_")
mod = opts[:module] || Macro.camelize(app)
bindings = [
app: app,
mod: mod,
dialup_version: @dialup_version
]
File.mkdir_p!(target_dir)
for {template_name, dest_path} <- template_mappings(app) do
source = template_path(template_name)
dest = Path.join(target_dir, dest_path)
content = EEx.eval_file(source, bindings, trim: true)
File.mkdir_p!(Path.dirname(dest))
File.write!(dest, content)
end
# priv/static/ ディレクトリを生成
static_dir = Path.join(target_dir, "priv/static")
File.mkdir_p!(static_dir)
File.write!(Path.join(static_dir, ".gitkeep"), "")
# Run mix format to fix indentation warnings
Mix.shell().info("Formatting files...")
System.cmd("mix", ["format"], cd: target_dir, stderr_to_stdout: true)
Mix.shell().info("""
Your Dialup project was created successfully.
To get started:
cd #{path}
mix deps.get
mix run --no-halt
Then visit http://localhost:4000
""")
end
defp template_path(name) do
priv_dir =
case :code.priv_dir(:dialup_new) do
{:error, :bad_name} ->
__ENV__.file
|> Path.dirname()
|> Path.join("../../../priv")
|> Path.expand()
dir ->
List.to_string(dir)
end
Path.join(priv_dir, "templates/dialup.new/#{name}.eex")
end
defp template_mappings(app) do
app_string = to_string(app)
[
{"mix.exs", "mix.exs"},
{"README.md", "README.md"},
{"gitignore", ".gitignore"},
{"formatter.exs", ".formatter.exs"},
{"app.ex", "lib/#{app_string}.ex"},
{"root.html.heex", "lib/root.html.heex"},
{"layout.ex", "lib/app/layout.ex"},
{"layout.css", "lib/app/layout.css"},
{"page.ex", "lib/app/page.ex"},
{"page.css", "lib/app/page.css"},
{"error.ex", "lib/app/error.ex"},
{"error.css", "lib/app/error.css"}
]
end
end