did_you_mean 1.4.0 → 1.5.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
  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