did_you_mean 0.9.10-java → 0.10.0-java

Sign up to get free protection for your applications and to get access to all the features.
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