Integrating `zernike.py` and creating a new ZernikeOptic

Ideally this would not be lumped in the same branch / same pull request, but it's not sufficiently straightforward to disentangle these changes that I feel like it'd be worth the trouble.

I did a formatting pass through `optics.py`, but didn't change any functionality except to fix #14 and implement the new optic classes.

There are also a few things left to do, which I'm leaving here for my future reference:

  - [x] Docstrings for `ZernikeOptic` and `ZernikeThinLens`
  - [x] ... or maybe I should just throw out `ZernikeThinLens`, and add pupil_radius to `ThinLens`...
  - [x] Figure out where the JW-specific stuff that used to be in `zernike.py` should live in WebbPSF
  - [x] On a related note, a way to swap out the basis set for `ZernikeOptic`
  - [x] Add tests to the suite for #14 and sanity checking of the `ZernikeOptic`
  - [x] Add ZernikeOptic to `__all__`
could try to cast pupil_radius to a scalar float here, for defensive programming's sake. And probably check that coefficients is an iterable and basis_factory is callable.