hanami 2.0.0.alpha1 → 2.0.0.alpha2

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +70 -5
  3. data/FEATURES.md +9 -1
  4. data/LICENSE.md +1 -1
  5. data/README.md +4 -5
  6. data/hanami.gemspec +11 -11
  7. data/lib/hanami.rb +19 -18
  8. data/lib/hanami/application.rb +322 -26
  9. data/lib/hanami/application/autoloader/inflector_adapter.rb +22 -0
  10. data/lib/hanami/application/container/boot/inflector.rb +7 -0
  11. data/lib/hanami/application/container/boot/logger.rb +8 -0
  12. data/lib/hanami/application/container/boot/rack_logger.rb +19 -0
  13. data/lib/hanami/application/container/boot/rack_monitor.rb +12 -0
  14. data/lib/hanami/application/container/boot/settings.rb +7 -0
  15. data/lib/hanami/application/router.rb +59 -0
  16. data/lib/hanami/application/routing/middleware/stack.rb +89 -0
  17. data/lib/hanami/application/routing/resolver.rb +82 -0
  18. data/lib/hanami/application/routing/resolver/node.rb +50 -0
  19. data/lib/hanami/application/routing/resolver/trie.rb +59 -0
  20. data/lib/hanami/application/settings.rb +23 -0
  21. data/lib/hanami/application/settings/definition.rb +26 -0
  22. data/lib/hanami/application/settings/loader.rb +97 -0
  23. data/lib/hanami/application/settings/struct.rb +65 -0
  24. data/lib/hanami/boot.rb +1 -2
  25. data/lib/hanami/cli/application/cli.rb +40 -0
  26. data/lib/hanami/cli/application/command.rb +47 -0
  27. data/lib/hanami/cli/application/commands.rb +16 -0
  28. data/lib/hanami/cli/application/commands/console.rb +81 -0
  29. data/lib/hanami/cli/base_command.rb +48 -0
  30. data/lib/hanami/cli/commands.rb +3 -2
  31. data/lib/hanami/cli/commands/command.rb +4 -4
  32. data/lib/hanami/configuration.rb +129 -64
  33. data/lib/hanami/configuration/middleware.rb +2 -2
  34. data/lib/hanami/configuration/router.rb +50 -0
  35. data/lib/hanami/init.rb +5 -0
  36. data/lib/hanami/setup.rb +9 -0
  37. data/lib/hanami/slice.rb +138 -0
  38. data/lib/hanami/version.rb +1 -1
  39. data/lib/hanami/web/rack_logger.rb +96 -0
  40. metadata +92 -54
  41. data/bin/hanami +0 -8
  42. data/lib/hanami/configuration/cookies.rb +0 -24
  43. data/lib/hanami/configuration/security.rb +0 -141
  44. data/lib/hanami/container.rb +0 -107
  45. data/lib/hanami/frameworks.rb +0 -28
  46. data/lib/hanami/routes.rb +0 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c197523a333228ef0596099b121a0f3a3e02c4a5a0da3f3f4fe837e794b7cf8
4
- data.tar.gz: 5a7526ef47fc6f64ebffdae725d26a17944e390274dbc478ff52d593c7ba63b9
3
+ metadata.gz: ee3c6a367cfd05f2b18ae080da80b75a08a8680bd922ac8b00433e0c59f53f2b
4
+ data.tar.gz: 2de0d4102bf80606d130c04d83716370fe2c1c985986cd034ce232ff08e9be61
5
5
  SHA512:
6
- metadata.gz: dd55bf77935140473affae77676eae8afe042f385dee3288dd9d80729fb887899f89950f26b83e2b793161545347cdc3dab8a5f6e0915013aa333c2caf2e080d
7
- data.tar.gz: d254599b55640e0e3a27b718c1ae7141a40662c7291e60463d9620383cc419d49f06f5c8d1712b484f50ba758b71bf3f0ae79729452243532a0769e00478af8b
6
+ metadata.gz: a7d143ccf35f088d91fa1702d40b5aac22b3cada72cf566b239403d97fdd22b0839f93a1c20286853ae440ea4898902605b0bfbd3b05854f149de98ef9a78a83
7
+ data.tar.gz: 8f512b014ed54456df5beb0d3ecccbe260f0186d3ebfba7fb2fc51f9d80956b511ab87e08e1149dd2dd02d94939a1b260059f2cfcaa1ee34ca6681aee1408434
data/CHANGELOG.md CHANGED
@@ -1,6 +1,40 @@
1
1
  # Hanami
2
2
  The web, with simplicity.
3
3
 
4
+ ## v2.0.0.alpha2 - 2021-05-04
5
+ ### Added
6
+ - [Luca Guidi] Official support for Ruby: MRI 3.0
7
+ - [Tim Riley] Code autoloading via Zeitwerk
8
+ - [Tim Riley] `Hanami::Application` subclasses generate and configure a `Dry::System::Container`, accessible via `.container` and `AppNamespace::Container`, with several common container methods available directly via the application subclass (e.g. `Bookshelf::Application["foo"]` or `Hanami.application["foo"]`)
9
+ - [Tim Riley] Introduced `Hanami::Application.register_bootable` to register custom components
10
+ - [Tim Riley] Introduced `Hanami::Application.keys` to get the list of resolved components
11
+ - [Tim Riley] Dynamically create an auto-injection mixin (e.g. `Bookshelf::Deps`)
12
+ ```ruby
13
+ # frozen_string_literal: true
14
+
15
+ module Bookshelf
16
+ class CreateThing
17
+ include Deps[service_client: "some_service.client"]
18
+
19
+ def call(attrs)
20
+ # Validate attrs, etc.
21
+ service_client.create(attrs)
22
+ end
23
+ end
24
+ end
25
+ ```
26
+ - [Tim Riley] Introduced application settings. They are accessible via `Hanami.application.settings` in `config/settings.rb`
27
+ - [Tim Riley] Introduced application slices to organise high-level application concerns. Slices are generated based on subdirectories of `slices/`, and map onto corresponding ruby module namespaces, e.g. `slices/main` -> `Main`, with the slice instance itself being `Main::Slice` (as well as being accessible via `Hanami.application.slices[:main]`)
28
+ - [Tim Riley] Each slice generates and configures has its own `Dry::System::Container`, accessible via the slice instance (e.g. `Main::Slice.container`) as well as via its own constant (e.g. `Main::Container`)
29
+ - [Tim Riley] Slice containers automatically import the application container, under the `"application"` namespace
30
+ - [Tim Riley] Allow slice containers to be imported by other slice containers
31
+
32
+ ### Changed
33
+ - [Luca Guidi] Drop support for Ruby: MRI 2.5
34
+ - [Tim Riley] Removed `config.cookies` in favor of `config.actions.cookies`
35
+ - [Tim Riley] Removed `config.sessions` in favor of `config.actions.sessions`
36
+ - [Tim Riley] Removed `config.security` settings
37
+
4
38
  ## v2.0.0.alpha1 - 2019-01-30
5
39
  ### Added
6
40
  - [Luca Guidi] Implemented from scratch `hanami version`
@@ -50,6 +84,37 @@ end
50
84
  - [Luca Guidi] Removed `shotgun` and code reloading from the core. Code reloading is implemented by `hanami-reloader` gem.
51
85
  - [Luca Guidi] Removed support for `.hanamirc`
52
86
 
87
+ ## v1.3.4 - 2021-05-02
88
+ ### Fixed
89
+ - [Slava Kardakov] Fix generated `config.ru` `require_relative` statement
90
+ - [Armin] Fix `Hanami::CommonLogger` elapsed time compatibility with `rack` 2.1.0+
91
+ - [Adam Daniels] Fix generated tests compatibility with `minitest` 6.0+
92
+
93
+ ## v1.3.3 - 2019-09-20
94
+ ### Added
95
+ - [Gray Manley] Standardize file loading for `.env` files (see: https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use)
96
+
97
+ ### Fixed
98
+ - [Alfonso Uceda & Luca Guidi] Ensure to use `:host` option when mounting an application in main router (e.g. `mount Beta::Application.new, at: "/", host: "beta.hanami.test"`)
99
+
100
+ ## v1.3.2 - 2019-07-26
101
+ ### Added
102
+ - [Luca Guidi] Support both `hanami-validations` 1 and 2
103
+
104
+ ### Fixed
105
+ - [Wisnu Adi Nurcahyo] Ensure `hanami generate` syntax for Welcome page is compatible with ZSH
106
+ - [Luca Guidi] Don't let `hanami` to crash when called without `bundle exec`
107
+
108
+ ## v1.3.1 - 2019-01-18
109
+ ### Added
110
+ - [Luca Guidi] Official support for Ruby: MRI 2.6
111
+ - [Luca Guidi] Support `bundler` 2.0+
112
+
113
+ ### Fixed
114
+ - [Aidan Coyle] Remove from app generator support for deprecated `force_ssl` setting
115
+ - [Alessandro Caporrini] Remove from app generator support for deprecated `body_parsers` setting
116
+ - [Daphne Rouw & Sean Collins] Make app generator to work when code in `config/environment.rb` uses double quotes
117
+
53
118
  ## v1.3.0 - 2018-10-24
54
119
  ### Added
55
120
  - [Luca Guidi] Automatically log body payload from body parsers
@@ -65,7 +130,7 @@ end
65
130
 
66
131
  ### Fixed
67
132
  - [Anton Davydov] Make possible to pass extra settings for custom logger instances (eg. `logger SemanticLogger.new, :foo, :bar`)
68
- - [graywolf] Ensure `hanami generate app` to work without `require_relative` entries in `config/enviroment.rb`
133
+ - [graywolf] Ensure `hanami generate app` to work without `require_relative` entries in `config/environment.rb`
69
134
  - [Makoto Tajitsu & Luca Guidi] Fixed regression for `hanami new .` that used to generate a broken project
70
135
 
71
136
  ### Fixed
@@ -182,7 +247,7 @@ end
182
247
  - [Luca Guidi] Make compatible with Rack 2.0 only
183
248
  - [Luca Guidi] Removed `logger` settings from Hanami applications
184
249
  - [Luca Guidi] Removed logger for Hanami applications (eg `Web.logger`)
185
- - [Luca Guidi] Changed mailer syntax in `config/enviroment.rb`
250
+ - [Luca Guidi] Changed mailer syntax in `config/environment.rb`
186
251
 
187
252
  ## v0.9.2 - 2016-12-19
188
253
  ## Added
@@ -271,11 +336,11 @@ end
271
336
 
272
337
  ## v0.7.2 - 2016-02-09
273
338
  ### Fixed
274
- - [Alfonso Uceda Pompa] Fixed routing issue when static assets server tried to hijiack paths that are matching directories in public directory
339
+ - [Alfonso Uceda Pompa] Fixed routing issue when static assets server tried to hijack paths that are matching directories in public directory
275
340
 
276
341
  ## v0.7.1 - 2016-02-05
277
342
  ### Fixed
278
- - [Anton Davydov] Fixed routing issue when static assets server tried to hijiack requests belonging to dynamic endpoints
343
+ - [Anton Davydov] Fixed routing issue when static assets server tried to hijack requests belonging to dynamic endpoints
279
344
  - [Anatolii Didukh] Ensure to fallback to default engine for `hanami console`
280
345
 
281
346
  ## v0.7.0 - 2016-01-22
@@ -410,7 +475,7 @@ end
410
475
  ## v0.3.0 - 2015-03-23
411
476
  ### Added
412
477
  - [Luca Guidi] Introduced action generator. Eg. `bundle exec lotus generate action web dashboard#index`
413
- - [Alfonso Uceda Pompa] Allow to specify default coookies options in application configuration. Eg. `cookies true, { domain: 'lotusrb.org' }`
478
+ - [Alfonso Uceda Pompa] Allow to specify default cookies options in application configuration. Eg. `cookies true, { domain: 'lotusrb.org' }`
414
479
  - [Tom Kadwill] Include `Lotus::Helpers` in views.
415
480
  - [Linus Pettersson] Allow to specify `--database` CLI option when generate a new project. Eg. `lotus new bookshelf --database=postgresql`
416
481
  - [Linus Pettersson] Initialize a Git repository when generating a new project
data/FEATURES.md CHANGED
@@ -5,6 +5,14 @@
5
5
 
6
6
  ## v2.0.0.alpha1 - 2019-01-30
7
7
 
8
+ ## v1.3.3 - 2019-09-20
9
+
10
+ - Standardize file loading for `.env` files (see: https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use)
11
+
12
+ ## v1.3.2 - 2019-07-26
13
+
14
+ ## v1.3.1 - 2019-01-18
15
+
8
16
  ## v1.3.0 - 2018-10-24
9
17
 
10
18
  - Default testing framework is RSpec
@@ -20,7 +28,7 @@
20
28
  - Unobtrusive JavaScript (UJS) (via `hanami-ujs` gem)
21
29
  - Interactive console for development error page (via `hanami-webconsole` gem)
22
30
  - CLI: register callbacks for `hanami` commands (`Hanami::CLI.after("db migrate", MyCallback.new)` or `Hanami::CLI.after("db migrate") { ... }`)
23
- - Project level Rack middleware stack (`Hanami.configure { middleware.use MyRackMiddlewre }`)
31
+ - Project level Rack middleware stack (`Hanami.configure { middleware.use MyRackMiddleware }`)
24
32
  - Plugins can hook into project configuration (`Hanami.plugin { middleware.use AnotherRackMiddleware }`)
25
33
  - Custom repository commands
26
34
  - Coloured logging
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2014-2017 Luca Guidi
1
+ Copyright © 2014-2021 Luca Guidi
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -18,7 +18,6 @@ which provides the glue that ties all the parts together:
18
18
  * [**Hanami::Helpers**](https://github.com/hanami/helpers) - View helpers for Ruby applications
19
19
  * [**Hanami::Mailer**](https://github.com/hanami/mailer) - Mail for Ruby applications
20
20
  * [**Hanami::Assets**](https://github.com/hanami/assets) - Assets management for Ruby
21
- * [**Hanami::CLI**](https://github.com/hanami/cli) - Ruby command line interface
22
21
  * [**Hanami::Utils**](https://github.com/hanami/utils) - Ruby core extensions and class utilities
23
22
 
24
23
  These components are designed to be used independently or together in a Hanami application.
@@ -26,14 +25,14 @@ These components are designed to be used independently or together in a Hanami a
26
25
  ## Status
27
26
 
28
27
  [![Gem Version](https://badge.fury.io/rb/hanami.svg)](https://badge.fury.io/rb/hanami)
29
- [![TravisCI](https://travis-ci.org/hanami/hanami.svg?branch=master)](https://travis-ci.org/hanami/hanami)
30
- [![Test Coverage](https://codecov.io/gh/hanami/hanami/branch/master/graph/badge.svg)](https://codecov.io/gh/hanami/hanami)
28
+ [![CI](https://github.com/hanami/hanami/workflows/ci/badge.svg?branch=unstable)](https://github.com/hanami/hanami/actions?query=workflow%3Aci+branch%3Aunstable)
29
+ [![Test Coverage](https://codecov.io/gh/hanami/hanami/branch/unstable/graph/badge.svg)](https://codecov.io/gh/hanami/hanami)
31
30
  [![Depfu](https://badges.depfu.com/badges/ba000e0f69e6ef1c44cd3038caaa1841/overview.svg)](https://depfu.com/github/hanami/hanami?project=Bundler)
32
31
  [![Inline Docs](http://inch-ci.org/github/hanami/hanami.svg)](http://inch-ci.org/github/hanami/hanami)
33
32
 
34
33
  ## Installation
35
34
 
36
- __Hanami__ supports Ruby (MRI) 2.5+
35
+ __Hanami__ supports Ruby (MRI) 2.6+
37
36
 
38
37
  ```shell
39
38
  gem install hanami
@@ -137,4 +136,4 @@ Released under MIT License.
137
136
 
138
137
  This project was formerly known as Lotus (`lotusrb`).
139
138
 
140
- Copyright © 2014-2019 Luca Guidi.
139
+ Copyright © 2014-2021 Luca Guidi.
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| # rubocop:disable Metrics/BlockLength
8
8
  spec.name = "hanami"
9
9
  spec.version = Hanami::VERSION
10
10
  spec.authors = ["Luca Guidi"]
@@ -15,22 +15,22 @@ Gem::Specification.new do |spec|
15
15
  spec.license = "MIT"
16
16
 
17
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")
18
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
18
  spec.test_files = spec.files.grep(%r{^(test)/})
20
19
  spec.require_paths = ["lib"]
21
- spec.required_ruby_version = ">= 2.5.0"
20
+ spec.required_ruby_version = ">= 2.6.0"
22
21
 
23
22
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
24
23
 
25
- spec.add_dependency "hanami-utils", "~> 2.0.alpha"
26
- spec.add_dependency "hanami-router", "~> 2.0.alpha"
27
- spec.add_dependency "hanami-controller", "~> 2.0.alpha"
28
- spec.add_dependency "hanami-cli", "~> 1.0.alpha"
29
- spec.add_dependency "dry-system", "~> 0.10"
30
- spec.add_dependency "dry-inflector", "~> 0.1", ">= 0.1.2"
31
24
  spec.add_dependency "bundler", ">= 1.16", "< 3"
25
+ spec.add_dependency "dry-core", "~> 0.4"
26
+ spec.add_dependency "dry-inflector", "~> 0.1", ">= 0.1.2"
27
+ spec.add_dependency "dry-monitor"
28
+ spec.add_dependency "dry-system", "~> 0.19", ">= 0.19.0"
29
+ spec.add_dependency "hanami-cli", "~> 2.0.alpha"
30
+ spec.add_dependency "hanami-utils", "~> 2.0.alpha"
31
+ spec.add_dependency "zeitwerk", "~> 2.4"
32
32
 
33
- spec.add_development_dependency "rspec", "~> 3.8"
33
+ spec.add_development_dependency "rspec", "~> 3.8"
34
34
  spec.add_development_dependency "rack-test", "~> 1.1"
35
- spec.add_development_dependency "rake", "~> 12.0"
35
+ spec.add_development_dependency "rake", "~> 13.0"
36
36
  end
data/lib/hanami.rb CHANGED
@@ -7,25 +7,27 @@
7
7
  # @see http://hanamirb.org
8
8
  module Hanami
9
9
  require "hanami/version"
10
- require "hanami/frameworks"
11
- require "hanami/container"
12
10
  require "hanami/application"
13
11
 
14
12
  @_mutex = Mutex.new
15
13
 
16
14
  def self.application
17
15
  @_mutex.synchronize do
18
- raise "Hanami application not configured" unless defined?(@_application)
16
+ raise "Hanami.application not configured" unless defined?(@_application)
19
17
 
20
18
  @_application
21
19
  end
22
20
  end
23
21
 
24
- def self.application=(app)
22
+ def self.application?
23
+ defined?(@_application)
24
+ end
25
+
26
+ def self.application=(klass)
25
27
  @_mutex.synchronize do
26
- raise "Hanami application already configured" if defined?(@_application)
28
+ raise "Hanami.application already configured" if defined?(@_application)
27
29
 
28
- @_application = app unless app.name.nil?
30
+ @_application = klass unless klass.name.nil?
29
31
  end
30
32
  end
31
33
 
@@ -45,10 +47,6 @@ module Hanami
45
47
  end
46
48
  end
47
49
 
48
- def self.root
49
- Container.root
50
- end
51
-
52
50
  def self.env
53
51
  (ENV["HANAMI_ENV"] || "development").to_sym
54
52
  end
@@ -58,18 +56,21 @@ module Hanami
58
56
  end
59
57
 
60
58
  def self.logger
61
- Container[:logger]
59
+ application[:logger]
62
60
  end
63
61
 
64
- def self.boot
65
- @_mutex.synchronize do
66
- raise "Hanami application already booted" if defined?(@_booted)
62
+ def self.init
63
+ application.init
64
+ end
67
65
 
68
- @_booted = true
69
- end
66
+ def self.boot(web: true)
67
+ if defined?(@_app)
68
+ @_app
69
+ else
70
+ application.boot
70
71
 
71
- Container.finalize!
72
- self.app = application.new
72
+ @_app = application.new if web
73
+ end
73
74
  end
74
75
 
75
76
  def self.bundler_groups
@@ -1,66 +1,362 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dry/system/container"
3
4
  require "hanami/configuration"
4
- require "hanami/routes"
5
- require "hanami/router"
5
+ require "pathname"
6
+ require "rack"
7
+ require_relative "slice"
8
+ require_relative "application/autoloader/inflector_adapter"
9
+ require_relative "application/settings"
6
10
 
7
11
  module Hanami
8
- # Hanami application
12
+ # Hanami application class
9
13
  #
10
14
  # @since 2.0.0
11
15
  class Application
12
16
  @_mutex = Mutex.new
13
17
 
14
- def self.inherited(app)
15
- @_mutex.synchronize do
16
- app.class_eval do
17
- @_mutex = Mutex.new
18
- @_configuration = Hanami::Configuration.new(env: Hanami.env)
18
+ class << self
19
+ def inherited(klass)
20
+ @_mutex.synchronize do
21
+ klass.class_eval do
22
+ @_mutex = Mutex.new
23
+ @_configuration = Hanami::Configuration.new(env: Hanami.env)
19
24
 
20
- extend ClassMethods
21
- include InstanceMethods
22
- end
25
+ extend ClassMethods
26
+ include InstanceMethods
27
+ end
28
+
29
+ klass.send :prepare_base_load_path
23
30
 
24
- Hanami.application = app
31
+ Hanami.application = klass
32
+ end
25
33
  end
26
34
  end
27
35
 
28
- # Class method interface
36
+ # Application class interface
29
37
  #
30
- # @since 2.0.0
38
+ # rubocop:disable Metrics/ModuleLength
31
39
  module ClassMethods
40
+ def self.extended(klass)
41
+ klass.class_eval do
42
+ @inited = @booted = false
43
+ end
44
+ end
45
+
32
46
  def configuration
33
47
  @_configuration
34
48
  end
35
49
 
36
50
  alias config configuration
37
51
 
38
- def routes(&blk)
52
+ def init # rubocop:disable Metrics/MethodLength
53
+ return self if inited?
54
+
55
+ configuration.finalize
56
+
57
+ load_settings
58
+
59
+ @container = prepare_container
60
+ @deps_module = prepare_deps_module
61
+
62
+ load_slices
63
+ slices.values.each(&:init)
64
+ slices.freeze
65
+
66
+ if configuration.autoloader
67
+ configuration.autoloader.inflector = Autoloader::InflectorAdapter.new(inflector)
68
+ configuration.autoloader.setup
69
+ end
70
+
71
+ load_routes
72
+
73
+ @inited = true
74
+ self
75
+ end
76
+
77
+ def inited?
78
+ @inited
79
+ end
80
+
81
+ def container
82
+ raise "Application not init'ed" unless defined?(@container)
83
+
84
+ @container
85
+ end
86
+
87
+ def deps
88
+ raise "Application not init'ed" unless defined?(@deps_module)
89
+
90
+ @deps_module
91
+ end
92
+
93
+ def slices
94
+ @slices ||= {}
95
+ end
96
+
97
+ def register_slice(name, **slice_args)
98
+ raise "Slice +#{name}+ already registered" if slices.key?(name.to_sym)
99
+
100
+ slice = Slice.new(self, name: name, **slice_args)
101
+ slice.namespace.const_set :Slice, slice if slice.namespace # rubocop:disable Style/SafeNavigation
102
+ slices[name.to_sym] = slice
103
+ end
104
+
105
+ def register(*args, **opts, &block)
106
+ container.register(*args, **opts, &block)
107
+ end
108
+
109
+ def register_bootable(*args, **opts, &block)
110
+ container.boot(*args, **opts, &block)
111
+ end
112
+
113
+ def init_bootable(*args)
114
+ container.init(*args)
115
+ end
116
+
117
+ def start_bootable(*args)
118
+ container.start(*args)
119
+ end
120
+
121
+ def key?(*args)
122
+ container.key?(*args)
123
+ end
124
+
125
+ def keys
126
+ container.keys
127
+ end
128
+
129
+ def [](*args)
130
+ container[*args]
131
+ end
132
+
133
+ def resolve(*args)
134
+ container.resolve(*args)
135
+ end
136
+
137
+ def boot(&block)
138
+ return self if booted?
139
+
140
+ init
141
+
142
+ container.finalize!(&block)
143
+
144
+ slices.values.each(&:boot)
145
+
146
+ @booted = true
147
+ self
148
+ end
149
+
150
+ def booted?
151
+ @booted
152
+ end
153
+
154
+ def settings(&block) # rubocop:disable Metrics/MethodLength
155
+ if block
156
+ @_settings = Application::Settings.build(
157
+ configuration.settings_loader,
158
+ configuration.settings_loader_options,
159
+ &block
160
+ )
161
+ elsif instance_variable_defined?(:@_settings)
162
+ @_settings
163
+ else
164
+ # Load settings lazily so they can be used to configure the
165
+ # Hanami::Application subclass (before the application has inited)
166
+ load_settings
167
+ @_settings ||= nil
168
+ end
169
+ end
170
+
171
+ def routes(&block)
39
172
  @_mutex.synchronize do
40
- if blk.nil?
173
+ if block.nil?
41
174
  raise "Hanami.application.routes not configured" unless defined?(@_routes)
42
175
 
43
176
  @_routes
44
177
  else
45
- @_routes = Routes.new(&blk)
178
+ @_routes = block
179
+ end
180
+ end
181
+ end
182
+
183
+ MODULE_DELIMITER = "::"
184
+ private_constant :MODULE_DELIMITER
185
+
186
+ def namespace
187
+ inflector.constantize(name.split(MODULE_DELIMITER)[0..-2].join(MODULE_DELIMITER))
188
+ end
189
+
190
+ def namespace_path
191
+ inflector.underscore(namespace)
192
+ end
193
+
194
+ def application_name
195
+ inflector.underscore(namespace).to_sym
196
+ end
197
+
198
+ def root
199
+ configuration.root
200
+ end
201
+
202
+ def inflector
203
+ configuration.inflector
204
+ end
205
+
206
+ # @api private
207
+ def component_provider(component)
208
+ raise "Hanami.application must be inited before detecting providers" unless inited?
209
+
210
+ # [Admin, Main, MyApp] or [MyApp::Admin, MyApp::Main, MyApp]
211
+ providers = slices.values + [self]
212
+
213
+ component_class = component.is_a?(Class) ? component : component.class
214
+ component_name = component_class.name
215
+
216
+ return unless component_name
217
+
218
+ providers.detect { |provider| component_name.include?(provider.namespace.to_s) }
219
+ end
220
+
221
+ private
222
+
223
+ def prepare_base_load_path
224
+ base_path = File.join(root, "lib")
225
+ $LOAD_PATH.unshift base_path unless $LOAD_PATH.include?(base_path)
226
+ end
227
+
228
+ def prepare_container
229
+ define_container.tap do |container|
230
+ configure_container container
231
+ end
232
+ end
233
+
234
+ def prepare_deps_module
235
+ define_deps_module
236
+ end
237
+
238
+ def define_container
239
+ require "#{application_name}/container"
240
+ namespace.const_get :Container
241
+ rescue LoadError, NameError
242
+ namespace.const_set :Container, Class.new(Dry::System::Container)
243
+ end
244
+
245
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
246
+ def configure_container(container)
247
+ container.use :env, inferrer: -> { Hanami.env }
248
+ container.use :notifications
249
+
250
+ container.configure do |config|
251
+ config.inflector = configuration.inflector
252
+
253
+ config.root = configuration.root
254
+ config.bootable_dirs = [
255
+ "config/boot",
256
+ Pathname(__dir__).join("application/container/boot").realpath,
257
+ ]
258
+
259
+ if configuration.autoloader
260
+ require "dry/system/loader/autoloading"
261
+ config.component_dirs.loader = Dry::System::Loader::Autoloading
262
+ config.component_dirs.add_to_load_path = false
263
+ end
264
+
265
+ if root.join("lib").directory?
266
+ config.component_dirs.add "lib" do |dir|
267
+ dir.default_namespace = application_name.to_s
268
+ end
269
+
270
+ configuration.autoloader&.push_dir(root.join("lib"))
46
271
  end
47
272
  end
273
+
274
+ container
275
+ end
276
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
277
+
278
+ def define_deps_module
279
+ require "#{application_name}/deps"
280
+ namespace.const_get :Deps
281
+ rescue LoadError, NameError
282
+ namespace.const_set :Deps, container.injector
283
+ end
284
+
285
+ def load_slices
286
+ Dir[File.join(slices_path, "*")]
287
+ .select(&File.method(:directory?))
288
+ .each(&method(:load_slice))
289
+ end
290
+
291
+ def slices_path
292
+ File.join(root, config.slices_dir)
293
+ end
294
+
295
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
296
+ def load_slice(slice_path)
297
+ slice_path = Pathname(slice_path)
298
+
299
+ slice_name = slice_path.relative_path_from(Pathname(slices_path)).to_s
300
+ slice_const_name = inflector.camelize(slice_name)
301
+
302
+ if config.slices_namespace.const_defined?(slice_const_name)
303
+ slice_module = config.slices_namespace.const_get(slice_const_name)
304
+
305
+ raise "Cannot use slice +#{slice_const_name}+ since it is not a module" unless slice_module.is_a?(Module)
306
+ else
307
+ slice_module = Module.new
308
+ config.slices_namespace.const_set inflector.camelize(slice_name), slice_module
309
+ end
310
+
311
+ register_slice(
312
+ slice_name,
313
+ namespace: slice_module,
314
+ root: slice_path.realpath
315
+ )
316
+ end
317
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
318
+
319
+ def load_routes
320
+ require File.join(configuration.root, configuration.router.routes)
321
+ rescue LoadError # rubocop:disable Lint/SuppressedException
322
+ end
323
+
324
+ def load_settings
325
+ prepare_base_load_path
326
+ require File.join(configuration.root, configuration.settings_path)
327
+ rescue LoadError # rubocop:disable Lint/SuppressedException
48
328
  end
49
329
  end
330
+ # rubocop:enable Metrics/ModuleLength
50
331
 
51
- # Instance method interface
52
- #
53
- # @since 2.0.0
332
+ # Application instance interface
54
333
  module InstanceMethods
55
- def initialize(configuration: self.class.configuration, routes: self.class.routes)
56
- @app = Rack::Builder.new do
57
- configuration.for_each_middleware do |m, *args|
58
- use m, *args
59
- end
334
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
335
+ def initialize(application = self.class)
336
+ require_relative "application/router"
337
+
338
+ application.boot
339
+
340
+ resolver = application.config.router.resolver.new(
341
+ slices: application.slices,
342
+ inflector: application.inflector
343
+ )
60
344
 
61
- run Hanami::Router.new(**configuration.router_settings, &routes)
345
+ router = Application::Router.new(
346
+ routes: application.routes,
347
+ resolver: resolver,
348
+ **application.configuration.router.options,
349
+ ) do
350
+ use application[:rack_monitor]
351
+
352
+ application.config.for_each_middleware do |m, *args, &block|
353
+ use(m, *args, &block)
354
+ end
62
355
  end
356
+
357
+ @app = router.to_rack_app
63
358
  end
359
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
64
360
 
65
361
  def call(env)
66
362
  @app.call(env)