Class: RuboCop::Cop::Style::HashSyntax
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/hash_syntax.rb |
Overview
Checks hash literal syntax.
It can enforce either the use of the class hash rocket syntax or the use of the newer Ruby 1.9 syntax (when applicable).
A separate offense is registered for each problematic pair.
The supported styles are:
-
ruby19 - forces use of the 1.9 syntax (e.g.
{a: 1}
) when hashes have all symbols for keys -
hash_rockets - forces use of hash rockets for all hashes
-
no_mixed_keys - simply checks for hashes with mixed syntaxes
-
ruby19_no_mixed_keys - forces use of ruby 1.9 syntax and forbids mixed syntax hashes
This cop has EnforcedShorthandSyntax
option.
It can enforce either the use of the explicit hash value syntax or
the use of Ruby 3.1’s hash value shorthand syntax.
The supported styles are:
-
always - forces use of the 3.1 syntax (e.g.
foo:
) -
never - forces use of explicit hash literal value
-
either - accepts both shorthand and explicit use of hash literal value
-
consistent - forces use of the 3.1 syntax only if all values can be omitted in the hash
Constant Summary
-
MSG_19 =
# File 'lib/rubocop/cop/style/hash_syntax.rb', line 119'Use the new Ruby 1.9 hash syntax.'
-
MSG_HASH_ROCKETS =
# File 'lib/rubocop/cop/style/hash_syntax.rb', line 121'Use hash rockets syntax.'
-
MSG_NO_MIXED_KEYS =
# File 'lib/rubocop/cop/style/hash_syntax.rb', line 120"Don't mix styles in the same hash."
::RuboCop::Cop::Base
- Inherited
EMPTY_OFFENSES, RESTRICT_ON_SEND
::RuboCop::Cop::ConfigurableEnforcedStyle
- Included
::RuboCop::Cop::HashShorthandSyntax
- Included
DO_NOT_MIX_EXPLICIT_VALUE_MSG, DO_NOT_MIX_MSG_PREFIX, DO_NOT_MIX_OMIT_VALUE_MSG, EXPLICIT_HASH_VALUE_MSG, OMIT_HASH_VALUE_MSG
::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 |
.builtin? |
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 | Cops (other than builtin) are encouraged to implement this. |
.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
::RuboCop::Cop::ConfigurableEnforcedStyle
- Included
::RuboCop::Cop::Base
- Inherited
::RuboCop::Cop::AutocorrectLogic
- Included
Instance Method Summary
- #alternative_style
- #hash_rockets_check(pairs)
- #no_mixed_keys_check(pairs)
- #on_hash(node)
- #ruby19_check(pairs)
- #ruby19_no_mixed_keys_check(pairs)
- #acceptable_19_syntax_symbol?(sym_name) ⇒ Boolean private
- #argument_without_space?(node) ⇒ Boolean private
- #autocorrect(corrector, node) private
- #autocorrect_hash_rockets(corrector, pair_node) private
- #autocorrect_no_mixed_keys(corrector, pair_node) private
- #autocorrect_ruby19(corrector, pair_node) private
- #check(pairs, delim, msg) private
- #force_hash_rockets?(pairs) ⇒ Boolean private
- #range_for_autocorrect_ruby19(pair_node) private
- #sym_indices?(pairs) ⇒ Boolean private
- #word_symbol_pair?(pair) ⇒ 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::HashShorthandSyntax
- 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, #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, #surrounding_heredoc, #surrounding_percent_array |
::RuboCop::Cop::IgnoredNode
- Included
Constructor Details
This class inherits a constructor from RuboCop::Cop::Base
Instance Method Details
#acceptable_19_syntax_symbol?(sym_name) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/hash_syntax.rb', line 199
def acceptable_19_syntax_symbol?(sym_name) sym_name.delete_prefix!(':') if cop_config['PreferHashRocketsForNonAlnumEndingSymbols'] && # Prefer { :production? => false } over { production?: false } and # similarly for other non-alnum final characters (except quotes, # to prefer { "x y": 1 } over { :"x y" => 1 }). !/[\p{Alnum}"']\z/.match?(sym_name) return false end # Most hash keys can be matched against a simple regex. return true if /\A[_a-z]\w*[?!]?\z/i.match?(sym_name) return false if target_ruby_version <= 2.1 (sym_name.start_with?("'") && sym_name.end_with?("'")) || (sym_name.start_with?('"') && sym_name.end_with?('"')) end
#alternative_style
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 167
def alternative_style case style when :hash_rockets :ruby19 when :ruby19, :ruby19_no_mixed_keys :hash_rockets end end
#argument_without_space?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/hash_syntax.rb', line 256
def argument_without_space?(node) node.argument? && node.source_range.begin_pos == node.parent.loc.selector.end_pos end
#autocorrect(corrector, node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 178
def autocorrect(corrector, node) if style == :hash_rockets || force_hash_rockets?(node.parent.pairs) autocorrect_hash_rockets(corrector, node) elsif style == :ruby19_no_mixed_keys || style == :no_mixed_keys autocorrect_no_mixed_keys(corrector, node) else autocorrect_ruby19(corrector, node) end end
#autocorrect_hash_rockets(corrector, pair_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 260
def autocorrect_hash_rockets(corrector, pair_node) op = pair_node.loc.operator key_with_hash_rocket = ":#{pair_node.key.source}#{pair_node.inverse_delimiter(true)}" key_with_hash_rocket += pair_node.key.source if pair_node.value_omission? corrector.replace(pair_node.key, key_with_hash_rocket) corrector.remove(range_with_surrounding_space(op)) end
#autocorrect_no_mixed_keys(corrector, pair_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 269
def autocorrect_no_mixed_keys(corrector, pair_node) if pair_node.colon? autocorrect_hash_rockets(corrector, pair_node) else autocorrect_ruby19(corrector, pair_node) end end
#autocorrect_ruby19(corrector, pair_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 235
def autocorrect_ruby19(corrector, pair_node) range = range_for_autocorrect_ruby19(pair_node) space = argument_without_space?(pair_node.parent) ? ' ' : '' corrector.replace(range, range.source.sub(/^:(.*\S)\s*=>\s*$/, "#{space}\\1: ")) hash_node = pair_node.parent return unless hash_node.parent&.return_type? && !hash_node.braces? corrector.wrap(hash_node, '{', '}') end
#check(pairs, delim, msg) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 220
def check(pairs, delim, msg) pairs.each do |pair| if pair.delimiter == delim location = pair.source_range.begin.join(pair.loc.operator) add_offense(location, message: msg) do |corrector| autocorrect(corrector, pair) opposite_style_detected end else correct_style_detected end end end
#force_hash_rockets?(pairs) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/hash_syntax.rb', line 277
def force_hash_rockets?(pairs) cop_config['UseHashRocketsWithSymbolValues'] && pairs.map(&:value).any?(&:sym_type?) end
#hash_rockets_check(pairs)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 145
def hash_rockets_check(pairs) check(pairs, ':', MSG_HASH_ROCKETS) end
#no_mixed_keys_check(pairs)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 159
def no_mixed_keys_check(pairs) if sym_indices?(pairs) check(pairs, pairs.first.inverse_delimiter, MSG_NO_MIXED_KEYS) else check(pairs, ':', MSG_NO_MIXED_KEYS) end end
#on_hash(node)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 123
def on_hash(node) pairs = node.pairs return if pairs.empty? on_hash_for_mixed_shorthand(node) if style == :hash_rockets || force_hash_rockets?(pairs) hash_rockets_check(pairs) elsif style == :ruby19_no_mixed_keys ruby19_no_mixed_keys_check(pairs) elsif style == :no_mixed_keys no_mixed_keys_check(pairs) else ruby19_check(pairs) end end
#range_for_autocorrect_ruby19(pair_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 248
def range_for_autocorrect_ruby19(pair_node) key = pair_node.key.source_range operator = pair_node.loc.operator range = key.join(operator) range_with_surrounding_space(range, side: :right) end
#ruby19_check(pairs)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 141
def ruby19_check(pairs) check(pairs, '=>', MSG_19) if sym_indices?(pairs) end
#ruby19_no_mixed_keys_check(pairs)
[ GitHub ]# File 'lib/rubocop/cop/style/hash_syntax.rb', line 149
def ruby19_no_mixed_keys_check(pairs) if force_hash_rockets?(pairs) check(pairs, ':', MSG_HASH_ROCKETS) elsif sym_indices?(pairs) check(pairs, '=>', MSG_19) else check(pairs, ':', MSG_NO_MIXED_KEYS) end end
#sym_indices?(pairs) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/hash_syntax.rb', line 188
def sym_indices?(pairs) pairs.all? { |p| word_symbol_pair?(p) } end
#word_symbol_pair?(pair) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/style/hash_syntax.rb', line 192
def word_symbol_pair?(pair) return false unless pair.key.sym_type? || pair.key.dsym_type? acceptable_19_syntax_symbol?(pair.key.source) end