README.md

Summary

Maintainability
Test Coverage
# Isy
*(pronounced like 'izzy')*

[![Build Status](https://travis-ci.org/CodingZeal/isy.svg?branch=master)](https://travis-ci.org/CodingZeal/isy)
[![Code Climate](https://codeclimate.com/github/acuppy/isy/badges/gpa.svg)](https://codeclimate.com/github/CodingZeal/isy)

Guard clauses for argument type assertions can be messy:

```ruby
def fullname segments=[]
  raise ArgumentError, 'User#fullname expects 'segments' to be an Array' if segments.is_a? Array
  # ...
end
```

Setting aside that an issue of this type could be a sign of a greater
architectural problem, `Isy` takes a declarative approach to solving the problem.
Instead of dictating the contraints (and resulting response) to each argument type,
you can leverage Isy's simple interface:

## Usage

The primary use of Isy is through the `isy` method, which is included into Object upon initialization

You can call isy from any point, but it's intended use is to be treated like a "guard clause" to
assert method argument types before those arguments are used (and potentially wreak havoc
throughout the implementation:

```ruby
def fullname segments=[]
  isy segments, Array
  # ...
end
```

The first argument is the subject of the test (i.e. what should match the proceeding assertion)
The second argument is the class, `Range`, `Regexp` or any object (type) which responds to `===`.

If the subject doesn't match the provided type, then it raises a formatted exception describing
what argument *value* was a type mismatch (as an `Isy::ArgumentTypeMismatch` exception).

Alternatively, you can use the predicate version for type assertion:

```ruby
def fullname segments=[]
  if isy? segments, Array
    # passes
  end
end
```

In the previous example, the interface is the same: subject, arguments,
optional block.  The difference is that if the assertion fails, it will
catch the `Isy::ArgumentTypeMismatch` exception and return `false`.

## Usage with an operation

Optionally, in place of a type as the second argument, you can pass a block, and perform
a more complex comparison operation:

```ruby
def fullname segments
  isy segments { |seg| seg.length == 3 }
  # ...
end
```

As illustrated above, `isy` yields to the operation the first argument (segments).  The expectation
is that the value returned by the operation (block) is a boolen (true => passes, false => failed).

*Note: predicate version has the same support*

## Performance

It's not great against a more "native" implementation; but, where you lose a little
in performance, you (may) gain in an ability to quickly reason about the
code.

A native implementation is incredibly light (see above): no additional dependencies
and logistical overhead.  Using `Isy` you're introducing an additional dependency and
better support for evaluation routines (by providing a block).

To run a comparison benchmark:

`$ ruby spec/benchmark.rb`

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'isy'
```

## 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.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/isy. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.

## License

Authored by the Engineering Team of [Coding ZEAL](https://codingzeal.com?utm_source=github)

Copyright (c) 2017 Zeal, LLC.  Licensed under the [MIT license](https://opensource.org/licenses/MIT).