Description
The standard library and the compiler together raise NotImplementedError
in 141 places, and their message is almost always the fully qualified type name followed by the method name. That calls for a refactor:
macro not_implemented!
::raise(::NotImplementedError.new(\{{ "#{@type}##{@def.name}" }}))
end
Then we can write things such as:
class Process::Status
def exit_signal : Signal
{% if flag?(:unix) %}
Signal.from_value(signal_code)
{% else %}
not_implemented!
{% end %}
end
end
# on Windows:
$?.exit_signal # Unhandled exception: Not Implemented: Process::Status#exit_signal (NotImplementedError)
A more robust macro should at least also check for class methods and top-level defs when producing that exception message, such as WinError.value
and the string_build_via_utf16
spec helper. (Yet other things, like file-private defs, #11764, and methods on Class
itself are also possible.)
The above defines not_implemented!
as a public, top-level macro, since third-party libraries may write platform-specific checks similar to the ones we have in the standard library. If we keep this internally it would be Crystal.not_implemented!
instead.