aboutsummaryrefslogtreecommitdiffstats
path: root/railties
diff options
context:
space:
mode:
authorGenadi Samokovarov <gsamokovarov@gmail.com>2018-02-27 17:06:33 +0200
committerGenadi Samokovarov <gsamokovarov@gmail.com>2018-03-04 17:50:37 +0200
commita951729f45c579aa17b76a73f72880f90df9e910 (patch)
tree3be25fd52a520322cbe0491b60a85523decc6a0e /railties
parent5af643d8d6f8af19a85a34475f40ac18db7c71e9 (diff)
downloadrails-a951729f45c579aa17b76a73f72880f90df9e910.tar.gz
rails-a951729f45c579aa17b76a73f72880f90df9e910.tar.bz2
rails-a951729f45c579aa17b76a73f72880f90df9e910.zip
Extract Rails::Command::Spellchecker
Diffstat (limited to 'railties')
-rw-r--r--railties/lib/rails/command.rb1
-rw-r--r--railties/lib/rails/command/behavior.rb40
-rw-r--r--railties/lib/rails/command/spellchecker.rb53
-rw-r--r--railties/lib/rails/generators.rb2
-rw-r--r--railties/test/command/spellchecker_test.rb10
5 files changed, 65 insertions, 41 deletions
diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb
index 078e9f937f..6d99ac9936 100644
--- a/railties/lib/rails/command.rb
+++ b/railties/lib/rails/command.rb
@@ -11,6 +11,7 @@ module Rails
module Command
extend ActiveSupport::Autoload
+ autoload :Spellchecker
autoload :Behavior
autoload :Base
diff --git a/railties/lib/rails/command/behavior.rb b/railties/lib/rails/command/behavior.rb
index 7a6dd28e1a..718e2d9ab2 100644
--- a/railties/lib/rails/command/behavior.rb
+++ b/railties/lib/rails/command/behavior.rb
@@ -19,46 +19,6 @@ module Rails
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
-
# Prints a list of generators.
def print_list(base, namespaces)
return if namespaces.empty?
diff --git a/railties/lib/rails/command/spellchecker.rb b/railties/lib/rails/command/spellchecker.rb
new file mode 100644
index 0000000000..59ccab4ea2
--- /dev/null
+++ b/railties/lib/rails/command/spellchecker.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module Rails
+ module Command
+ module Spellchecker # :nodoc:
+ class << self
+ def suggest(word, from:, count: 3)
+ from.sort_by { |w| levenshtein_distance(word, w) }.take(count)
+ 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
+end
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index 6a7175c02b..7248fbbc94 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -276,7 +276,7 @@ module Rails
klass.start(args, config)
else
options = sorted_groups.flat_map(&:last)
- suggestions = options.sort_by { |suggested| levenshtein_distance(namespace.to_s, suggested) }.first(3)
+ suggestions = Rails::Command::Spellchecker.suggest(namespace.to_s, from: options, count: 3)
suggestions.map! { |s| "'#{s}'" }
msg = "Could not find generator '#{namespace}'. ".dup
msg << "Maybe you meant #{ suggestions[0...-1].join(', ')} or #{suggestions[-1]}\n"
diff --git a/railties/test/command/spellchecker_test.rb b/railties/test/command/spellchecker_test.rb
new file mode 100644
index 0000000000..aff50a3e73
--- /dev/null
+++ b/railties/test/command/spellchecker_test.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require "abstract_unit"
+require "rails/command/spellchecker"
+
+class Rails::Command::SpellcheckerTest < ActiveSupport::TestCase
+ test "suggests a word correction from dictionary" do
+ assert_equal %w(thin cgi puma), Rails::Command::Spellchecker.suggest("tin", from: %w(puma thin cgi))
+ end
+end