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
Checks 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::AllowedMethods - Included
::RuboCop::Cop::ConfigurableEnforcedStyle - Included
::RuboCop::Cop::Base - Inherited
::RuboCop::Cop::AutocorrectLogic - Included
Instance Method Summary
- #on_block(node) (also: #on_numblock, #on_itblock)
-
#on_csend(node)
Alias for #on_send.
-
#on_itblock(node)
Alias for #on_block.
-
#on_numblock(node)
Alias for #on_block.
- #on_send(node) (also: #on_csend)
- #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
- #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_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
- #single_argument_operator_method?(node) ⇒ Boolean 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, | |
| #arguments_range | A range containing the first to the last argument of a method call or method definition. |
| #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, #ignored_line?, #matches_allowed_pattern?, #matches_ignored_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_gem_version | Returns a gems locked versions (i.e. |
| #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
::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 457
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 484
def array_or_range?(node) node.type?(:array, :range) end
#autocorrect(corrector, node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 215
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 488
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 243
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 429
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 255
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 406
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 410
def braces_required_methods cop_config.fetch('BracesRequiredMethods', []) end
#braces_style?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 439
def braces_style?(node) node.loc.begin.source == '{' end
#correction_would_break_code?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 443
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 331
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 453
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 449
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 349
def get_blocks(node, &block) case node.type when :block, :numblock, :itblock yield node when :send, :csend # 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 414
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 225
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 259
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 307
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, #on_itblock
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 200
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_csend(node)
Alias for #on_send.
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 198
alias on_csend on_send
#on_itblock(node)
Alias for #on_block.
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 211
alias on_itblock on_block
#on_numblock(node)
Alias for #on_block.
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 210
alias on_numblock on_block
#on_send(node) Also known as: #on_csend
[ 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.assignment_method? return if single_argument_operator_method?(node) 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 461
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 374
def proper_block_style?(node) return true if 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 338
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 270
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 286
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_do_end?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 386
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 477
def return_value_of_scope?(node) return false unless (parent = node.parent) parent.conditional? || parent.operator_keyword? || array_or_range?(parent) || parent.children.last == node end
#return_value_used?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 465
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 418
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 233
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
#single_argument_operator_method?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/style/block_delimiters.rb', line 494
def single_argument_operator_method?(node) return false unless node.operator_method? node.arguments.one? && node.first_argument.block_type? end
#source_range_before_comment(range, comment) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/block_delimiters.rb', line 321
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 393
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 399
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 303
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 299
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 344
def with_block?(node) node.respond_to?(:block_node) && node.block_node end