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 `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 |