aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib
diff options
context:
space:
mode:
authorutilum <oz@utilum.com>2018-04-29 12:35:37 +0200
committerutilum <oz@utilum.com>2018-05-01 18:09:05 +0200
commit52a41974c2de62af9ad5950be9a7ee21484a7b27 (patch)
treed0069f0f408c85743b2507a3e11d5771a0c8f5f1 /railties/lib
parent24aeccb1c873cb8bbf00ff77cb33432cfe598b3d (diff)
downloadrails-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/lib')
-rw-r--r--railties/lib/rails/command/spellchecker.rb51
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