did_you_mean 1.4.0 → 1.5.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
  SHA256:
3
- metadata.gz: '05887ae70010eb1df6b01afa6dc40a0b2831040983baf01a58dedc31a02e179a'
4
- data.tar.gz: ac63168212e43e8d4161c6a32632081f8c93f1a9c90279b654c7464119a2fefe
3
+ metadata.gz: 3befc8f677ec57e2975d04b2095fcecf7314ff207150aa994b197894dba883af
4
+ data.tar.gz: dc5a44ad2f6058ef68913f4080a23141f39b23f3b30129fe753d5d88cca85cc0
5
5
  SHA512:
6
- metadata.gz: 2aeccb65107c3f3f1fd8f084c173d914c5dc4e0827826372b22c3d7b9dbd3532c0e6dad043a194a7860ccc10df671b8b3008292d95bce26953f282a4d7c2a061
7
- data.tar.gz: f7b276aa466cbace238442d1fd3acc9a26a3b2b3623b5cb330b7b1dee15e9916b5a9140d5a74cb585586e30b95d371dbd02a97f7bad81f82b542517299c2df95
6
+ metadata.gz: 4d60d78614d4a6650b2be87599d3c3d867ab74f4cdf7f6083594229e3c51588af57a5c9574ca35ced229558f4280cd3677cbd7944cc5cef55e34a4f7ff7addf3
7
+ data.tar.gz: df5f07a5893afee4e03af416230ee828c7c2c2dfb8e5e35b5c525bebdff03710645b4af192563dc546abd4c210f8f2e8ce15e90124503488b74db19bd700f71c
@@ -13,36 +13,27 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  strategy:
15
15
  matrix:
16
- ruby: [ '2.5.4', '2.6.5', 'ruby-head', 'jruby-9.2.9.0', 'jruby-head' ]
16
+ ruby: [ '2.5.8', '2.6.6', '2.7.1', 'ruby-head', 'jruby-9.2.11.1', 'jruby-head' ]
17
17
  steps:
18
18
  - uses: actions/checkout@v1
19
- - name: Set up RVM
20
- run: |
21
- curl -sSL https://get.rvm.io | bash
22
- - name: Set up Ruby
23
- run: |
24
- source $HOME/.rvm/scripts/rvm
25
- rvm install ${{ matrix.ruby }} --binary
26
- rvm --default use ${{ matrix.ruby }}
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
27
22
  - name: Build and test with Rake
28
23
  run: |
29
- source $HOME/.rvm/scripts/rvm
30
24
  gem i test-unit
31
- rake
25
+ RUBYOPT='--disable-did_you_mean' rake
32
26
 
33
27
  benchmark:
34
28
  runs-on: ubuntu-latest
35
29
  steps:
36
30
  - uses: actions/checkout@v1
37
- - name: Set up Ruby 2.6
38
- uses: actions/setup-ruby@v1
31
+ - uses: ruby/setup-ruby@v1
39
32
  with:
40
- ruby-version: 2.6.x
33
+ ruby-version: 2.7.1
41
34
  - name: Test performance and accuracy
42
35
  run: |
43
36
  gem install bundler
44
37
  bundle install --jobs 4 --retry 2
45
- gem uni did_you_mean
46
- bundle exec rake test:accuracy
47
- bundle exec rake test:explore
48
- bundle exec rake benchmark:memory
38
+ RUBYOPT='--disable-did_you_mean' bundle exec rake test:accuracy
39
+ RUBYOPT='--disable-did_you_mean' bundle exec rake benchmark:memory
@@ -1,7 +1,41 @@
1
- ## v1.4.0 (Next)
1
+ ## v1.5.0
2
2
 
3
- - Remove the empty `tmp/` directory to comply with `rpmlint` ([#122](https://github.com/ruby/did_you_mean/issues/122))
4
- - Fixes a bug where suggestions are not shown on subsequent errors ([#120](https://github.com/ruby/did_you_mean/issues/120))
3
+ - Suggest require paths on LoadError ([#143](https://github.com/ruby/did_you_mean/pull/143))
4
+
5
+ ## [v1.4.0](https://github.com/ruby/did_you_mean/tree/v1.4.0)
6
+
7
+ _<sup>released at 2020-05-09 02:56:43 UTC</sup>_
8
+
9
+ As of Ruby 2.7, the `did_you_mean` gem has been promoted up to a default gem. I would like to thank [@kddeisz](https://github.com/kddeisz) for his hard work on making the entire gem easily portable the main ruby/ruby repo ([#132](https://github.com/ruby/did_you_mean/pull/132), [#131](https://github.com/ruby/did_you_mean/pull/131), and [ruby/ruby#2631](https://github.com/ruby/ruby/pull/2631)).
10
+
11
+ #### Features
12
+
13
+ - Add a new tree spell checker ([#119](https://github.com/ruby/did_you_mean/pull/119), [@obromios](https://github.com/obromios))
14
+ - Add a public API for registering an error ([#123](https://github.com/ruby/did_you_mean/pull/123), [@kddeisz](https://github.com/kddeisz))
15
+
16
+ #### Bug fixes
17
+
18
+ - Fixes a bug where wrong suggestion could be made when string requested on hash and keys are symbols ([@localhostdotdev](https://github.com/localhostdotdev), [#134](https://github.com/ruby/did_you_mean/pull/134))
19
+
20
+ #### Breaking changes
21
+
22
+ - Experimental features have been removed ([#135](https://github.com/ruby/did_you_mean/pull/135))
23
+
24
+ #### Internal changes
25
+
26
+ - Replace Travis CI with GitHub Actions ([#124](https://github.com/ruby/did_you_mean/pull/124))
27
+ - Drop mintiest dependency ([#129](https://github.com/ruby/did_you_mean/pull/129))
28
+ - Drop delegate dependency ([#138](https://github.com/ruby/did_you_mean/pull/138))
29
+
30
+ ## [v1.3.1](https://github.com/ruby/did_you_mean/tree/v1.3.1)
31
+
32
+ _<sup>released at 2019-09-29 03:58:46 UTC</sup>_
33
+
34
+ #### Bug fixes
35
+
36
+ - Fixes a test failure in Ruby core where DYM attempts to mutate immutable strings from `Symbol#to_s` ([#125](https://github.com/ruby/did_you_mean/pull/125), [@nobu](https://github.com/nobu), [@eregon](https://github.com/eregon), [@MSP-Greg](https://github.com/MSP-Greg))
37
+ - Removes the empty `tmp/` directory to comply with `rpmlint` ([#122](https://github.com/ruby/did_you_mean/issues/122), [@pvalena](https://github.com/pvalena))
38
+ - Fixes a bug where suggestions are not shown on subsequent errors ([#120](https://github.com/ruby/did_you_mean/issues/120), [@localhostdotdev](https://github.com/localhostdotdev))
5
39
 
6
40
  ## [v1.3.0](https://github.com/ruby/did_you_mean/tree/v1.3.0)
7
41
 
data/README.md CHANGED
@@ -61,6 +61,14 @@ hash.fetch(:fooo)
61
61
  # Did you mean? :foo
62
62
  ```
63
63
 
64
+ ### LoadError
65
+
66
+ ```ruby
67
+ require 'net-http'
68
+ # => LoadError (cannot load such file -- net-http)
69
+ # Did you mean? net/http
70
+ ```
71
+
64
72
  ## Verbose Formatter
65
73
 
66
74
  This verbose formatter changes the error message format to take more lines/spaces so it'll be slightly easier to read the suggestions. This formatter can totally be used in any environment including production.
data/Rakefile CHANGED
@@ -7,13 +7,16 @@ Rake::TestTask.new do |task|
7
7
  task.test_files = Dir['test/**/test_*.rb'].reject {|path| path.end_with?("test_explore.rb") }
8
8
  task.verbose = true
9
9
  task.warning = true
10
+ task.ruby_opts = %w[ --disable-did_you_mean ]
10
11
  end
11
12
 
12
13
  Rake::TestTask.new("test:explore") do |task|
13
14
  task.libs << "test"
14
- task.pattern = 'test/tree_spell/test_explore.rb'
15
- task.verbose = true
16
- task.warning = true
15
+
16
+ task.pattern = 'test/tree_spell/test_explore.rb'
17
+ task.verbose = true
18
+ task.warning = true
19
+ task.ruby_opts = %w[ --disable-did_you_mean ]
17
20
  end
18
21
 
19
22
  task default: %i(test)
@@ -22,7 +25,7 @@ namespace :test do
22
25
  namespace :accuracy do
23
26
  desc "Download Wiktionary's Simple English data and save it as a dictionary"
24
27
  task :prepare do
25
- sh 'ruby evaluation/dictionary_generator.rb'
28
+ sh "RUBYOPT='--disable-did_you_mean' ruby evaluation/dictionary_generator.rb"
26
29
  end
27
30
  end
28
31
 
@@ -34,7 +37,7 @@ namespace :test do
34
37
  puts "\n"
35
38
  end
36
39
 
37
- sh 'ruby evaluation/calculator.rb'
40
+ sh "RUBYOPT='--disable-did_you_mean' ruby evaluation/calculator.rb"
38
41
  end
39
42
  end
40
43
 
@@ -42,29 +45,29 @@ namespace :benchmark do
42
45
  namespace :ips do
43
46
  desc "Measure performance of the gem's Jaro distance implementation"
44
47
  task :jaro do
45
- sh "ruby benchmark/jaro_winkler/speed.rb"
48
+ sh "RUBYOPT='--disable-did_you_mean' ruby benchmark/jaro_winkler/speed.rb"
46
49
  end
47
50
 
48
51
  desc "Benchmark performance of the gem's Levenshtein distance implementation"
49
52
  task :levenshtein do
50
- sh "ruby benchmark/levenshtein/speed.rb"
53
+ sh "RUBYOPT='--disable-did_you_mean' ruby benchmark/levenshtein/speed.rb"
51
54
  end
52
55
  end
53
56
 
54
57
  desc "Benchmark memory usage in the gem's spell checker"
55
58
  task :memory do
56
- sh "ruby benchmark/memory_usage.rb"
59
+ sh "RUBYOPT='--disable-did_you_mean' ruby benchmark/memory_usage.rb"
57
60
  end
58
61
 
59
62
  namespace :memory do
60
63
  desc "Benchmark memory usage in the gem's Jaro distance implementation"
61
64
  task :jaro do
62
- sh "ruby benchmark/jaro_winkler/memory_usage.rb"
65
+ sh "RUBYOPT='--disable-did_you_mean' ruby benchmark/jaro_winkler/memory_usage.rb"
63
66
  end
64
67
 
65
68
  desc "Benchmark memory usage in the gem's Levenshtein distance implementation"
66
69
  task :levenshtein do
67
- sh "ruby benchmark/levenshtein/memory_usage.rb"
70
+ sh "RUBYOPT='--disable-did_you_mean' ruby benchmark/levenshtein/memory_usage.rb"
68
71
  end
69
72
  end
70
73
  end
@@ -0,0 +1,47 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # Run the following command to run this script:
4
+ #
5
+ # $ ruby --disable-did_you_mean benchmark/require_path_checker.rb
6
+ #
7
+
8
+ require_relative '../lib/did_you_mean/spell_checkers/require_path_checker'
9
+
10
+ require 'benchmark/ips'
11
+
12
+ Benchmark.ips do |x|
13
+ x.config(time: 10, warmup: 10)
14
+
15
+ exception_with_slash = begin
16
+ require 'net/htto'
17
+ rescue LoadError => error
18
+ error
19
+ end
20
+
21
+ exception_without_slash = begin
22
+ require 'net-http'
23
+ rescue LoadError => error
24
+ error
25
+ end
26
+
27
+ checker_for_path = DidYouMean::RequirePathChecker.new(exception_with_slash)
28
+ checker_for_file = DidYouMean::RequirePathChecker.new(exception_without_slash)
29
+
30
+ x.report "original (with a /)" do
31
+ checker_for_path.corrections
32
+ end
33
+
34
+ x.report "original (without /)" do
35
+ checker_for_file.corrections
36
+ end
37
+
38
+ #x.report "proposed (with a /)" do
39
+ # checker_for_path.experiment
40
+ #end
41
+ #
42
+ #x.report "proposed (without /)" do
43
+ # checker_for_file.experiment
44
+ #end
45
+
46
+ x.compare!
47
+ end
@@ -6,6 +6,7 @@ require_relative 'did_you_mean/spell_checkers/name_error_checkers'
6
6
  require_relative 'did_you_mean/spell_checkers/method_name_checker'
7
7
  require_relative 'did_you_mean/spell_checkers/key_error_checker'
8
8
  require_relative 'did_you_mean/spell_checkers/null_checker'
9
+ require_relative 'did_you_mean/spell_checkers/require_path_checker'
9
10
  require_relative 'did_you_mean/formatters/plain_formatter'
10
11
  require_relative 'did_you_mean/tree_spell_checker'
11
12
 
@@ -95,8 +96,9 @@ module DidYouMean
95
96
  correct_error NameError, NameErrorCheckers
96
97
  correct_error KeyError, KeyErrorChecker
97
98
  correct_error NoMethodError, MethodNameChecker
99
+ correct_error LoadError, RequirePathChecker if RUBY_VERSION >= '2.8.0'
98
100
 
99
- # Returns the currenctly set formatter. By default, it is set to +DidYouMean::Formatter+.
101
+ # Returns the currently set formatter. By default, it is set to +DidYouMean::Formatter+.
100
102
  def self.formatter
101
103
  @@formatter
102
104
  end
@@ -43,7 +43,12 @@ module DidYouMean
43
43
  end
44
44
 
45
45
  def corrections
46
- @corrections ||= SpellChecker.new(dictionary: RB_RESERVED_WORDS + method_names).correct(method_name) - names_to_exclude
46
+ @corrections ||= begin
47
+ dictionary = method_names
48
+ dictionary = RB_RESERVED_WORDS + dictionary if @private_call
49
+
50
+ SpellChecker.new(dictionary: dictionary).correct(method_name) - names_to_exclude
51
+ end
47
52
  end
48
53
 
49
54
  def method_names
@@ -0,0 +1,35 @@
1
+ # frozen-string-literal: true
2
+
3
+ require_relative "../spell_checker"
4
+ require_relative "../tree_spell_checker"
5
+
6
+ module DidYouMean
7
+ class RequirePathChecker
8
+ attr_reader :path
9
+
10
+ INITIAL_LOAD_PATH = $LOAD_PATH.dup.freeze
11
+ ENV_SPECIFIC_EXT = ".#{RbConfig::CONFIG["DLEXT"]}"
12
+
13
+ private_constant :INITIAL_LOAD_PATH, :ENV_SPECIFIC_EXT
14
+
15
+ def self.requireables
16
+ @requireables ||= INITIAL_LOAD_PATH
17
+ .flat_map {|path| Dir.glob("**/???*{.rb,#{ENV_SPECIFIC_EXT}}", base: path) }
18
+ .map {|path| path.chomp!(".rb") || path.chomp!(ENV_SPECIFIC_EXT) }
19
+ end
20
+
21
+ def initialize(exception)
22
+ @path = exception.path
23
+ end
24
+
25
+ def corrections
26
+ @corrections ||= begin
27
+ threshold = path.size * 2
28
+ dictionary = self.class.requireables.reject {|str| str.size >= threshold }
29
+ spell_checker = path.include?("/") ? TreeSpellChecker : SpellChecker
30
+
31
+ spell_checker.new(dictionary: dictionary).correct(path).uniq
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,137 +1,109 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DidYouMean
2
4
  # spell checker for a dictionary that has a tree
3
5
  # structure, see doc/tree_spell_checker_api.md
4
6
  class TreeSpellChecker
5
- attr_reader :dictionary, :dimensions, :separator, :augment
7
+ attr_reader :dictionary, :separator, :augment
6
8
 
7
9
  def initialize(dictionary:, separator: '/', augment: nil)
8
10
  @dictionary = dictionary
9
11
  @separator = separator
10
12
  @augment = augment
11
- @dimensions = parse_dimensions
12
13
  end
13
14
 
14
15
  def correct(input)
15
- plausibles = plausible_dimensions input
16
- return no_idea(input) if plausibles.empty?
17
- suggestions = find_suggestions input, plausibles
18
- return no_idea(input) if suggestions.empty?
19
- suggestions
20
- end
16
+ plausibles = plausible_dimensions(input)
17
+ return fall_back_to_normal_spell_check(input) if plausibles.empty?
21
18
 
22
- private
19
+ suggestions = find_suggestions(input, plausibles)
20
+ return fall_back_to_normal_spell_check(input) if suggestions.empty?
23
21
 
24
- def parse_dimensions
25
- ParseDimensions.new(dictionary, separator).call
22
+ suggestions
26
23
  end
27
24
 
28
- def find_suggestions(input, plausibles)
29
- states = plausibles[0].product(*plausibles[1..-1])
30
- paths = possible_paths states
31
- leaf = input.split(separator).last
32
- ideas = find_ideas(paths, leaf)
33
- ideas.compact.flatten
25
+ def dictionary_without_leaves
26
+ @dictionary_without_leaves ||= dictionary.map { |word| word.split(separator)[0..-2] }.uniq
34
27
  end
35
28
 
36
- def no_idea(input)
37
- return [] unless augment
38
- ::DidYouMean::SpellChecker.new(dictionary: dictionary).correct(input)
29
+ def tree_depth
30
+ @tree_depth ||= dictionary_without_leaves.max { |a, b| a.size <=> b.size }.size
39
31
  end
40
32
 
41
- def find_ideas(paths, leaf)
42
- paths.map do |path|
43
- names = find_leaves(path)
44
- ideas = CorrectElement.new.call names, leaf
45
- ideas_to_paths ideas, leaf, names, path
46
- end
33
+ def dimensions
34
+ @dimensions ||= tree_depth.times.map do |index|
35
+ dictionary_without_leaves.map { |element| element[index] }.compact.uniq
36
+ end
47
37
  end
48
38
 
49
- def ideas_to_paths(ideas, leaf, names, path)
50
- return nil if ideas.empty?
51
- return [path + separator + leaf] if names.include? leaf
52
- ideas.map { |str| path + separator + str }
39
+ def find_leaves(path)
40
+ path_with_separator = "#{path}#{separator}"
41
+
42
+ dictionary
43
+ .select {|str| str.include?(path_with_separator) }
44
+ .map {|str| str.gsub(path_with_separator, '') }
53
45
  end
54
46
 
55
- def find_leaves(path)
56
- dictionary.map do |str|
57
- next unless str.include? "#{path}#{separator}"
58
- str.gsub("#{path}#{separator}", '')
59
- end.compact
47
+ def plausible_dimensions(input)
48
+ input.split(separator)[0..-2]
49
+ .map
50
+ .with_index { |element, index| correct_element(dimensions[index], element) if dimensions[index] }
51
+ .compact
60
52
  end
61
53
 
62
54
  def possible_paths(states)
63
- states.map do |state|
64
- state.join separator
65
- end
55
+ states.map { |state| state.join(separator) }
66
56
  end
67
57
 
68
- def plausible_dimensions(input)
69
- elements = input.split(separator)[0..-2]
70
- elements.each_with_index.map do |element, i|
71
- next if dimensions[i].nil?
72
- CorrectElement.new.call dimensions[i], element
73
- end.compact
74
- end
75
- end
58
+ private
76
59
 
77
- # parses the elements in each dimension
78
- class ParseDimensions
79
- def initialize(dictionary, separator)
80
- @dictionary = dictionary
81
- @separator = separator
60
+ def find_suggestions(input, plausibles)
61
+ states = plausibles[0].product(*plausibles[1..-1])
62
+ paths = possible_paths(states)
63
+ leaf = input.split(separator).last
64
+
65
+ find_ideas(paths, leaf)
82
66
  end
83
67
 
84
- def call
85
- leafless = remove_leaves
86
- dimensions = find_elements leafless
87
- dimensions.map do |elements|
88
- elements.to_set.to_a
89
- end
68
+ def fall_back_to_normal_spell_check(input)
69
+ return [] unless augment
70
+
71
+ ::DidYouMean::SpellChecker.new(dictionary: dictionary).correct(input)
90
72
  end
91
73
 
92
- private
74
+ def find_ideas(paths, leaf)
75
+ paths.flat_map do |path|
76
+ names = find_leaves(path)
77
+ ideas = correct_element(names, leaf)
93
78
 
94
- def remove_leaves
95
- dictionary.map do |a|
96
- elements = a.split(separator)
97
- elements[0..-2]
98
- end.to_set.to_a
79
+ ideas_to_paths(ideas, leaf, names, path)
80
+ end.compact
99
81
  end
100
82
 
101
- def find_elements(leafless)
102
- max_elements = leafless.map(&:size).max
103
- dimensions = Array.new(max_elements) { [] }
104
- (0...max_elements).each do |i|
105
- leafless.each do |elements|
106
- dimensions[i] << elements[i] unless elements[i].nil?
107
- end
83
+ def ideas_to_paths(ideas, leaf, names, path)
84
+ if ideas.empty?
85
+ nil
86
+ elsif names.include?(leaf)
87
+ ["#{path}#{separator}#{leaf}"]
88
+ else
89
+ ideas.map {|str| "#{path}#{separator}#{str}" }
108
90
  end
109
- dimensions
110
91
  end
111
92
 
112
- attr_reader :dictionary, :separator
113
- end
93
+ def correct_element(names, element)
94
+ return names if names.size == 1
114
95
 
115
- # identifies the elements close to element
116
- class CorrectElement
117
- def initialize
118
- end
96
+ str = normalize(element)
119
97
 
120
- def call(names, element)
121
- return names if names.size == 1
122
- str = normalize element
123
- return [str] if names.include? str
124
- checker = ::DidYouMean::SpellChecker.new(dictionary: names)
125
- checker.correct(str)
126
- end
98
+ return [str] if names.include?(str)
127
99
 
128
- private
100
+ ::DidYouMean::SpellChecker.new(dictionary: names).correct(str)
101
+ end
129
102
 
130
- def normalize(leaf)
131
- str = leaf.dup
103
+ def normalize(str)
132
104
  str.downcase!
133
- return str unless str.include? '@'
134
- str.tr!('@', ' ')
105
+ str.tr!('@', ' ') if str.include?('@')
106
+ str
135
107
  end
136
108
  end
137
109
  end
@@ -1,3 +1,3 @@
1
1
  module DidYouMean
2
- VERSION = "1.4.0"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -1,4 +1,4 @@
1
1
  class Book
2
- class Cover
2
+ class Spine
3
3
  end
4
4
  end
@@ -66,11 +66,13 @@ class ClassNameCheckTest < Test::Unit::TestCase
66
66
  end
67
67
 
68
68
  def test_does_not_suggest_user_input
69
- error = assert_raise(NameError) { ::Book::Cover }
69
+ Book.send(:remove_const, :Spine) if Book.constants.include?(:Spine)
70
+
71
+ error = assert_raise(NameError) { ::Book::Spine }
70
72
 
71
73
  # This is a weird require, but in a multi-threaded condition, a constant may
72
74
  # be loaded between when a NameError occurred and when the spell checker
73
- # attemps to find a possible suggestion. The manual require here simulates
75
+ # attempts to find a possible suggestion. The manual require here simulates
74
76
  # a race condition a single test.
75
77
  require_relative '../fixtures/book'
76
78
 
@@ -137,4 +137,11 @@ class MethodNameCheckTest < Test::Unit::TestCase
137
137
  assert_correction :yield, error.corrections
138
138
  assert_match "Did you mean? yield", error.to_s
139
139
  end
140
+
141
+ def test_does_not_suggest_yield
142
+ error = assert_raise(NoMethodError) { 1.yeild }
143
+
144
+ assert_correction [], error.corrections
145
+ assert_not_match(/Did you mean\? +yield/, error.to_s)
146
+ end if RUBY_ENGINE != "jruby"
140
147
  end
@@ -0,0 +1,32 @@
1
+ require_relative '../helper'
2
+
3
+ return if !(RUBY_VERSION >= '2.8.0')
4
+
5
+ class RequirePathCheckTest < Test::Unit::TestCase
6
+ include DidYouMean::TestHelper
7
+
8
+ def test_load_error_from_require_has_suggestions
9
+ error = assert_raise LoadError do
10
+ require 'open_struct'
11
+ end
12
+
13
+ assert_correction 'ostruct', error.corrections
14
+ assert_match "Did you mean? ostruct", error.to_s
15
+ end
16
+
17
+ def test_load_error_from_require_for_nested_files_has_suggestions
18
+ error = assert_raise LoadError do
19
+ require 'net/htt'
20
+ end
21
+
22
+ assert_correction 'net/http', error.corrections
23
+ assert_match "Did you mean? net/http", error.to_s
24
+
25
+ error = assert_raise LoadError do
26
+ require 'net-http'
27
+ end
28
+
29
+ assert_correction ['net/http', 'net/https'], error.corrections
30
+ assert_match "Did you mean? net/http", error.to_s
31
+ end
32
+ end
@@ -1,11 +1,12 @@
1
- require 'set'
2
- require 'yaml'
1
+ # frozen_string_literal: true
3
2
 
4
- require_relative './helper'
3
+ require "yaml"
4
+
5
+ require_relative "./helper"
5
6
 
6
7
  class TreeSpellCheckerTest < Test::Unit::TestCase
7
- MINI_DIRECTORIES = YAML.load_file(File.expand_path('fixtures/mini_dir.yml', __dir__))
8
- RSPEC_DIRECTORIES = YAML.load_file(File.expand_path('fixtures/rspec_dir.yml', __dir__))
8
+ MINI_DIRECTORIES = YAML.load_file(File.expand_path("fixtures/mini_dir.yml", __dir__))
9
+ RSPEC_DIRECTORIES = YAML.load_file(File.expand_path("fixtures/rspec_dir.yml", __dir__))
9
10
 
10
11
  def setup
11
12
  @dictionary =
@@ -20,154 +21,150 @@ class TreeSpellCheckerTest < Test::Unit::TestCase
20
21
  spec/models/gfsga_spec.rb
21
22
  spec/controllers/vixen_controller_spec.rb
22
23
  )
23
- @test_str = 'spek/modeks/confirns/viken_spec.rb'
24
- @tsp = DidYouMean::TreeSpellChecker.new(dictionary: @dictionary)
24
+ @test_str = "spek/modeks/confirns/viken_spec.rb"
25
+ @tree_spell_checker = DidYouMean::TreeSpellChecker.new(dictionary: @dictionary)
25
26
  end
26
27
 
27
28
  def test_corrupt_root
28
- word = 'test/verbose_formatter_test.rb'
29
- word_error = 'btets/cverbose_formatter_etst.rb suggestions'
30
- tsp = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES)
31
- s = tsp.correct(word_error).first
32
- assert_match s, word
29
+ assert_tree_spell "test/verbose_formatter_test.rb",
30
+ input: "btets/cverbose_formatter_etst.rb suggestions",
31
+ dictionary: MINI_DIRECTORIES
33
32
  end
34
33
 
35
34
  def test_leafless_state
36
- tsp = DidYouMean::TreeSpellChecker.new(dictionary: @dictionary.push('spec/features'))
37
- word = 'spec/modals/confirms/efgh_spec.rb'
38
- word_error = 'spec/modals/confirXX/efgh_spec.rb'
39
- s = tsp.correct(word_error).first
40
- assert_equal s, word
41
- s = tsp.correct('spec/featuresXX')
42
- assert_equal 'spec/features', s.first
35
+ assert_tree_spell "spec/modals/confirms/efgh_spec.rb",
36
+ input: "spec/modals/confirXX/efgh_spec.rb",
37
+ dictionary: [*@dictionary, "spec/features"]
38
+
39
+ assert_tree_spell "spec/features",
40
+ input: "spec/featuresXX",
41
+ dictionary: [*@dictionary, "spec/features"]
43
42
  end
44
43
 
45
44
  def test_rake_dictionary
46
- dict = %w(parallel:prepare parallel:create parallel:rake parallel:migrate)
47
- word_error = 'parallel:preprare'
48
- tsp = DidYouMean::TreeSpellChecker.new(dictionary: dict, separator: ':')
49
- s = tsp.correct(word_error).first
50
- assert_match s, 'parallel:prepare'
45
+ assert_tree_spell "parallel:prepare",
46
+ input: "parallel:preprare",
47
+ dictionary: %w[parallel:prepare parallel:create parallel:rake parallel:migrate],
48
+ separator: ":"
51
49
  end
52
50
 
53
51
  def test_special_words_mini
54
- tsp = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES)
55
- special_words_mini.each do |word, word_error|
56
- s = tsp.correct(word_error).first
57
- assert_match s, word
52
+ [
53
+ %w(test/fixtures/book.rb test/fixture/book.rb),
54
+ %w(test/edit_distance/jaro_winkler_test.rb test/edit_distace/jaro_winkler_test.rb),
55
+ %w(test/edit_distance/jaro_winkler_test.rb teste/dit_distane/jaro_winkler_test.rb),
56
+ %w(test/fixtures/book.rb test/fixturWes/book.rb),
57
+ %w(test/test_helper.rb tes!t/test_helper.rb),
58
+ %w(test/fixtures/book.rb test/hfixtures/book.rb),
59
+ %w(test/edit_distance/jaro_winkler_test.rb test/eidt_distance/jaro_winkler_test.@rb),
60
+ %w(test/spell_checker_test.rb test/spell_checke@r_test.rb),
61
+ %w(test/tree_spell_human_typo_test.rb testt/ree_spell_human_typo_test.rb),
62
+ %w(test/edit_distance/jaro_winkler_test.rb test/edit_distance/jaro_winkler_tuest.rb),
63
+ ].each do |expected, user_input|
64
+ assert_tree_spell expected, input: user_input, dictionary: MINI_DIRECTORIES
58
65
  end
59
- end
60
66
 
61
- def test_special_words_rspec
62
- tsp = DidYouMean::TreeSpellChecker.new(dictionary: RSPEC_DIRECTORIES)
63
- special_words_rspec.each do |word, word_error|
64
- s = tsp.correct(word_error)
65
- assert_match s.first, word
66
- end
67
- end
68
-
69
- def special_words_rspec
70
67
  [
71
- ['spec/rspec/core/formatters/exception_presenter_spec.rb','spec/rspec/core/formatters/eception_presenter_spec.rb'],
72
- ['spec/rspec/core/ordering_spec.rb', 'spec/spec/core/odrering_spec.rb'],
73
- ['spec/rspec/core/metadata_spec.rb', 'spec/rspec/core/metadata_spe.crb'],
74
- ['spec/support/mathn_integration_support.rb', 'spec/support/mathn_itegrtion_support.rb']
75
- ]
68
+ %w(test/spell_checking/variable_name_check_test.rb test/spell_checking/vriabl_ename_check_test.rb),
69
+ %w(test/spell_checking/key_name_check_test.rb tesit/spell_checking/key_name_choeck_test.rb),
70
+ ].each do |expected, user_input|
71
+ assert_equal expected, DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES).correct(user_input)[0]
72
+ end
76
73
  end
77
74
 
78
- def special_words_mini
75
+ def test_special_words_rspec
79
76
  [
80
- ['test/fixtures/book.rb', 'test/fixture/book.rb'],
81
- ['test/fixtures/book.rb', 'test/fixture/book.rb'],
82
- ['test/edit_distance/jaro_winkler_test.rb', 'test/edit_distace/jaro_winkler_test.rb'],
83
- ['test/edit_distance/jaro_winkler_test.rb', 'teste/dit_distane/jaro_winkler_test.rb'],
84
- ['test/fixtures/book.rb', 'test/fixturWes/book.rb'],
85
- ['test/test_helper.rb', 'tes!t/test_helper.rb'],
86
- ['test/fixtures/book.rb', 'test/hfixtures/book.rb'],
87
- ['test/edit_distance/jaro_winkler_test.rb', 'test/eidt_distance/jaro_winkler_test.@rb'],
88
- ['test/spell_checker_test.rb', 'test/spell_checke@r_test.rb'],
89
- ['test/tree_spell_human_typo_test.rb', 'testt/ree_spell_human_typo_test.rb'],
90
- ['test/spell_checking/variable_name_check_test.rb', 'test/spell_checking/vriabl_ename_check_test.rb'],
91
- ['test/spell_checking/key_name_check_test.rb', 'tesit/spell_checking/key_name_choeck_test.rb'],
92
- ['test/edit_distance/jaro_winkler_test.rb', 'test/edit_distance/jaro_winkler_tuest.rb']
93
- ]
77
+ %w(spec/rspec/core/formatters/exception_presenter_spec.rb spec/rspec/core/formatters/eception_presenter_spec.rb),
78
+ %w(spec/rspec/core/metadata_spec.rb spec/rspec/core/metadata_spe.crb),
79
+ %w(spec/rspec/core/ordering_spec.rb spec/spec/core/odrering_spec.rb),
80
+ %w(spec/support/mathn_integration_support.rb spec/support/mathn_itegrtion_support.rb),
81
+ ].each do |expected, user_input|
82
+ assert_tree_spell expected, input: user_input, dictionary: RSPEC_DIRECTORIES
83
+ end
94
84
  end
95
85
 
96
86
  def test_file_in_root
97
- word = 'test/spell_checker_test.rb'
98
- word_error = 'test/spell_checker_test.r'
99
- suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES).correct word_error
100
- assert_equal word, suggestions.first
87
+ assert_tree_spell "test/spell_checker_test.rb", input: "test/spell_checker_test.r", dictionary: MINI_DIRECTORIES
101
88
  end
102
89
 
103
90
  def test_no_plausible_states
104
- word_error = 'testspell_checker_test.rb'
105
- suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES).correct word_error
106
- assert_equal [], suggestions
91
+ assert_tree_spell [], input: "testspell_checker_test.rb", dictionary: MINI_DIRECTORIES
107
92
  end
108
93
 
109
94
  def test_no_plausible_states_with_augmentation
110
- word_error = 'testspell_checker_test.rb'
111
- suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES).correct word_error
112
- assert_equal [], suggestions
113
- suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES, augment: true).correct word_error
114
- assert_equal 'test/spell_checker_test.rb', suggestions.first
95
+ assert_tree_spell [], input: "testspell_checker_test.rb", dictionary: MINI_DIRECTORIES
96
+
97
+ suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES, augment: true).correct("testspell_checker_test.rb")
98
+
99
+ assert_equal suggestions.first, "test/spell_checker_test.rb"
115
100
  end
116
101
 
117
102
  def test_no_idea_with_augmentation
118
- word_error = 'test/spell_checking/key_name.rb'
119
- suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES).correct word_error
120
- assert_equal [], suggestions
121
- suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES, augment: true).correct word_error
122
- assert_equal 'test/spell_checking/key_name_check_test.rb', suggestions.first
103
+ assert_tree_spell [], input: "test/spell_checking/key_name.rb", dictionary: MINI_DIRECTORIES
104
+
105
+ suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES, augment: true).correct("test/spell_checking/key_name.rb")
106
+
107
+ assert_equal suggestions.first, "test/spell_checking/key_name_check_test.rb"
123
108
  end
124
109
 
125
110
  def test_works_out_suggestions
126
- exp = ['spec/models/concerns/vixen_spec.rb',
127
- 'spec/models/concerns/vixenus_spec.rb']
128
- suggestions = @tsp.correct(@test_str)
129
- assert_equal suggestions.to_set, exp.to_set
111
+ assert_tree_spell %w(spec/models/concerns/vixen_spec.rb spec/models/concerns/vixenus_spec.rb),
112
+ input: "spek/modeks/confirns/viken_spec.rb",
113
+ dictionary: %w(spec/models/concerns/vixen_spec.rb spec/models/concerns/vixenus_spec.rb)
130
114
  end
131
115
 
132
116
  def test_works_when_input_is_correct
133
- correct_input = 'spec/models/concerns/vixenus_spec.rb'
134
- suggestions = @tsp.correct correct_input
135
- assert_equal suggestions.first, correct_input
117
+ assert_tree_spell "spec/models/concerns/vixenus_spec.rb",
118
+ input: "spec/models/concerns/vixenus_spec.rb",
119
+ dictionary: @dictionary
136
120
  end
137
121
 
138
122
  def test_find_out_leaves_in_a_path
139
- path = 'spec/modals/confirms'
140
- names = @tsp.send(:find_leaves, path)
141
- assert_equal names.to_set, %w(abcd_spec.rb efgh_spec.rb).to_set
123
+ names = @tree_spell_checker.find_leaves("spec/modals/confirms")
124
+
125
+ assert_equal %w[abcd_spec.rb efgh_spec.rb], names
142
126
  end
143
127
 
144
128
  def test_works_out_nodes
145
- exp_paths = ['spec/models/concerns',
146
- 'spec/models/confirms',
147
- 'spec/modals/concerns',
148
- 'spec/modals/confirms',
149
- 'spec/controllers/concerns',
150
- 'spec/controllers/confirms'].to_set
151
- states = @tsp.send(:parse_dimensions)
152
- nodes = states[0].product(*states[1..-1])
153
- paths = @tsp.send(:possible_paths, nodes)
154
- assert_equal paths.to_set, exp_paths.to_set
129
+ exp_paths = ["spec/models/concerns",
130
+ "spec/models/confirms",
131
+ "spec/modals/concerns",
132
+ "spec/modals/confirms",
133
+ "spec/controllers/concerns",
134
+ "spec/controllers/confirms"]
135
+
136
+ states = @tree_spell_checker.dimensions
137
+ nodes = states[0].product(*states[1..-1])
138
+ paths = @tree_spell_checker.possible_paths(nodes)
139
+
140
+ assert_equal paths, exp_paths
155
141
  end
156
142
 
157
143
  def test_works_out_state_space
158
- suggestions = @tsp.send(:plausible_dimensions, @test_str)
159
- assert_equal suggestions, [["spec"], ["models", "modals"], ["confirms", "concerns"]]
144
+ suggestions = @tree_spell_checker.plausible_dimensions(@test_str)
145
+
146
+ assert_equal [["spec"], %w[models modals], %w[confirms concerns]], suggestions
160
147
  end
161
148
 
162
149
  def test_parses_dictionary
163
- states = @tsp.send(:parse_dimensions)
164
- assert_equal states, [["spec"], ["models", "modals", "controllers"], ["concerns", "confirms"]]
150
+ states = @tree_spell_checker.dimensions
151
+
152
+ assert_equal [["spec"], %w[models modals controllers], %w[concerns confirms]], states
165
153
  end
166
154
 
167
155
  def test_parses_elementary_dictionary
168
- dictionary = ['spec/models/user_spec.rb', 'spec/services/account_spec.rb']
169
- tsp = DidYouMean::TreeSpellChecker.new(dictionary: dictionary)
170
- states = tsp.send(:parse_dimensions)
171
- assert_equal states, [['spec'], ['models', 'services']]
156
+ dimensions = DidYouMean::TreeSpellChecker
157
+ .new(dictionary: %w(spec/models/user_spec.rb spec/services/account_spec.rb))
158
+ .dimensions
159
+
160
+ assert_equal [["spec"], %w[models services]], dimensions
161
+ end
162
+
163
+ private
164
+
165
+ def assert_tree_spell(expected, input:, dictionary:, separator: "/")
166
+ suggestions = DidYouMean::TreeSpellChecker.new(dictionary: dictionary, separator: separator).correct(input)
167
+
168
+ assert_equal Array(expected), suggestions, "Expected to suggest #{expected}, but got #{suggestions.inspect}"
172
169
  end
173
170
  end
@@ -3,6 +3,8 @@ require_relative './helper'
3
3
  class VerboseFormatterTest < Test::Unit::TestCase
4
4
  def setup
5
5
  require_relative File.join(DidYouMean::TestHelper.root, 'verbose')
6
+
7
+ DidYouMean.formatter = DidYouMean::VerboseFormatter.new
6
8
  end
7
9
 
8
10
  def teardown
@@ -4,6 +4,9 @@ module TreeSpell
4
4
  # Simulate an error prone human typist
5
5
  # see doc/human_typo_api.md for the api description
6
6
  class HumanTypo
7
+ POPULAR_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ?<>,.!`+=-_":;@#$%^&*()'.split("").freeze
8
+ ACTION_TYPES = %i(insert transpose delete substitute).freeze
9
+
7
10
  def initialize(input, lambda: 0.05)
8
11
  @input = input
9
12
  check_input
@@ -15,7 +18,7 @@ module TreeSpell
15
18
  @word = input.dup
16
19
  i_place = initialize_i_place
17
20
  loop do
18
- action = action_type
21
+ action = ACTION_TYPES.sample
19
22
  @word = make_change action, i_place
20
23
  @len = word.length
21
24
  i_place += exponential
@@ -41,40 +44,17 @@ module TreeSpell
41
44
  (rand / (lambda / 2)).to_i
42
45
  end
43
46
 
44
- def rand_char
45
- popular_chars = alphabetic_characters + special_characters
46
- n = popular_chars.length
47
- popular_chars[rand(n)]
48
- end
49
-
50
- def alphabetic_characters
51
- ('a'..'z').to_a.join + ('A'..'Z').to_a.join
52
- end
53
-
54
- def special_characters
55
- '?<>,.!`+=-_":;@#$%^&*()'
56
- end
57
-
58
- def toss
59
- return +1 if rand >= 0.5
60
- -1
61
- end
62
-
63
- def action_type
64
- [:insert, :transpose, :delete, :substitute][rand(4)]
65
- end
66
-
67
47
  def make_change(action, i_place)
68
48
  cw = ChangeWord.new(word)
69
49
  case action
70
50
  when :delete
71
51
  cw.deletion(i_place)
72
52
  when :insert
73
- cw.insertion(i_place, rand_char)
53
+ cw.insertion(i_place, POPULAR_CHARS.sample)
74
54
  when :substitute
75
- cw.substitution(i_place, rand_char)
55
+ cw.substitution(i_place, POPULAR_CHARS.sample)
76
56
  when :transpose
77
- cw.transposition(i_place, toss)
57
+ cw.transposition(i_place, rand >= 0.5 ? +1 : -1)
78
58
  end
79
59
  end
80
60
 
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.4.0
4
+ version: 1.5.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: 2019-12-24 00:00:00.000000000 Z
11
+ date: 2020-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -44,6 +44,7 @@ files:
44
44
  - benchmark/levenshtein/memory_usage.rb
45
45
  - benchmark/levenshtein/speed.rb
46
46
  - benchmark/memory_usage.rb
47
+ - benchmark/require_path_checker.rb
47
48
  - benchmark/speed.yml
48
49
  - did_you_mean.gemspec
49
50
  - documentation/CHANGELOG.md.erb
@@ -54,8 +55,6 @@ files:
54
55
  - lib/did_you_mean.rb
55
56
  - lib/did_you_mean/core_ext/name_error.rb
56
57
  - lib/did_you_mean/experimental.rb
57
- - lib/did_you_mean/experimental/initializer_name_correction.rb
58
- - lib/did_you_mean/experimental/ivar_name_correction.rb
59
58
  - lib/did_you_mean/formatters/plain_formatter.rb
60
59
  - lib/did_you_mean/formatters/verbose_formatter.rb
61
60
  - lib/did_you_mean/jaro_winkler.rb
@@ -67,6 +66,7 @@ files:
67
66
  - lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb
68
67
  - lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb
69
68
  - lib/did_you_mean/spell_checkers/null_checker.rb
69
+ - lib/did_you_mean/spell_checkers/require_path_checker.rb
70
70
  - lib/did_you_mean/tree_spell_checker.rb
71
71
  - lib/did_you_mean/verbose.rb
72
72
  - lib/did_you_mean/version.rb
@@ -79,6 +79,7 @@ files:
79
79
  - test/spell_checking/test_class_name_check.rb
80
80
  - test/spell_checking/test_key_name_check.rb
81
81
  - test/spell_checking/test_method_name_check.rb
82
+ - test/spell_checking/test_require_path_check.rb
82
83
  - test/spell_checking/test_uncorrectable_name_check.rb
83
84
  - test/spell_checking/test_variable_name_check.rb
84
85
  - test/test_spell_checker.rb
@@ -108,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
109
  - !ruby/object:Gem::Version
109
110
  version: '0'
110
111
  requirements: []
111
- rubygems_version: 3.0.3
112
+ rubygems_version: 3.1.3
112
113
  signing_key:
113
114
  specification_version: 4
114
115
  summary: '"Did you mean?" experience in Ruby'
@@ -122,6 +123,7 @@ test_files:
122
123
  - test/spell_checking/test_class_name_check.rb
123
124
  - test/spell_checking/test_key_name_check.rb
124
125
  - test/spell_checking/test_method_name_check.rb
126
+ - test/spell_checking/test_require_path_check.rb
125
127
  - test/spell_checking/test_uncorrectable_name_check.rb
126
128
  - test/spell_checking/test_variable_name_check.rb
127
129
  - test/test_spell_checker.rb
@@ -1,20 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- require_relative '../levenshtein'
4
-
5
- module DidYouMean
6
- module Experimental
7
- module InitializerNameCorrection
8
- def method_added(name)
9
- super
10
-
11
- distance = Levenshtein.distance(name.to_s, 'initialize')
12
- if distance != 0 && distance <= 2
13
- warn "warning: #{name} might be misspelled, perhaps you meant initialize?"
14
- end
15
- end
16
- end
17
-
18
- ::Class.prepend(InitializerNameCorrection)
19
- end
20
- end
@@ -1,76 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- require_relative '../../did_you_mean'
4
-
5
- module DidYouMean
6
- module Experimental #:nodoc:
7
- class IvarNameCheckerBuilder #:nodoc:
8
- attr_reader :original_checker
9
-
10
- def initialize(original_checker) #:nodoc:
11
- @original_checker = original_checker
12
- end
13
-
14
- def new(no_method_error) #:nodoc:
15
- IvarNameChecker.new(no_method_error, original_checker: @original_checker)
16
- end
17
- end
18
-
19
- class IvarNameChecker #:nodoc:
20
- REPLS = {
21
- "(irb)" => -> { Readline::HISTORY.to_a.last }
22
- }
23
-
24
- TRACE = TracePoint.trace(:raise) do |tp|
25
- e = tp.raised_exception
26
-
27
- if SPELL_CHECKERS.include?(e.class.to_s) && !e.instance_variable_defined?(:@frame_binding)
28
- e.instance_variable_set(:@frame_binding, tp.binding)
29
- end
30
- end
31
-
32
- attr_reader :original_checker
33
-
34
- def initialize(no_method_error, original_checker: )
35
- @original_checker = original_checker.new(no_method_error)
36
-
37
- @location = no_method_error.backtrace_locations.first
38
- @ivar_names = no_method_error.frame_binding.receiver.instance_variables
39
-
40
- no_method_error.remove_instance_variable(:@frame_binding)
41
- end
42
-
43
- def corrections
44
- original_checker.corrections + ivar_name_corrections
45
- end
46
-
47
- def ivar_name_corrections
48
- @ivar_name_corrections ||= SpellChecker.new(dictionary: @ivar_names).correct(receiver_name.to_s)
49
- end
50
-
51
- private
52
-
53
- def receiver_name
54
- return unless @original_checker.receiver.nil?
55
-
56
- abs_path = @location.absolute_path
57
- lineno = @location.lineno
58
-
59
- /@(\w+)*\.#{@original_checker.method_name}/ =~ line(abs_path, lineno).to_s && $1
60
- end
61
-
62
- def line(abs_path, lineno)
63
- if REPLS[abs_path]
64
- REPLS[abs_path].call
65
- elsif File.exist?(abs_path)
66
- File.open(abs_path) do |file|
67
- file.detect { file.lineno == lineno }
68
- end
69
- end
70
- end
71
- end
72
- end
73
-
74
- NameError.send(:attr, :frame_binding)
75
- SPELL_CHECKERS['NoMethodError'] = Experimental::IvarNameCheckerBuilder.new(SPELL_CHECKERS['NoMethodError'])
76
- end