did_you_mean-1.2.1/0000755000004100000410000000000013263136567014213 5ustar www-datawww-datadid_you_mean-1.2.1/Rakefile0000644000004100000410000000222013263136567015654 0ustar www-datawww-datarequire 'bundler/gem_tasks' require 'rake/testtask' Rake::TestTask.new do |task| task.libs << "test" task.test_files = Dir['test/**/*_test.rb'].reject {|path| /(experimental)/ =~ path } task.verbose = true task.warning = true end Rake::TestTask.new("test:experimental") do |task| task.libs << "test" task.pattern = 'test/experimental/**/*_test.rb' task.verbose = true task.warning = true task.ruby_opts << "-rdid_you_mean/experimental" end task default: %i(test test:experimental) namespace :test do namespace :accuracy do desc "Download Wiktionary's Simple English data and save it as a dictionary" task :prepare do sh 'ruby evaluation/dictionary_generator.rb' end end desc "Calculate accuracy of the gems' spell checker" task :accuracy do if !File.exist?("evaluation/dictionary.yml") puts 'Generating dictionary for evaluation:' Rake::Task["test:accuracy:prepare"].execute puts "\n" end sh 'ruby evaluation/calculator.rb' end end namespace :benchmark do desc "Measure memory usage by the did_you_mean gem" task :memory do sh 'ruby benchmark/memory_usage.rb' end end did_you_mean-1.2.1/Gemfile0000644000004100000410000000025313263136567015506 0ustar www-datawww-datasource 'https://rubygems.org' # Specify your gem's dependencies in did_you_mean.gemspec gemspec gem 'benchmark-ips' gem 'memory_profiler' gem 'jaro_winkler', '>= 1.4.0' did_you_mean-1.2.1/doc/0000755000004100000410000000000013263136567014760 5ustar www-datawww-datadid_you_mean-1.2.1/doc/CHANGELOG.md.erb0000644000004100000410000000034613263136567017343 0ustar www-datawww-data<% releases.each do |release| %> ## [<%= release.name %>](https://github.com/<%= repository %>/tree/<%= release.tag_name %>) _released at <%= release.published_at %>_ <%= release.body.gsub(/\r\n/, "\n") %> <% end %> did_you_mean-1.2.1/doc/changelog_generator.rb0000644000004100000410000000156213263136567021306 0ustar www-datawww-datarequire 'octokit' require 'reverse_markdown' require 'erb' class ChangeLogGenerator attr :repository, :template_path, :changelog_path def initialize(repository, template_path: "CHANGELOG.md.erb", changelog_path: "CHANGELOG.md") @repository = repository @template_path = template_path @changelog_path = changelog_path end def generate_and_save! changelog_in_md = ERB.new(template).result(binding) changelog_in_html = Octokit.markdown(changelog_in_md, context: repository, mode: "gfm") File.open(changelog_path, 'w') do |file| file.write ReverseMarkdown.convert(changelog_in_html, github_flavored: true) end end private def template open("#{__dir__}/#{template_path}").read end def releases @releases ||= Octokit.releases(repository) end end ChangeLogGenerator.new("yuki24/did_you_mean").generate_and_save! did_you_mean-1.2.1/.ruby-version0000644000004100000410000000000613263136567016654 0ustar www-datawww-data2.5.1 did_you_mean-1.2.1/LICENSE.txt0000644000004100000410000000206413263136567016040 0ustar www-datawww-dataCopyright (c) 2014-2016 Yuki Nishijima MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. did_you_mean-1.2.1/.travis.yml0000644000004100000410000000033613263136567016326 0ustar www-datawww-datalanguage: ruby script: bundle exec rake cache: bundler sudo: false before_install: - gem install bundler after_success: - bundle exec rake test:accuracy - bundle exec rake benchmark:memory rvm: - 2.5.1 did_you_mean-1.2.1/benchmark/0000755000004100000410000000000013263136567016145 5ustar www-datawww-datadid_you_mean-1.2.1/benchmark/memory_usage.rb0000644000004100000410000000063213263136567021167 0ustar www-datawww-data# frozen-string-literal: true require 'memory_profiler' require 'did_you_mean' # public def foo; end # error = (self.fooo rescue $!) # executable = -> { error.to_s } METHODS = ''.methods INPUT = 'start_with?' collection = DidYouMean::SpellChecker.new(dictionary: METHODS) executable = proc { collection.correct(INPUT) } GC.disable MemoryProfiler.report { 100.times(&executable) }.pretty_print did_you_mean-1.2.1/benchmark/jaro_winkler/0000755000004100000410000000000013263136567020633 5ustar www-datawww-datadid_you_mean-1.2.1/benchmark/jaro_winkler/memory_usage.rb0000644000004100000410000000035213263136567023654 0ustar www-datawww-datarequire 'memory_profiler' require 'did_you_mean/jaro_winkler' str1, str2 = "user_signed_in?", "user_logged_in?" report = MemoryProfiler.report do 80.times do DidYouMean::Jaro.distance str1, str2 end end report.pretty_print did_you_mean-1.2.1/benchmark/jaro_winkler/speed.rb0000644000004100000410000000044413263136567022262 0ustar www-datawww-datarequire 'benchmark/ips' require 'did_you_mean' Benchmark.ips do |x| x.report "before" do DidYouMean::Jaro.before_distance "user_signed_in?", "user_logged_in?" end x.report "after" do DidYouMean::Jaro.after_distance "user_signed_in?", "user_logged_in?" end x.compare! end did_you_mean-1.2.1/benchmark/levenshtein/0000755000004100000410000000000013263136567020471 5ustar www-datawww-datadid_you_mean-1.2.1/benchmark/levenshtein/memory_usage.rb0000644000004100000410000000036013263136567023511 0ustar www-datawww-datarequire 'memory_profiler' require 'did_you_mean/levenshtein' str1, str2 = "user_signed_in?", "user_logged_in?" report = MemoryProfiler.report do 80.times do DidYouMean::Levenshtein.distance str1, str2 end end report.pretty_print did_you_mean-1.2.1/benchmark/levenshtein/speed.rb0000644000004100000410000000053013263136567022114 0ustar www-datawww-datarequire 'benchmark/ips' require 'did_you_mean' require 'did_you_mean/levenshtein' STR1, STR2 = "user_signed_in?", "user_logged_in?" Benchmark.ips do |x| x.report "enumerable" do DidYouMean::Levenshtein.before_distance STR1, STR2 end x.report "while" do DidYouMean::Levenshtein.after_distance STR1, STR2 end x.compare! end did_you_mean-1.2.1/lib/0000755000004100000410000000000013263136567014761 5ustar www-datawww-datadid_you_mean-1.2.1/lib/did_you_mean/0000755000004100000410000000000013263136567017415 5ustar www-datawww-datadid_you_mean-1.2.1/lib/did_you_mean/verbose.rb0000644000004100000410000000020413263136567021403 0ustar www-datawww-datarequire 'did_you_mean' require 'did_you_mean/formatters/verbose_formatter' DidYouMean.formatter = DidYouMean::VerboseFormatter.new did_you_mean-1.2.1/lib/did_you_mean/core_ext/0000755000004100000410000000000013263136567021225 5ustar www-datawww-datadid_you_mean-1.2.1/lib/did_you_mean/core_ext/name_error.rb0000644000004100000410000000076313263136567023711 0ustar www-datawww-datamodule DidYouMean module Correctable def original_message method(:to_s).super_method.call end def to_s msg = super.dup if !cause.respond_to?(:corrections) || cause.corrections.empty? msg << DidYouMean.formatter.message_for(corrections) end msg rescue super end def corrections spell_checker.corrections end def spell_checker @spell_checker ||= SPELL_CHECKERS[self.class.to_s].new(self) end end end did_you_mean-1.2.1/lib/did_you_mean/spell_checker.rb0000644000004100000410000000245413263136567022552 0ustar www-datawww-data# frozen-string-literal: true require "did_you_mean/levenshtein" require "did_you_mean/jaro_winkler" module DidYouMean class SpellChecker def initialize(dictionary: ) @dictionary = dictionary end def correct(input) input = normalize(input) threshold = input.length > 3 ? 0.834 : 0.77 words = @dictionary.select {|word| JaroWinkler.distance(normalize(word), input) >= threshold } words.reject! {|word| input == word.to_s } words.sort_by! {|word| JaroWinkler.distance(word.to_s, input) } words.reverse! # Correct mistypes threshold = (input.length * 0.25).ceil corrections = words.select {|c| Levenshtein.distance(normalize(c), input) <= threshold } # Correct misspells if corrections.empty? corrections = words.select do |word| word = normalize(word) length = input.length < word.length ? input.length : word.length Levenshtein.distance(word, input) < length end.first(1) end corrections end private def normalize(str_or_symbol) #:nodoc: str = if str_or_symbol.is_a?(String) str_or_symbol.dup else str_or_symbol.to_s end str.downcase! str.tr!("@", "") str end end end did_you_mean-1.2.1/lib/did_you_mean/experimental/0000755000004100000410000000000013263136567022112 5ustar www-datawww-datadid_you_mean-1.2.1/lib/did_you_mean/experimental/initializer_name_correction.rb0000644000004100000410000000072413263136567030214 0ustar www-datawww-data# frozen-string-literal: true require 'did_you_mean/levenshtein' module DidYouMean module Experimental module InitializerNameCorrection def method_added(name) super distance = Levenshtein.distance(name.to_s, 'initialize') if distance != 0 && distance <= 2 warn "warning: #{name} might be misspelled, perhaps you meant initialize?" end end end ::Class.prepend(InitializerNameCorrection) end end did_you_mean-1.2.1/lib/did_you_mean/experimental/ivar_name_correction.rb0000644000004100000410000000401613263136567026630 0ustar www-datawww-data# frozen-string-literal: true require 'did_you_mean' module DidYouMean module Experimental #:nodoc: class IvarNameCheckerBuilder #:nodoc: attr_reader :original_checker def initialize(original_checker) #:nodoc: @original_checker = original_checker end def new(no_method_error) #:nodoc: IvarNameChecker.new(no_method_error, original_checker: @original_checker) end end class IvarNameChecker #:nodoc: REPLS = { "(irb)" => -> { Readline::HISTORY.to_a.last } } TRACE = TracePoint.trace(:raise) do |tp| e = tp.raised_exception if SPELL_CHECKERS.include?(e.class.to_s) && !e.instance_variable_defined?(:@frame_binding) e.instance_variable_set(:@frame_binding, tp.binding) end end attr_reader :original_checker def initialize(no_method_error, original_checker: ) @original_checker = original_checker.new(no_method_error) @location = no_method_error.backtrace_locations.first @ivar_names = no_method_error.frame_binding.receiver.instance_variables end def corrections original_checker.corrections + ivar_name_corrections end def ivar_name_corrections @ivar_name_corrections ||= SpellChecker.new(dictionary: @ivar_names).correct(receiver_name.to_s) end private def receiver_name return unless @original_checker.receiver.nil? abs_path = @location.absolute_path lineno = @location.lineno /@(\w+)*\.#{@original_checker.method_name}/ =~ line(abs_path, lineno).to_s && $1 end def line(abs_path, lineno) if REPLS[abs_path] REPLS[abs_path].call elsif File.exist?(abs_path) File.open(abs_path) do |file| file.detect { file.lineno == lineno } end end end end end NameError.send(:attr, :frame_binding) SPELL_CHECKERS['NoMethodError'] = Experimental::IvarNameCheckerBuilder.new(SPELL_CHECKERS['NoMethodError']) end did_you_mean-1.2.1/lib/did_you_mean/jaro_winkler.rb0000644000004100000410000000345113263136567022433 0ustar www-datawww-datamodule DidYouMean module Jaro module_function def distance(str1, str2) str1, str2 = str2, str1 if str1.length > str2.length length1, length2 = str1.length, str2.length m = 0.0 t = 0.0 range = (length2 / 2).floor - 1 range = 0 if range < 0 flags1 = 0 flags2 = 0 # Avoid duplicating enumerable objects str1_codepoints = str1.codepoints str2_codepoints = str2.codepoints i = 0 while i < length1 last = i + range j = (i >= range) ? i - range : 0 while j <= last if flags2[j] == 0 && str1_codepoints[i] == str2_codepoints[j] flags2 |= (1 << j) flags1 |= (1 << i) m += 1 break end j += 1 end i += 1 end k = i = 0 while i < length1 if flags1[i] != 0 j = index = k k = while j < length2 index = j break(j + 1) if flags2[j] != 0 j += 1 end t += 1 if str1_codepoints[i] != str2_codepoints[index] end i += 1 end t = (t / 2).floor m == 0 ? 0 : (m / length1 + m / length2 + (m - t) / m) / 3 end end module JaroWinkler WEIGHT = 0.1 THRESHOLD = 0.7 module_function def distance(str1, str2) jaro_distance = Jaro.distance(str1, str2) if jaro_distance > THRESHOLD codepoints2 = str2.codepoints prefix_bonus = 0 i = 0 str1.each_codepoint do |char1| char1 == codepoints2[i] && i < 4 ? prefix_bonus += 1 : break i += 1 end jaro_distance + (prefix_bonus * WEIGHT * (1 - jaro_distance)) else jaro_distance end end end end did_you_mean-1.2.1/lib/did_you_mean/spell_checkers/0000755000004100000410000000000013263136567022403 5ustar www-datawww-datadid_you_mean-1.2.1/lib/did_you_mean/spell_checkers/null_checker.rb0000644000004100000410000000015013263136567025362 0ustar www-datawww-datamodule DidYouMean class NullChecker def initialize(*); end def corrections; [] end end end did_you_mean-1.2.1/lib/did_you_mean/spell_checkers/name_error_checkers/0000755000004100000410000000000013263136567026403 5ustar www-datawww-datadid_you_mean-1.2.1/lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb0000644000004100000410000000233213263136567032521 0ustar www-datawww-data# frozen-string-literal: true require 'delegate' require "did_you_mean/spell_checker" module DidYouMean class ClassNameChecker attr_reader :class_name def initialize(exception) @class_name, @receiver, @original_message = exception.name, exception.receiver, exception.original_message end def corrections @corrections ||= SpellChecker.new(dictionary: class_names) .correct(class_name) .map(&:full_name) .reject {|qualified_name| @original_message.include?(qualified_name) } end def class_names scopes.flat_map do |scope| scope.constants.map do |c| ClassName.new(c, scope == Object ? "" : "#{scope}::") end end end def scopes @scopes ||= @receiver.to_s.split("::").inject([Object]) do |_scopes, scope| _scopes << _scopes.last.const_get(scope) end.uniq end class ClassName < SimpleDelegator attr :namespace def initialize(name, namespace = '') super(name) @namespace = namespace end def full_name self.class.new("#{namespace}#{__getobj__}") end end private_constant :ClassName end end did_you_mean-1.2.1/lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb0000644000004100000410000000202313263136567033176 0ustar www-datawww-data# frozen-string-literal: true require "did_you_mean/spell_checker" module DidYouMean class VariableNameChecker attr_reader :name, :method_names, :lvar_names, :ivar_names, :cvar_names NAMES_TO_EXCLUDE = { 'foo' => [:fork] } NAMES_TO_EXCLUDE.default = [] RB_PREDEFINED_OBJECTS = [:false, :true, :nil] def initialize(exception) @name = exception.name.to_s.tr("@", "") @lvar_names = exception.respond_to?(:local_variables) ? exception.local_variables : [] receiver = exception.receiver @method_names = receiver.methods + receiver.private_methods @ivar_names = receiver.instance_variables @cvar_names = receiver.class.class_variables @cvar_names += receiver.class_variables if receiver.kind_of?(Module) end def corrections @corrections ||= SpellChecker .new(dictionary: (RB_PREDEFINED_OBJECTS + lvar_names + method_names + ivar_names + cvar_names)) .correct(name) - NAMES_TO_EXCLUDE[@name] end end end did_you_mean-1.2.1/lib/did_you_mean/spell_checkers/name_error_checkers.rb0000644000004100000410000000113513263136567026730 0ustar www-datawww-datarequire 'did_you_mean/spell_checkers/name_error_checkers/class_name_checker' require 'did_you_mean/spell_checkers/name_error_checkers/variable_name_checker' module DidYouMean class << (NameErrorCheckers = Object.new) def new(exception) case exception.original_message when /uninitialized constant/ ClassNameChecker when /undefined local variable or method/, /undefined method/, /uninitialized class variable/, /no member '.*' in struct/ VariableNameChecker else NullChecker end.new(exception) end end end did_you_mean-1.2.1/lib/did_you_mean/spell_checkers/key_error_checker.rb0000644000004100000410000000046613263136567026423 0ustar www-datawww-datarequire "did_you_mean/spell_checker" module DidYouMean class KeyErrorChecker def initialize(key_error) @key = key_error.key @keys = key_error.receiver.keys end def corrections @corrections ||= SpellChecker.new(dictionary: @keys).correct(@key).map(&:inspect) end end end did_you_mean-1.2.1/lib/did_you_mean/spell_checkers/method_name_checker.rb0000644000004100000410000000142213263136567026673 0ustar www-datawww-datarequire "did_you_mean/spell_checker" module DidYouMean class MethodNameChecker attr_reader :method_name, :receiver NAMES_TO_EXCLUDE = { NilClass => nil.methods } NAMES_TO_EXCLUDE.default = [] def initialize(exception) @method_name = exception.name @receiver = exception.receiver @private_call = exception.respond_to?(:private_call?) ? exception.private_call? : false end def corrections @corrections ||= SpellChecker.new(dictionary: method_names).correct(method_name) - NAMES_TO_EXCLUDE[@receiver.class] end def method_names method_names = receiver.methods + receiver.singleton_methods method_names += receiver.private_methods if @private_call method_names.uniq! method_names end end end did_you_mean-1.2.1/lib/did_you_mean/version.rb0000644000004100000410000000005213263136567021424 0ustar www-datawww-datamodule DidYouMean VERSION = "1.2.1" end did_you_mean-1.2.1/lib/did_you_mean/formatters/0000755000004100000410000000000013263136567021603 5ustar www-datawww-datadid_you_mean-1.2.1/lib/did_you_mean/formatters/verbose_formatter.rb0000644000004100000410000000043713263136567025664 0ustar www-datawww-data# frozen-string-literal: true module DidYouMean class VerboseFormatter def message_for(corrections) return "" if corrections.empty? output = "\n\n Did you mean? ".dup output << corrections.join("\n ") output << "\n " end end end did_you_mean-1.2.1/lib/did_you_mean/formatters/plain_formatter.rb0000644000004100000410000000032713263136567025320 0ustar www-datawww-data# frozen-string-literal: true module DidYouMean class PlainFormatter def message_for(corrections) corrections.empty? ? "" : "\nDid you mean? #{corrections.join("\n ")}" end end end did_you_mean-1.2.1/lib/did_you_mean/experimental.rb0000644000004100000410000000017113263136567022436 0ustar www-datawww-datarequire 'did_you_mean/experimental/initializer_name_correction' require 'did_you_mean/experimental/ivar_name_correction' did_you_mean-1.2.1/lib/did_you_mean/verbose_formatter.rb0000644000004100000410000000047113263136567023474 0ustar www-datawww-datarequire 'did_you_mean' require 'did_you_mean/formatters/verbose_formatter' DidYouMean.formatter = DidYouMean::VerboseFormatter.new warn '`require "did_you_mean/verbose_formatter"\' has been deprecated and will be removed' \ " in the next major Ruby version. Please require 'did_you_mean/verbose' instead." did_you_mean-1.2.1/lib/did_you_mean/levenshtein.rb0000644000004100000410000000254113263136567022270 0ustar www-datawww-datamodule DidYouMean module Levenshtein # :nodoc: # This code is based directly on the Text gem implementation # Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher. # # Returns a value representing the "cost" of transforming str1 into str2 def distance(str1, str2) n = str1.length m = str2.length return m if n.zero? return n if m.zero? d = (0..m).to_a x = nil # to avoid duplicating an enumerable object, create it outside of the loop str2_codepoints = str2.codepoints str1.each_codepoint.with_index(1) do |char1, i| j = 0 while j < m cost = (char1 == str2_codepoints[j]) ? 0 : 1 x = min3( d[j+1] + 1, # insertion i + 1, # deletion d[j] + cost # substitution ) d[j] = i i = x j += 1 end d[m] = x end x end module_function :distance private # detects the minimum value out of three arguments. This method is # faster than `[a, b, c].min` and puts less GC pressure. # See https://github.com/yuki24/did_you_mean/pull/1 for a performance # benchmark. def min3(a, b, c) if a < b && a < c a elsif b < c b else c end end module_function :min3 end end did_you_mean-1.2.1/lib/did_you_mean.rb0000644000004100000410000000303613263136567017744 0ustar www-datawww-datarequire "did_you_mean/version" require "did_you_mean/core_ext/name_error" require "did_you_mean/spell_checker" require 'did_you_mean/spell_checkers/name_error_checkers' require 'did_you_mean/spell_checkers/method_name_checker' require 'did_you_mean/spell_checkers/key_error_checker' require 'did_you_mean/spell_checkers/null_checker' require "did_you_mean/formatters/plain_formatter" module DidYouMean class DeprecatedIgnoredCallers < Array %i( + << []= insert unshift push ).each do |method_name| eval <<-RUBY, nil, __FILE__, __LINE__ + 1 def #{method_name}(*) warn "IGNORED_CALLERS has been deprecated and has no effect." super end RUBY end end IGNORED_CALLERS = DeprecatedIgnoredCallers.new SPELL_CHECKERS = Hash.new(NullChecker) SPELL_CHECKERS.merge!({ "NameError" => NameErrorCheckers, "NoMethodError" => MethodNameChecker, "KeyError" => KeyErrorChecker }) NameError.prepend DidYouMean::Correctable KeyError.prepend DidYouMean::Correctable def self.formatter @@formatter end def self.formatter=(formatter) @@formatter = formatter end self.formatter = PlainFormatter.new # Deprecated formatter class Formatter #:nodoc: def initialize(corrections = []) @corrections = corrections end def to_s return "" if @corrections.empty? output = "\nDid you mean? ".dup output << @corrections.join("\n ") end end deprecate_constant :Formatter end did_you_mean-1.2.1/did_you_mean.gemspec0000644000004100000410000000166513263136567020224 0ustar www-datawww-data# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'did_you_mean/version' Gem::Specification.new do |spec| spec.name = "did_you_mean" spec.version = DidYouMean::VERSION spec.authors = ["Yuki Nishijima"] spec.email = ["mail@yukinishijima.net"] spec.summary = '"Did you mean?" experience in Ruby' spec.description = 'The gem that has been saving people from typos since 2014.' spec.homepage = "https://github.com/yuki24/did_you_mean" spec.license = "MIT" spec.files = `git ls-files`.split($/).reject{|path| path.start_with?('evaluation/') } spec.test_files = spec.files.grep(%r{^(test)/}) spec.require_paths = ["lib"] spec.required_ruby_version = '>= 2.5.0' spec.add_development_dependency "bundler" spec.add_development_dependency "rake" spec.add_development_dependency "minitest" end did_you_mean-1.2.1/test/0000755000004100000410000000000013263136567015172 5ustar www-datawww-datadid_you_mean-1.2.1/test/deprecated_formatter_test.rb0000644000004100000410000000052313263136567022741 0ustar www-datawww-datarequire 'test_helper' class DeprecatedFormatterTest < Minitest::Test def test_deprecated_formatter assert_output nil, /test\/deprecated_formatter_test.rb:6: warning: constant DidYouMean::Formatter is deprecated/ do assert_equal "\nDid you mean? does_exist", ::DidYouMean::Formatter.new(['does_exist']).to_s end end end did_you_mean-1.2.1/test/core_ext/0000755000004100000410000000000013263136567017002 5ustar www-datawww-datadid_you_mean-1.2.1/test/core_ext/name_error_extension_test.rb0000644000004100000410000000223213263136567024612 0ustar www-datawww-datarequire 'test_helper' class NameErrorExtensionTest < Minitest::Test SPELL_CHECKERS = DidYouMean::SPELL_CHECKERS class TestSpellChecker def initialize(*); end def corrections; ["does_exist"]; end end def setup @org, SPELL_CHECKERS['NameError'] = SPELL_CHECKERS['NameError'], TestSpellChecker @error = assert_raises(NameError){ doesnt_exist } end def teardown SPELL_CHECKERS['NameError'] = @org end def test_message message = <<~MESSAGE.chomp undefined local variable or method `doesnt_exist' for #{to_s} Did you mean? does_exist MESSAGE assert_equal message, @error.to_s assert_equal message, @error.message end def test_to_s_does_not_make_disruptive_changes_to_error_message error = assert_raises(NameError) do raise NameError, "uninitialized constant Object" end error.to_s assert_equal 1, error.to_s.scan("Did you mean?").count end end class DeprecatedIgnoreCallersTest < Minitest::Test def test_ignore assert_output nil, "IGNORED_CALLERS has been deprecated and has no effect.\n" do DidYouMean::IGNORED_CALLERS << /( |`)do_not_correct_typo'/ end end end did_you_mean-1.2.1/test/edit_distance/0000755000004100000410000000000013263136567017771 5ustar www-datawww-datadid_you_mean-1.2.1/test/edit_distance/jaro_winkler_test.rb0000644000004100000410000000257413263136567024053 0ustar www-datawww-datarequire 'test_helper' # These tests were originally written by Jian Weihang (簡煒航) as part of his work # on the jaro_winkler gem. The original code could be found here: # https://github.com/tonytonyjan/jaro_winkler/blob/9bd12421/spec/jaro_winkler_spec.rb # # Copyright (c) 2014 Jian Weihang class JaroWinklerTest < Minitest::Test def test_jaro_winkler_distance assert_distance 0.9667, 'henka', 'henkan' assert_distance 1.0, 'al', 'al' assert_distance 0.9611, 'martha', 'marhta' assert_distance 0.8324, 'jones', 'johnson' assert_distance 0.9167, 'abcvwxyz', 'zabcvwxy' assert_distance 0.9583, 'abcvwxyz', 'cabvwxyz' assert_distance 0.84, 'dwayne', 'duane' assert_distance 0.8133, 'dixon', 'dicksonx' assert_distance 0.0, 'fvie', 'ten' assert_distance 0.9067, 'does_exist', 'doesnt_exist' assert_distance 1.0, 'x', 'x' end def test_jarowinkler_distance_with_utf8_strings assert_distance 0.9818, '變形金剛4:絕跡重生', '變形金剛4: 絕跡重生' assert_distance 0.8222, '連勝文', '連勝丼' assert_distance 0.8222, '馬英九', '馬英丸' assert_distance 0.6667, '良い', 'いい' end private def assert_distance(score, str1, str2) assert_equal score, DidYouMean::JaroWinkler.distance(str1, str2).round(4) end end did_you_mean-1.2.1/test/experimental/0000755000004100000410000000000013263136567017667 5ustar www-datawww-datadid_you_mean-1.2.1/test/experimental/method_name_checker_test.rb0000644000004100000410000000056113263136567025221 0ustar www-datawww-datarequire 'test_helper' class ExperimentalMethodNameCorrectionTest < Minitest::Test def test_corrects_incorrect_ivar_name @number = 1 @nubmer = nil error = assert_raises(NoMethodError) { @nubmer.zero? } remove_instance_variable :@nubmer assert_correction :@number, error.corrections assert_match "Did you mean? @number", error.to_s end end did_you_mean-1.2.1/test/experimental/initializer_name_correction_test.rb0000644000004100000410000000063513263136567027031 0ustar www-datawww-datarequire 'test_helper' class InitializerNameCorrectionTest < Minitest::Test def test_corrects_wrong_initializer_name assert_output nil, "warning: intialize might be misspelled, perhaps you meant initialize?\n" do Class.new { def intialize; end } end end def test_does_not_correct_correct_initializer_name assert_output nil, "" do Class.new { def initialize; end } end end end did_you_mean-1.2.1/test/fixtures/0000755000004100000410000000000013263136567017043 5ustar www-datawww-datadid_you_mean-1.2.1/test/fixtures/book.rb0000644000004100000410000000004313263136567020317 0ustar www-datawww-dataclass Book class Cover end end did_you_mean-1.2.1/test/test_helper.rb0000644000004100000410000000055113263136567020036 0ustar www-datawww-datarequire 'minitest/autorun' require 'minitest/pride' require 'did_you_mean' puts "DidYouMean version: #{DidYouMean::VERSION}" module DidYouMean::TestHelper def assert_correction(expected, array) assert_equal Array(expected), array, "Expected #{array.inspect} to only include #{expected.inspect}" end end MiniTest::Test.include(DidYouMean::TestHelper) did_you_mean-1.2.1/test/spell_checker_test.rb0000644000004100000410000000571613263136567021372 0ustar www-datawww-datarequire 'test_helper' class SpellCheckerTest < Minitest::Test def test_spell_checker_corrects_mistypes assert_spell 'foo', input: 'doo', dictionary: ['foo', 'fork'] assert_spell 'email', input: 'meail', dictionary: ['email', 'fail', 'eval'] assert_spell 'fail', input: 'fial', dictionary: ['email', 'fail', 'eval'] assert_spell 'fail', input: 'afil', dictionary: ['email', 'fail', 'eval'] assert_spell 'eval', input: 'eavl', dictionary: ['email', 'fail', 'eval'] assert_spell 'eval', input: 'veal', dictionary: ['email', 'fail', 'eval'] assert_spell 'sub!', input: 'suv!', dictionary: ['sub', 'gsub', 'sub!'] assert_spell 'sub', input: 'suv', dictionary: ['sub', 'gsub', 'sub!'] assert_spell %w(gsub! gsub), input: 'gsuv!', dictionary: %w(sub gsub gsub!) assert_spell %w(sub! sub gsub!), input: 'ssub!', dictionary: %w(sub sub! gsub gsub!) group_methods = %w(groups group_url groups_url group_path) assert_spell 'groups', input: 'group', dictionary: group_methods group_classes = %w( GroupMembership GroupMembershipPolicy GroupMembershipDecorator GroupMembershipSerializer GroupHelper Group GroupMailer NullGroupMembership ) assert_spell 'GroupMembership', dictionary: group_classes, input: 'GroupMemberhip' assert_spell 'GroupMembershipDecorator', dictionary: group_classes, input: 'GroupMemberhipDecorator' names = %w(first_name_change first_name_changed? first_name_will_change!) assert_spell names, input: 'first_name_change!', dictionary: names assert_empty DidYouMean::SpellChecker.new(dictionary: ['proc']).correct('product_path') assert_empty DidYouMean::SpellChecker.new(dictionary: ['fork']).correct('fooo') end def test_spell_checker_corrects_misspells assert_spell 'descendants', input: 'dependents', dictionary: ['descendants'] assert_spell 'drag_to', input: 'drag', dictionary: ['drag_to'] assert_spell 'set_result_count', input: 'set_result', dictionary: ['set_result_count'] end def test_spell_checker_sorts_results_by_simiarity expected = %w( name12345 name1234 name123 ) actual = DidYouMean::SpellChecker.new(dictionary: %w( name12 name123 name1234 name12345 name123456 )).correct('name123456') assert_equal expected, actual end def test_spell_checker_excludes_input_from_dictionary assert_empty DidYouMean::SpellChecker.new(dictionary: ['input']).correct('input') assert_empty DidYouMean::SpellChecker.new(dictionary: [:input]).correct('input') assert_empty DidYouMean::SpellChecker.new(dictionary: ['input']).correct(:input) end private def assert_spell(expected, input: , dictionary: ) corrections = DidYouMean::SpellChecker.new(dictionary: dictionary).correct(input) assert_equal Array(expected), corrections, "Expected to suggest #{expected}, but got #{corrections.inspect}" end end did_you_mean-1.2.1/test/spell_checking/0000755000004100000410000000000013263136567020144 5ustar www-datawww-datadid_you_mean-1.2.1/test/spell_checking/key_name_check_test.rb0000644000004100000410000000263313263136567024461 0ustar www-datawww-datarequire "test_helper" class KeyNameCheckTest < Minitest::Test def test_corrects_hash_key_name_with_fetch hash = { "foo" => 1, bar: 2 } error = assert_raises(KeyError) { hash.fetch(:bax) } assert_correction ":bar", error.corrections assert_match "Did you mean? :bar", error.to_s error = assert_raises(KeyError) { hash.fetch("fooo") } assert_correction %("foo"), error.corrections assert_match %(Did you mean? "foo"), error.to_s end def test_corrects_hash_key_name_with_fetch_values hash = { "foo" => 1, bar: 2 } error = assert_raises(KeyError) { hash.fetch_values("foo", :bar, :bax) } assert_correction ":bar", error.corrections assert_match "Did you mean? :bar", error.to_s error = assert_raises(KeyError) { hash.fetch_values("foo", :bar, "fooo") } assert_correction %("foo"), error.corrections assert_match %(Did you mean? "foo"), error.to_s end def test_corrects_sprintf_key_name error = assert_raises(KeyError) { sprintf("%d", {fooo: 1}) } assert_correction ":fooo", error.corrections assert_match "Did you mean? :fooo", error.to_s end def test_corrects_env_key_name ENV["FOO"] = "1" ENV["BAR"] = "2" error = assert_raises(KeyError) { ENV.fetch("BAX") } assert_correction %("BAR"), error.corrections assert_match %(Did you mean? "BAR"), error.to_s ensure ENV.delete("FOO") ENV.delete("BAR") end end did_you_mean-1.2.1/test/spell_checking/variable_name_check_test.rb0000644000004100000410000000614413263136567025457 0ustar www-datawww-datarequire 'test_helper' class VariableNameCheckTest < Minitest::Test class User def initialize @email_address = 'email_address@address.net' @first_name = nil @last_name = nil end def first_name; end def to_s "#{@first_name} #{@last_name} <#{email_address}>" end private def cia_codename; "Alexa" end end module UserModule def from_module; end end def setup @user = User.new.extend(UserModule) end def test_corrections_include_instance_method error = assert_raises(NameError) do @user.instance_eval { flrst_name } end @user.instance_eval do remove_instance_variable :@first_name remove_instance_variable :@last_name end assert_correction :first_name, error.corrections assert_match "Did you mean? first_name", error.to_s end def test_corrections_include_method_from_module error = assert_raises(NameError) do @user.instance_eval { fr0m_module } end assert_correction :from_module, error.corrections assert_match "Did you mean? from_module", error.to_s end def test_corrections_include_local_variable_name person = person = nil error = (eprson rescue $!) # Do not use @assert_raises here as it changes a scope. assert_correction :person, error.corrections assert_match "Did you mean? person", error.to_s end def test_corrections_include_ruby_predefined_objects some_var = nil false_error = assert_raises(NameError) do some_var = fals end true_error = assert_raises(NameError) do some_var = treu end nil_error = assert_raises(NameError) do some_var = nol end assert_correction :false, false_error.corrections assert_match "Did you mean? false", false_error.to_s assert_correction :true, true_error.corrections assert_match "Did you mean? true", true_error.to_s assert_correction :nil, nil_error.corrections assert_match "Did you mean? nil", nil_error.to_s end def test_corrections_include_instance_variable_name error = assert_raises(NameError){ @user.to_s } assert_correction :@email_address, error.corrections assert_match "Did you mean? @email_address", error.to_s end def test_corrections_include_private_method error = assert_raises(NameError) do @user.instance_eval { cia_code_name } end assert_correction :cia_codename, error.corrections assert_match "Did you mean? cia_codename", error.to_s end @@does_exist = true def test_corrections_include_class_variable_name error = assert_raises(NameError){ @@doesnt_exist } assert_correction :@@does_exist, error.corrections assert_match "Did you mean? @@does_exist", error.to_s end def test_struct_name_error value = Struct.new(:does_exist).new error = assert_raises(NameError){ value[:doesnt_exist] } assert_correction [:does_exist, :does_exist=], error.corrections assert_match "Did you mean? does_exist", error.to_s end def test_exclude_typical_incorrect_suggestions error = assert_raises(NameError){ foo } assert_empty error.corrections end end did_you_mean-1.2.1/test/spell_checking/class_name_check_test.rb0000644000004100000410000000406013263136567024772 0ustar www-datawww-datarequire 'test_helper' module ACRONYM end class Project def self.bo0k Bo0k end end class Book class TableOfContents; end def tableof_contents TableofContents end class Page def tableof_contents TableofContents end def self.tableof_contents TableofContents end end end class ClassNameCheckTest < Minitest::Test def test_corrections error = assert_raises(NameError) { ::Bo0k } assert_correction "Book", error.corrections end def test_corrections_include_case_specific_class_name error = assert_raises(NameError) { ::Acronym } assert_correction "ACRONYM", error.corrections end def test_corrections_include_top_level_class_name error = assert_raises(NameError) { Project.bo0k } assert_correction "Book", error.corrections end def test_names_in_corrections_have_namespaces error = assert_raises(NameError) { ::Book::TableofContents } assert_correction "Book::TableOfContents", error.corrections end def test_corrections_candidates_for_names_in_upper_level_scopes error = assert_raises(NameError) { Book::Page.tableof_contents } assert_correction "Book::TableOfContents", error.corrections end def test_corrections_should_work_from_within_instance_method error = assert_raises(NameError) { ::Book.new.tableof_contents } assert_correction "Book::TableOfContents", error.corrections end def test_corrections_should_work_from_within_instance_method_on_nested_class error = assert_raises(NameError) { ::Book::Page.new.tableof_contents } assert_correction "Book::TableOfContents", error.corrections end def test_does_not_suggest_user_input error = assert_raises(NameError) { ::Book::Cover } # This is a weird require, but in a multi-threaded condition, a constant may # be loaded between when a NameError occurred and when the spell checker # attemps to find a possible suggestion. The manual require here simulates # a race condition a single test. require_relative '../fixtures/book' assert_empty error.corrections end end did_you_mean-1.2.1/test/spell_checking/uncorrectable_name_check_test.rb0000644000004100000410000000047313263136567026521 0ustar www-datawww-datarequire 'test_helper' class UncorrectableNameCheckTest < Minitest::Test class FirstNameError < NameError; end def setup @error = assert_raises(FirstNameError) do raise FirstNameError, "Other name error" end end def test_message assert_equal "Other name error", @error.message end end did_you_mean-1.2.1/test/spell_checking/method_name_check_test.rb0000644000004100000410000000572513263136567025156 0ustar www-datawww-datarequire 'test_helper' class MethodNameCheckTest < Minitest::Test class User def friends; end def first_name; end def descendants; end def call_incorrect_private_method raiae NoMethodError end def raise_no_method_error self.firstname rescue NoMethodError => e raise e, e.message, e.backtrace end protected def the_protected_method; end private def friend; end def the_private_method; end class << self def load; end end end module UserModule def from_module; end end def setup @user = User.new.extend(UserModule) end def test_corrections_include_instance_method error = assert_raises(NoMethodError){ @user.flrst_name } assert_correction :first_name, error.corrections assert_match "Did you mean? first_name", error.to_s end def test_corrections_include_private_method error = assert_raises(NoMethodError){ @user.friend } assert_correction :friends, error.corrections assert_match "Did you mean? friends", error.to_s end def test_corrections_include_method_from_module error = assert_raises(NoMethodError){ @user.fr0m_module } assert_correction :from_module, error.corrections assert_match "Did you mean? from_module", error.to_s end def test_corrections_include_class_method error = assert_raises(NoMethodError){ User.l0ad } assert_correction :load, error.corrections assert_match "Did you mean? load", error.to_s end def test_private_methods_should_not_be_suggested error = assert_raises(NoMethodError){ User.new.the_protected_method } refute_includes error.corrections, :the_protected_method error = assert_raises(NoMethodError){ User.new.the_private_method } refute_includes error.corrections, :the_private_method end def test_corrections_when_private_method_is_called_with_args error = assert_raises(NoMethodError){ @user.call_incorrect_private_method } assert_correction :raise, error.corrections assert_match "Did you mean? raise", error.to_s end def test_exclude_methods_on_nil error = assert_raises(NoMethodError){ nil.map } assert_empty error.corrections end def test_does_not_exclude_custom_methods_on_nil def nil.empty? end error = assert_raises(NoMethodError){ nil.empty } assert_correction :empty?, error.corrections ensure NilClass.class_eval { undef empty? } end def test_does_not_append_suggestions_twice error = assert_raises NoMethodError do begin @user.firstname rescue NoMethodError => e raise e, e.message, e.backtrace end end assert_equal 1, error.to_s.scan(/Did you mean/).count end def test_does_not_append_suggestions_three_times error = assert_raises NoMethodError do begin @user.raise_no_method_error rescue NoMethodError => e raise e, e.message, e.backtrace end end assert_equal 1, error.to_s.scan(/Did you mean/).count end end did_you_mean-1.2.1/test/verbose_formatter_test.rb0000644000004100000410000000075513263136567022315 0ustar www-datawww-datarequire 'test_helper' class VerboseFormatterTest < Minitest::Test def setup require 'did_you_mean/verbose' does_exist = does_exist = nil @error = assert_raises(NameError){ doesnt_exist } end def teardown DidYouMean.formatter = DidYouMean::PlainFormatter.new end def test_message assert_equal <<~MESSAGE.chomp, @error.message undefined local variable or method `doesnt_exist' for #{to_s} Did you mean? does_exist MESSAGE end end did_you_mean-1.2.1/.gitignore0000644000004100000410000000027513263136567016207 0ustar www-datawww-data*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc test/tmp test/version_tmp tmp log evaluation/dictionary.yml benchmark/results did_you_mean-1.2.1/CHANGELOG.md0000644000004100000410000003626313263136567016036 0ustar www-datawww-data## [v1.1.2](https://github.com/yuki24/did_you_mean/tree/v1.1.2) _released at 2017-09-24 07:28:48 UTC_ **This version is compatible with Ruby 2.4 and older** #### Bug Fixes - Fixed a bug where `did_you_mean` shows duplicate suggestions when the exception is raised multiple times ([#84](https://github.com/yuki24/did_you_mean/pull/84), [c2e4008](https://github.com/yuki24/did_you_mean/commit/c2e40083cef604c00ccd10efc6d7a5036ad9eb5b)) ## [v1.1.1](https://github.com/yuki24/did_you_mean/tree/v1.1.1) _released at 2017-09-24 07:24:02 UTC_ ### This version has been yanked from Rubygems.org and is not available. ## [v1.1.0](https://github.com/yuki24/did_you_mean/tree/v1.1.0) _released at 2016-12-19 23:19:06 UTC_ The version `1.1.0` only has support for Ruby 2.4.0 and later. Also, all patch releasess under `1.1.*` will only be compatible with Ruby 2.4.0 and later as well. Versions under `1.0.*` will still be maintained until Ruby 2.3 is deprecated. Any other versions below `1.0` will no longer be maintained. #### New Features - Suggest a method name on a NameError from the `Struct#[]` or `Struct#[]=` method ([#73](https://github.com/yuki24/did_you_mean/pull/73)): ```ruby Struct.new(:foo).new[:fooo] # => NameError: no member 'fooo' in struct # Did you mean? foo # foo= ``` - Added a public interface for the gem's spell checker: ```ruby DidYouMean::SpellChecker.new(dictionary: ['email', 'fail', 'eval']).correct('meail') # => ['email'] ``` - Methods defined on `nil` by default are no longer suggested. Note that methods, defined after the gem is loaded, will still be suggested (e.g. ActiveSupport). #### Bug Fixes - Fixed a bug where private method names were added to the dictionary when an argument was passed in to a public method. Use the `NoMethodError#private_call?` method instead ([0a1b761](https://github.com/yuki24/did_you_mean/commit/0a1b7612252055e583a373b473932f789381ca0f)) ## [v1.0.3](https://github.com/yuki24/did_you_mean/tree/v1.0.3) _released at 2017-09-24 07:22:07 UTC_ **This version is compatible with Ruby 2.3 and older** #### Bug Fixes - Fixed a bug where `did_you_mean` shows duplicate suggestions when the exception is raised multiple times ([#84](https://github.com/yuki24/did_you_mean/pull/84), [c2e4008](https://github.com/yuki24/did_you_mean/commit/c2e40083cef604c00ccd10efc6d7a5036ad9eb5b)) ## [v1.0.2](https://github.com/yuki24/did_you_mean/tree/v1.0.2) _released at 2016-11-20 18:03:07 UTC_ **This version is compatible with Ruby 2.3 and older** #### Features - Experimental features are officially available through `require 'did_you_mean/experimental'` #### Deprecations - `require 'did_you_mean/extra_features'` is now deprecated in favor of `require 'did_you_mean/experimental'` #### Internal Changes - Replaced the `DidYouMean::SpellCheckable` module with the `DidYouMean::SpellChecker` class. This is a slower implementation but close to the model explained in [this talk](https://speakerdeck.com/yuki24/saving-people-from-typos), more reusable and possibly makes it easier to expose the class as a public interface. ## [v1.0.1](https://github.com/yuki24/did_you_mean/tree/v1.0.1) _released at 2016-05-15 05:17:22 UTC_ #### Bug Fixes - Fixed a bug where the gem suggests what is actually typed by the user: [1c52c88](https://github.com/yuki24/did_you_mean/commit/1c52c887c62b0921e799f94bcc4a846dc7cbc057) - Fixed features that didn't work on JRuby 9.1.0.0: [dc48dde](https://github.com/yuki24/did_you_mean/commit/dc48dde1b2a8f05aab1fcf897e1cb3075a206f53), [4de23f8](https://github.com/yuki24/did_you_mean/commit/4de23f880502c80c5f321371d39c08bb0fa34040), [00e3059](https://github.com/yuki24/did_you_mean/commit/00e305971060d150fae4817b5e895d6478b37579). The local variable name correction is still disabled. Also see: [jruby/jruby#3480](https://github.com/jruby/jruby/issues/3480) ## [v1.0.0](https://github.com/yuki24/did_you_mean/tree/v1.0.0) _released at 2015-12-25 05:13:04 UTC_ #### Features - Introduced a [verbose formatter](https://github.com/yuki24/did_you_mean#verbose-formatter) - Introduced an easy way to enabling [experimental features](https://github.com/yuki24/did_you_mean#experimental-features) #### Bug Fixes - Fixed a bug where the Jaro-Winkler implementation returns the wrong distance when 2 identical strings are given. fixes [#58](https://github.com/yuki24/did_you_mean/pull/58) #### Internal Changes - Slightly changed the spell checking algorithm. Take a look at [e2f5b24](https://github.com/yuki24/did_you_mean/commit/e2f5b2437f967565e4830eab6077f73ae166e0a7) for more details. fixes [#60](https://github.com/yuki24/did_you_mean/issues/60) ## [v1.0.0.rc1](https://github.com/yuki24/did_you_mean/tree/v1.0.0.rc1) _released at 2015-12-25 05:02:25 UTC_ #### Internal Chagens - No longer uses `TracePoint` API by default. fixes [#55](https://github.com/yuki24/did_you_mean/issues/55) and [#56](https://github.com/yuki24/did_you_mean/issues/56) ## [v1.0.0.beta3](https://github.com/yuki24/did_you_mean/tree/v1.0.0.beta3) _released at 2015-12-25 04:56:13 UTC_ #### Internal Changes - Use the `frozen-string-literal` pragma rather than calling `.freeze` everywhere - Use the `NameError#receiver` method in `DidYouMean:: ClassNameChecker` to know the namespace where the constant call is made - Refactored the `SpellCheckerTest` ## [v1.0.0.beta2](https://github.com/yuki24/did_you_mean/tree/v1.0.0.beta2) _released at 2015-12-25 04:50:36 UTC_ #### Bug Fixes - Fixed a bug where the gem doesn't install properly on Ruby 2.3.0dev ## [v1.0.0.beta1](https://github.com/yuki24/did_you_mean/tree/v1.0.0.beta1) _released at 2015-12-25 05:27:53 UTC_ #### Breaking Changes - Dropped support for MRIs older than 2.3, JRuby and Rubinus #### Internal Changes - The C extension has been removed since the `NameError#receiver` method has become part of the MRI 2.3 - The interception gem has been removed from the dependencies - Removed code that was needed to support multiple Ruby implementations ## [v0.10.0](https://github.com/yuki24/did_you_mean/tree/v0.10.0) _released at 2015-08-21 06:44:11 UTC_ #### Features - Now it corrects an instance variable name if the ivar name is mistyped and `NoMethodError` is raised: ```ruby @number = 1 @nubmer.zero? # => NoMethodError: undefined method `zero?' for nil:NilClass # # Did you mean? @number # ``` - Support for JRuby 9.0.0.0 - Prefix-based correction ( [@tjohn](https://github.com/tjohn), [#50](https://github.com/yuki24/did_you_mean/issues/50 "Match start of method name"), [#49](https://github.com/yuki24/did_you_mean/issues/49 "Use Jaro distance instead of Jaro-Winkler distance")) - Correction search is about 75% faster than 0.9.10 #### Breaking Changes - The ActiveRecord integration has been removed ## [v0.9.10](https://github.com/yuki24/did_you_mean/tree/v0.9.10) _released at 2015-05-14 03:04:47 UTC_ #### Bug Fixes - Fixed a bug where a duplicate "did you mean?" message was appended each time `#to_s` is called ( [@danfinnie](https://github.com/danfinnie), [#51](https://github.com/yuki24/did_you_mean/issues/51 "Duplicate output for constants in separate gem")) ## [v0.9.9](https://github.com/yuki24/did_you_mean/tree/v0.9.9) _released at 2015-05-13 03:48:19 UTC_ #### Features - Order word suggestions based on Levenshtein distance ( [@tleish](https://github.com/tleish), [#31](https://github.com/yuki24/did_you_mean/pull/31)) #### Internal Changes - Reduce memory allocation by about 40% - Speed up Levenshtein distance calculation by about 40% - The Java extension has been replaced with a pure JRuby implementation ## [v0.9.8](https://github.com/yuki24/did_you_mean/tree/v0.9.8) _released at 2015-04-12 01:55:27 UTC_ #### Internal Changes - Speed up Levenshtein by 50% and reduce 97% of memory usage ## [v0.9.7](https://github.com/yuki24/did_you_mean/tree/v0.9.7) _released at 2015-04-02 04:20:26 UTC_ #### Bug Fixes - Fixed an issue where _did\_you\_mean_ doesn't install on JRuby properly. ## [v0.9.6](https://github.com/yuki24/did_you_mean/tree/v0.9.6) _released at 2015-01-24 23:19:27 UTC_ #### Bug Fixes - Fixed a bug where did\_you\_mean incorrectly suggests protected methods when it just isn't callable ( [@glittershark](https://github.com/glittershark), [#34](https://github.com/yuki24/did_you_mean/issues/34 "Did\_you\_mean incorrectly called when attempting to call protected/private method")) ## [v0.9.5](https://github.com/yuki24/did_you_mean/tree/v0.9.5) _released at 2015-01-07 12:41:23 UTC_ #### Bug Fixes - Whitelist `#safe_constantize` method from `ActiveSupport::Inflector` to avoid significant performance slowdown ( [@tleish](https://github.com/tleish), [#19](https://github.com/yuki24/did_you_mean/issues/19 "Significant Slowdown when Using Debugger"), [#20](https://github.com/yuki24/did_you_mean/pull/20 "Whitelisting safe\_constantize (ActiveSupport::Inflector) method")) ## [v0.9.4](https://github.com/yuki24/did_you_mean/tree/v0.9.4) _released at 2014-11-19 20:00:00 UTC_ #### Bug Fixes - Fixed a bug where no suggestions will be made on JRuby ## [v0.9.3](https://github.com/yuki24/did_you_mean/tree/v0.9.3) _released at 2014-11-18 03:50:11 UTC_ **This version has been yanked from rubygems.org as it doesn't work with jRuby at all. Please upgrade to 0.9.4 or higher as soon as possible.** #### Internal Changes - Replaced the crazy C extension with a so much better one (thanks to [@nobu](https://github.com/nobu)!) ## [v0.9.2](https://github.com/yuki24/did_you_mean/tree/v0.9.2) _released at 2014-11-17 15:32:33 UTC_ #### Bug Fixes - Fixed a bug where did\_you\_mean doesn't compile on Ruby 2.1.2/2.1.5 ( [#16](https://github.com/yuki24/did_you_mean/issues/16 "Gem building failed on Debian 6.0.10 x86\_64")) ## [v0.9.1](https://github.com/yuki24/did_you_mean/tree/v0.9.1) _released at 2014-11-16 18:54:24 UTC_ **This version has been yanked from rubygems.org as it doesn't compile on Ruby 2.1.2 and 2.1.5. Please upgrade to 0.9.4 or higher as soon as possible.** #### Internal Changes - Shrink the gem size by removing unneeded ruby header files. - Now it forces everyone to upgrade the gem when they upgrade Ruby to a new version. This avoids introducing a bug like [#14](https://github.com/yuki24/did_you_mean/issues/14 "Compatibility with `letter\_opener` gem"). ## [v0.9.0](https://github.com/yuki24/did_you_mean/tree/v0.9.0) _released at 2014-11-09 01:26:31 UTC_ #### Features - did\_you\_mean now suggests instance variable names if `@` is missing ( [#12](https://github.com/yuki24/did_you_mean/issues/12 "Suggest instance- and class-vars"), [39d1e2b](https://github.com/yuki24/did_you_mean/commit/39d1e2bd66d6ff8acbc4dd5da922fc7e5fcefb20)) ```ruby @full_name = "Yuki Nishijima" first_name, last_name = full_name.split(" ") # => NameError: undefined local variable or method `full_name' for main:Object # # Did you mean? @full_name # ``` #### Bug Fixes - Fixed a bug where did\_you\_mean changes some behaviours of Ruby 2.1.3/2.1.4 installed on Max OS X ( [#14](https://github.com/yuki24/did_you_mean/issues/14 "Compatibility with `letter\_opener` gem"), [44c451f](https://github.com/yuki24/did_you_mean/commit/44c451f8c38b11763ba28ddf1ceb9696707ccea0), [9ebde21](https://github.com/yuki24/did_you_mean/commit/9ebde211e92eac8494e704f627c62fea7fdbee16)) - Fixed a bug where sometimes `NoMethodError` suggests duplicate method names ( [9865cc5](https://github.com/yuki24/did_you_mean/commit/9865cc5a9ce926dd9ad4c20d575b710e5f257a4b)) ## [v0.8.0](https://github.com/yuki24/did_you_mean/tree/v0.8.0) _released at 2014-10-27 02:03:13 UTC_ **This version has been yanked from rubygems.org as it has a serious bug with Ruby 2.1.3 and 2.1.4 installed on Max OS X. Please upgrade to 0.9.4 or higher as soon as possible.** #### Features - JRuby support! #### Bug Fixes - Fixed a bug where did\_you\_mean unexpectedly disables [better\_errors](https://github.com/charliesome/better_errors)'s REPL - Replaced [binding\_of\_caller](https://github.com/banister/binding_of_caller) dependency with [interception](https://github.com/ConradIrwin/interception) - Fixed the wrong implementation of Levenshtein algorithm ( [#2](https://github.com/yuki24/did_you_mean/pull/2 "Fix bug of DidYouMean::Levenshtein#min3."), [@fortissimo1997](https://github.com/fortissimo1997)) ## [v0.7.0](https://github.com/yuki24/did_you_mean/tree/v0.7.0) _released at 2014-09-26 03:37:18 UTC_ **This version has been yanked from rubygems.org as it has a serious bug with Ruby 2.1.3 and 2.1.4 installed on Max OS X. Please upgrade to 0.9.4 or higher as soon as possible.** #### Features - Added support for Ruby 2.1.3, 2.2.0-preview1 and ruby-head - Added support for ActiveRecord 4.2.0.beta1 - Word searching is now about 40% faster than v0.6.0 - Removed `text` gem dependency - Better output on pry and Rspec #### Internal Changes - A lot of internal refactoring ## [v0.6.0](https://github.com/yuki24/did_you_mean/tree/v0.6.0) _released at 2014-05-18 00:23:24 UTC_ **This version has been yanked from rubygems.org as it has a serious bug with Ruby 2.1.3 and 2.1.4 installed on Max OS X. Please upgrade to 0.9.4 or higher as soon as possible.** #### Features - Added basic support for constants. Now you'll see class name suggestions when you misspelled a class names/module names: ```ruby > Ocject # => NameError: uninitialized constant Ocject # # Did you mean? Object # ``` #### Bug Fixes - Fixed a bug where did\_you\_mean segfaults on Ruby head(2.2.0dev) ## [v0.5.0](https://github.com/yuki24/did_you_mean/tree/v0.5.0) _released at 2014-05-10 17:59:54 UTC_ #### Features - Added support for Ruby 2.1.2 ## [v0.4.0](https://github.com/yuki24/did_you_mean/tree/v0.4.0) _released at 2014-04-20 02:10:31 UTC_ #### Features - did\_you\_mean now suggests a similar attribute name when you misspelled it. ```ruby User.new(flrst_name: "wrong flrst name") # => ActiveRecord::UnknownAttributeError: unknown attribute: flrst_name # # Did you mean? first_name: string # ``` #### Bug Fixes - Fixed a bug where did\_you\_mean doesn't work with `ActiveRecord::UnknownAttributeError` ## [v0.3.1](https://github.com/yuki24/did_you_mean/tree/v0.3.1) _released at 2014-03-20 23:16:20 UTC_ #### Features - Changed output for readability. - Made the spell checking algorithm slight better to find the correct method. ## [v0.3.0](https://github.com/yuki24/did_you_mean/tree/v0.3.0) _released at 2014-03-20 23:13:13 UTC_ #### Features - Added support for Ruby 2.1.1 and 2.2.0(head). ## [v0.2.0](https://github.com/yuki24/did_you_mean/tree/v0.2.0) _released on 2014-03-20 23:12:13 UTC_ #### Features - did\_you\_mean no longer makes Ruby slow. #### Breaking Changes - dropped support for JRuby and Rubbinious. ## [v0.1.0: First Release](https://github.com/yuki24/did_you_mean/tree/v0.1.0) _released on 2014-03-20 23:11:14 UTC_ - Now you will have "did you mean?" experience in Ruby! - but still very experimental since this gem makes Ruby a lot slower. did_you_mean-1.2.1/README.md0000644000004100000410000000624713263136567015503 0ustar www-datawww-data# did_you_mean [![Gem Version](https://badge.fury.io/rb/did_you_mean.svg)](https://rubygems.org/gems/did_you_mean) [![Build Status](https://travis-ci.org/yuki24/did_you_mean.svg?branch=master)](https://travis-ci.org/yuki24/did_you_mean) ## Installation Ruby 2.3 and later ships with this gem and it will automatically be `require`d when a Ruby process starts up. No special setup is required. ## Examples ### NameError #### Correcting a Misspelled Method Name ```ruby methosd # => NameError: undefined local variable or method `methosd' for main:Object # Did you mean? methods # method ``` #### Correcting a Misspelled Class Name ```ruby OBject # => NameError: uninitialized constant OBject # Did you mean? Object ``` #### Suggesting an Instance Variable Name ```ruby @full_name = "Yuki Nishijima" first_name, last_name = full_name.split(" ") # => NameError: undefined local variable or method `full_name' for main:Object # Did you mean? @full_name ``` #### Correcting a Class Variable Name ```ruby @@full_name = "Yuki Nishijima" @@full_anme # => NameError: uninitialized class variable @@full_anme in Object # Did you mean? @@full_name ``` ### NoMethodError ```ruby full_name = "Yuki Nishijima" full_name.starts_with?("Y") # => NoMethodError: undefined method `starts_with?' for "Yuki Nishijima":String # Did you mean? start_with? ``` ### KeyError ```ruby hash = {foo: 1, bar: 2, baz: 3} hash.fetch(:fooo) # => KeyError: key not found: :fooo # Did you mean? :foo ``` ## Experimental Features Aside from the basic features above, the `did_you_mean` gem comes with experimental features. They can be enabled by calling `require 'did_you_mean/experimental'`. Note that **these experimental features should never be enabled in production as they would impact Ruby's performance and use some unstable Ruby APIs.** ### Correcting an Instance Variable When It's Incorrectly Spelled ```ruby require 'did_you_mean/experimental' @full_name = "Yuki Nishijima" @full_anme.split(" ") # => NoMethodError: undefined method `split' for nil:NilClass # Did you mean? @full_name ``` ### Displaying a Warning When `initialize` is Incorrectly Spelled ```ruby require 'did_you_mean/experimental' class Person def intialize ... end end # => warning: intialize might be misspelled, perhaps you meant initialize? ``` ## Verbose Formatter 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. ```ruby OBject # => NameError: uninitialized constant OBject # Did you mean? Object require 'did_you_mean/verbose' OBject # => NameError: uninitialized constant OBject # # Did you mean? Object # ``` ## Contributing 1. Fork it (http://github.com/yuki24/did_you_mean/fork) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Make sure all tests pass (`bundle exec rake`) 5. Push to the branch (`git push origin my-new-feature`) 6. Create new Pull Request ## License Copyright (c) 2014-16 Yuki Nishijima. See MIT-LICENSE for further details.