hanami 2.0.0 → 2.0.2
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 +17 -0
- data/lib/hanami/app.rb +2 -28
- data/lib/hanami/config/actions/content_security_policy.rb +1 -2
- data/lib/hanami/env.rb +52 -0
- data/lib/hanami/port.rb +45 -0
- data/lib/hanami/providers/rack.rb +14 -7
- data/lib/hanami/version.rb +1 -1
- data/spec/integration/dotenv_loading_spec.rb +1 -0
- data/spec/integration/rack_app/rack_app_spec.rb +59 -3
- 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/unit/hanami/config/actions/content_security_policy_spec.rb +16 -17
- data/spec/unit/hanami/port_spec.rb +117 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '099623ad9ce0088b28fc658340d85094d493f27e4320df725d4dfc062ee4939c'
|
4
|
+
data.tar.gz: 759492d76fb078f025d00e57d8c81cc5840ca769e5a20a0e50d20a0221c9a599
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa25a5f37d22c1faf03906914f1c0a4f5d119ae39088df6878d75ef5c830b7be7632b2b633aa915619ff44990784016da4df666b5343b56166cb31a1f613a4ea
|
7
|
+
data.tar.gz: ff70c18b250591af4c2fbaf32532a7ca5cb00adbc17ab87a03e0bb0dddd0ca5a19a7440aa63d0abc9c1570d9784027a4981d2d097632852e7b69f150ebd56328
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,23 @@
|
|
2
2
|
|
3
3
|
The web, with simplicity.
|
4
4
|
|
5
|
+
## v2.0.2 - 2022-12-25
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- [Luca Guidi] Official support for Ruby 3.2
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
|
13
|
+
- [Luca Guidi] Content Security Policy: remove deprecated `plugin-types`
|
14
|
+
|
15
|
+
## v2.0.1 - 2022-12-06
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
|
19
|
+
- [Luca Guidi] Ensure `Content-Security-Policy` HTTP response header to be returned as a single line
|
20
|
+
- [Tim Riley] Ensure Rack events are on internal notifications system
|
21
|
+
|
5
22
|
## v2.0.0 - 2022-11-22
|
6
23
|
|
7
24
|
### Added
|
data/lib/hanami/app.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "constants"
|
4
|
+
require_relative "env"
|
4
5
|
|
5
6
|
module Hanami
|
6
7
|
# The Hanami app is a singular slice tasked with managing the core components of the app and
|
@@ -28,8 +29,7 @@ module Hanami
|
|
28
29
|
@_mutex.synchronize do
|
29
30
|
subclass.class_eval do
|
30
31
|
@config = Hanami::Config.new(app_name: slice_name, env: Hanami.env)
|
31
|
-
|
32
|
-
load_dotenv
|
32
|
+
Hanami::Env.load
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -97,32 +97,6 @@ module Hanami
|
|
97
97
|
|
98
98
|
private
|
99
99
|
|
100
|
-
# Uses [dotenv](https://github.com/bkeepers/dotenv) (if available) to populate `ENV` from
|
101
|
-
# various `.env` files.
|
102
|
-
#
|
103
|
-
# For a given `HANAMI_ENV` environment, the `.env` files are looked up in the following order:
|
104
|
-
#
|
105
|
-
# - .env.{environment}.local
|
106
|
-
# - .env.local (unless the environment is `test`)
|
107
|
-
# - .env.{environment}
|
108
|
-
# - .env
|
109
|
-
#
|
110
|
-
# If dotenv is unavailable, the method exits and does nothing.
|
111
|
-
def load_dotenv
|
112
|
-
return unless Hanami.bundled?("dotenv")
|
113
|
-
|
114
|
-
hanami_env = Hanami.env
|
115
|
-
dotenv_files = [
|
116
|
-
".env.#{hanami_env}.local",
|
117
|
-
(".env.local" unless hanami_env == :test),
|
118
|
-
".env.#{hanami_env}",
|
119
|
-
".env"
|
120
|
-
].compact
|
121
|
-
|
122
|
-
require "dotenv"
|
123
|
-
Dotenv.load(*dotenv_files)
|
124
|
-
end
|
125
|
-
|
126
100
|
def prepare_all
|
127
101
|
prepare_load_path
|
128
102
|
|
@@ -22,7 +22,6 @@ module Hanami
|
|
22
22
|
img_src: "'self' https: data:",
|
23
23
|
media_src: "'self'",
|
24
24
|
object_src: "'none'",
|
25
|
-
plugin_types: "application/pdf",
|
26
25
|
script_src: "'self'",
|
27
26
|
style_src: "'self' 'unsafe-inline' https:"
|
28
27
|
}
|
@@ -102,7 +101,7 @@ module Hanami
|
|
102
101
|
def to_s
|
103
102
|
@policy.map do |key, value|
|
104
103
|
"#{dasherize(key)} #{value}"
|
105
|
-
end.join("
|
104
|
+
end.join(";")
|
106
105
|
end
|
107
106
|
|
108
107
|
private
|
data/lib/hanami/env.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Env
|
5
|
+
# @since 2.0.1
|
6
|
+
# @api private
|
7
|
+
@_loaded = false
|
8
|
+
|
9
|
+
# Uses [dotenv](https://github.com/bkeepers/dotenv) (if available) to populate `ENV` from
|
10
|
+
# various `.env` files.
|
11
|
+
#
|
12
|
+
# For a given `HANAMI_ENV` environment, the `.env` files are looked up in the following order:
|
13
|
+
#
|
14
|
+
# - .env.{environment}.local
|
15
|
+
# - .env.local (unless the environment is `test`)
|
16
|
+
# - .env.{environment}
|
17
|
+
# - .env
|
18
|
+
#
|
19
|
+
# If dotenv is unavailable, the method exits and does nothing.
|
20
|
+
#
|
21
|
+
# @since 2.0.1
|
22
|
+
# @api private
|
23
|
+
def self.load(env = Hanami.env)
|
24
|
+
return unless Hanami.bundled?("dotenv")
|
25
|
+
return if loaded?
|
26
|
+
|
27
|
+
dotenv_files = [
|
28
|
+
".env.#{env}.local",
|
29
|
+
(".env.local" unless env == :test),
|
30
|
+
".env.#{env}",
|
31
|
+
".env"
|
32
|
+
].compact
|
33
|
+
|
34
|
+
require "dotenv"
|
35
|
+
Dotenv.load(*dotenv_files)
|
36
|
+
|
37
|
+
loaded!
|
38
|
+
end
|
39
|
+
|
40
|
+
# @since 2.0.1
|
41
|
+
# @api private
|
42
|
+
def self.loaded?
|
43
|
+
@_loaded
|
44
|
+
end
|
45
|
+
|
46
|
+
# @since 2.0.1
|
47
|
+
# @api private
|
48
|
+
def self.loaded!
|
49
|
+
@_loaded = true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/hanami/port.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
# @since 2.0.1
|
5
|
+
# @api private
|
6
|
+
module Port
|
7
|
+
# @since 2.0.1
|
8
|
+
# @api private
|
9
|
+
DEFAULT = 2300
|
10
|
+
|
11
|
+
# @since 2.0.1
|
12
|
+
# @api private
|
13
|
+
ENV_VAR = "HANAMI_PORT"
|
14
|
+
|
15
|
+
# @since 2.0.1
|
16
|
+
# @api private
|
17
|
+
def self.call(value, env = ENV.fetch(ENV_VAR, nil))
|
18
|
+
return Integer(value) if !value.nil? && !default?(value)
|
19
|
+
return Integer(env) unless env.nil?
|
20
|
+
return Integer(value) unless value.nil?
|
21
|
+
|
22
|
+
DEFAULT
|
23
|
+
end
|
24
|
+
|
25
|
+
# @since 2.0.1
|
26
|
+
# @api private
|
27
|
+
def self.call!(value)
|
28
|
+
return if default?(value)
|
29
|
+
|
30
|
+
ENV[ENV_VAR] = value.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
# @since 2.0.1
|
34
|
+
# @api private
|
35
|
+
def self.default?(value)
|
36
|
+
value.to_i == DEFAULT
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
# @since 2.0.1
|
41
|
+
# @api private
|
42
|
+
alias_method :[], :call
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -15,20 +15,27 @@ module Hanami
|
|
15
15
|
class Rack < Dry::System::Provider::Source
|
16
16
|
# @api private
|
17
17
|
def prepare
|
18
|
-
require "dry/monitor"
|
19
|
-
require "hanami/web/rack_logger"
|
20
|
-
|
21
18
|
Dry::Monitor.load_extensions(:rack)
|
19
|
+
|
20
|
+
# Explicitly register the Rack middleware events on our notifications bus. The Dry::Monitor
|
21
|
+
# rack extension (activated above) does register these globally, but if the notifications
|
22
|
+
# bus has been used before this provider loads, then it will have created its own separate
|
23
|
+
# locally copy of all registered events as of that moment in time, which will not included
|
24
|
+
# the Rack events globally reigstered above.
|
25
|
+
notifications = target["notifications"]
|
26
|
+
notifications.register_event(Dry::Monitor::Rack::Middleware::REQUEST_START)
|
27
|
+
notifications.register_event(Dry::Monitor::Rack::Middleware::REQUEST_STOP)
|
28
|
+
notifications.register_event(Dry::Monitor::Rack::Middleware::REQUEST_ERROR)
|
22
29
|
end
|
23
30
|
|
24
31
|
# @api private
|
25
32
|
def start
|
26
33
|
target.start :logger
|
27
34
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
35
|
+
monitor_middleware = Dry::Monitor::Rack::Middleware.new(
|
36
|
+
target["notifications"],
|
37
|
+
clock: Dry::Monitor::Clock.new(unit: :microsecond)
|
38
|
+
)
|
32
39
|
|
33
40
|
rack_logger = Hanami::Web::RackLogger.new(target[:logger], env: target.env)
|
34
41
|
rack_logger.attach(monitor_middleware)
|
data/lib/hanami/version.rb
CHANGED
@@ -87,7 +87,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
87
87
|
end
|
88
88
|
RUBY
|
89
89
|
|
90
|
-
require "hanami/
|
90
|
+
require "hanami/prepare"
|
91
91
|
|
92
92
|
expect(Hanami.app["rack.monitor"]).to be_instance_of(Dry::Monitor::Rack::Middleware)
|
93
93
|
|
@@ -114,7 +114,63 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
-
|
117
|
+
specify "Logging via the rack monitor even when notifications bus has already been used" do
|
118
|
+
dir = Dir.mktmpdir
|
119
|
+
|
120
|
+
with_tmp_directory(dir) do
|
121
|
+
write "config/app.rb", <<~RUBY
|
122
|
+
require "hanami"
|
123
|
+
|
124
|
+
module TestApp
|
125
|
+
class App < Hanami::App
|
126
|
+
config.actions.format :json
|
127
|
+
config.logger.options = {colorize: true}
|
128
|
+
config.logger.stream = config.root.join("test.log")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
RUBY
|
132
|
+
|
133
|
+
write "config/routes.rb", <<~RUBY
|
134
|
+
module TestApp
|
135
|
+
class Routes < Hanami::Routes
|
136
|
+
post "/users", to: "users.create"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
RUBY
|
140
|
+
|
141
|
+
write "app/actions/users/create.rb", <<~RUBY
|
142
|
+
module TestApp
|
143
|
+
module Actions
|
144
|
+
module Users
|
145
|
+
class Create < Hanami::Action
|
146
|
+
def handle(req, resp)
|
147
|
+
resp.body = req.params.to_h.keys
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
RUBY
|
154
|
+
|
155
|
+
require "hanami/prepare"
|
156
|
+
|
157
|
+
# Simulate any component interacting with the notifications bus such that it creates its
|
158
|
+
# internal bus with a duplicate copy of all currently registered events. This means that the
|
159
|
+
# class-level Dry::Monitor::Notification events implicitly registered by the
|
160
|
+
# Dry::Monitor::Rack::Middleware activated via the rack provider are ignored, unless our
|
161
|
+
# provider explicitly re-registers them on _instance_ of the notifications bus.
|
162
|
+
#
|
163
|
+
# See Hanami::Providers::Rack for more detail.
|
164
|
+
Hanami.app["notifications"].instrument(:sql)
|
165
|
+
|
166
|
+
logs = -> { Pathname(dir).join("test.log").realpath.read }
|
167
|
+
|
168
|
+
post "/users", JSON.generate(name: "jane", password: "secret"), {"CONTENT_TYPE" => "application/json"}
|
169
|
+
expect(logs.()).to match %r{POST 200 \d+(µs|ms) 127.0.0.1 /}
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "Request logging when using slice router" do
|
118
174
|
let(:app) { Main::Slice.rack_app }
|
119
175
|
|
120
176
|
specify "Has rack monitor preconfigured with default request logging (when used via a slice)" do
|
@@ -139,7 +195,7 @@ RSpec.describe "Hanami web app", :app_integration do
|
|
139
195
|
end
|
140
196
|
RUBY
|
141
197
|
|
142
|
-
require "hanami/
|
198
|
+
require "hanami/prepare"
|
143
199
|
|
144
200
|
get "/"
|
145
201
|
|
@@ -13,21 +13,20 @@ RSpec.describe Hanami::Config::Actions, "#content_security_policy" do
|
|
13
13
|
expect(content_security_policy[:base_uri]).to eq("'self'")
|
14
14
|
|
15
15
|
expected = [
|
16
|
-
%(base-uri 'self'
|
17
|
-
%(child-src 'self'
|
18
|
-
%(connect-src 'self'
|
19
|
-
%(default-src 'none'
|
20
|
-
%(font-src 'self'
|
21
|
-
%(form-action 'self'
|
22
|
-
%(frame-ancestors 'self'
|
23
|
-
%(frame-src 'self'
|
24
|
-
%(img-src 'self' https: data
|
25
|
-
%(media-src 'self'
|
26
|
-
%(object-src 'none'
|
27
|
-
%(
|
28
|
-
%(script-src 'self';),
|
16
|
+
%(base-uri 'self'),
|
17
|
+
%(child-src 'self'),
|
18
|
+
%(connect-src 'self'),
|
19
|
+
%(default-src 'none'),
|
20
|
+
%(font-src 'self'),
|
21
|
+
%(form-action 'self'),
|
22
|
+
%(frame-ancestors 'self'),
|
23
|
+
%(frame-src 'self'),
|
24
|
+
%(img-src 'self' https: data:),
|
25
|
+
%(media-src 'self'),
|
26
|
+
%(object-src 'none'),
|
27
|
+
%(script-src 'self'),
|
29
28
|
%(style-src 'self' 'unsafe-inline' https:)
|
30
|
-
].join("
|
29
|
+
].join(";")
|
31
30
|
|
32
31
|
expect(content_security_policy.to_s).to eq(expected)
|
33
32
|
end
|
@@ -62,10 +61,10 @@ RSpec.describe Hanami::Config::Actions, "#content_security_policy" do
|
|
62
61
|
end
|
63
62
|
|
64
63
|
it "nullifies value" do
|
65
|
-
content_security_policy[:
|
64
|
+
content_security_policy[:object_src] = nil
|
66
65
|
|
67
|
-
expect(content_security_policy[:
|
68
|
-
expect(content_security_policy.to_s).to match("
|
66
|
+
expect(content_security_policy[:object_src]).to be(nil)
|
67
|
+
expect(content_security_policy.to_s).to match("object-src ;")
|
69
68
|
end
|
70
69
|
|
71
70
|
it "deletes key" do
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/port"
|
4
|
+
|
5
|
+
RSpec.describe Hanami::Port do
|
6
|
+
context "Hanami::Port::DEFAULT" do
|
7
|
+
it "returns default value" do
|
8
|
+
expect(Hanami::Port::DEFAULT).to eq(2300)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "Hanami::Port::ENV_VAR" do
|
13
|
+
it "returns default value" do
|
14
|
+
expect(Hanami::Port::ENV_VAR).to eq("HANAMI_PORT")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context ".call" do
|
19
|
+
let(:value) { nil }
|
20
|
+
let(:env) { nil }
|
21
|
+
|
22
|
+
it "is aliased as .[]" do
|
23
|
+
expect(described_class[value, env]).to be(2300)
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when ENV var is nil" do
|
27
|
+
context "and value is nil" do
|
28
|
+
it "returns default value" do
|
29
|
+
expect(described_class.call(value, env)).to be(2300)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "and value is not nil" do
|
34
|
+
let(:value) { 18_000 }
|
35
|
+
|
36
|
+
it "returns given value" do
|
37
|
+
expect(described_class.call(value, env)).to be(value)
|
38
|
+
end
|
39
|
+
|
40
|
+
context "and value is default" do
|
41
|
+
let(:value) { 2300 }
|
42
|
+
|
43
|
+
it "returns given value" do
|
44
|
+
expect(described_class.call(value, env)).to be(value)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when ENV var not nil" do
|
51
|
+
let(:env) { 9000 }
|
52
|
+
|
53
|
+
context "and value is nil" do
|
54
|
+
it "returns env value" do
|
55
|
+
expect(described_class.call(value, env)).to be(env)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "and value is not nil" do
|
60
|
+
let(:value) { 18_000 }
|
61
|
+
|
62
|
+
it "returns given value" do
|
63
|
+
expect(described_class.call(value, env)).to be(value)
|
64
|
+
end
|
65
|
+
|
66
|
+
context "and value is default" do
|
67
|
+
let(:value) { 2300 }
|
68
|
+
|
69
|
+
it "returns env value" do
|
70
|
+
expect(described_class.call(value, env)).to be(env)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context ".call!" do
|
78
|
+
before { ENV.delete("HANAMI_PORT") }
|
79
|
+
let(:value) { 2300 }
|
80
|
+
|
81
|
+
context "when given value is default" do
|
82
|
+
it "doesn't set env var" do
|
83
|
+
described_class.call!(value)
|
84
|
+
|
85
|
+
expect(ENV.key?("HANAMI_PORT")).to be(false)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "when given value isn't default" do
|
90
|
+
let(:value) { 9000 }
|
91
|
+
|
92
|
+
it "set env var" do
|
93
|
+
described_class.call!(value)
|
94
|
+
|
95
|
+
expect(ENV.fetch("HANAMI_PORT")).to eq(value.to_s)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context ".default?" do
|
101
|
+
context "when given value is default" do
|
102
|
+
let(:value) { 2300 }
|
103
|
+
|
104
|
+
it "returns true" do
|
105
|
+
expect(described_class.default?(value)).to be(true)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "when given value isn't default" do
|
110
|
+
let(:value) { 9000 }
|
111
|
+
|
112
|
+
it "returns false" do
|
113
|
+
expect(described_class.default?(value)).to be(false)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanami
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -268,6 +268,7 @@ files:
|
|
268
268
|
- lib/hanami/config/router.rb
|
269
269
|
- lib/hanami/config/views.rb
|
270
270
|
- lib/hanami/constants.rb
|
271
|
+
- lib/hanami/env.rb
|
271
272
|
- lib/hanami/errors.rb
|
272
273
|
- lib/hanami/extensions.rb
|
273
274
|
- lib/hanami/extensions/action.rb
|
@@ -276,6 +277,7 @@ files:
|
|
276
277
|
- lib/hanami/extensions/view/context.rb
|
277
278
|
- lib/hanami/extensions/view/slice_configured_context.rb
|
278
279
|
- lib/hanami/extensions/view/slice_configured_view.rb
|
280
|
+
- lib/hanami/port.rb
|
279
281
|
- lib/hanami/prepare.rb
|
280
282
|
- lib/hanami/providers/inflector.rb
|
281
283
|
- lib/hanami/providers/logger.rb
|
@@ -376,6 +378,7 @@ files:
|
|
376
378
|
- spec/unit/hanami/config/slices_spec.rb
|
377
379
|
- spec/unit/hanami/config/views_spec.rb
|
378
380
|
- spec/unit/hanami/env_spec.rb
|
381
|
+
- spec/unit/hanami/port_spec.rb
|
379
382
|
- spec/unit/hanami/settings/env_store_spec.rb
|
380
383
|
- spec/unit/hanami/settings_spec.rb
|
381
384
|
- spec/unit/hanami/slice_configurable_spec.rb
|
@@ -404,7 +407,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
404
407
|
- !ruby/object:Gem::Version
|
405
408
|
version: '0'
|
406
409
|
requirements: []
|
407
|
-
rubygems_version: 3.
|
410
|
+
rubygems_version: 3.4.1
|
408
411
|
signing_key:
|
409
412
|
specification_version: 4
|
410
413
|
summary: The web, with simplicity
|
@@ -488,6 +491,7 @@ test_files:
|
|
488
491
|
- spec/unit/hanami/config/slices_spec.rb
|
489
492
|
- spec/unit/hanami/config/views_spec.rb
|
490
493
|
- spec/unit/hanami/env_spec.rb
|
494
|
+
- spec/unit/hanami/port_spec.rb
|
491
495
|
- spec/unit/hanami/settings/env_store_spec.rb
|
492
496
|
- spec/unit/hanami/settings_spec.rb
|
493
497
|
- spec/unit/hanami/slice_configurable_spec.rb
|