Skip to content

Add inline variable refactor #2504

Open

Description

@vinistock

Note

This issue is aimed at those attending the RubyConf 2024 Hack Day

Add a new code action to inline a local variable. For example:

# BEFORE
def foo
  a = 5 * 10
  puts a
  b = a - 5
end

# AFTER
def foo
  puts 5 * 10
  b = 5 * 10 - 5
end

Here's an example PR adding a refactor end to end #2372.

Activity

  1. added
    enhancementNew feature or request
    help-wantedExtra attention is needed
    pinnedThis issue or pull request is pinned and won't be marked as stale
    serverThis pull request should be included in the server gem's release notes
    on Aug 28, 2024
  2. ttilberg commented on Sep 20, 2024

    @ttilberg
    Contributor

    I was reading through this issue, and wanted to note that the resulting expression may need to have parenthesis in order to keep order of operations good. I'm not sure if it would be possible to calculate that it's not needed. Some examples counter to the example in the issue:

    # Subtraction before multiplication
    # BEFORE
    def foo
      a = 5 - 10
      puts a  # => -5
      b = a * 5  # => -25
    end
    
    # Without ()
    def foo
      puts 5 - 10 # => -5
      b = 5 - 10 * 5 # => **-45**
    end
    
    # With ()
    def foo
      puts (5 - 10) # => -5
      b = (5 - 10) * 5 # => **-25**
    end
    

    I can't think of an example for this other thought quick enough, but I suspect there would be issues with certain method calling instances as well, akin to what you see with 1..10.map vs (1..10).map... you know, all those classic cases where you end up needing parens afterall.

    I just wanted to highlight this concern as I feel like this refactoring tool could create some easy-to-miss bugs if it doesn't wrap the expression in parens.

  3. ttilberg commented on Sep 20, 2024

    @ttilberg
    Contributor

    Maybe there should be a check for "does the replacement candidate, or replacement targets include any method calls" in the ast? And if so, we should use parens? This may be naïve, but it seems like that's where things can get sticky.

  4. vinistock commented on Sep 20, 2024

    @vinistock
    MemberAuthor

    That's a really good point. Maybe the implementation should check if the target of the inlining is a unary/math expression and then enforce parenthesis in those cases.

  5. IslamElsayed commented on Oct 28, 2026

    @IslamElsayed

    I'd like to pick this up. The plan is an "Inline variable" code action, offered when the cursor is on a local variable's assignment or on one of its reads. It replaces every read in the same scope with the assigned expression and removes the assignment, wrapping the expression in parentheses when it's a binary or unary expression, as you suggested above.

    I'd leave the action out when the variable is reassigned in the scope, and when the value contains a method call and is read more than once, since inlining would change how often it runs. Does that match what you had in mind?

    (I use AI assistance when working on patches, and I check and test everything before submitting.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp-wantedExtra attention is neededpinnedThis issue or pull request is pinned and won't be marked as staleserverThis pull request should be included in the server gem's release notes

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions