In many cases you may want to define an enum. For example in a blog application a post may have a finite list of statuses. Apart from accessing the current status value it is useful to have all possible values accessible too. Furthermore an enum is an
int => value map, so you can store integers somewhere and have them mapped to enum values conveniently.
# assuming we have types loaded into `Types` namespace # we can easily define an enum for our post struct class Post < Dry::Struct Statuses = Types::Strict::String.enum('draft', 'published', 'archived') attribute :title, Types::Strict::String attribute :body, Types::Strict::String attribute :status, Statuses end # enum values are frozen, let's be paranoid, doesn't hurt and have potential to # eliminate silly bugs Post::Statuses.values.frozen? # => true Post::Statuses.values.all?(&:frozen?) # => true # you can access values using indices or actual values Post::Statuses # => "draft" Post::Statuses['draft'] # => "draft" # it'll raise if something silly was passed in Post::Statuses['something silly'] # => Dry::Types::ConstraintError: "something silly" violates constraints # nil is considered as something silly too Post::Statuses[nil] # => Dry::Types::ConstraintError: nil violates constraints
Note that if you want to define an enum type with a default, you must call
.default before calling
.enum, not the other way around:
# this is the correct usage: Dry::Types::String.default('red').enum('blue', 'green', 'red') # this will raise an error: Dry::Types::String.enum('blue', 'green', 'red').default('red')