Skip to content

Instantly share code, notes, and snippets.

@tenderlove
Created April 15, 2020 16:52
Show Gist options
  • Save tenderlove/77c738262c2824374e30cb9015b9ef17 to your computer and use it in GitHub Desktop.
Save tenderlove/77c738262c2824374e30cb9015b9ef17 to your computer and use it in GitHub Desktop.

URI.encode deprecations

We're getting these deprecation warnings because URI.encode the method doesn't really makes sense. Paths in URIs are escaped differently than query parameters, and those are escaped differently than anchors (I think). So fixing these warnings isn't always straight forward. We need to think about the context in which the data will be used. Typically I've seen this method used with query parameters, and in that case we should use URI.encode_www_form.

Keyword Argument Deprecations

Ruby is going to start treating hashes and keyword arguments differently in the future. Before now, hashes could be passed as keyword arguments, but in the future that will not be the case.

Keyword argument deprecations warnings always come in two lines. The first line is the caller, and the second line is the recipient.

Hash Literals

Here is an example program that causes the warning:

def kwargs(foo:, bar:)
  "cool"
end

kwargs({foo: true, bar: true})

The warning output will be:

$ ruby thing2.rb
thing2.rb:5: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
thing2.rb:1: warning: The called method `kwargs' is defined here

The first line is the caller. The second line is the recipient. To fix this warning, we need to look at the caller, then look at the method signature of the recipient, then make sure the caller and recipient match. In this case, the caller is passing a hash as keyword parameters. The fix is to remove curly braces and pass keyword args:

def kwargs(foo:, bar:)
  "cool"
end

kwargs(foo: true, bar: true)

Dynamic Parameters

In cases where the parameters are not a hash literal, we need to splat out the keyword args. For example, this program will cause a warning:

def kwargs(foo:, bar:)
  "cool"
end

kwargs({foo: true}.merge({bar: true}))

To fix this warning, we need to splat the parameters out like this:

def kwargs(foo:, bar:)
  "cool"
end

kwargs(**{foo: true}.merge({bar: true}))

Rules for Fixing Keyword Args Warnings

The general rule for fixing keyword arg warnings is to look at the caller, then look at the recipient, then make sure the caller matches the signature of the recipient. In other words, the problem is probably at the callers location, not the recipient. The method signature is almost always right, and most likely the caller is the place that needs to be fixed.

In general, we've seen this warning in 4 situations:

  1. App code calling other app code
  2. App code calling library code
  3. Library code calling in to app code
  4. Library code calling other library code

I'll try to outline general strategies for each situation.

App code calling other app code

This is probably the easiest case, and should be considered a bug in the application. To fix it, look at the caller, look at the recipient, make them match.

App code calling library code

This another case where the bug is in the application. To fix it, look at the caller, look at the recipient (in a gem, probably), make them match.

Library code calling in to app code

This case is a bit harder. We've seen places where library code calls in to application code. For example, Faraday implements self.new with only *. * is only for positional arguments, where ** is for keyword arguments. In the Faraday case, this new method will end up calling in to subclasses that are implemented in the application.

Again, the issue is at the caller (Faraday), and will need to be fixed at the caller's location. Unfortunately, the reason this caller is incorrect is because its method signature is incorrect. Faraday's method signature for new is not compatible with all possible method signatures that subclasses could implement, and the super call implicitly passes the parameters from the method signature.

To eliminate these warnings, we need to fix Faraday, not the app code.

Library code calling other library code

If the warnings are coming from the same library, then we need to apply the "app code calling other app code" rules. Find the caller, find the recipient, make the caller match the recipient. The only thing special about this case is that we'll need to make the change in the upstream library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment