<commit_before>[gem]: https://rubygems.org/gems/dry-data
[travis]: https://travis-ci.org/dryrb/dry-data
[gemnasium]: https://gemnasium.com/dryrb/dry-data
[codeclimate]: https://codeclimate.com/github/dryrb/dry-data
[coveralls]: https://coveralls.io/r/dryrb/dry-data
[inchpages]: http://inch-ci.org/github/dryrb/dry-data

# dry-data [![Join the chat at https://gitter.im/dryrb/chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dryrb/chat)

[![Gem Version](https://badge.fury.io/rb/dry-data.svg)][gem]
[![Build Status](https://travis-ci.org/dryrb/dry-data.svg?branch=master)][travis]
[![Dependency Status](https://gemnasium.com/dryrb/dry-data.svg)][gemnasium]
[![Code Climate](https://codeclimate.com/github/dryrb/dry-data/badges/gpa.svg)][codeclimate]
[![Test Coverage](https://codeclimate.com/github/dryrb/dry-data/badges/coverage.svg)][codeclimate]
[![Inline docs](http://inch-ci.org/github/dryrb/dry-data.svg?branch=master)][inchpages]

A simple type system for Ruby with support for coercions.

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'dry-data'
```

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install dry-data

## Usage

You can use `dry-data` for defining various data types in your application, like
domain entities and value objects or hashes with coercible values used to handle
params.

Built-in types are grouped under 5 categories:

- default: pass-through without any checks
- `strict` - doesn't coerce and checks the input type against the primitive class
- `coercible` - tries to coerce and raises type-error if it failed
- `form` - non-strict coercion types suitable for form params
- `maybe` - accepts either a nil or something else

### Built-in Type Categories

Non-coercible:

- `nil`
- `symbol`
- `class`
- `true`
- `false`
- `date`
- `date_time`
- `time`

Coercible types using kernel coercion methods:

- `coercible.string`
- `coercible.int`
- `coercible.float`
- `coercible.decimal`
- `coercible.array`
- `coercible.hash`

Optional strict types:

- `maybe.strict.string`
- `maybe.strict.int`
- `maybe.strict.float`
- `maybe.strict.decimal`
- `maybe.strict.array`
- `maybe.strict.hash`

Optional coercible types:

- `maybe.coercible.string`
- `maybe.coercible.int`
- `maybe.coercible.float`
- `maybe.coercible.decimal`
- `maybe.coercible.array`
- `maybe.coercible.hash`

Coercible types suitable for form param processing:

- `form.nil`
- `form.date`
- `form.date_time`
- `form.time`
- `form.true`
- `form.false`
- `form.bool`
- `form.int`
- `form.float`
- `form.decimal`

### Accessing Built-in Types

``` ruby
# default passthrough category
float = Dry::Data["float"]

float[3.2] # => 3.2
float["3.2"] # "3.2"

# strict type-check category
int = Dry::Data["strict.int"]

int[1] # => 1
int['1'] # => raises TypeError

# coercible type-check group
string = Dry::Data["coercible.string"]
array = Dry::Data["coercible.array"]

string[:foo] # => 'foo'
array[:foo] # => [:foo]

# form group
date = Dry::Data["form.date"]
date['2015-11-29'] # => #<Date: 2015-11-29 ((2457356j,0s,0n),+0s,2299161j)>
```

### Optional types

All built-in types have their optional versions too, you can access them under
`"maybe.strict"` and `"maybe.coercible"` categories:

``` ruby
maybe_int = Dry::Data["maybe.strict.int"]

maybe_int[nil] # None
maybe_int[123] # Some(123)

maybe_coercible_float = Dry::Data["maybe.coercible.float"]

maybe_int[nil] # None
maybe_int['12.3'] # Some(12.3)
```

You can define your own optional types too:

``` ruby
maybe_string = Dry::Data["optional"] | Dry::Data["string"]

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
# => "SOMETHING"
```

### Constrained Types

You can create constrained types that will use validation rules to check if the
input is not violating any of the configured contraints. You can treat it as
a lower level guarantee that you're not instantiating objects that are broken.

All types support constraints API, but not all constraints are suitable for a
particular primitive, it's up to you to set up constraints that make sense.

Under the hood it uses `dry-validation`[https://github.com/dryrb/dry-validation]
and all of its predicates are supported.

IMPORTANT: `dry-data` does not have a runtime dependency on `dry-validation` so
if you want to use contrained types you need to add it to your Gemfile

``` ruby
string = Dry::Data["strict.string"].constrained(min_size: 3)

string['foo']
# => "foo"
<commit_msg>Update README [ci skip]<commit_after>[gem]: https://rubygems.org/gems/dry-data
[travis]: https://travis-ci.org/dryrb/dry-data
[gemnasium]: https://gemnasium.com/dryrb/dry-data
[codeclimate]: https://codeclimate.com/github/dryrb/dry-data
[coveralls]: https://coveralls.io/r/dryrb/dry-data
[inchpages]: http://inch-ci.org/github/dryrb/dry-data

# dry-data [![Join the chat at https://gitter.im/dryrb/chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dryrb/chat)

[![Gem Version](https://badge.fury.io/rb/dry-data.svg)][gem]
[![Build Status](https://travis-ci.org/dryrb/dry-data.svg?branch=master)][travis]
[![Dependency Status](https://gemnasium.com/dryrb/dry-data.svg)][gemnasium]
[![Code Climate](https://codeclimate.com/github/dryrb/dry-data/badges/gpa.svg)][codeclimate]
[![Test Coverage](https://codeclimate.com/github/dryrb/dry-data/badges/coverage.svg)][codeclimate]
[![Inline docs](http://inch-ci.org/github/dryrb/dry-data.svg?branch=master)][inchpages]

A simple type system for Ruby with support for coercions.

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'dry-data'
```

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install dry-data

## Usage

You can use `dry-data` for defining various data types in your application, like
domain entities and value objects or hashes with coercible values used to handle
params.

Built-in types are grouped under 5 categories:

- default: pass-through without any checks
- `strict` - doesn't coerce and checks the input type against the primitive class
- `coercible` - tries to coerce and raises type-error if it failed
- `form` - non-strict coercion types suitable for form params
- `maybe` - accepts either a nil or something else

### Built-in Type Categories

Non-coercible:

- `nil`
- `symbol`
- `class`
- `true`
- `false`
- `date`
- `date_time`
- `time`

Coercible types using kernel coercion methods:

- `coercible.string`
- `coercible.int`
- `coercible.float`
- `coercible.decimal`
- `coercible.array`
- `coercible.hash`

Optional strict types:

- `maybe.strict.string`
- `maybe.strict.int`
- `maybe.strict.float`
- `maybe.strict.decimal`
- `maybe.strict.array`
- `maybe.strict.hash`

Optional coercible types:

- `maybe.coercible.string`
- `maybe.coercible.int`
- `maybe.coercible.float`
- `maybe.coercible.decimal`
- `maybe.coercible.array`
- `maybe.coercible.hash`

Coercible types suitable for form param processing:

- `form.nil`
- `form.date`
- `form.date_time`
- `form.time`
- `form.true`
- `form.false`
- `form.bool`
- `form.int`
- `form.float`
- `form.decimal`

### Accessing Built-in Types

``` ruby
# default passthrough category
float = Dry::Data["float"]

float[3.2] # => 3.2
float["3.2"] # "3.2"

# strict type-check category
int = Dry::Data["strict.int"]

int[1] # => 1
int['1'] # => raises TypeError

# coercible type-check group
string = Dry::Data["coercible.string"]
array = Dry::Data["coercible.array"]

string[:foo] # => 'foo'
array[:foo] # => [:foo]

# form group
date = Dry::Data["form.date"]
date['2015-11-29'] # => #<Date: 2015-11-29 ((2457356j,0s,0n),+0s,2299161j)>
```

### Optional types

All built-in types have their optional versions too, you can access them under
`"maybe.strict"` and `"maybe.coercible"` categories:

``` ruby
maybe_int = Dry::Data["maybe.strict.int"]

maybe_int[nil] # None
maybe_int[123] # Some(123)

maybe_coercible_float = Dry::Data["maybe.coercible.float"]

maybe_int[nil] # None
maybe_int['12.3'] # Some(12.3)
```

You can define your own optional types too:

``` ruby
maybe_string = Dry::Data["optional"] | Dry::Data["string"]

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
# => "SOMETHING"
```

### Constrained Types

You can create constrained types that will use validation rules to check if the
input is not violating any of the configured contraints. You can treat it as
a lower level guarantee that you're not instantiating objects that are broken.

All types support constraints API, but not all constraints are suitable for a
particular primitive, it's up to you to set up constraints that make sense.

Under the hood it uses `dry-validation`[https://github.com/dryrb/dry-validation]
and all of its predicates are supported.

IMPORTANT: `dry-data` does not have a runtime dependency on `dry-validation` so
if you want to use contrained types you need to add it to your Gemfile

If you want to use constrained type you need to require it explicitly:

``` ruby
require "dry/data/type/constrained"
```

``` ruby
string = Dry::Data["strict.string"].constrained(min_size: 3)

string['foo']
# => "foo"

{'fraction_non_alphanumeric': 0.1584536958368734, 'fraction_numerical': 0.012744265080713678, 'mean_word_length': 4.622089552238806, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 29, 'https://': 28, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5138144', 'n_tokens_mistral': 3458, 'n_tokens_neox': 3262, 'n_words': 837}