hanami 2.0.0.alpha5 → 2.0.0.alpha6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +77 -0
- data/README.md +2 -6
- data/hanami.gemspec +5 -4
- data/lib/hanami/application/container/{boot → providers}/inflector.rb +1 -1
- data/lib/hanami/application/container/{boot → providers}/logger.rb +1 -1
- data/lib/hanami/application/container/providers/rack_logger.rb +15 -0
- data/lib/hanami/application/container/{boot → providers}/rack_monitor.rb +2 -2
- data/lib/hanami/application/container/{boot → providers}/routes_helper.rb +1 -1
- data/lib/hanami/application/container/{boot → providers}/settings.rb +1 -1
- data/lib/hanami/application.rb +59 -69
- data/lib/hanami/cli/application/cli.rb +1 -1
- data/lib/hanami/configuration.rb +1 -1
- data/lib/hanami/{init.rb → prepare.rb} +1 -1
- data/lib/hanami/slice.rb +97 -94
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +27 -51
- data/lib/hanami.rb +2 -2
- metadata +16 -18
- data/lib/hanami/application/autoloader/inflector_adapter.rb +0 -22
- data/lib/hanami/application/container/boot/rack_logger.rb +0 -19
- data/lib/hanami/application/routing/router.rb +0 -36
- data/lib/hanami/boot/source_dirs.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fc76408b7d97db32194d24bf73739bde8405fbd13855b7e4ea744f634d0739e
|
4
|
+
data.tar.gz: 30d954f8332ea7579898a87187a89a0ae2a1b34b5d9f564a86b6f61c0844f2af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f64124d027449d451f5be703f4c00850c826e4d55ebef1e6c396be63dea59a9019cb74438f7844f1e68a187299ea45c7f89ba1e98267380e7d8e1b1f8666e4b9
|
7
|
+
data.tar.gz: 8ea32aae47f0fe9536726c977af03904fa23f7258ef747b2cdd1a3b324eb064466beccc9340b7dddfb46d3d6a49c8aba899b1b488c6016377581599efd594577
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,83 @@
|
|
1
1
|
# Hanami
|
2
2
|
The web, with simplicity.
|
3
3
|
|
4
|
+
## v2.0.0.alpha6 - 2022-02-10
|
5
|
+
### Added
|
6
|
+
- [Luca Guidi] Official support for Ruby: MRI 3.1
|
7
|
+
- [Tim Riley] Introduce partial Slice imports and exports. It allows to selectively export a functionality from a slice and import into another.
|
8
|
+
|
9
|
+
Import from `search` slice, uses `search` as the imported key namespace:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
# config/application.rb
|
13
|
+
|
14
|
+
module MyApp
|
15
|
+
class Application < Hanami::Application
|
16
|
+
config.slice(:admin) do
|
17
|
+
import(from: :search)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
```
|
22
|
+
|
23
|
+
Import from `search` slice with custom namespace:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# config/application.rb
|
27
|
+
|
28
|
+
module MyApp
|
29
|
+
class Application < Hanami::Application
|
30
|
+
config.slice(:admin) do
|
31
|
+
import(from: :search, as: :search_engine)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
Import specific keys from `search` slice
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
# config/application.rb
|
41
|
+
|
42
|
+
module MyApp
|
43
|
+
class Application < Hanami::Application
|
44
|
+
config.slice(:admin) do
|
45
|
+
import(keys: ["run_query"], from: :search)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
Export only specific keys from `search` slice, and import them in `admin`
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
# config/application.rb
|
55
|
+
|
56
|
+
module MyApp
|
57
|
+
class Application < Hanami::Application
|
58
|
+
config.slice(:admin) do
|
59
|
+
import(from: :search)
|
60
|
+
end
|
61
|
+
|
62
|
+
config.slice(:search) do
|
63
|
+
container.config.exports = %w[run_query index_item]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
### Fixed
|
70
|
+
- [Luca Guidi] Ensure request logger to respect logger formatter option.
|
71
|
+
|
72
|
+
### Changed
|
73
|
+
- [Luca Guidi] Drop support for Ruby: MRI 2.6 and 2.7.
|
74
|
+
- [Tim Riley] `Hanami.init` => `Hanami.prepare` and `hanami/init` => `hanami/prepare`
|
75
|
+
- [Tim Riley] `Hanami.register_bootable` => `Hanami.register_provider`
|
76
|
+
- [Tim Riley] `Hanami.start_bootable` => `Hanami.start`
|
77
|
+
- [Tim Riley] `Hanami::Slice#init` => `Hanami::Slice#prepare`
|
78
|
+
- [Tim Riley] `Hanami::Slice#register_bootable` => `Hanami::Slice#register_provider`
|
79
|
+
- [Tim Riley] `Hanami::Slice#start_bootable` => `Hanami::Slice#start`
|
80
|
+
|
4
81
|
## v2.0.0.alpha5 - 2022-01-12
|
5
82
|
### Changed
|
6
83
|
- [Luca Guidi] Sensible default configuration for application logger, with per-environment defaults:
|
data/README.md
CHANGED
@@ -36,7 +36,7 @@ These components are designed to be used independently or together in a Hanami a
|
|
36
36
|
|
37
37
|
## Installation
|
38
38
|
|
39
|
-
__Hanami__ supports Ruby (MRI)
|
39
|
+
__Hanami__ supports Ruby (MRI) 3.0+
|
40
40
|
|
41
41
|
```shell
|
42
42
|
gem install hanami
|
@@ -136,8 +136,4 @@ __Hanami__ uses [Semantic Versioning 2.0.0](http://semver.org)
|
|
136
136
|
|
137
137
|
## Copyright
|
138
138
|
|
139
|
-
Released under MIT License.
|
140
|
-
|
141
|
-
This project was formerly known as Lotus (`lotusrb`).
|
142
|
-
|
143
|
-
Copyright © 2014-2021 Luca Guidi.
|
139
|
+
Copyright © 2014-2022 Hanami Team – Released under MIT License.
|
data/hanami.gemspec
CHANGED
@@ -4,7 +4,7 @@ lib = File.expand_path("../lib", __FILE__)
|
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require "hanami/version"
|
6
6
|
|
7
|
-
Gem::Specification.new do |spec|
|
7
|
+
Gem::Specification.new do |spec|
|
8
8
|
spec.name = "hanami"
|
9
9
|
spec.version = Hanami::VERSION
|
10
10
|
spec.authors = ["Luca Guidi"]
|
@@ -14,10 +14,11 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
|
|
14
14
|
spec.homepage = "http://hanamirb.org"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
|
-
spec.files = `git ls-files -c -o --exclude-standard -z -- lib/* bin/* LICENSE.md README.md CODE_OF_CONDUCT.md CHANGELOG.md FEATURES.md hanami.gemspec`.split("\x0")
|
17
|
+
spec.files = `git ls-files -c -o --exclude-standard -z -- lib/* bin/* LICENSE.md README.md CODE_OF_CONDUCT.md CHANGELOG.md FEATURES.md hanami.gemspec`.split("\x0") # rubocop:disable Layout/LineLength
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
|
-
spec.
|
20
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
21
|
+
spec.required_ruby_version = ">= 3.0"
|
21
22
|
|
22
23
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
23
24
|
|
@@ -26,7 +27,7 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
|
|
26
27
|
spec.add_dependency "dry-core", "~> 0.4"
|
27
28
|
spec.add_dependency "dry-inflector", "~> 0.2", ">= 0.2.1"
|
28
29
|
spec.add_dependency "dry-monitor"
|
29
|
-
spec.add_dependency "dry-system", "~> 0.
|
30
|
+
spec.add_dependency "dry-system", "~> 0.23", ">= 0.23.0"
|
30
31
|
spec.add_dependency "hanami-cli", "~> 2.0.alpha"
|
31
32
|
spec.add_dependency "hanami-utils", "~> 2.0.alpha"
|
32
33
|
spec.add_dependency "zeitwerk", "~> 2.4"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Hanami.application.register_provider :rack_logger do
|
4
|
+
start do
|
5
|
+
require "hanami/web/rack_logger"
|
6
|
+
|
7
|
+
target.start :logger
|
8
|
+
target.start :rack_monitor
|
9
|
+
|
10
|
+
rack_logger = Hanami::Web::RackLogger.new(target[:logger])
|
11
|
+
rack_logger.attach target[:rack_monitor]
|
12
|
+
|
13
|
+
register :rack_logger, rack_logger
|
14
|
+
end
|
15
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
Hanami.application.
|
3
|
+
Hanami.application.register_provider :rack_monitor do
|
4
4
|
start do
|
5
5
|
require "dry/monitor"
|
6
6
|
require "dry/monitor/rack/middleware"
|
7
7
|
|
8
|
-
middleware = Dry::Monitor::Rack::Middleware.new(
|
8
|
+
middleware = Dry::Monitor::Rack::Middleware.new(target[:notifications])
|
9
9
|
|
10
10
|
register :rack_monitor, middleware
|
11
11
|
end
|
data/lib/hanami/application.rb
CHANGED
@@ -7,7 +7,6 @@ require "pathname"
|
|
7
7
|
require "rack"
|
8
8
|
require "zeitwerk"
|
9
9
|
require_relative "slice"
|
10
|
-
require_relative "application/autoloader/inflector_adapter"
|
11
10
|
|
12
11
|
module Hanami
|
13
12
|
# Hanami application class
|
@@ -18,6 +17,7 @@ module Hanami
|
|
18
17
|
|
19
18
|
class << self
|
20
19
|
def inherited(klass)
|
20
|
+
super
|
21
21
|
@_mutex.synchronize do
|
22
22
|
klass.class_eval do
|
23
23
|
@_mutex = Mutex.new
|
@@ -39,7 +39,7 @@ module Hanami
|
|
39
39
|
module ClassMethods
|
40
40
|
def self.extended(klass)
|
41
41
|
klass.class_eval do
|
42
|
-
@
|
42
|
+
@prepared = @booted = false
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
@@ -47,35 +47,38 @@ module Hanami
|
|
47
47
|
@_configuration
|
48
48
|
end
|
49
49
|
|
50
|
-
|
50
|
+
alias_method :config, :configuration
|
51
51
|
|
52
|
-
def
|
53
|
-
|
52
|
+
def prepare(provider_name = nil)
|
53
|
+
if provider_name
|
54
|
+
container.prepare(provider_name)
|
55
|
+
return self
|
56
|
+
end
|
54
57
|
|
55
|
-
|
58
|
+
return self if prepared?
|
56
59
|
|
57
|
-
|
58
|
-
autoloader.inflector = Autoloader::InflectorAdapter.new(inflector)
|
60
|
+
configuration.finalize!
|
59
61
|
|
60
62
|
load_settings
|
61
63
|
|
64
|
+
@autoloader = Zeitwerk::Loader.new
|
62
65
|
@container = prepare_container
|
63
66
|
@deps_module = prepare_deps_module
|
64
67
|
|
65
68
|
load_slices
|
66
|
-
slices.
|
69
|
+
slices.each_value(&:prepare)
|
67
70
|
slices.freeze
|
68
71
|
|
69
|
-
autoloader.setup
|
72
|
+
@autoloader.setup
|
70
73
|
|
71
|
-
@
|
74
|
+
@prepared = true
|
72
75
|
self
|
73
76
|
end
|
74
77
|
|
75
78
|
def boot(&block)
|
76
79
|
return self if booted?
|
77
80
|
|
78
|
-
|
81
|
+
prepare
|
79
82
|
|
80
83
|
container.finalize!(&block)
|
81
84
|
|
@@ -89,8 +92,8 @@ module Hanami
|
|
89
92
|
container.shutdown!
|
90
93
|
end
|
91
94
|
|
92
|
-
def
|
93
|
-
@
|
95
|
+
def prepared?
|
96
|
+
@prepared
|
94
97
|
end
|
95
98
|
|
96
99
|
def booted?
|
@@ -98,25 +101,25 @@ module Hanami
|
|
98
101
|
end
|
99
102
|
|
100
103
|
def autoloader
|
101
|
-
raise "Application not
|
104
|
+
raise "Application not yet prepared" unless defined?(@autoloader)
|
102
105
|
|
103
106
|
@autoloader
|
104
107
|
end
|
105
108
|
|
106
109
|
def container
|
107
|
-
raise "Application not
|
110
|
+
raise "Application not yet prepared" unless defined?(@container)
|
108
111
|
|
109
112
|
@container
|
110
113
|
end
|
111
114
|
|
112
115
|
def deps
|
113
|
-
raise "Application not
|
116
|
+
raise "Application not yet prepared" unless defined?(@deps_module)
|
114
117
|
|
115
118
|
@deps_module
|
116
119
|
end
|
117
120
|
|
118
121
|
def router
|
119
|
-
raise "Application not
|
122
|
+
raise "Application not yet prepared" unless prepared?
|
120
123
|
|
121
124
|
@_mutex.synchronize do
|
122
125
|
@_router ||= load_router
|
@@ -139,36 +142,32 @@ module Hanami
|
|
139
142
|
slices[name.to_sym] = slice
|
140
143
|
end
|
141
144
|
|
142
|
-
def register(
|
143
|
-
container.register(
|
144
|
-
end
|
145
|
-
|
146
|
-
def register_bootable(*args, **opts, &block)
|
147
|
-
container.boot(*args, **opts, &block)
|
145
|
+
def register(...)
|
146
|
+
container.register(...)
|
148
147
|
end
|
149
148
|
|
150
|
-
def
|
151
|
-
container.
|
149
|
+
def register_provider(...)
|
150
|
+
container.register_provider(...)
|
152
151
|
end
|
153
152
|
|
154
|
-
def
|
155
|
-
container.start(
|
153
|
+
def start(...)
|
154
|
+
container.start(...)
|
156
155
|
end
|
157
156
|
|
158
|
-
def key?(
|
159
|
-
container.key?(
|
157
|
+
def key?(...)
|
158
|
+
container.key?(...)
|
160
159
|
end
|
161
160
|
|
162
161
|
def keys
|
163
162
|
container.keys
|
164
163
|
end
|
165
164
|
|
166
|
-
def [](
|
167
|
-
container[
|
165
|
+
def [](...)
|
166
|
+
container.[](...)
|
168
167
|
end
|
169
168
|
|
170
|
-
def resolve(
|
171
|
-
container.resolve(
|
169
|
+
def resolve(...)
|
170
|
+
container.resolve(...)
|
172
171
|
end
|
173
172
|
|
174
173
|
def settings
|
@@ -201,7 +200,7 @@ module Hanami
|
|
201
200
|
|
202
201
|
# @api private
|
203
202
|
def component_provider(component)
|
204
|
-
raise "Hanami.application must be
|
203
|
+
raise "Hanami.application must be prepared before detecting providers" unless prepared?
|
205
204
|
|
206
205
|
# [Admin, Main, MyApp] or [MyApp::Admin, MyApp::Main, MyApp]
|
207
206
|
providers = slices.values + [self]
|
@@ -221,53 +220,46 @@ module Hanami
|
|
221
220
|
$LOAD_PATH.unshift base_path unless $LOAD_PATH.include?(base_path)
|
222
221
|
end
|
223
222
|
|
223
|
+
# rubocop:disable Metrics/AbcSize
|
224
224
|
def prepare_container
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
end
|
233
|
-
|
234
|
-
def define_container
|
235
|
-
require "#{application_name}/container"
|
236
|
-
namespace.const_get :Container
|
237
|
-
rescue LoadError, NameError
|
238
|
-
namespace.const_set :Container, Class.new(Dry::System::Container)
|
239
|
-
end
|
225
|
+
container =
|
226
|
+
begin
|
227
|
+
require "#{application_name}/container"
|
228
|
+
namespace.const_get :Container
|
229
|
+
rescue LoadError, NameError
|
230
|
+
namespace.const_set :Container, Class.new(Dry::System::Container)
|
231
|
+
end
|
240
232
|
|
241
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
242
|
-
def configure_container(container)
|
243
233
|
container.use :env, inferrer: -> { Hanami.env }
|
234
|
+
container.use :zeitwerk, loader: autoloader, run_setup: false, eager_load: false
|
244
235
|
container.use :notifications
|
245
236
|
|
246
|
-
container.
|
247
|
-
|
248
|
-
|
249
|
-
config.root = configuration.root
|
250
|
-
config.bootable_dirs = [
|
251
|
-
"config/boot",
|
252
|
-
Pathname(__dir__).join("application/container/boot").realpath,
|
253
|
-
]
|
237
|
+
container.config.root = configuration.root
|
238
|
+
container.config.inflector = configuration.inflector
|
254
239
|
|
255
|
-
|
256
|
-
config
|
257
|
-
|
240
|
+
container.config.provider_dirs = [
|
241
|
+
"config/providers",
|
242
|
+
Pathname(__dir__).join("application/container/providers").realpath,
|
243
|
+
]
|
258
244
|
|
259
245
|
# Autoload classes defined in lib/[app_namespace]/
|
260
246
|
if root.join("lib", namespace_path).directory?
|
261
|
-
autoloader.push_dir(root.join("lib", namespace_path), namespace: namespace)
|
247
|
+
container.autoloader.push_dir(root.join("lib", namespace_path), namespace: namespace)
|
262
248
|
end
|
263
249
|
|
264
|
-
# Add lib/ to to the $LOAD_PATH so
|
265
|
-
#
|
250
|
+
# Add lib/ to to the $LOAD_PATH so any files there (outside the app namespace) can
|
251
|
+
# be required
|
266
252
|
container.add_to_load_path!("lib") if root.join("lib").directory?
|
267
253
|
|
254
|
+
container.configured!
|
255
|
+
|
268
256
|
container
|
269
257
|
end
|
270
|
-
# rubocop:enable Metrics/AbcSize
|
258
|
+
# rubocop:enable Metrics/AbcSize
|
259
|
+
|
260
|
+
def prepare_deps_module
|
261
|
+
define_deps_module
|
262
|
+
end
|
271
263
|
|
272
264
|
def define_deps_module
|
273
265
|
require "#{application_name}/deps"
|
@@ -286,7 +278,6 @@ module Hanami
|
|
286
278
|
File.join(root, config.slices_dir)
|
287
279
|
end
|
288
280
|
|
289
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
290
281
|
def load_slice(slice_path)
|
291
282
|
slice_path = Pathname(slice_path)
|
292
283
|
|
@@ -308,7 +299,6 @@ module Hanami
|
|
308
299
|
root: slice_path.realpath
|
309
300
|
)
|
310
301
|
end
|
311
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
312
302
|
|
313
303
|
def load_settings
|
314
304
|
require_relative "application/settings"
|
@@ -26,7 +26,7 @@ module Hanami
|
|
26
26
|
# of the boot process respect the provided env
|
27
27
|
ENV["HANAMI_ENV"] = arguments[:env] if arguments[:env]
|
28
28
|
|
29
|
-
require "hanami/
|
29
|
+
require "hanami/prepare"
|
30
30
|
application = Hanami.application
|
31
31
|
|
32
32
|
[command.with_application(application), arguments]
|
data/lib/hanami/configuration.rb
CHANGED
@@ -126,7 +126,7 @@ module Hanami
|
|
126
126
|
|
127
127
|
setting :root, constructor: -> path { Pathname(path) }
|
128
128
|
|
129
|
-
setting :inflector, default: Dry::Inflector.new
|
129
|
+
setting :inflector, default: Dry::Inflector.new
|
130
130
|
|
131
131
|
def inflections(&block)
|
132
132
|
self.inflector = Dry::Inflector.new(&block)
|
data/lib/hanami/slice.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "dry/system/container"
|
4
|
-
require "dry/system/loader/autoloading"
|
5
4
|
require "pathname"
|
6
5
|
|
7
6
|
module Hanami
|
@@ -16,7 +15,7 @@ module Hanami
|
|
16
15
|
@name = name.to_sym
|
17
16
|
@namespace = namespace
|
18
17
|
@root = root ? Pathname(root) : root
|
19
|
-
@container = container
|
18
|
+
@container = container
|
20
19
|
end
|
21
20
|
|
22
21
|
def inflector
|
@@ -27,17 +26,28 @@ module Hanami
|
|
27
26
|
@namespace_path ||= inflector.underscore(namespace.to_s)
|
28
27
|
end
|
29
28
|
|
30
|
-
def
|
31
|
-
|
29
|
+
def prepare(provider_name = nil)
|
30
|
+
if provider_name
|
31
|
+
container.prepare(provider_name)
|
32
|
+
return self
|
33
|
+
end
|
34
|
+
|
35
|
+
@container ||= define_container
|
36
|
+
|
37
|
+
container.import from: application.container, as: :application
|
32
38
|
|
33
39
|
slice_block = application.configuration.slices[name]
|
34
40
|
instance_eval(&slice_block) if slice_block
|
41
|
+
|
42
|
+
# This is here and not inside define_container to allow for the slice block to
|
43
|
+
# interact with container config
|
44
|
+
container.configured!
|
45
|
+
|
46
|
+
self
|
35
47
|
end
|
36
48
|
|
37
49
|
def boot
|
38
|
-
container.finalize!
|
39
|
-
container.config.env = application.container.config.env
|
40
|
-
end
|
50
|
+
container.finalize!
|
41
51
|
|
42
52
|
@booted = true
|
43
53
|
self
|
@@ -53,44 +63,47 @@ module Hanami
|
|
53
63
|
@container ||= define_container
|
54
64
|
end
|
55
65
|
|
56
|
-
def import(
|
66
|
+
def import(from:, **kwargs)
|
67
|
+
# TODO: This should be handled via dry-system (see dry-rb/dry-system#228)
|
57
68
|
raise "Cannot import after booting" if booted?
|
58
69
|
|
59
|
-
|
60
|
-
|
70
|
+
if from.is_a?(Symbol) || from.is_a?(String)
|
71
|
+
slice_name = from
|
72
|
+
# TODO: better error than the KeyError from fetch if the slice doesn't exist
|
73
|
+
from = application.slices.fetch(from.to_sym).container
|
61
74
|
end
|
75
|
+
|
76
|
+
as = kwargs[:as] || slice_name
|
77
|
+
|
78
|
+
container.import(from: from, as: as, **kwargs)
|
62
79
|
end
|
63
80
|
|
64
81
|
def register(*args, &block)
|
65
82
|
container.register(*args, &block)
|
66
83
|
end
|
67
84
|
|
68
|
-
def
|
69
|
-
container.
|
70
|
-
end
|
71
|
-
|
72
|
-
def init_bootable(*args)
|
73
|
-
container.init(*args)
|
85
|
+
def register_provider(...)
|
86
|
+
container.register_provider(...)
|
74
87
|
end
|
75
88
|
|
76
|
-
def
|
77
|
-
container.start(
|
89
|
+
def start(...)
|
90
|
+
container.start(...)
|
78
91
|
end
|
79
92
|
|
80
|
-
def key?(
|
81
|
-
container.key?(
|
93
|
+
def key?(...)
|
94
|
+
container.key?(...)
|
82
95
|
end
|
83
96
|
|
84
97
|
def keys
|
85
98
|
container.keys
|
86
99
|
end
|
87
100
|
|
88
|
-
def [](
|
89
|
-
container[
|
101
|
+
def [](...)
|
102
|
+
container.[](...)
|
90
103
|
end
|
91
104
|
|
92
|
-
def resolve(
|
93
|
-
container.resolve(
|
105
|
+
def resolve(...)
|
106
|
+
container.resolve(...)
|
94
107
|
end
|
95
108
|
|
96
109
|
private
|
@@ -98,82 +111,72 @@ module Hanami
|
|
98
111
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
99
112
|
def define_container
|
100
113
|
container = Class.new(Dry::System::Container)
|
101
|
-
container.use :env
|
102
114
|
|
103
|
-
container.
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
component_dir.namespaces.delete_root
|
149
|
-
component_dir.namespaces.add_root(const: dir_namespace_path, key: component_dir.path) # TODO: do we need to swap path delimiters for key delimiters here?
|
150
|
-
|
151
|
-
config.component_dirs.add(component_dir)
|
152
|
-
|
153
|
-
application.autoloader.push_dir(
|
154
|
-
container.root.join(component_dir.path),
|
155
|
-
namespace: autoloader_namespace
|
156
|
-
)
|
157
|
-
end
|
115
|
+
container.use :env
|
116
|
+
container.use :zeitwerk,
|
117
|
+
loader: application.autoloader,
|
118
|
+
run_setup: false,
|
119
|
+
eager_load: false
|
120
|
+
|
121
|
+
container.config.name = name
|
122
|
+
container.config.env = application.configuration.env
|
123
|
+
container.config.inflector = application.configuration.inflector
|
124
|
+
|
125
|
+
if root&.directory?
|
126
|
+
container.config.root = root
|
127
|
+
container.config.provider_dirs = ["config/providers"]
|
128
|
+
|
129
|
+
# Add component dirs for each configured component path
|
130
|
+
application.configuration.source_dirs.component_dirs.each do |component_dir|
|
131
|
+
next unless root.join(component_dir.path).directory?
|
132
|
+
|
133
|
+
component_dir = component_dir.dup
|
134
|
+
|
135
|
+
# TODO: this `== "lib"` check should be codified into a method somewhere
|
136
|
+
if component_dir.path == "lib"
|
137
|
+
# Expect component files in the root of the lib/ component dir to define
|
138
|
+
# classes inside the slice's namespace.
|
139
|
+
#
|
140
|
+
# e.g. "lib/foo.rb" should define SliceNamespace::Foo, to be registered as
|
141
|
+
# "foo"
|
142
|
+
component_dir.namespaces.delete_root
|
143
|
+
component_dir.namespaces.add_root(key: nil, const: namespace_path)
|
144
|
+
|
145
|
+
container.config.component_dirs.add(component_dir)
|
146
|
+
else
|
147
|
+
# Expect component files in the root of non-lib/ component dirs to define
|
148
|
+
# classes inside a namespace matching that dir.
|
149
|
+
#
|
150
|
+
# e.g. "actions/foo.rb" should define SliceNamespace::Actions::Foo, to be
|
151
|
+
# registered as "actions.foo"
|
152
|
+
|
153
|
+
dir_namespace_path = File.join(namespace_path, component_dir.path)
|
154
|
+
|
155
|
+
component_dir.namespaces.delete_root
|
156
|
+
component_dir.namespaces.add_root(const: dir_namespace_path, key: component_dir.path)
|
157
|
+
|
158
|
+
container.config.component_dirs.add(component_dir)
|
158
159
|
end
|
160
|
+
end
|
161
|
+
end
|
159
162
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
dir_namespace_path = File.join(namespace_path, autoload_path)
|
163
|
+
if root&.directory?
|
164
|
+
# Pass configured autoload dirs to the autoloader
|
165
|
+
application.configuration.source_dirs.autoload_paths.each do |autoload_path|
|
166
|
+
next unless root.join(autoload_path).directory?
|
165
167
|
|
166
|
-
|
167
|
-
inflector.constantize(inflector.camelize(dir_namespace_path))
|
168
|
-
rescue NameError
|
169
|
-
namespace.const_set(inflector.camelize(autoload_path), Module.new)
|
170
|
-
end
|
168
|
+
dir_namespace_path = File.join(namespace_path, autoload_path)
|
171
169
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
)
|
170
|
+
autoloader_namespace = begin
|
171
|
+
inflector.constantize(inflector.camelize(dir_namespace_path))
|
172
|
+
rescue NameError
|
173
|
+
namespace.const_set(inflector.camelize(autoload_path), Module.new)
|
176
174
|
end
|
175
|
+
|
176
|
+
container.config.autoloader.push_dir(
|
177
|
+
container.root.join(autoload_path),
|
178
|
+
namespace: autoloader_namespace
|
179
|
+
)
|
177
180
|
end
|
178
181
|
end
|
179
182
|
|
data/lib/hanami/version.rb
CHANGED
@@ -1,19 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "json"
|
4
|
-
require "rack/request"
|
5
|
-
require "hanami/utils/hash"
|
6
|
-
|
7
3
|
module Hanami
|
8
4
|
module Web
|
9
5
|
# Rack logger for Hanami applications
|
10
6
|
class RackLogger
|
11
|
-
|
12
|
-
|
7
|
+
REQUEST_METHOD = "REQUEST_METHOD"
|
8
|
+
private_constant :REQUEST_METHOD
|
9
|
+
|
10
|
+
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
|
11
|
+
private_constant :HTTP_X_FORWARDED_FOR
|
12
|
+
|
13
|
+
REMOTE_ADDR = "REMOTE_ADDR"
|
14
|
+
private_constant :REMOTE_ADDR
|
15
|
+
|
16
|
+
SCRIPT_NAME = "SCRIPT_NAME"
|
17
|
+
private_constant :SCRIPT_NAME
|
18
|
+
|
19
|
+
PATH_INFO = "PATH_INFO"
|
20
|
+
private_constant :PATH_INFO
|
21
|
+
|
22
|
+
ROUTER_PARAMS = "router.params"
|
23
|
+
private_constant :ROUTER_PARAMS
|
24
|
+
|
25
|
+
CONTENT_LENGTH = "Content-Length"
|
26
|
+
private_constant :CONTENT_LENGTH
|
13
27
|
|
14
|
-
def initialize(logger
|
28
|
+
def initialize(logger)
|
15
29
|
@logger = logger
|
16
|
-
@filter_params = filter_params
|
17
30
|
end
|
18
31
|
|
19
32
|
def attach(rack_monitor)
|
@@ -26,22 +39,20 @@ module Hanami
|
|
26
39
|
end
|
27
40
|
end
|
28
41
|
|
29
|
-
|
30
|
-
def log_request(env, status, time)
|
42
|
+
def log_request(env, status, elapsed)
|
31
43
|
data = {
|
32
|
-
http: env[HTTP_VERSION],
|
33
44
|
verb: env[REQUEST_METHOD],
|
34
45
|
status: status,
|
46
|
+
elapsed: "#{elapsed}ms",
|
35
47
|
ip: env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR],
|
36
48
|
path: env[SCRIPT_NAME] + env[PATH_INFO].to_s,
|
37
49
|
length: extract_content_length(env),
|
38
|
-
params:
|
39
|
-
|
50
|
+
params: env[ROUTER_PARAMS],
|
51
|
+
time: Time.now,
|
40
52
|
}
|
41
53
|
|
42
|
-
logger.info
|
54
|
+
logger.info(data)
|
43
55
|
end
|
44
|
-
# rubocop:enable Metrics/MethodLength
|
45
56
|
|
46
57
|
def log_exception(exception)
|
47
58
|
logger.error exception.message
|
@@ -50,47 +61,12 @@ module Hanami
|
|
50
61
|
|
51
62
|
private
|
52
63
|
|
53
|
-
|
54
|
-
REQUEST_METHOD = "REQUEST_METHOD"
|
55
|
-
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
|
56
|
-
REMOTE_ADDR = "REMOTE_ADDR"
|
57
|
-
SCRIPT_NAME = "SCRIPT_NAME"
|
58
|
-
PATH_INFO = "PATH_INFO"
|
59
|
-
RACK_ERRORS = "rack.errors"
|
60
|
-
QUERY_HASH = "rack.request.query_hash"
|
61
|
-
FORM_HASH = "rack.request.form_hash"
|
62
|
-
ROUTER_PARAMS = "router.params"
|
63
|
-
CONTENT_LENGTH = "Content-Length"
|
64
|
+
attr_reader :logger
|
64
65
|
|
65
66
|
def extract_content_length(env)
|
66
67
|
value = env[CONTENT_LENGTH]
|
67
68
|
!value || value.to_s == "0" ? "-" : value
|
68
69
|
end
|
69
|
-
|
70
|
-
def extract_params(env)
|
71
|
-
result = env.fetch(QUERY_HASH, {})
|
72
|
-
result.merge!(env.fetch(FORM_HASH, {}))
|
73
|
-
result.merge!(Hanami::Utils::Hash.deep_stringify(env.fetch(ROUTER_PARAMS, {})))
|
74
|
-
result
|
75
|
-
end
|
76
|
-
|
77
|
-
FILTERED = "[FILTERED]"
|
78
|
-
|
79
|
-
# rubocop:disable Metrics/MethodLength
|
80
|
-
def filter(params)
|
81
|
-
params.each_with_object({}) do |(k, v), h|
|
82
|
-
if filter_params.include?(k)
|
83
|
-
h.update(k => FILTERED)
|
84
|
-
elsif v.is_a?(Hash)
|
85
|
-
h.update(k => filter(v))
|
86
|
-
elsif v.is_a?(Array)
|
87
|
-
h.update(k => v.map { |m| m.is_a?(Hash) ? filter(m) : m })
|
88
|
-
else
|
89
|
-
h[k] = v
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
# rubocop:enable Metrics/MethodLength
|
94
70
|
end
|
95
71
|
end
|
96
72
|
end
|
data/lib/hanami.rb
CHANGED
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.0.
|
4
|
+
version: 2.0.0.alpha6
|
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-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -104,20 +104,20 @@ dependencies:
|
|
104
104
|
requirements:
|
105
105
|
- - "~>"
|
106
106
|
- !ruby/object:Gem::Version
|
107
|
-
version: '0.
|
107
|
+
version: '0.23'
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.
|
110
|
+
version: 0.23.0
|
111
111
|
type: :runtime
|
112
112
|
prerelease: false
|
113
113
|
version_requirements: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0.
|
117
|
+
version: '0.23'
|
118
118
|
- - ">="
|
119
119
|
- !ruby/object:Gem::Version
|
120
|
-
version: 0.
|
120
|
+
version: 0.23.0
|
121
121
|
- !ruby/object:Gem::Dependency
|
122
122
|
name: hanami-cli
|
123
123
|
requirement: !ruby/object:Gem::Requirement
|
@@ -217,13 +217,12 @@ files:
|
|
217
217
|
- hanami.gemspec
|
218
218
|
- lib/hanami.rb
|
219
219
|
- lib/hanami/application.rb
|
220
|
-
- lib/hanami/application/
|
221
|
-
- lib/hanami/application/container/
|
222
|
-
- lib/hanami/application/container/
|
223
|
-
- lib/hanami/application/container/
|
224
|
-
- lib/hanami/application/container/
|
225
|
-
- lib/hanami/application/container/
|
226
|
-
- lib/hanami/application/container/boot/settings.rb
|
220
|
+
- lib/hanami/application/container/providers/inflector.rb
|
221
|
+
- lib/hanami/application/container/providers/logger.rb
|
222
|
+
- lib/hanami/application/container/providers/rack_logger.rb
|
223
|
+
- lib/hanami/application/container/providers/rack_monitor.rb
|
224
|
+
- lib/hanami/application/container/providers/routes_helper.rb
|
225
|
+
- lib/hanami/application/container/providers/settings.rb
|
227
226
|
- lib/hanami/application/router.rb
|
228
227
|
- lib/hanami/application/routes.rb
|
229
228
|
- lib/hanami/application/routes_helper.rb
|
@@ -231,13 +230,11 @@ files:
|
|
231
230
|
- lib/hanami/application/routing/resolver.rb
|
232
231
|
- lib/hanami/application/routing/resolver/node.rb
|
233
232
|
- lib/hanami/application/routing/resolver/trie.rb
|
234
|
-
- lib/hanami/application/routing/router.rb
|
235
233
|
- lib/hanami/application/settings.rb
|
236
234
|
- lib/hanami/application/settings/dotenv_store.rb
|
237
235
|
- lib/hanami/assets/application_configuration.rb
|
238
236
|
- lib/hanami/assets/configuration.rb
|
239
237
|
- lib/hanami/boot.rb
|
240
|
-
- lib/hanami/boot/source_dirs.rb
|
241
238
|
- lib/hanami/cli/application/cli.rb
|
242
239
|
- lib/hanami/cli/application/command.rb
|
243
240
|
- lib/hanami/cli/application/commands.rb
|
@@ -253,7 +250,7 @@ files:
|
|
253
250
|
- lib/hanami/configuration/router.rb
|
254
251
|
- lib/hanami/configuration/sessions.rb
|
255
252
|
- lib/hanami/configuration/source_dirs.rb
|
256
|
-
- lib/hanami/
|
253
|
+
- lib/hanami/prepare.rb
|
257
254
|
- lib/hanami/server.rb
|
258
255
|
- lib/hanami/setup.rb
|
259
256
|
- lib/hanami/slice.rb
|
@@ -263,6 +260,7 @@ homepage: http://hanamirb.org
|
|
263
260
|
licenses:
|
264
261
|
- MIT
|
265
262
|
metadata:
|
263
|
+
rubygems_mfa_required: 'true'
|
266
264
|
allowed_push_host: https://rubygems.org
|
267
265
|
post_install_message:
|
268
266
|
rdoc_options: []
|
@@ -272,14 +270,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
272
270
|
requirements:
|
273
271
|
- - ">="
|
274
272
|
- !ruby/object:Gem::Version
|
275
|
-
version:
|
273
|
+
version: '3.0'
|
276
274
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
277
275
|
requirements:
|
278
276
|
- - ">"
|
279
277
|
- !ruby/object:Gem::Version
|
280
278
|
version: 1.3.1
|
281
279
|
requirements: []
|
282
|
-
rubygems_version: 3.
|
280
|
+
rubygems_version: 3.3.3
|
283
281
|
signing_key:
|
284
282
|
specification_version: 4
|
285
283
|
summary: The web, with simplicity
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Hanami
|
2
|
-
class Application
|
3
|
-
module Autoloader
|
4
|
-
# Allows the Hanami standard inflector (from dry-inflector) to be used with Zeitwerk
|
5
|
-
class InflectorAdapter
|
6
|
-
def initialize(inflector)
|
7
|
-
@inflector = inflector
|
8
|
-
end
|
9
|
-
|
10
|
-
def camelize(basename, _abspath)
|
11
|
-
# Discard unused `_abspath` argument before calling our own inflector's
|
12
|
-
# `#camelize` (which takes only one argument)
|
13
|
-
inflector.camelize(basename)
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
attr_reader :inflector
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
Hanami.application.register_bootable :rack_logger do |container|
|
4
|
-
start do
|
5
|
-
require "hanami/web/rack_logger"
|
6
|
-
|
7
|
-
use :logger
|
8
|
-
use :rack_monitor
|
9
|
-
|
10
|
-
rack_logger = Hanami::Web::RackLogger.new(
|
11
|
-
container[:logger],
|
12
|
-
filter_params: Hanami.application.configuration.logger.filters
|
13
|
-
)
|
14
|
-
|
15
|
-
rack_logger.attach container[:rack_monitor]
|
16
|
-
|
17
|
-
register :rack_logger, rack_logger
|
18
|
-
end
|
19
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# # frozen_string_literal: true
|
2
|
-
|
3
|
-
# require "hanami/application/router"
|
4
|
-
|
5
|
-
# Hanami.application.register_bootable :router do
|
6
|
-
# start do
|
7
|
-
# configuration = Hanami.application.configuration
|
8
|
-
|
9
|
-
# routes = begin
|
10
|
-
# require File.join(configuration.root, configuration.router.routes_path)
|
11
|
-
# routes_class = Hanami.application.send(:autodiscover_application_constant, configuration.router.routes_class_name) # WIP private
|
12
|
-
# routes_class.routes
|
13
|
-
# rescue LoadError
|
14
|
-
# proc {}
|
15
|
-
# end
|
16
|
-
|
17
|
-
# resolver = configuration.router.resolver.new(
|
18
|
-
# slices: Hanami.application.slices,
|
19
|
-
# inflector: Hanami.application.inflector # TODO: use container[:inflector]?
|
20
|
-
# )
|
21
|
-
|
22
|
-
# router = Hanami::Application::Router.new(
|
23
|
-
# routes: routes,
|
24
|
-
# resolver: resolver,
|
25
|
-
# **configuration.router.options,
|
26
|
-
# ) do
|
27
|
-
# use Hanami.application[:rack_monitor]
|
28
|
-
|
29
|
-
# Hanami.application.config.for_each_middleware do |m, *args, &block|
|
30
|
-
# use(m, *args, &block)
|
31
|
-
# end
|
32
|
-
# end
|
33
|
-
|
34
|
-
# register :router, router
|
35
|
-
# end
|
36
|
-
# end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module Hanami
|
2
|
-
module Boot
|
3
|
-
module SourceDirs
|
4
|
-
def self.setup_component_dir!(component_dir, slice, container)
|
5
|
-
# TODO: this `== "lib"` check should be codified into a method somewhere
|
6
|
-
if component_dir.path == "lib"
|
7
|
-
# Expect component files in the root of the lib
|
8
|
-
# component dir to define classes inside the slice's namespace.
|
9
|
-
#
|
10
|
-
# e.g. "lib/foo.rb" should define SliceNamespace::Foo, and will be
|
11
|
-
# registered as "foo"
|
12
|
-
component_dir.namespaces.root(key: nil, const: slice.namespace_path)
|
13
|
-
|
14
|
-
slice.application.autoloader.push_dir(slice.root.join("lib"), namespace: slice.namespace)
|
15
|
-
|
16
|
-
container.config.component_dirs.add(component_dir)
|
17
|
-
else
|
18
|
-
# Expect component files in the root of these component dirs to define
|
19
|
-
# classes inside a namespace matching the dir.
|
20
|
-
#
|
21
|
-
# e.g. "actions/foo.rb" should define SliceNamespace::Actions::Foo, and
|
22
|
-
# will be registered as "actions.foo"
|
23
|
-
|
24
|
-
dir_namespace_path = File.join(slice.namespace_path, component_dir.path)
|
25
|
-
|
26
|
-
autoloader_namespace = begin
|
27
|
-
slice.inflector.constantize(slice.inflector.camelize(dir_namespace_path))
|
28
|
-
rescue NameError
|
29
|
-
slice.namespace.const_set(slice.inflector.camelize(component_dir.path), Module.new)
|
30
|
-
end
|
31
|
-
|
32
|
-
# TODO: do we need to do something special to clear out any previously configured root namespace here?
|
33
|
-
component_dir.namespaces.root(const: dir_namespace_path, key: component_dir.path) # TODO: do we need to swap path delimiters for key delimiters here?
|
34
|
-
container.config.component_dirs.add(component_dir)
|
35
|
-
|
36
|
-
slice.application.autoloader.push_dir(
|
37
|
-
slice.root.join(component_dir.path),
|
38
|
-
namespace: autoloader_namespace
|
39
|
-
)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|