did_you_mean 1.1.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +1 -0
- data/CHANGELOG.md +110 -28
- data/README.md +52 -13
- data/Rakefile +4 -15
- data/did_you_mean.gemspec +2 -2
- data/doc/CHANGELOG.md.erb +1 -1
- data/lib/did_you_mean/core_ext/name_error.rb +6 -6
- data/lib/did_you_mean/experimental/initializer_name_correction.rb +2 -0
- data/lib/did_you_mean/experimental/ivar_name_correction.rb +36 -9
- data/lib/did_you_mean/experimental.rb +0 -15
- data/lib/did_you_mean/formatters/plain_formatter.rb +33 -0
- data/lib/did_you_mean/formatters/verbose_formatter.rb +49 -0
- data/lib/did_you_mean/spell_checkers/key_error_checker.rb +14 -0
- data/lib/did_you_mean/spell_checkers/method_name_checker.rb +32 -1
- data/lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb +6 -2
- data/lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb +57 -2
- data/lib/did_you_mean/spell_checkers/name_error_checkers.rb +2 -6
- data/lib/did_you_mean/verbose.rb +4 -0
- data/lib/did_you_mean/version.rb +1 -1
- data/lib/did_you_mean.rb +94 -4
- data/test/core_ext/name_error_extension_test.rb +9 -31
- data/test/edit_distance/jaro_winkler_test.rb +6 -1
- data/test/fixtures/book.rb +4 -0
- data/test/spell_checking/{class_name_test.rb → class_name_check_test.rb} +13 -1
- data/test/spell_checking/key_name_check_test.rb +44 -0
- data/test/spell_checking/{method_name_test.rb → method_name_check_test.rb} +38 -1
- data/test/spell_checking/{uncorrectable_name_test.rb → uncorrectable_name_check_test.rb} +1 -1
- data/test/spell_checking/{variable_name_test.rb → variable_name_check_test.rb} +40 -1
- data/test/verbose_formatter_test.rb +7 -1
- data/tmp/.keep +0 -0
- metadata +21 -20
- data/evaluation/calculator.rb +0 -105
- data/evaluation/dictionary_generator.rb +0 -37
- data/evaluation/incorrect_words.yaml +0 -1159
- data/lib/did_you_mean/experimental/key_error_name_correction.rb +0 -32
- data/lib/did_you_mean/formatter.rb +0 -16
- data/lib/did_you_mean/verbose_formatter.rb +0 -16
- data/test/experimental/key_error_test.rb +0 -15
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module DidYouMean
|
4
|
+
# The +DidYouMean::VerboseFormatter+ uses extra empty lines to make the
|
5
|
+
# suggestion stand out more in the error message.
|
6
|
+
#
|
7
|
+
# In order to activate the verbose formatter,
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# OBject
|
12
|
+
# # => NameError: uninitialized constant OBject
|
13
|
+
# # Did you mean? Object
|
14
|
+
#
|
15
|
+
# require 'did_you_mean/verbose'
|
16
|
+
#
|
17
|
+
# OBject
|
18
|
+
# # => NameError: uninitialized constant OBject
|
19
|
+
# #
|
20
|
+
# # Did you mean? Object
|
21
|
+
# #
|
22
|
+
#
|
23
|
+
class VerboseFormatter
|
24
|
+
|
25
|
+
# Returns a human readable string that contains +corrections+. This
|
26
|
+
# formatter is designed to be less verbose to not take too much screen
|
27
|
+
# space while being helpful enough to the user.
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
#
|
31
|
+
# formatter = DidYouMean::PlainFormatter.new
|
32
|
+
#
|
33
|
+
# puts formatter.message_for(["methods", "method"])
|
34
|
+
#
|
35
|
+
#
|
36
|
+
# Did you mean? methods
|
37
|
+
# method
|
38
|
+
#
|
39
|
+
# # => nil
|
40
|
+
#
|
41
|
+
def message_for(corrections)
|
42
|
+
return "" if corrections.empty?
|
43
|
+
|
44
|
+
output = "\n\n Did you mean? ".dup
|
45
|
+
output << corrections.join("\n ")
|
46
|
+
output << "\n "
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "did_you_mean/spell_checker"
|
2
|
+
|
3
|
+
module DidYouMean
|
4
|
+
class KeyErrorChecker
|
5
|
+
def initialize(key_error)
|
6
|
+
@key = key_error.key
|
7
|
+
@keys = key_error.receiver.keys
|
8
|
+
end
|
9
|
+
|
10
|
+
def corrections
|
11
|
+
@corrections ||= SpellChecker.new(dictionary: @keys).correct(@key).map(&:inspect)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "did_you_mean/spell_checker"
|
2
|
+
|
1
3
|
module DidYouMean
|
2
4
|
class MethodNameChecker
|
3
5
|
attr_reader :method_name, :receiver
|
@@ -5,6 +7,35 @@ module DidYouMean
|
|
5
7
|
NAMES_TO_EXCLUDE = { NilClass => nil.methods }
|
6
8
|
NAMES_TO_EXCLUDE.default = []
|
7
9
|
|
10
|
+
# +MethodNameChecker::RB_RESERVED_WORDS+ is the list of reserved words in
|
11
|
+
# Ruby that take an argument. Unlike
|
12
|
+
# +VariableNameChecker::RB_RESERVED_WORDS+, those reserved words reqquires
|
13
|
+
# an argument, and a +NoMethodError+ is raised due to the presence of the
|
14
|
+
# argument.
|
15
|
+
#
|
16
|
+
# The +MethodNameChecker+ will use this list to suggest a reversed word if
|
17
|
+
# a +NoMethodError+ is raised and found closest matches.
|
18
|
+
#
|
19
|
+
# Also see +VariableNameChecker::RB_RESERVED_WORDS+.
|
20
|
+
RB_RESERVED_WORDS = %i(
|
21
|
+
alias
|
22
|
+
case
|
23
|
+
def
|
24
|
+
defined?
|
25
|
+
elsif
|
26
|
+
end
|
27
|
+
ensure
|
28
|
+
for
|
29
|
+
rescue
|
30
|
+
super
|
31
|
+
undef
|
32
|
+
unless
|
33
|
+
until
|
34
|
+
when
|
35
|
+
while
|
36
|
+
yield
|
37
|
+
)
|
38
|
+
|
8
39
|
def initialize(exception)
|
9
40
|
@method_name = exception.name
|
10
41
|
@receiver = exception.receiver
|
@@ -12,7 +43,7 @@ module DidYouMean
|
|
12
43
|
end
|
13
44
|
|
14
45
|
def corrections
|
15
|
-
@corrections ||= SpellChecker.new(dictionary: method_names).correct(method_name) - NAMES_TO_EXCLUDE[@receiver.class]
|
46
|
+
@corrections ||= SpellChecker.new(dictionary: RB_RESERVED_WORDS + method_names).correct(method_name) - NAMES_TO_EXCLUDE[@receiver.class]
|
16
47
|
end
|
17
48
|
|
18
49
|
def method_names
|
@@ -1,16 +1,20 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
require 'delegate'
|
3
|
+
require "did_you_mean/spell_checker"
|
3
4
|
|
4
5
|
module DidYouMean
|
5
6
|
class ClassNameChecker
|
6
7
|
attr_reader :class_name
|
7
8
|
|
8
9
|
def initialize(exception)
|
9
|
-
@class_name, @receiver = exception.name, exception.receiver
|
10
|
+
@class_name, @receiver, @original_message = exception.name, exception.receiver, exception.original_message
|
10
11
|
end
|
11
12
|
|
12
13
|
def corrections
|
13
|
-
@corrections ||= SpellChecker.new(dictionary: class_names)
|
14
|
+
@corrections ||= SpellChecker.new(dictionary: class_names)
|
15
|
+
.correct(class_name)
|
16
|
+
.map(&:full_name)
|
17
|
+
.reject {|qualified_name| @original_message.include?(qualified_name) }
|
14
18
|
end
|
15
19
|
|
16
20
|
def class_names
|
@@ -1,12 +1,67 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
|
+
require "did_you_mean/spell_checker"
|
4
|
+
|
3
5
|
module DidYouMean
|
4
6
|
class VariableNameChecker
|
5
7
|
attr_reader :name, :method_names, :lvar_names, :ivar_names, :cvar_names
|
6
8
|
|
7
|
-
NAMES_TO_EXCLUDE = { 'foo' => [:fork] }
|
9
|
+
NAMES_TO_EXCLUDE = { 'foo' => [:fork, :for] }
|
8
10
|
NAMES_TO_EXCLUDE.default = []
|
9
11
|
|
12
|
+
# +VariableNameChecker::RB_RESERVED_WORDS+ is the list of all reserved
|
13
|
+
# words in Ruby. They could be declared like methods are, and a typo would
|
14
|
+
# cause Ruby to raise a +NameError+ because of the way they are declared.
|
15
|
+
#
|
16
|
+
# The +:VariableNameChecker+ will use this list to suggest a reversed word
|
17
|
+
# if a +NameError+ is raised and found closest matches, excluding:
|
18
|
+
#
|
19
|
+
# * +do+
|
20
|
+
# * +if+
|
21
|
+
# * +in+
|
22
|
+
# * +or+
|
23
|
+
#
|
24
|
+
# Also see +MethodNameChecker::RB_RESERVED_WORDS+.
|
25
|
+
RB_RESERVED_WORDS = %i(
|
26
|
+
BEGIN
|
27
|
+
END
|
28
|
+
alias
|
29
|
+
and
|
30
|
+
begin
|
31
|
+
break
|
32
|
+
case
|
33
|
+
class
|
34
|
+
def
|
35
|
+
defined?
|
36
|
+
else
|
37
|
+
elsif
|
38
|
+
end
|
39
|
+
ensure
|
40
|
+
false
|
41
|
+
for
|
42
|
+
module
|
43
|
+
next
|
44
|
+
nil
|
45
|
+
not
|
46
|
+
redo
|
47
|
+
rescue
|
48
|
+
retry
|
49
|
+
return
|
50
|
+
self
|
51
|
+
super
|
52
|
+
then
|
53
|
+
true
|
54
|
+
undef
|
55
|
+
unless
|
56
|
+
until
|
57
|
+
when
|
58
|
+
while
|
59
|
+
yield
|
60
|
+
__LINE__
|
61
|
+
__FILE__
|
62
|
+
__ENCODING__
|
63
|
+
)
|
64
|
+
|
10
65
|
def initialize(exception)
|
11
66
|
@name = exception.name.to_s.tr("@", "")
|
12
67
|
@lvar_names = exception.respond_to?(:local_variables) ? exception.local_variables : []
|
@@ -20,7 +75,7 @@ module DidYouMean
|
|
20
75
|
|
21
76
|
def corrections
|
22
77
|
@corrections ||= SpellChecker
|
23
|
-
.new(dictionary: (lvar_names + method_names + ivar_names + cvar_names))
|
78
|
+
.new(dictionary: (RB_RESERVED_WORDS + lvar_names + method_names + ivar_names + cvar_names))
|
24
79
|
.correct(name) - NAMES_TO_EXCLUDE[@name]
|
25
80
|
end
|
26
81
|
end
|
@@ -2,12 +2,8 @@ require 'did_you_mean/spell_checkers/name_error_checkers/class_name_checker'
|
|
2
2
|
require 'did_you_mean/spell_checkers/name_error_checkers/variable_name_checker'
|
3
3
|
|
4
4
|
module DidYouMean
|
5
|
-
|
6
|
-
def
|
7
|
-
raise "Do not include this module since it overrides Class.new method."
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.new(exception)
|
5
|
+
class << (NameErrorCheckers = Object.new)
|
6
|
+
def new(exception)
|
11
7
|
case exception.original_message
|
12
8
|
when /uninitialized constant/
|
13
9
|
ClassNameChecker
|
data/lib/did_you_mean/version.rb
CHANGED
data/lib/did_you_mean.rb
CHANGED
@@ -4,16 +4,106 @@ require "did_you_mean/core_ext/name_error"
|
|
4
4
|
require "did_you_mean/spell_checker"
|
5
5
|
require 'did_you_mean/spell_checkers/name_error_checkers'
|
6
6
|
require 'did_you_mean/spell_checkers/method_name_checker'
|
7
|
+
require 'did_you_mean/spell_checkers/key_error_checker'
|
7
8
|
require 'did_you_mean/spell_checkers/null_checker'
|
8
9
|
|
9
|
-
require "did_you_mean/
|
10
|
+
require "did_you_mean/formatters/plain_formatter"
|
10
11
|
|
12
|
+
# The +DidYouMean+ gem adds functionality to suggest possible method/class
|
13
|
+
# names upon errors such as +NameError+ and +NoMethodError+. In Ruby 2.3 or
|
14
|
+
# later, it is automatically activated during startup.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
#
|
18
|
+
# methosd
|
19
|
+
# # => NameError: undefined local variable or method `methosd' for main:Object
|
20
|
+
# # Did you mean? methods
|
21
|
+
# # method
|
22
|
+
#
|
23
|
+
# OBject
|
24
|
+
# # => NameError: uninitialized constant OBject
|
25
|
+
# # Did you mean? Object
|
26
|
+
#
|
27
|
+
# @full_name = "Yuki Nishijima"
|
28
|
+
# first_name, last_name = full_name.split(" ")
|
29
|
+
# # => NameError: undefined local variable or method `full_name' for main:Object
|
30
|
+
# # Did you mean? @full_name
|
31
|
+
#
|
32
|
+
# @@full_name = "Yuki Nishijima"
|
33
|
+
# @@full_anme
|
34
|
+
# # => NameError: uninitialized class variable @@full_anme in Object
|
35
|
+
# # Did you mean? @@full_name
|
36
|
+
#
|
37
|
+
# full_name = "Yuki Nishijima"
|
38
|
+
# full_name.starts_with?("Y")
|
39
|
+
# # => NoMethodError: undefined method `starts_with?' for "Yuki Nishijima":String
|
40
|
+
# # Did you mean? start_with?
|
41
|
+
#
|
42
|
+
# hash = {foo: 1, bar: 2, baz: 3}
|
43
|
+
# hash.fetch(:fooo)
|
44
|
+
# # => KeyError: key not found: :fooo
|
45
|
+
# # Did you mean? :foo
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# == Disabling +did_you_mean+
|
49
|
+
#
|
50
|
+
# Occasionally, you may want to disable the +did_you_mean+ gem for e.g.
|
51
|
+
# debugging issues in the error object itself. You can disable it entirely by
|
52
|
+
# specifying +--disable-did_you_mean+ option to the +ruby+ command:
|
53
|
+
#
|
54
|
+
# $ ruby --disable-did_you_mean -e "1.zeor?"
|
55
|
+
# -e:1:in `<main>': undefined method `zeor?' for 1:Integer (NameError)
|
56
|
+
#
|
57
|
+
# When you do not have direct access to the +ruby+ command (e.g.
|
58
|
+
# +rails console+, +irb+), you could applyoptions using the +RUBYOPT+
|
59
|
+
# environment variable:
|
60
|
+
#
|
61
|
+
# $ RUBYOPT='--disable-did_you_mean' irb
|
62
|
+
# irb:0> 1.zeor?
|
63
|
+
# # => NoMethodError (undefined method `zeor?' for 1:Integer)
|
64
|
+
#
|
65
|
+
#
|
66
|
+
# == Getting the original error message
|
67
|
+
#
|
68
|
+
# Sometimes, you do not want to disable the gem entirely, but need to get the
|
69
|
+
# original error message without suggestions (e.g. testing). In this case, you
|
70
|
+
# could use the +#original_message+ method on the error object:
|
71
|
+
#
|
72
|
+
# no_method_error = begin
|
73
|
+
# 1.zeor?
|
74
|
+
# rescue NoMethodError => error
|
75
|
+
# error
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# no_method_error.message
|
79
|
+
# # => NoMethodError (undefined method `zeor?' for 1:Integer)
|
80
|
+
# # Did you mean? zero?
|
81
|
+
#
|
82
|
+
# no_method_error.original_message
|
83
|
+
# # => NoMethodError (undefined method `zeor?' for 1:Integer)
|
84
|
+
#
|
11
85
|
module DidYouMean
|
12
|
-
|
13
|
-
|
86
|
+
# Map of error types and spell checker objects.
|
14
87
|
SPELL_CHECKERS = Hash.new(NullChecker)
|
88
|
+
|
15
89
|
SPELL_CHECKERS.merge!({
|
16
90
|
"NameError" => NameErrorCheckers,
|
17
|
-
"NoMethodError" => MethodNameChecker
|
91
|
+
"NoMethodError" => MethodNameChecker,
|
92
|
+
"KeyError" => KeyErrorChecker
|
18
93
|
})
|
94
|
+
|
95
|
+
NameError.prepend DidYouMean::Correctable
|
96
|
+
KeyError.prepend DidYouMean::Correctable
|
97
|
+
|
98
|
+
# Returns the currenctly set formatter. By default, it is set to +DidYouMean::Formatter+.
|
99
|
+
def self.formatter
|
100
|
+
@@formatter
|
101
|
+
end
|
102
|
+
|
103
|
+
# Updates the primary formatter used to format the suggestions.
|
104
|
+
def self.formatter=(formatter)
|
105
|
+
@@formatter = formatter
|
106
|
+
end
|
107
|
+
|
108
|
+
self.formatter = PlainFormatter.new
|
19
109
|
end
|
@@ -20,7 +20,7 @@ class NameErrorExtensionTest < Minitest::Test
|
|
20
20
|
|
21
21
|
def test_message
|
22
22
|
message = <<~MESSAGE.chomp
|
23
|
-
undefined local variable or method `doesnt_exist' for #{
|
23
|
+
undefined local variable or method `doesnt_exist' for #{to_s}
|
24
24
|
Did you mean? does_exist
|
25
25
|
MESSAGE
|
26
26
|
|
@@ -36,38 +36,16 @@ class NameErrorExtensionTest < Minitest::Test
|
|
36
36
|
error.to_s
|
37
37
|
assert_equal 1, error.to_s.scan("Did you mean?").count
|
38
38
|
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class IgnoreCallersTest < Minitest::Test
|
42
|
-
SPELL_CHECKERS = DidYouMean::SPELL_CHECKERS
|
43
|
-
|
44
|
-
class Boomer
|
45
|
-
def initialize(*)
|
46
|
-
raise Exception, "spell checker was created when it shouldn't!"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def setup
|
51
|
-
@org, SPELL_CHECKERS['NameError'] = SPELL_CHECKERS['NameError'], Boomer
|
52
|
-
DidYouMean::IGNORED_CALLERS << /( |`)do_not_correct_typo'/
|
53
|
-
|
54
|
-
@error = assert_raises(NameError){ doesnt_exist }
|
55
|
-
end
|
56
|
-
|
57
|
-
def teardown
|
58
|
-
SPELL_CHECKERS['NameError'] = @org
|
59
|
-
DidYouMean::IGNORED_CALLERS.clear
|
60
|
-
end
|
61
|
-
|
62
|
-
def test_ignore
|
63
|
-
assert_nothing_raised { do_not_correct_typo }
|
64
|
-
end
|
65
39
|
|
66
|
-
|
40
|
+
def test_correctable_error_objects_are_dumpable
|
41
|
+
error = begin
|
42
|
+
File.open('./tmp/.keep').sizee
|
43
|
+
rescue NoMethodError => e
|
44
|
+
e
|
45
|
+
end
|
67
46
|
|
68
|
-
|
47
|
+
error.to_s
|
69
48
|
|
70
|
-
|
71
|
-
yield
|
49
|
+
assert_equal "undefined method `sizee' for #<File:./tmp/.keep>", Marshal.load(Marshal.dump(error)).original_message
|
72
50
|
end
|
73
51
|
end
|
@@ -1,6 +1,11 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
1
|
require 'test_helper'
|
3
2
|
|
3
|
+
# These tests were originally written by Jian Weihang (簡煒航) as part of his work
|
4
|
+
# on the jaro_winkler gem. The original code could be found here:
|
5
|
+
# https://github.com/tonytonyjan/jaro_winkler/blob/9bd12421/spec/jaro_winkler_spec.rb
|
6
|
+
#
|
7
|
+
# Copyright (c) 2014 Jian Weihang
|
8
|
+
|
4
9
|
class JaroWinklerTest < Minitest::Test
|
5
10
|
def test_jaro_winkler_distance
|
6
11
|
assert_distance 0.9667, 'henka', 'henkan'
|
@@ -27,7 +27,7 @@ class Book
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
class
|
30
|
+
class ClassNameCheckTest < Minitest::Test
|
31
31
|
def test_corrections
|
32
32
|
error = assert_raises(NameError) { ::Bo0k }
|
33
33
|
assert_correction "Book", error.corrections
|
@@ -62,4 +62,16 @@ class ClassNameTest < Minitest::Test
|
|
62
62
|
error = assert_raises(NameError) { ::Book::Page.new.tableof_contents }
|
63
63
|
assert_correction "Book::TableOfContents", error.corrections
|
64
64
|
end
|
65
|
+
|
66
|
+
def test_does_not_suggest_user_input
|
67
|
+
error = assert_raises(NameError) { ::Book::Cover }
|
68
|
+
|
69
|
+
# This is a weird require, but in a multi-threaded condition, a constant may
|
70
|
+
# be loaded between when a NameError occurred and when the spell checker
|
71
|
+
# attemps to find a possible suggestion. The manual require here simulates
|
72
|
+
# a race condition a single test.
|
73
|
+
require_relative '../fixtures/book'
|
74
|
+
|
75
|
+
assert_empty error.corrections
|
76
|
+
end
|
65
77
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class KeyNameCheckTest < Minitest::Test
|
4
|
+
def test_corrects_hash_key_name_with_fetch
|
5
|
+
hash = { "foo" => 1, bar: 2 }
|
6
|
+
|
7
|
+
error = assert_raises(KeyError) { hash.fetch(:bax) }
|
8
|
+
assert_correction ":bar", error.corrections
|
9
|
+
assert_match "Did you mean? :bar", error.to_s
|
10
|
+
|
11
|
+
error = assert_raises(KeyError) { hash.fetch("fooo") }
|
12
|
+
assert_correction %("foo"), error.corrections
|
13
|
+
assert_match %(Did you mean? "foo"), error.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_corrects_hash_key_name_with_fetch_values
|
17
|
+
hash = { "foo" => 1, bar: 2 }
|
18
|
+
|
19
|
+
error = assert_raises(KeyError) { hash.fetch_values("foo", :bar, :bax) }
|
20
|
+
assert_correction ":bar", error.corrections
|
21
|
+
assert_match "Did you mean? :bar", error.to_s
|
22
|
+
|
23
|
+
error = assert_raises(KeyError) { hash.fetch_values("foo", :bar, "fooo") }
|
24
|
+
assert_correction %("foo"), error.corrections
|
25
|
+
assert_match %(Did you mean? "foo"), error.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_corrects_sprintf_key_name
|
29
|
+
error = assert_raises(KeyError) { sprintf("%<foo>d", {fooo: 1}) }
|
30
|
+
assert_correction ":fooo", error.corrections
|
31
|
+
assert_match "Did you mean? :fooo", error.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_corrects_env_key_name
|
35
|
+
ENV["FOO"] = "1"
|
36
|
+
ENV["BAR"] = "2"
|
37
|
+
error = assert_raises(KeyError) { ENV.fetch("BAX") }
|
38
|
+
assert_correction %("BAR"), error.corrections
|
39
|
+
assert_match %(Did you mean? "BAR"), error.to_s
|
40
|
+
ensure
|
41
|
+
ENV.delete("FOO")
|
42
|
+
ENV.delete("BAR")
|
43
|
+
end
|
44
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class MethodNameCheckTest < Minitest::Test
|
4
4
|
class User
|
5
5
|
def friends; end
|
6
6
|
def first_name; end
|
@@ -9,6 +9,12 @@ class MethodNameTest < Minitest::Test
|
|
9
9
|
raiae NoMethodError
|
10
10
|
end
|
11
11
|
|
12
|
+
def raise_no_method_error
|
13
|
+
self.firstname
|
14
|
+
rescue NoMethodError => e
|
15
|
+
raise e, e.message, e.backtrace
|
16
|
+
end
|
17
|
+
|
12
18
|
protected
|
13
19
|
def the_protected_method; end
|
14
20
|
|
@@ -86,4 +92,35 @@ class MethodNameTest < Minitest::Test
|
|
86
92
|
ensure
|
87
93
|
NilClass.class_eval { undef empty? }
|
88
94
|
end
|
95
|
+
|
96
|
+
def test_does_not_append_suggestions_twice
|
97
|
+
error = assert_raises NoMethodError do
|
98
|
+
begin
|
99
|
+
@user.firstname
|
100
|
+
rescue NoMethodError => e
|
101
|
+
raise e, e.message, e.backtrace
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
assert_equal 1, error.to_s.scan(/Did you mean/).count
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_does_not_append_suggestions_three_times
|
109
|
+
error = assert_raises NoMethodError do
|
110
|
+
begin
|
111
|
+
@user.raise_no_method_error
|
112
|
+
rescue NoMethodError => e
|
113
|
+
raise e, e.message, e.backtrace
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
assert_equal 1, error.to_s.scan(/Did you mean/).count
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_suggests_yield
|
121
|
+
error = assert_raises(NoMethodError) { yeild(1) }
|
122
|
+
|
123
|
+
assert_correction :yield, error.corrections
|
124
|
+
assert_match "Did you mean? yield", error.to_s
|
125
|
+
end
|
89
126
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class VariableNameCheckTest < Minitest::Test
|
4
4
|
class User
|
5
5
|
def initialize
|
6
6
|
@email_address = 'email_address@address.net'
|
@@ -57,6 +57,45 @@ class VariableNameTest < Minitest::Test
|
|
57
57
|
assert_match "Did you mean? person", error.to_s
|
58
58
|
end
|
59
59
|
|
60
|
+
def test_corrections_include_ruby_predefined_objects
|
61
|
+
some_var = nil
|
62
|
+
|
63
|
+
false_error = assert_raises(NameError) do
|
64
|
+
some_var = fals
|
65
|
+
end
|
66
|
+
|
67
|
+
true_error = assert_raises(NameError) do
|
68
|
+
some_var = treu
|
69
|
+
end
|
70
|
+
|
71
|
+
nil_error = assert_raises(NameError) do
|
72
|
+
some_var = nul
|
73
|
+
end
|
74
|
+
|
75
|
+
file_error = assert_raises(NameError) do
|
76
|
+
__FIEL__
|
77
|
+
end
|
78
|
+
|
79
|
+
assert_correction :false, false_error.corrections
|
80
|
+
assert_match "Did you mean? false", false_error.to_s
|
81
|
+
|
82
|
+
assert_correction :true, true_error.corrections
|
83
|
+
assert_match "Did you mean? true", true_error.to_s
|
84
|
+
|
85
|
+
assert_correction :nil, nil_error.corrections
|
86
|
+
assert_match "Did you mean? nil", nil_error.to_s
|
87
|
+
|
88
|
+
assert_correction :__FILE__, file_error.corrections
|
89
|
+
assert_match "Did you mean? __FILE__", file_error.to_s
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_suggests_yield
|
93
|
+
error = assert_raises(NameError) { yeild }
|
94
|
+
|
95
|
+
assert_correction :yield, error.corrections
|
96
|
+
assert_match "Did you mean? yield", error.to_s
|
97
|
+
end
|
98
|
+
|
60
99
|
def test_corrections_include_instance_variable_name
|
61
100
|
error = assert_raises(NameError){ @user.to_s }
|
62
101
|
|
@@ -2,13 +2,19 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class VerboseFormatterTest < Minitest::Test
|
4
4
|
def setup
|
5
|
+
require 'did_you_mean/verbose'
|
6
|
+
|
5
7
|
does_exist = does_exist = nil
|
6
8
|
@error = assert_raises(NameError){ doesnt_exist }
|
7
9
|
end
|
8
10
|
|
11
|
+
def teardown
|
12
|
+
DidYouMean.formatter = DidYouMean::PlainFormatter.new
|
13
|
+
end
|
14
|
+
|
9
15
|
def test_message
|
10
16
|
assert_equal <<~MESSAGE.chomp, @error.message
|
11
|
-
undefined local variable or method `doesnt_exist' for #{
|
17
|
+
undefined local variable or method `doesnt_exist' for #{to_s}
|
12
18
|
|
13
19
|
Did you mean? does_exist
|
14
20
|
|
data/tmp/.keep
ADDED
File without changes
|