RuboCop::SocketrySourceRuboCopSocketryLayoutBlockDelimiterSpacing

class BlockDelimiterSpacing

A RuboCop cop that enforces consistent spacing before block delimiters.

This cop enforces the following style:

Definitions

def lambda_or_proc?(send_node)

Check if the send node is a lambda or proc (any form)

Implementation

def lambda_or_proc?(send_node)
	return true if send_node.lambda? # stabby lambda: ->{}
	return true if send_node.method_name == :lambda # lambda keyword: lambda{}
	return true if send_node.method_name == :proc # proc keyword: proc{}
	
	# Check for Proc.new{}
	if send_node.method_name == :new && send_node.receiver&.const_type?
		# Check if the receiver is the Proc constant
		receiver = send_node.receiver
		return true if receiver.const_name == :Proc && receiver.children.first.nil?
	end
	
	false
end

def check_no_space_for_lambda(block_node, send_node)

Check that there's no space before the opening brace for lambdas

Implementation

def check_no_space_for_lambda(block_node, send_node)
	brace_begin = block_node.loc.begin
	
	# Find the position just before the brace
	char_before_pos = brace_begin.begin_pos - 1
	
	return if char_before_pos < 0
	
	char_before = processed_source.buffer.source[char_before_pos]
	
	# If there's no space before the brace, we're good
	return unless char_before == " "
	
	# Find the extent of whitespace before the brace
	start_pos = char_before_pos
	while start_pos > 0 && processed_source.buffer.source[start_pos - 1] =~ /\s/
		start_pos -= 1
	end
	
	space_range = Parser::Source::Range.new(
		processed_source.buffer,
		start_pos,
		brace_begin.begin_pos
	)
	
	add_offense(
		space_range,
		message: MSG_REMOVE_SPACE_LAMBDA
	) do |corrector|
		corrector.remove(space_range)
	end
end

def part_of_method_chain?(block_node)

Check if the block is part of a method chain (e.g., foo.bar or foo.bar.baz)

Implementation

def part_of_method_chain?(block_node)
	send_node = block_node.send_node
	parent = block_node.parent
	
	# Check if there's a method call after the block (foo{}.bar)
	has_chained_method_after = parent&.send_type? && parent.receiver == block_node
	
	# Check if the block's receiver exists (foo.bar{} or array.map{})
	# Any method call with a receiver is part of a chain
	has_receiver_before = send_node.receiver
	
	has_chained_method_after || has_receiver_before
end

def has_parentheses?(send_node)

Check if the method call has parentheses

Implementation

def has_parentheses?(send_node)
	send_node.parenthesized?
end

def check_space_after_parentheses(block_node, send_node)

Check that there's a space between closing paren and opening brace

Implementation

def check_space_after_parentheses(block_node, send_node)
	paren_end = send_node.loc.end
	brace_begin = block_node.loc.begin
	
	return unless paren_end && brace_begin
	
	# Get the source between ) and {
	space_range = Parser::Source::Range.new(
		processed_source.buffer,
		paren_end.end_pos,
		brace_begin.begin_pos
	)
	
	space_between = space_range.source
	
	# Should have exactly one space
	return if space_between == " "
	
	if space_between.empty?
		add_offense(
			brace_begin,
			message: MSG_ADD_SPACE
		) do |corrector|
			corrector.insert_before(brace_begin, " ")
		end
	elsif space_between.match?(/\A\s+\z/)
		# Multiple spaces or tabs - replace with single space
		add_offense(
			space_range,
			message: MSG_ADD_SPACE
		) do |corrector|
			corrector.replace(space_range, " ")
		end
	end
end

def check_no_space_before_brace(block_node, send_node)

Check that there's no space before the opening brace

Implementation

def check_no_space_before_brace(block_node, send_node)
	brace_begin = block_node.loc.begin
	
	# Find the position just before the brace
	char_before_pos = brace_begin.begin_pos - 1
	
	return if char_before_pos < 0
	
	char_before = processed_source.buffer.source[char_before_pos]
	
	# If there's a space before the brace, we need to remove it
	return unless char_before == " "
	
	# Don't remove space if it's after a closing paren (that case is handled separately)
	if send_node.loc.end && send_node.loc.end.end_pos == char_before_pos + 1
		return
	end
	
	# Find the extent of whitespace before the brace
	start_pos = char_before_pos
	while start_pos > 0 && processed_source.buffer.source[start_pos - 1] =~ /\s/
		start_pos -= 1
	end
	
	space_range = Parser::Source::Range.new(
		processed_source.buffer,
		start_pos,
		brace_begin.begin_pos
	)
	
	add_offense(
		space_range,
		message: MSG_REMOVE_SPACE
	) do |corrector|
		corrector.remove(space_range)
	end
end

def check_space_before_brace(block_node, send_node)

Check that there's a space before the opening brace (for standalone methods)

Implementation

def check_space_before_brace(block_node, send_node)
	brace_begin = block_node.loc.begin
	
	# Find the position just before the brace
	char_before_pos = brace_begin.begin_pos - 1
	
	return if char_before_pos < 0
	
	char_before = processed_source.buffer.source[char_before_pos]
	
	# If there's already a space, we're good
	return if char_before == " "
	
	# Otherwise, we need to add a space
	add_offense(
		brace_begin,
		message: MSG_ADD_SPACE
	) do |corrector|
		corrector.insert_before(brace_begin, " ")
	end
end