[docsite] add monads extension docs

This commit is contained in:
Svyatoslav Kryukov 2019-10-04 14:58:27 +03:00
parent 1d4fa6a18b
commit 9a6450a74b
No known key found for this signature in database
GPG Key ID: E1EB3B4F3AE95534
7 changed files with 150 additions and 77 deletions

View File

@ -15,7 +15,7 @@ Built-in types are grouped under 6 categories:
### Categories
Assuming you included `Dry::Types` ([see instructions](/gems/dry-types/1.0/getting-started)) in a module called `Types`:
Assuming you included `Dry::Types` ([see instructions](docs::getting-started)) in a module called `Types`:
* Nominal types:
- `Types::Nominal::Any`
@ -52,7 +52,7 @@ Assuming you included `Dry::Types` ([see instructions](/gems/dry-types/1.0/getti
- `Types::Strict::Array`
- `Types::Strict::Hash`
> All types in the `strict` category are [constrained](/gems/dry-types/1.0/constraints) by a type-check that is applied to make sure that the input is an instance of the primitive:
> All types in the `strict` category are [constrained](docs::constraints) by a type-check that is applied to make sure that the input is an instance of the primitive:
``` ruby
Types::Strict::Integer[1] # => 1
@ -113,4 +113,4 @@ Types::Strict::Integer['1'] # => raises Dry::Types::ConstraintError
- `Types::Maybe::Coercible::Array`
- `Types::Maybe::Coercible::Hash`
> `Maybe` types are not available by default - they must be loaded using `Dry::Types.load_extensions(:maybe)`. See [Optional Values](/gems/dry-types/1.0/optional-values) for more information.
> `Maybe` types are not available by default - they must be loaded using `Dry::Types.load_extensions(:maybe)`. See [Maybe extension](docs::extensions/maybe) for more information.

View File

@ -0,0 +1,15 @@
---
title: Extensions
layout: gem-single
name: dry-types
sections:
- maybe
- monads
---
`dry-types` can be extended with extension. Those extensions are loaded with `Dry::Types.load_extensions`.
Available extensions:
- [Maybe](docs::extensions/maybe)
- [Monads](docs::extensions/monads)

View File

@ -0,0 +1,57 @@
---
title: Maybe
layout: gem-single
name: dry-types
---
The [dry-monads gem](/gems/dry-monads/) provides approach to handling optional values by returning a [_Monad_](/gems/dry-monads/) object. This allows you to pass your type to a `Maybe(x)` block that only executes if `x` returns `Some` or `None`.
> NOTE: Requires the [dry-monads gem](/gems/dry-monads/) to be loaded.
1. Load the `:maybe` extension in your application.
```ruby
require 'dry-types'
Dry::Types.load_extensions(:maybe)
module Types
include Dry.Types()
end
```
2. Append `.maybe` to a _Type_ to return a _Monad_ object
```ruby
x = Types::Maybe::Strict::Integer[nil]
Maybe(x) { puts(x) }
x = Types::Maybe::Coercible::String[nil]
Maybe(x) { puts(x) }
x = Types::Maybe::Strict::Integer[123]
Maybe(x) { puts(x) }
x = Types::Maybe::Strict::String[123]
Maybe(x) { puts(x) }
```
```ruby
Types::Maybe::Strict::Integer[nil] # None
Types::Maybe::Strict::Integer[123] # Some(123)
Types::Maybe::Coercible::Float[nil] # None
Types::Maybe::Coercible::Float['12.3'] # Some(12.3)
# 'Maybe' types can also accessed by calling '.maybe' on a regular type:
Types::Strict::Integer.maybe # equivalent to Types::Maybe::Strict::Integer
```
You can define your own optional types:
``` ruby
maybe_string = Types::Strict::String.maybe
maybe_string[nil]
# => None
maybe_string[nil].fmap(&:upcase)
# => None
maybe_string['something']
# => Some('something')
maybe_string['something'].fmap(&:upcase)
# => Some('SOMETHING')
maybe_string['something'].fmap(&:upcase).value_or('NOTHING')
# => "SOMETHING"
```

View File

@ -0,0 +1,61 @@
---
title: Monads
layout: gem-single
name: dry-types
---
The monads extension makes `Dry::Types::Result` objects compatible with `dry-monads`.
To enable the extension:
```ruby
require 'dry/types'
Dry::Types.load_extensions(:monads)
```
After loading the extension, you can leverage monad API:
```ruby
Types = Dry.Types()
result = Types::String.try('Jane')
result.class #=> Dry::Types::Result::Success
monad = result.to_monad
monad.class #=> Dry::Monads::Result::Success
monad.value! # => 'Jane'
result = Types::String.try(nil)
result.class #=> Dry::Types::Result::Failure
monad = result.to_monad
monad.class #=> Dry::Monads::Result::Failure
monad.failure # => [#<Dry::Types::ConstraintError>, nil]
Types::String.try(nil)
.to_monad
.fmap { |result| puts "passed: #{result.inspect}" }
.or { |error, input| puts "input '#{input.inspect}' failed with error: #{error.to_s}" }
```
This can be useful when used with `dry-monads` and the [`do` notation](/gems/dry-monads/1.0/do-notation/):
```ruby
require 'dry/types'
Types = Dry.Types()
Dry::Types.load_extensions(:monads)
class AddTen
include Dry::Monads[:result, :do]
def call(input)
integer = yield Types::Coercible::Integer.try(input)
Success(integer + 10)
end
end
add_ten = AddTen.new
add_ten.call(10)
# => Success(20)
add_ten.call('integer')
# => Failure([#<Dry::Types::CoercionError: invalid value for Integer(): "integer">, "integer"])
```

View File

@ -31,7 +31,7 @@ name: dry-types
end
```
2. Define [Custom Types](/gems/dry-types/1.0/custom-types) in the `Types` module, then pass the name & type to `attribute`:
2. Define [Custom Types](docs::custom-types) in the `Types` module, then pass the name & type to `attribute`:
```ruby
module Types

View File

@ -15,6 +15,7 @@ sections:
- enum
- map
- custom-types
- extensions
---
`dry-types` is a simple and extendable type system for Ruby; useful for value coercions, applying constraints, defining complex structs or value objects and more. It was created as a successor to [Virtus](https://github.com/solnic/virtus).
@ -35,7 +36,7 @@ User.new(name: 'Bob', age: 35)
# => #<User name="Bob" age=35>
```
See [Built-in Types](/gems/dry-types/1.0/built-in-types/) for a full list of available types.
See [Built-in Types](docs::built-in-types/) for a full list of available types.
By themselves, the basic type definitions like `Types::String` and `Types::Integer` don't do anything except provide documentation about which type an attribute is expected to have. However, there are many more advanced possibilities:
@ -66,7 +67,7 @@ User.new(name: 'Bob', age: 'not coercible')
# => ArgumentError: invalid value for Integer(): "not coercible"
```
- Use `.optional` to denote that an attribute can be `nil` (see [Optional Values](/gems/dry-types/1.0/optional-values)):
- Use `.optional` to denote that an attribute can be `nil` (see [Optional Values](docs::optional-values)):
```ruby
class User < Dry::Struct
@ -84,7 +85,7 @@ User.new(name: 'Bob')
# => Dry::Struct::Error: [User.new] :age is missing in Hash input
```
- Add custom constraints (see [Constraints](/gems/dry-types/1.0/constraints.html)):
- Add custom constraints (see [Constraints](docs::constraints.html)):
```ruby
class User < Dry::Struct
@ -120,16 +121,16 @@ Types::Strict::String[10000]
### Features
* Support for [constrained types](/gems/dry-types/1.0/constraints)
* Support for [optional values](/gems/dry-types/1.0/optional-values)
* Support for [default values](/gems/dry-types/1.0/default-values)
* Support for [sum types](/gems/dry-types/1.0/sum)
* Support for [enums](/gems/dry-types/1.0/enum)
* Support for [hash type with type schemas](/gems/dry-types/1.0/hash-schemas)
* Support for [array type with members](/gems/dry-types/1.0/array-with-member)
* Support for [constrained types](docs::constraints)
* Support for [optional values](docs::optional-values)
* Support for [default values](docs::default-values)
* Support for [sum types](docs::sum)
* Support for [enums](docs::enum)
* Support for [hash type with type schemas](docs::hash-schemas)
* Support for [array type with members](docs::array-with-member)
* Support for arbitrary meta information
* Support for typed struct objects via [dry-struct](/gems/dry-struct)
* Types are [categorized](/gems/dry-types/1.0/built-in-types), which is especially important for optimized and dedicated coercion logic
* Types are [categorized](docs::built-in-types), which is especially important for optimized and dedicated coercion logic
* Types are composable and reusable objects
* No const-missing magic and complicated const lookups
* Roughly 6-10 x faster than Virtus

View File

@ -32,65 +32,4 @@ optional_string[123]
### Handle optional values using Monads
The [dry-monads gem](/gems/dry-monads/) provides another approach to handling optional values by returning a [_Monad_](/gems/dry-monads/) object. This allows you to pass your type to a `Maybe(x)` block that only executes if `x` returns `Some` or `None`.
> NOTE: Requires the [dry-monads gem](/gems/dry-monads/) to be loaded.
1. Load the `:maybe` extension in your application.
```ruby
require 'dry-types'
Dry::Types.load_extensions(:maybe)
module Types
include Dry.Types()
end
```
2. Append `.maybe` to a _Type_ to return a _Monad_ object
```ruby
x = Types::Maybe::Strict::Integer[nil]
Maybe(x) { puts(x) }
x = Types::Maybe::Coercible::String[nil]
Maybe(x) { puts(x) }
x = Types::Maybe::Strict::Integer[123]
Maybe(x) { puts(x) }
x = Types::Maybe::Strict::String[123]
Maybe(x) { puts(x) }
```
```ruby
Types::Maybe::Strict::Integer[nil] # None
Types::Maybe::Strict::Integer[123] # Some(123)
Types::Maybe::Coercible::Float[nil] # None
Types::Maybe::Coercible::Float['12.3'] # Some(12.3)
# 'Maybe' types can also accessed by calling '.maybe' on a regular type:
Types::Strict::Integer.maybe # equivalent to Types::Maybe::Strict::Integer
```
You can define your own optional types:
``` ruby
maybe_string = Types::Strict::String.maybe
maybe_string[nil]
# => None
maybe_string[nil].fmap(&:upcase)
# => None
maybe_string['something']
# => Some('something')
maybe_string['something'].fmap(&:upcase)
# => Some('SOMETHING')
maybe_string['something'].fmap(&:upcase).value_or('NOTHING')
# => "SOMETHING"
```
See [Maybe](docs::extensions/maybe) extension for another approach to handling optional values by returning a [_Monad_](/gems/dry-monads/) object.