hanami 2.2.0.beta2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d6bd309aaaf86dce283f25dbdf786db6da76567ae8b00aed92c34de637f8909
4
- data.tar.gz: 3b6430d47afb052bdc4df9ce200ceb3b2888b733b040bdb4de056052a8e99db2
3
+ metadata.gz: 7ebc4cbb51db37137a558abeeb3c4aa509d2a6d4db521458b465a427e503b098
4
+ data.tar.gz: fdd74d2e280be11ba0db6852a0dcfcd15df7629a1edb6e6b7067f623103d9fdd
5
5
  SHA512:
6
- metadata.gz: a73cfea60952ba798fe2d04b2cf430996f8b81960959054251e4277b9f0a53aadfdad23850d389fcedcdb3f77a0855acd2e128e5d8aa3cc8a82df485ae11d592
7
- data.tar.gz: 05a033e21dd6b9499b125583de931a39f128828ef5f8d730c7ef1522db765ffef35eb1938013b8f58d1199d68aa8564d5183a726bb733e4d1c5b1aaae9f79f7f
6
+ metadata.gz: 5c7fbba4c66f89f8426a675c88005b1c67a544f7051aec5835108a075631b253fde376b8a6b993a78257fb329e398dad45349f8380716ff0ca1d812b79624619
7
+ data.tar.gz: c5e66a40feaee584b0d6cc9d22aa31b01abcc4d8ec06a3fe09a9aca294f2cdf5d41c3bfa92a6da291a5c9015fac96f4986ac9535f8b85b3681b81708dd69dcdf
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  The web, with simplicity.
4
4
 
5
+ ## v2.2.0 - 2024-11-05
6
+
7
+ ### Changed
8
+
9
+ - [Tim Riley] Depend on dry-system v1.1, the stable release featuring the changes supporting the provider improvements introduced in beta1 and beta2 (#1467)
10
+ - [Tim Riley] Added specific "json" gem dependency to gemspec in order to suppress bundled gem deprecation warnings appearing in Ruby 3.3.5 (#1469)
11
+
12
+ ## v2.2.0.rc1 - 2024-10-29
13
+
14
+ ### Added
15
+
16
+ - [Adam Lassek] Add `#connection_options` to db gateways. These are a hash of options that will be passed to the lower-level driver when the gateway connects. For SQL databases, this means [Sequel's connection options](https://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html) (#1450)
17
+ - [Adam Lassek] Automatically configure `Dry::Operation` subclasses within Hanami apps for `transaction` support using the app's ROM container. (#1456)
18
+
19
+ ### Changed
20
+
21
+ - [Tim Riley] Apply config from matching gateways in parent slices (#1459)
22
+ - [Tim Riley] Remove `config.any_adapter` from DB provider (#1459)
23
+
5
24
  ## v2.2.0.beta2 - 2024-09-26
6
25
 
7
26
  ### Added
data/hanami.gemspec CHANGED
@@ -36,10 +36,11 @@ 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.beta2"
39
+ spec.add_dependency "dry-system", "~> 1.1"
40
40
  spec.add_dependency "dry-logger", "~> 1.0", "< 2"
41
- spec.add_dependency "hanami-cli", "= 2.2.0.beta2"
42
- spec.add_dependency "hanami-utils", "~> 2.2.beta"
41
+ spec.add_dependency "hanami-cli", "~> 2.2"
42
+ spec.add_dependency "hanami-utils", "~> 2.2"
43
+ spec.add_dependency "json", ">= 2.7.2"
43
44
  spec.add_dependency "zeitwerk", "~> 2.6"
44
45
 
45
46
  spec.add_development_dependency "rspec", "~> 3.8"
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/operation"
4
+ require "dry/operation/extensions/rom"
5
+
6
+ module Hanami
7
+ module Extensions
8
+ # Integrated behavior for `Dry::Operation` classes within Hanami apps.
9
+ #
10
+ # @see https://github.com/dry-rb/dry-operation
11
+ #
12
+ # @api public
13
+ # @since 2.2.0
14
+ module Operation
15
+ # @api private
16
+ # @since 2.2.0
17
+ def self.included(operation_class)
18
+ super
19
+
20
+ operation_class.extend(Hanami::SliceConfigurable)
21
+ operation_class.extend(ClassMethods)
22
+ end
23
+
24
+ # @api private
25
+ # @since 2.2.0
26
+ module ClassMethods
27
+ # @api private
28
+ # @since 2.2.0
29
+ def configure_for_slice(slice)
30
+ include slice.namespace::Deps["db.rom"]
31
+ end
32
+
33
+ # @api private
34
+ # @since 2.2.0
35
+ def inherited(subclass)
36
+ super
37
+
38
+ return unless subclass.superclass == self
39
+ return unless Hanami.bundled?("hanami-db")
40
+
41
+ subclass.include Dry::Operation::Extensions::ROM
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ Dry::Operation.include(Hanami::Extensions::Operation)
@@ -19,3 +19,7 @@ end
19
19
  if Hanami.bundled?("hanami-router")
20
20
  require_relative "extensions/router/errors"
21
21
  end
22
+
23
+ if Hanami.bundled?("dry-operation")
24
+ require_relative "extensions/operation"
25
+ end
@@ -30,9 +30,7 @@ module Hanami
30
30
  # @api private
31
31
  # @since 2.2.0
32
32
  def initialize
33
- @adapters = Hash.new do |hsh, key|
34
- hsh[key] = self.class.new_adapter(key)
35
- end
33
+ @adapters = {}
36
34
  end
37
35
 
38
36
  # @api private
@@ -44,6 +42,24 @@ module Hanami
44
42
  @adapters[key] = val.dup
45
43
  end
46
44
  end
45
+
46
+ # @api private
47
+ # @since 2.2.0
48
+ def adapter(key)
49
+ adapters[key] ||= new(key)
50
+ end
51
+
52
+ # @api private
53
+ # @since 2.2.0
54
+ def find(key)
55
+ adapters.fetch(key) { new(key) }
56
+ end
57
+
58
+ # @api private
59
+ # @since 2.2.0
60
+ def new(key)
61
+ self.class.new_adapter(key)
62
+ end
47
63
  end
48
64
  end
49
65
  end
@@ -20,24 +20,8 @@ module Hanami
20
20
 
21
21
  # @api public
22
22
  # @since 2.2.0
23
- def adapter_name
24
- self[:adapter]
25
- end
26
-
27
- # @api public
28
- # @since 2.2.0
29
- def adapter(name = Undefined)
30
- return adapter_name if name.eql?(Undefined)
31
-
32
- adapter = (adapters[name] ||= Adapter.new)
33
- yield adapter if block_given?
34
- adapter
35
- end
36
-
37
- # @api public
38
- # @since 2.2.0
39
- def any_adapter
40
- adapter = (adapters[nil] ||= Adapter.new)
23
+ def adapter(name)
24
+ adapter = adapters.adapter(name)
41
25
  yield adapter if block_given?
42
26
  adapter
43
27
  end
@@ -46,12 +30,10 @@ module Hanami
46
30
  def each_plugin
47
31
  return to_enum(__method__) unless block_given?
48
32
 
49
- universal_plugins = adapters[nil].plugins
50
-
51
33
  gateways.values.group_by(&:adapter_name).each do |adapter_name, adapter_gateways|
52
- per_adapter_plugins = adapter_gateways.map { _1.adapter.plugins }.flatten(1)
34
+ per_adapter_plugins = adapter_gateways.map { _1.adapter.plugins }.flatten(1).uniq
53
35
 
54
- (universal_plugins + per_adapter_plugins).uniq.each do |plugin_spec, config_block|
36
+ per_adapter_plugins.each do |plugin_spec, config_block|
55
37
  yield adapter_name, plugin_spec, config_block
56
38
  end
57
39
  end
@@ -15,6 +15,7 @@ module Hanami
15
15
  setting :database_url
16
16
  setting :adapter_name, default: :sql
17
17
  setting :adapter, mutable: true
18
+ setting :connection_options, default: {}
18
19
 
19
20
  # @api public
20
21
  # @since 2.2.0
@@ -34,13 +35,29 @@ module Hanami
34
35
  end
35
36
  end
36
37
 
38
+ # @api public
39
+ # @since 2.2.0
40
+ def connection_options(**options)
41
+ if options.any?
42
+ config.connection_options.merge!(options)
43
+ end
44
+
45
+ config.connection_options
46
+ end
47
+
48
+ # @api public
49
+ # @since 2.2.0
50
+ def options
51
+ {**connection_options, **config.adapter.gateway_options}
52
+ end
53
+
37
54
  # @api private
38
55
  def configure_adapter(default_adapters)
39
- default_adapter = default_adapters[config.adapter_name]
56
+ default_adapter = default_adapters.find(config.adapter_name)
40
57
  config.adapter ||= default_adapter.dup
41
58
 
42
59
  config.adapter.configure_from_adapter(default_adapter)
43
- config.adapter.configure_from_adapter(default_adapters[nil])
60
+
44
61
  config.adapter.configure_for_database(config.database_url)
45
62
 
46
63
  self
@@ -48,7 +65,7 @@ module Hanami
48
65
 
49
66
  # @api private
50
67
  def cache_keys
51
- [config.database_url, config.adapter.gateway_cache_keys]
68
+ [config.database_url, config.connection_options, config.adapter.gateway_cache_keys]
52
69
  end
53
70
 
54
71
  private
@@ -13,7 +13,7 @@ module Hanami
13
13
  # @api public
14
14
  # @since 2.2.0
15
15
  def extension(*extensions)
16
- self.extensions.concat(extensions)
16
+ self.extensions.concat(extensions).uniq!
17
17
  end
18
18
 
19
19
  # @api public
@@ -73,7 +73,7 @@ module Hanami
73
73
  )
74
74
 
75
75
  # Extensions for specific databases
76
- if database_url.to_s.start_with?(%r{postgres(ql)*://}) # FIXME: what is the canonical postgres URL?
76
+ if database_url.to_s.start_with?(%r{postgres(ql)*://})
77
77
  extension(
78
78
  :pg_array,
79
79
  :pg_enum,
@@ -85,7 +85,7 @@ module Hanami
85
85
 
86
86
  # @api private
87
87
  def gateway_options
88
- {extensions: config.extensions}
88
+ {extensions: extensions}
89
89
  end
90
90
 
91
91
  # @api public
@@ -113,7 +113,7 @@ module Hanami
113
113
  # Preserve settings already configured locally
114
114
  next if config.configured?(key)
115
115
 
116
- # Do not copy gateways, these are always configured per slice
116
+ # Skip gateway config, we handle this in #configure_gateways
117
117
  next if key == :gateways
118
118
 
119
119
  # Skip adapter config, we handle this below
@@ -123,12 +123,12 @@ module Hanami
123
123
  end
124
124
 
125
125
  parent_db_provider.source.config.adapters.each do |adapter_name, parent_adapter|
126
- adapter = config.adapters[adapter_name]
126
+ adapter = config.adapter(adapter_name)
127
127
 
128
128
  adapter.class.settings.keys.each do |key|
129
129
  next if adapter.config.configured?(key)
130
130
 
131
- adapter.config[key] = parent_adapter.config[key]
131
+ adapter.config[key] = parent_adapter.config[key].dup
132
132
  end
133
133
  end
134
134
  end
@@ -196,18 +196,40 @@ module Hanami
196
196
 
197
197
  ensure_database_gem(gw_config.database_url)
198
198
 
199
+ apply_parent_gateway_config(key, gw_config) if apply_parent_config?
200
+
199
201
  gw_config.configure_adapter(config.adapters)
200
202
  end
201
203
  end
202
204
 
205
+ def apply_parent_gateway_config(key, gw_config)
206
+ parent_gw_config = parent_db_provider.source.config.gateways[key]
207
+
208
+ # Only copy config from a parent gateway with the same name _and_ database URL
209
+ return unless parent_gw_config&.database_url == gw_config.database_url
210
+
211
+ # Copy config from matching parent gateway
212
+ (gw_config.class.settings.keys - [:adapter]).each do |key|
213
+ next if gw_config.config.configured?(key)
214
+
215
+ gw_config.config[key] = parent_gw_config.config[key].dup
216
+ end
217
+
218
+ # If there is an adapter configured within this slice, prefer that, and do not copy the
219
+ # adapter from the parent gateway
220
+ unless config.adapters[gw_config.adapter_name] || gw_config.configured?(:adapter)
221
+ gw_config.adapter = parent_gw_config.adapter.dup
222
+ end
223
+ end
224
+
203
225
  def prepare_gateways
204
226
  config.gateways.transform_values { |gw_config|
205
227
  # Avoid spurious connections by reusing identically configured gateways across slices
206
- gateway = fetch_or_store(gw_config.cache_keys) {
228
+ fetch_or_store(gw_config.cache_keys) {
207
229
  ROM::Gateway.setup(
208
230
  gw_config.adapter_name,
209
231
  gw_config.database_url,
210
- **gw_config.adapter.gateway_options
232
+ **gw_config.options
211
233
  )
212
234
  }
213
235
  }
@@ -7,7 +7,7 @@ module Hanami
7
7
  # @api private
8
8
  module Version
9
9
  # @api public
10
- VERSION = "2.2.0.beta2"
10
+ VERSION = "2.2.0"
11
11
 
12
12
  # @since 0.9.0
13
13
  # @api private
@@ -17,6 +17,7 @@ RSpec.describe "DB / Slices", :app_integration do
17
17
 
18
18
  module TestApp
19
19
  class App < Hanami::App
20
+ config.logger.stream = File::NULL
20
21
  end
21
22
  end
22
23
  RUBY
@@ -32,6 +33,67 @@ RSpec.describe "DB / Slices", :app_integration do
32
33
  end
33
34
  end
34
35
 
36
+ specify "slices using a parent gateway with connection options share a gateway/connection" do
37
+ with_tmp_directory(@dir = Dir.mktmpdir) do
38
+ write "config/app.rb", <<~RUBY
39
+ require "hanami"
40
+
41
+ module TestApp
42
+ class App < Hanami::App
43
+ config.logger.stream = File::NULL
44
+ end
45
+ end
46
+ RUBY
47
+
48
+ write "config/providers/db.rb", <<~RUBY
49
+ Hanami.app.configure_provider :db do
50
+ config.gateway :default do |gw|
51
+ gw.connection_options timeout: 10_000
52
+ end
53
+
54
+ config.gateway :extra do |gw|
55
+ gw.connection_options timeout: 20_000
56
+ end
57
+ end
58
+ RUBY
59
+
60
+ write "slices/main/config/providers/db.rb", <<~RUBY
61
+ Main::Slice.configure_provider :db do
62
+ config.gateway :bonus do |gw|
63
+ gw.connection_options timeout: 5_000
64
+ end
65
+ end
66
+ RUBY
67
+
68
+ write "db/.keep", ""
69
+ write "slices/admin/relations/.keep", ""
70
+ write "slices/main/relations/.keep", ""
71
+
72
+ ENV["DATABASE_URL"] = "sqlite://" + Pathname(@dir).realpath.join("app.sqlite").to_s
73
+ ENV["DATABASE_URL__EXTRA"] = "sqlite://" + Pathname(@dir).realpath.join("extra.sqlite").to_s
74
+ ENV["DATABASE_URL__BONUS"] = "sqlite://" + Pathname(@dir).realpath.join("bonus.sqlite").to_s
75
+
76
+ # "extra" gateway in admin slice, same URL as app
77
+ ENV["ADMIN__DATABASE_URL__EXTRA"] = ENV["DATABASE_URL__EXTRA"]
78
+ # "extra" gatway in main slice, different URL
79
+ ENV["MAIN__DATABASE_URL__EXTRA"] = "sqlite://" + Pathname(@dir).realpath.join("extra-main.sqlite").to_s
80
+ # "bonus" gateway in admin slice, same URL as app
81
+ ENV["ADMIN__DATABASE_URL__BONUS"] = ENV["DATABASE_URL__BONUS"]
82
+ # "bonus" gateway in main slice, same URL as app; different connection options in provider
83
+ ENV["MAIN__DATABASE_URL__BONUS"] = ENV["DATABASE_URL__BONUS"]
84
+
85
+ require "hanami/prepare"
86
+
87
+ expect(Admin::Slice["db.gateway"]).to be Hanami.app["db.gateway"]
88
+
89
+ expect(Admin::Slice["db.gateways.extra"]).to be Hanami.app["db.gateways.extra"]
90
+ expect(Main::Slice["db.gateways.extra"]).not_to be Hanami.app["db.gateways.extra"]
91
+
92
+ expect(Admin::Slice["db.gateways.bonus"]).to be Hanami.app["db.gateways.bonus"]
93
+ expect(Main::Slice["db.gateways.bonus"]).not_to be Hanami.app["db.gateways.bonus"]
94
+ end
95
+ end
96
+
35
97
  specify "slices using the same database_url but different extensions have distinct gateways/connections" do
36
98
  with_tmp_directory(@dir = Dir.mktmpdir) do
37
99
  write "config/app.rb", <<~RUBY
@@ -39,6 +101,7 @@ RSpec.describe "DB / Slices", :app_integration do
39
101
 
40
102
  module TestApp
41
103
  class App < Hanami::App
104
+ config.logger.stream = File::NULL
42
105
  end
43
106
  end
44
107
  RUBY
@@ -80,6 +143,7 @@ RSpec.describe "DB / Slices", :app_integration do
80
143
 
81
144
  module TestApp
82
145
  class App < Hanami::App
146
+ config.logger.stream = File::NULL
83
147
  end
84
148
  end
85
149
  RUBY
@@ -213,6 +277,7 @@ RSpec.describe "DB / Slices", :app_integration do
213
277
 
214
278
  module TestApp
215
279
  class App < Hanami::App
280
+ config.logger.stream = File::NULL
216
281
  end
217
282
  end
218
283
  RUBY
@@ -253,6 +318,7 @@ RSpec.describe "DB / Slices", :app_integration do
253
318
 
254
319
  module TestApp
255
320
  class App < Hanami::App
321
+ config.logger.stream = File::NULL
256
322
  end
257
323
  end
258
324
  RUBY
@@ -81,7 +81,48 @@ RSpec.describe "DB / Gateways", :app_integration do
81
81
  end
82
82
  end
83
83
 
84
+ it "configures connection options on their respective gateways" do
85
+ with_tmp_directory(@dir = Dir.mktmpdir) do
86
+ write "config/app.rb", <<~RUBY
87
+ require "hanami"
88
+
89
+ module TestApp
90
+ class App < Hanami::App
91
+ end
92
+ end
93
+ RUBY
94
+
95
+ write "db/.keep", ""
96
+
97
+ write "config/providers/db.rb", <<~RUBY
98
+ Hanami.app.configure_provider :db do
99
+ config.gateway :default do |gw|
100
+ gw.connection_options timeout: 10_000
84
101
 
102
+ gw.adapter :sql do |a|
103
+ a.skip_defaults :extensions
104
+ a.extension :error_sql
105
+ end
106
+ end
107
+
108
+ config.gateway :extra do |gw|
109
+ gw.connection_options readonly: true
110
+ end
111
+ end
112
+ RUBY
113
+
114
+ ENV["DATABASE_URL"] = "sqlite::memory"
115
+ ENV["DATABASE_URL__EXTRA"] = "sqlite::memory"
116
+
117
+ require "hanami/prepare"
118
+
119
+ default = Hanami.app["db.gateways.default"]
120
+ extra = Hanami.app["db.gateways.extra"]
121
+
122
+ expect(default.options).to eq({timeout: 10_000, extensions: [:error_sql]})
123
+ expect(extra.options).to eq({readonly: true, extensions: %i[caller_logging error_sql sql_comments]})
124
+ end
125
+ end
85
126
 
86
127
  it "exposes all database URLs as #database_urls on the provider source (for CLI commands)" do
87
128
  with_tmp_directory(@dir = Dir.mktmpdir) do
@@ -155,7 +196,7 @@ RSpec.describe "DB / Gateways", :app_integration do
155
196
  end
156
197
  end
157
198
 
158
- it "combines ROM plugins from the default adapter and all gateways" do
199
+ it "combines ROM plugins from both default adapter and gateway-configured adapters" do
159
200
  with_tmp_directory(@dir = Dir.mktmpdir) do
160
201
  write "config/app.rb", <<~RUBY
161
202
  require "hanami"
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/operation"
4
+
5
+ RSpec.describe "Operation / Extensions", :app_integration do
6
+ before do
7
+ @env = ENV.to_h
8
+ allow(Hanami::Env).to receive(:loaded?).and_return(false)
9
+ end
10
+
11
+ after { ENV.replace(@env) }
12
+
13
+ specify "Transaction interface is made available automatically" do
14
+ with_tmp_directory(Dir.mktmpdir) do
15
+ write "config/app.rb", <<~RUBY
16
+ require "hanami"
17
+
18
+ module TestApp
19
+ class App < Hanami::App
20
+ end
21
+ end
22
+ RUBY
23
+
24
+ write "app/operation.rb", <<~RUBY
25
+ module TestApp
26
+ class Operation < Dry::Operation
27
+ end
28
+ end
29
+ RUBY
30
+
31
+ write "slices/main/operation.rb", <<~RUBY
32
+ module Main
33
+ class Operation < Dry::Operation
34
+ end
35
+ end
36
+ RUBY
37
+
38
+ write "db/.keep", ""
39
+ write "app/relations/.keep", ""
40
+
41
+ write "slices/main/db/.keep", ""
42
+ write "slices/main/relations/.keep", ""
43
+
44
+ ENV["DATABASE_URL"] = "sqlite::memory"
45
+ ENV["MAIN__DATABASE_URL"] = "sqlite::memory"
46
+
47
+ require "hanami/prepare"
48
+
49
+ app = TestApp::Operation.new
50
+ main = Main::Operation.new
51
+
52
+ expect(app).to respond_to(:transaction)
53
+
54
+ expect(app.rom).to be TestApp::App["db.rom"]
55
+ expect(app.rom).not_to be Main::Slice["db.rom"]
56
+ expect(main.rom).to be Main::Slice["db.rom"]
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/system"
4
+ require "hanami/providers/db"
5
+
6
+ RSpec.describe "Hanami::Providers::DB / Config / Gateway config", :app_integration do
7
+ subject(:config) { provider.source.config }
8
+
9
+ let(:provider) {
10
+ Hanami.app.prepare
11
+ Hanami.app.configure_provider(:db)
12
+ Hanami.app.container.providers[:db]
13
+ }
14
+
15
+ before do
16
+ module TestApp
17
+ class App < Hanami::App
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "sql adapter" do
23
+ before do
24
+ config.adapter(:sql).configure_for_database("sqlite::memory")
25
+ end
26
+
27
+ describe "connection_options" do
28
+ let(:default) { config.gateway(:default) }
29
+
30
+ it "merges kwargs into connection_options configuration" do
31
+ expect { default.connection_options(timeout: 10_000) }
32
+ .to change { default.connection_options }.from({}).to({timeout: 10_000})
33
+ end
34
+
35
+ it "sets options per-gateway" do
36
+ other = config.gateway(:other)
37
+ expect { default.connection_options(timeout: 10_000) }
38
+ .to_not change { other.connection_options }
39
+ end
40
+
41
+ it "is reflected in Gateway#cache_keys" do
42
+ default.adapter(:sql) {}
43
+ expect { default.connection_options(timeout: 10_000) }
44
+ .to change { default.cache_keys }
45
+ end
46
+ end
47
+
48
+ describe "options" do
49
+ it "combines connection_options with adapter.gateway_options" do
50
+ config.gateway :default do |gw|
51
+ gw.connection_options foo: "bar"
52
+
53
+ gw.adapter :sql do |a|
54
+ a.skip_defaults
55
+ a.extension :baz, :quux
56
+ end
57
+ end
58
+
59
+ expect(config.gateway(:default).options)
60
+ .to include(foo: "bar", extensions: [:baz, :quux])
61
+ end
62
+
63
+ it "ignores conflicting keys from connection_options" do
64
+ config.gateway :default do |gw|
65
+ gw.connection_options extensions: "foo"
66
+ gw.adapter(:sql) { _1.skip_defaults }
67
+ end
68
+
69
+ expect(config.gateway(:default).options).to eq({extensions: []})
70
+ end
71
+ end
72
+ end
73
+ end
@@ -32,19 +32,6 @@ RSpec.describe "Hanami::Providers::DB.config", :app_integration do
32
32
  end
33
33
  end
34
34
 
35
- describe "#any_adapter" do
36
- it "adds an adapter keyed without a name" do
37
- expect { config.any_adapter }
38
- .to change { config.adapters.to_h }
39
- .to hash_including(nil)
40
- end
41
-
42
- it "yields the adapter for configuration" do
43
- expect { |b| config.any_adapter(&b) }
44
- .to yield_with_args(an_instance_of(Hanami::Providers::DB::Adapter))
45
- end
46
- end
47
-
48
35
  describe "adapters" do
49
36
  subject(:adapter) { config.adapter(:yaml) }
50
37
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  RSpec.describe "Hanami::VERSION" do
4
4
  it "returns current version" do
5
- expect(Hanami::VERSION).to eq("2.2.0.beta2")
5
+ expect(Hanami::VERSION).to eq("2.2.0")
6
6
  end
7
7
  end
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.2.0.beta2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-25 00:00:00.000000000 Z
11
+ date: 2024-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -132,16 +132,16 @@ dependencies:
132
132
  name: dry-system
133
133
  requirement: !ruby/object:Gem::Requirement
134
134
  requirements:
135
- - - '='
135
+ - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: 1.1.0.beta2
137
+ version: '1.1'
138
138
  type: :runtime
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
- - - '='
142
+ - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: 1.1.0.beta2
144
+ version: '1.1'
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: dry-logger
147
147
  requirement: !ruby/object:Gem::Requirement
@@ -166,30 +166,44 @@ dependencies:
166
166
  name: hanami-cli
167
167
  requirement: !ruby/object:Gem::Requirement
168
168
  requirements:
169
- - - '='
169
+ - - "~>"
170
170
  - !ruby/object:Gem::Version
171
- version: 2.2.0.beta2
171
+ version: '2.2'
172
172
  type: :runtime
173
173
  prerelease: false
174
174
  version_requirements: !ruby/object:Gem::Requirement
175
175
  requirements:
176
- - - '='
176
+ - - "~>"
177
177
  - !ruby/object:Gem::Version
178
- version: 2.2.0.beta2
178
+ version: '2.2'
179
179
  - !ruby/object:Gem::Dependency
180
180
  name: hanami-utils
181
181
  requirement: !ruby/object:Gem::Requirement
182
182
  requirements:
183
183
  - - "~>"
184
184
  - !ruby/object:Gem::Version
185
- version: 2.2.beta
185
+ version: '2.2'
186
186
  type: :runtime
187
187
  prerelease: false
188
188
  version_requirements: !ruby/object:Gem::Requirement
189
189
  requirements:
190
190
  - - "~>"
191
191
  - !ruby/object:Gem::Version
192
- version: 2.2.beta
192
+ version: '2.2'
193
+ - !ruby/object:Gem::Dependency
194
+ name: json
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - ">="
198
+ - !ruby/object:Gem::Version
199
+ version: 2.7.2
200
+ type: :runtime
201
+ prerelease: false
202
+ version_requirements: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: 2.7.2
193
207
  - !ruby/object:Gem::Dependency
194
208
  name: zeitwerk
195
209
  requirement: !ruby/object:Gem::Requirement
@@ -280,6 +294,7 @@ files:
280
294
  - lib/hanami/extensions/action.rb
281
295
  - lib/hanami/extensions/action/slice_configured_action.rb
282
296
  - lib/hanami/extensions/db/repo.rb
297
+ - lib/hanami/extensions/operation.rb
283
298
  - lib/hanami/extensions/router/errors.rb
284
299
  - lib/hanami/extensions/view.rb
285
300
  - lib/hanami/extensions/view/context.rb
@@ -376,6 +391,7 @@ files:
376
391
  - spec/integration/logging/exception_logging_spec.rb
377
392
  - spec/integration/logging/notifications_spec.rb
378
393
  - spec/integration/logging/request_logging_spec.rb
394
+ - spec/integration/operations/extension_spec.rb
379
395
  - spec/integration/rack_app/body_parser_spec.rb
380
396
  - spec/integration/rack_app/method_override_spec.rb
381
397
  - spec/integration/rack_app/middleware_spec.rb
@@ -455,6 +471,7 @@ files:
455
471
  - spec/unit/hanami/helpers/form_helper_spec.rb
456
472
  - spec/unit/hanami/port_spec.rb
457
473
  - spec/unit/hanami/providers/db/config/default_config_spec.rb
474
+ - spec/unit/hanami/providers/db/config/gateway_spec.rb
458
475
  - spec/unit/hanami/providers/db/config_spec.rb
459
476
  - spec/unit/hanami/router/errors/not_allowed_error_spec.rb
460
477
  - spec/unit/hanami/router/errors/not_found_error_spec.rb
@@ -486,7 +503,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
486
503
  - !ruby/object:Gem::Version
487
504
  version: '0'
488
505
  requirements: []
489
- rubygems_version: 3.5.16
506
+ rubygems_version: 3.5.22
490
507
  signing_key:
491
508
  specification_version: 4
492
509
  summary: The web, with simplicity
@@ -535,6 +552,7 @@ test_files:
535
552
  - spec/integration/logging/exception_logging_spec.rb
536
553
  - spec/integration/logging/notifications_spec.rb
537
554
  - spec/integration/logging/request_logging_spec.rb
555
+ - spec/integration/operations/extension_spec.rb
538
556
  - spec/integration/rack_app/body_parser_spec.rb
539
557
  - spec/integration/rack_app/method_override_spec.rb
540
558
  - spec/integration/rack_app/middleware_spec.rb
@@ -614,6 +632,7 @@ test_files:
614
632
  - spec/unit/hanami/helpers/form_helper_spec.rb
615
633
  - spec/unit/hanami/port_spec.rb
616
634
  - spec/unit/hanami/providers/db/config/default_config_spec.rb
635
+ - spec/unit/hanami/providers/db/config/gateway_spec.rb
617
636
  - spec/unit/hanami/providers/db/config_spec.rb
618
637
  - spec/unit/hanami/router/errors/not_allowed_error_spec.rb
619
638
  - spec/unit/hanami/router/errors/not_found_error_spec.rb