1 require_relative "did_you_mean/version"
2 require_relative "did_you_mean/core_ext/name_error"
4 require_relative "did_you_mean/spell_checker"
5 require_relative 'did_you_mean/spell_checkers/name_error_checkers'
6 require_relative 'did_you_mean/spell_checkers/method_name_checker'
7 require_relative 'did_you_mean/spell_checkers/key_error_checker'
8 require_relative 'did_you_mean/spell_checkers/null_checker'
9 require_relative 'did_you_mean/spell_checkers/require_path_checker'
10 require_relative 'did_you_mean/spell_checkers/pattern_key_name_checker'
11 require_relative 'did_you_mean/formatter'
12 require_relative 'did_you_mean/tree_spell_checker'
14 # The +DidYouMean+ gem adds functionality to suggest possible method/class
15 # names upon errors such as +NameError+ and +NoMethodError+. In Ruby 2.3 or
16 # later, it is automatically activated during startup.
21 # # => NameError: undefined local variable or method `methosd' for main:Object
22 # # Did you mean? methods
26 # # => NameError: uninitialized constant OBject
27 # # Did you mean? Object
29 # @full_name = "Yuki Nishijima"
30 # first_name, last_name = full_name.split(" ")
31 # # => NameError: undefined local variable or method `full_name' for main:Object
32 # # Did you mean? @full_name
34 # @@full_name = "Yuki Nishijima"
36 # # => NameError: uninitialized class variable @@full_anme in Object
37 # # Did you mean? @@full_name
39 # full_name = "Yuki Nishijima"
40 # full_name.starts_with?("Y")
41 # # => NoMethodError: undefined method `starts_with?' for "Yuki Nishijima":String
42 # # Did you mean? start_with?
44 # hash = {foo: 1, bar: 2, baz: 3}
46 # # => KeyError: key not found: :fooo
47 # # Did you mean? :foo
50 # == Disabling +did_you_mean+
52 # Occasionally, you may want to disable the +did_you_mean+ gem for e.g.
53 # debugging issues in the error object itself. You can disable it entirely by
54 # specifying +--disable-did_you_mean+ option to the +ruby+ command:
56 # $ ruby --disable-did_you_mean -e "1.zeor?"
57 # -e:1:in `<main>': undefined method `zeor?' for 1:Integer (NameError)
59 # When you do not have direct access to the +ruby+ command (e.g.
60 # +rails console+, +irb+), you could applyoptions using the +RUBYOPT+
61 # environment variable:
63 # $ RUBYOPT='--disable-did_you_mean' irb
65 # # => NoMethodError (undefined method `zeor?' for 1:Integer)
68 # == Getting the original error message
70 # Sometimes, you do not want to disable the gem entirely, but need to get the
71 # original error message without suggestions (e.g. testing). In this case, you
72 # could use the +#original_message+ method on the error object:
74 # no_method_error = begin
76 # rescue NoMethodError => error
80 # no_method_error.message
81 # # => NoMethodError (undefined method `zeor?' for 1:Integer)
82 # # Did you mean? zero?
84 # no_method_error.original_message
85 # # => NoMethodError (undefined method `zeor?' for 1:Integer)
88 # Map of error types and spell checker objects.
89 @spell_checkers = Hash.new(NullChecker)
91 # Returns a sharable hash map of error types and spell checker objects.
92 def self.spell_checkers
96 # Adds +DidYouMean+ functionality to an error using a given spell checker
97 def self.correct_error(error_class, spell_checker)
99 new_mapping = { **@spell_checkers, error_class.to_s => spell_checker }
100 new_mapping.default = NullChecker
102 @spell_checkers = Ractor.make_shareable(new_mapping)
104 spell_checkers[error_class.to_s] = spell_checker
107 error_class.prepend(Correctable) if error_class.is_a?(Class) && !(error_class < Correctable)
110 correct_error NameError, NameErrorCheckers
111 correct_error KeyError, KeyErrorChecker
112 correct_error NoMethodError, MethodNameChecker
113 correct_error LoadError, RequirePathChecker if RUBY_VERSION >= '2.8.0'
114 correct_error NoMatchingPatternKeyError, PatternKeyNameChecker if defined?(::NoMatchingPatternKeyError)
116 # TODO: Remove on the 3.4 development start:
117 class DeprecatedMapping # :nodoc:
119 warn "Calling `DidYouMean::SPELL_CHECKERS[#{key.to_s}] = #{value.to_s}' has been deprecated. " \
120 "Please call `DidYouMean.correct_error(#{key.to_s}, #{value.to_s})' instead."
122 DidYouMean.correct_error(key, value)
126 warn "Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. " \
127 "Please call `DidYouMean.correct_error(error_name, spell_checker)' instead."
129 hash.each do |error_class, spell_checker|
130 DidYouMean.correct_error(error_class, spell_checker)
135 # TODO: Remove on the 3.4 development start:
136 SPELL_CHECKERS = DeprecatedMapping.new
137 deprecate_constant :SPELL_CHECKERS
138 private_constant :DeprecatedMapping
140 # Returns the currently set formatter. By default, it is set to +DidYouMean::Formatter+.
143 Ractor.current[:__did_you_mean_formatter__] || Formatter
149 # Updates the primary formatter used to format the suggestions.
150 def self.formatter=(formatter)
152 Ractor.current[:__did_you_mean_formatter__] = formatter