Class: Shirobai::Cop::Style::PercentLiteralDelimiters
- Inherits:
-
RuboCop::Cop::Base
- Object
- RuboCop::Cop::Base
- Shirobai::Cop::Style::PercentLiteralDelimiters
- Extended by:
- RuboCop::Cop::AutoCorrector
- Defined in:
- lib/shirobai/cop/style/percent_literal_delimiters.rb
Overview
Drop-in Rust reimplementation of Style/PercentLiteralDelimiters.
Rust walks every percent literal once and decides on a per-type
PreferredDelimiters lookup (resolved Ruby-side from default +
per-type overrides) whether the literal:
- already uses the preferred opener, OR
- contains the preferred opener/closer in any str/sym child source
(stock's
contains_preferred_delimiter?), OR - (for
%w/%ionly) contains the begin delimiter's matchpair character —(/)/[/]/{`/`}/</>or the mirror single-byte forms — in a child source (stock'sinclude_same_character_as_used_for_delimiter?).
When none of the skips apply, Rust returns the offense range plus the
opening_loc and the single-byte closer (so regex options like the
trailing i in %r(.*)i survive the autocorrect, matching stock's
node.loc.end byte width). The wrapper builds the offense + corrector,
formatting both with the resolved preferred pair for the literal's type.
Constant Summary collapse
- MSG =
"`%<type>s`-literals should be delimited by `%<open>s` and `%<close>s`."- TYPES =
Canonical type order shared with
crates/.../percent_literal_delimiters.rsand stock'sPreferredDelimiters::PERCENT_LITERAL_TYPES. ["%", "%i", "%I", "%q", "%Q", "%r", "%s", "%w", "%W", "%x"].freeze
Class Method Summary collapse
- .badge ⇒ Object
-
.bundle_args(config) ⇒ Object
Returns
[pairs]— a 10-entry list of two-byte strings packed for the bundle path'slistsslot. - .cop_name ⇒ Object
Instance Method Summary collapse
Class Method Details
.badge ⇒ Object
35 |
# File 'lib/shirobai/cop/style/percent_literal_delimiters.rb', line 35 def self.badge = RuboCop::Cop::Badge.parse("Style/PercentLiteralDelimiters") |
.bundle_args(config) ⇒ Object
Returns [pairs] — a 10-entry list of two-byte strings packed for
the bundle path's lists slot. We resolve default + per-type
overrides exactly like stock's PreferredDelimiters#preferred_delimiters:
when default is set, every type defaults to it (then overridden by
its own key); without default the listed types still resolve.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/shirobai/cop/style/percent_literal_delimiters.rb', line 42 def self.bundle_args(config) cfg = config.for_badge(badge) configured = cfg.fetch("PreferredDelimiters", {}) # Stock raises ArgumentError on an unknown key. We mirror that here # so the `from_packed` side never sees a missing-type fallback. The # raise propagates through `Dispatch.bundle_token`, which surfaces # it just like stock would. invalid = configured.keys - (TYPES + ["default"]) unless invalid.empty? raise ArgumentError, "Invalid preferred delimiter config key: #{invalid.join(', ')}" end default = configured["default"] pairs = TYPES.map do |type| configured[type] || default end if pairs.any?(&:nil?) # Missing without `default` => the type has no preferred pair; we # use `()` as an inert placeholder. The cop never reaches the # `process` arm for this type (stock would also bail out), but # `from_packed` insists on 10 entries. pairs = pairs.map { |p| p || "()" } end [pairs] end |
.cop_name ⇒ Object
34 |
# File 'lib/shirobai/cop/style/percent_literal_delimiters.rb', line 34 def self.cop_name = "Style/PercentLiteralDelimiters" |
Instance Method Details
#bundle_eligible? ⇒ Boolean
68 69 70 |
# File 'lib/shirobai/cop/style/percent_literal_delimiters.rb', line 68 def bundle_eligible? true end |
#on_new_investigation ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/shirobai/cop/style/percent_literal_delimiters.rb', line 72 def on_new_investigation buffer = processed_source.buffer off = SourceOffsets.for(processed_source.raw_source) resolved_result.each do |start_offset, end_offset, begin_start, begin_end, end_start, end_end, type_index| type = TYPES[type_index] open_delim, close_delim = preferred_pair_for(type).chars range = Parser::Source::Range.new(buffer, off[start_offset], off[end_offset]) = format(MSG, type: type, open: open_delim, close: close_delim) add_offense(range, message: ) do |corrector| begin_range = Parser::Source::Range.new( buffer, off[begin_start], off[begin_end] ) end_range = Parser::Source::Range.new( buffer, off[end_start], off[end_end] ) corrector.replace(begin_range, "#{type}#{open_delim}") corrector.replace(end_range, close_delim) end end end |