Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Did you mean functionality. #2601

Merged
merged 24 commits into from
Mar 7, 2019
Merged

Did you mean functionality. #2601

merged 24 commits into from
Mar 7, 2019

Conversation

obromios
Copy link
Contributor

This PR is to add Did you mean? type functionality to rspec such that if an incorrect path is provided to the rspec command then suggestions will be made as to the correct path. A brief summary of of the changes needed to do this can be seen in the PR commit messages.

I welcome questions, suggestions or feedback in regard to this PR.

JonRowe and others added 6 commits February 10, 2019 08:23
The functionality provides for suggestions when a person enters an
rspec spec/some_file_pathcommand with  typographical errors.

If there are errors, then at lib/rspec/core/configuration.rb:2037
the code searches for suggestions. If useful suggestions are found
they are added to the reported exception at
lib/rspec/core/configuration.rb:2038.

The suggestions are done by the DidYouMean::Suggestions service
object, which calls the DidYouMean::Proximity service object.
These are found in lib/rspec/core/did_you_mean

The other change to the current code is to provide for autoloading
of the DidYouMean constants, this is done at lib/rspec/core.rb:142.

Two test files are added in the spec/rspec/core/did_you_mean directory.

This functionality was inspired by
https://github.com/yuki24/did_you_mean
and partly based on the jaro_winkler code from that source
https://github.com/yuki24/did_you_mean/blob/master
/lib/did_you_mean/jaro_winkler.rb. This code has an MIT licence.
Add comments for failing yard tests
Add work arounds for early rubies and jruby
Because of lack of robust support for UTF-8
Copy link
Member

@JonRowe JonRowe left a comment

Choose a reason for hiding this comment

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

Great work so far, just had a first pass of feedback

@@ -139,6 +139,7 @@ def self.world
module Core
autoload :ExampleStatusPersister, "rspec/core/example_status_persister"
autoload :Profiler, "rspec/core/profiler"
autoload :DidYouMean, "rspec/core/did_you_mean/did_you_mean"
Copy link
Member

Choose a reason for hiding this comment

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

Might as well line this up.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -1,4 +1,4 @@
# This file was generated on 2019-01-03T20:34:23+00:00 from the rspec-dev repo.
# This file was generated on 2019-01-08T11:28:05+00:00 from the rspec-dev repo.
Copy link
Member

Choose a reason for hiding this comment

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

I think if you rebase this commit will go away

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I assume you are talking about the commit #2591 with sha 511cec5. I am concerned that if I rebase this on my local machine and then push it, then the will be problems as I have already pushed this up. As well, if I look at rspec-core master, #2591 has a sha of cb1b4ce If I do a diff between my local did_you_mean branch and my local master it is not showing any files from 511cec5. Frankly, I do not understand what is happening here.

Copy link
Member

Choose a reason for hiding this comment

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

Its because its based off an older branch, github does that. You can use git push <origin> <branch> --force-with-lease to update this branch safely after a rebase, it won't let you ruin anything then.

autoload :Suggestions, 'rspec/core/did_you_mean/suggestions'
end
end
end
Copy link
Member

Choose a reason for hiding this comment

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

Can we ditch the two child files and have it all in here please.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. I also ditched the directory given there is now only one file.

end

def red_font(mytext)
"\e[31m#{mytext}\e[0m"
Copy link
Member

Choose a reason for hiding this comment

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

You can't colourise text like this, we have configurable colours and the reporter should take care of it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As you will see, in my did_you_mean.red_font, I now use the coloriser.wrap method to do the colouring. Is this OK, or do you want me to use the reporter more directly, say by modifying reporter. notify_non_example_exception to take care of this?

module DidYouMean
RSpec.describe Proximity do
# port of https://github.com/yuki24/did_you_mean/blob/master/test/edit_distance/jaro_winkler_test.rb
if RUBY_VERSION.to_f >= 2.0
Copy link
Member

Choose a reason for hiding this comment

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

We have functions in RSpec::Support to take care of things like this, see how it does the specs for encoded strings.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I looked at encoded string spec and it seems to use a similar approach (at line 88) as I am using. Am I looking in the right place?

However, I do wonder about the exact implementation being used at line 88. In particular, using RUBY_VERSION < '2.1' appears to rely on a string comparison which can give incorrect results e.g '11' < '2.1' evaluates as true.

Copy link
Member

Choose a reason for hiding this comment

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

The key difference is we use the function we need first, (for example line 43) then only use RUBY_VERSION for things we can't pick out by other means, we also gate this functionality out for the other gems via https://github.com/rspec/rspec-support/blob/master/lib/rspec/support/ruby_features.rb.

However, I do wonder about the exact implementation being used at line 88. In particular, using RUBY_VERSION < '2.1' appears to rely on a string comparison which can give incorrect results e.g '11' < '2.1' evaluates as true.

It does, however RUBY_VERSION will always by x.y.z unless tampered with, and why we prefer feature detection instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you, I will have a further look.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done, I think?


# provide probable suggestions if a LoadError
def call
return unless RUBY_VERSION.to_f >= 2.0
Copy link
Member

Choose a reason for hiding this comment

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

We don't typically do ruby version comparison at runtime, but instead define alternate methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

# provide probable suggestions if a LoadError
def call
return unless RUBY_VERSION.to_f >= 2.0
return unless exception.class == LoadError
Copy link
Member

Choose a reason for hiding this comment

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

We probably shouldn't call this at all if we don't have the error we expect.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

private

def formats(short_list)
rspec_format = short_list.map { |s, _| "rspec ./#{s}" }
Copy link
Member

Choose a reason for hiding this comment

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

I think we have some logic for this somewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have not been able to find it. Is your concern that sometimes the correct prefix is not 'rspec ./'?

module RSpec
module Core
module DidYouMean
# class to calculate jaro_winkler distance based on
Copy link
Member

Choose a reason for hiding this comment

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

I'm unsure if this is worth this complexity, is there not a similar simpler algorithm we can use?

Copy link
Member

Choose a reason for hiding this comment

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

Levenshtein is simpler to implement, might have to benchmark the two for comparison and see what suits better, and whats faster https://github.com/ioquatix/build-text/blob/master/lib/build/text/merge.rb#L60-L102

Copy link
Member

Choose a reason for hiding this comment

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

And it's there already in RubyGems:

> require 'rubygems/text'
> include Gem::Text
> levenshtein_distance 'abcd', 'sdff' # => 4

Copy link
Member

Choose a reason for hiding this comment

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

Mm, we can't use that directly, as we don't depend on rubygems and its not always available. We could however make this contextual on that, (e.g. disable the feature on load error.

module RSpec
  module Core
    module DidYouMean
      begin
        require 'rubygems/text'
        # ... define did you mean logic
      rescue LoadError
        # ... define identical public entry point which returns the old behaviour
      end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am still analysing levenshtein vs jaro-winkler so will comment on the idea of the using the text gem when I have completed the analysis.

Copy link
Contributor Author

@obromios obromios Feb 24, 2019

Choose a reason for hiding this comment

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

I have implemented the levenshtein and did a simple benchmark. When run on the rspec-core files, levenshtein takes about 100ms, whereas jaro-winkler took 17ms. Levenshtein is clearly O(n^2) where n is the string length, but according to this article jaro-winkler is O(n). This means if some projects are deeply nested i.e. have longer strings for the file names, then jaro-winkler will have an ever greater speed improvement over levenshtein.

Just based on my very limited testing, I think jaro-winkler may give better suggestions than levensthein though this may becasause of the cut_offs I have set.

As well, although the levensthein algorithm is shorter, it is a very clever bit of logic that uses dynamic programming to find the minimum number of inserts/deletions/substitutions to transform one string to another. By contrast jaro-winkler is simply counting the number of matches and transpositions so is conceptually much simpler. As well I think I can simplify the jaro-winkler algorithm by removing the winkler part which gives priority over the first four characters which in our case is always 'spec'.

So I suggest that we go with a simplified jaro-winkler. But I am happy to go with levenshtein, and if we do that I will consider the point about using the text gem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The total time for the did_you_mean is directly proportional to the number of files in the spec folder. If we go with jaro-winkler this is about 0.2 ms per file. For 1,000 files this is about 0.2 seconds which would not be perceptible, but for 10,000 files it would be 2 seconds which would cause a marked delay. If you think some users will have more than 1,000 files, I suggest I develop a test to determine the expected time and not look for suggestions if the time is greater than about 500ms. Please let me know if you think I should do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As suggested by palkan at #2590 I have changed to using the DidYouMean api. Using the DidYouMean api, a typical check takes about 6ms on my machine. If I put in a really bad long and unlikely string, it takes 17ms. On average it is much, much faster than Levenstein and faster than my implementation of jaro-winkler. It seems to give good suggestions and is much simpler.

@obromios
Copy link
Contributor Author

Jon, thank you for your suggestions, I will work through them over the next week or two.

Chris

@obromios
Copy link
Contributor Author

I am still failing the early ruby tests. I use rvm and it will not let me install 1.9.2 or earlier, so I have no way of testing early rubies locally. How do people working on rspec-core solve this problem.

@JonRowe
Copy link
Member

JonRowe commented Feb 25, 2019

@obromios see your original issue #2590 theres "automatically" provided functionality we can use

@JonRowe JonRowe mentioned this pull request Feb 26, 2019
Copy link
Member

@JonRowe JonRowe left a comment

Choose a reason for hiding this comment

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

Great work, mostly stylistic feedback this time :)

@@ -0,0 +1,44 @@
module RSpec
module Core
# Service object to provide did_you_mean suggestions
Copy link
Member

Choose a reason for hiding this comment

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

Unless you make this object yard private # @private you'll need to document all the methods in this file with yard, but I'm happy for this to be a private API. I'd suggest an improvement to this comment however.

# Wrapper around Ruby's `DidYouMean::SpellChecker` when available to provide file name suggestions.

As all of RSpec is "service" objects., and did_you_mean isn't a code path for us :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

end

if defined?(::DidYouMean::SpellChecker)
# provide probable suggestions if a LoadError
Copy link
Member

Choose a reason for hiding this comment

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

Nothing checks it's a load error here, so perhaps this comment is unnecessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

formats probables
end
else # ruby 2.3.2 or less
# return nil if API for ::DidYouMean::SpellChecker not supported
Copy link
Member

Choose a reason for hiding this comment

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

I think this should return an empty string, or maybe even a warning?, I feel the ruby comment is irrelevant, its if the library is available or not (which could also happens if someone uninstalls a standard gem).

Copy link
Member

Choose a reason for hiding this comment

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

What type of warning do you think we should we use? Don't think it will add noise?

Do you consider something like:

'did_you_mean' standard gem is not installed. It could help you to solve the loading failure
An error occurred while loading /folder/file.rb.

Copy link
Member

@JonRowe JonRowe Feb 27, 2019

Choose a reason for hiding this comment

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

Outputting:

"\nHint: Install the `did_you_mean` gem in order to provide suggestions for similarly named files."

Would produce:

An error occurred while loading #{relative_file}.
Hint: Install the `did_you_mean` gem in order to provide suggestions for similarly named files.

Copy link
Member

Choose a reason for hiding this comment

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

It seems a good idea!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

require 'tmpdir'
require 'rspec/support/spec/in_sub_process'

module RSpec
Copy link
Member

Choose a reason for hiding this comment

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

We favour RSpec::Core style name spacing, saves some spaces :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I prefer it too, but when I used it, I encountered the following cop:
Style/ClassAndModuleChildren: Use nested module/class definitions instead of compact style.
When I investigated further, I found this description of why the cop is there.

Copy link
Member

Choose a reason for hiding this comment

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

Weird, we do that style elsewhere, is it possible you're using more updated version of Rubocop than us? Or not running with our config?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am using 0.52.1, the same as in the Gemfile. I looked at .rubocop.yml and it has the following entry for this cop:

# Not sure what to do with this rule yet.
Style/ClassAndModuleChildren:
  Exclude:
    - lib/rspec/core/formatters.rb
    - lib/rspec/core/notifications.rb
    - lib/rspec/core/option_parser.rb
    - lib/rspec/core/reporter.rb

so I can either add did_you_mean.rb to this list, or leave the nested modules syntax in?

Copy link
Member

Choose a reason for hiding this comment

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

No its not a blocker

@@ -0,0 +1,41 @@
require 'tmpdir'
require 'rspec/support/spec/in_sub_process'
Copy link
Member

Choose a reason for hiding this comment

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

Are you using this/these still?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

module Core
RSpec.describe DidYouMean do
if defined?(::DidYouMean::SpellChecker)
describe 'Call to DidYouMean' do
Copy link
Member

Choose a reason for hiding this comment

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

We typically do describe "#method_name" for the outer, so #call in this case, with inner contexts so ideally this spec would have the layout, you can also use hide_const to test the functionality.

describe "#call" do
  if defined?(::DidYouMean::SpellChecker)
  context "when `DidYouMean::SpellChecker` is available", skip: defined?(::DidYouMean::SpellChecker) do
    # ...
  end
  context "when `DidYouMean::SpellChecker` is not available" do
    before do
      hide_const("DidYouMean::SpellChecker") if defined?(DidYouMean::SpellChecker)
    end
    # ...
  end
end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is neat, I was not aware of the hide_const. I have implemented this change, but had one puzzle. When I run rspec spec then I get following error:

 RSpec::Core::DidYouMean#call when `DidYouMean::SpellChecker` is not available Success returns a hint
     Failure/Error: checker = ::DidYouMean::SpellChecker.new(:dictionary => Dir["spec/**/*.rb"])
     
     NameError:
       uninitialized constant DidYouMean::SpellChecker
       Did you mean?  DidYouMean::SpellChecker
                      DidYouMean::SPELL_CHECKERS
     # ./lib/rspec/core/did_you_mean.rb:15:in `call'
     # ./spec/rspec/core/did_you_mean_spec.rb:34:in `block (5 levels) in <module:Core>'

but when I run script/run_build all rspec tests pass. Is there some filter or setting I should be adding when I do rspec spec on my local machine?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The CI tests have finished and it appears that the :skip keyword is not supported by the rspec that runs with the earlier rubies e.g. 1.8.7. Any suggestions what to do about this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thinking about the fact I get the error when running rspec spec but not when I run script/run_build, I think that although ruby is an interpreted language, there seems to be a two pass process that can see that the if defined?(::DidYouMean::SpellChecker) at did_you_mean:12, can be decided ahead of time.

The issue seems to be that when I run 'rspec spec' this is done after the did_you_mean_spec.rb code runs but before the did_you_mean.rb code runs. Whereas when I do script/run_build, the static compilation step is done prior to the did_you_mean_spec.rb code running. Does this make sense?

describe 'Call to DidYouMean' do
describe 'Success' do
let(:name) { './spec/rspec/core/did_you_mean_spec.rb' }
it 'should return a useful suggestion' do
Copy link
Member

Choose a reason for hiding this comment

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

We prefer positive text around expectations, eg. it 'returns a useful suggestion'

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

end
end
context 'No suitable suggestions' do
it 'Whereof one cannot speak, thereof one must be silent' do
Copy link
Member

Choose a reason for hiding this comment

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

Could we have something a bit er... plainer here? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right, not everyone is a Wittgenstein fan. Done.

RSpec.describe DidYouMean do
describe '#call' do
if defined?(::DidYouMean::SpellChecker)
context "when `DidYouMean::SpellChecker` is available", skip: !defined?(::DidYouMean::SpellChecker) do
Copy link
Member

Choose a reason for hiding this comment

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

For 1.8.7 etc this needs to be :skip =>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Of course. Done

module Core
RSpec.describe DidYouMean do
describe '#call' do
if defined?(::DidYouMean::SpellChecker)
Copy link
Member

Choose a reason for hiding this comment

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

You should be able to remove this

Copy link
Member

Choose a reason for hiding this comment

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

You need to remove this so the tests run when not defined for not defined

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

end
context "when `DidYouMean::SpellChecker` is not available" do
before do
hide_const("::DidYouMean::SpellChecker") if defined?(::DidYouMean::SpellChecker)
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't seem to work on windows, I wonder if we should should do :unless => defined?(::DidYouMean::SpellChecker) on the context instead

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Member

@JonRowe JonRowe left a comment

Choose a reason for hiding this comment

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

This is looking great! I would have merged it except for the windows CI failures, can you take a look?

@obromios
Copy link
Contributor Author

obromios commented Mar 1, 2019

The windows CI failures have the same pattern of failure that I see on my local machine when I run rspec spec/rspec/core/did_you_mean_spec.rb:31 (the hide_const test). It fails on ruby 2.4.4 but works on 2.3.0. So I agree that
:unless => defined?(::DidYouMean::SpellChecker)
should work. I will try this over the weekend.

@obromios
Copy link
Contributor Author

obromios commented Mar 3, 2019

I have added the unless defined?(::DidYouMean::SpellChecker) check to the did_you_mean_spec.rb. When testing I noticed the performace of the algorithm had deteriorated relative to my first implementation.

The DidYouMean api uses JaroWinkler as the major filter. This means it gives too much priority to errors early in the string and the thresholds are too low for the length of string that we are using. Accordingly, I re-introduced two ad-hoc fixes for this that I used in my first implementation. At a more fundamental level, the DidYouMean algorithm appears to be designed for short string lengths, say 1 to 15 characters and an unstructured dictionary.

The strings we are using are much longer. On the other hand, the dictionary that we are using is highly structured. Each path e.g. spec/models/user_spec.rb has relatively few choices at each node in the chain. As well, the choices have typically a small number of characters e.g. after spec/ the choices might be '[models, controllers, features]'.

We could develop an ad hoc approach to solving this, for instance palkans approach is an example that just uses the last node in the chain. I have been thinking about this, and think the problem may well lend itself to an elegant hidden markov model type approach, as well it would be interesting to see what other people done with structured dictionaries.

However, this is more a research project, it could take some time to get right, the code to implement such an algorithm would be of use to other programs e.g. minitest and cucumber, and code would be much more complex that the present implementation.

I suggest for the time being we go with what has been developed which does appear to be useful. After this has gone to the master branch, I will raise an issue on the DidYouMean gem to develop an option for the api to use a structured dictionary. If this is accepted and I or other people do develop such an option, then we would just need to slightly modify the our DidYouMean api to use this structured option.

Copy link
Member

@benoittgt benoittgt left a comment

Choose a reason for hiding this comment

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

Good job! LGTM!

Thanks for the detail last comment

@obromios
Copy link
Contributor Author

obromios commented Mar 7, 2019

JonRowe, would you like me to do anything further?

@JonRowe JonRowe merged commit cbd6d47 into rspec:master Mar 7, 2019
@JonRowe
Copy link
Member

JonRowe commented Mar 7, 2019

Thanks! ❤️ 💚 💛 💜

JonRowe added a commit that referenced this pull request Mar 7, 2019
@obromios
Copy link
Contributor Author

obromios commented Mar 7, 2019

Thank you JonRowe for your thoughtful reviewing.

MatheusRich pushed a commit to MatheusRich/rspec-core that referenced this pull request Oct 30, 2020
* Add did_you_mean functionality to rspec-core.

The functionality provides for suggestions when a person enters an
rspec spec/some_file_path command with typographical errors.

If there are errors, then the code at lib/rspec/core/configuration.rb:2037
searches for suggestions. If useful suggestions are found
they are added to the reported exception at
lib/rspec/core/configuration.rb:2038.

The suggestions are done by the ::DidYouMean::SpellChecker API
where available.
MatheusRich pushed a commit to MatheusRich/rspec-core that referenced this pull request Oct 30, 2020
yujinakayama pushed a commit to yujinakayama/rspec-monorepo that referenced this pull request Oct 6, 2021
* Add did_you_mean functionality to rspec-core.

The functionality provides for suggestions when a person enters an
rspec spec/some_file_path command with typographical errors.

If there are errors, then the code at lib/rspec/core/configuration.rb:2037
searches for suggestions. If useful suggestions are found
they are added to the reported exception at
lib/rspec/core/configuration.rb:2038.

The suggestions are done by the ::DidYouMean::SpellChecker API
where available.

---
This commit was imported from rspec/rspec-core@cbd6d47.
yujinakayama pushed a commit to yujinakayama/rspec-monorepo that referenced this pull request Oct 6, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants