Class: Shirobai::Cop::Layout::HashAlignment
- Inherits:
-
RuboCop::Cop::Base
- Object
- RuboCop::Cop::Base
- Shirobai::Cop::Layout::HashAlignment
- Extended by:
- RuboCop::Cop::AutoCorrector
- Includes:
- RuboCop::Cop::RangeHelp
- Defined in:
- lib/shirobai/cop/layout/hash_alignment.rb
Overview
Drop-in Rust reimplementation of Layout/HashAlignment.
Rust parses the source, walks every multi-line hash literal (replicating
the EnforcedLastArgumentHashStyle ignore_node of a call's last hash
argument and the Layout/ArgumentAlignment: with_fixed_indentation
incompatibility skip), and for each pair computes the column-delta triple
{key, separator, value} under each configured alignment
(EnforcedHashRocketStyle / EnforcedColonStyle, possibly multi-style).
A non-zero delta is an offense; for the colon/rocket flavours the
least-offending permitted style wins, and keyword-splat offenses are
always reported. Rust returns, per offending pair / kwsplat, the offense
range, a message selector, the delta triple and the byte ranges of the
key / operator / value (parser geometry). Ruby applies the realignment
via corrector.insert_before / corrector.remove, exactly like stock's
adjust (including the key_delta clamp to -key.column). Offenses
come from the per-file bundled run (Shirobai::Dispatch); the config
derivation is purely config-driven, so this cop is always
bundle-eligible.
Constant Summary collapse
- MESSAGES =
[ "Align the keys of a hash literal if they span more than one line.", "Align the separators of a hash literal if they span more than one line.", "Align the keys and values of a hash literal if they span more than one line.", "Align keyword splats with the rest of the hash if it spans more than one line." ].freeze
- STYLE_CODES =
{ "key" => "key", "separator" => "separator", "table" => "table" }.freeze
- LAST_ARG_CODES =
{ "always_inspect" => 0, "always_ignore" => 1, "ignore_explicit" => 2, "ignore_implicit" => 3 }.freeze
Class Method Summary collapse
- .badge ⇒ Object
-
.bundle_args(config) ⇒ Object
Packed args for the bundled run:
[rocket_styles, colon_styles, last_argument_style_code, enforce_fixed]. - .cop_name ⇒ Object
- .normalize_styles(value) ⇒ Object
Instance Method Summary collapse
Class Method Details
.badge ⇒ Object
44 |
# File 'lib/shirobai/cop/layout/hash_alignment.rb', line 44 def self.badge = RuboCop::Cop::Badge.parse("Layout/HashAlignment") |
.bundle_args(config) ⇒ Object
Packed args for the bundled run: [rocket_styles, colon_styles, last_argument_style_code, enforce_fixed]. The style lists carry the
EnforcedHashRocketStyle / EnforcedColonStyle values in config order
(deduplicated downstream, matching stock's formats.uniq). The
enforce flag replicates enforce_first_argument_with_fixed_indentation?
(Layout/ArgumentAlignment with_fixed_indentation), driving the
autocorrect_incompatible_with_other_cops? skip.
53 54 55 56 57 58 59 60 61 62 |
# File 'lib/shirobai/cop/layout/hash_alignment.rb', line 53 def self.bundle_args(config) cop_config = config.for_badge(badge) arg_alignment_config = config.for_enabled_cop("Layout/ArgumentAlignment") [ normalize_styles(cop_config["EnforcedHashRocketStyle"]), normalize_styles(cop_config["EnforcedColonStyle"]), LAST_ARG_CODES.fetch(cop_config["EnforcedLastArgumentHashStyle"], 0), arg_alignment_config["EnforcedStyle"] == "with_fixed_indentation" ] end |
.cop_name ⇒ Object
43 |
# File 'lib/shirobai/cop/layout/hash_alignment.rb', line 43 def self.cop_name = "Layout/HashAlignment" |
.normalize_styles(value) ⇒ Object
64 65 66 67 68 |
# File 'lib/shirobai/cop/layout/hash_alignment.rb', line 64 def self.normalize_styles(value) formats = value.is_a?(String) ? [value] : Array(value) formats = ["key"] if formats.empty? formats.map { |f| STYLE_CODES.fetch(f, "key") } end |
Instance Method Details
#on_new_investigation ⇒ Object
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/shirobai/cop/layout/hash_alignment.rb', line 70 def on_new_investigation buffer = processed_source.buffer offenses = Dispatch.offenses_for(processed_source, config, :hash_alignment) off = SourceOffsets.for(processed_source.raw_source) # Stock registers a hash's offenses inside one `on_hash` callback. If # one offense's corrector raises `Parser::ClobberingError` (adjacent # key/separator/value adjustments that collide), it aborts THAT # callback — keeping the offenses already added but dropping the # clobbering one and the rest of that hash — while other hashes # (separate callbacks) are unaffected. We add all offenses in one # `on_new_investigation`, so we reproduce that confinement explicitly: # the Rust `group` id marks each source hash, and a clobber skips only # the remaining offenses of its own group. aborted_group = nil offenses.each do |group, start, fin, , has_value, deltas, key, op, value| next if group == aborted_group range = Parser::Source::Range.new(buffer, off[start], off[fin]) begin add_offense(range, message: MESSAGES[]) do |corrector| if has_value correct_key_value(corrector, buffer, off, deltas, key, op, value) else # `correct_no_value`: adjust the whole node by the key delta. adjust(corrector, deltas[0], range) end end rescue Parser::ClobberingError aborted_group = group end end end |