Skip to content

Commit

Permalink
Prevent generating operation without namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
cllns committed Jun 19, 2024
1 parent 0f81a5c commit a5bd2f3
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 34 deletions.
4 changes: 4 additions & 0 deletions lib/hanami/cli/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,9 @@ def initialize(scheme)
super("`#{scheme}' is not a supported db scheme")
end
end

# @since x.x.x
# @api public
class NameNeedsNamespaceError < Error; end
end
end
20 changes: 14 additions & 6 deletions lib/hanami/cli/generators/app/operation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,18 @@ def generate_for_slice(context, slice)

if context.namespaces.any?
fs.mkdir(directory = fs.join(slice_directory, context.namespaces))
fs.write(fs.join(directory, "#{context.name}.rb"), t("nested_slice_operation.erb", context))
fs.write(fs.join(directory, "#{context.name}.rb"), t("slice_operation.erb", context))
else
fs.mkdir(directory = fs.join(slice_directory))
fs.write(fs.join(directory, "#{context.name}.rb"), t("top_level_slice_operation.erb", context))
print_error_message_about_naming(context.name, slice_directory)
end
end

def generate_for_app(context)
if context.namespaces.any?
fs.mkdir(directory = fs.join("app", context.namespaces))
fs.write(fs.join(directory, "#{context.name}.rb"), t("nested_app_operation.erb", context))
fs.write(fs.join(directory, "#{context.name}.rb"), t("app_operation.erb", context))
else
fs.mkdir(directory = fs.join("app"))
fs.write(fs.join(directory, "#{context.name}.rb"), t("top_level_app_operation.erb", context))
print_error_message_about_naming(context.name, "app")
end
end

Expand All @@ -67,6 +65,16 @@ def template(path, context)
).result(context.ctx)
end

def print_error_message_about_naming(provided_name, base_location)
raise NameNeedsNamespaceError.new(
"Failed to create operation `#{provided_name}'. " \
"This would create the operation directly in the `#{base_location}/' folder. " \
"Instead, you should provide a namespace for the folder where this operation will live. " \
"NOTE: We recommend giving it a name that's specific to your domain, " \
"but you can also use `operations.#{provided_name}' in the meantime if you're unsure."
)
end

alias_method :t, :template
end
end
Expand Down

This file was deleted.

This file was deleted.

78 changes: 66 additions & 12 deletions spec/unit/hanami/cli/commands/app/generate/operation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,23 @@ def output

context "generating for app" do
it "generates an operation" do
subject.call(name: "add_book")
subject.call(name: "operations/add_book")

operation_file = <<~EXPECTED
# frozen_string_literal: true
module Test
class AddBook < Test::Operation
def call
module Operations
class AddBook < Test::Operation
def call
end
end
end
end
EXPECTED

expect(fs.read("app/add_book.rb")).to eq(operation_file)
expect(output).to include("Created app/add_book.rb")
expect(fs.read("app/operations/add_book.rb")).to eq(operation_file)
expect(output).to include("Created app/operations/add_book.rb")
end

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

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

operation_file = <<~EXPECTED
Expand All @@ -78,26 +80,78 @@ def call
expect(fs.read("app/admin/books/add.rb")).to eq(operation_file)
expect(output).to include("Created app/admin/books/add.rb")
end

it "outputs an error if trying to generate an operation without a separator" do
expect {
subject.call(name: "add_book")
}.to raise_error(Hanami::CLI::NameNeedsNamespaceError).with_message(
"Failed to create operation `add_book'. " \
"This would create the operation directly in the `app/' folder. " \
"Instead, you should provide a namespace for the folder where this operation will live. " \
"NOTE: We recommend giving it a name that's specific to your domain, " \
"but you can also use `operations.add_book' in the meantime if you're unsure."
)
expect(fs.exist?("app/add_book.rb")).to be(false)
end
end

context "generating for a slice" do
it "generates a operation in a top-level namespace" do
it "generates a operation" do
fs.mkdir("slices/main")
subject.call(name: "operations.add_book", slice: "main")

operation_file = <<~EXPECTED
# frozen_string_literal: true
module Main
module Operations
class AddBook < Main::Operation
def call
end
end
end
end
EXPECTED

expect(fs.read("slices/main/operations/add_book.rb")).to eq(operation_file)
expect(output).to include("Created slices/main/operations/add_book.rb")
end

it "generates a operation in a deep namespace with default separator" do
fs.mkdir("slices/main")
subject.call(name: "add_book", slice: "main")
subject.call(name: "admin.books.add", slice: "main")

operation_file = <<~EXPECTED
# frozen_string_literal: true
module Main
class AddBook < Main::Operation
def call
module Admin
module Books
class Add < Main::Operation
def call
end
end
end
end
end
EXPECTED

expect(fs.read("slices/main/add_book.rb")).to eq(operation_file)
expect(output).to include("Created slices/main/add_book.rb")
expect(fs.read("slices/main/admin/books/add.rb")).to eq(operation_file)
expect(output).to include("Created slices/main/admin/books/add.rb")
end

it "outputs an error if trying to generate an operation without a separator" do
fs.mkdir("slices/main")
expect {
subject.call(name: "add_book", slice: "main")
}.to raise_error(Hanami::CLI::NameNeedsNamespaceError).with_message(
"Failed to create operation `add_book'. " \
"This would create the operation directly in the `slices/main/' folder. " \
"Instead, you should provide a namespace for the folder where this operation will live. " \
"NOTE: We recommend giving it a name that's specific to your domain, " \
"but you can also use `operations.add_book' in the meantime if you're unsure."
)
expect(fs.exist?("app/add_book.rb")).to be(false)
end
end
end

0 comments on commit a5bd2f3

Please sign in to comment.