How to pass &:read as argument to File.open as indicated by Rubocop

Viewed 752

I have this code

File.open(file_name, 'r') { |file| file.read }

but Rubocop is warning:

Offenses:

Style/SymbolProc: Pass &:read as argument to open instead of a block.

How do you do this?

3 Answers

I just created a file named "t.txt" that contains "Hello, World\n". We can read that as follows.

File.open('t.txt', 'r', &:read)
  #=> "Hello, World\n"

Incidentally, as the default of the second argument is 'r', it suffices to write:

File.open('t.txt', &:read)

Here's another example:

"This is A Test".gsub('i', &:upcase)
  #=> "ThIs Is A Test" 

In other words, include the proc (e.g., &:read) as the last argument.

File.open(file_name, 'r', &:read)

Rubocop wants you to use the 'symbol to proc' feature in Ruby instead of defining a complete block. This is purely stylistic, and doesn't affect the code execution. You can find it in the Rubocop style guide.

You can look up the offense in RuboCop's docs, e.g. Style/SymbolProc – it usually shows a "bad" and a "good" example:

# bad
something.map { |s| s.upcase }

# good
something.map(&:upcase)

If this doesn't help, you can have RuboCop auto-correct the offense (for cops supporting auto-correction like this one).

Given a file test.rb:

# frozen_string_literal: true

File.open(file_name, 'r') { |file| file.read }

Run rubocop -a: (the actual output depends on your config)

$ rubocop -a test.rb
Inspecting 1 file
C

Offenses:

test.rb:3:27: C: [Corrected] Style/SymbolProc: Pass &:read as an argument to open instead of a block.
File.open(file_name, 'r') { |file| file.read }
                          ^^^^^^^^^^^^^^^^^^^^

1 file inspected, 1 offense detected, 1 offense corrected

And test.rb will become:

# frozen_string_literal: true

File.open(file_name, 'r', &:read)
Related