TypedAttr
Typed Attributes and Composite Types for Functional Programming in Ruby
Usage
TypedAttr simplifies typed functional programming in Ruby.
The creation of data types is central to functional programming. Ruby does not enforce any typing of object attributes or method parameters.
TypedAttr introduces a class macro "typed_attr". It constructs an #initialize method given a list of attributes and their expected types.
Example:
require 'typed_attr'
class Account
typed_attr name: String, amount: Money
end
Account.new("Foo", Money.new(1234))
Account.new("Foo", 1234) # => raise TypeError
Use "typecheck" to perform checks on values:
def m x, y
typecheck x, String
typecheck y, Positive, Integer
x * y
end
m("string", -1) # => raise TypeError
m("string", 2) # => "stringstring"
The type assertions use the #=== matching operator.
Composite Types can be constructed to match deeper data structures:
h = { "a" => 1, "b" => :symbol }
typecheck h, Hash.of(String.with(Integer|Symbol))
Defining types through Modules:
module Even
def self.=== x
Integer === x and x.even?
end
end
Array.of(Even) === [ 2, 4, 10 ]
Composite types create dynamic Modules that redefine the #=== pattern matching operator. Thus composite types can be used in "case when" clauses:
case h
when Hash.of(String.with(Users)) ...
when Hash.of(Symbol.with(Object)) ...
end
Logical operators: #|, #&, #~ are supported:
a = [ 1, 2, 3 ]
typecheck a, Array.of(Positive & Numeric)
typecheck a, Array.of(~ NilClass)
b = [ 1, -2, 3 ]
typecheck b, Array.of(Positive & Numeric) # => raise TypeError
c = [ 1, nil, 3 ]
typecheck c, Array.of(~ NilClass) # => raise TypeError
Composite types are cached indefinitely, therefore anonymous Modules cannot be composed.
Installation
Add this line to your application's Gemfile:
gem 'typed_attr'
And then execute:
$ bundle
Or install it yourself as:
$ gem install typed_attr
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request