hanami-cli 2.2.0.beta1 → 2.2.0.rc1

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +13 -2
  3. data/.rubocop.yml +2 -0
  4. data/CHANGELOG.md +38 -2
  5. data/Gemfile +3 -0
  6. data/README.md +2 -0
  7. data/docker-compose.yml +6 -1
  8. data/lib/hanami/cli/command.rb +1 -1
  9. data/lib/hanami/cli/commands/app/command.rb +9 -3
  10. data/lib/hanami/cli/commands/app/console.rb +1 -5
  11. data/lib/hanami/cli/commands/app/db/command.rb +139 -31
  12. data/lib/hanami/cli/commands/app/db/create.rb +6 -2
  13. data/lib/hanami/cli/commands/app/db/drop.rb +6 -2
  14. data/lib/hanami/cli/commands/app/db/migrate.rb +49 -8
  15. data/lib/hanami/cli/commands/app/db/prepare.rb +36 -8
  16. data/lib/hanami/cli/commands/app/db/seed.rb +17 -1
  17. data/lib/hanami/cli/commands/app/db/structure/dump.rb +11 -6
  18. data/lib/hanami/cli/commands/app/db/structure/load.rb +9 -5
  19. data/lib/hanami/cli/commands/app/db/utils/database.rb +44 -14
  20. data/lib/hanami/cli/commands/app/db/utils/mysql.rb +57 -4
  21. data/lib/hanami/cli/commands/app/db/utils/postgres.rb +13 -8
  22. data/lib/hanami/cli/commands/app/db/version.rb +6 -3
  23. data/lib/hanami/cli/commands/app/generate/action.rb +12 -2
  24. data/lib/hanami/cli/commands/app/generate/command.rb +13 -2
  25. data/lib/hanami/cli/commands/app/generate/migration.rb +20 -0
  26. data/lib/hanami/cli/commands/app/generate/relation.rb +0 -6
  27. data/lib/hanami/cli/commands/app/generate/repo.rb +3 -7
  28. data/lib/hanami/cli/commands/app/generate/slice.rb +16 -3
  29. data/lib/hanami/cli/commands/app.rb +21 -9
  30. data/lib/hanami/cli/files.rb +22 -0
  31. data/lib/hanami/cli/generators/app/action.rb +27 -15
  32. data/lib/hanami/cli/generators/app/migration.rb +8 -9
  33. data/lib/hanami/cli/generators/app/operation.rb +5 -4
  34. data/lib/hanami/cli/generators/app/relation.rb +5 -4
  35. data/lib/hanami/cli/generators/app/repo.rb +5 -4
  36. data/lib/hanami/cli/generators/app/ruby_file_writer.rb +39 -37
  37. data/lib/hanami/cli/generators/app/slice.rb +5 -3
  38. data/lib/hanami/cli/generators/app/slice_context.rb +6 -0
  39. data/lib/hanami/cli/generators/app/struct.rb +5 -4
  40. data/lib/hanami/cli/generators/context.rb +4 -4
  41. data/lib/hanami/cli/generators/gem/app/gitignore.erb +3 -0
  42. data/lib/hanami/cli/generators/gem/app/operation.erb +0 -4
  43. data/lib/hanami/cli/generators/gem/app/seeds.erb +15 -0
  44. data/lib/hanami/cli/generators/gem/app.rb +3 -2
  45. data/lib/hanami/cli/repl/irb.rb +2 -2
  46. data/lib/hanami/cli/version.rb +1 -1
  47. metadata +4 -4
  48. data/lib/hanami/cli/generators/app/slice/entities.erb +0 -9
@@ -17,17 +17,14 @@ module Hanami
17
17
 
18
18
  # @since 2.2.0
19
19
  # @api private
20
- def call(_app_namespace, name, slice, **_opts)
21
- normalized_name = inflector.underscore(name)
22
- ensure_valid_name(normalized_name)
20
+ def call(key:, base_path:, gateway: nil, **_opts)
21
+ name = inflector.underscore(key)
22
+ ensure_valid_name(name)
23
23
 
24
- base = if slice
25
- fs.join("slices", slice, "config", "db", "migrate")
26
- else
27
- fs.join("config", "db", "migrate")
28
- end
24
+ base_path = nil if base_path == "app" # Migrations are in the root dir, not app/
25
+ migrate_dir = gateway ? "#{gateway}_migrate" : "migrate"
29
26
 
30
- path = fs.join(base, file_name(normalized_name))
27
+ path = fs.join(*[base_path, "config", "db", migrate_dir, file_name(name)].compact)
31
28
 
32
29
  fs.write(path, FILE_CONTENTS)
33
30
  end
@@ -59,6 +56,8 @@ module Hanami
59
56
  # Add your migration here.
60
57
  #
61
58
  # See https://sequel.jeremyevans.net/rdoc/files/doc/migration_rdoc.html for details.
59
+ change do
60
+ end
62
61
  end
63
62
  RUBY
64
63
  private_constant :FILE_CONTENTS
@@ -19,16 +19,17 @@ module Hanami
19
19
 
20
20
  # @since 2.2.0
21
21
  # @api private
22
- def call(app_namespace, key, slice)
22
+ def call(key:, namespace:, base_path:)
23
23
  RubyFileWriter.new(
24
24
  fs: fs,
25
25
  inflector: inflector,
26
- app_namespace: app_namespace,
26
+ ).call(
27
+ namespace: namespace,
28
+ base_path: base_path,
27
29
  key: key,
28
- slice: slice,
29
30
  relative_parent_class: "Operation",
30
31
  body: ["def call", "end"],
31
- ).call
32
+ )
32
33
 
33
34
  unless key.match?(KEY_SEPARATOR)
34
35
  out.puts(
@@ -19,19 +19,20 @@ module Hanami
19
19
 
20
20
  # @since 2.2.0
21
21
  # @api private
22
- def call(app_namespace, key, slice)
22
+ def call(key:, namespace:, base_path:)
23
23
  schema_name = key.split(KEY_SEPARATOR).last
24
24
 
25
25
  RubyFileWriter.new(
26
26
  fs: fs,
27
27
  inflector: inflector,
28
- app_namespace: app_namespace,
28
+ ).call(
29
+ namespace: namespace,
29
30
  key: key,
30
- slice: slice,
31
+ base_path: base_path,
31
32
  extra_namespace: "Relations",
32
33
  relative_parent_class: "DB::Relation",
33
34
  body: ["schema :#{schema_name}, infer: true"],
34
- ).call
35
+ )
35
36
  end
36
37
 
37
38
  private
@@ -17,17 +17,18 @@ module Hanami
17
17
 
18
18
  # @since 2.2.0
19
19
  # @api private
20
- def call(app_namespace, key, slice)
20
+ def call(key:, namespace:, base_path:)
21
21
  RubyFileWriter.new(
22
22
  fs: fs,
23
23
  inflector: inflector,
24
- app_namespace: app_namespace,
24
+ ).call(
25
25
  key: key,
26
- slice: slice,
26
+ namespace: namespace,
27
+ base_path: base_path,
27
28
  extra_namespace: "Repos",
28
29
  relative_parent_class: "DB::Repo",
29
30
  body: [],
30
- ).call
31
+ )
31
32
  end
32
33
 
33
34
  private
@@ -14,31 +14,55 @@ module Hanami
14
14
  class RubyFileWriter
15
15
  # @since 2.2.0
16
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
17
45
  def initialize(
18
46
  fs:,
19
47
  inflector:,
20
- app_namespace:,
21
48
  key:,
22
- slice:,
49
+ namespace:,
50
+ base_path:,
23
51
  relative_parent_class:,
24
52
  extra_namespace: nil,
25
53
  body: []
26
54
  )
27
55
  @fs = fs
28
56
  @inflector = inflector
29
- @app_namespace = app_namespace
30
57
  @key = key
31
- @slice = slice
58
+ @namespace = namespace
59
+ @base_path = base_path
32
60
  @extra_namespace = extra_namespace&.downcase
33
61
  @relative_parent_class = relative_parent_class
34
62
  @body = body
35
- raise_missing_slice_error_if_missing(slice) if slice
36
63
  end
37
64
 
38
- # @since 2.2.0
39
- # @api private
40
- def call
41
- fs.mkdir(directory)
65
+ def write
42
66
  fs.write(path, file_contents)
43
67
  end
44
68
 
@@ -49,9 +73,9 @@ module Hanami
49
73
  attr_reader(
50
74
  :fs,
51
75
  :inflector,
52
- :app_namespace,
53
76
  :key,
54
- :slice,
77
+ :namespace,
78
+ :base_path,
55
79
  :extra_namespace,
56
80
  :relative_parent_class,
57
81
  :body,
@@ -62,7 +86,6 @@ module Hanami
62
86
  def file_contents
63
87
  class_definition(
64
88
  class_name: class_name,
65
- container_namespace: container_namespace,
66
89
  local_namespaces: local_namespaces,
67
90
  )
68
91
  end
@@ -73,12 +96,6 @@ module Hanami
73
96
  key.split(KEY_SEPARATOR)[-1]
74
97
  end
75
98
 
76
- # @since 2.2.0
77
- # @api private
78
- def container_namespace
79
- slice || app_namespace
80
- end
81
-
82
99
  # @since 2.2.0
83
100
  # @api private
84
101
  def local_namespaces
@@ -88,16 +105,10 @@ module Hanami
88
105
  # @since 2.2.0
89
106
  # @api private
90
107
  def directory
91
- base = if slice
92
- fs.join("slices", slice)
93
- else
94
- fs.join("app")
95
- end
96
-
97
108
  @directory ||= if local_namespaces.any?
98
- fs.join(base, local_namespaces)
109
+ fs.join(base_path, local_namespaces)
99
110
  else
100
- fs.join(base)
111
+ base_path
101
112
  end
102
113
  end
103
114
 
@@ -109,8 +120,8 @@ module Hanami
109
120
 
110
121
  # @since 2.2.0
111
122
  # @api private
112
- def class_definition(class_name:, container_namespace:, local_namespaces:)
113
- container_module = normalize(container_namespace)
123
+ def class_definition(class_name:, local_namespaces:)
124
+ container_module = normalize(namespace)
114
125
 
115
126
  modules = local_namespaces
116
127
  .map { normalize(_1) }
@@ -133,15 +144,6 @@ module Hanami
133
144
  def normalize(name)
134
145
  inflector.camelize(name).gsub(/[^\p{Alnum}]/, "")
135
146
  end
136
-
137
- # @since 2.2.0
138
- # @api private
139
- def raise_missing_slice_error_if_missing(slice)
140
- if slice
141
- slice_directory = fs.join("slices", slice)
142
- raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
143
- end
144
- end
145
147
  end
146
148
  end
147
149
  end
@@ -22,9 +22,11 @@ module Hanami
22
22
  def call(app, slice, url, context: nil, **opts)
23
23
  context ||= SliceContext.new(inflector, app, slice, url, **opts)
24
24
 
25
- fs.inject_line_at_class_bottom(
26
- fs.join("config", "routes.rb"), "class Routes", t("routes.erb", context).chomp
27
- )
25
+ if context.generate_route?
26
+ fs.inject_line_at_class_bottom(
27
+ fs.join("config", "routes.rb"), "class Routes", t("routes.erb", context).chomp
28
+ )
29
+ end
28
30
 
29
31
  fs.mkdir(directory = "slices/#{slice}")
30
32
 
@@ -54,6 +54,12 @@ module Hanami
54
54
  !options.fetch(:skip_db, false)
55
55
  end
56
56
 
57
+ # @since 2.2.0
58
+ # @api private
59
+ def generate_route?
60
+ !options.fetch(:skip_route, false)
61
+ end
62
+
57
63
  private
58
64
 
59
65
  attr_reader :slice
@@ -17,16 +17,17 @@ module Hanami
17
17
 
18
18
  # @since 2.2.0
19
19
  # @api private
20
- def call(app_namespace, key, slice)
20
+ def call(key:, namespace:, base_path:)
21
21
  RubyFileWriter.new(
22
22
  fs: fs,
23
23
  inflector: inflector,
24
- app_namespace: app_namespace,
24
+ ).call(
25
25
  key: key,
26
- slice: slice,
26
+ namespace: namespace,
27
+ base_path: base_path,
27
28
  extra_namespace: "Structs",
28
29
  relative_parent_class: "DB::Struct",
29
- ).call
30
+ )
30
31
  end
31
32
 
32
33
  private
@@ -89,19 +89,19 @@ module Hanami
89
89
  # @since 2.2.0
90
90
  # @api private
91
91
  def generate_sqlite?
92
- database_option == Commands::Gem::New::DATABASE_SQLITE
92
+ generate_db? && database_option == Commands::Gem::New::DATABASE_SQLITE
93
93
  end
94
94
 
95
95
  # @since 2.2.0
96
96
  # @api private
97
97
  def generate_postgres?
98
- database_option == Commands::Gem::New::DATABASE_POSTGRES
98
+ generate_db? && database_option == Commands::Gem::New::DATABASE_POSTGRES
99
99
  end
100
100
 
101
101
  # @since 2.2.0
102
102
  # @api private
103
103
  def generate_mysql?
104
- database_option == Commands::Gem::New::DATABASE_MYSQL
104
+ generate_db? && database_option == Commands::Gem::New::DATABASE_MYSQL
105
105
  end
106
106
 
107
107
  # @since 2.2.0
@@ -112,7 +112,7 @@ module Hanami
112
112
  elsif generate_postgres?
113
113
  "postgres://localhost/#{app}"
114
114
  elsif generate_mysql?
115
- "mysql://localhost/#{app}"
115
+ "mysql2://root@localhost/#{app}"
116
116
  else
117
117
  raise "Unknown database option: #{database_option}"
118
118
  end
@@ -4,3 +4,6 @@ log/*
4
4
  public/
5
5
  node_modules/
6
6
  <%- end -%>
7
+ <%- if generate_sqlite? -%>
8
+ db/*.sqlite
9
+ <%- end -%>
@@ -5,9 +5,5 @@ require "dry/operation"
5
5
 
6
6
  module <%= camelized_app_name %>
7
7
  class Operation < Dry::Operation
8
- <%- if generate_db? -%>
9
- # Provide `transaction do ... end` method for database transactions
10
- include Dry::Operation::Extensions::ROM
11
- <%- end -%>
12
8
  end
13
9
  end
@@ -0,0 +1,15 @@
1
+ # This seeds file should create the database records required to run the app.
2
+ #
3
+ # The code should be idempotent so that it can be executed at any time.
4
+ #
5
+ # To load the seeds, run `hanami db seed`. Seeds are also loaded as part of `hanami db prepare`.
6
+
7
+ # For example, if you have appropriate repos available:
8
+ #
9
+ # category_repo = Hanami.app["repos.category_repo"]
10
+ # category_repo.create(title: "General")
11
+ #
12
+ # Alternatively, you can use relations directly:
13
+ #
14
+ # categories = Hanami.app["relations.categories"]
15
+ # categories.insert(title: "General")
@@ -78,10 +78,11 @@ module Hanami
78
78
  fs.write("app/db/struct.rb", t("struct.erb", context))
79
79
  fs.write("app/structs/.keep", t("keep.erb", context))
80
80
 
81
- fs.write("config/db/migrate/.keep" , t("keep.erb", context))
81
+ fs.write("config/db/seeds.rb", t("seeds.erb", context))
82
+ fs.write("config/db/migrate/.keep", t("keep.erb", context))
82
83
 
83
84
  if context.generate_sqlite?
84
- fs.write("db/.keep" , t("keep.erb", context))
85
+ fs.write("db/.keep", t("keep.erb", context))
85
86
  end
86
87
  end
87
88
 
@@ -24,8 +24,8 @@ module Hanami
24
24
  AUTO_INDENT: true,
25
25
  PROMPT_I: "#{prompt}> ",
26
26
  PROMPT_N: "#{prompt}> ",
27
- PROMPT_S: "#{prompt} %l> ",
28
- PROMPT_C: "#{prompt} ?> ",
27
+ PROMPT_S: "#{prompt}%l ",
28
+ PROMPT_C: "#{prompt}* ",
29
29
  RETURN: "=> %s\n"
30
30
  }
31
31
 
@@ -6,6 +6,6 @@ module Hanami
6
6
  #
7
7
  # @api public
8
8
  # @since 2.0.0
9
- VERSION = "2.2.0.beta1"
9
+ VERSION = "2.2.0.rc1"
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0.beta1
4
+ version: 2.2.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-07-16 00:00:00.000000000 Z
11
+ date: 2024-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -263,7 +263,6 @@ files:
263
263
  - lib/hanami/cli/generators/app/slice/app_css.erb
264
264
  - lib/hanami/cli/generators/app/slice/app_js.erb
265
265
  - lib/hanami/cli/generators/app/slice/app_layout.erb
266
- - lib/hanami/cli/generators/app/slice/entities.erb
267
266
  - lib/hanami/cli/generators/app/slice/favicon.ico
268
267
  - lib/hanami/cli/generators/app/slice/helpers.erb
269
268
  - lib/hanami/cli/generators/app/slice/keep.erb
@@ -309,6 +308,7 @@ files:
309
308
  - lib/hanami/cli/generators/gem/app/relation.erb
310
309
  - lib/hanami/cli/generators/gem/app/repo.erb
311
310
  - lib/hanami/cli/generators/gem/app/routes.erb
311
+ - lib/hanami/cli/generators/gem/app/seeds.erb
312
312
  - lib/hanami/cli/generators/gem/app/settings.erb
313
313
  - lib/hanami/cli/generators/gem/app/struct.erb
314
314
  - lib/hanami/cli/generators/gem/app/types.erb
@@ -354,7 +354,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
354
354
  - !ruby/object:Gem::Version
355
355
  version: '0'
356
356
  requirements: []
357
- rubygems_version: 3.5.9
357
+ rubygems_version: 3.5.22
358
358
  signing_key:
359
359
  specification_version: 4
360
360
  summary: Hanami CLI
@@ -1,9 +0,0 @@
1
- # auto_register: false
2
- # frozen_string_literal: true
3
-
4
- module <%= camelized_slice_name %>
5
- module Entities
6
- end
7
- end
8
-
9
- Dir[File.join(__dir__, "entities", "*.rb")].each(&method(:require))