hanami 2.0.0.alpha5 → 2.0.0.alpha6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c8875d3320057cffe3af1a7bb2ff781cd8ad2145c446fc9e9190d344a4a48e6
4
- data.tar.gz: c003bc2117815e10f2c15f458fb3bc6d94b480dfe9f2ec98e6458804f8a0d06d
3
+ metadata.gz: 3fc76408b7d97db32194d24bf73739bde8405fbd13855b7e4ea744f634d0739e
4
+ data.tar.gz: 30d954f8332ea7579898a87187a89a0ae2a1b34b5d9f564a86b6f61c0844f2af
5
5
  SHA512:
6
- metadata.gz: 7b133de3c728132ef6255480b10068482d58cf1e2708df395f00cc5981cdccac70cbecdb2c8325cd822298d7c92c0ee0253ab1f8f9d95ddf84b0d6de556e7f3f
7
- data.tar.gz: 42b525e3163e7bb73938b5e2fa444ccc15cc38def3e74225086f0e90bb0d805979e0a88a47703fcc73956d68598260ab366a1c155eb94b7114515b8ffc56671e
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) 2.6+
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| # rubocop:disable Metrics/BlockLength
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.required_ruby_version = ">= 2.6.0"
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.22", ">= 0.22.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"
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Hanami.application.register_bootable :inflector do
3
+ Hanami.application.register_provider :inflector do
4
4
  start do
5
5
  register :inflector, Hanami.application.inflector
6
6
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Hanami.application.register_bootable :logger do
3
+ Hanami.application.register_provider :logger do
4
4
  start do
5
5
  register :logger, Hanami.application.configuration.logger_instance
6
6
  end
@@ -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.register_bootable :rack_monitor do |container|
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(container[:notifications])
8
+ middleware = Dry::Monitor::Rack::Middleware.new(target[:notifications])
9
9
 
10
10
  register :rack_monitor, middleware
11
11
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Hanami.application.register_bootable :routes_helper do
3
+ Hanami.application.register_provider :routes_helper do
4
4
  start do
5
5
  require "hanami/application/routes_helper"
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Hanami.application.register_bootable :settings do
3
+ Hanami.application.register_provider :settings do
4
4
  start do
5
5
  register :settings, Hanami.application.settings
6
6
  end
@@ -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
- @inited = @booted = false
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
- alias config configuration
50
+ alias_method :config, :configuration
51
51
 
52
- def init # rubocop:disable Metrics/MethodLength
53
- return self if inited?
52
+ def prepare(provider_name = nil)
53
+ if provider_name
54
+ container.prepare(provider_name)
55
+ return self
56
+ end
54
57
 
55
- configuration.finalize!
58
+ return self if prepared?
56
59
 
57
- @autoloader = Zeitwerk::Loader.new
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.values.each(&:init)
69
+ slices.each_value(&:prepare)
67
70
  slices.freeze
68
71
 
69
- autoloader.setup
72
+ @autoloader.setup
70
73
 
71
- @inited = true
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
- init
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 inited?
93
- @inited
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 init'ed" unless defined?(@autoloader)
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 init'ed" unless defined?(@container)
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 init'ed" unless defined?(@deps_module)
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 init'ed" unless inited?
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(*args, **opts, &block)
143
- container.register(*args, **opts, &block)
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 init_bootable(*args)
151
- container.init(*args)
149
+ def register_provider(...)
150
+ container.register_provider(...)
152
151
  end
153
152
 
154
- def start_bootable(*args)
155
- container.start(*args)
153
+ def start(...)
154
+ container.start(...)
156
155
  end
157
156
 
158
- def key?(*args)
159
- container.key?(*args)
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 [](*args)
167
- container[*args]
165
+ def [](...)
166
+ container.[](...)
168
167
  end
169
168
 
170
- def resolve(*args)
171
- container.resolve(*args)
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 inited before detecting providers" unless inited?
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
- define_container.tap do |container|
226
- configure_container container
227
- end
228
- end
229
-
230
- def prepare_deps_module
231
- define_deps_module
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.configure do |config|
247
- config.inflector = configuration.inflector
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
- config.component_dirs.loader = Dry::System::Loader::Autoloading
256
- config.component_dirs.add_to_load_path = false
257
- end
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 other files there (outside the app namespace)
265
- # are require-able
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, Metrics/CyclomaticComplexity, Metrics/MethodLength
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/init"
29
+ require "hanami/prepare"
30
30
  application = Hanami.application
31
31
 
32
32
  [command.with_application(application), arguments]
@@ -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, cloneable: true
129
+ setting :inflector, default: Dry::Inflector.new
130
130
 
131
131
  def inflections(&block)
132
132
  self.inflector = Dry::Inflector.new(&block)
@@ -2,4 +2,4 @@
2
2
 
3
3
  require_relative "setup"
4
4
 
5
- Hanami.init
5
+ Hanami.prepare
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 || define_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 init
31
- container.import application: application.container
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! do
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(*slice_names)
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
- slice_names.each do |slice_name|
60
- container.import slice_name.to_sym => application.slices.fetch(slice_name.to_sym).container
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 register_bootable(*args, &block)
69
- container.boot(*args, &block)
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 start_bootable(*args)
77
- container.start(*args)
89
+ def start(...)
90
+ container.start(...)
78
91
  end
79
92
 
80
- def key?(*args)
81
- container.key?(*args)
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 [](*args)
89
- container[*args]
101
+ def [](...)
102
+ container.[](...)
90
103
  end
91
104
 
92
- def resolve(*args)
93
- container.resolve(*args)
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.configure do |config|
104
- config.name = name
105
- config.inflector = application.configuration.inflector
106
-
107
- config.component_dirs.loader = Dry::System::Loader::Autoloading
108
- config.component_dirs.add_to_load_path = false
109
-
110
- if root&.directory?
111
- config.root = root
112
- config.bootable_dirs = ["config/boot"]
113
-
114
- # Add component dirs for each configured component path
115
- application.configuration.source_dirs.component_dirs.each do |component_dir|
116
- next unless root.join(component_dir.path).directory?
117
-
118
- component_dir = component_dir.dup
119
-
120
- # TODO: this `== "lib"` check should be codified into a method somewhere
121
- if component_dir.path == "lib"
122
- # Expect component files in the root of the lib/ component dir to define
123
- # classes inside the slice's namespace.
124
- #
125
- # e.g. "lib/foo.rb" should define SliceNamespace::Foo, to be registered as
126
- # "foo"
127
- component_dir.namespaces.delete_root
128
- component_dir.namespaces.add_root(key: nil, const: namespace_path)
129
-
130
- config.component_dirs.add(component_dir)
131
-
132
- application.autoloader.push_dir(root.join("lib"), namespace: namespace)
133
- else
134
- # Expect component files in the root of non-lib/ component dirs to define
135
- # classes inside a namespace matching that dir.
136
- #
137
- # e.g. "actions/foo.rb" should define SliceNamespace::Actions::Foo, to be
138
- # registered as "actions.foo"
139
-
140
- dir_namespace_path = File.join(namespace_path, component_dir.path)
141
-
142
- autoloader_namespace = begin
143
- inflector.constantize(inflector.camelize(dir_namespace_path))
144
- rescue NameError
145
- namespace.const_set(inflector.camelize(component_dir.path), Module.new)
146
- end
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
- # Pass configured autoload dirs to the autoloader
161
- application.configuration.source_dirs.autoload_paths.each do |autoload_path|
162
- next unless root.join(autoload_path).directory?
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
- autoloader_namespace = begin
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
- application.autoloader.push_dir(
173
- container.root.join(autoload_path),
174
- namespace: autoloader_namespace
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
 
@@ -8,7 +8,7 @@ module Hanami
8
8
  module Version
9
9
  # @since 0.9.0
10
10
  # @api private
11
- VERSION = "2.0.0.alpha5"
11
+ VERSION = "2.0.0.alpha6"
12
12
 
13
13
  # @since 0.9.0
14
14
  # @api private
@@ -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
- attr_reader :logger
12
- attr_reader :filter_params
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, filter_params: [])
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
- # rubocop:disable Metrics/MethodLength
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: extract_params(env),
39
- elapsed: time,
50
+ params: env[ROUTER_PARAMS],
51
+ time: Time.now,
40
52
  }
41
53
 
42
- logger.info JSON.generate(data)
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
- HTTP_VERSION = "HTTP_VERSION"
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
@@ -47,8 +47,8 @@ module Hanami
47
47
  application[:logger]
48
48
  end
49
49
 
50
- def self.init
51
- application.init
50
+ def self.prepare
51
+ application.prepare
52
52
  end
53
53
 
54
54
  def self.boot
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.alpha5
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-01-12 00:00:00.000000000 Z
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.22'
107
+ version: '0.23'
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 0.22.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.22'
117
+ version: '0.23'
118
118
  - - ">="
119
119
  - !ruby/object:Gem::Version
120
- version: 0.22.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/autoloader/inflector_adapter.rb
221
- - lib/hanami/application/container/boot/inflector.rb
222
- - lib/hanami/application/container/boot/logger.rb
223
- - lib/hanami/application/container/boot/rack_logger.rb
224
- - lib/hanami/application/container/boot/rack_monitor.rb
225
- - lib/hanami/application/container/boot/routes_helper.rb
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/init.rb
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: 2.6.0
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.2.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