did_you_mean-1.2.0/0000755000004100000410000000000013221505156014176 5ustar www-datawww-datadid_you_mean-1.2.0/Rakefile0000644000004100000410000000222013221505156015637 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.0/Gemfile0000644000004100000410000000025313221505156015471 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.0/doc/0000755000004100000410000000000013221505156014743 5ustar www-datawww-datadid_you_mean-1.2.0/doc/CHANGELOG.md.erb0000644000004100000410000000034613221505156017326 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.0/doc/changelog_generator.rb0000644000004100000410000000156213221505156021271 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.0/.ruby-version0000644000004100000410000000001213221505156016634 0ustar www-datawww-data2.5.0-dev did_you_mean-1.2.0/LICENSE.txt0000644000004100000410000000206413221505156016023 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.0/.travis.yml0000644000004100000410000000034213221505156016306 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: - ruby-head did_you_mean-1.2.0/benchmark/0000755000004100000410000000000013221505156016130 5ustar www-datawww-datadid_you_mean-1.2.0/benchmark/memory_usage.rb0000644000004100000410000000063213221505156021152 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.0/benchmark/jaro_winkler/0000755000004100000410000000000013221505156020616 5ustar www-datawww-datadid_you_mean-1.2.0/benchmark/jaro_winkler/memory_usage.rb0000644000004100000410000000035213221505156023637 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.0/benchmark/jaro_winkler/speed.rb0000644000004100000410000000044413221505156022245 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.0/benchmark/levenshtein/0000755000004100000410000000000013221505156020454 5ustar www-datawww-datadid_you_mean-1.2.0/benchmark/levenshtein/memory_usage.rb0000644000004100000410000000036013221505156023474 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.0/benchmark/levenshtein/speed.rb0000644000004100000410000000053013221505156022077 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.0/lib/0000755000004100000410000000000013221505156014744 5ustar www-datawww-datadid_you_mean-1.2.0/lib/did_you_mean/0000755000004100000410000000000013221505156017400 5ustar www-datawww-datadid_you_mean-1.2.0/lib/did_you_mean/verbose.rb0000644000004100000410000000020413221505156021366 0ustar www-datawww-datarequire 'did_you_mean' require 'did_you_mean/formatters/verbose_formatter' DidYouMean.formatter = DidYouMean::VerboseFormatter.new did_you_mean-1.2.0/lib/did_you_mean/core_ext/0000755000004100000410000000000013221505156021210 5ustar www-datawww-datadid_you_mean-1.2.0/lib/did_you_mean/core_ext/name_error.rb0000644000004100000410000000076313221505156023674 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.0/lib/did_you_mean/spell_checker.rb0000644000004100000410000000245413221505156022535 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.0/lib/did_you_mean/experimental/0000755000004100000410000000000013221505156022075 5ustar www-datawww-datadid_you_mean-1.2.0/lib/did_you_mean/experimental/initializer_name_correction.rb0000644000004100000410000000072413221505156030177 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.0/lib/did_you_mean/experimental/ivar_name_correction.rb0000644000004100000410000000401613221505156026613 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.0/lib/did_you_mean/jaro_winkler.rb0000644000004100000410000000345113221505156022416 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.0/lib/did_you_mean/spell_checkers/0000755000004100000410000000000013221505156022366 5ustar www-datawww-datadid_you_mean-1.2.0/lib/did_you_mean/spell_checkers/null_checker.rb0000644000004100000410000000015013221505156025345 0ustar www-datawww-datamodule DidYouMean class NullChecker def initialize(*); end def corrections; [] end end end did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/name_error_checkers/0000755000004100000410000000000013221505156026366 5ustar www-datawww-datadid_you_mean-1.2.0/lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb0000644000004100000410000000202713221505156032505 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 = exception.name, exception.receiver end def corrections @corrections ||= SpellChecker.new(dictionary: class_names).correct(class_name).map(&:full_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.0/lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb0000644000004100000410000000202313221505156033161 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.0/lib/did_you_mean/spell_checkers/name_error_checkers.rb0000644000004100000410000000113513221505156026713 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.0/lib/did_you_mean/spell_checkers/key_error_checker.rb0000644000004100000410000000046613221505156026406 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.0/lib/did_you_mean/spell_checkers/method_name_checker.rb0000644000004100000410000000142213221505156026656 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.0/lib/did_you_mean/version.rb0000644000004100000410000000005213221505156021407 0ustar www-datawww-datamodule DidYouMean VERSION = "1.2.0" end did_you_mean-1.2.0/lib/did_you_mean/formatters/0000755000004100000410000000000013221505156021566 5ustar www-datawww-datadid_you_mean-1.2.0/lib/did_you_mean/formatters/verbose_formatter.rb0000644000004100000410000000043713221505156025647 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.0/lib/did_you_mean/formatters/plain_formatter.rb0000644000004100000410000000032713221505156025303 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.0/lib/did_you_mean/experimental.rb0000644000004100000410000000017113221505156022421 0ustar www-datawww-datarequire 'did_you_mean/experimental/initializer_name_correction' require 'did_you_mean/experimental/ivar_name_correction' did_you_mean-1.2.0/lib/did_you_mean/verbose_formatter.rb0000644000004100000410000000047113221505156023457 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.0/lib/did_you_mean/levenshtein.rb0000644000004100000410000000254113221505156022253 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.0/lib/did_you_mean.rb0000644000004100000410000000233013221505156017723 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 end did_you_mean-1.2.0/did_you_mean.gemspec0000644000004100000410000000161013221505156020175 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($/) spec.test_files = spec.files.grep(%r{^(test)/}) spec.require_paths = ["lib"] spec.required_ruby_version = '>= 2.5.0dev' spec.add_development_dependency "bundler" spec.add_development_dependency "rake" spec.add_development_dependency "minitest" end did_you_mean-1.2.0/test/0000755000004100000410000000000013221505156015155 5ustar www-datawww-datadid_you_mean-1.2.0/test/core_ext/0000755000004100000410000000000013221505156016765 5ustar www-datawww-datadid_you_mean-1.2.0/test/core_ext/name_error_extension_test.rb0000644000004100000410000000226513221505156024603 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 #{method(:to_s).super_method.call} 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.0/test/edit_distance/0000755000004100000410000000000013221505156017754 5ustar www-datawww-datadid_you_mean-1.2.0/test/edit_distance/jaro_winkler_test.rb0000644000004100000410000000262413221505156024032 0ustar www-datawww-data# -*- coding: utf-8 -*- require '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.0/test/experimental/0000755000004100000410000000000013221505156017652 5ustar www-datawww-datadid_you_mean-1.2.0/test/experimental/method_name_checker_test.rb0000644000004100000410000000056113221505156025204 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.0/test/experimental/initializer_name_correction_test.rb0000644000004100000410000000063513221505156027014 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.0/test/test_helper.rb0000644000004100000410000000055113221505156020021 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.0/test/spell_checker_test.rb0000644000004100000410000000571613221505156021355 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.0/test/spell_checking/0000755000004100000410000000000013221505156020127 5ustar www-datawww-datadid_you_mean-1.2.0/test/spell_checking/key_name_check_test.rb0000644000004100000410000000263313221505156024444 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.0/test/spell_checking/variable_name_check_test.rb0000644000004100000410000000614413221505156025442 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.0/test/spell_checking/class_name_check_test.rb0000644000004100000410000000315313221505156024757 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 end did_you_mean-1.2.0/test/spell_checking/uncorrectable_name_check_test.rb0000644000004100000410000000047313221505156026504 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.0/test/spell_checking/method_name_check_test.rb0000644000004100000410000000572513221505156025141 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.0/test/verbose_formatter_test.rb0000644000004100000410000000101013221505156022261 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 #{method(:to_s).super_method.call} Did you mean? does_exist MESSAGE end end did_you_mean-1.2.0/.gitignore0000644000004100000410000000027513221505156016172 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.0/evaluation/0000755000004100000410000000000013221505156016345 5ustar www-datawww-datadid_you_mean-1.2.0/evaluation/incorrect_words.yaml0000644000004100000410000005545313221505156022453 0ustar www-datawww-data# This data is based on Birkbeck Spelling Error Corpus: http://ota.ox.ac.uk/headers/0643.xml # More specifically, this is a yaml version of the data in FAWTHROP1DAT.643 and FAWTHROP2DAT.643. # released under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. # https://creativecommons.org/licenses/by-nc-sa/3.0/ --- abattoir: abbatoir abhorrence: abhorence absence: absense absorbent: absorbant absorption: absorbtion accede: acceed accelerate: acellerate accessible: accesible accidentally: accidently accommodate: accomodate accommodation: accomodation accommodations: accomodations accompaniment: accompanimen accompanying: acompaning accomplice: acomplice accrued: acrued accumulated: acumulated accustom: acustom achievement: acheivement acknowledgment: acknowledgement acquaintance: acquantance acquiesce: aquiese acquiescence: acquiesence acquire: aquire actually: actualy adaptability: adaptibility addition: additon address: adress adequately: adequattly adjacent: ajacent adjourned: adjorned administration: adminstration admissible: admissable admitting: admiting advantageous: advantageos advice: advise affidavit: afidavit aggravated: agravated aghast: agast agreeable: agreable allotted: alloted also: allso alumnae: alumni alumni: alumnae amateur: amatuer amiable: aimiable ammonia: amonia analogous: analagous analysis: analsis analyze: analize angel: angell anniversary: anniversery announcement: anouncement annoyance: anoyance answer: anwser antarctic: antartic any: anye anything: anythin apollo: appolo apology: appology apparent: apparant appearance: appearence appearing: appearin appetite: appitite appetites: appatites appropriate: apropriate appropriation: apropriation approximate: aproximate approximately: aproximatly archaeological: archeological ascertain: assertain asinine: assinine asking: askin asleep: asleeep assassinate: assasinate assessment: assesment assiduous: assidious assistance: assistence attorneys: attornies authoritative: authorative auxiliary: auxillary available: availble awkward: aukward bachelor: batchelor balloon: baloon banana: bananna bankruptcy: bankrupcy bargaining: baragining battalion: batallion beam: beame before: befor beginning: begining believe: belive belligerent: beligerant beneficent: beneficient beneficial: benificial bitch: bich brake: brakke brethren: bretheren brief: brif britain: britian britannia: britania brown: broun bungalow: bungalo buoyancy: bouyancy buoyant: bouyant buried: burried bushel: bushell business: busness buying: buyin cancellation: cancelation calling: callin cantaloupe: cantaloube caribbean: carribean catalogues: catologues category: catagorey cemetery: cemetary chauffeur: chauffuer chemistry: chemestry chimneys: chimnies cincinnati: cincinatti clever: cleva coalesced: coalesed coherent: coherant coliseum: colosium collateral: calateral colossal: collosal colossus: collosus commanded: commaunded commission: commision commitment: committment committee: committe communicate: comunicate comparative: comparitive comparatively: comparitively compendium: conpendium competent: compitent concede: consede conceive: concieve conceived: concieved conditions: condicions confectionery: confectionary confirmation: confermation confusing: confusin connoisseurs: connoiseurs conscience: concience conscientious: conscientous consensus: concensus considering: consderin consistent: consistant conspired: conpired consumer: comsumer contemptible: contempible continuous: continous controllable: controlable controversy: controversey conveniently: conviently coolly: cooly corduroy: corderoy correspondence: correspondanc corrugated: corrigated could: coud counting: countin countryman: countriman craftsman: craftman curiosity: curiousity curriculum: curicculum customary: customery cynical: synical darling: darlin decidedly: dicidely deem: deam definitely: definatly delinquent: delinquint delirious: dilirious delving: delvin denying: denyin dependant: dependent depreciation: depeciation descendant: descendent description: desacription despair: dispair deuce: duece develop: develope development: developement dictionary: dictionery dignitary: dignatary dilapidated: dilapadated diminish: diminsh dining: dinning diphtheria: diptheria disappoint: dissappoint disappointment: dissappointment disastrous: disasterous discipline: disiplin discrete: discite dispel: dispell dissipate: disippate divine: devine doctor: docter doctors: docters dormitory: dormatory doubt: doupt drastically: drasticly drawing: drawin dreaming: dreamin drew: drewe dropped: droped drunkenness: drunkeness duchess: dutchess duly: duely during: durin earnest: ernest ecstasy: ecstacy effecting: effectinge effeminate: affeminate effervescent: effervesent efficiency: effeciency eisenhower: eisenhhower eligible: elegable eliminate: illiminate embarrass: embarass embarrassment: embarrasment encyclopedia: encylopedia endorsement: endorsment enemy: emeny engineers: egnineers enlarged: enlargd entertained: enterteyned equipped: equipt equivalent: equivelant esteemed: estimed every: evrey exaggerate: exagerate exaggeration: exageration examination: eximination examining: examinin excellence: excelence exercises: excercises exhilarating: exhilirating exhorted: exorted existence: existance exorbitant: exhorbitant experience: experiance explicitly: explisitly exquisite: exqusite eyeing: eying facilitate: facilatate fascinating: facinating fatiguing: fatiging fear: feare february: febuary fictitious: fictitous fielder: fiedler fiery: firey fighting: fieghting filipinos: philipinoes filthiness: filthness finally: finaly flammable: flamable flourished: florished foreign: forien forthright: fortright forty: fourty fox: foxx frescos: frescoes friend: freind fulfill: fullfil fundamental: fundemental fundamentally: fundementally gardener: gardner gauge: guage generosity: generousity genius: genious ghastly: gastly gnawing: knawing gone: gonne government: goverment grabbing: grabbin grammar: grammer gramophone: grammophon grandeur: granduer grateful: greatful grievous: grievious grill: grille guarantee: gaurantee guaranteed: guarenteed guardian: guardien guttural: gutteral hammarskjold: hammerskjold hand: hande handkerchief: hankerchief handsome: hansome harass: harrass having: haveing heartrending: heartrendering height: heighth heinous: hienous hemorrhage: hemorrage heyday: heydey himself: himselfe hindrance: hinderence humbly: humly hurricane: huricane hygiene: hygeine identified: indentified idiosyncrasy: idiocyncracy imagination: imagnation imitation: immitation immediately: imidatly immensely: immensly impedance: impedence impresario: impressario incense: insense incessant: incesant incidentally: incidently incompatibility: incompatability inconvenience: inconvience incorrigible: incorigible incredible: incredable indefinite: indefinate independence: independance indictment: inditement indispensable: indispensible inevitable: inevitible infallible: infalable infinite: infinate ingratitude: ingratitoode innocuous: inocuous inoculate: innoculate insistence: insistance instantaneous: instantanous instead: insted intercede: intersede interfered: interferred interference: intereference interrupted: interupted invariably: invarably irrelevant: irrelavent irreparable: irrepairable irresistible: irristible itemized: itimized jackknife: jacknife jaguar: jagaur japanese: japaneze jaundice: jaundise jealousy: jelousy jeopardize: jeprodise judgment: judgement kaleidoscope: kaliedoscope kapok: kapock khaki: kahki kimono: kimona kindergarten: kindergarden kitchen: kitchin knickknacks: knicknacks labeled: labelled laboratory: labratory language: langauge leeway: leaway leisure: liesure leveled: levelled library: libray license: lisence lieutenant: leutenant linoleum: linolium liquefied: liquified liquefy: liquify livelihood: livelyhood lodestone: loadstone lodgment: lodgement lonely: lonley magnificent: magnigicient maintenance: maintainance mammoth: mamoth management: managment maneuver: manuveur manufactories: manufacturies masterpiece: masterpice material: materiel mathematics: mathmatics mattress: mattres maudlin: mauldin meant: ment medicine: medecine meeting: meetin mercenary: mercanery merchandise: merchandize merchantmen: merchantment meteorological: meterological metropolitan: metropolitian millionaire: millionnaire miniature: minature miscellaneous: miscelaneous mischievous: mischievious moccasins: mocassins momentous: momentus mortgage: morgage mortgaged: mortgauged murmurs: murmers mustnt: musnt mutilate: mutalate mythical: mithical nadir: nadar naphtha: naptha narrative: narative naturally: naturaly navigating: navagating necessarily: necessarilly necessary: nessisary niagara: niagra nickel: nickle niggardly: nigardly ninetieth: nintieth ninetyninth: nintynineth nocturnal: nocternal nonsense: nonsence notwithstanding: nothwithstanding nowadays: nowdays obbligato: obliggato obdurate: obdirate occasion: ocassion occasionally: occasionaly occurred: occureed occurrence: occurence octopus: octapus odyssey: oddysey ominous: omenous omission: ommision onerous: onirous opportunities: oppotunities opposition: oposition oppressor: oppresser optician: optitian oratorio: orotario orchestra: ochestra ordinarily: ordinarilly origin: origen originally: origionally own: owne pain: paine pamphlet: phamplet pamphlets: phamplets parallel: parellel paralysis: parallysis paraphernalia: parephernalia parenthesis: parenthasis participle: participal pastime: pasttime pastor: paster paternity: paternaty pavilion: pavillion peasant: peasent peculiar: pecular penance: pennance pendulum: pendelum penguins: pengiuns peninsula: peninsular penitentiary: penitentary perceive: percieve perforation: preforation permissible: permissable perseverance: perseverence personalty: personality perspiration: persperation persuade: pursuade persuaded: pursuaded persuasion: persausion pertaining: pertaning pervaded: prevaded pharaohs: pharoahs phase: faze phenomenal: phenominal phenomenon: phenonenon philippines: phillipines physician: physican pickerel: pickeral picnicking: picnicing pittsburgh: pittsburg plagiarism: plaigarism plaque: placque playwright: playwrite pleasant: plesent poetry: poetrie poisonous: poisenous ponderous: pondorous possess: posess possession: possesion possibilities: possablities prairie: prarie preceding: preceeding precipice: presipice preferable: preferrable preference: preferance preferred: prefered prejudice: prejedice preparation: preperation preserved: perserved presumptuous: presumptous prevalent: prevelant preventive: preventative prisoner: prisner privilege: priviledge probably: probabley procedure: proceduer professor: proffesor proffer: profer prominent: prominant promontory: promonotory pronunciation: pronounciation propeller: propellor prophecy: prophesy provisions: provisons pseudonym: pseudynom psychological: psycological public: publick publicly: publically pumpkin: pumkin pursue: persue pursuer: persuer pursuit: persuit qualified: qualafied quandary: quandry quantities: quanties quarantine: quarrantine quarreled: quarelled quarter: quater questionnaire: questionare quiescent: quiscent quorum: quorem radiant: radient radiator: radiater raise: raize rating: rateing really: realy rebuttal: rebutal receded: receeded receipt: reciept receipts: reciepts receive: recieve receiver: reciever receptacle: receptacel recipient: resipient reciprocal: reciprocel reckon: recon reclamation: reclaimation recommend: recomend recommendation: recomendation recommendations: reccomendations recommended: recommend recommending: recomending recompense: recompence redundant: redundent reference: refference referred: refered referring: refering refrigerator: refrigerater regretted: regreted rehabilitate: rehabilatate relevant: relevaant religious: religous remembrance: rememberance rendezvous: rendevous renegade: renagade renown: renoun reparation: repairation repel: repell repetition: repitition representatives: representitives rescinded: resinded reservoir: resevoir responsibility: responsiblity restaurant: restuarant restaurateur: restauranteur rhapsody: raphsody rheumatism: rhuematism rhododendron: rhododrendon rhubarb: ruhbarb rhythm: rythm ridiculous: rediculous romantic: romantick rummage: rumage running: runing sabbath: sabath sacrament: sacrement sacrilegious: sacreligious safety: safty sagacious: sagatious sailor: sailer sandwich: sanwich sanitary: sanatary satisfactory: satisfactary scarcity: scarsity scissors: sissers seize: sieze seized: siezed self: selfe sell: selle semesters: semisters seminary: seminery separate: seporate sergeant: sergant sheep: sheepe shepherd: sheperd silhouette: silhuette shipping: shippin shoulder: shouldda shoulders: sholders showing: showin shrubbery: shrubery siege: seige significant: significent silk: silke similar: similiar simultaneous: similtanous sincerity: sincerety slimmest: slimest smiling: smilin sociable: socable social: socal solemn: solomn sophomore: sophmore sorority: sororiety sought: saught source: sorce souvenir: souviner sovereignty: sovreignty sparsely: sparcely spear: speer specifically: specificly specimen: speciment specimens: specimans spirituous: spiritous sprinkle: sprinkel starting: startin stationary: stationery statue: statu stirring: stirrin stirrups: stirups stomach: stomack straining: strainin straitjacket: straightjacket stratagem: strategem strategy: stratagy strenuous: strenous stretched: streched stubbornness: stubborness suburban: sububan success: sucess sufficient: suficient suffrage: sufferage sugar: suger suing: sueing superficial: superfical superintendent: supertendent supersede: supercede supplement: suplement suppress: supress surprise: suprise surreptitious: sureptitous surrounded: surounded swearing: swearinge syllables: sylables symmetry: symetry synonymous: synonomous systematically: systemetically tacit: tasit taking: takin technically: technecally television: televison temperament: temperment temporarily: temporarly temporary: tempory tendency: tendancy terrestrial: terestial terrors: terrours that: thatt therefore: therefor thief: theaf think: thinke thinking: thinkin thorough: thourough thoroughly: throughly tobacco: tobbaco tobogganing: tobboganing tonnage: tonage tragedy: tradgedy tranquility: tranquillity tranquillity: tranquility transferable: transferrable transferred: transfred truculent: trucculent truly: truley tying: tieing tyrannical: tyranical undoubtedly: undoubtly unequaled: unequalled unfortunately: unfortunatly university: unversity unmistakable: unmistakeable unparalleled: unparalelled until: untill usage: useage usually: usualy usurious: usurous utterance: utterence vacancy: vancancy vaccination: vacinnation vacillate: vaccilate various: vairious vegetable: vegatable vengeance: vengance vertical: verticle vice: vise victuals: vituals vilify: villify villain: villian violence: violance violin: vioiln visible: visable vitamins: vitamines voucher: vouture wagging: waggin waggish: wagish wednesday: wensday weed: weede weight: weigth weird: wierd whether: wether which: whitch who: whoe withhold: withold worshiping: worshipping yacht: yaht yearned: yerned yeoman: yoman yield: yeild zealous: zelous zenith: zeenith ability: ablity academically: academicly accept: acept accepted: acepted access: acess accessibility: accessability accessing: accesing according: acording account: acount accounts: acounts acquaintances: aquantences adaptable: adabtable addressable: addresable adequate: adiquate adjournment: adjurnment advise: advice again: agiin agencies: agences aggravating: agravating allow: alow although: athough analyse: analiss analysed: analised analysing: aalysing and: anf announcing: anouncing annoying: anoying annual: anual anomalies: anomolies apologies: appologies apologised: appologised appeal: apeal appendix: apendix applicable: aplicable applied: upplied applying: applieing appointment: appoitment appointments: apointments appreciated: apreciated appreciation: apreciation approach: aproach approached: aproached are: arte arguing: aurguing arranged: arrainged arrangeing: aranging arrangement: arrangment arrangements: araingements articles: articals assessing: accesing associated: assosiated atmosphere: atmospher auguments: aurgument availability: avaiblity base: basse benefit: benifit benefits: benifits between: beetween bicycle: bicycal bingley: bingly bonus: bonas build: biuld building: biulding busy: buisy career: carrer careers: currers categories: catagoris centrally: centraly certain: cirtain challenges: chalenges challenge: chalange choice: choise choices: choises choose: chose choosing: chosing clerical: clearical clerk: clerck collate: colate combine: comibine commercial: comersial comments: coments commit: comit committees: commitees compare: compair compared: comppared comparison: comparrison completely: completly component: componant composed: compossed conditioning: conditining conference: conferance consider: concider considerable: conciderable consist: consisit consisting: consisiting consists: consisits contained: contasined containing: contasining continually: contually continued: contuned controlled: controled conversely: conversly corporate: corparate credit: creadit criticism: citisum currently: curruntly data: dsata dealt: delt decide: descide decided: descided decides: descides decision: descisions decisions: descisions declarations: declaratrions definition: defenition definitions: defenitions demands: diemands dependence: dependance described: discribed desirable: disiable desperately: despratly diagrammatically: diagrammatica different: diffrent difficult: dificult difficulty: dificulty disaggregate: disaggreagte disappointing: dissapoiting discretion: discresion dissension: desention dragged: draged earlier: earlyer earliest: earlyest easier: easer easily: easyly econometric: economtric edition: ediition eliminated: elimiated embellishing: embelishing employed: emploied employees: emploies employment: empolyment encompassing: encompasing encourage: encorage enormously: enomosly entirely: entierly equalled: equaled erroneous: errounous especially: especaily essential: esential eventually: eventully evident: evedent exact: exsact exactly: exsactly examine: examin excellent: exerlant except: excxept excessively: exessively executed: executted expansion: expanion expense: expence expensive: expencive experiences: experances explaining: explaning exponentially: exponentualy extremely: extreemly facilities: facilitys fails: failes 'false': faulse familiar: familer families: familys favourable: faverable favourably: favorably feeling: fealing female: femail figure: figuar figures: figuars financial: finatical financially: financialy flexible: flexable forbidden: forbiden forecast: forcast fourth: forth functionally: functionaly functions: functuions further: futher gaining: ganing generated: generataed geneva: geniva geographically: goegraphicaly graphically: graphicaly guidelines: guidlines handle: handel hierarchal: hierachial hierarchy: hierchy however: howeverr humour: humor ideally: idealy immediate: imediate inconceivable: inconcievable indeed: indead independent: independant inefficient: ineffiect initial: intital input: inut inquiries: equiries insight: insite intelligence: inteligence interest: intrest interesting: intresting interpretation: interpritatio interrogating: interogationg investigated: investegated journalism: journaism knowledge: knowlege largely: largly later: latter length: lengh level: leval levels: levals lieu: liew literature: litriture loans: lones locally: localy luckily: luckeley majority: majorty manually: manualy many: mony mathematically: mathematicaly matrix: matriiix mean: meen means: meens minutes: muiuets misleading: missleading monitoring: monitering months: monthes moving: moveing nationally: nationaly nature: natior necessitates: nessisitates necessity: nessesity negligible: negligable neither: niether night: nite normally: normaly now: noe numbers: numbuers obtaining: optaning occur: occure operations: operatins operator: opertor operators: oprators opinion: oppinion opportunity: oppotunity ordinary: ordenary organization: oranisation organized: oranised orientated: orentated output: oputput overall: overal paid: payed parameters: perametres partially: partialy particular: particulaur particularly: particulary patterns: pattarns per: pere perhaps: perhapse permanent: perminant permanently: perminantly personnel: personel pivoting: pivting politics: polatics position: possition possible: possable prepared: prepaired primarily: pimarily prior: piror proceeding: proceding profession: preffeson profit: proffit profits: proffits progresses: progressess progression: progresion projects: projeccts proportions: proprtions provide: provid provisionally: provisionaly proviso: provisoe qualities: quaties queries: quies reaching: reching readjusted: reajusted received: recived receives: recives receiving: reciving recently: reciently refered: reffered regained: regined register: rgister relatively: relitivly repetitive: repetative representative: representitiv requested: rquested required: reequired research: reserch resolved: resoved responsibilities: responsibliti responsible: responcible resulting: reulting retirement: retirment routine: rouint safeguard: safegaurd salaries: salarys scheme: scheem scrutinized: scrutiniesed search: serch searching: serching secretaries: secutaries security: seurity seen: seeen segment: segemnt senior: sienior sense: sence sensible: sensable separated: seperated separation: seperation session: sesion set: et sheets: sheertes shortened: shortend shown: hown sign: eign simular: similar singular: singulaur someone: somone sources: sorces speaking: speeking standardizing: stanerdizing stopped: stoped students: studens studying: studing subsequent: subsiquent subtract: subtrcat successful: sucssuful successive: sucsesive such: shuch suffering: suufering suggested: sugested suggestion: sugestion suggests: sugests suited: suted summarys: sumarys supervision: supervison supplementary: suplementary supplements: suplements supposedly: supposidly surrounding: serounding surroundings: suroundings surveys: servays surveying: servaying system: sysem table: tasble technique: tecnique techniques: tecniques the: thw their: thier there: thear thermawear: thermawhere these: thess they: thay thoughts: thorts through: throut throughout: throuout timing: timeing titles: tittles to: ro together: togehter totally: totaly traditionally: traditionaly transactions: trasactions transportability: transportibil triangular: triangulaur umbrella: umberalla unavailable: unavailble understandable: understadable unequalled: unequaled unequivocally: unequivocaly union: unioun unique: uneque universally: universaly unnecessarily: unessasarily unnecessary: unessessay unresolved: unresloved used: usedf useful: usful user: uers utilized: utalised valuable: valuble variable: varible variant: vairiant variety: variatry virtually: vertually visitor: vistor visitors: vistors voluntary: volantry voting: voteing weapons: wepons weighted: wagted were: where when: whn whereas: wheras widely: widly will: wil within: withing would: whould written: writen years: yesars did_you_mean-1.2.0/evaluation/dictionary_generator.rb0000644000004100000410000000144413221505156023110 0ustar www-datawww-datarequire 'open-uri' require 'cgi' require 'json' per_page = 500 base_url = "https://simple.wiktionary.org/w/api.php?action=query&aplimit=#{per_page}&list=allpages&format=json" filename = "evaluation/dictionary.yml" apfrom = "" num = 0 titles = [] loop do url = base_url + "&apfrom=#{apfrom}" puts "downloading page %2d: #{url}" % num body = open(url).read json = JSON.load(body) count = json["query"]["allpages"].size apfrom = CGI.escape(json["query"]["allpages"].last['title']) if count > 0 titles += json["query"]["allpages"].map {|hash| hash["title"] } num += 1 break if count != per_page end require 'yaml' File.open(filename, 'w') do |file| file.write(titles.uniq.to_yaml) end puts " Number of titles: #{titles.uniq.size} Dictionary saved: #{filename} " did_you_mean-1.2.0/evaluation/calculator.rb0000644000004100000410000000462013221505156021025 0ustar www-datawww-data# frozen-string-literal: true require 'benchmark' require 'did_you_mean' def report(message, &block) time = 1000 * Benchmark.realtime(&block) if (time / 1000 / 60) >= 1 minutes = (time / 1000 / 60).floor seconds = (time % (60 * 1000)) / 1000 puts " \e[36m%2dm%.3fs:\e[0m %s" % [minutes, seconds, message] elsif (time / 1000) >= 1 seconds = (time % (60 * 1000)) / 1000 puts " \e[36m%9.3fs:\e[0m %s" % [seconds, message] else puts " \e[36m%8.1fms:\e[0m %s" % [time, message] end time end puts "did_you_mean version: #{DidYouMean::VERSION}\n\n" report "loading program" do require 'yaml' require 'set' begin require 'jaro_winkler' DidYouMean::JaroWinkler.module_eval do module_function def distance(str1, str2) ::JaroWinkler.distance(str1, str2) end if RUBY_ENGINE != 'jruby' end rescue LoadError, NameError => e puts "couldn't load the jaro_winkler gem: #{e.message}\n\n" end end report "loading dictionary" do yaml = open("evaluation/dictionary.yml").read yaml = YAML.load(yaml).map{|word| word.downcase.tr(" ", "_") } DICTIONARY = Set.new(yaml) end report "loading correct/incorrect words" do SPELL_CHECKER = DidYouMean::SpellChecker.new(dictionary: DICTIONARY) INCORRECT_WORDS = YAML.load(open("evaluation/incorrect_words.yaml").read) end total_count = 0 correct_count = 0 words_not_corrected = [] filename = "log/words_not_corrected_#{Time.now.to_i}.yml" puts <<-MSG Total number of test data: #{INCORRECT_WORDS.size} MSG report "calculating accuracy" do INCORRECT_WORDS.each_with_index do |(expected, user_input), index| if DICTIONARY.include?(expected) total_count += 1 corrections = SPELL_CHECKER.correct(user_input) if corrections.first == expected correct_count += 1 else words_not_corrected << { 'input' => user_input, 'expected' => expected, 'actual' => corrections } end end puts "processed #{index} items" if index % 100 == 0 end puts "\n" end puts <<-MSG Evaulation result Total count : #{total_count} Correct count: #{correct_count} Accuracy : #{correct_count.to_f / total_count} MSG Dir.mkdir('log') unless File.exist?('log') File.open(filename, 'w') do |file| file.write(words_not_corrected.to_yaml) end puts "Incorrect corrections were logged to #{filename}." did_you_mean-1.2.0/CHANGELOG.md0000644000004100000410000003626313221505156016021 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.0/README.md0000644000004100000410000000624713221505156015466 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.