[ruby-core:116084] [Ruby master Feature#20164] Add Exception#deconstruct_keys

Issue #20164 has been reported by Dan0042 (Daniel DeLorme). ---------------------------------------- Feature #20164: Add Exception#deconstruct_keys https://bugs.ruby-lang.org/issues/20164 * Author: Dan0042 (Daniel DeLorme) * Status: Open * Priority: Normal ---------------------------------------- It would be convenient to perform pattern matching with exception classes. So `Exception#deconstruct_keys` should return a hash with `:message` (original_message) as well as any other keys specific to the exception subclass. Examples: ``` begin #code rescue => err case err in StandardError(message: /Permission denied/) abort "please select a different file" in NameError(name: :foo) retry if require "foo_helper else raise end end ``` -- https://bugs.ruby-lang.org/

Issue #20164 has been updated by palkan (Vladimir Dementyev). +1 for making exceptions pattern-matching friendly. The example above demonstrates the use case pretty well (class + message matching). The question is what keys must be supported for each standard exception class? The plain Ruby implementation could be as follows: ```ruby class Exception # Not sure if we need to take into account the `keys` argument def deconstruct_keys(*) = {message:, cause:} end class NameError def deconstruct_keys(*) = super.merge(name:) end ``` ---------------------------------------- Feature #20164: Add Exception#deconstruct_keys https://bugs.ruby-lang.org/issues/20164#change-106167 * Author: Dan0042 (Daniel DeLorme) * Status: Open * Priority: Normal ---------------------------------------- It would be convenient to perform pattern matching with exception classes. So `Exception#deconstruct_keys` should return a hash with `:message` (original_message) as well as any other keys specific to the exception subclass. Examples: ``` begin #code rescue => err case err in StandardError(message: /Permission denied/) abort "please select a different file" in NameError(name: :foo) retry if require "foo_helper else raise end end ``` -- https://bugs.ruby-lang.org/

Issue #20164 has been updated by Dan0042 (Daniel DeLorme). palkan (Vladimir Dementyev) wrote in #note-1:
The question is what keys must be supported for each standard exception class?
I computed a quick list and it would look something like this. ``` Exception [:sortkey, :inspect, :backtrace, :to_s, :backtrace_locations, :cause, :message] StopIteration [:result] FrozenError [:receiver] SignalException [:signo, :signm] KeyError [:receiver, :key] LoadError [:path] LocalJumpError [:exit_value, :reason] NameError [:name, :receiver, :local_variables] NoMatchingPatternKeyError [:key, :matchee] NoMethodError [:args, :private_call?] SyntaxError [:path] SystemCallError [:errno] SystemExit [:status, :success?] UncaughtThrowError [:tag, :value] Encoding::InvalidByteSequenceError [:readagain_bytes, :source_encoding, :source_encoding_name, :incomplete_input?, :destination_encoding, :destination_encoding_name, :error_bytes] Encoding::UndefinedConversionError [:error_char, :source_encoding, :source_encoding_name, :destination_encoding, :destination_encoding_name] OptionParser::ParseError [:args, :reason, :additional] Ractor::RemoteError [:ractor] Timeout::Error [:thread] RDoc::RI::Driver::NotFoundError [:name] RDoc::Store::MissingFileError [:name, :file, :store] Reline::Config::InvalidInputrc [:file, :lineno] Gem::LoadError [:name, :requirement] Gem::ConflictError [:target, :conflicts] Gem::DependencyResolutionError [:conflict, :conflicting_dependencies] Gem::FilePermissionError [:directory] Gem::FormatException [:file_path] Gem::GemNotInHomeException [:spec] Gem::ImpossibleDependenciesError [:request, :build_message, :dependency, :conflicts] Gem::MissingSpecVersionError [:specs] Gem::RuntimeRequirementNotMetError [:suggestion] Gem::SpecificGemNotFoundException [:name, :errors, :version] Gem::SystemExitException [:exit_code] Gem::UninstallError [:spec] Gem::UnknownCommandError [:unknown_command] Gem::UnsatisfiableDependencyError [:name, :dependency, :errors, :version] Gem::RequestSet::Lockfile::ParseError [:column, :path, :line] Gem::Resolver::Molinillo::CircularDependencyError [:dependencies] Gem::Resolver::Molinillo::NoSuchDependencyError [:dependency, :required_by] Gem::Resolver::Molinillo::VersionConflict [:specification_provider, :conflicts] ``` Even assuming some of those keys are not relevant, that's still a **lot** of #deconstruct_keys to define for various classes, so maybe a dynamic approach like below would be more feasible? ```ruby class Exception def deconstruct_keys(*keys) h = @diagnostics ||= {} keys.each do |k| unless h.key?(k) h[a] = self.send(k) rescue nil end end h end end ``` ---------------------------------------- Feature #20164: Add Exception#deconstruct_keys https://bugs.ruby-lang.org/issues/20164#change-106234 * Author: Dan0042 (Daniel DeLorme) * Status: Open * Priority: Normal ---------------------------------------- It would be convenient to perform pattern matching with exception classes. So `Exception#deconstruct_keys` should return a hash with `:message` (original_message) as well as any other keys specific to the exception subclass. Examples: ``` begin #code rescue => err case err in StandardError(message: /Permission denied/) abort "please select a different file" in NameError(name: :foo) retry if require "foo_helper else raise end end ``` -- https://bugs.ruby-lang.org/
participants (2)
-
Dan0042 (Daniel DeLorme)
-
palkan (Vladimir Dementyev)