hanami 0.0.0 → 0.7.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 (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +214 -0
  3. data/FEATURES.md +156 -0
  4. data/LICENSE.md +22 -0
  5. data/README.md +80 -15
  6. data/bin/hanami +5 -0
  7. data/hanami.gemspec +27 -12
  8. data/lib/hanami.rb +78 -2
  9. data/lib/hanami/action/csrf_protection.rb +167 -0
  10. data/lib/hanami/action/routing_helpers.rb +40 -0
  11. data/lib/hanami/application.rb +244 -0
  12. data/lib/hanami/application_name.rb +101 -0
  13. data/lib/hanami/cli.rb +119 -0
  14. data/lib/hanami/cli_sub_commands/assets.rb +29 -0
  15. data/lib/hanami/cli_sub_commands/db.rb +124 -0
  16. data/lib/hanami/cli_sub_commands/destroy.rb +102 -0
  17. data/lib/hanami/cli_sub_commands/generate.rb +127 -0
  18. data/lib/hanami/commands/assets/precompile.rb +35 -0
  19. data/lib/hanami/commands/console.rb +90 -0
  20. data/lib/hanami/commands/db/abstract.rb +19 -0
  21. data/lib/hanami/commands/db/apply.rb +14 -0
  22. data/lib/hanami/commands/db/console.rb +50 -0
  23. data/lib/hanami/commands/db/create.rb +14 -0
  24. data/lib/hanami/commands/db/drop.rb +14 -0
  25. data/lib/hanami/commands/db/migrate.rb +19 -0
  26. data/lib/hanami/commands/db/prepare.rb +14 -0
  27. data/lib/hanami/commands/db/version.rb +14 -0
  28. data/lib/hanami/commands/generate/abstract.rb +63 -0
  29. data/lib/hanami/commands/generate/action.rb +262 -0
  30. data/lib/hanami/commands/generate/app.rb +116 -0
  31. data/lib/hanami/commands/generate/mailer.rb +118 -0
  32. data/lib/hanami/commands/generate/migration.rb +63 -0
  33. data/lib/hanami/commands/generate/model.rb +96 -0
  34. data/lib/hanami/commands/new/abstract.rb +128 -0
  35. data/lib/hanami/commands/new/app.rb +116 -0
  36. data/lib/hanami/commands/new/container.rb +102 -0
  37. data/lib/hanami/commands/routes.rb +41 -0
  38. data/lib/hanami/commands/server.rb +79 -0
  39. data/lib/hanami/config/configure.rb +17 -0
  40. data/lib/hanami/config/cookies.rb +68 -0
  41. data/lib/hanami/config/framework_configuration.rb +42 -0
  42. data/lib/hanami/config/load_paths.rb +27 -0
  43. data/lib/hanami/config/mapper.rb +36 -0
  44. data/lib/hanami/config/mapping.rb +12 -0
  45. data/lib/hanami/config/routes.rb +16 -0
  46. data/lib/hanami/config/security.rb +58 -0
  47. data/lib/hanami/config/sessions.rb +97 -0
  48. data/lib/hanami/configuration.rb +1728 -0
  49. data/lib/hanami/container.rb +59 -0
  50. data/lib/hanami/environment.rb +485 -0
  51. data/lib/hanami/frameworks.rb +14 -0
  52. data/lib/hanami/generators/action/action.rb.tt +8 -0
  53. data/lib/hanami/generators/action/action_spec.minitest.tt +12 -0
  54. data/lib/hanami/generators/action/action_spec.rspec.tt +11 -0
  55. data/lib/hanami/generators/action/action_without_view.rb.tt +9 -0
  56. data/lib/hanami/generators/action/template.tt +0 -0
  57. data/lib/hanami/generators/action/view.rb.tt +5 -0
  58. data/lib/hanami/generators/action/view_spec.minitest.tt +13 -0
  59. data/lib/hanami/generators/action/view_spec.rspec.tt +12 -0
  60. data/lib/hanami/generators/app/.gitkeep.tt +1 -0
  61. data/lib/hanami/generators/app/application.rb.tt +273 -0
  62. data/lib/hanami/generators/app/config/initializers/.gitkeep +0 -0
  63. data/lib/hanami/generators/app/config/routes.rb.tt +2 -0
  64. data/lib/hanami/generators/app/favicon.ico +0 -0
  65. data/lib/hanami/generators/app/templates/application.html.erb.tt +10 -0
  66. data/lib/hanami/generators/app/views/application_layout.rb.tt +7 -0
  67. data/lib/hanami/generators/application/app/.env.development.tt +4 -0
  68. data/lib/hanami/generators/application/app/.env.test.tt +4 -0
  69. data/lib/hanami/generators/application/app/.env.tt +1 -0
  70. data/lib/hanami/generators/application/app/.gitignore +0 -0
  71. data/lib/hanami/generators/application/app/.gitkeep +1 -0
  72. data/lib/hanami/generators/application/app/Gemfile.tt +37 -0
  73. data/lib/hanami/generators/application/app/Rakefile.minitest.tt +11 -0
  74. data/lib/hanami/generators/application/app/Rakefile.rspec.tt +6 -0
  75. data/lib/hanami/generators/application/app/apps/.gitkeep.tt +1 -0
  76. data/lib/hanami/generators/application/app/capybara.rb.rspec.tt +8 -0
  77. data/lib/hanami/generators/application/app/config.ru.tt +3 -0
  78. data/lib/hanami/generators/application/app/config/application.rb.tt +270 -0
  79. data/lib/hanami/generators/application/app/config/environment.rb.tt +5 -0
  80. data/lib/hanami/generators/application/app/config/initializers/.gitkeep +0 -0
  81. data/lib/hanami/generators/application/app/config/routes.rb.tt +2 -0
  82. data/lib/hanami/generators/application/app/db/.gitkeep +1 -0
  83. data/lib/hanami/generators/application/app/favicon.ico +0 -0
  84. data/lib/hanami/generators/application/app/features_helper.rb.minitest.tt +11 -0
  85. data/lib/hanami/generators/application/app/features_helper.rb.rspec.tt +12 -0
  86. data/lib/hanami/generators/application/app/gitignore.tt +2 -0
  87. data/lib/hanami/generators/application/app/gitignore_with_db.tt +4 -0
  88. data/lib/hanami/generators/application/app/hanamirc.tt +3 -0
  89. data/lib/hanami/generators/application/app/lib/app_name.rb.tt +59 -0
  90. data/lib/hanami/generators/application/app/lib/chirp/entities/.gitkeep +1 -0
  91. data/lib/hanami/generators/application/app/lib/chirp/repositories/.gitkeep +1 -0
  92. data/lib/hanami/generators/application/app/lib/config/mapping.rb.tt +7 -0
  93. data/lib/hanami/generators/application/app/rspec.rspec.tt +2 -0
  94. data/lib/hanami/generators/application/app/schema.sql.tt +0 -0
  95. data/lib/hanami/generators/application/app/spec_helper.rb.minitest.tt +7 -0
  96. data/lib/hanami/generators/application/app/spec_helper.rb.rspec.tt +104 -0
  97. data/lib/hanami/generators/application/app/templates/application.html.erb.tt +10 -0
  98. data/lib/hanami/generators/application/app/views/application_layout.rb.tt +7 -0
  99. data/lib/hanami/generators/application/container/.env.development.tt +3 -0
  100. data/lib/hanami/generators/application/container/.env.test.tt +3 -0
  101. data/lib/hanami/generators/application/container/.env.tt +1 -0
  102. data/lib/hanami/generators/application/container/.gitignore +0 -0
  103. data/lib/hanami/generators/application/container/.gitkeep +1 -0
  104. data/lib/hanami/generators/application/container/Gemfile.tt +36 -0
  105. data/lib/hanami/generators/application/container/Rakefile.minitest.tt +11 -0
  106. data/lib/hanami/generators/application/container/Rakefile.rspec.tt +6 -0
  107. data/lib/hanami/generators/application/container/capybara.rb.rspec.tt +8 -0
  108. data/lib/hanami/generators/application/container/config.ru.tt +3 -0
  109. data/lib/hanami/generators/application/container/config/environment.rb.tt +7 -0
  110. data/lib/hanami/generators/application/container/config/initializers/.gitkeep +0 -0
  111. data/lib/hanami/generators/application/container/db/.gitkeep +1 -0
  112. data/lib/hanami/generators/application/container/features_helper.rb.minitest.tt +11 -0
  113. data/lib/hanami/generators/application/container/features_helper.rb.rspec.tt +12 -0
  114. data/lib/hanami/generators/application/container/gitignore.tt +2 -0
  115. data/lib/hanami/generators/application/container/gitignore_with_db.tt +4 -0
  116. data/lib/hanami/generators/application/container/hanamirc.tt +3 -0
  117. data/lib/hanami/generators/application/container/lib/app_name.rb.tt +60 -0
  118. data/lib/hanami/generators/application/container/lib/chirp/entities/.gitkeep +1 -0
  119. data/lib/hanami/generators/application/container/lib/chirp/mailers/.gitkeep +0 -0
  120. data/lib/hanami/generators/application/container/lib/chirp/mailers/templates/.gitkeep +0 -0
  121. data/lib/hanami/generators/application/container/lib/chirp/repositories/.gitkeep +1 -0
  122. data/lib/hanami/generators/application/container/lib/config/mapping.rb.tt +7 -0
  123. data/lib/hanami/generators/application/container/rspec.rspec.tt +2 -0
  124. data/lib/hanami/generators/application/container/schema.sql.tt +0 -0
  125. data/lib/hanami/generators/application/container/spec_helper.rb.minitest.tt +7 -0
  126. data/lib/hanami/generators/application/container/spec_helper.rb.rspec.tt +104 -0
  127. data/lib/hanami/generators/database_config.rb +99 -0
  128. data/lib/hanami/generators/generatable.rb +51 -0
  129. data/lib/hanami/generators/generator.rb +35 -0
  130. data/lib/hanami/generators/mailer/mailer.rb.tt +7 -0
  131. data/lib/hanami/generators/mailer/mailer_spec.rb.tt +7 -0
  132. data/lib/hanami/generators/mailer/template.html.tt +0 -0
  133. data/lib/hanami/generators/mailer/template.txt.tt +0 -0
  134. data/lib/hanami/generators/migration/migration.rb.tt +4 -0
  135. data/lib/hanami/generators/model/entity.rb.tt +3 -0
  136. data/lib/hanami/generators/model/entity_spec.minitest.tt +5 -0
  137. data/lib/hanami/generators/model/entity_spec.rspec.tt +3 -0
  138. data/lib/hanami/generators/model/repository.rb.tt +3 -0
  139. data/lib/hanami/generators/model/repository_spec.minitest.tt +5 -0
  140. data/lib/hanami/generators/model/repository_spec.rspec.tt +3 -0
  141. data/lib/hanami/generators/test_framework.rb +42 -0
  142. data/lib/hanami/hanamirc.rb +152 -0
  143. data/lib/hanami/loader.rb +258 -0
  144. data/lib/hanami/mailer/glue.rb +68 -0
  145. data/lib/hanami/middleware.rb +143 -0
  146. data/lib/hanami/rake_helper.rb +68 -0
  147. data/lib/hanami/rake_tasks.rb +2 -0
  148. data/lib/hanami/rendering_policy.rb +77 -0
  149. data/lib/hanami/repositories/car_repository.rb +3 -0
  150. data/lib/hanami/repositories/name_repository.rb +3 -0
  151. data/lib/hanami/root.rb +7 -0
  152. data/lib/hanami/routes.rb +151 -0
  153. data/lib/hanami/routing/default.rb +25 -0
  154. data/lib/hanami/setup.rb +3 -0
  155. data/lib/hanami/static.rb +77 -0
  156. data/lib/hanami/templates/default.html.erb +9 -0
  157. data/lib/hanami/templates/welcome.html.erb +52 -0
  158. data/lib/hanami/version.rb +4 -1
  159. data/lib/hanami/views/default.rb +34 -0
  160. data/lib/hanami/views/default_template_finder.rb +20 -0
  161. data/lib/hanami/views/null_view.rb +17 -0
  162. data/lib/hanami/welcome.rb +40 -0
  163. metadata +357 -16
  164. data/.gitignore +0 -9
  165. data/Gemfile +0 -4
  166. data/Rakefile +0 -2
  167. data/bin/console +0 -14
  168. data/bin/setup +0 -8
@@ -0,0 +1,262 @@
1
+ require 'hanami/commands/generate/abstract'
2
+ require 'hanami/routing/route'
3
+
4
+ module Hanami
5
+ module Commands
6
+ class Generate
7
+ class Action < Abstract
8
+
9
+ # @since 0.5.0
10
+ # @api private
11
+ ACTION_SEPARATOR = /[\/,#]/
12
+
13
+ # @since 0.5.0
14
+ # @api private
15
+ ROUTE_ENDPOINT_SEPARATOR = '#'.freeze
16
+
17
+ # @since 0.5.0
18
+ # @api private
19
+ QUOTED_NAME = /(\"|\'|\\)/
20
+
21
+ # Default HTTP method used when generating an action.
22
+ #
23
+ # @since 0.5.0
24
+ # @api private
25
+ DEFAULT_HTTP_METHOD = 'GET'.freeze
26
+
27
+ # HTTP methods used when generating resourceful actions.
28
+ #
29
+ # @since 0.6.0
30
+ # @api private
31
+ RESOURCEFUL_HTTP_METHODS = {
32
+ 'Create' => 'POST',
33
+ 'Update' => 'PATCH',
34
+ 'Destroy' => 'DELETE'
35
+ }.freeze
36
+
37
+ # For resourceful actions, what to add to the end of the base URL
38
+ #
39
+ # @since 0.6.0
40
+ # @api private
41
+ RESOURCEFUL_ROUTE_URL_SUFFIXES = {
42
+ 'Show' => '/:id',
43
+ 'Update' => '/:id',
44
+ 'Destroy' => '/:id',
45
+ 'New' => '/new',
46
+ 'Edit' => '/:id/edit',
47
+ }.freeze
48
+
49
+ def initialize(options, application_name, controller_and_action_name)
50
+ super(options)
51
+ if !environment.container?
52
+ application_name = File.basename(Dir.pwd)
53
+ end
54
+
55
+ controller_and_action_name = Utils::String.new(controller_and_action_name).underscore.gsub(QUOTED_NAME, '')
56
+
57
+ *controller_name, action_name = controller_and_action_name.split(ACTION_SEPARATOR)
58
+
59
+ @application_name = Utils::String.new(application_name).classify
60
+ @controller_name = Utils::String.new(controller_name.join("/")).classify
61
+ @action_name = Utils::String.new(action_name).classify
62
+ @controller_pathname = Utils::String.new(@controller_name).underscore
63
+
64
+ assert_application_name!
65
+ assert_controller_name!
66
+ assert_action_name!
67
+ assert_http_method!
68
+ end
69
+
70
+ def map_templates
71
+ add_mapping("action_spec.#{test_framework.framework}.tt", action_spec_path)
72
+
73
+ if skip_view?
74
+ add_mapping('action_without_view.rb.tt', action_path)
75
+ else
76
+ add_mapping('action.rb.tt', action_path)
77
+ add_mapping('view.rb.tt', view_path)
78
+ add_mapping('template.tt', template_path)
79
+ add_mapping("view_spec.#{test_framework.framework}.tt", view_spec_path)
80
+ end
81
+ end
82
+
83
+ def post_process_templates
84
+ generate_route
85
+ end
86
+
87
+ # @since 0.5.0
88
+ # @api private
89
+ def template_options
90
+ {
91
+ app: @application_name,
92
+ controller: @controller_name,
93
+ action: @action_name,
94
+ relative_action_path: relative_action_path,
95
+ relative_view_path: relative_view_path,
96
+ template_path: template_path,
97
+ }
98
+ end
99
+
100
+ private
101
+
102
+ # @since 0.5.0
103
+ # @api private
104
+ def generate_route
105
+ routes_path.dirname.mkpath
106
+ FileUtils.touch(routes_path)
107
+
108
+ generator.prepend_to_file(routes_path, "#{ http_method } '#{ route_url }', to: '#{ route_endpoint }'\n")
109
+ end
110
+
111
+ def skip_view?
112
+ options.fetch(:skip_view, false)
113
+ end
114
+
115
+ # @since 0.5.0
116
+ # @api private
117
+ def http_method
118
+ options.fetch(:method, resourceful_http_method).downcase
119
+ end
120
+
121
+ # @since 0.6.0
122
+ # @api private
123
+ def resourceful_http_method
124
+ RESOURCEFUL_HTTP_METHODS.fetch(@action_name, DEFAULT_HTTP_METHOD)
125
+ end
126
+
127
+ # @since 0.5.0
128
+ # @api private
129
+ def route_url
130
+ options.fetch(:url, "/#{ @controller_pathname }#{ resourceful_route_url_suffix }")
131
+ end
132
+
133
+ # @since 0.6.0
134
+ # @api private
135
+ def resourceful_route_url_suffix
136
+ RESOURCEFUL_ROUTE_URL_SUFFIXES.fetch(@action_name, "")
137
+ end
138
+
139
+ # @since 0.5.0
140
+ # @api private
141
+ def route_endpoint
142
+ "#{ @controller_pathname }#{ ROUTE_ENDPOINT_SEPARATOR }#{ @action_name }".downcase
143
+ end
144
+
145
+ # @since 0.5.0
146
+ # @api private
147
+ def known_application_names
148
+ Dir.glob(applications_path.join('/*')).map do |name|
149
+ File.basename(name)
150
+ end
151
+ end
152
+
153
+ # @since 0.5.0
154
+ # @api private
155
+ def assert_controller_name!
156
+ if @controller_name.nil? || @controller_name.empty?
157
+ raise ArgumentError.new("Unknown controller, please add controllers name with this syntax controller_name#action_name")
158
+ end
159
+ end
160
+
161
+ # @since 0.5.0
162
+ # @api private
163
+ def assert_action_name!
164
+ if @action_name.nil? || @action_name.strip == ''
165
+ raise ArgumentError.new("Unknown action, please add actions name with this syntax controller_name#action_name")
166
+ end
167
+ end
168
+
169
+ # @since 0.5.0
170
+ # @api private
171
+ def assert_application_name!
172
+ return if !environment.container?
173
+ if @application_name.nil? || @application_name.strip == '' || !application_path.exist?
174
+ existing_apps = known_application_names.join('/')
175
+ raise ArgumentError.new("Unknown app: `#{ @application_name.downcase }'. Please specify one of (#{ existing_apps }) as application name")
176
+ end
177
+ end
178
+
179
+ # @since 0.5.0
180
+ # @api private
181
+ def assert_http_method!
182
+ if !Hanami::Routing::Route::VALID_HTTP_VERBS.include?(http_method.upcase)
183
+ existing_http_methods = Hanami::Routing::Route::VALID_HTTP_VERBS
184
+ raise ArgumentError.new("Unknown HTTP method '#{http_method}', please use one of #{ existing_http_methods.join('/') }.")
185
+ end
186
+ end
187
+
188
+ def routes_path
189
+ if environment.container?
190
+ application_path.join('config', 'routes.rb')
191
+ else
192
+ application_path.join('..', 'config', 'routes.rb')
193
+ end
194
+ end
195
+
196
+ # The directory of the application
197
+ # ./app for 'app' architecture
198
+ # ./apps/APPLICATION_NAME for 'container'
199
+ def application_path
200
+ if environment.container?
201
+ applications_path.join(application_name_as_snake_case)
202
+ else
203
+ Pathname.new('app')
204
+ end
205
+ end
206
+
207
+ # The parent dir of the application directory.
208
+ def applications_path
209
+ Pathname.new('apps')
210
+ end
211
+
212
+ def view_path
213
+ application_path.join('views', @controller_pathname, "#{@action_name.downcase}.rb")
214
+ end
215
+
216
+ def view_spec_path
217
+ spec_root.join('views', @controller_pathname, "#{@action_name.downcase}_spec.rb")
218
+ end
219
+
220
+ def template_path
221
+ application_path.join('templates', @controller_pathname, "#{@action_name.downcase}.html.#{template_engine}")
222
+ end
223
+
224
+ def action_path
225
+ application_path.join('controllers', @controller_pathname, "#{@action_name.downcase}.rb")
226
+ end
227
+
228
+ def action_spec_path
229
+ spec_root.join('controllers', @controller_pathname, "#{ @action_name.downcase}_spec.rb")
230
+ end
231
+
232
+ def spec_root
233
+ Pathname.new('spec').join(app_base_dir)
234
+ end
235
+
236
+ def relative_action_path
237
+ path = Pathname.new('.').join('..', '..', '..')
238
+ path = path.join('..') if environment.container?
239
+ path.join(application_path, 'controllers', @controller_pathname, @action_name.downcase)
240
+ end
241
+
242
+ def relative_view_path
243
+ path = Pathname.new('.').join('..', '..', '..')
244
+ path = path.join('..') if environment.container?
245
+ path.join(application_path, 'views', @controller_pathname, @action_name.downcase)
246
+ end
247
+
248
+ def app_base_dir
249
+ if environment.container?
250
+ application_name_as_snake_case
251
+ else
252
+ ''
253
+ end
254
+ end
255
+
256
+ def application_name_as_snake_case
257
+ @application_name.gsub(/(.)([A-Z])/,'\1_\2').downcase
258
+ end
259
+ end
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,116 @@
1
+ require 'hanami/commands/generate/abstract'
2
+ require 'hanami/application_name'
3
+ require 'securerandom'
4
+
5
+ module Hanami
6
+ module Commands
7
+ class Generate
8
+ class App < Abstract
9
+
10
+ attr_reader :base_path
11
+
12
+ def initialize(options, application_name)
13
+ super(options)
14
+
15
+ assert_application_name!(application_name)
16
+ assert_architecture!
17
+
18
+ @application_name = ApplicationName.new(application_name)
19
+ @base_path = Pathname.pwd
20
+ end
21
+
22
+ def map_templates
23
+ add_mapping('application.rb.tt', 'application.rb')
24
+ add_mapping('config/routes.rb.tt', 'config/routes.rb')
25
+ add_mapping('views/application_layout.rb.tt', 'views/application_layout.rb')
26
+ add_mapping('templates/application.html.erb.tt', 'templates/application.html.erb')
27
+ add_mapping('favicon.ico', 'assets/favicon.ico')
28
+
29
+ add_mapping('.gitkeep', 'controllers/.gitkeep')
30
+ add_mapping('.gitkeep', 'assets/images/.gitkeep')
31
+ add_mapping('.gitkeep', 'assets/javascripts/.gitkeep')
32
+ add_mapping('.gitkeep', 'assets/stylesheets/.gitkeep')
33
+ add_mapping('.gitkeep', "../../spec/#{ app_name }/features/.gitkeep")
34
+ add_mapping('.gitkeep', "../../spec/#{ app_name }/controllers/.gitkeep")
35
+ add_mapping('.gitkeep', "../../spec/#{ app_name }/views/.gitkeep")
36
+ end
37
+
38
+ def template_options
39
+ {
40
+ app_name: app_name,
41
+ upcase_app_name: upcase_app_name,
42
+ classified_app_name: classified_app_name,
43
+ app_base_url: application_base_url,
44
+ app_base_path: application_base_path,
45
+ }
46
+ end
47
+
48
+ def post_process_templates
49
+ add_require_app
50
+ add_mount_app
51
+ add_web_session_secret
52
+ end
53
+
54
+ private
55
+
56
+ def application_base_url
57
+ options.fetch(:application_base_url, "/#{app_name}")
58
+ end
59
+
60
+ def add_require_app
61
+ # Add "require_relative '../apps/web/application'"
62
+ generator.inject_into_file base_path.join('config/environment.rb'), after: /require_relative '\.\.\/lib\/.*'/ do
63
+ "\nrequire_relative '../apps/#{ app_name }/application'"
64
+ end
65
+ end
66
+
67
+ def add_mount_app
68
+ generator.inject_into_file base_path.join('config/environment.rb'), after: /Hanami::Container.configure do/ do |match|
69
+ "\n mount #{ classified_app_name }::Application, at: '#{ application_base_url }'"
70
+ end
71
+ end
72
+
73
+ def add_web_session_secret
74
+ ['development', 'test'].each do |environment|
75
+ # Add WEB_SESSIONS_SECRET="abc123" (random hex)
76
+ generator.append_to_file base_path.join(".env.#{ environment }") do
77
+ %(#{ upcase_app_name }_SESSIONS_SECRET="#{ SecureRandom.hex(32) }"\n)
78
+ end
79
+ end
80
+ end
81
+
82
+ def target_path
83
+ base_path.join(application_base_path)
84
+ end
85
+
86
+ def app_name
87
+ @application_name.to_s
88
+ end
89
+
90
+ def upcase_app_name
91
+ @application_name.to_env_s
92
+ end
93
+
94
+ def application_base_path
95
+ ["apps", @application_name].join(::File::SEPARATOR)
96
+ end
97
+
98
+ def classified_app_name
99
+ Utils::String.new(app_name).classify.tr('::', '')
100
+ end
101
+
102
+ def assert_application_name!(value)
103
+ if value.nil? || value.strip.empty?
104
+ raise ArgumentError.new('Application name is nil or empty')
105
+ end
106
+ end
107
+
108
+ def assert_architecture!
109
+ if !environment.container?
110
+ raise ArgumentError.new('App generator is only available for container architecture.')
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,118 @@
1
+ require "hanami/commands/generate/abstract"
2
+
3
+ module Hanami
4
+ module Commands
5
+ class Generate
6
+ # @since 0.5.0
7
+ # @api private
8
+ class Mailer < Abstract
9
+
10
+ attr_reader :name, :name_underscored, :from, :to, :subject
11
+
12
+ # @since 0.5.0
13
+ # @api private
14
+ TXT_FORMAT = ".txt".freeze
15
+
16
+ # @since 0.5.0
17
+ # @api private
18
+ HTML_FORMAT = ".html".freeze
19
+
20
+ # @since 0.5.0
21
+ # @api private
22
+ DEFAULT_ENGINE = "erb".freeze
23
+
24
+ # @since 0.5.0
25
+ # @api private
26
+ DEFAULT_FROM = "'<from>'".freeze
27
+
28
+ # @since 0.5.0
29
+ # @api private
30
+ DEFAULT_TO = "'<to>'".freeze
31
+
32
+ # @since 0.5.0
33
+ # @api private
34
+ DEFAULT_SUBJECT = "'Hello'".freeze
35
+
36
+ # @since 0.5.0
37
+ # @api private
38
+ def initialize(options, name)
39
+ super(options)
40
+
41
+ @name_underscored = Utils::String.new(name).underscore
42
+ @name = Utils::String.new(name_underscored).classify
43
+ @from = options[:from] || DEFAULT_FROM
44
+ @to = options[:to] || DEFAULT_TO
45
+ @subject = options[:subject] || DEFAULT_SUBJECT
46
+
47
+ assert_name!
48
+ end
49
+
50
+ # @since 0.x.x
51
+ # @api private
52
+ def map_templates
53
+ add_mapping("mailer_spec.rb.tt", mailer_spec_path)
54
+ add_mapping("mailer.rb.tt", mailer_path)
55
+ add_mapping("template.txt.tt", txt_template_path)
56
+ add_mapping("template.html.tt", html_template_path)
57
+ end
58
+
59
+ def template_options
60
+ {
61
+ mailer: name,
62
+ from: from,
63
+ to: to,
64
+ subject: subject,
65
+ }
66
+ end
67
+
68
+ private
69
+
70
+ # @since 0.5.0
71
+ # @api private
72
+ def assert_name!
73
+ if name.nil? || name.strip.empty?
74
+ raise ArgumentError.new("Missing mailer name")
75
+ end
76
+ end
77
+
78
+ # @since 0.5.0
79
+ # @api private
80
+ def mailer_path
81
+ core_root.join('mailers', "#{ name_underscored }.rb").to_s
82
+ end
83
+
84
+ # @since 0.5.0
85
+ # @api private
86
+ def mailer_spec_path
87
+ spec_root.join(::File.basename(Dir.getwd), "mailers", "#{ name_underscored }_spec.rb")
88
+ end
89
+
90
+ # @since 0.5.0
91
+ # @api private
92
+ def txt_template_path
93
+ template_path(TXT_FORMAT)
94
+ end
95
+
96
+ # @since 0.5.0
97
+ # @api private
98
+ def html_template_path
99
+ template_path(HTML_FORMAT)
100
+ end
101
+
102
+ # @since 0.5.0
103
+ # @api private
104
+ def template_path(format)
105
+ core_root.join("mailers", "templates", "#{ name_underscored }#{ format }.#{ DEFAULT_ENGINE }")
106
+ end
107
+
108
+ def spec_root
109
+ Pathname.new("spec")
110
+ end
111
+
112
+ def core_root
113
+ Pathname.new("lib").join(::File.basename(Dir.getwd))
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end