did_you_mean 1.0.0.rc1 → 1.0.0

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.
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