hanami 2.2.0.beta1 → 2.2.0.beta2

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: ada7b19a9d5205199e825e57d41758bbc67c350f3d565b01cd4720b9ed8f3ad4
4
- data.tar.gz: 2af8c539547dcbc78dde70db5e31fc72bafa9578dcf391178ec342b618ea6467
3
+ metadata.gz: 6d6bd309aaaf86dce283f25dbdf786db6da76567ae8b00aed92c34de637f8909
4
+ data.tar.gz: 3b6430d47afb052bdc4df9ce200ceb3b2888b733b040bdb4de056052a8e99db2
5
5
  SHA512:
6
- metadata.gz: ed3735c73b897db477ba35cd3d2f0aee79c98940eb4cba651590e5bedf74f34d3969a8dc8200fcae2cfda1a1f7345e873b9bcd075a3f3a627d81eef0ac36ac94
7
- data.tar.gz: 65aebf467d397b29148dda81262550c528469adbd75759615415e89293cefd0cdb1444bd7fc1513c07d46da290ac2092f31752c4d3adeb856f709c04d540497f
6
+ metadata.gz: a73cfea60952ba798fe2d04b2cf430996f8b81960959054251e4277b9f0a53aadfdad23850d389fcedcdb3f77a0855acd2e128e5d8aa3cc8a82df485ae11d592
7
+ data.tar.gz: 05a033e21dd6b9499b125583de931a39f128828ef5f8d730c7ef1522db765ffef35eb1938013b8f58d1199d68aa8564d5183a726bb733e4d1c5b1aaae9f79f7f
data/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  The web, with simplicity.
4
4
 
5
+ ## v2.2.0.beta2 - 2024-09-26
6
+
7
+ ### Added
8
+
9
+ - [Tim Riley] Support multiple gateways within each slice's `:db` provider (#1452)
10
+ - [Tim Riley] Register ROM commands and mappers in `db/commands/` and `db/mappers/`. Support registration of components from deeply nested files within these directories. (#1448)
11
+ - [Adam Lassek, Tim Riley] Make `slice` available inside providers (as an alias for `target`) (#1446)
12
+
13
+ ### Changed
14
+
15
+ - [Tim Riley] Register deeply nested relation files with ROM (#1448)
16
+ - [Kyle Plump] Raise helpful error when preparing `:db` provider if the relevant driver gem for the configured database type is not installed (#1453)
17
+ - [Sean Collins] Remove "disabled" attribute on the `<option>` generated via the `select` helper's `prompt:`, so it shows properly on the select box in the browser (#1444)
18
+
5
19
  ## v2.2.0.beta1 - 2024-07-16
6
20
 
7
21
  ### Added
data/hanami.gemspec CHANGED
@@ -36,9 +36,9 @@ Gem::Specification.new do |spec|
36
36
  spec.add_dependency "dry-core", "~> 1.0", "< 2"
37
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.1.0.beta1"
39
+ spec.add_dependency "dry-system", "= 1.1.0.beta2"
40
40
  spec.add_dependency "dry-logger", "~> 1.0", "< 2"
41
- spec.add_dependency "hanami-cli", "= 2.2.0.beta1"
41
+ spec.add_dependency "hanami-cli", "= 2.2.0.beta2"
42
42
  spec.add_dependency "hanami-utils", "~> 2.2.beta"
43
43
  spec.add_dependency "zeitwerk", "~> 2.6"
44
44
 
@@ -52,4 +52,8 @@ module Hanami
52
52
  # @api private
53
53
  RB_EXT = ".rb"
54
54
  private_constant :RB_EXT
55
+
56
+ # @api private
57
+ RB_EXT_REGEXP = %r{.rb$}
58
+ private_constant :RB_EXT_REGEXP
55
59
  end
@@ -938,7 +938,7 @@ module Hanami
938
938
  #
939
939
  # =>
940
940
  # <select name="book[store]" id="book-store" class="form-control">
941
- # <option disabled="disabled">Select a store</option>
941
+ # <option>Select a store</option>
942
942
  # <option value="it">Italy</option>
943
943
  # <option value="au">Australia</option>
944
944
  # </select>
@@ -995,7 +995,7 @@ module Hanami
995
995
  input_value = _value(name)
996
996
 
997
997
  option_tags = []
998
- option_tags << tag.option(prompt, disabled: true) if prompt
998
+ option_tags << tag.option(prompt) if prompt
999
999
 
1000
1000
  already_selected = nil
1001
1001
  values.each do |content, value|
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module Provider
5
+ class Source < Dry::System::Provider::Source
6
+ attr_reader :slice
7
+
8
+ def initialize(slice:, **options, &block)
9
+ @slice = slice
10
+ super(**options, &block)
11
+ end
12
+
13
+ def target_container = slice
14
+ end
15
+ end
16
+ end
@@ -19,8 +19,10 @@ module Hanami
19
19
  @slice = slice
20
20
  end
21
21
 
22
- def target_container
23
- slice
22
+ def provider_source_class = Hanami::Provider::Source
23
+
24
+ def provider_source_options
25
+ {slice: slice}
24
26
  end
25
27
  end
26
28
  end
@@ -9,7 +9,7 @@ module Hanami
9
9
  #
10
10
  # @api private
11
11
  # @since 2.0.0
12
- class Assets < Dry::System::Provider::Source
12
+ class Assets < Hanami::Provider::Source
13
13
  # @api private
14
14
  def prepare
15
15
  require "hanami/assets"
@@ -17,9 +17,9 @@ module Hanami
17
17
 
18
18
  # @api private
19
19
  def start
20
- root = target.app.root.join("public", "assets", Hanami::Assets.public_assets_dir(target).to_s)
20
+ root = slice.app.root.join("public", "assets", Hanami::Assets.public_assets_dir(target).to_s)
21
21
 
22
- assets = Hanami::Assets.new(config: target.config.assets, root: root)
22
+ assets = Hanami::Assets.new(config: slice.config.assets, root: root)
23
23
 
24
24
  register(:assets, assets)
25
25
  end
@@ -4,7 +4,7 @@ require "dry/configurable"
4
4
 
5
5
  module Hanami
6
6
  module Providers
7
- class DB < Dry::System::Provider::Source
7
+ class DB < Hanami::Provider::Source
8
8
  # @api public
9
9
  # @since 2.2.0
10
10
  class Adapter
@@ -30,6 +30,13 @@ module Hanami
30
30
  @skip_defaults[setting_name]
31
31
  end
32
32
 
33
+ # @api private
34
+ def configure_from_adapter(other_adapter)
35
+ return if skip_defaults?
36
+
37
+ plugins.concat(other_adapter.plugins).uniq! unless skip_defaults?(:plugins)
38
+ end
39
+
33
40
  # @api private
34
41
  def configure_for_database(database_url)
35
42
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Hanami
4
4
  module Providers
5
- class DB < Dry::System::Provider::Source
5
+ class DB < Hanami::Provider::Source
6
6
  # @api public
7
7
  # @since 2.2.0
8
8
  class Adapters
@@ -17,6 +17,12 @@ module Hanami
17
17
 
18
18
  def_delegators :adapters, :[], :[]=, :each, :to_h
19
19
 
20
+ # @api private
21
+ # @since 2.2.0
22
+ def self.new_adapter(name)
23
+ ADAPTER_CLASSES[name].new
24
+ end
25
+
20
26
  # @api private
21
27
  # @since 2.2.0
22
28
  attr_reader :adapters
@@ -25,7 +31,7 @@ module Hanami
25
31
  # @since 2.2.0
26
32
  def initialize
27
33
  @adapters = Hash.new do |hsh, key|
28
- hsh[key] = ADAPTER_CLASSES[key].new
34
+ hsh[key] = self.class.new_adapter(key)
29
35
  end
30
36
  end
31
37
 
@@ -4,12 +4,20 @@ require "dry/core"
4
4
 
5
5
  module Hanami
6
6
  module Providers
7
- class DB < Dry::System::Provider::Source
7
+ class DB < Hanami::Provider::Source
8
8
  # @api public
9
9
  # @since 2.2.0
10
10
  class Config < Dry::Configurable::Config
11
11
  include Dry::Core::Constants
12
12
 
13
+ # @api public
14
+ # @since 2.2.0
15
+ def gateway(key)
16
+ gateway = (gateways[key] ||= Gateway.new)
17
+ yield gateway if block_given?
18
+ gateway
19
+ end
20
+
13
21
  # @api public
14
22
  # @since 2.2.0
15
23
  def adapter_name
@@ -30,34 +38,22 @@ module Hanami
30
38
  # @since 2.2.0
31
39
  def any_adapter
32
40
  adapter = (adapters[nil] ||= Adapter.new)
33
- yield adapter if block_given?
41
+ yield adapter if block_given?
34
42
  adapter
35
43
  end
36
44
 
37
45
  # @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
46
  def each_plugin
52
- universal_plugins = adapters[nil].plugins
53
- adapter_plugins = adapters[adapter_name].plugins
47
+ return to_enum(__method__) unless block_given?
54
48
 
55
- plugins = universal_plugins + adapter_plugins
49
+ universal_plugins = adapters[nil].plugins
56
50
 
57
- return to_enum(__method__) unless block_given?
51
+ gateways.values.group_by(&:adapter_name).each do |adapter_name, adapter_gateways|
52
+ per_adapter_plugins = adapter_gateways.map { _1.adapter.plugins }.flatten(1)
58
53
 
59
- plugins.each do |plugin_spec, config_block|
60
- yield plugin_spec, config_block
54
+ (universal_plugins + per_adapter_plugins).uniq.each do |plugin_spec, config_block|
55
+ yield adapter_name, plugin_spec, config_block
56
+ end
61
57
  end
62
58
  end
63
59
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+ require "dry/core"
5
+
6
+ module Hanami
7
+ module Providers
8
+ class DB < Hanami::Provider::Source
9
+ # @api public
10
+ # @since 2.2.0
11
+ class Gateway
12
+ include Dry::Core::Constants
13
+ include Dry::Configurable
14
+
15
+ setting :database_url
16
+ setting :adapter_name, default: :sql
17
+ setting :adapter, mutable: true
18
+
19
+ # @api public
20
+ # @since 2.2.0
21
+ def adapter(name = Undefined)
22
+ return config.adapter if name.eql?(Undefined)
23
+
24
+ if block_given?
25
+ # If a block is given, explicitly configure the gateway's adapter
26
+ config.adapter_name = name
27
+ adapter = (config.adapter ||= Adapters.new_adapter(name))
28
+ yield adapter
29
+ adapter
30
+ else
31
+ # If an adapter name is given without a block, use the default adapter configured with
32
+ # the same name
33
+ config.adapter_name = adapter_name
34
+ end
35
+ end
36
+
37
+ # @api private
38
+ def configure_adapter(default_adapters)
39
+ default_adapter = default_adapters[config.adapter_name]
40
+ config.adapter ||= default_adapter.dup
41
+
42
+ config.adapter.configure_from_adapter(default_adapter)
43
+ config.adapter.configure_from_adapter(default_adapters[nil])
44
+ config.adapter.configure_for_database(config.database_url)
45
+
46
+ self
47
+ end
48
+
49
+ # @api private
50
+ def cache_keys
51
+ [config.database_url, config.adapter.gateway_cache_keys]
52
+ end
53
+
54
+ private
55
+
56
+ def method_missing(name, *args, &block)
57
+ if config.respond_to?(name)
58
+ config.public_send(name, *args, &block)
59
+ else
60
+ super
61
+ end
62
+ end
63
+
64
+ def respond_to_missing?(name, _include_all = false)
65
+ config.respond_to?(name) || super
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Hanami
4
4
  module Providers
5
- class DB < Dry::System::Provider::Source
5
+ class DB < Hanami::Provider::Source
6
6
  # @api public
7
7
  # @since 2.2.0
8
8
  class SQLAdapter < Adapter
@@ -22,6 +22,20 @@ module Hanami
22
22
  config.extensions ||= []
23
23
  end
24
24
 
25
+ # @api private
26
+ def configure_from_adapter(other_adapter)
27
+ super
28
+
29
+ return if skip_defaults?
30
+
31
+ # As part of gateway configuration, every gateway will receive the "any adapter" here,
32
+ # which is a plain `Adapter`, not an `SQLAdapter`. Its configuration will have been merged
33
+ # by `super`, so no further work is required.
34
+ return unless other_adapter.is_a?(self.class)
35
+
36
+ extensions.concat(other_adapter.extensions).uniq! unless skip_defaults?(:extensions)
37
+ end
38
+
25
39
  # @api private
26
40
  def configure_for_database(database_url)
27
41
  return if skip_defaults?
@@ -34,13 +48,19 @@ module Hanami
34
48
  private def configure_plugins
35
49
  return if skip_defaults?(:plugins)
36
50
 
37
- plugin relations: :instrumentation do |plugin|
38
- plugin.notifications = target["notifications"]
39
- end
51
+ # Configure the plugin via a frozen proc, so it can be properly uniq'ed when configured
52
+ # for multiple gateways. See `Hanami::Providers::DB::Config#each_plugin`.
53
+ plugin(relations: :instrumentation, &INSTRUMENTATION_PLUGIN_CONFIG)
40
54
 
41
55
  plugin relations: :auto_restrictions
42
56
  end
43
57
 
58
+ # @api private
59
+ INSTRUMENTATION_PLUGIN_CONFIG = -> plugin {
60
+ plugin.notifications = target["notifications"]
61
+ }.freeze
62
+ private_constant :INSTRUMENTATION_PLUGIN_CONFIG
63
+
44
64
  # @api private
45
65
  private def configure_extensions(database_url)
46
66
  return if skip_defaults?(:extensions)
@@ -53,7 +73,7 @@ module Hanami
53
73
  )
54
74
 
55
75
  # Extensions for specific databases
56
- if database_url.to_s.start_with?("postgresql://")
76
+ if database_url.to_s.start_with?(%r{postgres(ql)*://}) # FIXME: what is the canonical postgres URL?
57
77
  extension(
58
78
  :pg_array,
59
79
  :pg_enum,