Skip to content

Commit 8b0c412

Browse files
author
José Valim
committed
Merge pull request #2618 from patrickgombert/mix-new
Validate app and module on mix new
2 parents b5febd9 + dc4b7c8 commit 8b0c412

File tree

2 files changed

+41
-12
lines changed

2 files changed

+41
-12
lines changed

lib/mix/lib/mix/tasks/new.ex

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ defmodule Mix.Tasks.New do
2323
An `--umbrella` option can be given to generate an
2424
umbrella project.
2525
26+
An `--app` option can be given in order to
27+
name the OTP application for the project.
28+
29+
A `--module` option can be given in order
30+
to name the modules in the generated code skeleton.
31+
2632
## Examples
2733
2834
mix new hello_world
@@ -43,22 +49,23 @@ defmodule Mix.Tasks.New do
4349
[] ->
4450
Mix.raise "Expected PATH to be given, please use `mix new PATH`"
4551
[path|_] ->
46-
name = opts[:app] || Path.basename(Path.expand(path))
47-
check_project_name!(name)
52+
app = opts[:app] || Path.basename(Path.expand(path))
53+
check_application_name!(app, !!opts[:app])
54+
mod = opts[:module] || camelize(app)
55+
check_mod_name!(mod)
4856
File.mkdir_p!(path)
4957

5058
File.cd! path, fn ->
5159
if opts[:umbrella] do
52-
do_generate_umbrella(name, path, opts)
60+
do_generate_umbrella(app, mod, path, opts)
5361
else
54-
do_generate(name, path, opts)
62+
do_generate(app, mod, path, opts)
5563
end
5664
end
5765
end
5866
end
5967

60-
defp do_generate(app, path, opts) do
61-
mod = opts[:module] || camelize(app)
68+
defp do_generate(app, mod, path, opts) do
6269
assigns = [app: app, mod: mod, otp_app: otp_app(mod, !!opts[:sup])]
6370

6471
create_file "README.md", readme_template(assigns)
@@ -105,8 +112,7 @@ defmodule Mix.Tasks.New do
105112
" [applications: [:logger],\n mod: {#{mod}, []}]"
106113
end
107114

108-
defp do_generate_umbrella(app, path, _opts) do
109-
mod = camelize(app)
115+
defp do_generate_umbrella(app, mod, path, _opts) do
110116
assigns = [mod: mod]
111117

112118
create_file ".gitignore", gitignore_text
@@ -135,9 +141,18 @@ defmodule Mix.Tasks.New do
135141
"""
136142
end
137143

138-
defp check_project_name!(name) do
144+
defp check_application_name!(name, from_app_flag) do
139145
unless name =~ ~r/^[a-z][\w_]*$/ do
140-
Mix.raise "Project path must start with a letter and have only lowercase letters, numbers and underscore"
146+
error = "Application name must start with a letter and have only lowercase letters, numbers and underscore"
147+
if !from_app_flag, do: error = error <> ". The application name is inferred from the path, if you'd like to explicitly name the application then use the `--app APP` option."
148+
Mix.raise error
149+
end
150+
end
151+
152+
defp check_mod_name!(name) do
153+
unless name =~ ~r/^[A-Z][A-Za-z0-9]*(\.[A-Z][A-Za-z0-9]*)*$/ do
154+
error = "Module name must start with a capital letter, have all periods immediately followed by a capital letter, and must contain only letters, numbers, and periods"
155+
Mix.raise error
141156
end
142157
end
143158

lib/mix/test/mix/tasks/new_test.exs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,25 @@ defmodule Mix.Tasks.NewTest do
110110
end
111111

112112
test "new with invalid args" do
113-
in_tmp "new with invalid args", fn ->
114-
assert_raise Mix.Error, "Project path must start with a letter and have only lowercase letters, numbers and underscore", fn ->
113+
in_tmp "new with an invalid application name", fn ->
114+
assert_raise Mix.Error, "Application name must start with a letter and have only lowercase letters, numbers and underscore. The application name is inferred from the path, if you'd like to explicitly name the application then use the `--app APP` option.", fn ->
115115
Mix.Tasks.New.run ["007invalid"]
116116
end
117+
end
118+
119+
in_tmp "new with an invalid application name from the app option", fn ->
120+
assert_raise Mix.Error, "Application name must start with a letter and have only lowercase letters, numbers and underscore", fn ->
121+
Mix.Tasks.New.run ["valid", "--app", "007invalid"]
122+
end
123+
end
124+
125+
in_tmp "new with an invalid module name from the module options", fn ->
126+
assert_raise Mix.Error, "Module name must start with a capital letter, have all periods immediately followed by a capital letter, and must contain only letters, numbers, and periods", fn ->
127+
Mix.Tasks.New.run ["valid", "--module", "not.valid"]
128+
end
129+
end
117130

131+
in_tmp "new without a specified path", fn ->
118132
assert_raise Mix.Error, "Expected PATH to be given, please use `mix new PATH`", fn ->
119133
Mix.Tasks.New.run []
120134
end

0 commit comments

Comments
 (0)