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
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
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
The expected behavior problem shows how to reproduce the problem.
$ rubocop -V
0.51.0
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))
Most helpful comment
It's another question entirely if using
tapfor a single expression is a good idea. 馃槈 I was planning at some point adding a cop for that. With an option do discouragetapcompletely as well. I've yet to find code that becomes more readable because oftap.