How to define constants with traits

Updated . Posted . Visible to the public. Repeats.

When defining a trait using the Modularity gem Show archive.org snapshot , you must take extra steps to define constants to avoid caveats (like when defining subclasses through traits).

tl;dr

In traits, always define constants with explicit self.

If your trait defines a constant inside the as_trait block, it will be bound to the trait module, not the class including the trait.
While this may seem unproblematic at first glance, it becomes a problem when including traits in multiple classes, especially when using parameterized traits.

Example (bad)

Consider the following trait and class.

module ExampleTrait
  as_trait do |audience|
    HELLO = "hello #{audience}" # don't do this
  end
end
class Foo
  include ExampleTrait["world"]
end

No problem so far:

>> Foo::HELLO
=> "hello world"

We then include the trait in another class, with a different configuration.

class Bar
  include ExampleTrait["universe"]
end

Bar::HELLO is set to "hello universe":

>> Bar::HELLO
=> "hello universe"

But Foo::HELLO has also changed!

>> Foo::HELLO
=> "hello universe" # oh no

Solution

In the as_trait block, always define constants on self. self references the class the trait is evaluated on.

module ExampleTrait
  as_trait do |audience|
    self::HELLO = "hello #{audience}"
  end
end
class Foo
  include ExampleTrait["world"]
end
class Bar
  include ExampleTrait["universe"]
end

Now, every class has its own HELLO constant with its expected value.

>> Foo::HELLO
=> "hello world"
>> Bar::HELLO
=> "hello universe"

Side notes

  • Without self, you'll also see an already initialized constant warning printed to your terminal when including your trait into a second class.
  • Without self, you are actually defining ExampleTrait::HELLO.
  • If you want to define a constant that belongs to a trait module, you can do that, and there a valid reasons to do so. Just define it outside of the as_trait block.
Profile picture of Arne Hartherz
Arne Hartherz
Last edit
Arne Hartherz
License
Source code in this card is licensed under the MIT License.
Posted by Arne Hartherz to makandra dev (2011-02-01 09:12)