···6161end
6262```
63636464+## `Literal::Value`
6565+6666+`Literal::Value` is like a `Literal::Data`, but specifically designed to enrich a single value. You could wrap a `String` as an `EmailAddress` or an `Integer` as a `UserId`.
6767+6868+```ruby
6969+EmailAddress = Literal::Value.define(String)
7070+UserID = Literal::Value.define(Integer)
7171+```
7272+7373+We can create a new `UserID` like this:
7474+7575+```ruby
7676+user_id = UserID.new(123)
7777+```
7878+7979+The input will be type-checked. If it's not frozen already, it will be duplicated and frozen.
8080+8181+You can access the value by calling `value` on the object:
8282+8383+```ruby
8484+user_id.value # => 123
8585+```
8686+8787+Because these value types are defined with an underlying type — in this case, `Integer` — the value objects also implement specific coercion methods. With an `Integer` value, you can call `to_i` to get the underlying value:
8888+8989+```ruby
9090+user_id.to_i # => 123
9191+```
9292+9393+With the `EmailAddress`, we could call `to_s` or `to_str`.
9494+9595+These value objects are designed to help you add extra type safety to your application. Let's say we have an operation that sends an email to a user. We could define the operation like this.
9696+9797+```ruby
9898+class EmailUser
9999+ include Literal::Attributes
100100+101101+ attribute :user_id, UserID
102102+103103+ def call
104104+ # ...
105105+ end
106106+end
107107+```
108108+109109+Now, if we try to call the operation with an `Integer` that isn't a `UserID`, we get a type error.
110110+64111## `Literal::Types`
6511266113`Literal::Attributes`, `Literal::Struct`, and `Literal::Data` all extend `Literal::Types`, which provide some advanced types including some generic-like collection types.
+45
lib/literal/value.rb
···11+class Literal::Value
22+ class << self
33+ attr_reader :__type__
44+55+ def define(type, &block)
66+ value_class = Class.new(self) do
77+ @__type__ = type
88+99+ case type
1010+ when Literal::Types::_Class(String)
1111+ alias_method :to_s, :value
1212+ alias_method :to_str, :value
1313+ when Literal::Types::_Class(Symbol)
1414+ alias_method :to_sym, :value
1515+ when Literal::Types::_Class(Integer)
1616+ alias_method :to_i, :value
1717+ when Literal::Types::_Class(Float)
1818+ alias_method :to_f, :value
1919+ when Literal::Types::_Class(Set)
2020+ alias_method :to_set, :value
2121+ when Literal::Types::_Class(Array)
2222+ alias_method :to_a, :value
2323+ alias_method :to_ary, :value
2424+ when Literal::Types::_Class(Hash)
2525+ alias_method :to_h, :value
2626+ when Literal::Types::_Class(Proc)
2727+ alias_method :to_proc, :value
2828+ end
2929+ end
3030+3131+ value_class.class_exec(&block) if block
3232+ value_class.freeze
3333+ value_class
3434+ end
3535+ end
3636+3737+ def initialize(value)
3838+ type = self.class.__type__
3939+ raise Literal::TypeError, "Expected value: `#{value.inspect}` to be: `#{type.inspect}`." unless type === value
4040+ @value = value.frozen? ? value : value.dup.freeze
4141+ freeze
4242+ end
4343+4444+ attr_reader :value
4545+end