hanami-cli 2.0.3 → 2.1.0.beta1

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +1 -1
  5. data/lib/hanami/cli/bundler.rb +2 -2
  6. data/lib/hanami/cli/commands/app/db/rollback.rb +30 -6
  7. data/lib/hanami/cli/commands/app/db/utils/database.rb +5 -1
  8. data/lib/hanami/cli/commands/app/generate/action.rb +2 -2
  9. data/lib/hanami/cli/commands/app/generate/view.rb +57 -0
  10. data/lib/hanami/cli/commands/app/generate.rb +2 -2
  11. data/lib/hanami/cli/commands/app.rb +1 -0
  12. data/lib/hanami/cli/generators/app/action/slice_template.html.erb +1 -0
  13. data/lib/hanami/cli/generators/app/action/slice_view.erb +10 -0
  14. data/lib/hanami/cli/generators/app/action/template.html.erb +1 -2
  15. data/lib/hanami/cli/generators/app/action/view.erb +2 -5
  16. data/lib/hanami/cli/generators/app/action.rb +31 -16
  17. data/lib/hanami/cli/generators/app/action_context.rb +1 -1
  18. data/lib/hanami/cli/generators/app/slice/helpers.erb +10 -0
  19. data/lib/hanami/cli/generators/app/slice/layouts_app.html.erb +1 -0
  20. data/lib/hanami/cli/generators/app/slice/view.erb +0 -2
  21. data/lib/hanami/cli/generators/app/slice.rb +8 -5
  22. data/lib/hanami/cli/generators/app/view/app_template.html.erb +1 -0
  23. data/lib/hanami/cli/generators/app/view/app_view.erb +10 -0
  24. data/lib/hanami/cli/generators/app/view/slice_template.html.erb +1 -0
  25. data/lib/hanami/cli/generators/app/view/slice_view.erb +10 -0
  26. data/lib/hanami/cli/generators/app/view.rb +89 -0
  27. data/lib/hanami/cli/generators/app/view_context.rb +100 -0
  28. data/lib/hanami/cli/generators/context.rb +1 -1
  29. data/lib/hanami/cli/generators/gem/app/404.html +11 -0
  30. data/lib/hanami/cli/generators/gem/app/500.html +11 -0
  31. data/lib/hanami/cli/generators/gem/app/gemfile.erb +2 -0
  32. data/lib/hanami/cli/generators/gem/app/helpers.erb +10 -0
  33. data/lib/hanami/cli/generators/gem/app/layouts_app.html.erb +1 -0
  34. data/lib/hanami/cli/generators/gem/app/puma.erb +5 -3
  35. data/lib/hanami/cli/generators/gem/app/view.erb +9 -0
  36. data/lib/hanami/cli/generators/gem/app.rb +6 -0
  37. data/lib/hanami/cli/url.rb +1 -1
  38. data/lib/hanami/cli/version.rb +1 -1
  39. metadata +21 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bcebd7bee28802b90462073bbc9def8c6f1c13b7fc032cc8f20859b082310a4
4
- data.tar.gz: fd38025e1fa7a2b5c6650710e16076fefa8f8697a1b3bba3035eedaa9ce612b4
3
+ metadata.gz: '078a7a10f1196ed8635a9c27ee48ac10178cdcff50d2646138f61b55f79f86a7'
4
+ data.tar.gz: 870c056fc5da9f5952daf357ca2861f0e276510c6ca1e63a2f821af76ebdd09a
5
5
  SHA512:
6
- metadata.gz: bdebf6ac07bfad66d9a7d37050ce6b91c7d29abc781c44807a0efdc8c7085db42ed7afcbf5b5b32f264213499e59d31754823a670eb43d71acee1be39dd0b5c2
7
- data.tar.gz: 56a41e42c83896516b0b20d7aea8864743c9a96508fd520d226de683d59de612a85cd99e83f7ed50bf39cfa87564152afb903bbfdc6d4d8e48ed9eb1904705e1
6
+ metadata.gz: d70ee9d87779f442c25517abfefde102460848e8a29ba9ef30ae28cc2b2593f73027dad42b99e5617820952a84fd22013a8de5d039fb2e6161a64fd2eef706a1
7
+ data.tar.gz: 815418cd1c416bea1f7a77c56dff20ed143b582795bbcd79904260509c8c62c7d62a7be76c11305d26dc793dd2c2a13fcba0532c365ad47278212159e40eff69
data/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  Hanami Command Line Interface
4
4
 
5
+ ## v2.1.0.beta1 - 2023-06-29
6
+
7
+ ### Added
8
+
9
+ - [Tim Riley] `hanami new` to generate default views, templates, and helpers
10
+ - [Tim Riley] `hanami generate slice` to generate default views, templates, and helpers
11
+ - [Tim Riley] `hanami generate action` to generate associated view and template
12
+ - [Tim Riley] Introduced `hanami generate view`
13
+ - [Tim Riley] `hanami new` to generate `Gemfile` with `hanami-view` and `hanami-webconsole` gems
14
+ - [Tim Riley] `hanami new` to generate default error pages for `404` and `500` HTTP errors
15
+
16
+ ### Fixed
17
+
18
+ - [Philip Arndt] `hanami server` to start only one Puma worker by default
19
+
5
20
  ## v2.0.3 - 2023-02-01
6
21
 
7
22
  ### Added
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2014-2022 Luca Guidi
1
+ Copyright © 2014 Hanami Team
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -44,4 +44,4 @@ Everyone interacting in the `Hanami::CLI` project's codebases, issue trackers, c
44
44
 
45
45
  ## Copyright
46
46
 
47
- Copyright © 2014-2022 Hanami Team – Released under MIT License
47
+ Copyright © 2014 Hanami Team – Released under MIT License
@@ -4,8 +4,8 @@ require "bundler"
4
4
  require "open3"
5
5
  require "etc"
6
6
  require "dry/files"
7
- require_relative "./system_call"
8
- require_relative "./errors"
7
+ require_relative "system_call"
8
+ require_relative "errors"
9
9
 
10
10
  module Hanami
11
11
  module CLI
@@ -20,12 +20,20 @@ module Hanami
20
20
  migration_code, migration_name = find_migration(target)
21
21
 
22
22
  if migration_name.nil?
23
- out.puts "==> migration file for target #{target} was not found"
23
+ output = if target
24
+ "==> migration file for target #{target} was not found"
25
+ else
26
+ "==> no migrations to rollback"
27
+ end
28
+
29
+ out.puts output
24
30
  return
25
31
  end
26
32
 
27
33
  measure "database #{database.name} rolled back to #{migration_name}" do
28
34
  database.run_migrations(target: Integer(migration_code))
35
+
36
+ true
29
37
  end
30
38
 
31
39
  run_command Structure::Dump if dump
@@ -33,14 +41,30 @@ module Hanami
33
41
 
34
42
  private
35
43
 
36
- def find_migration(code)
37
- migration = database.applied_migrations.then { |migrations|
44
+ def find_migration(code) # rubocop:disable Metrics/PerceivedComplexity
45
+ applied_migrations = database.applied_migrations
46
+
47
+ return if applied_migrations.empty?
48
+
49
+ # Rollback to initial state if we have only one migration and
50
+ # no target is specified. In this case the rollback target
51
+ # will be the current migration timestamp minus 1
52
+ if applied_migrations.one? && code.nil?
53
+ migration = applied_migrations.first
54
+
55
+ migration_code = Integer(migration.split("_").first) - 1
56
+ migration_name = "initial state"
57
+
58
+ return [migration_code, migration_name]
59
+ end
60
+
61
+ # Otherwise rollback to target or to previous migration
62
+ migration =
38
63
  if code
39
- migrations.detect { |m| m.split("_").first == code }
64
+ applied_migrations.detect { |m| m.split("_").first == code }
40
65
  else
41
- migrations.last
66
+ applied_migrations[-2]
42
67
  end
43
- }
44
68
 
45
69
  return unless migration
46
70
 
@@ -139,7 +139,11 @@ module Hanami
139
139
  @sequel_migrator ||= begin
140
140
  require "sequel"
141
141
  Sequel.extension :migration
142
- Sequel::TimestampMigrator.new(migrator.connection, migrations_path, {})
142
+
143
+ require "rom/sql"
144
+ ROM::SQL.with_gateway(gateway) do
145
+ Sequel::TimestampMigrator.new(migrator.connection, migrations_path, {})
146
+ end
143
147
  end
144
148
  end
145
149
 
@@ -26,8 +26,8 @@ module Hanami
26
26
  option :url, required: false, type: :string, desc: "Action URL"
27
27
  option :http, required: false, type: :string, desc: "Action HTTP method"
28
28
  # option :format, required: false, type: :string, default: DEFAULT_FORMAT, desc: "Template format"
29
- # option :skip_view, required: false, type: :boolean, default: DEFAULT_SKIP_VIEW,
30
- # desc: "Skip view and template generation"
29
+ option :skip_view, required: false, type: :boolean, default: DEFAULT_SKIP_VIEW,
30
+ desc: "Skip view and template generation"
31
31
  option :slice, required: false, desc: "Slice name"
32
32
 
33
33
  # rubocop:disable Layout/LineLength
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/inflector"
4
+ require "dry/files"
5
+ require "shellwords"
6
+ require_relative "../../../naming"
7
+ require_relative "../../../errors"
8
+
9
+ module Hanami
10
+ module CLI
11
+ module Commands
12
+ module App
13
+ module Generate
14
+ # @since 2.0.0
15
+ # @api private
16
+ class View < App::Command
17
+ # TODO: make this configurable
18
+ DEFAULT_FORMAT = "html"
19
+ private_constant :DEFAULT_FORMAT
20
+
21
+ # TODO: make engine configurable
22
+
23
+ argument :name, required: true, desc: "View name"
24
+ option :slice, required: false, desc: "Slice name"
25
+
26
+ example [
27
+ %(books.index (MyApp::Actions::Books::Index)),
28
+ %(books.index --slice=admin (Admin::Actions::Books::Index)),
29
+ ]
30
+ attr_reader :generator
31
+ private :generator
32
+
33
+ # @since 2.0.0
34
+ # @api private
35
+ def initialize(
36
+ fs: Hanami::CLI::Files.new,
37
+ inflector: Dry::Inflector.new,
38
+ generator: Generators::App::View.new(fs: fs, inflector: inflector),
39
+ **
40
+ )
41
+ @generator = generator
42
+ super(fs: fs)
43
+ end
44
+
45
+ # @since 2.0.0
46
+ # @api private
47
+ def call(name:, format: DEFAULT_FORMAT, slice: nil, **)
48
+ slice = inflector.underscore(Shellwords.shellescape(slice)) if slice
49
+
50
+ generator.call(app.namespace, name, format, slice)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -7,8 +7,8 @@ module Hanami
7
7
  # @since 2.0.0
8
8
  # @api private
9
9
  module Generate
10
- require_relative "./generate/slice"
11
- require_relative "./generate/action"
10
+ require_relative "generate/slice"
11
+ require_relative "generate/action"
12
12
  end
13
13
  end
14
14
  end
@@ -22,6 +22,7 @@ module Hanami
22
22
  register "generate", aliases: ["g"] do |prefix|
23
23
  prefix.register "slice", Generate::Slice
24
24
  prefix.register "action", Generate::Action
25
+ prefix.register "view", Generate::View
25
26
  end
26
27
  end
27
28
  end
@@ -0,0 +1 @@
1
+ <h1><%= camelized_slice_name %>::Views::<%= camelized_controller_name %>::<%= camelized_action_name %></h1>
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= camelized_slice_name %>
4
+ module Views
5
+ <%= module_controller_declaration %>
6
+ <%= module_controller_offset %>class <%= camelized_action_name %> < <%= camelized_slice_name %>::View
7
+ <%= module_controller_offset %>end
8
+ <%= module_controller_end %>
9
+ end
10
+ end
@@ -1,2 +1 @@
1
- <h1><%= camelized_slice_name %>::Views::<%= camelized_controller_name %>::<%= camelized_action_name %></h1>
2
- <h2><%= template_path %></h2>
1
+ <h1><%= camelized_app_name %>::Views::<%= camelized_controller_name %>::<%= camelized_action_name %></h1>
@@ -1,12 +1,9 @@
1
- # auto_register: false
2
1
  # frozen_string_literal: true
3
2
 
4
- require "<%= underscored_slice_name %>/view"
5
-
6
- module <%= camelized_slice_name %>
3
+ module <%= camelized_app_name %>
7
4
  module Views
8
5
  <%= module_controller_declaration %>
9
- <%= module_controller_offset %>class <%= camelized_action_name %> < <%= camelized_slice_name %>::View
6
+ <%= module_controller_offset %>class <%= camelized_action_name %> < <%= camelized_app_name %>::View
10
7
  <%= module_controller_offset %>end
11
8
  <%= module_controller_end %>
12
9
  end
@@ -66,7 +66,8 @@ module Hanami
66
66
 
67
67
  attr_reader :inflector
68
68
 
69
- def generate_for_slice(controller, action, url, http, _format, _skip_view, slice, context)
69
+ # rubocop:disable Metrics/AbcSize
70
+ def generate_for_slice(controller, action, url, http, format, skip_view, slice, context)
70
71
  slice_directory = fs.join("slices", slice)
71
72
  raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
72
73
 
@@ -79,16 +80,17 @@ module Hanami
79
80
  fs.mkdir(directory = fs.join(slice_directory, "actions", controller))
80
81
  fs.write(fs.join(directory, "#{action}.rb"), t("slice_action.erb", context))
81
82
 
82
- # unless skip_view
83
- # fs.mkdir(directory = fs.join(slice_directory, "views", controller))
84
- # fs.write(fs.join(directory, "#{action}.rb"), t("view.erb", context))
85
- #
86
- # fs.mkdir(directory = fs.join(slice_directory, "templates", controller))
87
- # fs.write(fs.join(directory, "#{action}.#{format}.erb"), t(template_format(format), context))
88
- # end
83
+ unless skip_view
84
+ fs.mkdir(directory = fs.join(slice_directory, "views", controller))
85
+ fs.write(fs.join(directory, "#{action}.rb"), t("slice_view.erb", context))
86
+
87
+ fs.mkdir(directory = fs.join(slice_directory, "templates", controller))
88
+ fs.write(fs.join(directory, "#{action}.#{format}.erb"),
89
+ t(template_with_format_ext("slice_template", format), context))
90
+ end
89
91
  end
90
92
 
91
- def generate_for_app(controller, action, url, http, _format, _skip_view, context)
93
+ def generate_for_app(controller, action, url, http, format, skip_view, context)
92
94
  fs.inject_line_at_class_bottom(
93
95
  fs.join("config", "routes.rb"),
94
96
  "class Routes",
@@ -97,7 +99,17 @@ module Hanami
97
99
 
98
100
  fs.mkdir(directory = fs.join("app", "actions", controller))
99
101
  fs.write(fs.join(directory, "#{action}.rb"), t("action.erb", context))
102
+
103
+ unless skip_view
104
+ fs.mkdir(directory = fs.join("app", "views", controller))
105
+ fs.write(fs.join(directory, "#{action}.rb"), t("view.erb", context))
106
+
107
+ fs.mkdir(directory = fs.join("app", "templates", controller))
108
+ fs.write(fs.join(directory, "#{action}.#{format}.erb"),
109
+ t(template_with_format_ext("template", format), context))
110
+ end
100
111
  end
112
+ # rubocop:enable Metrics/AbcSize
101
113
 
102
114
  def slice_matcher(slice)
103
115
  /slice[[:space:]]*:#{slice}/
@@ -108,13 +120,16 @@ module Hanami
108
120
  http)} "#{route_url(controller, action, url)}", to: "#{controller.join('.')}.#{action}")
109
121
  end
110
122
 
111
- def template_format(format)
112
- case format.to_sym
113
- when :html
114
- "template.html.erb"
115
- else
116
- "template.erb"
117
- end
123
+ def template_with_format_ext(name, format)
124
+ ext =
125
+ case format.to_sym
126
+ when :html
127
+ ".html.erb"
128
+ else
129
+ ".erb"
130
+ end
131
+
132
+ "#{name}#{ext}"
118
133
  end
119
134
 
120
135
  def template(path, context)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "./slice_context"
3
+ require_relative "slice_context"
4
4
  require "dry/files/path"
5
5
 
6
6
  module Hanami
@@ -0,0 +1,10 @@
1
+ # auto_register: false
2
+ # frozen_string_literal: true
3
+
4
+ module <%= camelized_slice_name %>
5
+ module Views
6
+ module Helpers
7
+ # Add your view helpers here
8
+ end
9
+ end
10
+ end
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -1,8 +1,6 @@
1
1
  # auto_register: false
2
2
  # frozen_string_literal: true
3
3
 
4
- require "<%= underscored_app_name %>/view"
5
-
6
4
  module <%= camelized_slice_name %>
7
5
  class View < <%= camelized_app_name %>::View
8
6
  end
@@ -19,7 +19,7 @@ module Hanami
19
19
 
20
20
  # @since 2.0.0
21
21
  # @api private
22
- def call(app, slice, url, context: SliceContext.new(inflector, app, slice, url))
22
+ def call(app, slice, url, context: SliceContext.new(inflector, app, slice, url)) # rubocop:disable Metrics/AbcSize
23
23
  fs.inject_line_at_class_bottom(
24
24
  fs.join("config", "routes.rb"), "class Routes", t("routes.erb", context).chomp
25
25
  )
@@ -28,14 +28,17 @@ module Hanami
28
28
 
29
29
  # fs.write("#{directory}/config/slice.rb", t("slice.erb", context))
30
30
  fs.write(fs.join(directory, "action.rb"), t("action.erb", context))
31
- # fs.write(fs.join(directory, "/view.rb"), t("view.erb", context))
31
+ fs.write(fs.join(directory, "view.rb"), t("view.erb", context))
32
+ fs.write(fs.join(directory, "views", "helpers.rb"), t("helpers.erb", context))
33
+ fs.write(fs.join(directory, "templates", "layouts", "app.html.erb"),
34
+ File.read(File.join(__dir__, "slice", "layouts_app.html.erb")))
32
35
  # fs.write(fs.join(directory, "/entities.rb"), t("entities.erb", context))
33
36
  # fs.write(fs.join(directory, "/repository.rb"), t("repository.erb", context))
34
37
 
35
38
  fs.write(fs.join(directory, "actions/.keep"), t("keep.erb", context))
36
- # fs.write(fs.join(directory, views/.keep"), t("keep.erb", context))
37
- # fs.write(fs.join(directory, templates/.keep"), t("keep.erb", context))
38
- # fs.write(fs.join(directory, templates/layouts/.keep"), t("keep.erb", context))
39
+ fs.write(fs.join(directory, "views/.keep"), t("keep.erb", context))
40
+ fs.write(fs.join(directory, "templates/.keep"), t("keep.erb", context))
41
+ fs.write(fs.join(directory, "templates/layouts/.keep"), t("keep.erb", context))
39
42
  # fs.write(fs.join(directory, entities/.keep"), t("keep.erb", context))
40
43
  # fs.write(fs.join(directory, repositories/.keep"), t("keep.erb", context))
41
44
  end
@@ -0,0 +1 @@
1
+ <h1><%= camelized_app_name %>::Views::<%= camelized_namespace %>::<%= camelized_name %></h1>
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= camelized_app_name %>
4
+ module Views
5
+ <%= module_namespace_declaration %>
6
+ <%= module_namespace_offset %>class <%= camelized_name %> < <%= camelized_app_name %>::View
7
+ <%= module_namespace_offset %>end
8
+ <%= module_namespace_end %>
9
+ end
10
+ end
@@ -0,0 +1 @@
1
+ <h1><%= camelized_slice_name %>::Views::<%= camelized_namespace %>::<%= camelized_name %></h1>
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= camelized_slice_name %>
4
+ module Views
5
+ <%= module_namespace_declaration %>
6
+ <%= module_namespace_offset %>class <%= camelized_name %> < <%= camelized_slice_name %>::View
7
+ <%= module_namespace_offset %>end
8
+ <%= module_namespace_end %>
9
+ end
10
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "dry/files"
5
+ require_relative "../../errors"
6
+
7
+ module Hanami
8
+ module CLI
9
+ module Generators
10
+ module App
11
+ # @since 2.0.0
12
+ # @api private
13
+ class View
14
+ # @since 2.0.0
15
+ # @api private
16
+ def initialize(fs:, inflector:)
17
+ @fs = fs
18
+ @inflector = inflector
19
+ end
20
+
21
+ # @since 2.0.0
22
+ # @api private
23
+ def call(app, key, format, slice)
24
+ context = ViewContext.new(inflector, app, slice, key)
25
+
26
+ if slice
27
+ generate_for_slice(context, format, slice)
28
+ else
29
+ generate_for_app(context, format, slice)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :fs
36
+
37
+ attr_reader :inflector
38
+
39
+ # rubocop:disable Metrics/AbcSize
40
+
41
+ def generate_for_slice(context, format, slice)
42
+ slice_directory = fs.join("slices", slice)
43
+ raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
44
+
45
+ fs.mkdir(directory = fs.join(slice_directory, "views", context.namespaces))
46
+ fs.write(fs.join(directory, "#{context.name}.rb"), t("slice_view.erb", context))
47
+
48
+ fs.mkdir(directory = fs.join(slice_directory, "templates", context.namespaces))
49
+ fs.write(fs.join(directory, "#{context.name}.#{format}.erb"),
50
+ t(template_with_format_ext("slice_template", format), context))
51
+ end
52
+
53
+ def generate_for_app(context, format, _slice)
54
+ fs.mkdir(directory = fs.join("app", "views", context.namespaces))
55
+ fs.write(fs.join(directory, "#{context.name}.rb"), t("app_view.erb", context))
56
+
57
+ fs.mkdir(directory = fs.join("app", "templates", context.namespaces))
58
+ fs.write(fs.join(directory, "#{context.name}.#{format}.erb"),
59
+ t(template_with_format_ext("app_template", format), context))
60
+ end
61
+
62
+ # rubocop:enable Metrics/AbcSize
63
+
64
+ def template_with_format_ext(name, format)
65
+ ext =
66
+ case format.to_sym
67
+ when :html
68
+ ".html.erb"
69
+ else
70
+ ".erb"
71
+ end
72
+
73
+ "#{name}#{ext}"
74
+ end
75
+
76
+ def template(path, context)
77
+ require "erb"
78
+
79
+ ERB.new(
80
+ File.read(__dir__ + "/view/#{path}")
81
+ ).result(context.ctx)
82
+ end
83
+
84
+ alias_method :t, :template
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "slice_context"
4
+ require "dry/files/path"
5
+
6
+ module Hanami
7
+ module CLI
8
+ module Generators
9
+ # @since 2.1.0
10
+ # @api private
11
+ module App
12
+ # @since 2.1.0
13
+ # @api private
14
+ class ViewContext < SliceContext
15
+ # TODO: move these constants somewhere that will let us reuse them
16
+ KEY_SEPARATOR = "."
17
+ private_constant :KEY_SEPARATOR
18
+
19
+ NAMESPACE_SEPARATOR = "::"
20
+ private_constant :NAMESPACE_SEPARATOR
21
+
22
+ INDENTATION = " "
23
+ private_constant :INDENTATION
24
+
25
+ OFFSET = INDENTATION * 2
26
+ private_constant :OFFSET
27
+
28
+ # @since 2.1.0
29
+ # @api private
30
+ attr_reader :key
31
+
32
+ # @since 2.1.0
33
+ # @api private
34
+ def initialize(inflector, app, slice, key)
35
+ @key = key
36
+ super(inflector, app, slice, nil)
37
+ end
38
+
39
+ # @since 2.1.0
40
+ # @api private
41
+ def namespaces
42
+ @namespaces ||= key.split(KEY_SEPARATOR)[..-2]
43
+ end
44
+
45
+ # @since 2.1.0
46
+ # @api private
47
+ def name
48
+ @name ||= key.split(KEY_SEPARATOR)[-1]
49
+ end
50
+
51
+ # @since 2.1.0
52
+ # @api private
53
+ def camelized_namespace
54
+ namespaces.map { inflector.camelize(_1) }.join(NAMESPACE_SEPARATOR)
55
+ end
56
+
57
+ # @since 2.1.0
58
+ # @api private
59
+ def camelized_name
60
+ inflector.camelize(name)
61
+ end
62
+
63
+ # @since 2.1.0
64
+ # @api private
65
+ def underscored_namespace
66
+ namespaces.map { inflector.underscore(_1) }
67
+ end
68
+
69
+ # @since 2.1.0
70
+ # @api private
71
+ def underscored_name
72
+ inflector.underscore(name)
73
+ end
74
+
75
+ # @since 2.1.0
76
+ # @api private
77
+ def module_namespace_declaration
78
+ namespaces.each_with_index.map { |token, i|
79
+ "#{OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
80
+ }.join($/)
81
+ end
82
+
83
+ # @since 2.1.0
84
+ # @api private
85
+ def module_namespace_end
86
+ namespaces.each_with_index.map { |_, i|
87
+ "#{OFFSET}#{INDENTATION * i}end"
88
+ }.reverse.join($/)
89
+ end
90
+
91
+ # @since 2.1.0
92
+ # @api private
93
+ def module_namespace_offset
94
+ "#{OFFSET}#{INDENTATION * namespaces.count}"
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "./version"
3
+ require_relative "version"
4
4
 
5
5
  module Hanami
6
6
  module CLI
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn’t exist (404)</title>
5
+ </head>
6
+ <body>
7
+ <!-- This file lives in public/404.html -->
8
+ <h1>The page you were looking for doesn’t exist.</h1>
9
+ <p>You may have mistyped the address or the page may have moved.</p>
10
+ </body>
11
+ </html>
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We’re sorry, but something went wrong (500)</title>
5
+ </head>
6
+ <body>
7
+ <!-- This file lives in public/500.html -->
8
+ <h1>We’re sorry, but something went wrong.</h1>
9
+ <p>If you are the application owner, check the logs for more information.</p>
10
+ </body>
11
+ </html>
@@ -6,6 +6,8 @@ gem "hanami", "<%= hanami_version %>"
6
6
  gem "hanami-router", "<%= hanami_version %>"
7
7
  gem "hanami-controller", "<%= hanami_version %>"
8
8
  gem "hanami-validations", "<%= hanami_version %>"
9
+ gem "hanami-view", "<%= hanami_version %>"
10
+ gem "hanami-webconsole", "<%= hanami_version %>"
9
11
 
10
12
  gem "dry-types", "~> 1.0", ">= 1.6.1"
11
13
  gem "puma"
@@ -0,0 +1,10 @@
1
+ # auto_register: false
2
+ # frozen_string_literal: true
3
+
4
+ module <%= camelized_app_name %>
5
+ module Views
6
+ module Helpers
7
+ # Add your view helpers here
8
+ end
9
+ end
10
+ end
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -6,10 +6,12 @@ threads min_threads_count, max_threads_count
6
6
 
7
7
  port ENV.fetch("<%= Hanami::Port::ENV_VAR %>", <%= Hanami::Port::DEFAULT %>)
8
8
  environment ENV.fetch("HANAMI_ENV", "development")
9
- workers ENV.fetch("HANAMI_WEB_CONCURRENCY", 2)
9
+ workers ENV.fetch("HANAMI_WEB_CONCURRENCY", 0)
10
10
 
11
- on_worker_boot do
12
- Hanami.shutdown
11
+ if ENV.fetch("HANAMI_WEB_CONCURRENCY", 0) > 0
12
+ on_worker_boot do
13
+ Hanami.shutdown
14
+ end
13
15
  end
14
16
 
15
17
  preload_app!
@@ -0,0 +1,9 @@
1
+ # auto_register: false
2
+ # frozen_string_literal: true
3
+
4
+ require "hanami/view"
5
+
6
+ module <%= camelized_app_name %>
7
+ class View < Hanami::View
8
+ end
9
+ end
@@ -52,6 +52,12 @@ module Hanami
52
52
 
53
53
  fs.write("app/actions/.keep", t("keep.erb", context))
54
54
  fs.write("app/action.rb", t("action.erb", context))
55
+ fs.write("app/view.rb", t("view.erb", context))
56
+ fs.write("app/views/helpers.rb", t("helpers.erb", context))
57
+ fs.write("app/templates/layouts/app.html.erb", File.read(File.join(__dir__, "app", "layouts_app.html.erb")))
58
+
59
+ fs.write("public/404.html", File.read(File.join(__dir__, "app", "404.html")))
60
+ fs.write("public/500.html", File.read(File.join(__dir__, "app", "500.html")))
55
61
  end
56
62
 
57
63
  def template(path, context)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "uri"
4
- require_relative "./errors"
4
+ require_relative "errors"
5
5
 
6
6
  module Hanami
7
7
  module CLI
@@ -6,6 +6,6 @@ module Hanami
6
6
  #
7
7
  # @api public
8
8
  # @since 2.0.0
9
- VERSION = "2.0.3"
9
+ VERSION = "2.1.0.beta1"
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.0.3
4
+ version: 2.1.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-02-01 00:00:00.000000000 Z
11
+ date: 2023-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -212,6 +212,7 @@ files:
212
212
  - lib/hanami/cli/commands/app/generate.rb
213
213
  - lib/hanami/cli/commands/app/generate/action.rb
214
214
  - lib/hanami/cli/commands/app/generate/slice.rb
215
+ - lib/hanami/cli/commands/app/generate/view.rb
215
216
  - lib/hanami/cli/commands/app/install.rb
216
217
  - lib/hanami/cli/commands/app/middleware.rb
217
218
  - lib/hanami/cli/commands/app/routes.rb
@@ -225,6 +226,8 @@ files:
225
226
  - lib/hanami/cli/generators/app/action.rb
226
227
  - lib/hanami/cli/generators/app/action/action.erb
227
228
  - lib/hanami/cli/generators/app/action/slice_action.erb
229
+ - lib/hanami/cli/generators/app/action/slice_template.html.erb
230
+ - lib/hanami/cli/generators/app/action/slice_view.erb
228
231
  - lib/hanami/cli/generators/app/action/template.erb
229
232
  - lib/hanami/cli/generators/app/action/template.html.erb
230
233
  - lib/hanami/cli/generators/app/action/view.erb
@@ -232,21 +235,33 @@ files:
232
235
  - lib/hanami/cli/generators/app/slice.rb
233
236
  - lib/hanami/cli/generators/app/slice/action.erb
234
237
  - lib/hanami/cli/generators/app/slice/entities.erb
238
+ - lib/hanami/cli/generators/app/slice/helpers.erb
235
239
  - lib/hanami/cli/generators/app/slice/keep.erb
240
+ - lib/hanami/cli/generators/app/slice/layouts_app.html.erb
236
241
  - lib/hanami/cli/generators/app/slice/repository.erb
237
242
  - lib/hanami/cli/generators/app/slice/routes.erb
238
243
  - lib/hanami/cli/generators/app/slice/slice.erb
239
244
  - lib/hanami/cli/generators/app/slice/view.erb
240
245
  - lib/hanami/cli/generators/app/slice_context.rb
246
+ - lib/hanami/cli/generators/app/view.rb
247
+ - lib/hanami/cli/generators/app/view/app_template.html.erb
248
+ - lib/hanami/cli/generators/app/view/app_view.erb
249
+ - lib/hanami/cli/generators/app/view/slice_template.html.erb
250
+ - lib/hanami/cli/generators/app/view/slice_view.erb
251
+ - lib/hanami/cli/generators/app/view_context.rb
241
252
  - lib/hanami/cli/generators/context.rb
242
253
  - lib/hanami/cli/generators/gem/app.rb
254
+ - lib/hanami/cli/generators/gem/app/404.html
255
+ - lib/hanami/cli/generators/gem/app/500.html
243
256
  - lib/hanami/cli/generators/gem/app/action.erb
244
257
  - lib/hanami/cli/generators/gem/app/app.erb
245
258
  - lib/hanami/cli/generators/gem/app/config_ru.erb
246
259
  - lib/hanami/cli/generators/gem/app/env.erb
247
260
  - lib/hanami/cli/generators/gem/app/gemfile.erb
248
261
  - lib/hanami/cli/generators/gem/app/gitignore.erb
262
+ - lib/hanami/cli/generators/gem/app/helpers.erb
249
263
  - lib/hanami/cli/generators/gem/app/keep.erb
264
+ - lib/hanami/cli/generators/gem/app/layouts_app.html.erb
250
265
  - lib/hanami/cli/generators/gem/app/puma.erb
251
266
  - lib/hanami/cli/generators/gem/app/rakefile.erb
252
267
  - lib/hanami/cli/generators/gem/app/readme.erb
@@ -254,6 +269,7 @@ files:
254
269
  - lib/hanami/cli/generators/gem/app/settings.erb
255
270
  - lib/hanami/cli/generators/gem/app/types.erb
256
271
  - lib/hanami/cli/generators/gem/app/validator.erb
272
+ - lib/hanami/cli/generators/gem/app/view.erb
257
273
  - lib/hanami/cli/generators/version.rb
258
274
  - lib/hanami/cli/middleware_stack_inspector.rb
259
275
  - lib/hanami/cli/naming.rb
@@ -288,11 +304,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
288
304
  version: '3.0'
289
305
  required_rubygems_version: !ruby/object:Gem::Requirement
290
306
  requirements:
291
- - - ">="
307
+ - - ">"
292
308
  - !ruby/object:Gem::Version
293
- version: '0'
309
+ version: 1.3.1
294
310
  requirements: []
295
- rubygems_version: 3.4.5
311
+ rubygems_version: 3.4.13
296
312
  signing_key:
297
313
  specification_version: 4
298
314
  summary: Hanami CLI