Class: RuboCop::Cop::Style::BlockDelimiters
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
::RuboCop::Cop::AutoCorrector ,
::RuboCop::Cop::Base ,
::RuboCop::ExcludeLimit ,
NodePattern::Macros,
RuboCop::AST::Sexp
|
|
Instance Chain:
|
|
Inherits: |
RuboCop::Cop::Base
|
Defined in: | lib/rubocop/cop/style/block_delimiters.rb |
Overview
Check for uses of braces or do/end around single line or multi-line blocks.
Methods that can be either procedural or functional and cannot be
categorised from their usage alone is ignored.
lambda
, proc
, and it
are their defaults.
Additional methods can be added to the ::RuboCop::Cop::AllowedMethods
.
Constant Summary
-
ALWAYS_BRACES_MESSAGE =
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 175'Prefer `{...}` over `do...end` for blocks.'
-
BRACES_REQUIRED_MESSAGE =
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 177"Brace delimiters `{...}` required for '%<method_name>s' method."
::RuboCop::Cop::Base
- Inherited
EMPTY_OFFENSES, RESTRICT_ON_SEND
::RuboCop::Cop::ConfigurableEnforcedStyle
- Included
::RuboCop::Cop::RangeHelp
- Included
Class Attribute Summary
::RuboCop::Cop::AutoCorrector
- Extended
::RuboCop::Cop::Base
- Inherited
.gem_requirements, .lint?, | |
.support_autocorrect? | Returns if class supports autocorrect. |
.support_multiple_source? | Override if your cop should be called repeatedly for multiple investigations Between calls to |
Class Method Summary
::RuboCop::Cop::Base
- Inherited
.autocorrect_incompatible_with | List of cops that should not try to autocorrect at the same time as this cop. |
.badge | Naming. |
.callbacks_needed, .cop_name, .department, | |
.documentation_url | Returns a url to view this cops documentation online. |
.exclude_from_registry | Call for abstract Cop classes. |
.inherited, | |
.joining_forces | Override and return the Force class(es) you need to join. |
.match? | Returns true if the cop name or the cop namespace matches any of the given names. |
.new, | |
.requires_gem | Register a version requirement for the given gem name. |
.restrict_on_send |
::RuboCop::ExcludeLimit
- Extended
exclude_limit | Sets up a configuration option to have an exclude limit tracked. |
transform |
Instance Attribute Summary
- #procedural_oneliners_may_have_braces? ⇒ Boolean readonly private
::RuboCop::Cop::AllowedPattern
- Included
::RuboCop::Cop::AllowedMethods
- Included
::RuboCop::Cop::ConfigurableEnforcedStyle
- Included
::RuboCop::Cop::Base
- Inherited
::RuboCop::Cop::AutocorrectLogic
- Included
Instance Method Summary
- #on_block(node) (also: #on_numblock)
-
#on_numblock(node)
Alias for #on_block.
- #on_send(node)
- #array_or_range?(node) ⇒ Boolean private
- #autocorrect(corrector, node) private
- #begin_required?(block_node) ⇒ Boolean private
- #braces_for_chaining_message(node) private
- #braces_for_chaining_style?(node) ⇒ Boolean private
- #braces_required_message(node) private
- #braces_required_method?(method_name) ⇒ Boolean private
- #braces_required_methods private
- #braces_style?(node) ⇒ Boolean private
- #conditional?(node) ⇒ Boolean private
- #correction_would_break_code?(node) ⇒ Boolean private
- #end_of_chain(node) private
- #functional_block?(node) ⇒ Boolean private
- #functional_method?(method_name) ⇒ Boolean private
- #get_blocks(node, &block) private
- #line_count_based_block_style?(node) ⇒ Boolean private
- #line_count_based_message(node) private
- #message(node) private
- #move_comment_before_block(corrector, comment, block_node, closing_brace) private
- #procedural_method?(method_name) ⇒ Boolean private
- #proper_block_style?(node) ⇒ Boolean private
- #remove_trailing_whitespace(corrector, range, comment) private
- #replace_braces_with_do_end(corrector, loc) private
- #replace_do_end_with_braces(corrector, node) private
- #require_braces?(node) ⇒ Boolean private
- #require_do_end?(node) ⇒ Boolean private
- #return_value_of_scope?(node) ⇒ Boolean private
- #return_value_used?(node) ⇒ Boolean private
- #semantic_block_style?(node) ⇒ Boolean private
- #semantic_message(node) private
- #source_range_before_comment(range, comment) private
- #special_method?(method_name) ⇒ Boolean private
- #special_method_proper_block_style?(node) ⇒ Boolean private
- #whitespace_after?(range, length = 1) ⇒ Boolean private
- #whitespace_before?(range) ⇒ Boolean private
- #with_block?(node) ⇒ Boolean private
::RuboCop::Cop::RangeHelp
- Included
#add_range, #column_offset_between, | |
#contents_range | A range containing only the contents of a literal with delimiters (e.g. |
#directions, | |
#effective_column | Returns the column attribute of the range, except if the range is on the first line and there’s a byte order mark at the beginning of that line, in which case 1 is subtracted from the column value. |
#final_pos, #move_pos, #move_pos_str, #range_between, #range_by_whole_lines, #range_with_comments, #range_with_comments_and_lines, #range_with_surrounding_comma, #range_with_surrounding_space, #source_range |
::RuboCop::Cop::AllowedPattern
- Included
#allowed_line?, #allowed_patterns, #cop_config_deprecated_methods_values, #cop_config_patterns_values, #matches_allowed_pattern? |
::RuboCop::Cop::AllowedMethods
- Included
::RuboCop::Cop::ConfigurableEnforcedStyle
- Included
::RuboCop::Cop::Base
- Inherited
#add_global_offense | Adds an offense that has no particular location. |
#add_offense | Adds an offense on the specified range (or node with an expression) Unless that offense is disabled for this range, a corrector will be yielded to provide the cop the opportunity to autocorrect the offense. |
#begin_investigation | Called before any investigation. |
#callbacks_needed, | |
#cop_config | Configuration Helpers. |
#cop_name, #excluded_file?, | |
#external_dependency_checksum | This method should be overridden when a cop’s behavior depends on state that lives outside of these locations: |
#inspect, | |
#message | Gets called if no message is specified when calling |
#name | Alias for Base#cop_name. |
#offenses, | |
#on_investigation_end | Called after all on_… |
#on_new_investigation | Called before all on_… |
#on_other_file | Called instead of all on_… |
#parse | There should be very limited reasons for a Cop to do it’s own parsing. |
#parser_engine, | |
#ready | Called between investigations. |
#relevant_file?, #target_rails_version, #target_ruby_version, #annotate, #apply_correction, #attempt_correction, | |
#callback_argument | Reserved for Cop::Cop. |
#complete_investigation | Called to complete an investigation. |
#correct, #current_corrector, | |
#current_offense_locations | Reserved for Commissioner: |
#current_offenses, #currently_disabled_lines, #custom_severity, #default_severity, #disable_uncorrectable, #enabled_line?, #file_name_matches_any?, #find_message, #find_severity, #range_for_original, #range_from_node_or_range, | |
#reset_investigation | Actually private methods. |
#use_corrector |
::RuboCop::Cop::AutocorrectLogic
- Included
#disable_offense, #disable_offense_at_end_of_line, #disable_offense_before_and_after, #disable_offense_with_eol_or_surround_comment, #max_line_length, | |
#range_by_lines | Expand the given range to include all of any lines it covers. |
#range_of_first_line, #range_overlaps_offense?, #string_continuation, #string_continuation?, #surrounding_heredoc, #surrounding_percent_array |
::RuboCop::Cop::IgnoredNode
- Included
Constructor Details
This class inherits a constructor from RuboCop::Cop::Base
Class Method Details
.autocorrect_incompatible_with
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 179
def self.autocorrect_incompatible_with [Style::RedundantBegin] end
Instance Attribute Details
#procedural_oneliners_may_have_braces? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 464
def procedural_oneliners_may_have_braces? cop_config['AllowBracesOnProceduralOneLiners'] end
Instance Method Details
#array_or_range?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 495
def array_or_range?(node) node.array_type? || node.range_type? end
#autocorrect(corrector, node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 212
def autocorrect(corrector, node) return if correction_would_break_code?(node) if node.braces? replace_braces_with_do_end(corrector, node.loc) else replace_do_end_with_braces(corrector, node) end end
#begin_required?(block_node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 499
def begin_required?(block_node) # If the block contains `rescue` or `ensure`, it needs to be wrapped in # `begin`...`end` when changing `do-end` to `{}`. block_node.each_child_node(:rescue, :ensure).any? && !block_node.single_line? end
#braces_for_chaining_message(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 240
def (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) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 436
def braces_for_chaining_style?(node) block_begin = node.loc.begin.source block_begin == if node.multiline? (node.chained? ? '{' : 'do') else '{' end end
#braces_required_message(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 252
def (node) format(BRACES_REQUIRED_MESSAGE, method_name: node.method_name.to_s) end
#braces_required_method?(method_name) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 413
def braces_required_method?(method_name) braces_required_methods.include?(method_name.to_s) end
#braces_required_methods (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 417
def braces_required_methods cop_config.fetch('BracesRequiredMethods', []) end
#braces_style?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 446
def braces_style?(node) node.loc.begin.source == '{' end
#conditional?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 491
def conditional?(node) node.if_type? || node.operator_keyword? end
#correction_would_break_code?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 450
def correction_would_break_code?(node) return false unless node.keywords? node.send_node.arguments? && !node.send_node.parenthesized? end
#end_of_chain(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 328
def end_of_chain(node) return end_of_chain(node.block_node) if with_block?(node) return node unless node.chained? end_of_chain(node.parent) end
#functional_block?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 460
def functional_block?(node) return_value_used?(node) || return_value_of_scope?(node) end
#functional_method?(method_name) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 456
def functional_method?(method_name) cop_config['FunctionalMethods'].map(&:to_sym).include?(method_name) end
#get_blocks(node, &block) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 346
def get_blocks(node, &block) case node.type when :block, :numblock yield node when :send # When a method has an argument which is another method with a block, # that block needs braces, otherwise a syntax error will be introduced # for subsequent arguments. # Additionally, even without additional arguments, changing `{...}` to # `do...end` will change the binding of the block to the outer method. get_blocks(node.receiver, &block) if node.receiver node.arguments.each { |argument| get_blocks(argument, &block) } 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` is replaced with `{...}` 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) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 421
def line_count_based_block_style?(node) node.multiline? ^ node.braces? end
#line_count_based_message(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 222
def (node) if node.multiline? 'Avoid using `{...}` for multi-line blocks.' else 'Prefer `{...}` over `do...end` for single-line blocks.' end end
#message(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 256
def (node) return (node) if braces_required_method?(node.method_name) case style when :line_count_based then (node) when :semantic then (node) when :braces_for_chaining then (node) when :always_braces then ALWAYS_BRACES_MESSAGE end end
#move_comment_before_block(corrector, comment, block_node, closing_brace) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 304
def move_comment_before_block(corrector, comment, block_node, closing_brace) range = block_node.chained? ? end_of_chain(block_node.parent).source_range : closing_brace # It is possible that there is code between the block and the comment # which needs to be preserved and trimmed. pre_comment_range = source_range_before_comment(range, comment) corrector.remove(range_with_surrounding_space(comment.source_range, side: :right)) remove_trailing_whitespace(corrector, pre_comment_range, comment) corrector.insert_after(pre_comment_range, "\n") corrector.insert_before(block_node, "#{comment.text}\n") end
#on_block(node) Also known as: #on_numblock
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 198
def on_block(node) return if ignored_node?(node) return if proper_block_style?(node) = (node) add_offense(node.loc.begin, message: ) do |corrector| autocorrect(corrector, node) end end
#on_numblock(node)
Alias for #on_block.
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 208
alias on_numblock on_block
#on_send(node)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 183
def on_send(node) return unless node.arguments? return if node.parenthesized? return if node.operator_method? || node.assignment_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
#procedural_method?(method_name) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 468
def procedural_method?(method_name) cop_config['ProceduralMethods'].map(&:to_sym).include?(method_name) end
#proper_block_style?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 372
def proper_block_style?(node) return true if require_braces?(node) || require_do_end?(node) return special_method_proper_block_style?(node) if special_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
#remove_trailing_whitespace(corrector, range, comment) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 335
def remove_trailing_whitespace(corrector, range, comment) range_of_trailing = range.end.join(comment.source_range.begin) corrector.remove(range_of_trailing) if range_of_trailing.source.match?(/\A\s+\z/) end
#replace_braces_with_do_end(corrector, loc) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 267
def replace_braces_with_do_end(corrector, loc) b = loc.begin e = loc.end 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') if (comment = processed_source.comment_at_line(e.line)) move_comment_before_block(corrector, comment, loc.node, e) end corrector.replace(e, 'end') end
#replace_do_end_with_braces(corrector, node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 283
def replace_do_end_with_braces(corrector, node) loc = node.loc b = loc.begin e = loc.end corrector.insert_after(b, ' ') unless whitespace_after?(b, 2) corrector.replace(b, '{') corrector.replace(e, '}') corrector.wrap(node.body, "begin\n", "\nend") if begin_required?(node) end
#require_braces?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 385
def require_braces?(node) return false unless node.braces? node.each_ancestor(:send).any? do |send| send.arithmetic_operation? && node.source_range.end_pos < send.loc.selector.begin_pos end end
#require_do_end?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 393
def require_do_end?(node) return false if node.braces? || node.multiline? return false unless (resbody = node.each_descendant(:resbody).first) resbody.children.first&.array_type? end
#return_value_of_scope?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 484
def return_value_of_scope?(node) return false unless node.parent conditional?(node.parent) || array_or_range?(node.parent) || node.parent.children.last == node end
#return_value_used?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 472
def return_value_used?(node) return false 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.call_type? end end
#semantic_block_style?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 425
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) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 230
def (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
#source_range_before_comment(range, comment) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 318
def source_range_before_comment(range, comment) range = range.end.join(comment.source_range.begin) # End the range before any whitespace that precedes the comment trailing_whitespace_count = range.source[/\s+\z/]&.length range = range.adjust(end_pos: -trailing_whitespace_count) if trailing_whitespace_count range end
#special_method?(method_name) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 400
def special_method?(method_name) allowed_method?(method_name) || matches_allowed_pattern?(method_name) || braces_required_method?(method_name) end
#special_method_proper_block_style?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 406
def special_method_proper_block_style?(node) method_name = node.method_name return true if allowed_method?(method_name) || matches_allowed_pattern?(method_name) node.braces? if braces_required_method?(method_name) end
#whitespace_after?(range, length = 1) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 300
def whitespace_after?(range, length = 1) /\s/.match?(range.source_buffer.source[range.begin_pos + length, 1]) end
#whitespace_before?(range) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 296
def whitespace_before?(range) /\s/.match?(range.source_buffer.source[range.begin_pos - 1, 1]) end
#with_block?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 341
def with_block?(node) node.respond_to?(:block_node) && node.block_node end