Skip to content

Commit

Permalink
Convert Part generator to use RubyFileWriter and Generate::Command
Browse files Browse the repository at this point in the history
  • Loading branch information
cllns committed Feb 28, 2025
1 parent a233e12 commit 6b8c979
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 90 deletions.
25 changes: 4 additions & 21 deletions lib/hanami/cli/commands/app/generate/part.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ module App
module Generate
# @since 2.1.0
# @api private
class Part < App::Command
class Part < Command
DEFAULT_SKIP_TESTS = false
private_constant :DEFAULT_SKIP_TESTS

argument :name, required: true, desc: "Part name"
option :slice, required: false, desc: "Slice name"

option \
:skip_tests,
required: false,
Expand All @@ -28,26 +28,9 @@ class Part < App::Command
%(book (MyApp::Views::Parts::Book)),
%(book --slice=admin (Admin::Views::Parts::Book)),
]
attr_reader :generator
private :generator

# @since 2.0.0
# @api private
def initialize(
fs:, inflector:,
generator: Generators::App::Part.new(fs: fs, inflector: inflector),
**opts
)
super(fs: fs, inflector: inflector, **opts)
@generator = generator
end

# @since 2.0.0
# @api private
def call(name:, slice: nil, skip_tests: DEFAULT_SKIP_TESTS, **) # rubocop:disable Lint/UnusedMethodArgument
slice = inflector.underscore(Shellwords.shellescape(slice)) if slice

generator.call(app.namespace, name, slice)
def generator_class
Generators::App::Part
end
end
end
Expand Down
106 changes: 42 additions & 64 deletions lib/hanami/cli/generators/app/part.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,87 +13,65 @@ module App
class Part
# @since 2.1.0
# @api private
def initialize(fs:, inflector:)
def initialize(fs:, inflector:, out: $stdout)
@fs = fs
@inflector = inflector
@out = out
end

# @since 2.1.0
# @api private
def call(app, key, slice)
context = PartContext.new(inflector, app, slice, key)

if slice
generate_for_slice(context, slice)
else
generate_for_app(context)
end
def call(key:, namespace:, base_path:)
create_app_base_part_if_missing(key:, namespace:, base_path:)
create_slice_part_if_missing(key:, namespace:, base_path:) unless namespace == Hanami.app.namespace
create_generated_part(key:, namespace:, base_path:)
end

private

# @since 2.1.0
# @api private
attr_reader :fs

# @since 2.1.0
# @api private
attr_reader :inflector

# @since 2.1.0
# @api private
def generate_for_slice(context, slice)
slice_directory = fs.join("slices", slice)
raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)

generate_base_part_for_app(context)
generate_base_part_for_slice(context, slice)

fs.mkdir(directory = fs.join(slice_directory, "views", "parts", *context.underscored_namespace))
fs.create(fs.join(directory, "#{context.underscored_name}.rb"), t("slice_part.erb", context))
end

# @since 2.1.0
# @api private
def generate_for_app(context)
generate_base_part_for_app(context)

fs.mkdir(directory = fs.join("app", "views", "parts", *context.underscored_namespace))
fs.create(fs.join(directory, "#{context.underscored_name}.rb"), t("app_part.erb", context))
end

# @since 2.1.0
# @api private
def generate_base_part_for_app(context)
path = fs.join("app", "views", "part.rb")
return if fs.exist?(path)

fs.write(path, t("app_base_part.erb", context))
attr_reader :fs, :inflector, :out

def create_app_base_part_if_missing(key:, namespace:, base_path:)
return if fs.exist?(fs.join(base_path, "views", "part.rb"))

RubyClassFile.new(
fs: fs,
inflector: inflector,
namespace: Hanami.app.namespace,
key: "views.part",
base_path: "app/",
absolute_parent_class: "Hanami::View::Part",
auto_register: false
).create
end

# @since 2.1.0
# @api private
def generate_base_part_for_slice(context, slice)
path = fs.join("slices", slice, "views", "part.rb")
return if fs.exist?(path)

fs.write(path, t("slice_base_part.erb", context))
def create_slice_part_if_missing(key:, namespace:, base_path:)
return if fs.exist?(fs.join(base_path, "views", "part.rb"))

RubyClassFile.new(
fs: fs,
inflector: inflector,
namespace: namespace,
key: "views.part",
base_path: base_path,
absolute_parent_class: "#{Hanami.app.namespace}::Views::Part",
auto_register: false
).create
end

# @since 2.1.0
# @api private
def template(path, context)
require "erb"

ERB.new(
File.read(__dir__ + "/part/#{path}"),
trim_mode: "-"
).result(context.ctx)
def create_generated_part(key:, namespace:, base_path:)
RubyClassFile.new(
fs: fs,
inflector: inflector,
namespace: namespace,
key: inflector.underscore("views.parts.#{key}"),
base_path: base_path,
relative_parent_class: "Views::Part",
auto_register: false
).create
end

# @since 2.1.0
# @api private
alias_method :t, :template
end
end
end
Expand Down
28 changes: 25 additions & 3 deletions lib/hanami/cli/generators/app/ruby_class_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,25 @@ def initialize(
key:,
namespace:,
base_path:,
relative_parent_class:,
extra_namespace: nil,
relative_parent_class: nil,
absolute_parent_class: nil,
auto_register: nil,
body: []
)
if relative_parent_class && absolute_parent_class
raise "Must provide only one of relative_parent_class or absolute_parent_class"
end

@fs = fs
@inflector = inflector
@key = key
@namespace = namespace
@base_path = base_path
@extra_namespace = extra_namespace&.downcase
@relative_parent_class = relative_parent_class
@absolute_parent_class = absolute_parent_class
@auto_register = auto_register
@body = body
end

Expand Down Expand Up @@ -61,6 +69,8 @@ def fully_qualified_name
:base_path,
:extra_namespace,
:relative_parent_class,
:absolute_parent_class,
:auto_register,
:body,
)

Expand Down Expand Up @@ -111,17 +121,29 @@ def class_definition(class_name:, local_namespaces:)
.compact
.prepend(container_module)

parent_class = [container_module, relative_parent_class].join("::") if relative_parent_class
parent_class = if relative_parent_class
[container_module, relative_parent_class].join("::")
else
absolute_parent_class
end

RubyFileGenerator.class(
normalize(class_name),
parent_class: parent_class,
modules: modules,
header: ["# frozen_string_literal: true"],
header: headers,
body: body
)
end

def headers
[
# Intentionally ternary logic. Skip if nil, else 'true' or 'false'
("# auto_register: #{auto_register}" unless auto_register.nil?),
"# frozen_string_literal: true",
].compact
end

# @since 2.2.2
# @api private
def normalize(name)
Expand Down
3 changes: 1 addition & 2 deletions spec/unit/hanami/cli/commands/app/generate/part_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
require "ostruct"

RSpec.describe Hanami::CLI::Commands::App::Generate::Part, :app do
subject { described_class.new(fs: fs, inflector: inflector, generator: generator) }
subject { described_class.new(fs: fs, inflector: inflector, out: out) }

let(:out) { StringIO.new }
let(:fs) { Hanami::CLI::Files.new(memory: true, out: out) }
let(:inflector) { Dry::Inflector.new }
let(:generator) { Hanami::CLI::Generators::App::Part.new(fs: fs, inflector: inflector) }
let(:app) { Hanami.app.namespace }
let(:dir) { inflector.underscore(app) }

Expand Down

0 comments on commit 6b8c979

Please sign in to comment.