1
0
Fork 0
mirror of https://github.com/thoughtbot/factory_bot.git synced 2022-11-09 11:43:51 -05:00

Fix ruby 2.7 kwargs warning

Ruby 2.7 deprecated passing kwargs when the method expects a hash or passing a hash when the method expects kwargs. In factory_bot, this creates the warning:

```
/Users/hparker/code/factory_bot/lib/factory_bot/decorator/new_constructor.rb:9: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
/Users/hparker/code/factory_bot/spec/acceptance/initialize_with_spec.rb:220: warning: The called method `initialize' is defined here
```

We can fix this warning by updating the syntax. We need to include `**kwargs` in the `method_missing` calls when we are on ruby 2.7 or later.
In decorator.rb, adding `**kwargs` alone doesn't work since adding `**kwargs` can change what arguments remain in the `args`.

In this case we have to class eval the method if we are running ruby 2.7. This way the syntax is valid in previous versions and we can use the `...` operator which allows us to avoid changing the arguments passed on in method missing.

Co-authored-by: Lee Quarella <leequarella@gmail.com>
This commit is contained in:
Adam Hess 2020-06-23 09:54:55 -07:00 committed by Daniel Colson
parent 468536ff65
commit 5c071d42fd
4 changed files with 45 additions and 16 deletions

View file

@ -6,18 +6,30 @@ module FactoryBot
@component = component
end
def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissingSuper
@component.send(name, *args, &block)
if ::Gem::Version.new(::RUBY_VERSION) >= ::Gem::Version.new("2.7")
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
def method_missing(...) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
@component.send(...)
end
def send(...)
__send__(...)
end
RUBY
else
def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
@component.send(name, *args, &block)
end
def send(symbol, *args, &block)
__send__(symbol, *args, &block)
end
end
def respond_to_missing?(name, include_private = false)
@component.respond_to?(name, true) || super
end
def send(symbol, *args, &block)
__send__(symbol, *args, &block)
end
def self.const_missing(name)
::Object.const_get(name)
end

View file

@ -6,9 +6,16 @@ module FactoryBot
@invoked_methods = []
end
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
@invoked_methods << name
super
if ::Gem::Version.new(::RUBY_VERSION) >= ::Gem::Version.new("2.7")
def method_missing(name, *args, **kwargs, &block) # rubocop:disable Style/MissingRespondToMissing
@invoked_methods << name
super
end
else
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
@invoked_methods << name
super
end
end
def __invoked_methods__

View file

@ -35,11 +35,21 @@ module FactoryBot
attr_writer :instance
def method_missing(method_name, *args, &block) # rubocop:disable Style/MethodMissingSuper
if @instance.respond_to?(method_name)
@instance.send(method_name, *args, &block)
else
SyntaxRunner.new.send(method_name, *args, &block)
if ::Gem::Version.new(::RUBY_VERSION) >= ::Gem::Version.new("2.7")
def method_missing(method_name, *args, **kwargs, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
if @instance.respond_to?(method_name)
@instance.send(method_name, *args, **kwargs, &block)
else
SyntaxRunner.new.send(method_name, *args, **kwargs, &block)
end
end
else
def method_missing(method_name, *args, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
if @instance.respond_to?(method_name)
@instance.send(method_name, *args, &block)
else
SyntaxRunner.new.send(method_name, *args, &block)
end
end
end

View file

@ -201,7 +201,7 @@ describe "initialize_with has access to all attributes for construction" do
name { email.gsub(/@.+/, "") }
initialize_with { new(attributes) }
initialize_with { new(**attributes) }
end
end
@ -225,7 +225,7 @@ describe "initialize_with with an 'attributes' attribute" do
FactoryBot.define do
factory :user do
attributes { {name: "Daniel"} }
initialize_with { new(attributes) }
initialize_with { new(**attributes) }
end
end