hanami-cli 2.0.3 → 2.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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