Uninitialized constant issue with Minitest

In a mentoring session, we found that the Minitest wasn’t seeing my namespaced InvalidCodonError class.

Minitest::UnexpectedError: NameError: uninitialized constant ProteinTranslationTest::InvalidCodonError

    assert_raises(InvalidCodonError) do
                  ^^^^^^^^^^^^^^^^^
    /Users/anagy/Exercism/ruby/protein-translation/protein_translation_test.rb:164:in `test_non_existing_codon_cant_translate'
/Users/anagy/Exercism/ruby/protein-translation/protein_translation_test.rb:164:in `test_non_existing_codon_cant_translate'

The temporary fix was that I used the scope operator to dump it in the global namespace, but that doesn’t feel right.

Ruby Code with uninitialized constant
module CodonExceptions    
  class InvalidCodonError < EncodingError; end
end

class Translation
  include CodonExceptions

 
  CYSTEINE      = 'Cysteine'
  <... SNIP ...>
  TYROSINE      = 'Tyrosine'
  STOP          = 'STOP'


  CODON_TO_PROTEIN = {
    UGU: CYSTEINE,
   <... SNIP ... >
    UGA: STOP
  }

  CODON_TO_PROTEIN.default_proc = proc do
    raise InvalidCodonError, "InvalidCodonError: Codon must be one of #{CODON_TO_PROTEIN.keys * ', '}"
  end

It’s common for errors in Ruby to live in the “global namespace” in smaller “projects”, like this one. It’s also normal that constants will not be “read” from a namespace, because the module system doesn’t work that way.

In real life, you’d include CodonExceptions in ProteinTranslationTest or you’d use a fully qualified lookup. Otherwise you’d not namespace the error to begin with :slight_smile: .

In my own code, I do often namespace errors and I consider it good practice, but that’s also because I write a lot of libraries where it will be something like:

module MyLibrary
  class Error < RunTimeError; end

  class SpecificError < Error; end
end

This way, MyLibrary::Error can be rescued in order to rescue any library error, but more specific errors exist.