Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow specifying engine for generated templates #280

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion lib/hanami/cli/commands/app/generate/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class Action < App::Command
DEFAULT_SKIP_ROUTE = false
private_constant :DEFAULT_SKIP_ROUTE

DEFAULT_TEMPLATE = "erb"
private_constant :DEFAULT_TEMPLATE

argument :name, required: true, desc: "Action name"
option :url, required: false, type: :string, desc: "Action URL"
option :http, required: false, type: :string, desc: "Action HTTP method"
Expand All @@ -51,6 +54,8 @@ class Action < App::Command
default: DEFAULT_SKIP_ROUTE,
desc: "Skip route generation"
option :slice, required: false, desc: "Slice name"
option :template, required: false, type: :string, default: DEFAULT_TEMPLATE,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used template because this was mentioned in the original issue and apparently it was named like this in Hanami 1 times. But maybe template-engine would be more descriptive? Although a bit long.

desc: "Template engine to use (officially supported options: erb, haml, slim)"

# rubocop:disable Layout/LineLength
example [
Expand Down Expand Up @@ -94,6 +99,7 @@ def call(
skip_view: DEFAULT_SKIP_VIEW,
skip_tests: DEFAULT_SKIP_TESTS, # rubocop:disable Lint/UnusedMethodArgument,
skip_route: DEFAULT_SKIP_ROUTE,
template: DEFAULT_TEMPLATE,
slice: nil,
context: nil,
**
Expand All @@ -106,7 +112,8 @@ def call(
raise InvalidActionNameError.new(name)
end

generator.call(app.namespace, controller, action, url, http, format, skip_view, skip_route, slice, context: context)
generator.call(app.namespace, controller, action, url, http, format, skip_view, skip_route, template, slice,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels weird with so many positional arguments. Should I convert this to keyword?

context: context)
end

# rubocop:enable Metrics/ParameterLists
Expand Down
8 changes: 4 additions & 4 deletions lib/hanami/cli/commands/app/generate/view.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ class View < App::Command
DEFAULT_FORMAT = "html"
private_constant :DEFAULT_FORMAT

# TODO: make engine configurable

argument :name, required: true, desc: "View name"
option :slice, required: false, desc: "Slice name"
option :template, required: false, desc: "Template engine to use (officially supported: erb, haml, slim)",
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should happen if an engine outside the list is called? Currently you can do --template md and it will create a file with .md extension and with default HTML (from ERb engine). Which is not entirely wrong, but maybe the list should be restricted and produce error if user specifies unsupported engine?

This also brought the question if this should not be extensible in some way, so gems could hook into it and provide own base templates for their engines (for example hanami-phlex).

default: "erb"

example [
%(books.index (MyApp::Actions::Books::Index)),
Expand All @@ -43,10 +43,10 @@ def initialize(

# @since 2.0.0
# @api private
def call(name:, format: DEFAULT_FORMAT, slice: nil, **)
def call(name:, format: DEFAULT_FORMAT, template: "erb", slice: nil, **)
slice = inflector.underscore(Shellwords.shellescape(slice)) if slice

generator.call(app.namespace, name, format, slice)
generator.call(app.namespace, name, format, template, slice)
end
end
end
Expand Down
25 changes: 13 additions & 12 deletions lib/hanami/cli/generators/app/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ def initialize(fs:, inflector:)

# @since 2.0.0
# @api private
def call(app, controller, action, url, http, format, skip_view, skip_route, slice, context: nil)
def call(app, controller, action, url, http, format, skip_view, skip_route, engine, slice, context: nil)
context ||= ActionContext.new(inflector, app, slice, controller, action)
if slice
generate_for_slice(controller, action, url, http, format, skip_view, skip_route, slice, context)
generate_for_slice(controller, action, url, http, format, skip_view, skip_route, engine, slice, context)
else
generate_for_app(controller, action, url, http, format, skip_view, skip_route, context)
generate_for_app(controller, action, url, http, format, skip_view, skip_route, engine, context)
end
end

Expand Down Expand Up @@ -72,7 +72,8 @@ def call(app, controller, action, url, http, format, skip_view, skip_route, slic
attr_reader :inflector

# rubocop:disable Metrics/AbcSize
def generate_for_slice(controller, action, url, http, format, skip_view, skip_route, slice, context)
def generate_for_slice(controller, action, url, http, format, skip_view, skip_route, engine, slice,
context)
slice_directory = fs.join("slices", slice)
raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)

Expand All @@ -92,12 +93,12 @@ def generate_for_slice(controller, action, url, http, format, skip_view, skip_ro
fs.create(fs.join(directory, "#{action}.rb"), t("slice_view.erb", context))

fs.mkdir(directory = fs.join(slice_directory, "templates", controller))
fs.create(fs.join(directory, "#{action}.#{format}.erb"),
t(template_with_format_ext("slice_template", format), context))
fs.create(fs.join(directory, "#{action}.#{format}.#{engine}"),
t(template_with_format_ext("slice_template", format, engine), context))
end
end

def generate_for_app(controller, action, url, http, format, skip_view, skip_route, context)
def generate_for_app(controller, action, url, http, format, skip_view, skip_route, engine, context)
if generate_route?(skip_route)
fs.inject_line_at_class_bottom(
fs.join("config", "routes.rb"),
Expand All @@ -117,8 +118,8 @@ def generate_for_app(controller, action, url, http, format, skip_view, skip_rout
fs.create(fs.join(view_directory, "#{view}.rb"), t("view.erb", context))

fs.mkdir(template_directory = fs.join("app", "templates", controller))
fs.create(fs.join(template_directory, "#{view}.#{format}.erb"),
t(template_with_format_ext("template", format), context))
fs.create(fs.join(template_directory, "#{view}.#{format}.#{engine}"),
t(template_with_format_ext("template", format, engine), context))
end
end
# rubocop:enable Metrics/AbcSize
Expand Down Expand Up @@ -169,13 +170,13 @@ def corresponding_restful_view(view)
RESTFUL_COUNTERPART_VIEWS.fetch(view, nil)
end

def template_with_format_ext(name, format)
def template_with_format_ext(name, format, engine)
ext =
case format.to_sym
when :html
".html.erb"
".html.#{engine}"
else
".erb"
".#{engine}"
end

"#{name}#{ext}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
%h1= <%= camelized_slice_name %>::Views::<%= camelized_controller_name %>::<%= camelized_action_name %>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
h1 = <%= camelized_slice_name %>::Views::<%= camelized_controller_name %>::<%= camelized_action_name %>
1 change: 1 addition & 0 deletions lib/hanami/cli/generators/app/action/template.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
%h1= <%= camelized_app_name %>::Views::<%= camelized_controller_name %>::<%= camelized_action_name %>
1 change: 1 addition & 0 deletions lib/hanami/cli/generators/app/action/template.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
h1 = <%= camelized_app_name %>::Views::<%= camelized_controller_name %>::<%= camelized_action_name %>
24 changes: 12 additions & 12 deletions lib/hanami/cli/generators/app/view.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ def initialize(fs:, inflector:)

# @since 2.0.0
# @api private
def call(app, key, format, slice)
def call(app, key, format, engine, slice)
context = ViewContext.new(inflector, app, slice, key)

if slice
generate_for_slice(context, format, slice)
generate_for_slice(context, format, engine, slice)
else
generate_for_app(context, format, slice)
generate_for_app(context, format, engine, slice)
end
end

Expand All @@ -38,36 +38,36 @@ def call(app, key, format, slice)

# rubocop:disable Metrics/AbcSize

def generate_for_slice(context, format, slice)
def generate_for_slice(context, format, engine, slice)
slice_directory = fs.join("slices", slice)
raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)

fs.mkdir(directory = fs.join(slice_directory, "views", context.namespaces))
fs.create(fs.join(directory, "#{context.name}.rb"), t("slice_view.erb", context))

fs.mkdir(directory = fs.join(slice_directory, "templates", context.namespaces))
fs.create(fs.join(directory, "#{context.name}.#{format}.erb"),
t(template_with_format_ext("slice_template", format), context))
fs.create(fs.join(directory, "#{context.name}.#{format}.#{engine}"),
t(template_with_format_ext("slice_template", format, engine), context))
end

def generate_for_app(context, format, _slice)
def generate_for_app(context, format, engine, _slice)
fs.mkdir(directory = fs.join("app", "views", context.namespaces))
fs.create(fs.join(directory, "#{context.name}.rb"), t("app_view.erb", context))

fs.mkdir(directory = fs.join("app", "templates", context.namespaces))
fs.create(fs.join(directory, "#{context.name}.#{format}.erb"),
t(template_with_format_ext("app_template", format), context))
fs.create(fs.join(directory, "#{context.name}.#{format}.#{engine}"),
t(template_with_format_ext("app_template", format, engine), context))
end

# rubocop:enable Metrics/AbcSize

def template_with_format_ext(name, format)
def template_with_format_ext(name, format, engine)
ext =
case format.to_sym
when :html
".html.erb"
".html.#{engine}"
else
".erb"
".#{engine}"
end

"#{name}#{ext}"
Expand Down
1 change: 1 addition & 0 deletions lib/hanami/cli/generators/app/view/app_template.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
%h1 <%= camelized_app_name %>::Views::<%= camelized_namespace %>::<%= camelized_name %>
1 change: 1 addition & 0 deletions lib/hanami/cli/generators/app/view/app_template.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
h1 <%= camelized_app_name %>::Views::<%= camelized_namespace %>::<%= camelized_name %>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
%h1 <%= camelized_slice_name %>::Views::<%= camelized_namespace %>::<%= camelized_name %>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
h1 <%= camelized_slice_name %>::Views::<%= camelized_namespace %>::<%= camelized_name %>
22 changes: 22 additions & 0 deletions spec/unit/hanami/cli/commands/app/generate/action_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,28 @@ def handle(request, response)
end
end

it "allows to specify slim template engine" do
within_application_directory do
subject.call(name: action_name, template: "slim")

template_file = <<~EXPECTED
h1 = Test::Views::Users::Index
EXPECTED
expect(fs.read("app/templates/#{controller}/#{action}.html.slim")).to eq(template_file)
end
end

it "allows to specify HAML template engine" do
within_application_directory do
subject.call(name: action_name, template: "haml")

template_file = <<~EXPECTED
%h1= Test::Views::Users::Index
EXPECTED
expect(fs.read("app/templates/#{controller}/#{action}.html.haml")).to eq(template_file)
end
end

include_context "with existing files" do
let(:generate_action) { subject.call(name: action_name) }
end
Expand Down
45 changes: 45 additions & 0 deletions spec/unit/hanami/cli/commands/app/generate/view_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,28 @@ class Index < Test::View
end
end

it "allows to specify slim template engine" do
within_application_directory do
subject.call(name: "special.users.index", template: "slim")

template_file = <<~EXPECTED
h1 Test::Views::Special::Users::Index
EXPECTED
expect(fs.read("app/templates/special/users/index.html.slim")).to eq(template_file)
end
end

it "allows to specify HAML template engine" do
within_application_directory do
subject.call(name: "special.users.index", template: "haml")

template_file = <<~EXPECTED
%h1 Test::Views::Special::Users::Index
EXPECTED
expect(fs.read("app/templates/special/users/index.html.haml")).to eq(template_file)
end
end

context "with existing file" do
before do
within_application_directory do
Expand Down Expand Up @@ -143,6 +165,29 @@ class Index < Main::View
expect(output).to include("Created slices/main/templates/users/index.html.erb")
end
end
it "allows to specify slim template engine" do
within_application_directory do
fs.mkdir("slices/main")
subject.call(name: "users.index", slice: "main", template: "slim")

template_file = <<~EXPECTED
h1 Main::Views::Users::Index
EXPECTED
expect(fs.read("slices/main/templates/users/index.html.slim")).to eq(template_file)
end
end

it "allows to specify HAML template engine" do
within_application_directory do
fs.mkdir("slices/main")
subject.call(name: "users.index", slice: "main", template: "haml")

template_file = <<~EXPECTED
%h1 Main::Views::Users::Index
EXPECTED
expect(fs.read("slices/main/templates/users/index.html.haml")).to eq(template_file)
end
end

context "with existing file" do
before do
Expand Down