hanami 0.0.0 → 0.7.0

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