Skip to content

Commit a5bd2f3

Browse files
committed
Prevent generating operation without namespace
1 parent 0f81a5c commit a5bd2f3

File tree

7 files changed

+84
-34
lines changed

7 files changed

+84
-34
lines changed

lib/hanami/cli/errors.rb

+4
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,9 @@ def initialize(scheme)
9191
super("`#{scheme}' is not a supported db scheme")
9292
end
9393
end
94+
95+
# @since x.x.x
96+
# @api public
97+
class NameNeedsNamespaceError < Error; end
9498
end
9599
end

lib/hanami/cli/generators/app/operation.rb

+14-6
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,18 @@ def generate_for_slice(context, slice)
4242

4343
if context.namespaces.any?
4444
fs.mkdir(directory = fs.join(slice_directory, context.namespaces))
45-
fs.write(fs.join(directory, "#{context.name}.rb"), t("nested_slice_operation.erb", context))
45+
fs.write(fs.join(directory, "#{context.name}.rb"), t("slice_operation.erb", context))
4646
else
47-
fs.mkdir(directory = fs.join(slice_directory))
48-
fs.write(fs.join(directory, "#{context.name}.rb"), t("top_level_slice_operation.erb", context))
47+
print_error_message_about_naming(context.name, slice_directory)
4948
end
5049
end
5150

5251
def generate_for_app(context)
5352
if context.namespaces.any?
5453
fs.mkdir(directory = fs.join("app", context.namespaces))
55-
fs.write(fs.join(directory, "#{context.name}.rb"), t("nested_app_operation.erb", context))
54+
fs.write(fs.join(directory, "#{context.name}.rb"), t("app_operation.erb", context))
5655
else
57-
fs.mkdir(directory = fs.join("app"))
58-
fs.write(fs.join(directory, "#{context.name}.rb"), t("top_level_app_operation.erb", context))
56+
print_error_message_about_naming(context.name, "app")
5957
end
6058
end
6159

@@ -67,6 +65,16 @@ def template(path, context)
6765
).result(context.ctx)
6866
end
6967

68+
def print_error_message_about_naming(provided_name, base_location)
69+
raise NameNeedsNamespaceError.new(
70+
"Failed to create operation `#{provided_name}'. " \
71+
"This would create the operation directly in the `#{base_location}/' folder. " \
72+
"Instead, you should provide a namespace for the folder where this operation will live. " \
73+
"NOTE: We recommend giving it a name that's specific to your domain, " \
74+
"but you can also use `operations.#{provided_name}' in the meantime if you're unsure."
75+
)
76+
end
77+
7078
alias_method :t, :template
7179
end
7280
end

lib/hanami/cli/generators/app/operation/top_level_app_operation.erb

-8
This file was deleted.

lib/hanami/cli/generators/app/operation/top_level_slice_operation.erb

-8
This file was deleted.

spec/unit/hanami/cli/commands/app/generate/operation_spec.rb

+66-12
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,23 @@ def output
1818

1919
context "generating for app" do
2020
it "generates an operation" do
21-
subject.call(name: "add_book")
21+
subject.call(name: "operations/add_book")
2222

2323
operation_file = <<~EXPECTED
2424
# frozen_string_literal: true
2525
2626
module Test
27-
class AddBook < Test::Operation
28-
def call
27+
module Operations
28+
class AddBook < Test::Operation
29+
def call
30+
end
2931
end
3032
end
3133
end
3234
EXPECTED
3335

34-
expect(fs.read("app/add_book.rb")).to eq(operation_file)
35-
expect(output).to include("Created app/add_book.rb")
36+
expect(fs.read("app/operations/add_book.rb")).to eq(operation_file)
37+
expect(output).to include("Created app/operations/add_book.rb")
3638
end
3739

3840
it "generates a operation in a deep namespace with default separator" do
@@ -57,7 +59,7 @@ def call
5759
expect(output).to include("Created app/admin/books/add.rb")
5860
end
5961

60-
it "generates an operation in a deep namespace with slash separators" do
62+
it "generates an operation in a deep namespace with slash separator" do
6163
subject.call(name: "admin/books/add")
6264

6365
operation_file = <<~EXPECTED
@@ -78,26 +80,78 @@ def call
7880
expect(fs.read("app/admin/books/add.rb")).to eq(operation_file)
7981
expect(output).to include("Created app/admin/books/add.rb")
8082
end
83+
84+
it "outputs an error if trying to generate an operation without a separator" do
85+
expect {
86+
subject.call(name: "add_book")
87+
}.to raise_error(Hanami::CLI::NameNeedsNamespaceError).with_message(
88+
"Failed to create operation `add_book'. " \
89+
"This would create the operation directly in the `app/' folder. " \
90+
"Instead, you should provide a namespace for the folder where this operation will live. " \
91+
"NOTE: We recommend giving it a name that's specific to your domain, " \
92+
"but you can also use `operations.add_book' in the meantime if you're unsure."
93+
)
94+
expect(fs.exist?("app/add_book.rb")).to be(false)
95+
end
8196
end
8297

8398
context "generating for a slice" do
84-
it "generates a operation in a top-level namespace" do
99+
it "generates a operation" do
100+
fs.mkdir("slices/main")
101+
subject.call(name: "operations.add_book", slice: "main")
102+
103+
operation_file = <<~EXPECTED
104+
# frozen_string_literal: true
105+
106+
module Main
107+
module Operations
108+
class AddBook < Main::Operation
109+
def call
110+
end
111+
end
112+
end
113+
end
114+
EXPECTED
115+
116+
expect(fs.read("slices/main/operations/add_book.rb")).to eq(operation_file)
117+
expect(output).to include("Created slices/main/operations/add_book.rb")
118+
end
119+
120+
it "generates a operation in a deep namespace with default separator" do
85121
fs.mkdir("slices/main")
86-
subject.call(name: "add_book", slice: "main")
122+
subject.call(name: "admin.books.add", slice: "main")
87123

88124
operation_file = <<~EXPECTED
89125
# frozen_string_literal: true
90126
91127
module Main
92-
class AddBook < Main::Operation
93-
def call
128+
module Admin
129+
module Books
130+
class Add < Main::Operation
131+
def call
132+
end
133+
end
94134
end
95135
end
96136
end
97137
EXPECTED
98138

99-
expect(fs.read("slices/main/add_book.rb")).to eq(operation_file)
100-
expect(output).to include("Created slices/main/add_book.rb")
139+
expect(fs.read("slices/main/admin/books/add.rb")).to eq(operation_file)
140+
expect(output).to include("Created slices/main/admin/books/add.rb")
141+
end
142+
143+
it "outputs an error if trying to generate an operation without a separator" do
144+
fs.mkdir("slices/main")
145+
expect {
146+
subject.call(name: "add_book", slice: "main")
147+
}.to raise_error(Hanami::CLI::NameNeedsNamespaceError).with_message(
148+
"Failed to create operation `add_book'. " \
149+
"This would create the operation directly in the `slices/main/' folder. " \
150+
"Instead, you should provide a namespace for the folder where this operation will live. " \
151+
"NOTE: We recommend giving it a name that's specific to your domain, " \
152+
"but you can also use `operations.add_book' in the meantime if you're unsure."
153+
)
154+
expect(fs.exist?("app/add_book.rb")).to be(false)
101155
end
102156
end
103157
end

0 commit comments

Comments
 (0)