did_you_mean 1.0.0.rc1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 60c129eec72ca04e09a5f0514c53156b27f309e2
4
- data.tar.gz: c0f1132a91404efafe5919a9144eda26a779d7be
3
+ metadata.gz: 4765e62fea49eb8f8863c01825a7ec89b1be951e
4
+ data.tar.gz: 4c993cb9c366008086539cf047ba7a81eddf7450
5
5
  SHA512:
6
- metadata.gz: 34f6395d7a241ab9bc18aac2292ea59a4677bfffc44d6ed57db26b0c72cb91f5abfe9945a8bc86c89de29144e6d571218fa249c0de51a5a264069a2fd63b622f
7
- data.tar.gz: 8732e1821ba7d7834b90e58f77d094ba3caf36093a21f9aba37bf64e4c0c14fabab01eff7be5c1325a59bf3b29a79a3aa252556789763975bb4e4602b00ae52b
6
+ metadata.gz: e68859b53e91e551e698168bdb06a1ad0034e5a12457ca974a2d2147504f2627344af672de248c156d4a8df64afb0e298bf523b6242c1192f84f5cea94a9bcb2
7
+ data.tar.gz: 16f2eb958b3494439251ae0c33fb5f924370f7fab9632bbddaa062b8d6023214247bd98af7b0c806f1b0a17aa3e059a986a048bba1b93141dcfb658b1c96d84d
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
- script: bundle exec rake test
2
+ script: bundle exec rake
3
3
  cache: bundler
4
4
  sudo: false
5
5
 
data/Rakefile CHANGED
@@ -3,12 +3,32 @@ require 'rake/testtask'
3
3
 
4
4
  Rake::TestTask.new do |task|
5
5
  task.libs << "test"
6
- task.pattern = 'test/**/*_test.rb'
6
+
7
+ task.test_files = Dir['test/**/*_test.rb'].reject do |path|
8
+ /(verbose_formatter|extra_features)/ =~ path
9
+ end
10
+
11
+ task.verbose = true
12
+ task.warning = true
13
+ end
14
+
15
+ Rake::TestTask.new("test:verbose_formatter") do |task|
16
+ task.libs << "test"
17
+ task.pattern = 'test/verbose_formatter_test.rb'
18
+ task.verbose = true
19
+ task.warning = true
20
+ task.ruby_opts << "-rdid_you_mean/verbose_formatter"
21
+ end
22
+
23
+ Rake::TestTask.new("test:extra_features") do |task|
24
+ task.libs << "test"
25
+ task.pattern = 'test/extra_features/**/*_test.rb'
7
26
  task.verbose = true
8
27
  task.warning = true
28
+ task.ruby_opts << "-rdid_you_mean/extra_features"
9
29
  end
10
30
 
11
- task default: :test
31
+ task default: %i(test test:verbose_formatter test:extra_features)
12
32
 
13
33
  namespace :test do
14
34
  namespace :accuracy do
@@ -9,14 +9,6 @@ require 'did_you_mean/spell_checkers/null_checker'
9
9
  require "did_you_mean/formatter"
10
10
 
11
11
  module DidYouMean
12
- TRACE = TracePoint.new(:raise) do |tp|
13
- e = tp.raised_exception
14
-
15
- if SPELL_CHECKERS.include?(e.class.to_s) && !e.instance_variable_defined?(:@frame_binding)
16
- e.instance_variable_set(:@frame_binding, tp.binding)
17
- end
18
- end
19
-
20
12
  IGNORED_CALLERS = []
21
13
 
22
14
  SPELL_CHECKERS = Hash.new(NullChecker)
@@ -0,0 +1,16 @@
1
+ require 'did_you_mean'
2
+
3
+ module DidYouMean
4
+ TRACE = TracePoint.trace(:raise) do |tp|
5
+ e = tp.raised_exception
6
+
7
+ if SPELL_CHECKERS.include?(e.class.to_s) && !e.instance_variable_defined?(:@frame_binding)
8
+ e.instance_variable_set(:@frame_binding, tp.binding)
9
+ end
10
+ end
11
+
12
+ NameError.send(:attr, :frame_binding)
13
+ end
14
+
15
+ require 'did_you_mean/extra_features/initializer_name_correction'
16
+ require 'did_you_mean/extra_features/ivar_name_correction'
@@ -0,0 +1,18 @@
1
+ # -*- frozen-string-literal: true -*-
2
+
3
+ module DidYouMean
4
+ module ExtraFeatures
5
+ module InitializerNameCorrection
6
+ def method_added(name)
7
+ super
8
+
9
+ distance = Levenshtein.distance(name.to_s, 'initialize')
10
+ if distance != 0 && distance <= 2
11
+ warn "warning: #{name} might be misspelled, perhaps you meant initialize?"
12
+ end
13
+ end
14
+ end
15
+
16
+ ::Class.prepend(InitializerNameCorrection)
17
+ end
18
+ end
@@ -0,0 +1,43 @@
1
+ module DidYouMean
2
+ module ExtraFeatures
3
+ module IvarNameCorrectable
4
+ REPLS = {
5
+ "(irb)" => -> { Readline::HISTORY.to_a.last }
6
+ }
7
+
8
+ def initialize(no_method_error)
9
+ super
10
+
11
+ @location = no_method_error.backtrace_locations.first
12
+ @ivar_names = no_method_error.frame_binding.receiver.instance_variables
13
+ end
14
+
15
+ def candidates
16
+ super.merge(receiver_name.to_s => @ivar_names)
17
+ end
18
+
19
+ private
20
+
21
+ def receiver_name
22
+ return unless receiver.nil?
23
+
24
+ abs_path = @location.absolute_path
25
+ lineno = @location.lineno
26
+
27
+ /@(\w+)*\.#{method_name}/ =~ line(abs_path, lineno).to_s && $1
28
+ end
29
+
30
+ def line(abs_path, lineno)
31
+ if REPLS[abs_path]
32
+ REPLS[abs_path].call
33
+ elsif File.exist?(abs_path)
34
+ File.open(abs_path) do |file|
35
+ file.detect { file.lineno == lineno }
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ SPELL_CHECKERS['NoMethodError'].prepend(IvarNameCorrectable)
42
+ end
43
+ end
@@ -9,6 +9,7 @@ module DidYouMean
9
9
  m = 0.0
10
10
  t = 0.0
11
11
  range = (length2 / 2).floor - 1
12
+ range = 0 if range < 0
12
13
  flags1 = 0
13
14
  flags2 = 0
14
15
 
@@ -16,11 +16,13 @@ module DidYouMean
16
16
 
17
17
  # Correct mistypes
18
18
  threshold = (input.length * 0.25).ceil
19
- corrections = seed.select {|c| Levenshtein.distance(normalize(c), input) <= threshold }
19
+ has_mistype = seed.rindex {|c| Levenshtein.distance(normalize(c), input) <= threshold }
20
20
 
21
- # Correct misspells
22
- if corrections.empty?
23
- corrections = seed.select do |candidate|
21
+ corrections = if has_mistype
22
+ seed.take(has_mistype + 1)
23
+ else
24
+ # Correct misspells
25
+ seed.select do |candidate|
24
26
  candidate = normalize(candidate)
25
27
  length = input.length < candidate.length ? input.length : candidate.length
26
28
 
@@ -6,6 +6,7 @@ module DidYouMean
6
6
  def initialize(exception)
7
7
  @method_name = exception.name
8
8
  @receiver = exception.receiver
9
+ @has_args = !exception.args&.empty?
9
10
  end
10
11
 
11
12
  def candidates
@@ -13,48 +14,11 @@ module DidYouMean
13
14
  end
14
15
 
15
16
  def method_names
16
- method_names = receiver.methods + receiver.singleton_methods + receiver.private_methods
17
+ method_names = receiver.methods + receiver.singleton_methods
18
+ method_names += receiver.private_methods if @has_args
17
19
  method_names.delete(method_name)
18
20
  method_names.uniq!
19
21
  method_names
20
22
  end
21
-
22
- module IvarNameCorrectable
23
- REPLS = {
24
- "(irb)" => -> { Readline::HISTORY.to_a.last }
25
- }
26
-
27
- def initialize(exception)
28
- super
29
-
30
- @location = exception.backtrace_locations.first
31
- @ivar_names = exception.instance_variable_get(:@frame_binding).receiver.instance_variables
32
- end
33
-
34
- def candidates
35
- super.merge(receiver_name.to_s => @ivar_names)
36
- end
37
-
38
- private
39
-
40
- def receiver_name
41
- return unless receiver.nil?
42
-
43
- abs_path = @location.absolute_path
44
- lineno = @location.lineno
45
-
46
- /@(\w+)*\.#{method_name}/ =~ line(abs_path, lineno).to_s && $1
47
- end
48
-
49
- def line(abs_path, lineno)
50
- if REPLS[abs_path]
51
- REPLS[abs_path].call
52
- elsif File.exist?(abs_path)
53
- File.open(abs_path) do |file|
54
- file.detect { file.lineno == lineno }
55
- end
56
- end
57
- end
58
- end
59
23
  end
60
24
  end
@@ -0,0 +1,16 @@
1
+ # -*- frozen-string-literal: true -*-
2
+ require 'did_you_mean/formatter'
3
+
4
+ module DidYouMean
5
+ module VerboseFormatter
6
+ prepend_features DidYouMean::Formatter
7
+
8
+ def to_s
9
+ return "" if @corrections.empty?
10
+
11
+ output = "\n\n Did you mean? ".dup
12
+ output << @corrections.join("\n ")
13
+ output << "\n "
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module DidYouMean
2
- VERSION = "1.0.0.rc1"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -71,23 +71,4 @@ class MethodNameTest < Minitest::Test
71
71
  assert_correction :raise, error.corrections
72
72
  assert_match "Did you mean? raise", error.to_s
73
73
  end
74
-
75
- D = DidYouMean
76
- M = D::MethodNameChecker
77
-
78
- def test_corrects_incorrect_ivar_name
79
- D::TRACE.enable
80
- D::SPELL_CHECKERS['NoMethodError'] = M.dup.prepend(M::IvarNameCorrectable)
81
-
82
- @number = 1
83
- @nubmer = nil
84
- error = assert_raises(NoMethodError) { @nubmer.zero? }
85
- remove_instance_variable :@nubmer
86
-
87
- assert_correction :@number, error.corrections
88
- assert_match "Did you mean? @number", error.to_s
89
- ensure
90
- D::TRACE.disable
91
- D::SPELL_CHECKERS['NoMethodError'] = M
92
- end
93
74
  end
@@ -13,6 +13,7 @@ class JaroWinklerTest < Minitest::Test
13
13
  assert_distance 0.8133, 'dixon', 'dicksonx'
14
14
  assert_distance 0.0, 'fvie', 'ten'
15
15
  assert_distance 0.9067, 'does_exist', 'doesnt_exist'
16
+ assert_distance 1.0, 'x', 'x'
16
17
  end
17
18
 
18
19
  def test_jarowinkler_distance_with_utf8_strings
@@ -0,0 +1,15 @@
1
+ require 'test_helper'
2
+
3
+ class InitializerNameCorrectionTest < Minitest::Test
4
+ def test_corrects_wrong_initializer_name
5
+ assert_output nil, "warning: intialize might be misspelled, perhaps you meant initialize?\n" do
6
+ Class.new { def intialize; end }
7
+ end
8
+ end
9
+
10
+ def test_does_not_correct_correct_initializer_name
11
+ assert_output nil, "" do
12
+ Class.new { def initialize; end }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ require 'test_helper'
2
+
3
+ class MethodNameWithExtraFeaturesTest < Minitest::Test
4
+ def test_corrects_incorrect_ivar_name
5
+ @number = 1
6
+ @nubmer = nil
7
+ error = assert_raises(NoMethodError) { @nubmer.zero? }
8
+ remove_instance_variable :@nubmer
9
+
10
+ assert_correction :@number, error.corrections
11
+ assert_match "Did you mean? @number", error.to_s
12
+ end
13
+ end
@@ -9,7 +9,7 @@ class SpellCheckerTest < Minitest::Test
9
9
  end
10
10
  end
11
11
 
12
- def test_similar_to_corrects_mistypes
12
+ def test_spell_checker_corrects_mistypes
13
13
  assert_spell 'foo', input: 'doo', dictionary: ['foo', 'fork']
14
14
  assert_spell 'email', input: 'meail', dictionary: ['email', 'fail', 'eval']
15
15
  assert_spell 'fail', input: 'fial', dictionary: ['email', 'fail', 'eval']
@@ -19,8 +19,9 @@ class SpellCheckerTest < Minitest::Test
19
19
  assert_spell 'sub!', input: 'suv!', dictionary: ['sub', 'gsub', 'sub!']
20
20
  assert_spell 'sub', input: 'suv', dictionary: ['sub', 'gsub', 'sub!']
21
21
 
22
- assert_equal %w(gsub! gsub), SpellChecker.new('gsuv!', %w(sub gsub gsub!)).corrections
23
- assert_equal %w(sub! sub gsub!), SpellChecker.new('ssub!', %w(sub sub! gsub gsub!)).corrections
22
+ assert_spell %w(gsub! gsub), input: 'gsuv!', dictionary: %w(sub gsub gsub!)
23
+ assert_spell %w(sub! sub gsub!), input: 'ssub!', dictionary: %w(sub sub! gsub gsub!)
24
+ assert_spell %i(read rand), input: 'raed', dictionary: File.methods + File.private_methods
24
25
 
25
26
  group_methods = %w(groups group_url groups_url group_path)
26
27
  assert_spell 'groups', input: 'group', dictionary: group_methods
@@ -40,19 +41,19 @@ class SpellCheckerTest < Minitest::Test
40
41
  assert_spell 'GroupMembershipDecorator', dictionary: group_classes, input: 'GroupMemberhipDecorator'
41
42
 
42
43
  names = %w(first_name_change first_name_changed? first_name_will_change!)
43
- assert_equal names, SpellChecker.new('first_name_change!', names).corrections
44
+ assert_spell names, input: 'first_name_change!', dictionary: names
44
45
 
45
46
  assert_empty SpellChecker.new('product_path', ['proc']).corrections
46
47
  assert_empty SpellChecker.new('fooo', ['fork']).corrections
47
48
  end
48
49
 
49
- def test_similar_to_corrects_misspells
50
+ def test_spell_checker_corrects_misspells
50
51
  assert_spell 'descendants', input: 'dependents', dictionary: ['descendants']
51
52
  assert_spell 'drag_to', input: 'drag', dictionary: ['drag_to']
52
53
  assert_spell 'set_result_count', input: 'set_result', dictionary: ['set_result_count']
53
54
  end
54
55
 
55
- def test_similar_to_sorts_results_by_simiarity
56
+ def test_spell_checker_sorts_results_by_simiarity
56
57
  expected = %w(
57
58
  name123456
58
59
  name12345
@@ -75,6 +76,6 @@ class SpellCheckerTest < Minitest::Test
75
76
 
76
77
  def assert_spell(expected, input: , dictionary: )
77
78
  corrections = SpellChecker.new(input, dictionary).corrections
78
- assert_equal [expected], corrections, "Expected to suggest #{expected}, but got #{corrections.inspect}"
79
+ assert_equal Array(expected), corrections, "Expected to suggest #{expected}, but got #{corrections.inspect}"
79
80
  end
80
81
  end
@@ -0,0 +1,17 @@
1
+ require 'test_helper'
2
+
3
+ class VerboseFormatterTest < Minitest::Test
4
+ def setup
5
+ does_exist = does_exist = nil
6
+ @error = assert_raises(NameError){ doesnt_exist }
7
+ end
8
+
9
+ def test_message
10
+ assert_equal <<~MESSAGE.chomp, @error.message
11
+ undefined local variable or method `doesnt_exist' for #{method(:to_s).super_method.call}
12
+
13
+ Did you mean? does_exist
14
+
15
+ MESSAGE
16
+ end
17
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: did_you_mean
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuki Nishijima
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-08 00:00:00.000000000 Z
11
+ date: 2015-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -81,6 +81,9 @@ files:
81
81
  - evaluation/incorrect_words.yaml
82
82
  - lib/did_you_mean.rb
83
83
  - lib/did_you_mean/core_ext/name_error.rb
84
+ - lib/did_you_mean/extra_features.rb
85
+ - lib/did_you_mean/extra_features/initializer_name_correction.rb
86
+ - lib/did_you_mean/extra_features/ivar_name_correction.rb
84
87
  - lib/did_you_mean/formatter.rb
85
88
  - lib/did_you_mean/jaro_winkler.rb
86
89
  - lib/did_you_mean/levenshtein.rb
@@ -90,6 +93,7 @@ files:
90
93
  - lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb
91
94
  - lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb
92
95
  - lib/did_you_mean/spell_checkers/null_checker.rb
96
+ - lib/did_you_mean/verbose_formatter.rb
93
97
  - lib/did_you_mean/version.rb
94
98
  - test/core_ext/name_error_extension_test.rb
95
99
  - test/correctable/class_name_test.rb
@@ -97,8 +101,11 @@ files:
97
101
  - test/correctable/uncorrectable_name_test.rb
98
102
  - test/correctable/variable_name_test.rb
99
103
  - test/edit_distance/jaro_winkler_test.rb
104
+ - test/extra_features/initializer_name_correction_test.rb
105
+ - test/extra_features/method_name_checker_test.rb
100
106
  - test/spell_checker_test.rb
101
107
  - test/test_helper.rb
108
+ - test/verbose_formatter_test.rb
102
109
  homepage: https://github.com/yuki24/did_you_mean
103
110
  licenses:
104
111
  - MIT
@@ -114,12 +121,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
121
  version: 2.3.0dev
115
122
  required_rubygems_version: !ruby/object:Gem::Requirement
116
123
  requirements:
117
- - - ">"
124
+ - - ">="
118
125
  - !ruby/object:Gem::Version
119
- version: 1.3.1
126
+ version: '0'
120
127
  requirements: []
121
128
  rubyforge_project:
122
- rubygems_version: 2.5.0
129
+ rubygems_version: 2.5.1
123
130
  signing_key:
124
131
  specification_version: 4
125
132
  summary: '"Did you mean?" experience in Ruby'
@@ -130,5 +137,8 @@ test_files:
130
137
  - test/correctable/uncorrectable_name_test.rb
131
138
  - test/correctable/variable_name_test.rb
132
139
  - test/edit_distance/jaro_winkler_test.rb
140
+ - test/extra_features/initializer_name_correction_test.rb
141
+ - test/extra_features/method_name_checker_test.rb
133
142
  - test/spell_checker_test.rb
134
143
  - test/test_helper.rb
144
+ - test/verbose_formatter_test.rb