Class: RuboCop::Cop::Style::FileOpen

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/style/file_open.rb

Overview

Checks for File.open without a block, which can leak file descriptors.

When File.open is called without a block, the caller is responsible for closing the file descriptor. If it is not explicitly closed, it will only be closed when the garbage collector runs, which may lead to resource exhaustion. Using the block form ensures the file is automatically closed when the block exits.

This cop only registers an offense when the result of File.open is assigned to a variable or has a method chained on it, as those are the clearest indicators that the block form should be used instead. When File.open is used as a return value or passed as an argument, the caller is likely managing the file descriptor intentionally.

Examples:

# bad
f = File.open('file')

# bad
File.open('file').read

# good
File.open('file') do |f|
  f.read
end

# good
File.open('file', &:read)

# good - pass an open file object to an API that manages its lifecycle
process(io: File.open('file'))

# good - return an open file object for the caller to manage
def json_key_io
  File.open('file')
end

# good - use File.read for one-shot reads
File.read('file')

Constant Summary collapse

MSG =
'`File.open` without a block may leak a file descriptor; use the block form.'
RESTRICT_ON_SEND =
i[open].freeze

Instance Attribute Summary

Attributes inherited from Base

#config, #processed_source

Instance Method Summary collapse

Methods inherited from Base

#active_support_extensions_enabled?, #add_global_offense, #add_offense, #always_autocorrect?, autocorrect_incompatible_with, badge, #begin_investigation, #callbacks_needed, callbacks_needed, #config_to_allow_offenses, #config_to_allow_offenses=, #contextual_autocorrect?, #cop_config, #cop_name, cop_name, department, documentation_url, exclude_from_registry, #excluded_file?, #external_dependency_checksum, inherited, #initialize, #inspect, joining_forces, lint?, match?, #message, #offenses, #on_investigation_end, #on_new_investigation, #on_other_file, #parse, #parser_engine, #ready, #relevant_file?, requires_gem, #string_literals_frozen_by_default?, support_autocorrect?, support_multiple_source?, #target_gem_version, #target_rails_version, #target_ruby_version

Methods included from ExcludeLimit

#exclude_limit

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #autocorrect_with_disable_uncorrectable?, #correctable?, #disable_uncorrectable?, #safe_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

silence_warnings

Constructor Details

This class inherits a constructor from RuboCop::Cop::Base

Instance Method Details

#file_open?(node) ⇒ Object



57
58
59
# File 'lib/rubocop/cop/style/file_open.rb', line 57

def_node_matcher :file_open?, "(send (const {nil? cbase} :File) :open ...)\n"

#on_send(node) ⇒ Object Also known as: on_csend



61
62
63
64
65
66
67
# File 'lib/rubocop/cop/style/file_open.rb', line 61

def on_send(node)
  return unless file_open?(node)
  return if node.block_argument?
  return unless offensive_usage?(node)

  add_offense(node)
end