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

Add Hanami::CLI::RubyFileGenerator, convert Operation to use it instead of ERB #186

Merged
merged 61 commits into from
Jul 14, 2024
Merged
Changes from 1 commit
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
d3e5e78
Add dry-operation to default Gemfile
cllns Jun 14, 2024
888c388
Add base Operation class, based on dry-operation
cllns Jun 14, 2024
24d3d6b
Fix view spec
cllns Jun 14, 2024
bc2670a
Add Operation generators
cllns Jun 15, 2024
1c37df3
Add empty `call` method definition
cllns Jun 15, 2024
a3f6a03
Remove ostruct
cllns Jun 15, 2024
d93dfc8
Merge branch 'main' into add-dry-operation
cllns Jun 17, 2024
649bdcb
Allow slash separator for generator
cllns Jun 17, 2024
f74519f
Allow slash separator for generator
cllns Jun 17, 2024
0f9f814
Rename module to admin
cllns Jun 17, 2024
663abc6
Remove newlines in generated files
cllns Jun 17, 2024
3b72feb
Remove input as default args
cllns Jun 19, 2024
0f81a5c
Remove Operations namespace, generate in app/ or slices/SLICE_NAME/
cllns Jun 19, 2024
a5bd2f3
Prevent generating operation without namespace
cllns Jun 19, 2024
eb391ca
Revert "Prevent generating operation without namespace"
cllns Jun 20, 2024
1023225
Add recommendation to add namespace to operations
cllns Jun 20, 2024
6a3c32a
Change examples
cllns Jun 20, 2024
8dc3de4
Switch to outputting directly, remove Files#recommend
cllns Jun 21, 2024
7059e7e
Add Hanami::CLI::RubyFileGenerator
cllns Jun 21, 2024
0dfdf7d
x.x.x => 2.2.0
cllns Jun 22, 2024
8f90b33
x.x.x => 2.2.0
cllns Jun 22, 2024
8e62aa3
Include Dry::Monads[:result] in base Action
cllns Jun 22, 2024
f0e0994
Add .module tests
cllns Jun 24, 2024
ed47e5e
Convert top-level app operation to use RubyFileGenerator
cllns Jun 24, 2024
4769bd6
Convert nested app operation to use RubyFileGenerator
cllns Jun 24, 2024
8e5c575
Support slash separators
cllns Jun 24, 2024
8effa30
Convert top-level slice operation to use RubyFileGenerator
cllns Jun 24, 2024
06f2750
Remove OperationContext
cllns Jun 24, 2024
79699f0
Remove namespaces instance variable
cllns Jun 24, 2024
3879144
Refactor to variables
cllns Jun 24, 2024
6f6fce3
Remove last temporary instance variable
cllns Jun 24, 2024
30c2a94
Refactor
cllns Jun 24, 2024
da093d4
More refactoring, for clarity
cllns Jun 24, 2024
40237de
Rename variable for clarity
cllns Jun 24, 2024
f0cf827
Rename helper method
cllns Jun 24, 2024
2dff130
Simplify RubyFileGenerator, support older versions
cllns Jun 24, 2024
36c7b3b
Convert Operation generator to use simplified RubyFileGenerator
cllns Jun 24, 2024
1c47e7e
Merge branch 'add-dry-operation' into add-file-generator
cllns Jun 24, 2024
2a4f0b6
Remove un-used errors
cllns Jun 24, 2024
0223bea
Refactor
cllns Jun 24, 2024
8e458ce
Older kwargs forwarding style
cllns Jun 24, 2024
d4e13bd
Refactor
cllns Jun 24, 2024
f9221f0
Rename variable
cllns Jun 24, 2024
5f5887b
Add explanatory comment
cllns Jul 1, 2024
e9e7051
Merge remote-tracking branch 'origin/main' into add-file-generator
cllns Jul 5, 2024
a051c7d
Fix base slice action
cllns Jul 5, 2024
d0d02c7
Remove un-used ERB templates
cllns Jul 5, 2024
145f7ee
Remove OperationContext
cllns Jul 5, 2024
b76942c
Ternary over and/or
cllns Jul 5, 2024
26a665b
Fix missing 'end' from bad merge
cllns Jul 5, 2024
b07cf35
Fix namespace recommendation
cllns Jul 5, 2024
23aace2
Merge remote-tracking branch 'origin/main' into add-file-generator
cllns Jul 11, 2024
f649975
Extract App::Generate::Command
cllns Jul 11, 2024
5239824
Specify full name, to use App::Command
cllns Jul 11, 2024
511b6a0
Merge remote-tracking branch 'origin' into add-file-generator
cllns Jul 12, 2024
fffd123
Use constants file
cllns Jul 12, 2024
54dd28b
Move class methods above initialize
cllns Jul 14, 2024
303f502
Use constants file
cllns Jul 14, 2024
e824e5d
Add yard comments
cllns Jul 14, 2024
94c92e1
Revert "Use constants file"
cllns Jul 14, 2024
66d0c80
Fix indent to be two spaces
cllns Jul 14, 2024
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
Prev Previous commit
Next Next commit
Add .module tests
cllns committed Jun 24, 2024
commit f0e09944a5b6a541b5a455fdc2e4793f95b41374
3 changes: 2 additions & 1 deletion lib/hanami/cli/ruby_file_generator.rb
Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@ def self.class(class_name, **)
new(class_name: class_name, **).to_s
end

def self.module(*name, **)
def self.module(*names, **)
module_names = if names.first.is_a?(Array)
names.first
else
@@ -75,6 +75,7 @@ def self.module(*name, **)

new(modules: module_names, class_name: nil, parent_class: nil, **).to_s
end

def to_s
definition = lines(modules).map { |line| "#{line}\n" }.join

1,031 changes: 546 additions & 485 deletions spec/unit/hanami/cli/ruby_file_generator_spec.rb
Original file line number Diff line number Diff line change
@@ -1,614 +1,675 @@
# frozen_string_literal: true

RSpec.describe Hanami::CLI::RubyFileGenerator do
describe "no methods" do
describe "top-level" do
it "generates class without parent class" do
expect(
described_class.class("Greeter")
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
describe ".class" do
describe "no methods" do
describe "top-level" do
it "generates class without parent class" do
expect(
described_class.class("Greeter")
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
class Greeter
end
OUTPUT
)
)
end

it "generates class with parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
).to_s
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
class Greeter < BaseService
end
OUTPUT
)
)
end
end

describe "with single module" do
it "generates class without parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Services],
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Services
class Greeter
end
end
OUTPUT
)
)
end
OUTPUT
)
)
end

it "generates class with parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
).to_s
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
it "generates class with parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Services]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Services
class Greeter < BaseService
end
end
OUTPUT
OUTPUT
)
)
)
end
end
end

describe "with two modules" do
it "generates class without parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Admin Services],
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
describe "with single module" do
it "generates class without parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Services],
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Admin
module Services
class Greeter
end
end
end
OUTPUT
)
)
end

it "generates class with parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Admin Services]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
OUTPUT
)
)
end

it "generates class with parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Services]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Admin
module Services
class Greeter < BaseService
end
end
end
OUTPUT
OUTPUT
)
)
)
end
end
end

describe "with three modules" do
it "generates class without parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Internal Admin Services]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
describe "with two modules" do
it "generates class without parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Admin Services],
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Internal
module Admin
module Services
class Greeter
end
end
end
end
OUTPUT
)
)
end

it "generates class with parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Internal Admin Services]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
OUTPUT
)
)
end

it "generates class with parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Admin Services]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Internal
module Admin
module Services
class Greeter < BaseService
end
end
end
end
OUTPUT
OUTPUT
)
)
)
end
end
end
end

describe "with methods" do
describe "top-level" do
it "generates class without parent class and call method with no args" do
expect(
described_class.class("Greeter", methods: {call: nil})
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true

class Greeter
def call
describe "with three modules" do
it "generates class without parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Internal Admin Services]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Internal
module Admin
module Services
class Greeter
end
end
end
end
end
OUTPUT
)
)
end

it "generates class with parent class and call method with 1 arg" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
methods: {call: ["args"]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
class Greeter < BaseService
def call(args)
OUTPUT
)
)
end

it "generates class with parent class" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Internal Admin Services]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Internal
module Admin
module Services
class Greeter < BaseService
end
end
end
end
end
OUTPUT
OUTPUT
)
)
)
end
end
end

describe "with single module" do
it "generates class without parent class and call methods with 2 args" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Services],
methods: {call: %w[request response]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
describe "with methods" do
describe "top-level" do
it "generates class without parent class and call method with no args" do
expect(
described_class.class("Greeter", methods: {call: nil})
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Services
class Greeter
def call(request, response)
def call
end
end
end
OUTPUT
)
)
end
OUTPUT
)
)
end

it "generates class with parent class and call method with 1 arg" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
methods: {call: ["args"]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
it "generates class with parent class and call method with required keyword args" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Services],
methods: {call: %w[request: response:]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Services
class Greeter < BaseService
def call(request:, response:)
def call(args)
end
end
end
OUTPUT
OUTPUT
)
)
)
end
end
end

describe "with two modules" do
it "generates class without parent class and call method with mix of args" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Admin Services],
methods: {call: ["env", "request:", "response:", "context: nil"]}
).to_s
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Admin
describe "with single module" do
it "generates class without parent class and call methods with 2 args" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Services],
methods: {call: %w[request response]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Services
class Greeter
def call(env, request:, response:, context: nil)
def call(request, response)
end
end
end
end
OUTPUT
)
)
end

it "generates class with parent class and two methods" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Admin Services],
methods: {initialize: ["context"], call: ["args"]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
OUTPUT
)
)
end

it "generates class with parent class and call method with required keyword args" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Services],
methods: {call: %w[request: response:]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Admin
module Services
class Greeter < BaseService
def initialize(context)
end
def call(args)
def call(request:, response:)
end
end
end
end
OUTPUT
OUTPUT
)
)
)
end
end
end

describe "with three modules" do
it "generates class without parent class, with ivars and method" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Internal Admin Services],
ivars: [:@name, :@birthdate],
methods: {call: [:env]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
describe "with two modules" do
it "generates class without parent class and call method with mix of args" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Admin Services],
methods: {call: ["env", "request:", "response:", "context: nil"]}
).to_s
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Internal
module Admin
module Services
class Greeter
def initialize(name:, birthdate:)
@name = name
@birthdate = birthdate
def call(env, request:, response:, context: nil)
end
def call(env)
end
private
attr_reader :name, :birthdate
end
end
end
end
OUTPUT
)
)
end

it "raises error when ivars don't lead with @" do
expect {
described_class.class("Greeter", ivars: [:name])
}.to(raise_error(Hanami::CLI::RubyFileGenerator::InvalidInstanceVariablesError))
end

it "raises error when 'initialize' method is specified and ivars are present" do
expect {
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
ivars: [:@name],
methods: {initialize: nil}
)
}.to(raise_error(Hanami::CLI::RubyFileGenerator::DuplicateInitializeMethodError))
end

it "generates class with parent class, and requires" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Internal Admin Services],
requires: ["roobi/fake"]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
require "roobi/fake"
OUTPUT
)
)
end

it "generates class with parent class and two methods" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Admin Services],
methods: {initialize: ["context"], call: ["args"]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Internal
module Admin
module Services
class Greeter < BaseService
def initialize(context)
end
def call(args)
end
end
end
end
end
OUTPUT
OUTPUT
)
)
)
end
end
end

describe "with includes" do
it "generates class with includes" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
includes: ["Enumerable", %(Import["external.api"])]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true

class Greeter
include Enumerable
include Import["external.api"]
end
OUTPUT
describe "with three modules" do
it "generates class without parent class, with ivars and method" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: %w[Internal Admin Services],
ivars: [:@name, :@birthdate],
methods: {call: [:env]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Internal
module Admin
module Services
class Greeter
def initialize(name:, birthdate:)
@name = name
@birthdate = birthdate
end
def call(env)
end
private
attr_reader :name, :birthdate
end
end
end
end
OUTPUT
)
)
end

it "raises error when ivars don't lead with @" do
expect {
described_class.class("Greeter", ivars: [:name])
}.to(raise_error(Hanami::CLI::RubyFileGenerator::InvalidInstanceVariablesError))
end

it "raises error when 'initialize' method is specified and ivars are present" do
expect {
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
ivars: [:@name],
methods: {initialize: nil}
)
}.to(raise_error(Hanami::CLI::RubyFileGenerator::DuplicateInitializeMethodError))
end

it "generates class with parent class, and requires" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
parent_class: "BaseService",
modules: %w[Internal Admin Services],
requires: ["roobi/fake"]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
require "roobi/fake"
module Internal
module Admin
module Services
class Greeter < BaseService
end
end
end
end
OUTPUT
)
)
)
end
end

it "generates class with includes and ivars" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
includes: ["Enumerable", %(Import["external.api"])],
ivars: [:@name]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
class Greeter
include Enumerable
include Import["external.api"]
describe "with includes" do
it "generates class with includes" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
includes: ["Enumerable", %(Import["external.api"])]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
def initialize(name:)
@name = name
class Greeter
include Enumerable
include Import["external.api"]
end
OUTPUT
)
)
end

it "generates class with includes and ivars" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
includes: ["Enumerable", %(Import["external.api"])],
ivars: [:@name]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
private
attr_reader :name
end
OUTPUT
)
)
end
class Greeter
include Enumerable
include Import["external.api"]
it "generates class with includes and one method" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
includes: ["Enumerable", %(Import["external.api"])],
methods: {call: ["name"]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
def initialize(name:)
@name = name
end
class Greeter
include Enumerable
include Import["external.api"]
private
def call(name)
attr_reader :name
end
end
OUTPUT
)
)
end
end
OUTPUT
)
)
end

it "generates class with includes and one method" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
includes: ["Enumerable", %(Import["external.api"])],
methods: {call: ["name"]}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
describe "with inline syntax name for parent, module, class" do
it "generates class with inline-syntax" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Services::Greeter",
parent_class: "Internal::BaseService",
modules: ["Internal::Admin"]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
class Greeter
include Enumerable
include Import["external.api"]
module Internal::Admin
class Services::Greeter < Internal::BaseService
def call(name)
end
end
end
OUTPUT
OUTPUT
)
)
)
end
end
end

describe "with magic comment" do
it "generates class with custom magic comment" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: ["Internal"],
magic_comments: {value: true}
describe "with inline syntax name for parent, module, class" do
it "generates class with inline-syntax" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Services::Greeter",
parent_class: "Internal::BaseService",
modules: ["Internal::Admin"]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Internal::Admin
class Services::Greeter < Internal::BaseService
end
end
OUTPUT
)
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
# value: true
end
end

module Internal
class Greeter
describe "with magic comment" do
it "generates class with custom magic comment" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: ["Internal"],
magic_comments: {value: true}
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
# value: true
module Internal
class Greeter
end
end
end
OUTPUT
OUTPUT
)
)
)
end
end
end

describe "with top contents" do
it "generates simple class with only top contents as comment" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Foo",
top_contents: ["# code goes here"]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
describe "with top contents" do
it "generates simple class with only top contents as comment" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Foo",
top_contents: ["# code goes here"]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
class Foo
# code goes here
end
OUTPUT
)
)
end

it "generates class with top contents in correct spot" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
includes: ["Validatable"],
ivars: [:@name],
top_contents: ["before_call :validate"]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
class Foo
# code goes here
end
OUTPUT
)
)
end
class Greeter
include Validatable
it "generates class with top contents in correct spot" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
includes: ["Validatable"],
ivars: [:@name],
top_contents: ["before_call :validate"]
)
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
before_call :validate
class Greeter
include Validatable
def initialize(name:)
@name = name
end
before_call :validate
private
def initialize(name:)
@name = name
attr_reader :name
end
OUTPUT
)
)
end
end
end

private
attr_reader :name
it "generates class with sorted custom magic comments, including frozen_string_literal" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: ["Internal"],
magic_comments: {abc: 123, value: true}
)
).to(
eq(
<<~OUTPUT
# abc: 123
# frozen_string_literal: true
# value: true
module Internal
class Greeter
end
OUTPUT
)
end
OUTPUT
)
end
)
end
end

it "generates class with sorted custom magic comments, including frozen_string_literal" do
expect(
Hanami::CLI::RubyFileGenerator.class(
"Greeter",
modules: ["Internal"],
magic_comments: {abc: 123, value: true}
it "fails to generate unparseable ruby code" do
expect { described_class.class("%%Greeter") }.to(
raise_error(Hanami::CLI::RubyFileGenerator::GeneratedUnparseableCodeError)
)
).to(
eq(
<<~OUTPUT
# abc: 123
# frozen_string_literal: true
# value: true
module Internal
class Greeter
end

describe ".module" do
describe "no methods" do
describe "without frozen_string_literal" do
describe "top-level" do
it "generates module by itself" do
expect(
described_class.module("Greetable")
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Greetable
end
OUTPUT
)
)
end
end
OUTPUT
)
)
end

it "fails to generate unparseable ruby code" do
expect { described_class.class("%%Greeter") }.to(
raise_error(Hanami::CLI::RubyFileGenerator::GeneratedUnparseableCodeError)
)
it "generates modules nested in a module, from arrray" do
expect(
described_class.module(%w[External Greetable])
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module External
module Greetable
end
end
OUTPUT
)
)
end

it "generates modules nested in a module, from list" do
expect(
described_class.module("Admin", "External", "Greetable")
).to(
eq(
<<~OUTPUT
# frozen_string_literal: true
module Admin
module External
module Greetable
end
end
end
OUTPUT
)
)
end
end
end
end
end
end
end