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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -19
- data/LICENSE +20 -0
- data/README.md +18 -35
- data/hanami.gemspec +36 -37
- data/lib/hanami/config/db.rb +2 -0
- data/lib/hanami/config/i18n.rb +138 -0
- data/lib/hanami/config/logger.rb +15 -7
- data/lib/hanami/config/null_config.rb +1 -1
- data/lib/hanami/config/views.rb +17 -0
- data/lib/hanami/config.rb +66 -22
- data/lib/hanami/errors.rb +6 -0
- data/lib/hanami/extensions/action/slice_configured_action.rb +1 -1
- data/lib/hanami/extensions/action.rb +2 -2
- data/lib/hanami/extensions/mailer/slice_configured_mailer.rb +120 -0
- data/lib/hanami/extensions/mailer.rb +28 -0
- data/lib/hanami/extensions/operation/slice_configured_db_operation.rb +2 -0
- data/lib/hanami/extensions/view/context.rb +26 -4
- data/lib/hanami/extensions/view/part.rb +2 -0
- data/lib/hanami/extensions/view/slice_configured_context.rb +7 -0
- data/lib/hanami/extensions/view/slice_configured_part.rb +2 -0
- data/lib/hanami/extensions/view/slice_configured_view.rb +8 -8
- data/lib/hanami/extensions/view/standard_helpers.rb +4 -0
- data/lib/hanami/extensions.rb +6 -1
- data/lib/hanami/helpers/assets_helper.rb +0 -4
- data/lib/hanami/helpers/form_helper.rb +1 -1
- data/lib/hanami/helpers/i18n_helper.rb +176 -0
- data/lib/hanami/logger/rack_formatter.rb +73 -0
- data/lib/hanami/logger/sql_formatter.rb +80 -0
- data/lib/hanami/logger/sql_logger.rb +48 -0
- data/lib/hanami/middleware/render_errors.rb +2 -2
- data/lib/hanami/providers/db.rb +7 -2
- data/lib/hanami/providers/db_logging.rb +4 -7
- data/lib/hanami/providers/i18n/backend.rb +369 -0
- data/lib/hanami/providers/i18n/locale/en.yml +57 -0
- data/lib/hanami/providers/i18n.rb +114 -0
- data/lib/hanami/providers/mailers.rb +101 -0
- data/lib/hanami/routes.rb +1 -0
- data/lib/hanami/settings/composite_store.rb +53 -0
- data/lib/hanami/settings.rb +4 -4
- data/lib/hanami/slice/router.rb +15 -10
- data/lib/hanami/slice.rb +71 -11
- data/lib/hanami/slice_registrar.rb +2 -2
- data/lib/hanami/universal_logger.rb +250 -0
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +2 -80
- data/lib/hanami/web/welcome.html.erb +443 -58
- data/lib/hanami.rb +4 -2
- metadata +28 -276
- data/CODE_OF_CONDUCT.md +0 -74
- data/FEATURES.md +0 -269
- data/LICENSE.md +0 -22
- data/spec/integration/action/cookies_spec.rb +0 -58
- data/spec/integration/action/csrf_protection_spec.rb +0 -54
- data/spec/integration/action/format_config_spec.rb +0 -129
- data/spec/integration/action/routes_spec.rb +0 -71
- data/spec/integration/action/sessions_spec.rb +0 -50
- data/spec/integration/action/slice_configuration_spec.rb +0 -284
- data/spec/integration/action/view_rendering/automatic_rendering_spec.rb +0 -247
- data/spec/integration/action/view_rendering/paired_view_inference_spec.rb +0 -115
- data/spec/integration/action/view_rendering/view_context_spec.rb +0 -221
- data/spec/integration/action/view_rendering_spec.rb +0 -89
- data/spec/integration/assets/assets_spec.rb +0 -155
- data/spec/integration/assets/cross_slice_assets_helpers_spec.rb +0 -129
- data/spec/integration/assets/serve_static_assets_spec.rb +0 -152
- data/spec/integration/code_loading/loading_from_app_spec.rb +0 -152
- data/spec/integration/code_loading/loading_from_lib_spec.rb +0 -242
- data/spec/integration/code_loading/loading_from_slice_spec.rb +0 -165
- data/spec/integration/container/application_routes_helper_spec.rb +0 -48
- data/spec/integration/container/auto_injection_spec.rb +0 -53
- data/spec/integration/container/auto_registration_spec.rb +0 -86
- data/spec/integration/container/autoloader_spec.rb +0 -82
- data/spec/integration/container/imports_spec.rb +0 -253
- data/spec/integration/container/prepare_container_spec.rb +0 -125
- data/spec/integration/container/provider_environment_spec.rb +0 -52
- data/spec/integration/container/provider_lifecycle_spec.rb +0 -61
- data/spec/integration/container/shutdown_spec.rb +0 -91
- data/spec/integration/container/standard_providers/rack_provider_spec.rb +0 -44
- data/spec/integration/container/standard_providers_spec.rb +0 -124
- data/spec/integration/db/auto_registration_spec.rb +0 -39
- data/spec/integration/db/commands_spec.rb +0 -80
- data/spec/integration/db/db_inflector_spec.rb +0 -57
- data/spec/integration/db/db_slices_spec.rb +0 -398
- data/spec/integration/db/db_spec.rb +0 -245
- data/spec/integration/db/gateways_spec.rb +0 -361
- data/spec/integration/db/logging_spec.rb +0 -301
- data/spec/integration/db/mappers_spec.rb +0 -84
- data/spec/integration/db/provider_config_spec.rb +0 -88
- data/spec/integration/db/provider_spec.rb +0 -35
- data/spec/integration/db/relations_spec.rb +0 -60
- data/spec/integration/db/repo_spec.rb +0 -300
- data/spec/integration/db/slices_importing_from_parent.rb +0 -130
- data/spec/integration/dotenv_loading_spec.rb +0 -138
- data/spec/integration/logging/exception_logging_spec.rb +0 -120
- data/spec/integration/logging/notifications_spec.rb +0 -68
- data/spec/integration/logging/request_logging_spec.rb +0 -202
- data/spec/integration/operations/extension_spec.rb +0 -122
- data/spec/integration/rack_app/body_parser_spec.rb +0 -108
- data/spec/integration/rack_app/method_override_spec.rb +0 -97
- data/spec/integration/rack_app/middleware_spec.rb +0 -720
- data/spec/integration/rack_app/non_booted_rack_app_spec.rb +0 -104
- data/spec/integration/rack_app/rack_app_spec.rb +0 -442
- data/spec/integration/rake_tasks_spec.rb +0 -107
- data/spec/integration/router/resource_routes_spec.rb +0 -281
- data/spec/integration/settings/access_in_slice_class_body_spec.rb +0 -83
- data/spec/integration/settings/access_to_constants_spec.rb +0 -46
- data/spec/integration/settings/loading_from_env_spec.rb +0 -188
- data/spec/integration/settings/settings_component_loading_spec.rb +0 -113
- data/spec/integration/settings/slice_registration_spec.rb +0 -145
- data/spec/integration/settings/using_types_spec.rb +0 -80
- data/spec/integration/setup_spec.rb +0 -165
- data/spec/integration/slices/external_slice_spec.rb +0 -91
- data/spec/integration/slices/slice_configuration_spec.rb +0 -42
- data/spec/integration/slices/slice_loading_spec.rb +0 -171
- data/spec/integration/slices/slice_registrations_spec.rb +0 -80
- data/spec/integration/slices/slice_routing_spec.rb +0 -219
- data/spec/integration/slices_spec.rb +0 -471
- data/spec/integration/view/config/default_context_spec.rb +0 -149
- data/spec/integration/view/config/inflector_spec.rb +0 -57
- data/spec/integration/view/config/part_class_spec.rb +0 -147
- data/spec/integration/view/config/part_namespace_spec.rb +0 -103
- data/spec/integration/view/config/paths_spec.rb +0 -119
- data/spec/integration/view/config/scope_class_spec.rb +0 -147
- data/spec/integration/view/config/scope_namespace_spec.rb +0 -103
- data/spec/integration/view/config/template_spec.rb +0 -38
- data/spec/integration/view/context/assets_spec.rb +0 -79
- data/spec/integration/view/context/inflector_spec.rb +0 -40
- data/spec/integration/view/context/request_spec.rb +0 -57
- data/spec/integration/view/context/routes_spec.rb +0 -84
- data/spec/integration/view/helpers/form_helper_spec.rb +0 -174
- data/spec/integration/view/helpers/part_helpers_spec.rb +0 -124
- data/spec/integration/view/helpers/scope_helpers_spec.rb +0 -84
- data/spec/integration/view/helpers/user_defined_helpers/part_helpers_spec.rb +0 -162
- data/spec/integration/view/helpers/user_defined_helpers/scope_helpers_spec.rb +0 -119
- data/spec/integration/view/parts/default_rendering_spec.rb +0 -138
- data/spec/integration/view/slice_configuration_spec.rb +0 -289
- data/spec/integration/view/views_spec.rb +0 -103
- data/spec/integration/web/content_security_policy_nonce_spec.rb +0 -251
- data/spec/integration/web/render_detailed_errors_spec.rb +0 -107
- data/spec/integration/web/render_errors_spec.rb +0 -242
- data/spec/integration/web/welcome_view_spec.rb +0 -84
- data/spec/spec_helper.rb +0 -28
- data/spec/support/app_integration.rb +0 -157
- data/spec/support/coverage.rb +0 -1
- data/spec/support/matchers.rb +0 -32
- data/spec/support/rspec.rb +0 -27
- data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +0 -96
- data/spec/unit/hanami/config/actions/cookies_spec.rb +0 -46
- data/spec/unit/hanami/config/actions/csrf_protection_spec.rb +0 -58
- data/spec/unit/hanami/config/actions/default_values_spec.rb +0 -43
- data/spec/unit/hanami/config/actions/sessions_spec.rb +0 -48
- data/spec/unit/hanami/config/actions_spec.rb +0 -52
- data/spec/unit/hanami/config/base_url_spec.rb +0 -25
- data/spec/unit/hanami/config/console_spec.rb +0 -22
- data/spec/unit/hanami/config/db_spec.rb +0 -38
- data/spec/unit/hanami/config/inflector_spec.rb +0 -35
- data/spec/unit/hanami/config/logger_spec.rb +0 -195
- data/spec/unit/hanami/config/render_detailed_errors_spec.rb +0 -25
- data/spec/unit/hanami/config/render_errors_spec.rb +0 -25
- data/spec/unit/hanami/config/router_spec.rb +0 -44
- data/spec/unit/hanami/config/slices_spec.rb +0 -34
- data/spec/unit/hanami/config/views_spec.rb +0 -80
- data/spec/unit/hanami/env_spec.rb +0 -37
- data/spec/unit/hanami/extensions/view/context_spec.rb +0 -59
- data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +0 -120
- data/spec/unit/hanami/helpers/assets_helper/audio_tag_spec.rb +0 -132
- data/spec/unit/hanami/helpers/assets_helper/favicon_tag_spec.rb +0 -87
- data/spec/unit/hanami/helpers/assets_helper/image_tag_spec.rb +0 -92
- data/spec/unit/hanami/helpers/assets_helper/javascript_tag_spec.rb +0 -143
- data/spec/unit/hanami/helpers/assets_helper/stylesheet_tag_spec.rb +0 -126
- data/spec/unit/hanami/helpers/assets_helper/video_tag_spec.rb +0 -136
- data/spec/unit/hanami/helpers/form_helper_spec.rb +0 -2857
- data/spec/unit/hanami/port_spec.rb +0 -117
- data/spec/unit/hanami/providers/db/config/default_config_spec.rb +0 -100
- data/spec/unit/hanami/providers/db/config/gateway_spec.rb +0 -73
- data/spec/unit/hanami/providers/db/config_spec.rb +0 -143
- data/spec/unit/hanami/router/errors/not_allowed_error_spec.rb +0 -27
- data/spec/unit/hanami/router/errors/not_found_error_spec.rb +0 -22
- data/spec/unit/hanami/settings/env_store_spec.rb +0 -52
- data/spec/unit/hanami/settings_spec.rb +0 -111
- data/spec/unit/hanami/slice_configurable_spec.rb +0 -141
- data/spec/unit/hanami/slice_name_spec.rb +0 -47
- data/spec/unit/hanami/slice_spec.rb +0 -99
- 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
|