jaimegildesagredo/expects — pull request #6 by jvrsantacruz (2013-07-16 23:04:46+00:00)
Title: Adds support for iterables in have

Even though the 'in' operator supports checking whether some item is contained within a generator, this becomes quite unreliable for multiple item checking.

The problem consist in the generator being consumed on every check, turning the whole operation order-dependent:

```python
>>> iterable = iter(['foo', 'bar'])
>>> 'bar' in iterable
True
>>> 'foo' in iterable
False
```

The operator walks the iterable for a match, disposing non-matching elements.

```python
>>> iterable = iter(['foo', 'bar'])
>>> 'bar' in iterable
True
>>> list(iterable)
[]
```

Such convenient default behaviour has been maintained for the special case of checking one single element.

When more than one item are tested, the iterable is consumed into a set, which is subsequently checked multiple times.

Alternatives were to copy the generator on each checking:

```python
for arg in args:
assert(arg in copy(generator))
```
This might be regarded as cleaner, but it is rather unefficient approach as the generator has to be walked every time, bringing in O(n * args).

What was actually done is to construct a set, which is O(n) and then check against it, which is O(1).

The iterable becomes inusable after being checked.
Very large iterables would be loaded on memory (although avoiding repeated items).
Infinite iterables would bite the user.
Checking on infinite iterables could be achieved by using the `copy` approach, as it does not tries to consume it completely before. Hummm.