Rubocop: Style/SymbolProc gives bad advice for Object#tap

Created on 23 Nov 2017  路  5Comments  路  Source: rubocop-hq/rubocop

In code where Object#tap is passed a block containing a single, no-argument method, the Style/SymbolProc cop reports the following offense:

Style/SymbolProc: Pass &:method as an argument to tap instead of a block.

Since Object#tap does not support a single, non-block argument, this advice can not be followed.

The workaround is to include the following in the .rubocop.yml:

Style/SymbolProc:
  IgnoredMethods:
    - tap

Expected behavior

Given a ruby file called 'test.rb' containing
  """
    #!/usr/bin/env ruby

    # ShellOut knows how to run command line commands
    #
    class ShellOut
      def initialize(_command)
        # stub for initialize
      end

      def run_command
        # stub for run_command
        self
      end

      def error!
        # error! raises an exception if there was an error
        # otherwise it returns nil
        nil
      end

      def stdout
        "file1.txt\nfile2.txt\n"
      end
    end

    output = ShellOut.new('ls').run_command.tap { |c| c.error! }.stdout

    puts output
  """
When I run "rubocop test.rb"
Then 0 offenses should be detected

Actual behavior

With Rubocop 0.51.0, rubocop returns the following:

$ rubocop test.rb
Inspecting 1 file
C

Offenses:

test.rb:26:45: C: Style/SymbolProc: Pass &:error! as an argument to tap instead of a block.
output = ShellOut.new('ls').run_command.tap { |c| c.error! }.stdout
                                            ^^^^^^^^^^^^^^^^

1 file inspected, 1 offense detected

Steps to reproduce the problem

The expected behavior problem shows how to reproduce the problem.

RuboCop version

$ rubocop -V
0.51.0

Most helpful comment

It's another question entirely if using tap for a single expression is a good idea. 馃槈 I was planning at some point adding a cop for that. With an option do discourage tap completely as well. I've yet to find code that becomes more readable because of tap.

All 5 comments

Since Object#tap does not support a single, non-block argument, this advice can not be followed.

It seems supported.

p 'a'.tap { |c| c.upcase! } # => "A"
p 'a'.tap(&:upcase!)  # => "A"

Since Object#tap does not support a single, non-block argument, this advice can not be followed.

&:error! is a block argument. (& is block coercion in Ruby.) 馃檪

It's another question entirely if using tap for a single expression is a good idea. 馃槈 I was planning at some point adding a cop for that. With an option do discourage tap completely as well. I've yet to find code that becomes more readable because of tap.

@pocke, @drenmi, and @bbatsov

Thank you for pointing out what I missed. I appreciate it.

It seems Style/SymbolProc fits not always. I use rest-client and it has two options for making requests, for example:

> RestClient.get('http://example.com/not-found') 
Traceback (most recent call last):
       13: from /usr/local/bundle/bin/racksh:23:in `<main>'
       12: from /usr/local/bundle/bin/racksh:23:in `load'
       11: from /usr/local/bundle/gems/racksh-1.0.0/bin/racksh:21:in `<top (required)>'
       10: from (irb):14
        9: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient.rb:67:in `get'
        8: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/request.rb:52:in `execute'
        7: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/request.rb:145:in `execute'
        6: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/request.rb:715:in `transmit'
        5: from /usr/local/lib/ruby/2.5.0/net/http.rb:910:in `start'
        4: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/request.rb:725:in `block in transmit'
        3: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/request.rb:809:in `process_result'
        2: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/abstract_response.rb:103:in `return!'
        1: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/abstract_response.rb:223:in `exception_with_response'
RestClient::NotFound (404 Not Found)

and

> RestClient.get('http://example.com/not-found') { |response| response.body }
=> "<!doctype html>\n<html>\n<head>\n    <title>Example Domain</title>\n\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <style type=\"text/css\">\n    body {\n        background-color: #f0f0f2;\n        margin: 0;\n        padding: 0;\n        font-family: \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n        \n    }\n    div {\n        width: 600px;\n        margin: 5em auto;\n        padding: 50px;\n        background-color: #fff;\n        border-radius: 1em;\n    }\n    a:link, a:visited {\n        color: #38488f;\n        text-decoration: none;\n    }\n    @media (max-width: 700px) {\n        body {\n            background-color: #fff;\n        }\n        div {\n            width: auto;\n            margin: 0 auto;\n            border-radius: 0;\n            padding: 1em;\n        }\n    }\n    </style>    \n</head>\n\n<body>\n<div>\n    <h1>Example Domain</h1>\n    <p>This domain is established to be used for illustrative examples in documents. You may use this\n    domain in examples without prior coordination or asking for permission.</p>\n    <p><a href=\"http://www.iana.org/domains/example\">More information...</a></p>\n</div>\n</body>\n</html>\n"

Here is details. So advise Style/SymbolProc: Pass &:body as an argument to get instead of a block. gives the error like:

> RestClient.get('http://example.com/not-found', &:body)
Traceback (most recent call last):
       12: from /usr/local/bundle/bin/racksh:23:in `<main>'
       11: from /usr/local/bundle/bin/racksh:23:in `load'
       10: from /usr/local/bundle/gems/racksh-1.0.0/bin/racksh:21:in `<top (required)>'
        9: from (irb):16
        8: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient.rb:67:in `get'
        7: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/request.rb:52:in `execute'
        6: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/request.rb:145:in `execute'
        5: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/request.rb:715:in `transmit'
        4: from /usr/local/lib/ruby/2.5.0/net/http.rb:910:in `start'
        3: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/request.rb:725:in `block in transmit'
        2: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/request.rb:807:in `process_result'
        1: from /usr/local/bundle/gems/rest-client-2.0.2/lib/restclient/response.rb:16:in `body'
ArgumentError (wrong number of arguments (given 2, expected 0))

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lepieru picture lepieru  路  3Comments

david942j picture david942j  路  3Comments

NobodysNightmare picture NobodysNightmare  路  3Comments

kirrmann picture kirrmann  路  3Comments

AndreiMotinga picture AndreiMotinga  路  3Comments