class RuboCop::Cop::Style::BlockDelimiters
Check for uses of braces or do/end around single line or multi-line blocks.
@example EnforcedStyle: line_count_based (default)
# bad - single line block items.each do |item| item / 5 end # good - single line block items.each { |item| item / 5 } # bad - multi-line block things.map { |thing| something = thing.some_method process(something) } # good - multi-line block things.map do |thing| something = thing.some_method process(something) end
@example EnforcedStyle: semantic
# Prefer `do...end` over `{...}` for procedural blocks. # return value is used/assigned # bad foo = map do |x| x end puts (map do |x| x end) # return value is not used out of scope # good map do |x| x end # Prefer `{...}` over `do...end` for functional blocks. # return value is not used out of scope # bad each { |x| x } # return value is used/assigned # good foo = map { |x| x } map { |x| x }.inspect # The AllowBracesOnProceduralOneLiners option is ignored unless the # EnforcedStyle is set to `semantic`. If so: # If the AllowBracesOnProceduralOneLiners option is unspecified, or # set to `false` or any other falsey value, then semantic purity is # maintained, so one-line procedural blocks must use do-end, not # braces. # bad collection.each { |element| puts element } # good collection.each do |element| puts element end # If the AllowBracesOnProceduralOneLiners option is set to `true`, or # any other truthy value, then one-line procedural blocks may use # either style. (There is no setting for requiring braces on them.) # good collection.each { |element| puts element } # also good collection.each do |element| puts element end
@example EnforcedStyle: braces_for_chaining
# bad words.each do |word| word.flip.flop end.join("-") # good words.each { |word| word.flip.flop }.join("-")
@example EnforcedStyle: always_braces
# bad words.each do |word| word.flip.flop end # good words.each { |word| word.flip.flop }
Constants
- ALWAYS_BRACES_MESSAGE
Public Instance Methods
autocorrect(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 135 def autocorrect(node) return if correction_would_break_code?(node) if node.braces? replace_braces_with_do_end(node.loc) else replace_do_end_with_braces(node.loc) end end
on_block(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 129 def on_block(node) return if ignored_node?(node) add_offense(node, location: :begin) unless proper_block_style?(node) end
on_send(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 115 def on_send(node) return unless node.arguments? return if node.parenthesized? || node.operator_method? node.arguments.each do |arg| get_blocks(arg) do |block| # If there are no parentheses around the arguments, then braces # and do-end have different meaning due to how they bind, so we # allow either. ignore_node(block) end end end
Private Instance Methods
array_or_range?(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 324 def array_or_range?(node) node.array_type? || node.range_type? end
braces_for_chaining_message(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 165 def braces_for_chaining_message(node) if node.multiline? if node.chained? 'Prefer `{...}` over `do...end` for multi-line chained blocks.' else 'Prefer `do...end` for multi-line blocks without chaining.' end else 'Prefer `{...}` over `do...end` for single-line blocks.' end end
braces_for_chaining_style?(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 265 def braces_for_chaining_style?(node) block_begin = node.loc.begin.source block_begin == if node.multiline? (node.chained? ? '{' : 'do') else '{' end end
braces_style?(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 275 def braces_style?(node) node.loc.begin.source == '{' end
conditional?(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 320 def conditional?(node) node.if_type? || node.or_type? || node.and_type? end
correction_would_break_code?(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 279 def correction_would_break_code?(node) return unless node.keywords? node.send_node.arguments? && !node.send_node.parenthesized? end
functional_block?(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 289 def functional_block?(node) return_value_used?(node) || return_value_of_scope?(node) end
functional_method?(method_name)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 285 def functional_method?(method_name) cop_config['FunctionalMethods'].map(&:to_sym).include?(method_name) end
get_blocks(node) { |node| ... }
click to toggle source
rubocop:disable Metrics/CyclomaticComplexity
# File lib/rubocop/cop/style/block_delimiters.rb, line 220 def get_blocks(node, &block) case node.type when :block yield node when :send get_blocks(node.receiver, &block) if node.receiver when :hash # A hash which is passed as method argument may have no braces # In that case, one of the K/V pairs could contain a block node # which could change in meaning if do...end replaced {...} return if node.braces? node.each_child_node { |child| get_blocks(child, &block) } when :pair node.each_child_node { |child| get_blocks(child, &block) } end end
line_count_based_block_style?(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 250 def line_count_based_block_style?(node) node.multiline? ^ node.braces? end
line_count_based_message(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 147 def line_count_based_message(node) if node.multiline? 'Avoid using `{...}` for multi-line blocks.' else 'Prefer `{...}` over `do...end` for single-line blocks.' end end
message(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 177 def message(node) case style when :line_count_based then line_count_based_message(node) when :semantic then semantic_message(node) when :braces_for_chaining then braces_for_chaining_message(node) when :always_braces then ALWAYS_BRACES_MESSAGE end end
procedural_method?(method_name)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 297 def procedural_method?(method_name) cop_config['ProceduralMethods'].map(&:to_sym).include?(method_name) end
procedural_oneliners_may_have_braces?()
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 293 def procedural_oneliners_may_have_braces? cop_config['AllowBracesOnProceduralOneLiners'] end
proper_block_style?(node)
click to toggle source
rubocop:enable Metrics/CyclomaticComplexity
# File lib/rubocop/cop/style/block_delimiters.rb, line 239 def proper_block_style?(node) return true if ignored_method?(node.method_name) case style when :line_count_based then line_count_based_block_style?(node) when :semantic then semantic_block_style?(node) when :braces_for_chaining then braces_for_chaining_style?(node) when :always_braces then braces_style?(node) end end
replace_braces_with_do_end(loc)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 186 def replace_braces_with_do_end(loc) b = loc.begin e = loc.end lambda do |corrector| corrector.insert_before(b, ' ') unless whitespace_before?(b) corrector.insert_before(e, ' ') unless whitespace_before?(e) corrector.insert_after(b, ' ') unless whitespace_after?(b) corrector.replace(b, 'do') corrector.replace(e, 'end') end end
replace_do_end_with_braces(loc)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 199 def replace_do_end_with_braces(loc) b = loc.begin e = loc.end lambda do |corrector| corrector.insert_after(b, ' ') unless whitespace_after?(b, 2) corrector.replace(b, '{') corrector.replace(e, '}') end end
return_value_of_scope?(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 313 def return_value_of_scope?(node) return unless node.parent conditional?(node.parent) || array_or_range?(node.parent) || node.parent.children.last == node end
return_value_used?(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 301 def return_value_used?(node) return unless node.parent # If there are parentheses around the block, check if that # is being used. if node.parent.begin_type? return_value_used?(node.parent) else node.parent.assignment? || node.parent.send_type? end end
semantic_block_style?(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 254 def semantic_block_style?(node) method_name = node.method_name if node.braces? functional_method?(method_name) || functional_block?(node) || (procedural_oneliners_may_have_braces? && !node.multiline?) else procedural_method?(method_name) || !return_value_used?(node) end end
semantic_message(node)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 155 def semantic_message(node) block_begin = node.loc.begin.source if block_begin == '{' 'Prefer `do...end` over `{...}` for procedural blocks.' else 'Prefer `{...}` over `do...end` for functional blocks.' end end
whitespace_after?(range, length = 1)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 215 def whitespace_after?(range, length = 1) range.source_buffer.source[range.begin_pos + length, 1] =~ /\s/ end
whitespace_before?(range)
click to toggle source
# File lib/rubocop/cop/style/block_delimiters.rb, line 211 def whitespace_before?(range) range.source_buffer.source[range.begin_pos - 1, 1] =~ /\s/ end