Back to selected work

Open source contributions

I added push and pop directives to RuboCop, the Ruby linter and formatter, then fixed two bugs in them and an indentation regression. All four pull requests are merged. I also maintain a fork of tree-sitter-ruby, the Ruby grammar for the tree-sitter parser generator.

Projects
RuboCop, tree-sitter-ruby
Merged pull requests
4 (RuboCop)
Merge dates
Dec 2025 to Jan 2026
Fork
tree-sitter-ruby
Languages
Ruby, C, JavaScript
The four pull requests
Pull requestChangeStatus
RuboCop #14633Push and pop directivesMerged Dec 2025
RuboCop #14774Push arguments no longer read as enable commentsMerged Jan 2026
RuboCop #14814Nested scopes and department names in push and popMerged Jan 2026
RuboCop #14818Indentation regression in RuboCop 1.84.0Merged Jan 2026

Push and pop directives

RuboCop runs checks called cops, and comments switch them off and on for part of a file: # rubocop:disable Style/For, then # rubocop:enable Style/For. These comments are switches, not scopes. An enable turns the cop on whatever its state was before, so a pair placed inside a region where the cop is already off turns it back on too early, and every pair repeats the cop names. Issue #13854, “disable/enable is too imperative”, asked for a stack instead.

With push and pop, push saves the state of the cops and can change some of them on the same line, and pop restores whatever was saved. A - before a cop name disables it and a + enables it. This example is from the RuboCop documentation:

# rubocop:disable Style/For
for x in [1, 2, 3]
  puts x
end
# rubocop:push +Style/For -Style/GuardClause
for y in [4, 5, 6]  # Style/For is re-enabled here
  if y > 0
    return y        # Style/GuardClause is disabled here
  end
end
# rubocop:pop
# Back to original state: Style/For disabled, Style/GuardClause enabled

Pull request #14633 changed eight files:

  • Added push and pop to the directive parser, with optional + and - arguments.
  • Made the analysis of directive comments keep a stack: push saves the state of every cop and applies its arguments, pop ends the scope and restores the saved state.
  • Kept Lint/RedundantCopDisableDirective from reporting push and pop comments, and added the new modes to the message of Lint/CopDirectiveSyntax.
  • Documented the directives, with nested examples.
  • Added specs for ten scenarios, from one disabled cop to nested scopes and inline arguments.

Merged Dec 2025. The RuboCop 1.84.0 release notes list it as a new feature.

Three follow-up fixes

Two fix push and pop themselves; the third fixes a regression in Layout/IndentationWidth that RuboCop 1.84.0 introduced.

Push arguments read as enable comments

After #14633, Lint/RedundantCopEnableDirective reported # rubocop:push -Style/GuardClause as an unnecessary enabling of a cop named -Style/GuardClause. The method that collects enable comments did not skip push and pop, so the argument took the path of an enable directive. I added a guard that skips them, a regression test, and the changelog entry for #14633.

Pull request #14774, merged Jan 2026. Three files changed.

Nested scopes and department names

My first implementation did not always restore the intermediate state of nested push and pop blocks, and department names such as +Metrics or -Style in push arguments did not work. I reworked the push and pop handling: department names now expand to every cop in the department, each push saves the cops it changes, and pop ends the scope on the line before it and resumes an earlier disabled state from its own line. I updated the specs to check the state of each cop line by line, including nested blocks and departments.

Pull request #14814, merged Jan 2026, released in RuboCop 1.84.1. Two files changed.

An indentation regression in RuboCop 1.84.0

In RuboCop 1.84.0, Layout/IndentationWidth measured the body of a block that follows a multi-line method chain from the column of the closing brace or end, and reported correctly indented code (issue #14805). I changed the base back to the dot of the chain whenever that dot starts its own line, whatever the EnforcedStyleAlignWith setting, which brings back the indentation from before 1.84.0. I added specs for brace and do blocks after a multi-line chain and for a long receiver, and updated an autocorrect spec.

Pull request #14818, merged Jan 2026, released in RuboCop 1.84.1. Four files changed.

My tree-sitter-ruby fork

tree-sitter-ruby is the Ruby grammar for tree-sitter, a parser generator that editors use for syntax highlighting and code navigation. My fork, Magikdidi24/tree-sitter-ruby, adds:

  • Ruby 3.0+ syntax: endless methods whose body is a command call without parentheses, such as def a1 = puts 1, lambda parameters with block-local variables, as in ->(;a) { a = 1 }, return followed by parenthesized values, and a range left open at the end of a line.
  • Fixes in the hand-written C scanner for heredocs, regular expressions, percent literals, unary arguments and comments inside ERB templates, several of them for issues reported on the original repository.
  • A differential check that parses the ruby/spec test suite with both tree-sitter and Prism, Ruby's own parser, and lists where they disagree.
  • Build and CI updated for the tree-sitter CLI 0.27.1, and 878 new lines of test cases in the grammar's corpus, which pair a Ruby snippet with the syntax tree the parser must produce.