hanami 2.1.1 → 2.2.0.beta1

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/README.md +7 -7
  4. data/hanami.gemspec +6 -6
  5. data/lib/hanami/app.rb +5 -1
  6. data/lib/hanami/config/db.rb +33 -0
  7. data/lib/hanami/config.rb +36 -9
  8. data/lib/hanami/extensions/db/repo.rb +103 -0
  9. data/lib/hanami/extensions.rb +4 -0
  10. data/lib/hanami/helpers/form_helper/form_builder.rb +2 -4
  11. data/lib/hanami/provider_registrar.rb +26 -0
  12. data/lib/hanami/providers/assets.rb +2 -20
  13. data/lib/hanami/providers/db/adapter.rb +68 -0
  14. data/lib/hanami/providers/db/adapters.rb +44 -0
  15. data/lib/hanami/providers/db/config.rb +66 -0
  16. data/lib/hanami/providers/db/sql_adapter.rb +80 -0
  17. data/lib/hanami/providers/db.rb +203 -0
  18. data/lib/hanami/providers/db_logging.rb +22 -0
  19. data/lib/hanami/providers/rack.rb +1 -1
  20. data/lib/hanami/providers/relations.rb +31 -0
  21. data/lib/hanami/providers/routes.rb +1 -13
  22. data/lib/hanami/rake_tasks.rb +8 -7
  23. data/lib/hanami/slice.rb +84 -4
  24. data/lib/hanami/version.rb +1 -1
  25. data/lib/hanami.rb +3 -0
  26. data/spec/integration/container/provider_environment_spec.rb +52 -0
  27. data/spec/integration/db/auto_registration_spec.rb +39 -0
  28. data/spec/integration/db/db_inflector_spec.rb +57 -0
  29. data/spec/integration/db/db_slices_spec.rb +327 -0
  30. data/spec/integration/db/db_spec.rb +220 -0
  31. data/spec/integration/db/logging_spec.rb +238 -0
  32. data/spec/integration/db/provider_config_spec.rb +88 -0
  33. data/spec/integration/db/provider_spec.rb +35 -0
  34. data/spec/integration/db/repo_spec.rb +215 -0
  35. data/spec/integration/db/slices_importing_from_parent.rb +130 -0
  36. data/spec/integration/slices/slice_configuration_spec.rb +4 -4
  37. data/spec/support/app_integration.rb +3 -0
  38. data/spec/unit/hanami/config/db_spec.rb +38 -0
  39. data/spec/unit/hanami/config/router_spec.rb +1 -1
  40. data/spec/unit/hanami/helpers/form_helper_spec.rb +31 -0
  41. data/spec/unit/hanami/providers/db/config/default_config_spec.rb +107 -0
  42. data/spec/unit/hanami/providers/db/config_spec.rb +206 -0
  43. data/spec/unit/hanami/slice_spec.rb +32 -0
  44. data/spec/unit/hanami/version_spec.rb +1 -1
  45. metadata +61 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 190712bdfa529ad5769aa5effd9335e436b067cd91b6a109a3aa9a4718a73507
4
- data.tar.gz: 353ccb232425a07133e981d5d8ae6c6906f49cb48d38d7f2b55dc4e28a9c797b
3
+ metadata.gz: ada7b19a9d5205199e825e57d41758bbc67c350f3d565b01cd4720b9ed8f3ad4
4
+ data.tar.gz: 2af8c539547dcbc78dde70db5e31fc72bafa9578dcf391178ec342b618ea6467
5
5
  SHA512:
6
- metadata.gz: 4a4e7e1885c9b3eb494863b63f4d376739d6736764b435b83ce75e9a1bb68340681a26bea3883ed20c679e4d88bf99b3d487ae40e2e80f0fb15adb99acfa561d
7
- data.tar.gz: 8fe1a9d8f9f7372d67ee3f7b9c6e55b0e1aa59acbaee7264028d876dd5cd7b586f147ae08cd268d67c923d5028344bf37868d190cd2d56229932db56828dcce1
6
+ metadata.gz: ed3735c73b897db477ba35cd3d2f0aee79c98940eb4cba651590e5bedf74f34d3969a8dc8200fcae2cfda1a1f7345e873b9bcd075a3f3a627d81eef0ac36ac94
7
+ data.tar.gz: 65aebf467d397b29148dda81262550c528469adbd75759615415e89293cefd0cdb1444bd7fc1513c07d46da290ac2092f31752c4d3adeb856f709c04d540497f
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  The web, with simplicity.
4
4
 
5
+ ## v2.2.0.beta1 - 2024-07-16
6
+
7
+ ### Added
8
+
9
+ - [Tim Riley, Adam Lassek] Introduce database layer
10
+ - [Adam Lassek] Add `Hanami::Slice.app?`, returning false for slices and true for the app (#1399)
11
+ - [Tim Riley] Add `Slice#registered?`, an additional method delegating to the internal container. Returns true only if a component is already registered for the given, without triggering lazy loading (#1382)
12
+
13
+ ### Changed
14
+
15
+ - [Tim Riley] `target` inside providers is now the slice itself, instead of the slice's internal container (#1382)
16
+ - Drop support for Ruby 3.0
17
+
18
+ ### Fixed
19
+
20
+ - [Damian C. Rossney] Allow form `label` helper to receive a symbol (#1423)
21
+ - [Damian C. Rossney] Fix invalid input names generated when using form `fields_for_collection` helper (#1421)
22
+ - [Tim Riley] Fix dry-logger compatibility check for versions of dry-logger >= 1.0.4 (#1384)
23
+
5
24
  ## v2.1.1 - 2024-05-12
6
25
 
7
26
  ### Fixed
data/README.md CHANGED
@@ -4,7 +4,7 @@ The web, with simplicity.
4
4
 
5
5
  ## Version
6
6
 
7
- **This branch contains the code for `hanami` 2.0.x.**
7
+ **This branch contains the code for `hanami`: 2.2**
8
8
 
9
9
  ## Frameworks
10
10
 
@@ -14,9 +14,8 @@ This repository is for the full-stack framework, which provides the glue that ti
14
14
 
15
15
  * [**Hanami::Router**](https://github.com/hanami/router) - Rack compatible HTTP router for Ruby
16
16
  * [**Hanami::Controller**](https://github.com/hanami/controller) - Full featured, fast and testable actions for Rack
17
+ * [**Hanami::Validations**](https://github.com/hanami/validations) - Parameter validations & coercion for actions
17
18
  * [**Hanami::View**](https://github.com/hanami/view) - Presentation with a separation between views and templates
18
- * [**Hanami::Helpers**](https://github.com/hanami/helpers) - View helpers for Ruby applications
19
- * [**Hanami::Mailer**](https://github.com/hanami/mailer) - Mail for Ruby applications
20
19
  * [**Hanami::Assets**](https://github.com/hanami/assets) - Assets management for Ruby
21
20
 
22
21
  These components are designed to be used independently or together in a Hanami application.
@@ -24,12 +23,13 @@ These components are designed to be used independently or together in a Hanami a
24
23
  ## Status
25
24
 
26
25
  [![Gem Version](https://badge.fury.io/rb/hanami.svg)](https://badge.fury.io/rb/hanami)
27
- [![CI](https://github.com/hanami/hanami/workflows/ci/badge.svg?branch=main)](https://github.com/hanami/hanami/actions?query=workflow%3Aci+branch%3Amain)
26
+ [![CI](https://github.com/hanami/hanami/actions/workflows/ci.yml/badge.svg)](https://github.com/hanami/hanami/actions?query=workflow%3Aci+branch%3Amain)
27
+ [![Test Coverage](https://codecov.io/gh/hanami/hanami/branch/main/graph/badge.svg)](https://codecov.io/gh/hanami/hanami)
28
28
  [![Depfu](https://badges.depfu.com/badges/ba000e0f69e6ef1c44cd3038caaa1841/overview.svg)](https://depfu.com/github/hanami/hanami?project=Bundler)
29
29
 
30
30
  ## Installation
31
31
 
32
- __Hanami__ supports Ruby (MRI) 3.0+
32
+ __Hanami__ supports Ruby (MRI) 3.1+.
33
33
 
34
34
  ```shell
35
35
  gem install hanami
@@ -110,7 +110,7 @@ $ bundle exec rspec path/to/spec.rb
110
110
 
111
111
  ### Development Requirements
112
112
 
113
- * Ruby >= 3.0
113
+ * Ruby >= 3.1
114
114
  * Bundler
115
115
  * Node.js (MacOS)
116
116
 
@@ -120,4 +120,4 @@ __Hanami__ uses [Semantic Versioning 2.0.0](http://semver.org)
120
120
 
121
121
  ## Copyright
122
122
 
123
- Copyright © 2014 Hanami Team – Released under MIT License.
123
+ Copyright © 2014–2024 Hanami Team – Released under MIT License.
data/hanami.gemspec CHANGED
@@ -27,19 +27,19 @@ Gem::Specification.new do |spec|
27
27
  spec.test_files = Dir["spec/**/*"]
28
28
  spec.require_paths = ["lib"]
29
29
  spec.metadata["rubygems_mfa_required"] = "true"
30
- spec.required_ruby_version = ">= 3.0"
30
+ spec.required_ruby_version = ">= 3.1"
31
31
 
32
32
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
33
33
 
34
34
  spec.add_dependency "bundler", ">= 1.16", "< 3"
35
- spec.add_dependency "dry-configurable", "~> 1.0", "< 2"
35
+ spec.add_dependency "dry-configurable", "~> 1.0", ">= 1.2.0", "< 2"
36
36
  spec.add_dependency "dry-core", "~> 1.0", "< 2"
37
- spec.add_dependency "dry-inflector", "~> 1.0", "< 2"
37
+ spec.add_dependency "dry-inflector", "~> 1.0", ">= 1.1.0", "< 2"
38
38
  spec.add_dependency "dry-monitor", "~> 1.0", ">= 1.0.1", "< 2"
39
- spec.add_dependency "dry-system", "~> 1.0", "< 2"
39
+ spec.add_dependency "dry-system", "= 1.1.0.beta1"
40
40
  spec.add_dependency "dry-logger", "~> 1.0", "< 2"
41
- spec.add_dependency "hanami-cli", "~> 2.1"
42
- spec.add_dependency "hanami-utils", "~> 2.1"
41
+ spec.add_dependency "hanami-cli", "= 2.2.0.beta1"
42
+ spec.add_dependency "hanami-utils", "~> 2.2.beta"
43
43
  spec.add_dependency "zeitwerk", "~> 2.6"
44
44
 
45
45
  spec.add_development_dependency "rspec", "~> 3.8"
data/lib/hanami/app.rb CHANGED
@@ -152,7 +152,7 @@ module Hanami
152
152
  register_provider(:inflector, source: Hanami::Providers::Inflector)
153
153
 
154
154
  # Allow logger to be replaced by users with a manual provider, for advanced cases
155
- unless container.providers.find_and_load_provider(:logger)
155
+ unless container.providers[:logger]
156
156
  require_relative "providers/logger"
157
157
  register_provider(:logger, source: Hanami::Providers::Logger)
158
158
  end
@@ -161,6 +161,10 @@ module Hanami
161
161
  require_relative "providers/rack"
162
162
  register_provider(:rack, source: Hanami::Providers::Rack, namespace: true)
163
163
  end
164
+
165
+ if Hanami.bundled?("hanami-db")
166
+ register_provider(:db_logging, source: Hanami::Providers::DBLogging)
167
+ end
164
168
  end
165
169
 
166
170
  def prepare_autoloader
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+
5
+ module Hanami
6
+ class Config
7
+ # Hanami DB config
8
+ #
9
+ # @since 2.2.0
10
+ # @api public
11
+ class DB
12
+ include Dry::Configurable
13
+
14
+ setting :configure_from_parent, default: true
15
+
16
+ setting :import_from_parent, default: false
17
+
18
+ private
19
+
20
+ def method_missing(name, *args, &block)
21
+ if config.respond_to?(name)
22
+ config.public_send(name, *args, &block)
23
+ else
24
+ super
25
+ end
26
+ end
27
+
28
+ def respond_to_missing?(name, _include_all = false)
29
+ config.respond_to?(name) || super
30
+ end
31
+ end
32
+ end
33
+ end
data/lib/hanami/config.rb CHANGED
@@ -110,7 +110,12 @@ module Hanami
110
110
  #
111
111
  # @api public
112
112
  # @since 2.0.0
113
- setting :no_auto_register_paths, default: %w[entities]
113
+ setting :no_auto_register_paths, default: [
114
+ "db",
115
+ "entities",
116
+ "relations",
117
+ "structs"
118
+ ]
114
119
 
115
120
  # @!attribute [rw] base_url
116
121
  # Sets the base URL for app's web server.
@@ -216,6 +221,20 @@ module Hanami
216
221
  # @since 2.0.0
217
222
  attr_reader :actions
218
223
 
224
+ # Returns the app's db config, or a null config if hanami-db is not bundled.
225
+ #
226
+ # @example When hanami-db is bundled
227
+ # config.db.import_from_parent # => false
228
+ #
229
+ # @example When hanami-db is not bundle
230
+ # config.db.import_from_parent # => NoMethodError
231
+ #
232
+ # @return [Hanami::Config::DB, Hanami::Config::NullConfig]
233
+ #
234
+ # @api public
235
+ # @since 2.2.0
236
+ attr_reader :db
237
+
219
238
  # Returns the app's middleware stack, or nil if hanami-router is not bundled.
220
239
  #
221
240
  # Use this to configure middleware that should apply to all routes.
@@ -288,16 +307,27 @@ module Hanami
288
307
  self.render_detailed_errors = (env == :development)
289
308
  load_from_env
290
309
 
291
- @logger = Config::Logger.new(env: env, app_name: app_name)
292
310
 
293
311
  @actions = load_dependent_config("hanami-controller") {
294
312
  require_relative "config/actions"
295
313
  Actions.new
296
314
  }
297
315
 
316
+ @assets = load_dependent_config("hanami-assets") {
317
+ require_relative "config/assets"
318
+ Hanami::Config::Assets.new
319
+ }
320
+
321
+ @db = load_dependent_config("hanami-db") { DB.new }
322
+
323
+ @logger = Config::Logger.new(env: env, app_name: app_name)
324
+
325
+ @middleware = load_dependent_config("hanami-router") {
326
+ Slice::Routing::Middleware::Stack.new
327
+ }
328
+
298
329
  @router = load_dependent_config("hanami-router") {
299
330
  require_relative "config/router"
300
- @middleware = Slice::Routing::Middleware::Stack.new
301
331
  Router.new(self)
302
332
  }
303
333
 
@@ -306,11 +336,6 @@ module Hanami
306
336
  Views.new
307
337
  }
308
338
 
309
- @assets = load_dependent_config("hanami-assets") {
310
- require_relative "config/assets"
311
- Hanami::Config::Assets.new
312
- }
313
-
314
339
  yield self if block_given?
315
340
  end
316
341
  # rubocop:enable Metrics/AbcSize
@@ -321,8 +346,10 @@ module Hanami
321
346
 
322
347
  @app_name = app_name.dup
323
348
 
324
- @assets = source.assets.dup
325
349
  @actions = source.actions.dup
350
+ @assets = source.assets.dup
351
+ @db = source.db.dup
352
+ @logger = source.logger.dup
326
353
  @middleware = source.middleware.dup
327
354
  @router = source.router.dup.tap do |router|
328
355
  router.instance_variable_set(:@base_config, self)
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/db"
4
+
5
+ module Hanami
6
+ module Extensions
7
+ # @api private
8
+ # @since 2.2.0
9
+ module DB
10
+ # @api private
11
+ # @since 2.2.0
12
+ module Repo
13
+ def self.included(repo_class)
14
+ super
15
+
16
+ repo_class.extend(Hanami::SliceConfigurable)
17
+ repo_class.extend(ClassMethods)
18
+ end
19
+
20
+ # @api private
21
+ # @since 2.2.0
22
+ module ClassMethods
23
+ def configure_for_slice(slice)
24
+ extend SliceConfiguredRepo.new(slice)
25
+ end
26
+ end
27
+ end
28
+
29
+ # @api private
30
+ # @since 2.2.0
31
+ class SliceConfiguredRepo < Module
32
+ attr_reader :slice
33
+
34
+ def initialize(slice)
35
+ super()
36
+ @slice = slice
37
+ end
38
+
39
+ def extended(repo_class)
40
+ define_inherited
41
+ configure_repo(repo_class)
42
+ define_new
43
+ end
44
+
45
+ def inspect
46
+ "#<#{self.class.name}[#{slice.name}]>"
47
+ end
48
+
49
+ private
50
+
51
+ def define_inherited
52
+ root_for_repo_class = method(:root_for_repo_class)
53
+
54
+ define_method(:inherited) do |subclass|
55
+ super(subclass)
56
+
57
+ unless subclass.root
58
+ root = root_for_repo_class.(subclass)
59
+ subclass.root root if root
60
+ end
61
+ end
62
+ end
63
+
64
+ def configure_repo(repo_class)
65
+ repo_class.struct_namespace struct_namespace
66
+ end
67
+
68
+ def define_new
69
+ resolve_rom = method(:resolve_rom)
70
+
71
+ define_method(:new) do |**kwargs|
72
+ super(container: kwargs.fetch(:container) { resolve_rom.() })
73
+ end
74
+ end
75
+
76
+ def resolve_rom
77
+ slice["db.rom"]
78
+ end
79
+
80
+ def root_for_repo_class(repo_class)
81
+ return unless repo_class.to_s.end_with?("Repo")
82
+
83
+ slice.inflector.demodulize(repo_class)
84
+ .then { slice.inflector.underscore(_1) }
85
+ .then { _1.gsub(/_repo$/, "") }
86
+ .then { slice.inflector.pluralize(_1) }
87
+ .then { _1.to_sym }
88
+ end
89
+
90
+ def struct_namespace
91
+ @struct_namespace ||=
92
+ if slice.namespace.const_defined?(:Structs)
93
+ slice.namespace.const_get(:Structs)
94
+ else
95
+ slice.namespace.const_set(:Structs, Module.new)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ Hanami::DB::Repo.include(Hanami::Extensions::DB::Repo)
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ if Hanami.bundled?("hanami-db")
4
+ require_relative "extensions/db/repo"
5
+ end
6
+
3
7
  if Hanami.bundled?("hanami-controller")
4
8
  require_relative "extensions/action"
5
9
  end
@@ -226,10 +226,8 @@ module Hanami
226
226
  # @api public
227
227
  # @since 2.1.0
228
228
  def fields_for_collection(name, &block)
229
- collection_base_name = [base_name, name.to_s].compact.join(INPUT_NAME_SEPARATOR)
230
-
231
229
  _value(name).each_with_index do |value, index|
232
- fields_for("#{collection_base_name}.#{index}", index, value, &block)
230
+ fields_for("#{name}.#{index}", index, value, &block)
233
231
  end
234
232
  end
235
233
 
@@ -295,7 +293,7 @@ module Hanami
295
293
  attributes[:for] = _input_id(attributes[:for] || content)
296
294
 
297
295
  if content && !for_attribute_given
298
- content = inflector.humanize(content.split(INPUT_NAME_SEPARATOR).last)
296
+ content = inflector.humanize(content.to_s.split(INPUT_NAME_SEPARATOR).last)
299
297
  end
300
298
 
301
299
  tag.label(content, **attributes, &block)
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 2.2.0
5
+ module Hanami
6
+ class ProviderRegistrar < Dry::System::ProviderRegistrar
7
+ def self.for_slice(slice)
8
+ Class.new(self) do
9
+ define_singleton_method(:new) do |container|
10
+ super(container, slice)
11
+ end
12
+ end
13
+ end
14
+
15
+ attr_reader :slice
16
+
17
+ def initialize(container, slice)
18
+ super(container)
19
+ @slice = slice
20
+ end
21
+
22
+ def target_container
23
+ slice
24
+ end
25
+ end
26
+ end
@@ -10,18 +10,6 @@ module Hanami
10
10
  # @api private
11
11
  # @since 2.0.0
12
12
  class Assets < Dry::System::Provider::Source
13
- # @api private
14
- def self.for_slice(slice)
15
- Class.new(self) do |klass|
16
- klass.instance_variable_set(:@slice, slice)
17
- end
18
- end
19
-
20
- # @api private
21
- def self.slice
22
- @slice || Hanami.app
23
- end
24
-
25
13
  # @api private
26
14
  def prepare
27
15
  require "hanami/assets"
@@ -29,18 +17,12 @@ module Hanami
29
17
 
30
18
  # @api private
31
19
  def start
32
- root = slice.app.root.join("public", "assets", Hanami::Assets.public_assets_dir(slice).to_s)
20
+ root = target.app.root.join("public", "assets", Hanami::Assets.public_assets_dir(target).to_s)
33
21
 
34
- assets = Hanami::Assets.new(config: slice.config.assets, root: root)
22
+ assets = Hanami::Assets.new(config: target.config.assets, root: root)
35
23
 
36
24
  register(:assets, assets)
37
25
  end
38
-
39
- private
40
-
41
- def slice
42
- self.class.slice
43
- end
44
26
  end
45
27
  end
46
28
  end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+
5
+ module Hanami
6
+ module Providers
7
+ class DB < Dry::System::Provider::Source
8
+ # @api public
9
+ # @since 2.2.0
10
+ class Adapter
11
+ include Dry::Configurable
12
+
13
+ # @api public
14
+ # @since 2.2.0
15
+ setting :plugins, mutable: true
16
+
17
+ # @api private
18
+ def initialize(...)
19
+ @skip_defaults = Hash.new(false)
20
+ end
21
+
22
+ # @api public
23
+ # @since 2.2.0
24
+ def skip_defaults(setting_name = nil)
25
+ @skip_defaults[setting_name] = true
26
+ end
27
+
28
+ # @api private
29
+ private def skip_defaults?(setting_name = nil)
30
+ @skip_defaults[setting_name]
31
+ end
32
+
33
+ # @api private
34
+ def configure_for_database(database_url)
35
+ end
36
+
37
+ # @api public
38
+ # @since 2.2.0
39
+ def plugin(**plugin_spec, &config_block)
40
+ plugins << [plugin_spec, config_block]
41
+ end
42
+
43
+ # @api public
44
+ # @since 2.2.0
45
+ def plugins
46
+ config.plugins ||= []
47
+ end
48
+
49
+ # @api private
50
+ def gateway_cache_keys
51
+ gateway_options
52
+ end
53
+
54
+ # @api private
55
+ def gateway_options
56
+ {}
57
+ end
58
+
59
+ # @api public
60
+ # @since 2.2.0
61
+ def clear
62
+ config.plugins = nil
63
+ self
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module Providers
5
+ class DB < Dry::System::Provider::Source
6
+ # @api public
7
+ # @since 2.2.0
8
+ class Adapters
9
+ # @api private
10
+ # @since 2.2.0
11
+ ADAPTER_CLASSES = Hash.new(Adapter).update(
12
+ sql: SQLAdapter
13
+ ).freeze
14
+ private_constant :ADAPTER_CLASSES
15
+
16
+ extend Forwardable
17
+
18
+ def_delegators :adapters, :[], :[]=, :each, :to_h
19
+
20
+ # @api private
21
+ # @since 2.2.0
22
+ attr_reader :adapters
23
+
24
+ # @api private
25
+ # @since 2.2.0
26
+ def initialize
27
+ @adapters = Hash.new do |hsh, key|
28
+ hsh[key] = ADAPTER_CLASSES[key].new
29
+ end
30
+ end
31
+
32
+ # @api private
33
+ # @since 2.2.0
34
+ def initialize_copy(source)
35
+ @adapters = source.adapters.dup
36
+
37
+ source.adapters.each do |key, val|
38
+ @adapters[key] = val.dup
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core"
4
+
5
+ module Hanami
6
+ module Providers
7
+ class DB < Dry::System::Provider::Source
8
+ # @api public
9
+ # @since 2.2.0
10
+ class Config < Dry::Configurable::Config
11
+ include Dry::Core::Constants
12
+
13
+ # @api public
14
+ # @since 2.2.0
15
+ def adapter_name
16
+ self[:adapter]
17
+ end
18
+
19
+ # @api public
20
+ # @since 2.2.0
21
+ def adapter(name = Undefined)
22
+ return adapter_name if name.eql?(Undefined)
23
+
24
+ adapter = (adapters[name] ||= Adapter.new)
25
+ yield adapter if block_given?
26
+ adapter
27
+ end
28
+
29
+ # @api public
30
+ # @since 2.2.0
31
+ def any_adapter
32
+ adapter = (adapters[nil] ||= Adapter.new)
33
+ yield adapter if block_given?
34
+ adapter
35
+ end
36
+
37
+ # @api private
38
+ # @since 2.2.0
39
+ def gateway_cache_keys
40
+ adapters[adapter_name].gateway_cache_keys
41
+ end
42
+
43
+ # @api private
44
+ # @since 2.2.0
45
+ def gateway_options
46
+ adapters[adapter_name].gateway_options
47
+ end
48
+
49
+ # @api public
50
+ # @since 2.2.0
51
+ def each_plugin
52
+ universal_plugins = adapters[nil].plugins
53
+ adapter_plugins = adapters[adapter_name].plugins
54
+
55
+ plugins = universal_plugins + adapter_plugins
56
+
57
+ return to_enum(__method__) unless block_given?
58
+
59
+ plugins.each do |plugin_spec, config_block|
60
+ yield plugin_spec, config_block
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end