Skip to content

Commit

Permalink
Avoid 'last arg as keyword param' warning when building user middleware
Browse files Browse the repository at this point in the history
This change marks the methods which construct user middleware, so they are
called with the 2.6 keyword argument behaviour in 2.7 (and avoid printing a
warning about it).

Some users add their own middleware & write their own constructors with named
parameters, and use keyword arguments when adding their middleware to the
builder:

```
class MyMiddleware < Faraday::Middleware
  def initialize(app, my_argument:)
    @app = app
    @my_argument = my_argument
  end

[...]

connection = Faraday.new() do |configuration|
  configuration.use MyMiddleware, my_argument: 'hello'
end
```

This works great in 2.6 & 2.7, but 2.7 prints a deprecation warning:
```
/Users/danielholz/.gem/ruby/2.7.0/gems/faraday-1.0.1/lib/faraday/dependency_loader.rb:21: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
/Users/danielholz/code/some_project/lib/some_project/faraday_middleware.rb:2: warning: The called method `initialize' is defined here
```
The warning is a bit frustrating, since the calling code is not in the user's
code, so they cannot add `**` to the call. The best option for them is to
change their middleware to accept a Hash as a positional parameter & pass a
Hash when adding their middleware (and checking for required parameters
themselves).

I tried an alternative to `ruby2_keywords` by adding an explicit `**kwargs`
argument to `Faraday::RackBuilder#use`, `Faraday::RackBuilder#use_symbol`,
`Faraday::RackBuilder::Handler#initialize`, and
`Faraday::DependencyLoader#new`, but it hit the explicit delegation of keyword
arguments issue
(https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/#why-deprecated)
in 2.6.
  • Loading branch information
dgholz committed May 1, 2020
1 parent 5547e91 commit 7ae6a33
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 4 deletions.
4 changes: 3 additions & 1 deletion lib/faraday/dependency_loader.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true

def ruby2_keywords(*) end if RUBY_VERSION < '2.7'

module Faraday
# DependencyLoader helps Faraday adapters and middleware load dependencies.
module DependencyLoader
Expand All @@ -13,7 +15,7 @@ def dependency(lib = nil)
self.load_error = e
end

def new(*)
ruby2_keywords def new(*)
unless loaded?
raise "missing dependency for #{self}: #{load_error.message}"
end
Expand Down
8 changes: 5 additions & 3 deletions lib/faraday/rack_builder.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true

def ruby2_keywords(*) end if RUBY_VERSION < '2.7'

require 'faraday/adapter_registry'

module Faraday
Expand Down Expand Up @@ -27,7 +29,7 @@ class Handler

attr_reader :name

def initialize(klass, *args, &block)
ruby2_keywords def initialize(klass, *args, &block)
@name = klass.to_s
REGISTRY.set(klass) if klass.respond_to?(:name)
@args = args
Expand Down Expand Up @@ -89,7 +91,7 @@ def locked?
@handlers.frozen?
end

def use(klass, *args, &block)
ruby2_keywords def use(klass, *args, &block)
if klass.is_a? Symbol
use_symbol(Faraday::Middleware, klass, *args, &block)
else
Expand Down Expand Up @@ -234,7 +236,7 @@ def is_adapter?(klass) # rubocop:disable Naming/PredicateName
klass.ancestors.include?(Faraday::Adapter)
end

def use_symbol(mod, key, *args, &block)
ruby2_keywords def use_symbol(mod, key, *args, &block)
use(mod.lookup_middleware(key), *args, &block)
end

Expand Down
25 changes: 25 additions & 0 deletions spec/faraday/rack_builder_spec.rb
Expand Up @@ -193,4 +193,29 @@ class Broken < Faraday::Middleware
end
end
end

context 'when middleware is added with arguments' do
let(:conn) { Faraday::Connection.new {} }

class Dog < Faraday::Middleware
attr_accessor :name
def initialize(app, name)
super(app)
@name = name
end
end
class Cat < Faraday::Middleware
attr_accessor :name
def initialize(app, name:)
super(app)
@name = name
end
end
it 'adds a handler to construct middleware with options passed to use' do
subject.use Dog, 'Rex'
expect(subject.handlers.find { |handler| handler == Dog }.build.name).to eq('Rex')
subject.use Cat, name: 'Felix'
expect(subject.handlers.find { |handler| handler == Cat }.build.name).to eq('Felix')
end
end
end

0 comments on commit 7ae6a33

Please sign in to comment.