hanami 2.0.0.alpha1 → 2.0.0.alpha2

Sign up to get free protection for your applications and to get access to all the features.
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)