Proposal: Allow operator overloading for custom classes to return custom objects
#### Code Sample, a copy-pastable example if possible

```python
import numpy
import pandas

class Pipe:
    def __init__(self, function):
        self.function = function

    def __ror__(self, other):
        return self.function(other)

    def __array_ufunc__(self, func, method, *args, **kwargs):
        if func == numpy.bitwise_or:
            return self.function(args[0])
        return NotImplemented

>>> numpy.arange(4) | Pipe(lambda x: x[x > 1]) | Pipe(print)
[2, 3]
>>> pandas.Series([1,2,3]) | Pipe(lambda x: x[x > 1]) | Pipe(print)
Traceback (most recent call last):
...
ValueError: Length of passed values is 2, index implies 3
```

#### Problem description
Numpy allows custom classes to implement `__array_ufunc__` and customize the behavior for operators that apply on numpy array instances and custom classes. For example, I have implemented a Pipe class that calls function on its operand by `|` operator. You see that numpy instance detects `__array_ufunc__` method of its operand and delegates to my implementation, but pandas doesn't.

I have [monkeypatched](https://github.com/sspipe/sspipe/blob/eb4f8ef2a618307288a8e093059521163b93279c/sspipe/patch.py#L6-L32) this operator in [sspipe](https://github.com/sspipe/sspipe) library for now, but allowsing custom classes to implement custom behaviors makes opportunity for third-party libraries to integrate better with pandas.
