mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	Promote did_you_mean to default gem
At the moment, there are some problems with regard to bundler + did_you_mean because of did_you_mean being a bundled gem. Since the vendored version of thor inside bundler and ruby itself explicitly requires did_you_mean, it can become difficult to load it when using Bundler.setup. See this issue: https://github.com/yuki24/did_you_mean/issues/117#issuecomment-482733159 for more details.
This commit is contained in:
		
							parent
							
								
									a2fc6a51dd
								
							
						
					
					
						commit
						171803d5d3
					
				
				
				Notes:
				
					git
				
				2019-12-01 11:08:56 +09:00 
				
			
			
			
		
		
					 42 changed files with 2074 additions and 4 deletions
				
			
		
							
								
								
									
										48
									
								
								test/did_you_mean/core_ext/test_name_error_extension.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								test/did_you_mean/core_ext/test_name_error_extension.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
require_relative '../helper'
 | 
			
		||||
 | 
			
		||||
class NameErrorExtensionTest < Test::Unit::TestCase
 | 
			
		||||
  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_raise(NameError){ doesnt_exist }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def teardown
 | 
			
		||||
    SPELL_CHECKERS['NameError'] = @org
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_message
 | 
			
		||||
    assert_match(/Did you mean\?  does_exist/, @error.to_s)
 | 
			
		||||
    assert_match(/Did you mean\?  does_exist/, @error.message)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_to_s_does_not_make_disruptive_changes_to_error_message
 | 
			
		||||
    error = assert_raise(NameError) do
 | 
			
		||||
      raise NameError, "uninitialized constant Object"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    error.to_s
 | 
			
		||||
    assert_equal 1, error.to_s.scan("Did you mean?").count
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_correctable_error_objects_are_dumpable
 | 
			
		||||
    error =
 | 
			
		||||
      begin
 | 
			
		||||
        Dir.chdir(__dir__) { File.open('test_name_error_extension.rb').sizee }
 | 
			
		||||
      rescue NoMethodError => e
 | 
			
		||||
        e
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    error.to_s
 | 
			
		||||
 | 
			
		||||
    assert_equal "undefined method `sizee' for #<File:test_name_error_extension.rb>",
 | 
			
		||||
                 Marshal.load(Marshal.dump(error)).original_message
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										36
									
								
								test/did_you_mean/edit_distance/test_jaro_winkler.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								test/did_you_mean/edit_distance/test_jaro_winkler.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
require_relative '../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 < Test::Unit::TestCase
 | 
			
		||||
  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
 | 
			
		||||
							
								
								
									
										4
									
								
								test/did_you_mean/fixtures/book.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/did_you_mean/fixtures/book.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
class Book
 | 
			
		||||
  class Cover
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										15
									
								
								test/did_you_mean/fixtures/mini_dir.yml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								test/did_you_mean/fixtures/mini_dir.yml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
---
 | 
			
		||||
- test/core_ext/name_error_extension_test.rb
 | 
			
		||||
- test/edit_distance/jaro_winkler_test.rb
 | 
			
		||||
- test/fixtures/book.rb
 | 
			
		||||
- test/spell_checker_test.rb
 | 
			
		||||
- test/spell_checking/class_name_check_test.rb
 | 
			
		||||
- test/spell_checking/key_name_check_test.rb
 | 
			
		||||
- test/spell_checking/method_name_check_test.rb
 | 
			
		||||
- test/spell_checking/uncorrectable_name_check_test.rb
 | 
			
		||||
- test/spell_checking/variable_name_check_test.rb
 | 
			
		||||
- test/test_helper.rb
 | 
			
		||||
- test/tree_spell_checker_test.rb
 | 
			
		||||
- test/tree_spell_explore_test.rb
 | 
			
		||||
- test/tree_spell_human_typo_test.rb
 | 
			
		||||
- test/verbose_formatter_test.rb
 | 
			
		||||
							
								
								
									
										112
									
								
								test/did_you_mean/fixtures/rspec_dir.yml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								test/did_you_mean/fixtures/rspec_dir.yml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,112 @@
 | 
			
		|||
---
 | 
			
		||||
- spec/spec_helper.rb
 | 
			
		||||
- spec/integration/suite_hooks_errors_spec.rb
 | 
			
		||||
- spec/integration/filtering_spec.rb
 | 
			
		||||
- spec/integration/spec_file_load_errors_spec.rb
 | 
			
		||||
- spec/integration/failed_line_detection_spec.rb
 | 
			
		||||
- spec/integration/persistence_failures_spec.rb
 | 
			
		||||
- spec/integration/bisect_runners_spec.rb
 | 
			
		||||
- spec/integration/order_spec.rb
 | 
			
		||||
- spec/integration/fail_if_no_examples_spec.rb
 | 
			
		||||
- spec/integration/bisect_spec.rb
 | 
			
		||||
- spec/integration/output_stream_spec.rb
 | 
			
		||||
- spec/support/sandboxing.rb
 | 
			
		||||
- spec/support/spec_files.rb
 | 
			
		||||
- spec/support/fake_libs/json.rb
 | 
			
		||||
- spec/support/fake_libs/open3.rb
 | 
			
		||||
- spec/support/fake_libs/drb/acl.rb
 | 
			
		||||
- spec/support/fake_libs/drb/drb.rb
 | 
			
		||||
- spec/support/fake_libs/mocha/api.rb
 | 
			
		||||
- spec/support/fake_libs/test/unit/assertions.rb
 | 
			
		||||
- spec/support/fake_libs/flexmock/rspec.rb
 | 
			
		||||
- spec/support/fake_libs/rake/tasklib.rb
 | 
			
		||||
- spec/support/fake_libs/coderay.rb
 | 
			
		||||
- spec/support/fake_libs/rr.rb
 | 
			
		||||
- spec/support/fake_libs/rake.rb
 | 
			
		||||
- spec/support/fake_libs/erb.rb
 | 
			
		||||
- spec/support/fake_libs/rspec/mocks.rb
 | 
			
		||||
- spec/support/fake_libs/rspec/expectations.rb
 | 
			
		||||
- spec/support/fake_libs/minitest/assertions.rb
 | 
			
		||||
- spec/support/fake_libs/minitest.rb
 | 
			
		||||
- spec/support/matchers.rb
 | 
			
		||||
- spec/support/runner_support.rb
 | 
			
		||||
- spec/support/isolated_home_directory.rb
 | 
			
		||||
- spec/support/config_options_helper.rb
 | 
			
		||||
- spec/support/mathn_integration_support.rb
 | 
			
		||||
- spec/support/helper_methods.rb
 | 
			
		||||
- spec/support/formatter_support.rb
 | 
			
		||||
- spec/support/fake_bisect_runner.rb
 | 
			
		||||
- spec/support/shared_example_groups.rb
 | 
			
		||||
- spec/support/aruba_support.rb
 | 
			
		||||
- spec/rspec/core/runner_spec.rb
 | 
			
		||||
- spec/rspec/core/did_you_mean_spec.rb
 | 
			
		||||
- spec/rspec/core/drb_spec.rb
 | 
			
		||||
- spec/rspec/core/metadata_spec.rb
 | 
			
		||||
- spec/rspec/core/example_group_spec.rb
 | 
			
		||||
- spec/rspec/core/configuration/only_failures_support_spec.rb
 | 
			
		||||
- spec/rspec/core/rake_task_spec.rb
 | 
			
		||||
- spec/rspec/core/memoized_helpers_spec.rb
 | 
			
		||||
- spec/rspec/core/ordering_spec.rb
 | 
			
		||||
- spec/rspec/core/option_parser_spec.rb
 | 
			
		||||
- spec/rspec/core/example_execution_result_spec.rb
 | 
			
		||||
- spec/rspec/core/suite_hooks_spec.rb
 | 
			
		||||
- spec/rspec/core/set_spec.rb
 | 
			
		||||
- spec/rspec/core/configuration_spec.rb
 | 
			
		||||
- spec/rspec/core/rspec_matchers_spec.rb
 | 
			
		||||
- spec/rspec/core/hooks_filtering_spec.rb
 | 
			
		||||
- spec/rspec/core/bisect/shell_command_spec.rb
 | 
			
		||||
- spec/rspec/core/bisect/server_spec.rb
 | 
			
		||||
- spec/rspec/core/bisect/example_minimizer_spec.rb
 | 
			
		||||
- spec/rspec/core/bisect/shell_runner_spec.rb
 | 
			
		||||
- spec/rspec/core/bisect/utilities_spec.rb
 | 
			
		||||
- spec/rspec/core/bisect/coordinator_spec.rb
 | 
			
		||||
- spec/rspec/core/resources/a_foo.rb
 | 
			
		||||
- spec/rspec/core/resources/formatter_specs.rb
 | 
			
		||||
- spec/rspec/core/resources/inconsistently_ordered_specs.rb
 | 
			
		||||
- spec/rspec/core/resources/a_bar.rb
 | 
			
		||||
- spec/rspec/core/resources/utf8_encoded.rb
 | 
			
		||||
- spec/rspec/core/resources/a_spec.rb
 | 
			
		||||
- spec/rspec/core/resources/acceptance/bar.rb
 | 
			
		||||
- spec/rspec/core/resources/acceptance/foo_spec.rb
 | 
			
		||||
- spec/rspec/core/resources/custom_example_group_runner.rb
 | 
			
		||||
- spec/rspec/core/failed_example_notification_spec.rb
 | 
			
		||||
- spec/rspec/core/hooks_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/profile_formatter_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/deprecation_formatter_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/syntax_highlighter_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/base_text_formatter_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/snippet_extractor_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/progress_formatter_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/html_snippet_extractor_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/helpers_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/html_formatter_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/json_formatter_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/documentation_formatter_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/exception_presenter_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/console_codes_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters/fallback_message_formatter_spec.rb
 | 
			
		||||
- spec/rspec/core/invocations_spec.rb
 | 
			
		||||
- spec/rspec/core/configuration_options_spec.rb
 | 
			
		||||
- spec/rspec/core/pending_spec.rb
 | 
			
		||||
- spec/rspec/core/profiler_spec.rb
 | 
			
		||||
- spec/rspec/core/project_initializer_spec.rb
 | 
			
		||||
- spec/rspec/core/aggregate_failures_spec.rb
 | 
			
		||||
- spec/rspec/core/dsl_spec.rb
 | 
			
		||||
- spec/rspec/core/ruby_project_spec.rb
 | 
			
		||||
- spec/rspec/core/formatters_spec.rb
 | 
			
		||||
- spec/rspec/core/metadata_filter_spec.rb
 | 
			
		||||
- spec/rspec/core/example_group_constants_spec.rb
 | 
			
		||||
- spec/rspec/core/world_spec.rb
 | 
			
		||||
- spec/rspec/core/shared_context_spec.rb
 | 
			
		||||
- spec/rspec/core/pending_example_spec.rb
 | 
			
		||||
- spec/rspec/core/filter_manager_spec.rb
 | 
			
		||||
- spec/rspec/core/shared_example_group_spec.rb
 | 
			
		||||
- spec/rspec/core/example_status_persister_spec.rb
 | 
			
		||||
- spec/rspec/core/backtrace_formatter_spec.rb
 | 
			
		||||
- spec/rspec/core/output_wrapper_spec.rb
 | 
			
		||||
- spec/rspec/core/example_spec.rb
 | 
			
		||||
- spec/rspec/core/reporter_spec.rb
 | 
			
		||||
- spec/rspec/core/filterable_item_repository_spec.rb
 | 
			
		||||
- spec/rspec/core/notifications_spec.rb
 | 
			
		||||
- spec/rspec/core/warnings_spec.rb
 | 
			
		||||
- spec/rspec/core_spec.rb
 | 
			
		||||
							
								
								
									
										29
									
								
								test/did_you_mean/helper.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								test/did_you_mean/helper.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
require 'test/unit'
 | 
			
		||||
 | 
			
		||||
module DidYouMean
 | 
			
		||||
  module TestHelper
 | 
			
		||||
    class << self
 | 
			
		||||
      attr_reader :root
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if File.file?(File.expand_path('../lib/did_you_mean.rb', __dir__))
 | 
			
		||||
      # In this case we're being run from inside the gem, so we just want to
 | 
			
		||||
      # require the root of the library
 | 
			
		||||
 | 
			
		||||
      @root = File.expand_path('../lib/did_you_mean', __dir__)
 | 
			
		||||
      require_relative @root
 | 
			
		||||
    else
 | 
			
		||||
      # In this case we're being run from inside ruby core, and we want to
 | 
			
		||||
      # include the experimental features in the test suite
 | 
			
		||||
 | 
			
		||||
      @root = File.expand_path('../../lib/did_you_mean', __dir__)
 | 
			
		||||
      require_relative @root
 | 
			
		||||
      # We are excluding experimental features for now.
 | 
			
		||||
      # require_relative File.join(@root, 'experimental')
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def assert_correction(expected, array)
 | 
			
		||||
      assert_equal Array(expected), array, "Expected #{array.inspect} to only include #{expected.inspect}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										79
									
								
								test/did_you_mean/spell_checking/test_class_name_check.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								test/did_you_mean/spell_checking/test_class_name_check.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
require_relative '../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 < Test::Unit::TestCase
 | 
			
		||||
  include DidYouMean::TestHelper
 | 
			
		||||
 | 
			
		||||
  def test_corrections
 | 
			
		||||
    error = assert_raise(NameError) { ::Bo0k }
 | 
			
		||||
    assert_correction "Book", error.corrections
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_corrections_include_case_specific_class_name
 | 
			
		||||
    error = assert_raise(NameError) { ::Acronym }
 | 
			
		||||
    assert_correction "ACRONYM", error.corrections
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_corrections_include_top_level_class_name
 | 
			
		||||
    error = assert_raise(NameError) { Project.bo0k }
 | 
			
		||||
    assert_correction "Book", error.corrections
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_names_in_corrections_have_namespaces
 | 
			
		||||
    error = assert_raise(NameError) { ::Book::TableofContents }
 | 
			
		||||
    assert_correction "Book::TableOfContents", error.corrections
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_corrections_candidates_for_names_in_upper_level_scopes
 | 
			
		||||
    error = assert_raise(NameError) { Book::Page.tableof_contents }
 | 
			
		||||
    assert_correction "Book::TableOfContents", error.corrections
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_corrections_should_work_from_within_instance_method
 | 
			
		||||
    error = assert_raise(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_raise(NameError) { ::Book::Page.new.tableof_contents }
 | 
			
		||||
    assert_correction "Book::TableOfContents", error.corrections
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_does_not_suggest_user_input
 | 
			
		||||
    error = assert_raise(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
 | 
			
		||||
							
								
								
									
										54
									
								
								test/did_you_mean/spell_checking/test_key_name_check.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								test/did_you_mean/spell_checking/test_key_name_check.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
require_relative '../helper'
 | 
			
		||||
 | 
			
		||||
class KeyNameCheckTest < Test::Unit::TestCase
 | 
			
		||||
  include DidYouMean::TestHelper
 | 
			
		||||
 | 
			
		||||
  def test_corrects_hash_key_name_with_fetch
 | 
			
		||||
    hash = { "foo" => 1, bar: 2 }
 | 
			
		||||
 | 
			
		||||
    error = assert_raise(KeyError) { hash.fetch(:bax) }
 | 
			
		||||
    assert_correction ":bar", error.corrections
 | 
			
		||||
    assert_match "Did you mean?  :bar", error.to_s
 | 
			
		||||
 | 
			
		||||
    error = assert_raise(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_raise(KeyError) { hash.fetch_values("foo", :bar, :bax) }
 | 
			
		||||
    assert_correction ":bar", error.corrections
 | 
			
		||||
    assert_match "Did you mean?  :bar", error.to_s
 | 
			
		||||
 | 
			
		||||
    error = assert_raise(KeyError) { hash.fetch_values("foo", :bar, "fooo") }
 | 
			
		||||
    assert_correction %("foo"), error.corrections
 | 
			
		||||
    assert_match %(Did you mean?  "foo"), error.to_s
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_correct_symbolized_hash_keys_with_string_value
 | 
			
		||||
    hash = { foo_1: 1, bar_2: 2 }
 | 
			
		||||
 | 
			
		||||
    error = assert_raise(KeyError) { hash.fetch('foo_1') }
 | 
			
		||||
    assert_correction %(:foo_1), error.corrections
 | 
			
		||||
    assert_match %(Did you mean?  :foo_1), error.to_s
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_corrects_sprintf_key_name
 | 
			
		||||
    error = assert_raise(KeyError) { sprintf("%<foo>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_raise(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
 | 
			
		||||
							
								
								
									
										140
									
								
								test/did_you_mean/spell_checking/test_method_name_check.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								test/did_you_mean/spell_checking/test_method_name_check.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,140 @@
 | 
			
		|||
require_relative '../helper'
 | 
			
		||||
 | 
			
		||||
class MethodNameCheckTest < Test::Unit::TestCase
 | 
			
		||||
  include DidYouMean::TestHelper
 | 
			
		||||
 | 
			
		||||
  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_raise(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_raise(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_raise(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_raise(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_raise(NoMethodError){ User.new.the_protected_method }
 | 
			
		||||
    refute_includes error.corrections, :the_protected_method
 | 
			
		||||
 | 
			
		||||
    error = assert_raise(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_raise(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_raise(NoMethodError){ nil.map }
 | 
			
		||||
    assert_empty error.corrections
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_does_not_exclude_custom_methods_on_nil
 | 
			
		||||
    def nil.empty?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    error = assert_raise(NoMethodError){ nil.empty }
 | 
			
		||||
    assert_correction :empty?, error.corrections
 | 
			
		||||
  ensure
 | 
			
		||||
    NilClass.class_eval { undef empty? }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_does_not_append_suggestions_twice
 | 
			
		||||
    error = assert_raise 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_raise 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
 | 
			
		||||
 | 
			
		||||
  def test_suggests_corrections_on_nested_error
 | 
			
		||||
    error = assert_raise NoMethodError do
 | 
			
		||||
      begin
 | 
			
		||||
        @user.firstname
 | 
			
		||||
      rescue NoMethodError
 | 
			
		||||
        @user.firstname
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    assert_equal 1, error.to_s.scan(/Did you mean/).count
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_suggests_yield
 | 
			
		||||
    error = assert_raise(NoMethodError) { yeild(1) }
 | 
			
		||||
 | 
			
		||||
    assert_correction :yield, error.corrections
 | 
			
		||||
    assert_match "Did you mean?  yield", error.to_s
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
require_relative '../helper'
 | 
			
		||||
 | 
			
		||||
class UncorrectableNameCheckTest < Test::Unit::TestCase
 | 
			
		||||
  class FirstNameError < NameError; end
 | 
			
		||||
 | 
			
		||||
  def setup
 | 
			
		||||
    @error = assert_raise(FirstNameError) do
 | 
			
		||||
      raise FirstNameError, "Other name error"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_message
 | 
			
		||||
    assert_equal "Other name error", @error.message
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										140
									
								
								test/did_you_mean/spell_checking/test_variable_name_check.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								test/did_you_mean/spell_checking/test_variable_name_check.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,140 @@
 | 
			
		|||
require_relative '../helper'
 | 
			
		||||
 | 
			
		||||
class VariableNameCheckTest < Test::Unit::TestCase
 | 
			
		||||
  include DidYouMean::TestHelper
 | 
			
		||||
 | 
			
		||||
  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_raise(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_raise(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
 | 
			
		||||
    if RUBY_ENGINE != "jruby"
 | 
			
		||||
      person = person = nil
 | 
			
		||||
      error = (eprson rescue $!) # Do not use @assert_raise here as it changes a scope.
 | 
			
		||||
 | 
			
		||||
      assert_correction :person, error.corrections
 | 
			
		||||
      assert_match "Did you mean?  person", error.to_s
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_corrections_include_ruby_predefined_objects
 | 
			
		||||
    some_var = some_var = nil
 | 
			
		||||
 | 
			
		||||
    false_error = assert_raise(NameError) do
 | 
			
		||||
      some_var = fals
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    true_error = assert_raise(NameError) do
 | 
			
		||||
      some_var = treu
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    nil_error = assert_raise(NameError) do
 | 
			
		||||
      some_var = nul
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    file_error = assert_raise(NameError) do
 | 
			
		||||
      __FIEL__
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
    assert_correction :__FILE__, file_error.corrections
 | 
			
		||||
    assert_match "Did you mean?  __FILE__", file_error.to_s
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_suggests_yield
 | 
			
		||||
    error = assert_raise(NameError) { yeild }
 | 
			
		||||
 | 
			
		||||
    assert_correction :yield, error.corrections
 | 
			
		||||
    assert_match "Did you mean?  yield", error.to_s
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_corrections_include_instance_variable_name
 | 
			
		||||
    error = assert_raise(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_raise(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_raise(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_raise(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_raise(NameError){ foo }
 | 
			
		||||
    assert_empty error.corrections
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										77
									
								
								test/did_you_mean/test_spell_checker.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								test/did_you_mean/test_spell_checker.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
require_relative './helper'
 | 
			
		||||
 | 
			
		||||
class SpellCheckerTest < Test::Unit::TestCase
 | 
			
		||||
  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
 | 
			
		||||
							
								
								
									
										22
									
								
								test/did_you_mean/test_verbose_formatter.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								test/did_you_mean/test_verbose_formatter.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
require_relative './helper'
 | 
			
		||||
 | 
			
		||||
class VerboseFormatterTest < Test::Unit::TestCase
 | 
			
		||||
  def setup
 | 
			
		||||
    require_relative File.join(DidYouMean::TestHelper.root, 'verbose')
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def teardown
 | 
			
		||||
    DidYouMean.formatter = DidYouMean::PlainFormatter.new
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_message
 | 
			
		||||
    @error = assert_raise(NoMethodError){ 1.zeor? }
 | 
			
		||||
 | 
			
		||||
    assert_equal <<~MESSAGE.chomp, @error.message
 | 
			
		||||
      undefined method `zeor?' for 1:Integer
 | 
			
		||||
 | 
			
		||||
          Did you mean? zero?
 | 
			
		||||
       
 | 
			
		||||
    MESSAGE
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										61
									
								
								test/did_you_mean/tree_spell/change_word.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								test/did_you_mean/tree_spell/change_word.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
module TreeSpell
 | 
			
		||||
  # Changes a word with one of four actions:
 | 
			
		||||
  # insertion, substitution, deletion and transposition.
 | 
			
		||||
  class ChangeWord
 | 
			
		||||
    # initialize with input string
 | 
			
		||||
    def initialize(input)
 | 
			
		||||
      @input = input
 | 
			
		||||
      @len = input.length
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # insert char after index of i_place
 | 
			
		||||
    def insertion(i_place, char)
 | 
			
		||||
      @word = input.dup
 | 
			
		||||
      return char + word if i_place == 0
 | 
			
		||||
      return word + char if i_place == len - 1
 | 
			
		||||
      word.insert(i_place + 1, char)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # substitute char at index of i_place
 | 
			
		||||
    def substitution(i_place, char)
 | 
			
		||||
      @word = input.dup
 | 
			
		||||
      word[i_place] = char
 | 
			
		||||
      word
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # delete character at index of i_place
 | 
			
		||||
    def deletion(i_place)
 | 
			
		||||
      @word = input.dup
 | 
			
		||||
      word.slice!(i_place)
 | 
			
		||||
      word
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # transpose char at i_place with char at i_place + direction
 | 
			
		||||
    # if i_place + direction is out of bounds just swap in other direction
 | 
			
		||||
    def transposition(i_place, direction)
 | 
			
		||||
      @word = input.dup
 | 
			
		||||
      w = word.dup
 | 
			
		||||
      return  swap_first_two(w) if i_place + direction < 0
 | 
			
		||||
      return  swap_last_two(w) if i_place + direction >= len
 | 
			
		||||
      swap_two(w, i_place, direction)
 | 
			
		||||
      w
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    attr_accessor :word, :input, :len
 | 
			
		||||
 | 
			
		||||
    def swap_first_two(w)
 | 
			
		||||
      w[1] + w[0] + word[2..-1]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def swap_last_two(w)
 | 
			
		||||
      w[0...(len - 2)] + word[len - 1] + word[len - 2]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def swap_two(w, i_place, direction)
 | 
			
		||||
      w[i_place] = word[i_place + direction]
 | 
			
		||||
      w[i_place + direction] = word[i_place]
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										89
									
								
								test/did_you_mean/tree_spell/human_typo.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								test/did_you_mean/tree_spell/human_typo.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,89 @@
 | 
			
		|||
# module for classes needed to test TreeSpellChecker
 | 
			
		||||
module TreeSpell
 | 
			
		||||
  require_relative 'change_word'
 | 
			
		||||
  # Simulate an error prone human typist
 | 
			
		||||
  # see doc/human_typo_api.md for the api description
 | 
			
		||||
  class HumanTypo
 | 
			
		||||
    def initialize(input, lambda: 0.05)
 | 
			
		||||
      @input = input
 | 
			
		||||
      check_input
 | 
			
		||||
      @len = input.length
 | 
			
		||||
      @lambda = lambda
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def call
 | 
			
		||||
      @word = input.dup
 | 
			
		||||
      i_place = initialize_i_place
 | 
			
		||||
      loop do
 | 
			
		||||
        action = action_type
 | 
			
		||||
        @word = make_change action, i_place
 | 
			
		||||
        @len = word.length
 | 
			
		||||
        i_place += exponential
 | 
			
		||||
        break if i_place >= len
 | 
			
		||||
      end
 | 
			
		||||
      word
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    attr_accessor :input, :word, :len, :lambda
 | 
			
		||||
 | 
			
		||||
    def initialize_i_place
 | 
			
		||||
      i_place = nil
 | 
			
		||||
      loop do
 | 
			
		||||
        i_place = exponential
 | 
			
		||||
        break if i_place < len
 | 
			
		||||
      end
 | 
			
		||||
      i_place
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def exponential
 | 
			
		||||
      (rand / (lambda / 2)).to_i
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def rand_char
 | 
			
		||||
      popular_chars =  alphabetic_characters + special_characters
 | 
			
		||||
      n = popular_chars.length
 | 
			
		||||
      popular_chars[rand(n)]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def alphabetic_characters
 | 
			
		||||
      ('a'..'z').to_a.join + ('A'..'Z').to_a.join
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def special_characters
 | 
			
		||||
      '?<>,.!`+=-_":;@#$%^&*()'
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def toss
 | 
			
		||||
      return +1 if rand >= 0.5
 | 
			
		||||
      -1
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def action_type
 | 
			
		||||
      [:insert, :transpose, :delete, :substitute][rand(4)]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def make_change(action, i_place)
 | 
			
		||||
      cw = ChangeWord.new(word)
 | 
			
		||||
      case action
 | 
			
		||||
      when :delete
 | 
			
		||||
        cw.deletion(i_place)
 | 
			
		||||
      when :insert
 | 
			
		||||
        cw.insertion(i_place, rand_char)
 | 
			
		||||
      when :substitute
 | 
			
		||||
        cw.substitution(i_place, rand_char)
 | 
			
		||||
      when :transpose
 | 
			
		||||
        cw.transposition(i_place, toss)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_input
 | 
			
		||||
      fail check_input_message if input.nil? || input.length < 5
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def check_input_message
 | 
			
		||||
      "input length must be greater than 5 characters: #{input}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										38
									
								
								test/did_you_mean/tree_spell/test_change_word.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								test/did_you_mean/tree_spell/test_change_word.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
require_relative '../helper'
 | 
			
		||||
require_relative 'change_word'
 | 
			
		||||
 | 
			
		||||
class ChangeWordTest < Test::Unit::TestCase
 | 
			
		||||
  def setup
 | 
			
		||||
    @input = 'spec/services/anything_spec'
 | 
			
		||||
    @cw = TreeSpell::ChangeWord.new(@input)
 | 
			
		||||
    @len = @input.length
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_deleletion
 | 
			
		||||
    assert_match @cw.deletion(5), 'spec/ervices/anything_spec'
 | 
			
		||||
    assert_match @cw.deletion(@len - 1), 'spec/services/anything_spe'
 | 
			
		||||
    assert_match @cw.deletion(0), 'pec/services/anything_spec'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_substitution
 | 
			
		||||
    assert_match @cw.substitution(5, '$'), 'spec/$ervices/anything_spec'
 | 
			
		||||
    assert_match @cw.substitution(@len - 1, '$'), 'spec/services/anything_spe$'
 | 
			
		||||
    assert_match @cw.substitution(0, '$'), '$pec/services/anything_spec'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_insertion
 | 
			
		||||
    assert_match @cw.insertion(7, 'X'), 'spec/serXvices/anything_spec'
 | 
			
		||||
    assert_match @cw.insertion(0, 'X'), 'Xspec/services/anything_spec'
 | 
			
		||||
    assert_match @cw.insertion(@len - 1, 'X'), 'spec/services/anything_specX'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_transposition
 | 
			
		||||
    n = @input.length
 | 
			
		||||
    assert_match @cw.transposition(0, -1), 'psec/services/anything_spec'
 | 
			
		||||
    assert_match @cw.transposition(n - 1, +1), 'spec/services/anything_spce'
 | 
			
		||||
    assert_match @cw.transposition(4, +1), 'specs/ervices/anything_spec'
 | 
			
		||||
    assert_match @cw.transposition(4, -1), 'spe/cservices/anything_spec'
 | 
			
		||||
    assert_match @cw.transposition(21, -1), 'spec/services/anythign_spec'
 | 
			
		||||
    assert_match @cw.transposition(21, +1), 'spec/services/anythin_gspec'
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										24
									
								
								test/did_you_mean/tree_spell/test_human_typo.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								test/did_you_mean/tree_spell/test_human_typo.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
require_relative '../helper'
 | 
			
		||||
require_relative 'human_typo'
 | 
			
		||||
 | 
			
		||||
class HumanTypoTest < Test::Unit::TestCase
 | 
			
		||||
  def setup
 | 
			
		||||
    @input = 'spec/services/anything_spec'
 | 
			
		||||
    @sh = TreeSpell::HumanTypo.new(@input, lambda: 0.05)
 | 
			
		||||
    @len = @input.length
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_changes
 | 
			
		||||
    # srand seed ensures all four actions are called
 | 
			
		||||
    srand 247_696_449
 | 
			
		||||
    sh = TreeSpell::HumanTypo.new(@input, lambda: 0.20)
 | 
			
		||||
    word_error = sh.call
 | 
			
		||||
    assert_equal word_error, 'spec/suervcieq/anythin_gpec'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_check_input
 | 
			
		||||
    assert_raise(RuntimeError, "input length must be greater than 5 characters: tiny") do
 | 
			
		||||
      TreeSpell::HumanTypo.new('tiny')
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										173
									
								
								test/did_you_mean/tree_spell_checker_test.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								test/did_you_mean/tree_spell_checker_test.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,173 @@
 | 
			
		|||
require 'set'
 | 
			
		||||
require 'yaml'
 | 
			
		||||
 | 
			
		||||
require_relative './helper'
 | 
			
		||||
 | 
			
		||||
class TreeSpellCheckerTest < Test::Unit::TestCase
 | 
			
		||||
  MINI_DIRECTORIES = YAML.load_file(File.expand_path('fixtures/mini_dir.yml', __dir__))
 | 
			
		||||
  RSPEC_DIRECTORIES = YAML.load_file(File.expand_path('fixtures/rspec_dir.yml', __dir__))
 | 
			
		||||
 | 
			
		||||
  def setup
 | 
			
		||||
    @dictionary =
 | 
			
		||||
      %w(
 | 
			
		||||
        spec/models/concerns/vixen_spec.rb
 | 
			
		||||
        spec/models/concerns/abcd_spec.rb
 | 
			
		||||
        spec/models/concerns/vixenus_spec.rb
 | 
			
		||||
        spec/models/concerns/efgh_spec.rb
 | 
			
		||||
        spec/modals/confirms/abcd_spec.rb
 | 
			
		||||
        spec/modals/confirms/efgh_spec.rb
 | 
			
		||||
        spec/models/gafafa_spec.rb
 | 
			
		||||
        spec/models/gfsga_spec.rb
 | 
			
		||||
        spec/controllers/vixen_controller_spec.rb
 | 
			
		||||
      )
 | 
			
		||||
    @test_str = 'spek/modeks/confirns/viken_spec.rb'
 | 
			
		||||
    @tsp = DidYouMean::TreeSpellChecker.new(dictionary: @dictionary)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_corrupt_root
 | 
			
		||||
    word = 'test/verbose_formatter_test.rb'
 | 
			
		||||
    word_error = 'btets/cverbose_formatter_etst.rb suggestions'
 | 
			
		||||
    tsp = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES)
 | 
			
		||||
    s = tsp.correct(word_error).first
 | 
			
		||||
    assert_match s, word
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_leafless_state
 | 
			
		||||
    tsp = DidYouMean::TreeSpellChecker.new(dictionary: @dictionary.push('spec/features'))
 | 
			
		||||
    word = 'spec/modals/confirms/efgh_spec.rb'
 | 
			
		||||
    word_error = 'spec/modals/confirXX/efgh_spec.rb'
 | 
			
		||||
    s = tsp.correct(word_error).first
 | 
			
		||||
    assert_equal s, word
 | 
			
		||||
    s = tsp.correct('spec/featuresXX')
 | 
			
		||||
    assert_equal 'spec/features', s.first
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_rake_dictionary
 | 
			
		||||
    dict = %w(parallel:prepare parallel:create parallel:rake parallel:migrate)
 | 
			
		||||
    word_error = 'parallel:preprare'
 | 
			
		||||
    tsp = DidYouMean::TreeSpellChecker.new(dictionary: dict, separator: ':')
 | 
			
		||||
    s = tsp.correct(word_error).first
 | 
			
		||||
    assert_match s, 'parallel:prepare'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_special_words_mini
 | 
			
		||||
    tsp = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES)
 | 
			
		||||
    special_words_mini.each do |word, word_error|
 | 
			
		||||
      s = tsp.correct(word_error).first
 | 
			
		||||
      assert_match s, word
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_special_words_rspec
 | 
			
		||||
    tsp = DidYouMean::TreeSpellChecker.new(dictionary: RSPEC_DIRECTORIES)
 | 
			
		||||
    special_words_rspec.each do |word, word_error|
 | 
			
		||||
      s = tsp.correct(word_error)
 | 
			
		||||
      assert_match s.first, word
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def special_words_rspec
 | 
			
		||||
    [
 | 
			
		||||
      ['spec/rspec/core/formatters/exception_presenter_spec.rb','spec/rspec/core/formatters/eception_presenter_spec.rb'],
 | 
			
		||||
      ['spec/rspec/core/ordering_spec.rb', 'spec/spec/core/odrering_spec.rb'],
 | 
			
		||||
      ['spec/rspec/core/metadata_spec.rb', 'spec/rspec/core/metadata_spe.crb'],
 | 
			
		||||
      ['spec/support/mathn_integration_support.rb', 'spec/support/mathn_itegrtion_support.rb']
 | 
			
		||||
    ]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def special_words_mini
 | 
			
		||||
    [
 | 
			
		||||
     ['test/fixtures/book.rb', 'test/fixture/book.rb'],
 | 
			
		||||
     ['test/fixtures/book.rb', 'test/fixture/book.rb'],
 | 
			
		||||
     ['test/edit_distance/jaro_winkler_test.rb', 'test/edit_distace/jaro_winkler_test.rb'],
 | 
			
		||||
     ['test/edit_distance/jaro_winkler_test.rb', 'teste/dit_distane/jaro_winkler_test.rb'],
 | 
			
		||||
     ['test/fixtures/book.rb', 'test/fixturWes/book.rb'],
 | 
			
		||||
     ['test/test_helper.rb', 'tes!t/test_helper.rb'],
 | 
			
		||||
     ['test/fixtures/book.rb', 'test/hfixtures/book.rb'],
 | 
			
		||||
     ['test/edit_distance/jaro_winkler_test.rb', 'test/eidt_distance/jaro_winkler_test.@rb'],
 | 
			
		||||
     ['test/spell_checker_test.rb', 'test/spell_checke@r_test.rb'],
 | 
			
		||||
     ['test/tree_spell_human_typo_test.rb', 'testt/ree_spell_human_typo_test.rb'],
 | 
			
		||||
     ['test/spell_checking/variable_name_check_test.rb', 'test/spell_checking/vriabl_ename_check_test.rb'],
 | 
			
		||||
     ['test/spell_checking/key_name_check_test.rb', 'tesit/spell_checking/key_name_choeck_test.rb'],
 | 
			
		||||
     ['test/edit_distance/jaro_winkler_test.rb', 'test/edit_distance/jaro_winkler_tuest.rb']
 | 
			
		||||
  ]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_file_in_root
 | 
			
		||||
    word = 'test/spell_checker_test.rb'
 | 
			
		||||
    word_error = 'test/spell_checker_test.r'
 | 
			
		||||
    suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES).correct word_error
 | 
			
		||||
    assert_equal word, suggestions.first
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_no_plausible_states
 | 
			
		||||
    word_error = 'testspell_checker_test.rb'
 | 
			
		||||
    suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES).correct word_error
 | 
			
		||||
    assert_equal [], suggestions
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_no_plausible_states_with_augmentation
 | 
			
		||||
    word_error = 'testspell_checker_test.rb'
 | 
			
		||||
    suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES).correct word_error
 | 
			
		||||
    assert_equal [], suggestions
 | 
			
		||||
    suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES, augment: true).correct word_error
 | 
			
		||||
    assert_equal 'test/spell_checker_test.rb', suggestions.first
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_no_idea_with_augmentation
 | 
			
		||||
    word_error = 'test/spell_checking/key_name.rb'
 | 
			
		||||
    suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES).correct word_error
 | 
			
		||||
    assert_equal [], suggestions
 | 
			
		||||
    suggestions = DidYouMean::TreeSpellChecker.new(dictionary: MINI_DIRECTORIES, augment: true).correct word_error
 | 
			
		||||
    assert_equal 'test/spell_checking/key_name_check_test.rb', suggestions.first
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_works_out_suggestions
 | 
			
		||||
    exp = ['spec/models/concerns/vixen_spec.rb',
 | 
			
		||||
           'spec/models/concerns/vixenus_spec.rb']
 | 
			
		||||
    suggestions = @tsp.correct(@test_str)
 | 
			
		||||
    assert_equal suggestions.to_set, exp.to_set
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_works_when_input_is_correct
 | 
			
		||||
    correct_input = 'spec/models/concerns/vixenus_spec.rb'
 | 
			
		||||
    suggestions = @tsp.correct correct_input
 | 
			
		||||
    assert_equal suggestions.first, correct_input
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_find_out_leaves_in_a_path
 | 
			
		||||
    path = 'spec/modals/confirms'
 | 
			
		||||
    names = @tsp.send(:find_leaves, path)
 | 
			
		||||
    assert_equal names.to_set, %w(abcd_spec.rb efgh_spec.rb).to_set
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_works_out_nodes
 | 
			
		||||
    exp_paths = ['spec/models/concerns',
 | 
			
		||||
                 'spec/models/confirms',
 | 
			
		||||
                 'spec/modals/concerns',
 | 
			
		||||
                 'spec/modals/confirms',
 | 
			
		||||
                 'spec/controllers/concerns',
 | 
			
		||||
                 'spec/controllers/confirms'].to_set
 | 
			
		||||
    states = @tsp.send(:parse_dimensions)
 | 
			
		||||
    nodes = states[0].product(*states[1..-1])
 | 
			
		||||
    paths = @tsp.send(:possible_paths, nodes)
 | 
			
		||||
    assert_equal paths.to_set, exp_paths.to_set
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_works_out_state_space
 | 
			
		||||
    suggestions = @tsp.send(:plausible_dimensions, @test_str)
 | 
			
		||||
    assert_equal suggestions, [["spec"], ["models", "modals"], ["confirms", "concerns"]]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_parses_dictionary
 | 
			
		||||
    states = @tsp.send(:parse_dimensions)
 | 
			
		||||
    assert_equal states, [["spec"], ["models", "modals", "controllers"], ["concerns", "confirms"]]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_parses_elementary_dictionary
 | 
			
		||||
    dictionary = ['spec/models/user_spec.rb', 'spec/services/account_spec.rb']
 | 
			
		||||
    tsp = DidYouMean::TreeSpellChecker.new(dictionary: dictionary)
 | 
			
		||||
    states = tsp.send(:parse_dimensions)
 | 
			
		||||
    assert_equal states, [['spec'], ['models', 'services']]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue