did_you_mean 0.9.10-java → 0.10.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +13 -19
  4. data/CHANGELOG.md +229 -0
  5. data/Gemfile +4 -7
  6. data/README.md +5 -16
  7. data/Rakefile +35 -33
  8. data/benchmark/jaro_winkler/memory_usage.rb +12 -0
  9. data/benchmark/jaro_winkler/speed.rb +14 -0
  10. data/benchmark/levenshtein/memory_usage.rb +12 -0
  11. data/benchmark/levenshtein/speed.rb +17 -0
  12. data/benchmark/memory_usage.rb +31 -0
  13. data/did_you_mean.gemspec +9 -2
  14. data/evaluation/calculator.rb +122 -0
  15. data/evaluation/dictionary_generator.rb +36 -0
  16. data/evaluation/incorrect_words.yaml +1159 -0
  17. data/ext/did_you_mean/extconf.rb +1 -1
  18. data/ext/did_you_mean/{method_missing.c → method_receiver.c} +1 -1
  19. data/lib/did_you_mean.rb +22 -3
  20. data/lib/did_you_mean/core_ext/name_error.rb +30 -22
  21. data/lib/did_you_mean/core_ext/no_method_error.rb +13 -2
  22. data/lib/did_you_mean/core_ext/rubinius.rb +16 -0
  23. data/lib/did_you_mean/finders.rb +48 -17
  24. data/lib/did_you_mean/finders/method_finder.rb +62 -0
  25. data/lib/did_you_mean/finders/name_error_finders.rb +8 -11
  26. data/lib/did_you_mean/finders/name_error_finders/class_finder.rb +77 -0
  27. data/lib/did_you_mean/finders/name_error_finders/name_finder.rb +18 -0
  28. data/lib/did_you_mean/formatter.rb +20 -0
  29. data/lib/did_you_mean/jaro_winkler.rb +87 -0
  30. data/lib/did_you_mean/test_helper.rb +1 -1
  31. data/lib/did_you_mean/version.rb +1 -1
  32. data/test/core_ext/name_error_extension_test.rb +74 -0
  33. data/test/{no_method_error_extension_test.rb → core_ext/no_method_error_extension_test.rb} +1 -1
  34. data/test/correctable/class_name_test.rb +65 -0
  35. data/test/correctable/method_name_test.rb +84 -0
  36. data/test/{null_finder_test.rb → correctable/uncorrectable_name_test.rb} +3 -7
  37. data/test/correctable/variable_name_test.rb +79 -0
  38. data/test/edit_distance/jaro_winkler_test.rb +30 -0
  39. data/test/test_helper.rb +2 -20
  40. data/test/word_collection_test.rb +76 -12
  41. metadata +58 -56
  42. data/Appraisals +0 -23
  43. data/gemfiles/activerecord_32.gemfile +0 -21
  44. data/gemfiles/activerecord_40.gemfile +0 -21
  45. data/gemfiles/activerecord_41.gemfile +0 -21
  46. data/gemfiles/activerecord_42.gemfile +0 -21
  47. data/gemfiles/activerecord_edge.gemfile +0 -25
  48. data/lib/did_you_mean/finders/name_error_finders/similar_class_finder.rb +0 -50
  49. data/lib/did_you_mean/finders/name_error_finders/similar_name_finder.rb +0 -61
  50. data/lib/did_you_mean/finders/similar_attribute_finder.rb +0 -26
  51. data/lib/did_you_mean/finders/similar_method_finder.rb +0 -34
  52. data/lib/did_you_mean/word_collection.rb +0 -30
  53. data/test/all_test.rb +0 -18
  54. data/test/name_error_extension_test.rb +0 -73
  55. data/test/similar_attribute_finder_test.rb +0 -17
  56. data/test/similar_class_finder_test.rb +0 -85
  57. data/test/similar_method_finder_test.rb +0 -60
  58. data/test/similar_name_finder_test.rb +0 -62
@@ -1,25 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- git "git://github.com/rails/rails.git" do
6
- gem "activerecord", :require => "activerecord"
7
- end
8
-
9
- gem "arel", :github => "rails/arel"
10
-
11
- platforms :ruby do
12
- gem "sqlite3"
13
- end
14
-
15
- platforms :jruby do
16
- gem "activerecord-jdbcsqlite3-adapter"
17
- end
18
-
19
- platforms :rbx do
20
- gem "rubysl", "~> 2.0"
21
- gem "racc"
22
- gem "rubinius-developer_tools"
23
- end
24
-
25
- gemspec :path => "../"
@@ -1,50 +0,0 @@
1
- module DidYouMean
2
- class SimilarClassFinder
3
- include BaseFinder
4
- attr_reader :class_name, :original_message
5
-
6
- def initialize(exception)
7
- @class_name, @original_message = exception.name, exception.original_message
8
- end
9
-
10
- def words
11
- scopes.flat_map do |scope|
12
- scope.constants.map {|name| ConstantName.new(name, scope) }
13
- end
14
- end
15
-
16
- def name_from_message
17
- class_name || /([A-Z]\w*$)/.match(original_message)[0]
18
- end
19
- alias target_word name_from_message
20
-
21
- def similar_words
22
- super.map(&:full_name)
23
- end
24
-
25
- def scopes
26
- @scopes ||= scope_base.size.times.map do |count|
27
- eval(scope_base[0..(- count)].join("::"))
28
- end.reverse << Object
29
- end
30
-
31
- private
32
-
33
- def scope_base
34
- @scope_base ||= (/(([A-Z]\w*::)*)([A-Z]\w*)$/ =~ original_message ? $1 : "").split("::")
35
- end
36
-
37
- class ConstantName < String
38
- attr_reader :scope
39
-
40
- def initialize(str, scope)
41
- super(str.to_s)
42
- @scope = scope.to_s
43
- end
44
-
45
- def full_name
46
- scope == "Object" ? to_s : "#{scope}::#{to_s}"
47
- end
48
- end
49
- end
50
- end
@@ -1,61 +0,0 @@
1
- module DidYouMean
2
- class SimilarNameFinder
3
- include BaseFinder
4
- attr_reader :name, :_methods, :_local_variables, :_instance_variables
5
-
6
- def initialize(exception)
7
- @name = exception.name
8
- @_methods = exception.frame_binding.eval("methods")
9
- @_local_variables = exception.frame_binding.eval("local_variables")
10
- @_instance_variables = exception.frame_binding.eval("instance_variables").map do |name|
11
- name.to_s.tr("@", "")
12
- end
13
- end
14
-
15
- def words
16
- local_variable_names + method_names + instance_variable_names
17
- end
18
-
19
- alias target_word name
20
-
21
- def local_variable_names
22
- _local_variables.map {|word| LocalVariableName.new(word.to_s) }
23
- end
24
-
25
- def similar_local_variables
26
- similar_words.select{|word| word.is_a?(LocalVariableName) }
27
- end
28
-
29
- def method_names
30
- _methods.map {|word| MethodName.new(word.to_s) }
31
- end
32
-
33
- def similar_methods
34
- similar_words.select{|word| word.is_a?(MethodName) }
35
- end
36
-
37
- def instance_variable_names
38
- _instance_variables.map {|word| InstanceVariableName.new(word.to_s) }
39
- end
40
-
41
- def similar_instance_variables
42
- similar_words.select {|word| word.is_a?(InstanceVariableName) }
43
- end
44
-
45
- def format(word)
46
- "#{word.prefix}#{word}"
47
- end
48
-
49
- class MethodName < String
50
- def prefix; "#"; end
51
- end
52
-
53
- class LocalVariableName < String
54
- def prefix; ""; end
55
- end
56
-
57
- class InstanceVariableName < String
58
- def prefix; "@"; end
59
- end
60
- end
61
- end
@@ -1,26 +0,0 @@
1
- module DidYouMean
2
- class SimilarAttributeFinder
3
- include BaseFinder
4
- attr_reader :columns, :attribute_name
5
-
6
- def initialize(exception)
7
- @columns = exception.frame_binding.eval("self.class").columns
8
- @attribute_name = (/unknown attribute(: | ')(\w+)/ =~ exception.original_message) && $2
9
- end
10
-
11
- def words
12
- columns.map(&:name)
13
- end
14
-
15
- alias target_word attribute_name
16
-
17
- def format(column_name)
18
- "%{column}: %{type}" % {
19
- column: column_name,
20
- type: columns.detect{|c| c.name == column_name }.type
21
- }
22
- end
23
- end
24
-
25
- finders["ActiveRecord::UnknownAttributeError"] = SimilarAttributeFinder
26
- end
@@ -1,34 +0,0 @@
1
- module DidYouMean
2
- class SimilarMethodFinder
3
- include BaseFinder
4
- attr_reader :method_name, :receiver
5
-
6
- def initialize(exception)
7
- @method_name, @receiver = exception.name, exception.receiver
8
- end
9
-
10
- def words
11
- method_names = receiver.methods + receiver.singleton_methods
12
- method_names.delete(@method_name)
13
- method_names.uniq
14
- end
15
-
16
- alias target_word method_name
17
-
18
- def format(word)
19
- "#{separator}#{word}"
20
- end
21
-
22
- def class_method?
23
- receiver.is_a? Class
24
- end
25
-
26
- def separator
27
- class_method? ? "." : "#"
28
- end
29
- end
30
-
31
- if RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'jruby'
32
- finders["NoMethodError"] = SimilarMethodFinder
33
- end
34
- end
@@ -1,30 +0,0 @@
1
- require 'did_you_mean/levenshtein'
2
-
3
- module DidYouMean
4
- class WordCollection
5
- include Enumerable
6
- attr_reader :words
7
-
8
- def initialize(words)
9
- @words = words
10
- end
11
-
12
- def each(&block) words.each(&block); end
13
-
14
- def similar_to(target_word)
15
- target_word = target_word.to_s
16
- threshold = threshold(target_word)
17
-
18
- map {|word| [Levenshtein.distance(word.to_s, target_word), word] }
19
- .select {|distance, _| distance <= threshold }
20
- .sort
21
- .map(&:last)
22
- end
23
-
24
- private
25
-
26
- def threshold(word)
27
- (word.size * 0.3).ceil
28
- end
29
- end
30
- end
data/test/all_test.rb DELETED
@@ -1,18 +0,0 @@
1
- require_relative 'null_finder_test'
2
- require_relative 'word_collection_test'
3
- require_relative 'name_error_extension_test'
4
- require_relative 'similar_name_finder_test'
5
-
6
- if defined?(RUBY_ENGINE) && %w(ruby jruby).include?(RUBY_ENGINE)
7
- require_relative 'similar_method_finder_test'
8
- require_relative 'no_method_error_extension_test'
9
- else
10
- puts "didn't run the tests for NoMethodError extension."
11
- puts "running tests for #{RUBY_ENGINE}." if defined?(RUBY_ENGINE)
12
- end
13
-
14
- if defined?(ActiveRecord)
15
- require_relative 'similar_attribute_finder_test'
16
- end
17
-
18
- require_relative 'similar_class_finder_test'
@@ -1,73 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class NameErrorExtensionTest < Minitest::Test
4
- class TestFinder
5
- def initialize(*); end
6
- def did_you_mean?; "Y U SO SLOW?"; end
7
- end
8
-
9
- def setup
10
- @old_finder = DidYouMean.finders["NameError"]
11
- DidYouMean.finders["NameError"] = TestFinder
12
-
13
- @error = assert_raises(NameError){ doesnt_exist }
14
- end
15
-
16
- def teardown
17
- DidYouMean.finders["NameError"] = @old_finder
18
- end
19
-
20
- def test_message
21
- assert_match "Y U SO SLOW?", @error.to_s
22
- assert_match "Y U SO SLOW?", @error.message
23
- end
24
-
25
- def test_to_s_does_not_make_disruptive_changes_to_error_message
26
- error = assert_raises(NameError) do
27
- raise NameError, "uninitialized constant Object".freeze
28
- end
29
-
30
- assert_equal 1, error.to_s.scan("Y U SO SLOW?").count
31
- end
32
- end
33
-
34
- class IgnoreCallersTest < Minitest::Test
35
- class Boomer
36
- def initialize(*)
37
- raise Exception, "finder was created when it shouldn't!"
38
- end
39
- end
40
-
41
- def setup
42
- @org = DidYouMean.finders["NameError"]
43
- DidYouMean.finders["NameError"] = Boomer
44
-
45
- @error = assert_raises(NameError){ doesnt_exist }
46
- end
47
-
48
- def teardown
49
- DidYouMean.finders["NameError"] = @org
50
- end
51
-
52
- def test_ignore_missing_name
53
- assert_nothing_raised { missing_name }
54
- end
55
-
56
- def test_ignore_safe_constantize
57
- assert_nothing_raised { safe_constantize }
58
- end
59
-
60
- private
61
-
62
- def safe_constantize
63
- @error.message
64
- end
65
-
66
- def missing_name
67
- @error.message
68
- end
69
-
70
- def assert_nothing_raised
71
- yield
72
- end
73
- end
@@ -1,17 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class SimilarAttributeFinderTest < Minitest::Test
4
- def setup
5
- @error = assert_raises(ActiveRecord::UnknownAttributeError) do
6
- User.new(flrst_name: "wrong flrst name")
7
- end
8
- end
9
-
10
- def test_similar_words
11
- assert_suggestion @error.finder.similar_words, "first_name"
12
- end
13
-
14
- def test_did_you_mean?
15
- assert_match "Did you mean? first_name: string", @error.did_you_mean?
16
- end
17
- end
@@ -1,85 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class Project
4
- def self.bo0k
5
- Bo0k
6
- end
7
- end
8
-
9
- class Book
10
- class TableOfContents; end
11
-
12
- def tableof_contents
13
- TableofContents
14
- end
15
-
16
- class Page
17
- def tableof_contents
18
- TableofContents
19
- end
20
-
21
- def self.tableof_contents
22
- TableofContents
23
- end
24
- end
25
- end
26
-
27
- class SimpleSimilarClassFinderTest < Minitest::Test
28
- def setup
29
- @error = assert_raises(NameError) { ::Bo0k }
30
- end
31
-
32
- def test_similar_words
33
- assert_suggestion @error.finder.similar_words, "Book"
34
- end
35
- end
36
-
37
- class SimilarClassFinderInsideClassTest < Minitest::Test
38
- def setup
39
- @error = assert_raises(NameError) { Project.bo0k }
40
- end
41
-
42
- def test_similar_words
43
- assert_suggestion @error.finder.similar_words, "Book"
44
- end
45
- end
46
-
47
- class SimilarClassFinderInsideNestedClassTest < Minitest::Test
48
- def setup
49
- @error = assert_raises(NameError) { Book::Page.tableof_contents }
50
- end
51
-
52
- def test_similar_words
53
- assert_suggestion @error.finder.similar_words, "Book::TableOfContents"
54
- end
55
- end
56
-
57
- class SimilarClassFinderForClassWithNamespaceTest < Minitest::Test
58
- def setup
59
- @error = assert_raises(NameError) { ::Book::TableofContents }
60
- end
61
-
62
- def test_similar_words
63
- assert_suggestion @error.finder.similar_words, "Book::TableOfContents"
64
- end
65
- end
66
-
67
- class SimilarClassFinderFromInstanceTest < Minitest::Test
68
- def setup
69
- @error = assert_raises(NameError) { ::Book.new.tableof_contents }
70
- end
71
-
72
- def test_similar_words
73
- assert_suggestion @error.finder.similar_words, "Book::TableOfContents"
74
- end
75
- end
76
-
77
- class SimilarClassFinderFromNestedInstanceTest < Minitest::Test
78
- def setup
79
- @error = assert_raises(NameError) { ::Book::Page.new.tableof_contents }
80
- end
81
-
82
- def test_similar_words
83
- assert_suggestion @error.finder.similar_words, "Book::TableOfContents"
84
- end
85
- end
@@ -1,60 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class SimilarMethodFinderTest < Minitest::Test
4
- class User
5
- def friends; end
6
- def first_name; end
7
- def descendants; end
8
-
9
- protected
10
- def the_protected_method; end
11
-
12
- private
13
- def friend; end
14
- def the_private_method; end
15
-
16
- class << self
17
- def load; end
18
- end
19
- end
20
-
21
- module UserModule
22
- def from_module; end
23
- end
24
-
25
- def setup
26
- user = User.new.extend(UserModule)
27
-
28
- @error_from_instance_method = assert_raises(NoMethodError){ user.flrst_name }
29
- @error_from_private_method = assert_raises(NoMethodError){ user.friend }
30
- @error_from_module_method = assert_raises(NoMethodError){ user.fr0m_module }
31
- @error_from_class_method = assert_raises(NoMethodError){ User.l0ad }
32
- end
33
-
34
- def test_similar_words
35
- assert_suggestion @error_from_instance_method.finder.similar_words, :first_name
36
- assert_suggestion @error_from_private_method.finder.similar_words, :friends
37
- assert_suggestion @error_from_module_method.finder.similar_words, :from_module
38
- assert_suggestion @error_from_class_method.finder.similar_words, :load
39
- end
40
-
41
- def test_did_you_mean?
42
- assert_match "Did you mean? #first_name", @error_from_instance_method.did_you_mean?
43
- assert_match "Did you mean? #friends", @error_from_private_method.did_you_mean?
44
- assert_match "Did you mean? #from_module", @error_from_module_method.did_you_mean?
45
- assert_match "Did you mean? .load", @error_from_class_method.did_you_mean?
46
- end
47
-
48
- def test_similar_words_for_long_method_name
49
- error = assert_raises(NoMethodError){ User.new.dependents }
50
- assert_suggestion error.finder.similar_words, :descendants
51
- end
52
-
53
- def test_private_methods_should_not_be_suggested
54
- error = assert_raises(NoMethodError){ User.new.the_protected_method }
55
- refute_includes error.finder.similar_words, 'the_protected_method'
56
-
57
- error = assert_raises(NoMethodError){ User.new.the_private_method }
58
- refute_includes error.finder.similar_words, 'the_private_method'
59
- end
60
- end