hanami 2.3.2 → 3.0.0.rc1

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 (184) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -19
  3. data/LICENSE +20 -0
  4. data/README.md +18 -35
  5. data/hanami.gemspec +36 -37
  6. data/lib/hanami/config/db.rb +2 -0
  7. data/lib/hanami/config/i18n.rb +138 -0
  8. data/lib/hanami/config/logger.rb +15 -7
  9. data/lib/hanami/config/null_config.rb +1 -1
  10. data/lib/hanami/config/views.rb +17 -0
  11. data/lib/hanami/config.rb +66 -22
  12. data/lib/hanami/errors.rb +6 -0
  13. data/lib/hanami/extensions/action/slice_configured_action.rb +1 -1
  14. data/lib/hanami/extensions/action.rb +2 -2
  15. data/lib/hanami/extensions/mailer/slice_configured_mailer.rb +120 -0
  16. data/lib/hanami/extensions/mailer.rb +28 -0
  17. data/lib/hanami/extensions/operation/slice_configured_db_operation.rb +2 -0
  18. data/lib/hanami/extensions/view/context.rb +26 -4
  19. data/lib/hanami/extensions/view/part.rb +2 -0
  20. data/lib/hanami/extensions/view/slice_configured_context.rb +7 -0
  21. data/lib/hanami/extensions/view/slice_configured_part.rb +2 -0
  22. data/lib/hanami/extensions/view/slice_configured_view.rb +8 -8
  23. data/lib/hanami/extensions/view/standard_helpers.rb +4 -0
  24. data/lib/hanami/extensions.rb +6 -1
  25. data/lib/hanami/helpers/assets_helper.rb +0 -4
  26. data/lib/hanami/helpers/form_helper.rb +1 -1
  27. data/lib/hanami/helpers/i18n_helper.rb +176 -0
  28. data/lib/hanami/logger/rack_formatter.rb +73 -0
  29. data/lib/hanami/logger/sql_formatter.rb +80 -0
  30. data/lib/hanami/logger/sql_logger.rb +48 -0
  31. data/lib/hanami/middleware/render_errors.rb +2 -2
  32. data/lib/hanami/providers/db.rb +7 -2
  33. data/lib/hanami/providers/db_logging.rb +4 -7
  34. data/lib/hanami/providers/i18n/backend.rb +369 -0
  35. data/lib/hanami/providers/i18n/locale/en.yml +57 -0
  36. data/lib/hanami/providers/i18n.rb +114 -0
  37. data/lib/hanami/providers/mailers.rb +101 -0
  38. data/lib/hanami/routes.rb +1 -0
  39. data/lib/hanami/settings/composite_store.rb +53 -0
  40. data/lib/hanami/settings.rb +4 -4
  41. data/lib/hanami/slice/router.rb +15 -10
  42. data/lib/hanami/slice.rb +71 -11
  43. data/lib/hanami/slice_registrar.rb +2 -2
  44. data/lib/hanami/universal_logger.rb +250 -0
  45. data/lib/hanami/version.rb +1 -1
  46. data/lib/hanami/web/rack_logger.rb +2 -80
  47. data/lib/hanami/web/welcome.html.erb +443 -58
  48. data/lib/hanami.rb +4 -2
  49. metadata +28 -276
  50. data/CODE_OF_CONDUCT.md +0 -74
  51. data/FEATURES.md +0 -269
  52. data/LICENSE.md +0 -22
  53. data/spec/integration/action/cookies_spec.rb +0 -58
  54. data/spec/integration/action/csrf_protection_spec.rb +0 -54
  55. data/spec/integration/action/format_config_spec.rb +0 -129
  56. data/spec/integration/action/routes_spec.rb +0 -71
  57. data/spec/integration/action/sessions_spec.rb +0 -50
  58. data/spec/integration/action/slice_configuration_spec.rb +0 -284
  59. data/spec/integration/action/view_rendering/automatic_rendering_spec.rb +0 -247
  60. data/spec/integration/action/view_rendering/paired_view_inference_spec.rb +0 -115
  61. data/spec/integration/action/view_rendering/view_context_spec.rb +0 -221
  62. data/spec/integration/action/view_rendering_spec.rb +0 -89
  63. data/spec/integration/assets/assets_spec.rb +0 -155
  64. data/spec/integration/assets/cross_slice_assets_helpers_spec.rb +0 -129
  65. data/spec/integration/assets/serve_static_assets_spec.rb +0 -152
  66. data/spec/integration/code_loading/loading_from_app_spec.rb +0 -152
  67. data/spec/integration/code_loading/loading_from_lib_spec.rb +0 -242
  68. data/spec/integration/code_loading/loading_from_slice_spec.rb +0 -165
  69. data/spec/integration/container/application_routes_helper_spec.rb +0 -48
  70. data/spec/integration/container/auto_injection_spec.rb +0 -53
  71. data/spec/integration/container/auto_registration_spec.rb +0 -86
  72. data/spec/integration/container/autoloader_spec.rb +0 -82
  73. data/spec/integration/container/imports_spec.rb +0 -253
  74. data/spec/integration/container/prepare_container_spec.rb +0 -125
  75. data/spec/integration/container/provider_environment_spec.rb +0 -52
  76. data/spec/integration/container/provider_lifecycle_spec.rb +0 -61
  77. data/spec/integration/container/shutdown_spec.rb +0 -91
  78. data/spec/integration/container/standard_providers/rack_provider_spec.rb +0 -44
  79. data/spec/integration/container/standard_providers_spec.rb +0 -124
  80. data/spec/integration/db/auto_registration_spec.rb +0 -39
  81. data/spec/integration/db/commands_spec.rb +0 -80
  82. data/spec/integration/db/db_inflector_spec.rb +0 -57
  83. data/spec/integration/db/db_slices_spec.rb +0 -398
  84. data/spec/integration/db/db_spec.rb +0 -245
  85. data/spec/integration/db/gateways_spec.rb +0 -361
  86. data/spec/integration/db/logging_spec.rb +0 -301
  87. data/spec/integration/db/mappers_spec.rb +0 -84
  88. data/spec/integration/db/provider_config_spec.rb +0 -88
  89. data/spec/integration/db/provider_spec.rb +0 -35
  90. data/spec/integration/db/relations_spec.rb +0 -60
  91. data/spec/integration/db/repo_spec.rb +0 -300
  92. data/spec/integration/db/slices_importing_from_parent.rb +0 -130
  93. data/spec/integration/dotenv_loading_spec.rb +0 -138
  94. data/spec/integration/logging/exception_logging_spec.rb +0 -120
  95. data/spec/integration/logging/notifications_spec.rb +0 -68
  96. data/spec/integration/logging/request_logging_spec.rb +0 -202
  97. data/spec/integration/operations/extension_spec.rb +0 -122
  98. data/spec/integration/rack_app/body_parser_spec.rb +0 -108
  99. data/spec/integration/rack_app/method_override_spec.rb +0 -97
  100. data/spec/integration/rack_app/middleware_spec.rb +0 -720
  101. data/spec/integration/rack_app/non_booted_rack_app_spec.rb +0 -104
  102. data/spec/integration/rack_app/rack_app_spec.rb +0 -442
  103. data/spec/integration/rake_tasks_spec.rb +0 -107
  104. data/spec/integration/router/resource_routes_spec.rb +0 -281
  105. data/spec/integration/settings/access_in_slice_class_body_spec.rb +0 -83
  106. data/spec/integration/settings/access_to_constants_spec.rb +0 -46
  107. data/spec/integration/settings/loading_from_env_spec.rb +0 -188
  108. data/spec/integration/settings/settings_component_loading_spec.rb +0 -113
  109. data/spec/integration/settings/slice_registration_spec.rb +0 -145
  110. data/spec/integration/settings/using_types_spec.rb +0 -80
  111. data/spec/integration/setup_spec.rb +0 -165
  112. data/spec/integration/slices/external_slice_spec.rb +0 -91
  113. data/spec/integration/slices/slice_configuration_spec.rb +0 -42
  114. data/spec/integration/slices/slice_loading_spec.rb +0 -171
  115. data/spec/integration/slices/slice_registrations_spec.rb +0 -80
  116. data/spec/integration/slices/slice_routing_spec.rb +0 -219
  117. data/spec/integration/slices_spec.rb +0 -471
  118. data/spec/integration/view/config/default_context_spec.rb +0 -149
  119. data/spec/integration/view/config/inflector_spec.rb +0 -57
  120. data/spec/integration/view/config/part_class_spec.rb +0 -147
  121. data/spec/integration/view/config/part_namespace_spec.rb +0 -103
  122. data/spec/integration/view/config/paths_spec.rb +0 -119
  123. data/spec/integration/view/config/scope_class_spec.rb +0 -147
  124. data/spec/integration/view/config/scope_namespace_spec.rb +0 -103
  125. data/spec/integration/view/config/template_spec.rb +0 -38
  126. data/spec/integration/view/context/assets_spec.rb +0 -79
  127. data/spec/integration/view/context/inflector_spec.rb +0 -40
  128. data/spec/integration/view/context/request_spec.rb +0 -57
  129. data/spec/integration/view/context/routes_spec.rb +0 -84
  130. data/spec/integration/view/helpers/form_helper_spec.rb +0 -174
  131. data/spec/integration/view/helpers/part_helpers_spec.rb +0 -124
  132. data/spec/integration/view/helpers/scope_helpers_spec.rb +0 -84
  133. data/spec/integration/view/helpers/user_defined_helpers/part_helpers_spec.rb +0 -162
  134. data/spec/integration/view/helpers/user_defined_helpers/scope_helpers_spec.rb +0 -119
  135. data/spec/integration/view/parts/default_rendering_spec.rb +0 -138
  136. data/spec/integration/view/slice_configuration_spec.rb +0 -289
  137. data/spec/integration/view/views_spec.rb +0 -103
  138. data/spec/integration/web/content_security_policy_nonce_spec.rb +0 -251
  139. data/spec/integration/web/render_detailed_errors_spec.rb +0 -107
  140. data/spec/integration/web/render_errors_spec.rb +0 -242
  141. data/spec/integration/web/welcome_view_spec.rb +0 -84
  142. data/spec/spec_helper.rb +0 -28
  143. data/spec/support/app_integration.rb +0 -157
  144. data/spec/support/coverage.rb +0 -1
  145. data/spec/support/matchers.rb +0 -32
  146. data/spec/support/rspec.rb +0 -27
  147. data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +0 -96
  148. data/spec/unit/hanami/config/actions/cookies_spec.rb +0 -46
  149. data/spec/unit/hanami/config/actions/csrf_protection_spec.rb +0 -58
  150. data/spec/unit/hanami/config/actions/default_values_spec.rb +0 -43
  151. data/spec/unit/hanami/config/actions/sessions_spec.rb +0 -48
  152. data/spec/unit/hanami/config/actions_spec.rb +0 -52
  153. data/spec/unit/hanami/config/base_url_spec.rb +0 -25
  154. data/spec/unit/hanami/config/console_spec.rb +0 -22
  155. data/spec/unit/hanami/config/db_spec.rb +0 -38
  156. data/spec/unit/hanami/config/inflector_spec.rb +0 -35
  157. data/spec/unit/hanami/config/logger_spec.rb +0 -195
  158. data/spec/unit/hanami/config/render_detailed_errors_spec.rb +0 -25
  159. data/spec/unit/hanami/config/render_errors_spec.rb +0 -25
  160. data/spec/unit/hanami/config/router_spec.rb +0 -44
  161. data/spec/unit/hanami/config/slices_spec.rb +0 -34
  162. data/spec/unit/hanami/config/views_spec.rb +0 -80
  163. data/spec/unit/hanami/env_spec.rb +0 -37
  164. data/spec/unit/hanami/extensions/view/context_spec.rb +0 -59
  165. data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +0 -120
  166. data/spec/unit/hanami/helpers/assets_helper/audio_tag_spec.rb +0 -132
  167. data/spec/unit/hanami/helpers/assets_helper/favicon_tag_spec.rb +0 -87
  168. data/spec/unit/hanami/helpers/assets_helper/image_tag_spec.rb +0 -92
  169. data/spec/unit/hanami/helpers/assets_helper/javascript_tag_spec.rb +0 -143
  170. data/spec/unit/hanami/helpers/assets_helper/stylesheet_tag_spec.rb +0 -126
  171. data/spec/unit/hanami/helpers/assets_helper/video_tag_spec.rb +0 -136
  172. data/spec/unit/hanami/helpers/form_helper_spec.rb +0 -2857
  173. data/spec/unit/hanami/port_spec.rb +0 -117
  174. data/spec/unit/hanami/providers/db/config/default_config_spec.rb +0 -100
  175. data/spec/unit/hanami/providers/db/config/gateway_spec.rb +0 -73
  176. data/spec/unit/hanami/providers/db/config_spec.rb +0 -143
  177. data/spec/unit/hanami/router/errors/not_allowed_error_spec.rb +0 -27
  178. data/spec/unit/hanami/router/errors/not_found_error_spec.rb +0 -22
  179. data/spec/unit/hanami/settings/env_store_spec.rb +0 -52
  180. data/spec/unit/hanami/settings_spec.rb +0 -111
  181. data/spec/unit/hanami/slice_configurable_spec.rb +0 -141
  182. data/spec/unit/hanami/slice_name_spec.rb +0 -47
  183. data/spec/unit/hanami/slice_spec.rb +0 -99
  184. data/spec/unit/hanami/web/rack_logger_spec.rb +0 -99
@@ -1,720 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rack/test"
4
- require "stringio"
5
-
6
- RSpec.describe "Hanami web app", :app_integration do
7
- include Rack::Test::Methods
8
-
9
- let(:app) { Hanami.app }
10
-
11
- around do |example|
12
- with_tmp_directory(Dir.mktmpdir, &example)
13
- end
14
-
15
- before do
16
- module TestApp
17
- module Middlewares
18
- class Core
19
- def initialize(app)
20
- @app = app
21
- end
22
- end
23
-
24
- class Prepare < Core
25
- def call(env)
26
- env["tested"] = []
27
- @app.call(env)
28
- end
29
- end
30
-
31
- class AppendOne < Core
32
- def call(env)
33
- env["tested"] << "one"
34
- @app.call(env)
35
- end
36
- end
37
-
38
- class AppendTwo < Core
39
- def call(env)
40
- env["tested"] << "two"
41
- @app.call(env)
42
- end
43
- end
44
- end
45
- end
46
- end
47
-
48
- specify "Setting middlewares in the config" do
49
- write "config/app.rb", <<~RUBY
50
- require "hanami"
51
-
52
- module TestApp
53
- class App < Hanami::App
54
- config.logger.stream = StringIO.new
55
-
56
- config.middleware.use Middlewares::AppendOne
57
- config.middleware.use Middlewares::Prepare, before: Middlewares::AppendOne
58
- config.middleware.use Middlewares::AppendTwo, after: Middlewares::AppendOne
59
- end
60
- end
61
- RUBY
62
-
63
- write "config/routes.rb", <<~RUBY
64
- require "hanami/router"
65
-
66
- module TestApp
67
- class Routes < Hanami::Routes
68
- slice :main, at: "/" do
69
- root to: "home.index"
70
- end
71
- end
72
- end
73
- RUBY
74
-
75
- write "slices/main/actions/home/index.rb", <<~RUBY
76
- require "hanami/action"
77
-
78
- module Main
79
- module Actions
80
- module Home
81
- class Index < Hanami::Action
82
- def handle(req, res)
83
- res.body = req.env["tested"].join(".")
84
- end
85
- end
86
- end
87
- end
88
- end
89
- RUBY
90
-
91
- require "hanami/boot"
92
-
93
- get "/"
94
-
95
- expect(last_response).to be_successful
96
- expect(last_response.body).to eql("one.two")
97
- end
98
-
99
- specify "Setting middlewares in the router" do
100
- write "config/app.rb", <<~RUBY
101
- require "hanami"
102
-
103
- module TestApp
104
- class App < Hanami::App
105
- config.logger.stream = StringIO.new
106
- end
107
- end
108
- RUBY
109
-
110
- write "config/routes.rb", <<~RUBY
111
- require "hanami/router"
112
-
113
- module TestApp
114
- class Routes < Hanami::Routes
115
- slice :main, at: "/" do
116
- use TestApp::Middlewares::AppendOne
117
- use TestApp::Middlewares::Prepare, before: TestApp::Middlewares::AppendOne
118
- use TestApp::Middlewares::AppendTwo, after: TestApp::Middlewares::AppendOne
119
-
120
- root to: "home.index"
121
- end
122
- end
123
- end
124
- RUBY
125
-
126
- write "slices/main/actions/home/index.rb", <<~RUBY
127
- require "hanami/action"
128
-
129
- module Main
130
- module Actions
131
- module Home
132
- class Index < Hanami::Action
133
- def handle(req, res)
134
- res.body = req.env["tested"].join(".")
135
- end
136
- end
137
- end
138
- end
139
- end
140
- RUBY
141
-
142
- require "hanami/boot"
143
-
144
- get "/"
145
-
146
- expect(last_response).to be_successful
147
- expect(last_response.body).to eql("one.two")
148
- end
149
-
150
- specify "Setting a middleware that requires keyword arguments" do
151
- write "config/app.rb", <<~RUBY
152
- require "hanami"
153
-
154
- module TestApp
155
- class TestMiddleware
156
- def initialize(app, key:, value:)
157
- @app = app
158
- @key = key
159
- @value = value
160
- end
161
-
162
- def call(env)
163
- env[@key] = @value
164
- @app.call(env)
165
- end
166
- end
167
-
168
- class App < Hanami::App
169
- config.logger.stream = StringIO.new
170
-
171
- # Test middleware with keywords inside config
172
- config.middleware.use(TestApp::TestMiddleware, key: "from_config", value: "config")
173
- end
174
- end
175
- RUBY
176
-
177
- write "config/routes.rb", <<~RUBY
178
- require "hanami/router"
179
-
180
- module TestApp
181
- class Routes < Hanami::Routes
182
- slice :main, at: "/" do
183
- # Also test middleware with keywords inside routes
184
- use TestApp::TestMiddleware, key: "from_routes", value: "routes"
185
-
186
- root to: "home.index"
187
- end
188
- end
189
- end
190
- RUBY
191
-
192
- write "slices/main/actions/home/index.rb", <<~RUBY
193
- require "hanami/action"
194
-
195
- module Main
196
- module Actions
197
- module Home
198
- class Index < Hanami::Action
199
- def handle(request, response)
200
- response.body = [request.env["from_config"], request.env["from_routes"]].join(", ")
201
- end
202
- end
203
- end
204
- end
205
- end
206
- RUBY
207
-
208
- require "hanami/boot"
209
-
210
- get "/"
211
-
212
- expect(last_response).to be_successful
213
- expect(last_response.body).to eq "config, routes"
214
- end
215
-
216
- specify "Setting a middleware that requires a block" do
217
- write "config/app.rb", <<~RUBY
218
- require "hanami"
219
-
220
- module TestApp
221
- class TestMiddleware
222
- def initialize(app, &block)
223
- @app = app
224
- @block = block
225
- end
226
-
227
- def call(env)
228
- @block.call(env)
229
- @app.call(env)
230
- end
231
- end
232
-
233
- class App < Hanami::App
234
- config.logger.stream = StringIO.new
235
-
236
- config.middleware.use(TestApp::TestMiddleware) { |env| env["tested"] = "yes" }
237
- end
238
- end
239
- RUBY
240
-
241
- write "config/routes.rb", <<~RUBY
242
- require "hanami/router"
243
-
244
- module TestApp
245
- class Routes < Hanami::Routes
246
- slice :main, at: "/" do
247
- root to: "home.index"
248
- end
249
- end
250
- end
251
- RUBY
252
-
253
- write "slices/main/actions/home/index.rb", <<~RUBY
254
- require "hanami/action"
255
-
256
- module Main
257
- module Actions
258
- module Home
259
- class Index < Hanami::Action
260
- def handle(req, res)
261
- res.body = req.env["tested"]
262
- end
263
- end
264
- end
265
- end
266
- end
267
- RUBY
268
-
269
- require "hanami/boot"
270
-
271
- get "/"
272
-
273
- expect(last_response).to be_successful
274
- expect(last_response.body).to eql("yes")
275
- end
276
-
277
- context "Using module as a middleware" do
278
- it "sets the module as the middleware" do
279
- mod = Module.new
280
- app = Class.new(Hanami::App) { config.middleware.use(mod) }
281
-
282
- expect(app.config.middleware.stack["/"][0]).to include(mod)
283
- end
284
- end
285
-
286
- context "Setting an unsupported middleware" do
287
- it "raises meaningful error when an unsupported middleware spec was passed" do
288
- expect {
289
- Class.new(Hanami::App) do
290
- config.middleware.use("oops")
291
- end
292
- }.to raise_error(Hanami::UnsupportedMiddlewareSpecError)
293
- end
294
-
295
- it "raises meaningful error when corresponding file failed to load" do
296
- expect {
297
- Class.new(Hanami::App) do
298
- config.middleware.namespaces.delete(Hanami::Middleware)
299
- config.middleware.use(:body_parser)
300
- end
301
- }.to raise_error(Hanami::UnsupportedMiddlewareSpecError)
302
- end
303
- end
304
-
305
- context "with simple app" do
306
- before do
307
- write "config/app.rb", <<~RUBY
308
- require "hanami"
309
-
310
- module TestApp
311
- class App < Hanami::App
312
- config.logger.stream = File.new("/dev/null", "w")
313
- config.render_errors = true
314
- end
315
- end
316
- RUBY
317
-
318
- write "lib/test_app/middleware/authentication.rb", <<~RUBY
319
- module TestApp
320
- module Middleware
321
- class Authentication
322
- def self.inspect
323
- "<Middleware::Auth>"
324
- end
325
-
326
- def initialize(app)
327
- @app = app
328
- end
329
-
330
- def call(env)
331
- env["AUTH_USER_ID"] = user_id = "23"
332
- status, headers, body = @app.call(env)
333
- headers["X-Auth-User-ID"] = user_id
334
-
335
- [status, headers, body]
336
- end
337
- end
338
- end
339
- end
340
- RUBY
341
-
342
- write "config/routes.rb", <<~RUBY
343
- require "test_app/middleware/authentication"
344
-
345
- module TestApp
346
- class Routes < Hanami::Routes
347
- root to: ->(*) { [200, {"Content-Length" => "4"}, ["Home"]] }
348
-
349
- slice :admin, at: "/admin" do
350
- use TestApp::Middleware::Authentication
351
-
352
- root to: "home.show"
353
- end
354
- end
355
- end
356
- RUBY
357
-
358
- write "slices/admin/actions/home/show.rb", <<~RUBY
359
- module Admin
360
- module Actions
361
- module Home
362
- class Show < Hanami::Action
363
- def handle(req, res)
364
- res.body = "Hello from admin (User ID " + req.env['AUTH_USER_ID'] + ")"
365
- end
366
- end
367
- end
368
- end
369
- end
370
- RUBY
371
-
372
- require "hanami/boot"
373
- end
374
-
375
- it "excludes root scope" do
376
- get "/"
377
-
378
- expect(last_response.status).to eq 200
379
- expect(last_response.body).to eq "Home"
380
- expect(last_response.headers).to_not have_key("X-Auth-User-ID")
381
- end
382
-
383
- it "excludes not found routes in root scope" do
384
- get "/foo"
385
-
386
- expect(last_response.status).to eq 404
387
- expect(last_response.headers).to_not have_key("X-Auth-User-ID")
388
- end
389
-
390
- context "within slice" do
391
- it "uses Rack middleware" do
392
- get "/admin"
393
-
394
- expect(last_response.status).to eq 200
395
- expect(last_response.body).to eq "Hello from admin (User ID 23)"
396
- expect(last_response.headers).to have_key("X-Auth-User-ID")
397
- end
398
-
399
- it "does not uses the Rack middleware for not found paths" do
400
- get "/admin/users"
401
-
402
- expect(last_response.status).to eq 404
403
- expect(last_response.headers).not_to have_key("X-Auth-User-ID")
404
- end
405
- end
406
- end
407
-
408
- context "with complex app" do
409
- let(:app_modules) { %i[TestApp Admin APIV1] }
410
-
411
- before do
412
- write "config/app.rb", <<~RUBY
413
- require "hanami"
414
-
415
- module TestApp
416
- class App < Hanami::App
417
- config.logger.stream = File.new("/dev/null", "w")
418
- config.render_errors = true
419
- end
420
- end
421
- RUBY
422
-
423
- write "lib/test_app/middleware/elapsed.rb", <<~RUBY
424
- module TestApp
425
- module Middleware
426
- class Elapsed
427
- def self.inspect
428
- "<Middleware::Elapsed>"
429
- end
430
-
431
- def initialize(app)
432
- @app = app
433
- end
434
-
435
- def call(env)
436
- with_time_instrumentation do
437
- @app.call(env)
438
- end
439
- end
440
-
441
- private
442
-
443
- def with_time_instrumentation
444
- starting = now
445
- status, headers, body = yield
446
- ending = now
447
-
448
- headers["X-Elapsed"] = (ending - starting).round(5).to_s
449
- [status, headers, body]
450
- end
451
-
452
- def now
453
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
454
- end
455
- end
456
- end
457
- end
458
- RUBY
459
-
460
- write "lib/test_app/middleware/authentication.rb", <<~RUBY
461
- module TestApp
462
- module Middleware
463
- class Authentication
464
- def self.inspect
465
- "<Middleware::Auth>"
466
- end
467
-
468
- def initialize(app)
469
- @app = app
470
- end
471
-
472
- def call(env)
473
- env["AUTH_USER_ID"] = user_id = "23"
474
- status, headers, body = @app.call(env)
475
- headers["X-Auth-User-ID"] = user_id
476
-
477
- [status, headers, body]
478
- end
479
- end
480
- end
481
- end
482
- RUBY
483
-
484
- write "lib/test_app/middleware/rate_limiter.rb", <<~RUBY
485
- module TestApp
486
- module Middleware
487
- class RateLimiter
488
- def self.inspect
489
- "<Middleware::API::Limiter>"
490
- end
491
-
492
- def initialize(app)
493
- @app = app
494
- end
495
-
496
- def call(env)
497
- status, headers, body = @app.call(env)
498
- headers["X-API-Rate-Limit-Quota"] = "4000"
499
-
500
- [status, headers, body]
501
- end
502
- end
503
- end
504
- end
505
- RUBY
506
-
507
- write "lib/test_app/middleware/api_version.rb", <<~RUBY
508
- module TestApp
509
- module Middleware
510
- class APIVersion
511
- def self.inspect
512
- "<Middleware::API::Version>"
513
- end
514
-
515
- def initialize(app)
516
- @app = app
517
- end
518
-
519
- def call(env)
520
- status, headers, body = @app.call(env)
521
- headers["X-API-Version"] = "1"
522
-
523
- [status, headers, body]
524
- end
525
- end
526
- end
527
- end
528
- RUBY
529
-
530
- write "lib/test_app/middleware/api_deprecation.rb", <<~RUBY
531
- module TestApp
532
- module Middleware
533
- class APIDeprecation
534
- def self.inspect
535
- "<Middleware::API::Deprecation>"
536
- end
537
-
538
- def initialize(app)
539
- @app = app
540
- end
541
-
542
- def call(env)
543
- status, headers, body = @app.call(env)
544
- headers["X-API-Deprecated"] = "API v1 is deprecated"
545
-
546
- [status, headers, body]
547
- end
548
- end
549
- end
550
- end
551
- RUBY
552
-
553
- write "lib/test_app/middleware/scope_identifier.rb", <<~RUBY
554
- module TestApp
555
- module Middleware
556
- class ScopeIdentifier
557
- def self.inspect
558
- "<Middleware::API::ScopeIdentifier>"
559
- end
560
-
561
- def initialize(app, scope)
562
- @app = app
563
- @scope = scope
564
- end
565
-
566
- def call(env)
567
- status, header, body = @app.call(env)
568
- header["X-Identifier-" + @scope] = "true"
569
- [status, header, body]
570
- end
571
-
572
- def inspect
573
- "Scope identifier: " + @scope.inspect
574
- end
575
- end
576
- end
577
- end
578
- RUBY
579
-
580
- write "config/routes.rb", <<~RUBY
581
- module TestApp
582
- class Routes < Hanami::Routes
583
- use TestApp::Middleware::Elapsed
584
- use TestApp::Middleware::ScopeIdentifier, "Root"
585
- root to: ->(*) { [200, {"Content-Length" => "4"}, ["Home (complex app)"]] }
586
-
587
- mount ->(*) { [200, {"Content-Length" => "7"}, ["Mounted"]] }, at: "/mounted"
588
-
589
- slice :admin, at: "/admin" do
590
- use TestApp::Middleware::Authentication
591
- use TestApp::Middleware::ScopeIdentifier, "Admin"
592
-
593
- root to: "home.show"
594
- end
595
-
596
- # Without leading slash
597
- # See: https://github.com/hanami/api/issues/8
598
- scope "api" do
599
- use TestApp::Middleware::RateLimiter
600
- use TestApp::Middleware::ScopeIdentifier, "API"
601
-
602
- root to: ->(*) { [200, {"Content-Length" => "3"}, ["API"]] }
603
-
604
- slice :api_v1, at: "/v1" do
605
- use TestApp::Middleware::APIVersion
606
- use TestApp::Middleware::APIDeprecation
607
- use TestApp::Middleware::ScopeIdentifier, "API-V1"
608
-
609
- root to: "home.show"
610
- end
611
- end
612
- end
613
- end
614
- RUBY
615
-
616
- write "slices/admin/actions/home/show.rb", <<~RUBY
617
- module Admin
618
- module Actions
619
- module Home
620
- class Show < Hanami::Action
621
- def handle(req, res)
622
- res.body = "Hello from admin (User ID " + req.env['AUTH_USER_ID'] + ")"
623
- end
624
- end
625
- end
626
- end
627
- end
628
- RUBY
629
-
630
- write "slices/api_v1/actions/home/show.rb", <<~RUBY
631
- module APIV1
632
- module Actions
633
- module Home
634
- class Show < Hanami::Action
635
- def handle(req, res)
636
- res.body = "API v1"
637
- end
638
- end
639
- end
640
- end
641
- end
642
- RUBY
643
-
644
- require "hanami/boot"
645
- end
646
-
647
- it "uses Rack middleware" do
648
- get "/"
649
-
650
- expect(last_response.status).to be(200)
651
- expect(last_response.body).to eq("Home (complex app)")
652
- expect(last_response.headers["X-Identifier-Root"]).to eq("true")
653
- expect(last_response.headers).to have_key("X-Elapsed")
654
- expect(last_response.headers).to_not have_key("X-Auth-User-ID")
655
- expect(last_response.headers).to_not have_key("X-API-Rate-Limit-Quota")
656
- expect(last_response.headers).to_not have_key("X-API-Version")
657
- end
658
-
659
- it "does not use Rack middleware for other paths" do
660
- get "/__not_found__"
661
-
662
- expect(last_response.status).to eq 404
663
- expect(last_response.headers).not_to have_key("X-Identifier-Root")
664
- expect(last_response.headers).not_to have_key("X-Elapsed")
665
- expect(last_response.headers).not_to have_key("X-Auth-User-ID")
666
- expect(last_response.headers).not_to have_key("X-API-Rate-Limit-Quota")
667
- expect(last_response.headers).not_to have_key("X-API-Version")
668
- end
669
-
670
- context "scoped" do
671
- it "uses Rack middleware" do
672
- get "/admin"
673
-
674
- expect(last_response.status).to be(200)
675
- expect(last_response.headers["X-Identifier-Admin"]).to eq("true")
676
- expect(last_response.headers).to have_key("X-Elapsed")
677
- expect(last_response.headers).to have_key("X-Auth-User-ID")
678
- expect(last_response.headers).to_not have_key("X-API-Rate-Limit-Quota")
679
- expect(last_response.headers).to_not have_key("X-API-Version")
680
- end
681
-
682
- it "uses Rack middleware for other paths" do
683
- get "/admin/__not_found__"
684
-
685
- expect(last_response.status).to eq 404
686
- expect(last_response.headers).not_to have_key("X-Identifier-Admin")
687
- expect(last_response.headers).not_to have_key("X-Elapsed")
688
- expect(last_response.headers).not_to have_key("X-Elapsed")
689
- expect(last_response.headers).not_to have_key("X-Auth-User-ID")
690
- expect(last_response.headers).not_to have_key("X-API-Rate-Limit-Quota")
691
- expect(last_response.headers).not_to have_key("X-API-Version")
692
- end
693
-
694
- # See: https://github.com/hanami/api/issues/8
695
- it "uses Rack middleware for scope w/o leading slash" do
696
- get "/api"
697
-
698
- expect(last_response.status).to be(200)
699
- expect(last_response.headers["X-Identifier-Api"]).to eq("true")
700
- expect(last_response.headers).to have_key("X-Elapsed")
701
- expect(last_response.headers).to_not have_key("X-Auth-User-ID")
702
- expect(last_response.headers).to have_key("X-API-Rate-Limit-Quota")
703
- expect(last_response.headers).to_not have_key("X-API-Version")
704
- end
705
-
706
- # See: https://github.com/hanami/api/issues/8
707
- it "uses Rack middleware for nested scope w/o leading slash" do
708
- get "/api/v1"
709
-
710
- expect(last_response.status).to be(200)
711
- expect(last_response.headers["X-Identifier-API-V1"]).to eq("true")
712
- expect(last_response.headers).to have_key("X-Elapsed")
713
- expect(last_response.headers).to_not have_key("X-Auth-User-ID")
714
- expect(last_response.headers).to have_key("X-API-Rate-Limit-Quota")
715
- expect(last_response.headers).to have_key("X-API-Deprecated")
716
- expect(last_response.headers["X-API-Version"]).to eq("1")
717
- end
718
- end
719
- end
720
- end