hanami-cli 2.1.1 → 2.2.0.beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +29 -13
  3. data/.rubocop.yml +2 -0
  4. data/CHANGELOG.md +28 -0
  5. data/Gemfile +6 -1
  6. data/README.md +13 -7
  7. data/docker-compose.yml +14 -0
  8. data/hanami-cli.gemspec +2 -2
  9. data/lib/hanami/cli/command.rb +2 -2
  10. data/lib/hanami/cli/commands/app/command.rb +2 -16
  11. data/lib/hanami/cli/commands/app/db/command.rb +148 -0
  12. data/lib/hanami/cli/commands/app/db/create.rb +21 -11
  13. data/lib/hanami/cli/commands/app/db/drop.rb +21 -10
  14. data/lib/hanami/cli/commands/app/db/migrate.rb +50 -12
  15. data/lib/hanami/cli/commands/app/db/prepare.rb +68 -0
  16. data/lib/hanami/cli/commands/app/db/seed.rb +22 -21
  17. data/lib/hanami/cli/commands/app/db/structure/dump.rb +32 -7
  18. data/lib/hanami/cli/commands/app/db/structure/load.rb +54 -0
  19. data/lib/hanami/cli/commands/app/db/utils/database.rb +100 -75
  20. data/lib/hanami/cli/commands/app/db/utils/mysql.rb +59 -6
  21. data/lib/hanami/cli/commands/app/db/utils/postgres.rb +42 -21
  22. data/lib/hanami/cli/commands/app/db/utils/sqlite.rb +58 -10
  23. data/lib/hanami/cli/commands/app/db/version.rb +14 -8
  24. data/lib/hanami/cli/commands/app/generate/action.rb +4 -3
  25. data/lib/hanami/cli/commands/app/generate/command.rb +60 -0
  26. data/lib/hanami/cli/commands/app/generate/component.rb +49 -0
  27. data/lib/hanami/cli/commands/app/generate/migration.rb +47 -0
  28. data/lib/hanami/cli/commands/app/generate/operation.rb +26 -0
  29. data/lib/hanami/cli/commands/app/generate/part.rb +1 -1
  30. data/lib/hanami/cli/commands/app/generate/relation.rb +29 -0
  31. data/lib/hanami/cli/commands/app/generate/repo.rb +42 -0
  32. data/lib/hanami/cli/commands/app/generate/slice.rb +20 -3
  33. data/lib/hanami/cli/commands/app/generate/struct.rb +27 -0
  34. data/lib/hanami/cli/commands/app/install.rb +1 -1
  35. data/lib/hanami/cli/commands/app/middleware.rb +1 -1
  36. data/lib/hanami/cli/commands/app/server.rb +2 -2
  37. data/lib/hanami/cli/commands/app.rb +21 -2
  38. data/lib/hanami/cli/commands/gem/new.rb +78 -14
  39. data/lib/hanami/cli/errors.rb +28 -0
  40. data/lib/hanami/cli/files.rb +22 -0
  41. data/lib/hanami/cli/generators/app/action_context.rb +5 -13
  42. data/lib/hanami/cli/generators/app/component/component.erb +8 -0
  43. data/lib/hanami/cli/generators/app/component/slice_component.erb +8 -0
  44. data/lib/hanami/cli/generators/app/component.rb +61 -0
  45. data/lib/hanami/cli/generators/app/component_context.rb +82 -0
  46. data/lib/hanami/cli/generators/app/migration.rb +66 -0
  47. data/lib/hanami/cli/generators/app/operation.rb +49 -0
  48. data/lib/hanami/cli/generators/app/part_context.rb +5 -21
  49. data/lib/hanami/cli/generators/app/relation.rb +45 -0
  50. data/lib/hanami/cli/generators/app/repo.rb +41 -0
  51. data/lib/hanami/cli/generators/app/ruby_file_writer.rb +151 -0
  52. data/lib/hanami/cli/generators/app/slice/{entities.erb → operation.erb} +1 -3
  53. data/lib/hanami/cli/generators/app/slice/relation.erb +8 -0
  54. data/lib/hanami/cli/generators/app/slice/{slice.erb → repo.erb} +3 -1
  55. data/lib/hanami/cli/generators/app/slice/struct.erb +8 -0
  56. data/lib/hanami/cli/generators/app/slice.rb +14 -6
  57. data/lib/hanami/cli/generators/app/slice_context.rb +9 -2
  58. data/lib/hanami/cli/generators/app/struct.rb +40 -0
  59. data/lib/hanami/cli/generators/app/view_context.rb +4 -16
  60. data/lib/hanami/cli/generators/constants.rb +39 -0
  61. data/lib/hanami/cli/generators/context.rb +48 -0
  62. data/lib/hanami/cli/generators/gem/app/action.erb +3 -0
  63. data/lib/hanami/cli/generators/gem/app/env.erb +4 -0
  64. data/lib/hanami/cli/generators/gem/app/gemfile.erb +11 -0
  65. data/lib/hanami/cli/generators/gem/app/gitignore.erb +4 -1
  66. data/lib/hanami/cli/generators/gem/app/operation.erb +13 -0
  67. data/lib/hanami/cli/generators/gem/app/relation.erb +10 -0
  68. data/lib/hanami/cli/generators/gem/app/repo.erb +10 -0
  69. data/lib/hanami/cli/generators/gem/app/struct.erb +10 -0
  70. data/lib/hanami/cli/generators/gem/app.rb +19 -0
  71. data/lib/hanami/cli/ruby_file_generator.rb +123 -0
  72. data/lib/hanami/cli/version.rb +1 -1
  73. metadata +39 -17
  74. data/lib/hanami/cli/commands/app/db/create_migration.rb +0 -32
  75. data/lib/hanami/cli/commands/app/db/reset.rb +0 -28
  76. data/lib/hanami/cli/commands/app/db/rollback.rb +0 -81
  77. data/lib/hanami/cli/commands/app/db/sample_data.rb +0 -42
  78. data/lib/hanami/cli/commands/app/db/setup.rb +0 -26
  79. data/lib/hanami/cli/commands/app/db/utils/database_config.rb +0 -60
  80. data/lib/hanami/cli/generators/app/slice/repository.erb +0 -10
@@ -18,7 +18,11 @@ module Hanami
18
18
  # @api private
19
19
  def write(path, *content)
20
20
  already_exists = exist?(path)
21
+
21
22
  super
23
+
24
+ delete_keepfiles(path) unless already_exists
25
+
22
26
  if already_exists
23
27
  updated(path)
24
28
  else
@@ -46,6 +50,24 @@ module Hanami
46
50
 
47
51
  attr_reader :out
48
52
 
53
+ # Removes .keep files in any directories leading up to the given path.
54
+ #
55
+ # Does not attempt to remove `.keep` files in the following scenarios:
56
+ # - When the given path is a `.keep` file itself.
57
+ # - When the given path is absolute, since ascending up this path may lead to removal of
58
+ # files outside the Hanami project directory.
59
+ def delete_keepfiles(path)
60
+ path = Pathname(path)
61
+
62
+ return if path.absolute?
63
+ return if path.relative_path_from(path.dirname).to_s == ".keep"
64
+
65
+ path.dirname.ascend do |part|
66
+ keepfile = (part + ".keep").to_path
67
+ delete(keepfile) if exist?(keepfile)
68
+ end
69
+ end
70
+
49
71
  def updated(path)
50
72
  out.puts "Updated #{path}"
51
73
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "slice_context"
4
3
  require "dry/files/path"
4
+ require_relative "slice_context"
5
+ require_relative "../constants"
5
6
 
6
7
  module Hanami
7
8
  module CLI
@@ -52,7 +53,7 @@ module Hanami
52
53
  # @api private
53
54
  def module_controller_declaration
54
55
  controller.each_with_index.map do |token, i|
55
- "#{OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
56
+ "#{NESTED_OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
56
57
  end.join($/)
57
58
  end
58
59
 
@@ -60,14 +61,14 @@ module Hanami
60
61
  # @api private
61
62
  def module_controller_end
62
63
  controller.each_with_index.map do |_, i|
63
- "#{OFFSET}#{INDENTATION * i}end"
64
+ "#{NESTED_OFFSET}#{INDENTATION * i}end"
64
65
  end.reverse.join($/)
65
66
  end
66
67
 
67
68
  # @since 2.0.0
68
69
  # @api private
69
70
  def module_controller_offset
70
- "#{OFFSET}#{INDENTATION * controller.count}"
71
+ "#{NESTED_OFFSET}#{INDENTATION * controller.count}"
71
72
  end
72
73
 
73
74
  # @since 2.0.0
@@ -79,15 +80,6 @@ module Hanami
79
80
 
80
81
  private
81
82
 
82
- NAMESPACE_SEPARATOR = "::"
83
- private_constant :NAMESPACE_SEPARATOR
84
-
85
- INDENTATION = " "
86
- private_constant :INDENTATION
87
-
88
- OFFSET = INDENTATION * 2
89
- private_constant :OFFSET
90
-
91
83
  attr_reader :controller
92
84
 
93
85
  attr_reader :action
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= camelized_app_name %>
4
+ <%= module_namespace_declaration %>
5
+ <%= module_namespace_offset %>class <%= camelized_name %>
6
+ <%= module_namespace_offset %>end
7
+ <%= module_namespace_end %>
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= camelized_slice_name %>
4
+ <%= module_namespace_declaration %>
5
+ <%= module_namespace_offset %>class <%= camelized_name %>
6
+ <%= module_namespace_offset %>end
7
+ <%= module_namespace_end %>
8
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "dry/files"
5
+ module Hanami
6
+ module CLI
7
+ module Generators
8
+ module App
9
+ # @api private
10
+ # @since 2.2.0
11
+ class Component
12
+ # @api private
13
+ # @since 2.2.0
14
+ def initialize(fs:, inflector:)
15
+ @fs = fs
16
+ @inflector = inflector
17
+ end
18
+
19
+ # @api private
20
+ # @since 2.2.0
21
+ def call(app, key, slice)
22
+ context = ComponentContext.new(inflector, app, slice, key)
23
+
24
+ if slice
25
+ generate_for_slice(context, slice)
26
+ else
27
+ generate_for_app(context)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :fs
34
+
35
+ attr_reader :inflector
36
+
37
+ def generate_for_slice(context, slice)
38
+ slice_directory = fs.join("slices", slice)
39
+ raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
40
+
41
+ fs.mkdir(directory = fs.join(slice_directory, context.namespaces))
42
+ fs.write(fs.join(directory, "#{context.underscored_name}.rb"), t("slice_component.erb", context))
43
+ end
44
+
45
+ def generate_for_app(context)
46
+ fs.mkdir(directory = fs.join("app", context.namespaces))
47
+ fs.write(fs.join(directory, "#{context.underscored_name}.rb"), t("component.erb", context))
48
+ end
49
+
50
+ def template(path, context)
51
+ ERB.new(
52
+ File.read(__dir__ + "/component/#{path}")
53
+ ).result(context.ctx)
54
+ end
55
+
56
+ alias_method :t, :template
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../constants"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Generators
8
+ module App
9
+ class ComponentContext < SliceContext
10
+ # @api private
11
+ # @since 2.2.0
12
+ attr_reader :key
13
+
14
+ # @api private
15
+ # @since 2.2.0
16
+ def initialize(inflector, app, slice, key)
17
+ @key = key
18
+ super(inflector, app, slice, nil)
19
+ end
20
+
21
+ # @api private
22
+ # @since 2.2.0
23
+ def namespaces
24
+ @namespaces ||= key.split(MATCHER_PATTERN)[..-2].map { inflector.underscore(_1) }
25
+ end
26
+
27
+ # @api private
28
+ # @since 2.2.0
29
+ def name
30
+ @name ||= key.split(MATCHER_PATTERN)[-1]
31
+ end
32
+
33
+ # @api private
34
+ # @since 2.2.0
35
+ def camelized_namespace
36
+ namespaces.map { inflector.camelize(_1) }.join(NAMESPACE_SEPARATOR)
37
+ end
38
+
39
+ # @api private
40
+ # @since 2.2.0
41
+ def camelized_name
42
+ inflector.camelize(name)
43
+ end
44
+
45
+ # @api private
46
+ # @since 2.2.0
47
+ def underscored_namespace
48
+ namespaces.map { inflector.underscore(_1) }
49
+ end
50
+
51
+ # @api private
52
+ # @since 2.2.0
53
+ def underscored_name
54
+ inflector.underscore(name)
55
+ end
56
+
57
+ # @api private
58
+ # @since 2.2.0
59
+ def module_namespace_declaration
60
+ namespaces.each_with_index.map { |token, i|
61
+ "#{OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
62
+ }.join($/)
63
+ end
64
+
65
+ # @api private
66
+ # @since 2.2.0
67
+ def module_namespace_end
68
+ namespaces.each_with_index.map { |_, i|
69
+ "#{OFFSET}#{INDENTATION * i}end"
70
+ }.reverse.join($/)
71
+ end
72
+
73
+ # @api private
74
+ # @since 2.2.0
75
+ def module_namespace_offset
76
+ "#{OFFSET}#{INDENTATION * namespaces.count}"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module CLI
5
+ module Generators
6
+ module App
7
+ # @since 2.2.0
8
+ # @api private
9
+ class Migration
10
+ # @since 2.2.0
11
+ # @api private
12
+ def initialize(fs:, inflector:, out: $stdout)
13
+ @fs = fs
14
+ @inflector = inflector
15
+ @out = out
16
+ end
17
+
18
+ # @since 2.2.0
19
+ # @api private
20
+ def call(key:, base_path:, gateway: nil, **_opts)
21
+ name = inflector.underscore(key)
22
+ ensure_valid_name(name)
23
+
24
+ base_path = nil if base_path == "app" # Migrations are in the root dir, not app/
25
+ migrate_dir = gateway ? "#{gateway}_migrate" : "migrate"
26
+
27
+ path = fs.join(*[base_path, "config", "db", migrate_dir, file_name(name)].compact)
28
+
29
+ fs.write(path, FILE_CONTENTS)
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :fs, :inflector, :out
35
+
36
+ VALID_NAME_REGEX = /^[_a-z0-9]+$/
37
+ private_constant :VALID_NAME_REGEX
38
+
39
+ def ensure_valid_name(name)
40
+ unless VALID_NAME_REGEX.match?(name.downcase)
41
+ raise InvalidMigrationNameError.new(name)
42
+ end
43
+ end
44
+
45
+ def file_name(name)
46
+ "#{Time.now.strftime(VERSION_FORMAT)}_#{name}.rb"
47
+ end
48
+
49
+ VERSION_FORMAT = "%Y%m%d%H%M%S"
50
+ private_constant :VERSION_FORMAT
51
+
52
+ FILE_CONTENTS = <<~RUBY
53
+ # frozen_string_literal: true
54
+
55
+ ROM::SQL.migration do
56
+ # Add your migration here.
57
+ #
58
+ # See https://sequel.jeremyevans.net/rdoc/files/doc/migration_rdoc.html for details.
59
+ end
60
+ RUBY
61
+ private_constant :FILE_CONTENTS
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../constants"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Generators
8
+ module App
9
+ # @since 2.2.0
10
+ # @api private
11
+ class Operation
12
+ # @since 2.2.0
13
+ # @api private
14
+ def initialize(fs:, inflector:, out: $stdout)
15
+ @fs = fs
16
+ @inflector = inflector
17
+ @out = out
18
+ end
19
+
20
+ # @since 2.2.0
21
+ # @api private
22
+ def call(key:, namespace:, base_path:)
23
+ RubyFileWriter.new(
24
+ fs: fs,
25
+ inflector: inflector,
26
+ ).call(
27
+ namespace: namespace,
28
+ base_path: base_path,
29
+ key: key,
30
+ relative_parent_class: "Operation",
31
+ body: ["def call", "end"],
32
+ )
33
+
34
+ unless key.match?(KEY_SEPARATOR)
35
+ out.puts(
36
+ " Note: We generated a top-level operation. " \
37
+ "To generate into a directory, add a namespace: `my_namespace.add_book`"
38
+ )
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :fs, :inflector, :out
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "slice_context"
4
3
  require "dry/files/path"
4
+ require_relative "slice_context"
5
+ require_relative "../constants"
5
6
 
6
7
  module Hanami
7
8
  module CLI
@@ -12,23 +13,6 @@ module Hanami
12
13
  # @since 2.1.0
13
14
  # @api private
14
15
  class PartContext < SliceContext
15
- # TODO: move these constants somewhere that will let us reuse them
16
-
17
- # @since 2.1.0
18
- # @api private
19
- KEY_SEPARATOR = "."
20
- private_constant :KEY_SEPARATOR
21
-
22
- # @since 2.1.0
23
- # @api private
24
- INDENTATION = " "
25
- private_constant :INDENTATION
26
-
27
- # @since 2.1.0
28
- # @api private
29
- OFFSET = INDENTATION * 2
30
- private_constant :OFFSET
31
-
32
16
  # @since 2.1.0
33
17
  # @api private
34
18
  attr_reader :key
@@ -74,7 +58,7 @@ module Hanami
74
58
  # @api private
75
59
  def module_namespace_declaration
76
60
  namespaces.each_with_index.map { |token, i|
77
- "#{OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
61
+ "#{NESTED_OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
78
62
  }.join($/)
79
63
  end
80
64
 
@@ -82,14 +66,14 @@ module Hanami
82
66
  # @api private
83
67
  def module_namespace_end
84
68
  namespaces.each_with_index.map { |_, i|
85
- "#{OFFSET}#{INDENTATION * i}end"
69
+ "#{NESTED_OFFSET}#{INDENTATION * i}end"
86
70
  }.reverse.join($/)
87
71
  end
88
72
 
89
73
  # @since 2.1.0
90
74
  # @api private
91
75
  def module_namespace_offset
92
- "#{OFFSET}#{INDENTATION * namespaces.count}"
76
+ "#{NESTED_OFFSET}#{INDENTATION * namespaces.count}"
93
77
  end
94
78
  end
95
79
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../constants"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Generators
8
+ module App
9
+ # @since 2.2.0
10
+ # @api private
11
+ class Relation
12
+ # @since 2.2.0
13
+ # @api private
14
+ def initialize(fs:, inflector:, out: $stdout)
15
+ @fs = fs
16
+ @inflector = inflector
17
+ @out = out
18
+ end
19
+
20
+ # @since 2.2.0
21
+ # @api private
22
+ def call(key:, namespace:, base_path:)
23
+ schema_name = key.split(KEY_SEPARATOR).last
24
+
25
+ RubyFileWriter.new(
26
+ fs: fs,
27
+ inflector: inflector,
28
+ ).call(
29
+ namespace: namespace,
30
+ key: key,
31
+ base_path: base_path,
32
+ extra_namespace: "Relations",
33
+ relative_parent_class: "DB::Relation",
34
+ body: ["schema :#{schema_name}, infer: true"],
35
+ )
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :fs, :inflector, :out
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module CLI
5
+ module Generators
6
+ module App
7
+ # @since 2.2.0
8
+ # @api private
9
+ class Repo
10
+ # @since 2.2.0
11
+ # @api private
12
+ def initialize(fs:, inflector:, out: $stdout)
13
+ @fs = fs
14
+ @inflector = inflector
15
+ @out = out
16
+ end
17
+
18
+ # @since 2.2.0
19
+ # @api private
20
+ def call(key:, namespace:, base_path:)
21
+ RubyFileWriter.new(
22
+ fs: fs,
23
+ inflector: inflector,
24
+ ).call(
25
+ key: key,
26
+ namespace: namespace,
27
+ base_path: base_path,
28
+ extra_namespace: "Repos",
29
+ relative_parent_class: "DB::Repo",
30
+ body: [],
31
+ )
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :fs, :inflector, :out
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "dry/files"
5
+ require_relative "../constants"
6
+ require_relative "../../errors"
7
+
8
+ module Hanami
9
+ module CLI
10
+ module Generators
11
+ module App
12
+ # @since 2.2.0
13
+ # @api private
14
+ class RubyFileWriter
15
+ # @since 2.2.0
16
+ # @api private
17
+ def initialize(fs:, inflector:)
18
+ @fs = fs
19
+ @inflector = inflector
20
+ end
21
+
22
+ # @since 2.2.0
23
+ # @api private
24
+ def call(key:, namespace:, base_path:, relative_parent_class:, extra_namespace: nil, body: [])
25
+ ClassFile.new(
26
+ fs: fs,
27
+ inflector: inflector,
28
+ key: key,
29
+ namespace: namespace,
30
+ base_path: base_path,
31
+ relative_parent_class: relative_parent_class,
32
+ extra_namespace: extra_namespace,
33
+ body: body,
34
+ ).write
35
+ end
36
+
37
+ private
38
+
39
+ # @since 2.2.0
40
+ # @api private
41
+ attr_reader :fs, :inflector
42
+ end
43
+
44
+ class ClassFile
45
+ def initialize(
46
+ fs:,
47
+ inflector:,
48
+ key:,
49
+ namespace:,
50
+ base_path:,
51
+ relative_parent_class:,
52
+ extra_namespace: nil,
53
+ body: []
54
+ )
55
+ @fs = fs
56
+ @inflector = inflector
57
+ @key = key
58
+ @namespace = namespace
59
+ @base_path = base_path
60
+ @extra_namespace = extra_namespace&.downcase
61
+ @relative_parent_class = relative_parent_class
62
+ @body = body
63
+ end
64
+
65
+ def write
66
+ fs.write(path, file_contents)
67
+ end
68
+
69
+ private
70
+
71
+ # @since 2.2.0
72
+ # @api private
73
+ attr_reader(
74
+ :fs,
75
+ :inflector,
76
+ :key,
77
+ :namespace,
78
+ :base_path,
79
+ :extra_namespace,
80
+ :relative_parent_class,
81
+ :body,
82
+ )
83
+
84
+ # @since 2.2.0
85
+ # @api private
86
+ def file_contents
87
+ class_definition(
88
+ class_name: class_name,
89
+ local_namespaces: local_namespaces,
90
+ )
91
+ end
92
+
93
+ # @since 2.2.0
94
+ # @api private
95
+ def class_name
96
+ key.split(KEY_SEPARATOR)[-1]
97
+ end
98
+
99
+ # @since 2.2.0
100
+ # @api private
101
+ def local_namespaces
102
+ Array(extra_namespace) + key.split(KEY_SEPARATOR)[..-2]
103
+ end
104
+
105
+ # @since 2.2.0
106
+ # @api private
107
+ def directory
108
+ @directory ||= if local_namespaces.any?
109
+ fs.join(base_path, local_namespaces)
110
+ else
111
+ base_path
112
+ end
113
+ end
114
+
115
+ # @since 2.2.0
116
+ # @api private
117
+ def path
118
+ fs.join(directory, "#{class_name}.rb")
119
+ end
120
+
121
+ # @since 2.2.0
122
+ # @api private
123
+ def class_definition(class_name:, local_namespaces:)
124
+ container_module = normalize(namespace)
125
+
126
+ modules = local_namespaces
127
+ .map { normalize(_1) }
128
+ .compact
129
+ .prepend(container_module)
130
+
131
+ parent_class = [container_module, relative_parent_class].join("::")
132
+
133
+ RubyFileGenerator.class(
134
+ normalize(class_name),
135
+ parent_class: parent_class,
136
+ modules: modules,
137
+ header: ["# frozen_string_literal: true"],
138
+ body: body
139
+ )
140
+ end
141
+
142
+ # @since 2.2.0
143
+ # @api private
144
+ def normalize(name)
145
+ inflector.camelize(name).gsub(/[^\p{Alnum}]/, "")
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -2,8 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module <%= camelized_slice_name %>
5
- module Entities
5
+ class Operation < <%= camelized_app_name %>::Operation
6
6
  end
7
7
  end
8
-
9
- Dir[File.join(__dir__, "entities", "*.rb")].each(&method(:require))
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= camelized_slice_name %>
4
+ module DB
5
+ class Relation < <%= camelized_app_name %>::DB::Relation
6
+ end
7
+ end
8
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module <%= camelized_slice_name %>
4
- class Slice < Hanami::Slice
4
+ module DB
5
+ class Repo < <%= camelized_app_name %>::DB::Repo
6
+ end
5
7
  end
6
8
  end