README.md in dry-data-0.2.1 vs README.md in dry-data-0.3.0
- old
+ new
@@ -49,10 +49,12 @@
### Built-in Type Categories
Non-coercible:
- `nil`
+- `symbol`
+- `class`
- `true`
- `false`
- `date`
- `date_time`
- `time`
@@ -160,10 +162,125 @@
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"
+
+string['fo']
+# => Dry::Data::ConstraintError: "fo" violates constraints
+
+email = Dry::Data['strict.string'].constrained(
+ format: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
+)
+
+email["jane@doe.org"]
+# => "jane@doe.org"
+
+email["jane"]
+# => Dry::Data::ConstraintError: "fo" violates constraints
+```
+
+### Setting Type Constants
+
+Types can be stored as easily accessible constants in a configured namespace:
+
+``` ruby
+module Types; end
+
+Dry::Data.configure do |config|
+ config.namespace = Types
+end
+
+# after defining your custom types (if you've got any) you can finalize setup
+Dry::Data.finalize
+
+# this defines all types under your namespace
+Types::Coercible::String
+# => #<Dry::Data::Type:0x007feffb104aa8 @constructor=#<Method: Kernel.String>, @primitive=String>
+```
+
+With types accessible as constants you can easily compose more complex types,
+like sum-types or constrained types, in hash schemas or structs:
+
+``` ruby
+Dry::Data.configure do |config|
+ config.namespace = Types
+end
+
+Dry::Data.finalize
+
+module Types
+ Email = String.constrained(format: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i)
+ Age = Int.constrained(gt: 18)
+end
+
+class User < Dry::Data::Struct
+ attribute :name, Types::String
+ attribute :email, Types::Email
+ attribute :age, Types::Age
+end
+```
+
+### Defining Enums
+
+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 a `int => value` map, so you can store integers somewhere and have them
+mapped to enum values conveniently.
+
+You can define enums for every type but it probably only makes sense for `string`:
+
+``` ruby
+# assuming we have types loaded into `Types` namespace
+# we can easily define an enum for our post struct
+class Post < Dry::Data::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[0] # => "draft"
+Post::Statuses['draft'] # => "draft"
+
+# it'll raise if something silly was passed in
+Post::Statuses['something silly']
+# => Dry::Data::ConstraintError: "something silly" violates constraints
+
+# nil is considered as something silly too
+Post::Statuses[nil]
+# => Dry::Data::ConstraintError: nil violates constraints
+```
+
### Defining a hash with explicit schema
The built-in hash type has constructors that you can use to define hashes with
explicit schemas and coercible values using the built-in types.
@@ -228,15 +345,15 @@
user.name # => Some("Jane")
user.age # => 21
```
-## WIP
+## Status and Roadmap
-This is early alpha with a rough plan to:
+This library is in an early stage of development but you are encauraged to try it
+out and provide feedback.
-* Add constrained types (ie a string with a strict length, a number with a strict range etc.)
-* Benchmark against other libs and make sure it's fast enough
+For planned features check out [the issues](https://github.com/dryrb/dry-data/labels/feature).
## Development
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.