hanami-cli 2.0.0 → 2.1.0

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -0
  3. data/{.action_hero.yml → .repobot.yml} +1 -3
  4. data/.rubocop.yml +6 -0
  5. data/CHANGELOG.md +115 -0
  6. data/Gemfile +7 -2
  7. data/LICENSE.md +1 -1
  8. data/README.md +1 -1
  9. data/hanami-cli.gemspec +1 -1
  10. data/lib/hanami/cli/bundler.rb +26 -9
  11. data/lib/hanami/cli/command.rb +28 -6
  12. data/lib/hanami/cli/commands/app/assets/command.rb +155 -0
  13. data/lib/hanami/cli/commands/app/assets/compile.rb +35 -0
  14. data/lib/hanami/cli/commands/app/assets/watch.rb +29 -0
  15. data/lib/hanami/cli/commands/app/assets.rb +16 -0
  16. data/lib/hanami/cli/commands/app/command.rb +5 -3
  17. data/lib/hanami/cli/commands/app/db/rollback.rb +30 -6
  18. data/lib/hanami/cli/commands/app/db/utils/database.rb +5 -1
  19. data/lib/hanami/cli/commands/app/dev.rb +50 -0
  20. data/lib/hanami/cli/commands/app/generate/action.rb +38 -9
  21. data/lib/hanami/cli/commands/app/generate/part.rb +57 -0
  22. data/lib/hanami/cli/commands/app/generate/slice.rb +6 -3
  23. data/lib/hanami/cli/commands/app/generate/view.rb +56 -0
  24. data/lib/hanami/cli/commands/app/generate.rb +2 -2
  25. data/lib/hanami/cli/commands/app/install.rb +16 -1
  26. data/lib/hanami/cli/commands/app/server.rb +6 -10
  27. data/lib/hanami/cli/commands/app.rb +10 -0
  28. data/lib/hanami/cli/commands/gem/new.rb +70 -12
  29. data/lib/hanami/cli/errors.rb +30 -0
  30. data/lib/hanami/cli/files.rb +8 -2
  31. data/lib/hanami/cli/generators/app/action/action.erb +5 -1
  32. data/lib/hanami/cli/generators/app/action/slice_action.erb +5 -1
  33. data/lib/hanami/cli/generators/app/action/slice_template.html.erb +1 -0
  34. data/lib/hanami/cli/generators/app/action/slice_view.erb +10 -0
  35. data/lib/hanami/cli/generators/app/action/template.html.erb +1 -2
  36. data/lib/hanami/cli/generators/app/action/view.erb +2 -5
  37. data/lib/hanami/cli/generators/app/action.rb +74 -22
  38. data/lib/hanami/cli/generators/app/action_context.rb +1 -1
  39. data/lib/hanami/cli/generators/app/part/app_base_part.erb +9 -0
  40. data/lib/hanami/cli/generators/app/part/app_part.erb +13 -0
  41. data/lib/hanami/cli/generators/app/part/slice_base_part.erb +9 -0
  42. data/lib/hanami/cli/generators/app/part/slice_part.erb +13 -0
  43. data/lib/hanami/cli/generators/app/part.rb +101 -0
  44. data/lib/hanami/cli/generators/app/part_context.rb +98 -0
  45. data/lib/hanami/cli/generators/app/slice/app_css.erb +5 -0
  46. data/lib/hanami/cli/generators/app/slice/app_js.erb +1 -0
  47. data/lib/hanami/cli/generators/app/slice/app_layout.erb +18 -0
  48. data/lib/hanami/cli/generators/app/slice/favicon.ico +0 -0
  49. data/lib/hanami/cli/generators/app/slice/helpers.erb +10 -0
  50. data/lib/hanami/cli/generators/app/slice/view.erb +0 -2
  51. data/lib/hanami/cli/generators/app/slice.rb +20 -6
  52. data/lib/hanami/cli/generators/app/slice_context.rb +18 -0
  53. data/lib/hanami/cli/generators/app/view/app_template.html.erb +1 -0
  54. data/lib/hanami/cli/generators/app/view/app_view.erb +10 -0
  55. data/lib/hanami/cli/generators/app/view/slice_template.html.erb +1 -0
  56. data/lib/hanami/cli/generators/app/view/slice_view.erb +10 -0
  57. data/lib/hanami/cli/generators/app/view.rb +89 -0
  58. data/lib/hanami/cli/generators/app/view_context.rb +100 -0
  59. data/lib/hanami/cli/generators/context.rb +72 -5
  60. data/lib/hanami/cli/generators/gem/app/404.html +82 -0
  61. data/lib/hanami/cli/generators/gem/app/500.html +82 -0
  62. data/lib/hanami/cli/generators/gem/app/app_css.erb +5 -0
  63. data/lib/hanami/cli/generators/gem/app/app_js.erb +1 -0
  64. data/lib/hanami/cli/generators/gem/app/app_layout.erb +18 -0
  65. data/lib/hanami/cli/generators/gem/app/assets.js +16 -0
  66. data/lib/hanami/cli/generators/gem/app/dev +8 -0
  67. data/lib/hanami/cli/generators/gem/app/favicon.ico +0 -0
  68. data/lib/hanami/cli/generators/gem/app/gemfile.erb +14 -6
  69. data/lib/hanami/cli/generators/gem/app/gitignore.erb +6 -0
  70. data/lib/hanami/cli/generators/gem/app/helpers.erb +10 -0
  71. data/lib/hanami/cli/generators/gem/app/package.json.erb +8 -0
  72. data/lib/hanami/cli/generators/gem/app/procfile.erb +4 -0
  73. data/lib/hanami/cli/generators/gem/app/puma.erb +39 -7
  74. data/lib/hanami/cli/generators/gem/app/routes.erb +1 -1
  75. data/lib/hanami/cli/generators/gem/app/view.erb +9 -0
  76. data/lib/hanami/cli/generators/gem/app.rb +25 -1
  77. data/lib/hanami/cli/generators/version.rb +14 -2
  78. data/lib/hanami/cli/interactive_system_call.rb +65 -0
  79. data/lib/hanami/cli/naming.rb +25 -0
  80. data/lib/hanami/cli/system_call.rb +8 -2
  81. data/lib/hanami/cli/url.rb +1 -1
  82. data/lib/hanami/cli/version.rb +1 -1
  83. metadata +47 -6
@@ -2,60 +2,90 @@
2
2
 
3
3
  module Hanami
4
4
  module CLI
5
+ # @since 0.1.0
6
+ # @api public
5
7
  class Error < StandardError
6
8
  end
7
9
 
10
+ # @since 2.0.0
11
+ # @api public
8
12
  class NotImplementedError < Error
9
13
  end
10
14
 
15
+ # @since 2.0.0
16
+ # @api public
11
17
  class BundleInstallError < Error
12
18
  def initialize(message)
13
19
  super("`bundle install' failed\n\n\n#{message.inspect}")
14
20
  end
15
21
  end
16
22
 
23
+ # @since 2.0.0
24
+ # @api public
17
25
  class HanamiInstallError < Error
18
26
  def initialize(message)
19
27
  super("`hanami install' failed\n\n\n#{message.inspect}")
20
28
  end
21
29
  end
22
30
 
31
+ # @since 2.1.0
32
+ # @api public
33
+ class HanamiExecError < Error
34
+ def initialize(cmd, message)
35
+ super("`bundle exec hanami #{cmd}' failed\n\n\n#{message.inspect}")
36
+ end
37
+ end
38
+
39
+ # @since 2.0.0
40
+ # @api public
23
41
  class PathAlreadyExistsError < Error
24
42
  def initialize(path)
25
43
  super("Cannot create new Hanami app in an existing path: `#{path}'")
26
44
  end
27
45
  end
28
46
 
47
+ # @since 2.0.0
48
+ # @api public
29
49
  class MissingSliceError < Error
30
50
  def initialize(slice)
31
51
  super("slice `#{slice}' is missing, please generate with `hanami generate slice #{slice}'")
32
52
  end
33
53
  end
34
54
 
55
+ # @since 2.0.0
56
+ # @api public
35
57
  class InvalidURLError < Error
36
58
  def initialize(url)
37
59
  super("invalid URL: `#{url}'")
38
60
  end
39
61
  end
40
62
 
63
+ # @since 2.0.0
64
+ # @api public
41
65
  class InvalidURLPrefixError < Error
42
66
  def initialize(url)
43
67
  super("invalid URL prefix: `#{url}'")
44
68
  end
45
69
  end
46
70
 
71
+ # @since 2.0.0
72
+ # @api public
47
73
  class InvalidActionNameError < Error
48
74
  def initialize(name)
49
75
  super("cannot parse controller and action name: `#{name}'\n\texample: `hanami generate action users.show'")
50
76
  end
51
77
  end
52
78
 
79
+ # @since 2.0.0
80
+ # @api public
53
81
  class UnknownHTTPMethodError < Error
54
82
  def initialize(name)
55
83
  super("unknown HTTP method: `#{name}'")
56
84
  end
57
85
  end
58
86
 
87
+ # @since 2.0.0
88
+ # @api public
59
89
  class UnsupportedDatabaseSchemeError < Error
60
90
  def initialize(scheme)
61
91
  super("`#{scheme}' is not a supported db scheme")
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dry/files"
4
+
3
5
  module Hanami
4
6
  module CLI
5
7
  # @since 2.0.0
@@ -29,7 +31,7 @@ module Hanami
29
31
  def mkdir(path)
30
32
  unless exist?(path)
31
33
  super
32
- created("#{path}/")
34
+ created(_path(path))
33
35
  end
34
36
  end
35
37
 
@@ -53,7 +55,11 @@ module Hanami
53
55
  end
54
56
 
55
57
  def within_folder(path)
56
- out.puts "-> Within #{path}/"
58
+ out.puts "-> Within #{_path(path)}"
59
+ end
60
+
61
+ def _path(path)
62
+ path + ::File::SEPARATOR
57
63
  end
58
64
  end
59
65
  end
@@ -4,8 +4,12 @@ module <%= camelized_app_name %>
4
4
  module Actions
5
5
  <%= module_controller_declaration %>
6
6
  <%= module_controller_offset %>class <%= camelized_action_name %> < <%= camelized_app_name %>::Action
7
- <%= module_controller_offset %> def handle(*, response)
7
+ <%- if bundled_views? -%>
8
+ <%= module_controller_offset %> def handle(request, response)
9
+ <%- else -%>
10
+ <%= module_controller_offset %> def handle(request, response)
8
11
  <%= module_controller_offset %> response.body = self.class.name
12
+ <%- end -%>
9
13
  <%= module_controller_offset %> end
10
14
  <%= module_controller_offset %>end
11
15
  <%= module_controller_end %>
@@ -4,8 +4,12 @@ module <%= camelized_slice_name %>
4
4
  module Actions
5
5
  <%= module_controller_declaration %>
6
6
  <%= module_controller_offset %>class <%= camelized_action_name %> < <%= camelized_slice_name %>::Action
7
- <%= module_controller_offset %> def handle(*, response)
7
+ <%- if bundled_views? -%>
8
+ <%= module_controller_offset %> def handle(request, response)
9
+ <%- else -%>
10
+ <%= module_controller_offset %> def handle(request, response)
8
11
  <%= module_controller_offset %> response.body = self.class.name
12
+ <%- end -%>
9
13
  <%= module_controller_offset %> end
10
14
  <%= module_controller_offset %>end
11
15
  <%= module_controller_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
@@ -19,11 +19,10 @@ module Hanami
19
19
  @inflector = inflector
20
20
  end
21
21
 
22
- # rubocop:disable Layout/LineLength
23
-
24
22
  # @since 2.0.0
25
23
  # @api private
26
- def call(app, controller, action, url, http, format, skip_view, slice, context: ActionContext.new(inflector, app, slice, controller, action))
24
+ def call(app, controller, action, url, http, format, skip_view, slice, context: nil)
25
+ context ||= ActionContext.new(inflector, app, slice, controller, action)
27
26
  if slice
28
27
  generate_for_slice(controller, action, url, http, format, skip_view, slice, context)
29
28
  else
@@ -31,8 +30,6 @@ module Hanami
31
30
  end
32
31
  end
33
32
 
34
- # rubocop:enable Layout/LineLength
35
-
36
33
  private
37
34
 
38
35
  ROUTE_HTTP_METHODS = %w[get post delete put patch trace options link unlink].freeze
@@ -59,6 +56,14 @@ module Hanami
59
56
  }.freeze
60
57
  private_constant :ROUTE_RESTFUL_URL_SUFFIXES
61
58
 
59
+ # @api private
60
+ # @since 2.1.0
61
+ RESTFUL_COUNTERPART_VIEWS = {
62
+ "create" => "new",
63
+ "update" => "edit"
64
+ }.freeze
65
+ private_constant :RESTFUL_COUNTERPART_VIEWS
66
+
62
67
  PATH_SEPARATOR = "/"
63
68
  private_constant :PATH_SEPARATOR
64
69
 
@@ -66,7 +71,8 @@ module Hanami
66
71
 
67
72
  attr_reader :inflector
68
73
 
69
- def generate_for_slice(controller, action, url, http, _format, _skip_view, slice, context)
74
+ # rubocop:disable Metrics/AbcSize
75
+ def generate_for_slice(controller, action, url, http, format, skip_view, slice, context)
70
76
  slice_directory = fs.join("slices", slice)
71
77
  raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
72
78
 
@@ -79,16 +85,17 @@ module Hanami
79
85
  fs.mkdir(directory = fs.join(slice_directory, "actions", controller))
80
86
  fs.write(fs.join(directory, "#{action}.rb"), t("slice_action.erb", context))
81
87
 
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
88
+ if generate_view?(skip_view, action, directory)
89
+ fs.mkdir(directory = fs.join(slice_directory, "views", controller))
90
+ fs.write(fs.join(directory, "#{action}.rb"), t("slice_view.erb", context))
91
+
92
+ fs.mkdir(directory = fs.join(slice_directory, "templates", controller))
93
+ fs.write(fs.join(directory, "#{action}.#{format}.erb"),
94
+ t(template_with_format_ext("slice_template", format), context))
95
+ end
89
96
  end
90
97
 
91
- def generate_for_app(controller, action, url, http, _format, _skip_view, context)
98
+ def generate_for_app(controller, action, url, http, format, skip_view, context)
92
99
  fs.inject_line_at_class_bottom(
93
100
  fs.join("config", "routes.rb"),
94
101
  "class Routes",
@@ -97,7 +104,20 @@ module Hanami
97
104
 
98
105
  fs.mkdir(directory = fs.join("app", "actions", controller))
99
106
  fs.write(fs.join(directory, "#{action}.rb"), t("action.erb", context))
107
+
108
+ view = action
109
+ view_directory = fs.join("app", "views", controller)
110
+
111
+ if generate_view?(skip_view, view, view_directory)
112
+ fs.mkdir(view_directory)
113
+ fs.write(fs.join(view_directory, "#{view}.rb"), t("view.erb", context))
114
+
115
+ fs.mkdir(template_directory = fs.join("app", "templates", controller))
116
+ fs.write(fs.join(template_directory, "#{view}.#{format}.erb"),
117
+ t(template_with_format_ext("template", format), context))
118
+ end
100
119
  end
120
+ # rubocop:enable Metrics/AbcSize
101
121
 
102
122
  def slice_matcher(slice)
103
123
  /slice[[:space:]]*:#{slice}/
@@ -108,20 +128,52 @@ module Hanami
108
128
  http)} "#{route_url(controller, action, url)}", to: "#{controller.join('.')}.#{action}")
109
129
  end
110
130
 
111
- def template_format(format)
112
- case format.to_sym
113
- when :html
114
- "template.html.erb"
115
- else
116
- "template.erb"
117
- end
131
+ # @api private
132
+ # @since 2.1.0
133
+ def generate_view?(skip_view, view, directory)
134
+ return false if skip_view
135
+ return generate_restful_view?(view, directory) if rest_view?(view)
136
+
137
+ true
138
+ end
139
+
140
+ # @api private
141
+ # @since 2.1.0
142
+ def generate_restful_view?(view, directory)
143
+ corresponding_action = corresponding_restful_view(view)
144
+
145
+ !fs.exist?(fs.join(directory, "#{corresponding_action}.rb"))
146
+ end
147
+
148
+ # @api private
149
+ # @since 2.1.0
150
+ def rest_view?(view)
151
+ RESTFUL_COUNTERPART_VIEWS.keys.include?(view)
152
+ end
153
+
154
+ # @api private
155
+ # @since 2.1.0
156
+ def corresponding_restful_view(view)
157
+ RESTFUL_COUNTERPART_VIEWS.fetch(view, nil)
158
+ end
159
+
160
+ def template_with_format_ext(name, format)
161
+ ext =
162
+ case format.to_sym
163
+ when :html
164
+ ".html.erb"
165
+ else
166
+ ".erb"
167
+ end
168
+
169
+ "#{name}#{ext}"
118
170
  end
119
171
 
120
172
  def template(path, context)
121
173
  require "erb"
122
174
 
123
175
  ERB.new(
124
- File.read(__dir__ + "/action/#{path}")
176
+ File.read(__dir__ + "/action/#{path}"), trim_mode: "-",
125
177
  ).result(context.ctx)
126
178
  end
127
179
 
@@ -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,9 @@
1
+ # auto_register: false
2
+ # frozen_string_literal: true
3
+
4
+ module <%= camelized_app_name %>
5
+ module Views
6
+ class Part < Hanami::View::Part
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ # auto_register: false
2
+ # frozen_string_literal: true
3
+
4
+ module <%= camelized_app_name %>
5
+ module Views
6
+ module Parts
7
+ <%= module_namespace_declaration -%>
8
+ <%= module_namespace_offset %>class <%= camelized_name %> < <%= camelized_app_name %>::Views::Part
9
+ <%= module_namespace_offset %>end
10
+ <%= module_namespace_end -%>
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # auto_register: false
2
+ # frozen_string_literal: true
3
+
4
+ module <%= camelized_slice_name %>
5
+ module Views
6
+ class Part < <%= camelized_app_name %>::Views::Part
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ # auto_register: false
2
+ # frozen_string_literal: true
3
+
4
+ module <%= camelized_slice_name %>
5
+ module Views
6
+ module Parts
7
+ <%= module_namespace_declaration -%>
8
+ <%= module_namespace_offset %>class <%= camelized_name %> < <%= camelized_slice_name %>::Views::Part
9
+ <%= module_namespace_offset %>end
10
+ <%= module_namespace_end -%>
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,101 @@
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.1.0
12
+ # @api private
13
+ class Part
14
+ # @since 2.1.0
15
+ # @api private
16
+ def initialize(fs:, inflector:)
17
+ @fs = fs
18
+ @inflector = inflector
19
+ end
20
+
21
+ # @since 2.1.0
22
+ # @api private
23
+ def call(app, key, slice)
24
+ context = PartContext.new(inflector, app, slice, key)
25
+
26
+ if slice
27
+ generate_for_slice(context, slice)
28
+ else
29
+ generate_for_app(context)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ # @since 2.1.0
36
+ # @api private
37
+ attr_reader :fs
38
+
39
+ # @since 2.1.0
40
+ # @api private
41
+ attr_reader :inflector
42
+
43
+ # @since 2.1.0
44
+ # @api private
45
+ def generate_for_slice(context, slice)
46
+ slice_directory = fs.join("slices", slice)
47
+ raise MissingSliceError.new(slice) unless fs.directory?(slice_directory)
48
+
49
+ generate_base_part_for_app(context)
50
+ generate_base_part_for_slice(context, slice)
51
+
52
+ fs.mkdir(directory = fs.join(slice_directory, "views", "parts", *context.underscored_namespace))
53
+ fs.write(fs.join(directory, "#{context.underscored_name}.rb"), t("slice_part.erb", context))
54
+ end
55
+
56
+ # @since 2.1.0
57
+ # @api private
58
+ def generate_for_app(context)
59
+ generate_base_part_for_app(context)
60
+
61
+ fs.mkdir(directory = fs.join("app", "views", "parts", *context.underscored_namespace))
62
+ fs.write(fs.join(directory, "#{context.underscored_name}.rb"), t("app_part.erb", context))
63
+ end
64
+
65
+ # @since 2.1.0
66
+ # @api private
67
+ def generate_base_part_for_app(context)
68
+ path = fs.join("app", "views", "part.rb")
69
+ return if fs.exist?(path)
70
+
71
+ fs.write(path, t("app_base_part.erb", context))
72
+ end
73
+
74
+ # @since 2.1.0
75
+ # @api private
76
+ def generate_base_part_for_slice(context, slice)
77
+ path = fs.join("slices", slice, "views", "part.rb")
78
+ return if fs.exist?(path)
79
+
80
+ fs.write(path, t("slice_base_part.erb", context))
81
+ end
82
+
83
+ # @since 2.1.0
84
+ # @api private
85
+ def template(path, context)
86
+ require "erb"
87
+
88
+ ERB.new(
89
+ File.read(__dir__ + "/part/#{path}"),
90
+ trim_mode: "-"
91
+ ).result(context.ctx)
92
+ end
93
+
94
+ # @since 2.1.0
95
+ # @api private
96
+ alias_method :t, :template
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,98 @@
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 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
+ # @since 2.1.0
33
+ # @api private
34
+ attr_reader :key
35
+
36
+ # @since 2.1.0
37
+ # @api private
38
+ def initialize(inflector, app, slice, key)
39
+ @key = key
40
+ super(inflector, app, slice, nil)
41
+ end
42
+
43
+ # @since 2.1.0
44
+ # @api private
45
+ def namespaces
46
+ @namespaces ||= key.split(KEY_SEPARATOR)[..-2]
47
+ end
48
+
49
+ # @since 2.1.0
50
+ # @api private
51
+ def name
52
+ @name ||= key.split(KEY_SEPARATOR)[-1]
53
+ end
54
+
55
+ # @since 2.1.0
56
+ # @api private
57
+ def camelized_name
58
+ inflector.camelize(name)
59
+ end
60
+
61
+ # @since 2.1.0
62
+ # @api private
63
+ def underscored_namespace
64
+ namespaces.map { inflector.underscore(_1) }
65
+ end
66
+
67
+ # @since 2.1.0
68
+ # @api private
69
+ def underscored_name
70
+ inflector.underscore(name)
71
+ end
72
+
73
+ # @since 2.1.0
74
+ # @api private
75
+ def module_namespace_declaration
76
+ namespaces.each_with_index.map { |token, i|
77
+ "#{OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
78
+ }.join($/)
79
+ end
80
+
81
+ # @since 2.1.0
82
+ # @api private
83
+ def module_namespace_end
84
+ namespaces.each_with_index.map { |_, i|
85
+ "#{OFFSET}#{INDENTATION * i}end"
86
+ }.reverse.join($/)
87
+ end
88
+
89
+ # @since 2.1.0
90
+ # @api private
91
+ def module_namespace_offset
92
+ "#{OFFSET}#{INDENTATION * namespaces.count}"
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,5 @@
1
+ body {
2
+ background-color: #fff;
3
+ color: #000;
4
+ font-family: sans-serif;
5
+ }
@@ -0,0 +1 @@
1
+ import "../css/app.css";
@@ -0,0 +1,18 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title><%= humanized_app_name %> - <%= humanized_slice_name %></title>
7
+ <%- if bundled_assets? -%>
8
+ <%%= favicon_tag %>
9
+ <%= stylesheet_erb_tag %>
10
+ <%- end -%>
11
+ </head>
12
+ <body>
13
+ <%%= yield %>
14
+ <%- if bundled_assets? -%>
15
+ <%= javascript_erb_tag %>
16
+ <%- end -%>
17
+ </body>
18
+ </html>
@@ -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
@@ -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