Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework method/parameter name validation to use the compiler #1066

Merged
merged 1 commit into from
Jul 18, 2022

Conversation

paracycle
Copy link
Member

@paracycle paracycle commented Jul 15, 2022

Motivation

Our current way of doing method name and parameter name checks are a bit hacky and that's been showing through.

Implementation

A better way to do this is to use the compiler to do the name checks, similar to how Ruby does it in its codebase. (Thanks to @tenderlove for showing me this method name validation check)

This method relies on compiling a method definition with the given name and then checking if the compiled code actually defines a method with that name.

Tests

Only updated the error message from a test to make it explicit which case is failing.

@paracycle paracycle force-pushed the uk-rework-method-name-validation branch 2 times, most recently from 40fd719 to 653e838 Compare July 18, 2022 14:24
@paracycle paracycle marked this pull request as ready for review July 18, 2022 14:25
@paracycle paracycle requested a review from a team as a code owner July 18, 2022 14:25
@paracycle paracycle changed the title Change method/parameter name validation to lean on the compiler Rework method/parameter name validation to use the compiler Jul 18, 2022
end

sig { params(name: String).returns(T::Boolean) }
def valid_parameter_name?(name)
/^([[:lower:]]|_|[^[[:ascii:]]])([[:alnum:]]|_|[^[[:ascii:]]])*$/.match?(name)
sentinel_method_name = :sentinel_method_name
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How cleaner and faster is this compared to a regular expression?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the compiler version might be drastically slower, so I ran some large gem RBI generation (rubocop) on the codebase, before and after this change and got super similar results:

$ hyperfine --prepare "git reset --hard 822611bf" "bundle exec tapioca gem rubocop" --prepare "git reset --hard 1984b06b" "bundle exec tapioca gem rubocop # symbol hack"
Benchmark 1: bundle exec tapioca gem rubocop
  Time (mean ± σ):     26.091 s ±  0.474 s    [User: 23.142 s, System: 2.413 s]
  Range (min … max):   25.420 s … 27.032 s    10 runs
 
Benchmark 2: bundle exec tapioca gem rubocop # symbol hack
  Time (mean ± σ):     26.132 s ±  0.684 s    [User: 23.127 s, System: 2.402 s]
  Range (min … max):   25.498 s … 27.923 s    10 runs
 
Summary
  'bundle exec tapioca gem rubocop' ran
    1.00 ± 0.03 times faster than 'bundle exec tapioca gem rubocop # symbol hack'

(the one with the comment # symbol hack being the version before these changes)

In general, I think this is "cleaner" since we rely on the Ruby to tell us what is considered a valid method name or parameter name, instead of relying on regular expressions that may or may not cover edge cases.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting!

It's definitely better than the symbol hack and, as you said, at least we don't have to bother with it anymore since now it's handled by the Ruby VM.

Our current way of doing method name and parameter name checks are a bit
hacky and [that's been showing through](#1045).

A better way to do this is to use the compiler to do the name checks,
similar to [how Ruby does it in its codebase](https://github.com/ruby/ruby/blob/241dced625f9ba8a4071954579778a0940e75179/ext/rubyvm/lib/forwardable/impl.rb#L3-L9).

This method relies on compiling a method definition with the given name
and then checking if the compiled code actually defines a method with
that name.
@paracycle paracycle force-pushed the uk-rework-method-name-validation branch from 653e838 to 28de350 Compare July 18, 2022 15:02
@paracycle paracycle merged commit de0ec30 into main Jul 18, 2022
@paracycle paracycle deleted the uk-rework-method-name-validation branch July 18, 2022 17:30
@shopify-shipit shopify-shipit bot temporarily deployed to production July 19, 2022 17:59 Inactive
@shopify-shipit shopify-shipit bot temporarily deployed to 0-9-stable August 22, 2022 21:36 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants