hanami 2.0.0.rc1 → 2.0.1
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 +24 -0
- data/FEATURES.md +15 -21
- data/README.md +7 -37
- data/hanami.gemspec +5 -5
- data/lib/hanami/app.rb +2 -33
- data/lib/hanami/config/actions/content_security_policy.rb +1 -1
- data/lib/hanami/config/actions.rb +0 -3
- data/lib/hanami/config/logger.rb +52 -29
- data/lib/hanami/config.rb +22 -1
- data/lib/hanami/env.rb +52 -0
- data/lib/hanami/extensions/action/slice_configured_action.rb +5 -2
- data/lib/hanami/extensions/view/slice_configured_view.rb +4 -1
- data/lib/hanami/port.rb +45 -0
- data/lib/hanami/providers/rack.rb +15 -7
- data/lib/hanami/rake_tasks.rb +4 -5
- data/lib/hanami/slice.rb +3 -1
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +64 -15
- data/lib/hanami.rb +24 -5
- data/spec/integration/action/format_config_spec.rb +194 -0
- data/spec/integration/action/slice_configuration_spec.rb +39 -42
- data/spec/integration/code_loading/loading_from_lib_spec.rb +34 -0
- data/spec/integration/dotenv_loading_spec.rb +1 -0
- data/spec/integration/rack_app/body_parser_spec.rb +2 -5
- data/spec/integration/rack_app/rack_app_spec.rb +132 -5
- data/spec/integration/settings/access_in_slice_class_body_spec.rb +1 -0
- data/spec/integration/settings/loading_from_env_spec.rb +1 -0
- data/spec/integration/setup_spec.rb +2 -2
- data/spec/spec_helper.rb +12 -0
- data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +14 -14
- data/spec/unit/hanami/config/actions/default_values_spec.rb +0 -8
- data/spec/unit/hanami/config/actions_spec.rb +7 -10
- data/spec/unit/hanami/config/logger_spec.rb +4 -4
- data/spec/unit/hanami/port_spec.rb +117 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- data/spec/unit/hanami/web/rack_logger_spec.rb +4 -1
- metadata +36 -12
@@ -8,6 +8,9 @@ module Hanami
|
|
8
8
|
# @api private
|
9
9
|
# @since 2.0.0
|
10
10
|
class RackLogger
|
11
|
+
EMPTY_PARAMS = {}.freeze
|
12
|
+
private_constant :EMPTY_PARAMS
|
13
|
+
|
11
14
|
REQUEST_METHOD = "REQUEST_METHOD"
|
12
15
|
private_constant :REQUEST_METHOD
|
13
16
|
|
@@ -29,10 +32,46 @@ module Hanami
|
|
29
32
|
CONTENT_LENGTH = "Content-Length"
|
30
33
|
private_constant :CONTENT_LENGTH
|
31
34
|
|
35
|
+
MILISECOND = "ms"
|
36
|
+
private_constant :MILISECOND
|
37
|
+
|
38
|
+
MICROSECOND = "µs"
|
39
|
+
private_constant :MICROSECOND
|
40
|
+
|
41
|
+
# Dynamic extension used in production environments
|
42
|
+
# @api private
|
43
|
+
module Production
|
44
|
+
private
|
45
|
+
|
46
|
+
# @since 1.0.0
|
47
|
+
# @api private
|
48
|
+
def data(env, status:, elapsed:)
|
49
|
+
payload = super
|
50
|
+
payload[:elapsed] = elapsed
|
51
|
+
payload[:elapsed_unit] = MICROSECOND
|
52
|
+
payload
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Dynamic extension used in non-production environments
|
57
|
+
# @api private
|
58
|
+
module Development
|
59
|
+
private
|
60
|
+
|
61
|
+
# @since 1.0.0
|
62
|
+
# @api private
|
63
|
+
def data(env, status:, elapsed:)
|
64
|
+
payload = super
|
65
|
+
payload[:elapsed] = elapsed > 1000 ? "#{elapsed / 1000}ms" : "#{elapsed}#{MICROSECOND}"
|
66
|
+
payload
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
32
70
|
# @api private
|
33
71
|
# @since 2.0.0
|
34
|
-
def initialize(logger)
|
72
|
+
def initialize(logger, env: :development)
|
35
73
|
@logger = logger
|
74
|
+
extend(env == :production ? Production : Development)
|
36
75
|
end
|
37
76
|
|
38
77
|
# @api private
|
@@ -43,36 +82,46 @@ module Hanami
|
|
43
82
|
end
|
44
83
|
|
45
84
|
rack_monitor.on :error do |event|
|
46
|
-
|
85
|
+
# TODO: why we don't provide time on error?
|
86
|
+
log_exception event[:env], event[:exception], 500, 0
|
47
87
|
end
|
48
88
|
end
|
49
89
|
|
50
90
|
# @api private
|
51
91
|
# @since 2.0.0
|
52
92
|
def log_request(env, status, elapsed)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
elapsed: "#{elapsed}ms",
|
57
|
-
ip: env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR],
|
58
|
-
path: env[SCRIPT_NAME] + env[PATH_INFO].to_s,
|
59
|
-
length: extract_content_length(env),
|
60
|
-
params: env[ROUTER_PARAMS]
|
61
|
-
}
|
62
|
-
|
63
|
-
logger.info(data)
|
93
|
+
logger.tagged(:rack) do
|
94
|
+
logger.info(data(env, status: status, elapsed: elapsed))
|
95
|
+
end
|
64
96
|
end
|
65
97
|
|
66
98
|
# @api private
|
67
99
|
# @since 2.0.0
|
68
|
-
def log_exception(exception)
|
69
|
-
logger.
|
100
|
+
def log_exception(env, exception, status, elapsed)
|
101
|
+
logger.tagged(:rack) do
|
102
|
+
logger.error(exception, **data(env, status: status, elapsed: elapsed))
|
103
|
+
end
|
70
104
|
end
|
71
105
|
|
72
106
|
private
|
73
107
|
|
74
108
|
attr_reader :logger
|
75
109
|
|
110
|
+
# @api private
|
111
|
+
# @since 2.0.0
|
112
|
+
def data(env, status:, elapsed:)
|
113
|
+
{
|
114
|
+
verb: env[REQUEST_METHOD],
|
115
|
+
status: status,
|
116
|
+
ip: env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR],
|
117
|
+
path: "#{env[SCRIPT_NAME]}#{env[PATH_INFO]}",
|
118
|
+
length: extract_content_length(env),
|
119
|
+
params: env.fetch(ROUTER_PARAMS, EMPTY_PARAMS)
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
# @api private
|
124
|
+
# @since 2.0.0
|
76
125
|
def extract_content_length(env)
|
77
126
|
value = env[CONTENT_LENGTH]
|
78
127
|
!value || value.to_s == "0" ? "-" : value
|
data/lib/hanami.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "pathname"
|
3
4
|
require "zeitwerk"
|
4
5
|
require_relative "hanami/constants"
|
5
6
|
|
@@ -36,7 +37,8 @@ module Hanami
|
|
36
37
|
app_path = self.app_path
|
37
38
|
|
38
39
|
if app_path
|
39
|
-
|
40
|
+
prepare_load_path
|
41
|
+
require(app_path.to_s)
|
40
42
|
app
|
41
43
|
elsif raise_exception
|
42
44
|
raise(
|
@@ -47,6 +49,23 @@ module Hanami
|
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
52
|
+
# Prepare the load path as early as possible (based on the default root inferred from the location
|
53
|
+
# of `config/app.rb`), so `require` can work at the top of `config/app.rb`. This may be useful
|
54
|
+
# when external classes are needed for configuring certain aspects of the app.
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
# @since 2.0.0
|
58
|
+
private_class_method def self.prepare_load_path
|
59
|
+
lib_path = app_path&.join("..", "..", LIB_DIR)
|
60
|
+
|
61
|
+
if lib_path&.directory?
|
62
|
+
path = lib_path.realpath.to_s
|
63
|
+
$LOAD_PATH.prepend(path) unless $LOAD_PATH.include?(path)
|
64
|
+
end
|
65
|
+
|
66
|
+
lib_path
|
67
|
+
end
|
68
|
+
|
50
69
|
# Returns the Hamami app class.
|
51
70
|
#
|
52
71
|
# To ensure your Hanami app is loaded, run {.setup} (or `require "hanami/setup"`) first.
|
@@ -98,10 +117,10 @@ module Hanami
|
|
98
117
|
# Searches within the given directory, then searches upwards through parent directories until the
|
99
118
|
# app file can be found.
|
100
119
|
#
|
101
|
-
# @param dir [String] The directory from which to start searching. Defaults to the
|
102
|
-
# directory.
|
120
|
+
# @param dir [String, Pathname] The directory from which to start searching. Defaults to the
|
121
|
+
# current directory.
|
103
122
|
#
|
104
|
-
# @return [
|
123
|
+
# @return [Pathname, nil] the app file path, or nil if not found.
|
105
124
|
#
|
106
125
|
# @api public
|
107
126
|
# @since 2.0.0
|
@@ -110,7 +129,7 @@ module Hanami
|
|
110
129
|
path = dir.join(APP_PATH)
|
111
130
|
|
112
131
|
if path.file?
|
113
|
-
path
|
132
|
+
path
|
114
133
|
elsif !dir.root?
|
115
134
|
app_path(dir.parent)
|
116
135
|
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "rack/test"
|
5
|
+
|
6
|
+
RSpec.describe "App action / Format config", :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
|
+
it "adds a body parser middleware for the accepted formats from the action config" do
|
16
|
+
write "config/app.rb", <<~RUBY
|
17
|
+
require "hanami"
|
18
|
+
|
19
|
+
module TestApp
|
20
|
+
class App < Hanami::App
|
21
|
+
config.logger.stream = StringIO.new
|
22
|
+
|
23
|
+
config.actions.format :json
|
24
|
+
end
|
25
|
+
end
|
26
|
+
RUBY
|
27
|
+
|
28
|
+
write "config/routes.rb", <<~RUBY
|
29
|
+
module TestApp
|
30
|
+
class Routes < Hanami::Routes
|
31
|
+
post "/users", to: "users.create"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
RUBY
|
35
|
+
|
36
|
+
write "app/action.rb", <<~RUBY
|
37
|
+
# auto_register: false
|
38
|
+
|
39
|
+
module TestApp
|
40
|
+
class Action < Hanami::Action
|
41
|
+
end
|
42
|
+
end
|
43
|
+
RUBY
|
44
|
+
|
45
|
+
write "app/actions/users/create.rb", <<~RUBY
|
46
|
+
module TestApp
|
47
|
+
module Actions
|
48
|
+
module Users
|
49
|
+
class Create < TestApp::Action
|
50
|
+
def handle(req, res)
|
51
|
+
res.body = req.params[:users].join("-")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
RUBY
|
58
|
+
|
59
|
+
require "hanami/boot"
|
60
|
+
|
61
|
+
post(
|
62
|
+
"/users",
|
63
|
+
JSON.generate("users" => %w[jane john jade joe]),
|
64
|
+
"CONTENT_TYPE" => "application/json"
|
65
|
+
)
|
66
|
+
|
67
|
+
expect(last_response).to be_successful
|
68
|
+
expect(last_response.body).to eql("jane-john-jade-joe")
|
69
|
+
end
|
70
|
+
|
71
|
+
specify "adds a body parser middleware configured to parse any custom content type for the accepted formats" do
|
72
|
+
write "config/app.rb", <<~RUBY
|
73
|
+
require "hanami"
|
74
|
+
|
75
|
+
module TestApp
|
76
|
+
class App < Hanami::App
|
77
|
+
config.logger.stream = StringIO.new
|
78
|
+
|
79
|
+
config.actions.formats.add :json, ["application/json+scim", "application/json"]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
RUBY
|
83
|
+
|
84
|
+
write "config/routes.rb", <<~RUBY
|
85
|
+
module TestApp
|
86
|
+
class Routes < Hanami::Routes
|
87
|
+
post "/users", to: "users.create"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
RUBY
|
91
|
+
|
92
|
+
write "app/action.rb", <<~RUBY
|
93
|
+
# auto_register: false
|
94
|
+
|
95
|
+
module TestApp
|
96
|
+
class Action < Hanami::Action
|
97
|
+
end
|
98
|
+
end
|
99
|
+
RUBY
|
100
|
+
|
101
|
+
write "app/actions/users/create.rb", <<~RUBY
|
102
|
+
module TestApp
|
103
|
+
module Actions
|
104
|
+
module Users
|
105
|
+
class Create < TestApp::Action
|
106
|
+
def handle(req, res)
|
107
|
+
res.body = req.params[:users].join("-")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
RUBY
|
114
|
+
|
115
|
+
require "hanami/boot"
|
116
|
+
|
117
|
+
post(
|
118
|
+
"/users",
|
119
|
+
JSON.generate("users" => %w[jane john jade joe]),
|
120
|
+
"CONTENT_TYPE" => "application/json+scim"
|
121
|
+
)
|
122
|
+
|
123
|
+
expect(last_response).to be_successful
|
124
|
+
expect(last_response.body).to eql("jane-john-jade-joe")
|
125
|
+
|
126
|
+
post(
|
127
|
+
"/users",
|
128
|
+
JSON.generate("users" => %w[jane john jade joe]),
|
129
|
+
"CONTENT_TYPE" => "application/json"
|
130
|
+
)
|
131
|
+
|
132
|
+
expect(last_response).to be_successful
|
133
|
+
expect(last_response.body).to eql("jane-john-jade-joe")
|
134
|
+
end
|
135
|
+
|
136
|
+
it "does not add a body parser middleware if one is already added" do
|
137
|
+
write "config/app.rb", <<~RUBY
|
138
|
+
require "hanami"
|
139
|
+
|
140
|
+
module TestApp
|
141
|
+
class App < Hanami::App
|
142
|
+
config.logger.stream = StringIO.new
|
143
|
+
|
144
|
+
config.actions.format :json
|
145
|
+
config.middleware.use :body_parser, [json: "application/json+custom"]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
RUBY
|
149
|
+
|
150
|
+
write "config/routes.rb", <<~RUBY
|
151
|
+
module TestApp
|
152
|
+
class Routes < Hanami::Routes
|
153
|
+
post "/users", to: "users.create"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
RUBY
|
157
|
+
|
158
|
+
write "app/action.rb", <<~RUBY
|
159
|
+
# auto_register: false
|
160
|
+
|
161
|
+
module TestApp
|
162
|
+
class Action < Hanami::Action
|
163
|
+
end
|
164
|
+
end
|
165
|
+
RUBY
|
166
|
+
|
167
|
+
write "app/actions/users/create.rb", <<~RUBY
|
168
|
+
module TestApp
|
169
|
+
module Actions
|
170
|
+
module Users
|
171
|
+
class Create < TestApp::Action
|
172
|
+
config.formats.clear
|
173
|
+
|
174
|
+
def handle(req, res)
|
175
|
+
res.body = req.params[:users].join("-")
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
RUBY
|
182
|
+
|
183
|
+
require "hanami/boot"
|
184
|
+
|
185
|
+
post(
|
186
|
+
"/users",
|
187
|
+
JSON.generate("users" => %w[jane john jade joe]),
|
188
|
+
"CONTENT_TYPE" => "application/json+custom"
|
189
|
+
)
|
190
|
+
|
191
|
+
expect(last_response).to be_successful
|
192
|
+
expect(last_response.body).to eql("jane-john-jade-joe")
|
193
|
+
end
|
194
|
+
end
|
@@ -34,24 +34,25 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
34
34
|
it "applies default actions config from the app", :aggregate_failures do
|
35
35
|
prepare_app
|
36
36
|
|
37
|
-
expect(TestApp::Action.config.
|
38
|
-
expect(TestApp::Action.config.default_response_format).to eq :html
|
37
|
+
expect(TestApp::Action.config.formats.values).to eq []
|
39
38
|
end
|
40
39
|
|
41
40
|
it "applies actions config from the app" do
|
42
|
-
Hanami.app.config.actions.
|
41
|
+
Hanami.app.config.actions.format :json
|
43
42
|
|
44
43
|
prepare_app
|
45
44
|
|
46
|
-
expect(TestApp::Action.config.
|
45
|
+
expect(TestApp::Action.config.formats.values).to eq [:json]
|
47
46
|
end
|
48
47
|
|
49
48
|
it "does not override config in the base class" do
|
50
|
-
Hanami.app.config.actions.
|
49
|
+
Hanami.app.config.actions.format :csv
|
51
50
|
|
52
51
|
prepare_app
|
53
52
|
|
54
|
-
TestApp::Action.config.
|
53
|
+
TestApp::Action.config.format :json
|
54
|
+
|
55
|
+
expect(TestApp::Action.config.formats.values).to eq [:json]
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
@@ -74,24 +75,23 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
74
75
|
it "applies default actions config from the app", :aggregate_failures do
|
75
76
|
prepare_app
|
76
77
|
|
77
|
-
expect(TestApp::Actions::Articles::Index.config.
|
78
|
-
expect(TestApp::Actions::Articles::Index.config.default_response_format).to eq :html
|
78
|
+
expect(TestApp::Actions::Articles::Index.config.formats.values).to eq []
|
79
79
|
end
|
80
80
|
|
81
81
|
it "applies actions config from the app" do
|
82
|
-
Hanami.app.config.actions.
|
82
|
+
Hanami.app.config.actions.format :json
|
83
83
|
|
84
84
|
prepare_app
|
85
85
|
|
86
|
-
expect(TestApp::Actions::Articles::Index.config.
|
86
|
+
expect(TestApp::Actions::Articles::Index.config.formats.values).to eq [:json]
|
87
87
|
end
|
88
88
|
|
89
89
|
it "applies config from the base class" do
|
90
90
|
prepare_app
|
91
91
|
|
92
|
-
TestApp::Action.config.
|
92
|
+
TestApp::Action.config.format :json
|
93
93
|
|
94
|
-
expect(TestApp::Actions::Articles::Index.config.
|
94
|
+
expect(TestApp::Actions::Articles::Index.config.formats.values).to eq [:json]
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
@@ -114,24 +114,23 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
114
114
|
it "applies default actions config from the app", :aggregate_failures do
|
115
115
|
prepare_app
|
116
116
|
|
117
|
-
expect(Admin::Actions::Articles::Index.config.
|
118
|
-
expect(Admin::Actions::Articles::Index.config.default_response_format).to eq :html
|
117
|
+
expect(Admin::Actions::Articles::Index.config.formats.values).to eq []
|
119
118
|
end
|
120
119
|
|
121
120
|
it "applies actions config from the app" do
|
122
|
-
Hanami.app.config.actions.
|
121
|
+
Hanami.app.config.actions.format :json
|
123
122
|
|
124
123
|
prepare_app
|
125
124
|
|
126
|
-
expect(Admin::Actions::Articles::Index.config.
|
125
|
+
expect(Admin::Actions::Articles::Index.config.formats.values).to eq [:json]
|
127
126
|
end
|
128
127
|
|
129
128
|
it "applies config from the base class" do
|
130
129
|
prepare_app
|
131
130
|
|
132
|
-
TestApp::Action.config.
|
131
|
+
TestApp::Action.config.format :json
|
133
132
|
|
134
|
-
expect(Admin::Actions::Articles::Index.config.
|
133
|
+
expect(Admin::Actions::Articles::Index.config.formats.values).to eq [:json]
|
135
134
|
end
|
136
135
|
end
|
137
136
|
end
|
@@ -152,24 +151,23 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
152
151
|
it "applies default actions config from the app", :aggregate_failures do
|
153
152
|
prepare_app
|
154
153
|
|
155
|
-
expect(Admin::Action.config.
|
156
|
-
expect(Admin::Action.config.default_response_format).to eq :html
|
154
|
+
expect(Admin::Action.config.formats.values).to eq []
|
157
155
|
end
|
158
156
|
|
159
157
|
it "applies actions config from the app" do
|
160
|
-
Hanami.app.config.actions.
|
158
|
+
Hanami.app.config.actions.format :json
|
161
159
|
|
162
160
|
prepare_app
|
163
161
|
|
164
|
-
expect(Admin::Action.config.
|
162
|
+
expect(Admin::Action.config.formats.values).to eq [:json]
|
165
163
|
end
|
166
164
|
|
167
165
|
it "applies config from the app base class" do
|
168
166
|
prepare_app
|
169
167
|
|
170
|
-
TestApp::Action.config.
|
168
|
+
TestApp::Action.config.format :json
|
171
169
|
|
172
|
-
expect(Admin::Action.config.
|
170
|
+
expect(Admin::Action.config.formats.values).to eq [:json]
|
173
171
|
end
|
174
172
|
|
175
173
|
context "slice actions config present" do
|
@@ -178,7 +176,7 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
178
176
|
write "config/slices/admin.rb", <<~'RUBY'
|
179
177
|
module Admin
|
180
178
|
class Slice < Hanami::Slice
|
181
|
-
config.actions.
|
179
|
+
config.actions.format :csv
|
182
180
|
end
|
183
181
|
end
|
184
182
|
RUBY
|
@@ -188,24 +186,24 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
188
186
|
it "applies actions config from the slice" do
|
189
187
|
prepare_app
|
190
188
|
|
191
|
-
expect(Admin::Action.config.
|
189
|
+
expect(Admin::Action.config.formats.values).to eq [:csv]
|
192
190
|
end
|
193
191
|
|
194
192
|
it "prefers actions config from the slice over config from the app-level base class" do
|
195
193
|
prepare_app
|
196
194
|
|
197
|
-
TestApp::Action.config.
|
195
|
+
TestApp::Action.config.format :json
|
198
196
|
|
199
|
-
expect(Admin::Action.config.
|
197
|
+
expect(Admin::Action.config.formats.values).to eq [:csv]
|
200
198
|
end
|
201
199
|
|
202
200
|
it "prefers config from the base class over actions config from the slice" do
|
203
201
|
prepare_app
|
204
202
|
|
205
|
-
TestApp::Action.config.
|
206
|
-
Admin::Action.config.
|
203
|
+
TestApp::Action.config.format :csv
|
204
|
+
Admin::Action.config.format :json
|
207
205
|
|
208
|
-
expect(Admin::Action.config.
|
206
|
+
expect(Admin::Action.config.formats.values).to eq [:json]
|
209
207
|
end
|
210
208
|
end
|
211
209
|
end
|
@@ -229,16 +227,15 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
229
227
|
it "applies default actions config from the app", :aggregate_failures do
|
230
228
|
prepare_app
|
231
229
|
|
232
|
-
expect(Admin::Actions::Articles::Index.config.
|
233
|
-
expect(Admin::Actions::Articles::Index.config.default_response_format).to eq :html
|
230
|
+
expect(Admin::Actions::Articles::Index.config.formats.values).to eq []
|
234
231
|
end
|
235
232
|
|
236
233
|
it "applies actions config from the app" do
|
237
|
-
Hanami.app.config.actions.
|
234
|
+
Hanami.app.config.actions.format :json
|
238
235
|
|
239
236
|
prepare_app
|
240
237
|
|
241
|
-
expect(Admin::Actions::Articles::Index.config.
|
238
|
+
expect(Admin::Actions::Articles::Index.config.formats.values).to eq [:json]
|
242
239
|
end
|
243
240
|
|
244
241
|
it "applies actions config from the slice" do
|
@@ -246,7 +243,7 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
246
243
|
write "config/slices/admin.rb", <<~'RUBY'
|
247
244
|
module Admin
|
248
245
|
class Slice < Hanami::Slice
|
249
|
-
config.actions.
|
246
|
+
config.actions.format :json
|
250
247
|
end
|
251
248
|
end
|
252
249
|
RUBY
|
@@ -254,15 +251,15 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
254
251
|
|
255
252
|
prepare_app
|
256
253
|
|
257
|
-
expect(Admin::Actions::Articles::Index.config.
|
254
|
+
expect(Admin::Actions::Articles::Index.config.formats.values).to eq [:json]
|
258
255
|
end
|
259
256
|
|
260
257
|
it "applies config from the slice base class" do
|
261
258
|
prepare_app
|
262
259
|
|
263
|
-
Admin::Action.config.
|
260
|
+
Admin::Action.config.format :json
|
264
261
|
|
265
|
-
expect(Admin::Actions::Articles::Index.config.
|
262
|
+
expect(Admin::Actions::Articles::Index.config.formats.values).to eq [:json]
|
266
263
|
end
|
267
264
|
|
268
265
|
it "prefers config from the slice base class over actions config from the slice" do
|
@@ -270,7 +267,7 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
270
267
|
write "config/slices/admin.rb", <<~'RUBY'
|
271
268
|
module Admin
|
272
269
|
class Slice < Hanami::Slice
|
273
|
-
config.actions.
|
270
|
+
config.actions.format :csv
|
274
271
|
end
|
275
272
|
end
|
276
273
|
RUBY
|
@@ -278,9 +275,9 @@ RSpec.describe "App action / Slice configuration", :app_integration do
|
|
278
275
|
|
279
276
|
prepare_app
|
280
277
|
|
281
|
-
Admin::Action.config.
|
278
|
+
Admin::Action.config.format :json
|
282
279
|
|
283
|
-
expect(Admin::Actions::Articles::Index.config.
|
280
|
+
expect(Admin::Actions::Articles::Index.config.formats.values).to eq [:json]
|
284
281
|
end
|
285
282
|
end
|
286
283
|
end
|
@@ -82,6 +82,40 @@ RSpec.describe "Code loading / Loading from lib directory", :app_integration do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
+
describe "default root with requires at top of app file" do
|
86
|
+
before :context do
|
87
|
+
with_directory(@dir = make_tmp_directory.realpath) do
|
88
|
+
write "config/app.rb", <<~'RUBY'
|
89
|
+
require "hanami"
|
90
|
+
require "external_class"
|
91
|
+
|
92
|
+
module TestApp
|
93
|
+
class App < Hanami::App
|
94
|
+
@class_from_lib = ExternalClass
|
95
|
+
|
96
|
+
def self.class_from_lib
|
97
|
+
@class_from_lib
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
RUBY
|
102
|
+
|
103
|
+
write "lib/external_class.rb", <<~'RUBY'
|
104
|
+
class ExternalClass
|
105
|
+
end
|
106
|
+
RUBY
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
before do
|
111
|
+
with_directory(@dir) { require "hanami/setup" }
|
112
|
+
end
|
113
|
+
|
114
|
+
specify "classes in lib/ can be required directly from the top of the app file" do
|
115
|
+
expect(Hanami.app.class_from_lib).to be ExternalClass
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
85
119
|
context "app root reconfigured" do
|
86
120
|
before :context do
|
87
121
|
with_directory(@dir = make_tmp_directory.realpath) do
|
@@ -18,6 +18,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
18
18
|
|
19
19
|
module TestApp
|
20
20
|
class App < Hanami::App
|
21
|
+
config.actions.format :json
|
21
22
|
config.middleware.use :body_parser, :json
|
22
23
|
config.logger.stream = StringIO.new
|
23
24
|
end
|
@@ -37,8 +38,6 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
37
38
|
module Actions
|
38
39
|
module Users
|
39
40
|
class Create < Hanami::Action
|
40
|
-
accept :json
|
41
|
-
|
42
41
|
def handle(req, res)
|
43
42
|
res.body = req.params[:users].join("-")
|
44
43
|
end
|
@@ -66,7 +65,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
66
65
|
|
67
66
|
module TestApp
|
68
67
|
class App < Hanami::App
|
69
|
-
config.actions.formats["application/json+scim"]
|
68
|
+
config.actions.formats.add :json, ["application/json+scim"]
|
70
69
|
config.middleware.use :body_parser, [json: "application/json+scim"]
|
71
70
|
config.logger.stream = StringIO.new
|
72
71
|
end
|
@@ -86,8 +85,6 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
86
85
|
module Actions
|
87
86
|
module Users
|
88
87
|
class Create < Hanami::Action
|
89
|
-
accept :json
|
90
|
-
|
91
88
|
def handle(req, res)
|
92
89
|
res.body = req.params[:users].join("-")
|
93
90
|
end
|