diff options
author | utilum <oz@utilum.com> | 2018-04-29 12:35:37 +0200 |
---|---|---|
committer | utilum <oz@utilum.com> | 2018-05-01 18:09:05 +0200 |
commit | 52a41974c2de62af9ad5950be9a7ee21484a7b27 (patch) | |
tree | d0069f0f408c85743b2507a3e11d5771a0c8f5f1 /railties | |
parent | 24aeccb1c873cb8bbf00ff77cb33432cfe598b3d (diff) | |
download | rails-52a41974c2de62af9ad5950be9a7ee21484a7b27.tar.gz rails-52a41974c2de62af9ad5950be9a7ee21484a7b27.tar.bz2 rails-52a41974c2de62af9ad5950be9a7ee21484a7b27.zip |
Partly revert #32289 to provide Rails' custom fallback in case
`DidYouMean::SpellChecker` is not defined.
`did_you_mean` is bundled in Ruby but can be uninstalled, and is not always
available, sometimes even on our CI:
https://travis-ci.org/rails/rails/jobs/372638523#L2405
https://travis-ci.org/rails/rails/jobs/372638523#L2416
https://travis-ci.org/rails/rails/jobs/372638523#L2427
...
Diffstat (limited to 'railties')
-rw-r--r-- | railties/lib/rails/command/spellchecker.rb | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/railties/lib/rails/command/spellchecker.rb b/railties/lib/rails/command/spellchecker.rb index 154358cd45..04485097fa 100644 --- a/railties/lib/rails/command/spellchecker.rb +++ b/railties/lib/rails/command/spellchecker.rb @@ -3,8 +3,55 @@ module Rails module Command module Spellchecker # :nodoc: - def self.suggest(word, from:) - DidYouMean::SpellChecker.new(dictionary: from.map(&:to_s)).correct(word).first + class << self + def suggest(word, from:) + if defined?(DidYouMean::SpellChecker) + DidYouMean::SpellChecker.new(dictionary: from.map(&:to_s)).correct(word).first + else + from.sort_by { |w| levenshtein_distance(word, w) }.first + end + end + + private + + # This code is based directly on the Text gem implementation. + # Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher. + # + # Returns a value representing the "cost" of transforming str1 into str2. + def levenshtein_distance(str1, str2) # :doc: + s = str1 + t = str2 + n = s.length + m = t.length + + return m if (0 == n) + return n if (0 == m) + + d = (0..m).to_a + x = nil + + # avoid duplicating an enumerable object in the loop + str2_codepoint_enumerable = str2.each_codepoint + + str1.each_codepoint.with_index do |char1, i| + e = i + 1 + + str2_codepoint_enumerable.with_index do |char2, j| + cost = (char1 == char2) ? 0 : 1 + x = [ + d[j + 1] + 1, # insertion + e + 1, # deletion + d[j] + cost # substitution + ].min + d[j] = e + e = x + end + + d[m] = x + end + + x + end end end end |