Skip to content

Commit

Permalink
enhance documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
rmorshea committed Dec 4, 2020
1 parent 86df9c5 commit 8925f2f
Show file tree
Hide file tree
Showing 14 changed files with 179 additions and 72 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var/
*.egg-info/
.installed.cfg
*.egg
*.whl

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
12 changes: 6 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ script: eval $TEST_CMD
matrix:
include:
- name: "dist"
python: 3.7
python: 3.8
env:
- TEST_CMD="python setup.py sdist bdist_wheel; pip install readme_renderer; twine check dist/*"
- name: "black"
python: 3.7
python: 3.8
env:
- TEST_CMD="black --verbose ."
- TEST_CMD="black --check ."
- name: "flake8"
python: 3.7
python: 3.8
env:
- TEST_CMD="flake8"
- name: "python-3.6"
python: 3.6
- name: "python-3.7"
python: 3.7
- name: "python-3.8-dev"
python: 3.8-dev
- name: "python-3.8"
python: 3.8
17 changes: 17 additions & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
API
===

.. automodule:: spectate.models
:members:

.. automodule:: spectate.base
:members:

.. automodule:: spectate.events
:members:

.. automodule:: spectate.utils
:members:

.. automodule:: spectate.mvc
:members:
11 changes: 0 additions & 11 deletions docs/source/api/index.rst

This file was deleted.

14 changes: 0 additions & 14 deletions docs/source/api/mvc.rst

This file was deleted.

5 changes: 0 additions & 5 deletions docs/source/api/spectate.rst

This file was deleted.

36 changes: 28 additions & 8 deletions docs/source/usage/basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ The Basics

Spectate defines three main constructs:

1. :class:`models <spectate.mvc.base.Model>` - objects which get modified by the user.
1. :class:`models <spectate.base.Model>` - objects which get modified by the user.

2. :func:`views <spectate.mvc.base.view>` - functions which receives change events.
2. :func:`views <spectate.base.view>` - functions which receives change events.

3. :class:`controls <spectate.mvc.base.Control>` - private attributes of a model which produces change events.
3. :class:`controls <spectate.base.Control>` - private attributes of a model which produces change events.

Since the :mod:`mvc <spectate.mvc>` module already provides some basic models for us you
don't need to worry about :class:`controls <spectate.mvc.base.Control>` yet. Let's begin
by considering a builtin :class:`~spectate.mvc.models.Dict` model. We can instantiate
Since the :mod:`mvc <spectate>` module already provides some basic models for us you
don't need to worry about :class:`controls <spectate.base.Control>` yet. Let's begin
by considering a builtin :class:`~spectate.models.Dict` model. We can instantiate
this object just as we would with a standard :class:`dict`:

.. code-block:: python
Expand All @@ -20,7 +20,7 @@ this object just as we would with a standard :class:`dict`:
d = mvc.Dict(a=0)
Now though, we can now register a :func:`~spectate.mvc.base.view` function with a
Now though, we can now register a :func:`~spectate.base.view` function with a
decorator. This view function is called any time a change is made to the model ``d``
that causes its data to be mutated.

Expand All @@ -33,7 +33,7 @@ that causes its data to be mutated.
Change events are passed into this function as a tuple of immutable dict-like objects
containing change information. Each model has its own change event information.
In the case of a :class:`~spectate.mvc.models.Dict` the event objects have the fields
In the case of a :class:`~spectate.models.Dict` the event objects have the fields
``key``, ``old``, and ``new``. So when we change a key in ``d`` we'll find that our
``printer`` view function is called and that it prints out an event object with the
expected information:
Expand All @@ -57,3 +57,23 @@ objects can be broadcast to the view function:
{'key': 'b', 'old': Undefined, 'new': 2}
{'key': 'c', 'old': Undefined, 'new': 3}
Nested Models
-------------

What if we want to observe changes to nested data structures though? Thankfuly
Spectate's :ref:`Builtin Model Types` which inherit from :class:`~spectate.models.Structure`
can handle this for you:

.. code-block:: python
from spectate import mvc
outer_dict = mvc.Dict()
inner_dict = mvc.Dict()
outer_dict["inner"] = inner_dict
@mvc.view(outer_dict)
def printer(value, events):
28 changes: 14 additions & 14 deletions docs/source/usage/builtins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ then you can :ref:`define your own models <Creating Models>`.
Dictionary
''''''''''

The :class:`~spectate.mvc.models.Dict` model is a subclass of Python's standard
The :class:`~spectate.models.Dict` model is a subclass of Python's standard
:class:`dict`. This will produce events when the value of a key in the dictionary
changes or is deleted. This will result when calling methods like :meth:`dict.update`
and :meth:`dict.pop`, but also when using the normal syntax to set or delete an item.
Events produced by :class:`~spectate.mvc.models.Dict` have the following fields:
Events produced by :class:`~spectate.models.Dict` have the following fields:

.. list-table::
:widths: 1 10
Expand All @@ -27,22 +27,22 @@ Events produced by :class:`~spectate.mvc.models.Dict` have the following fields:

* - ``old``
- * The value that was present in the key before the change
* Is :attr:`~spectate.mvc.models.Undefined` if the index was not present.
* Is :attr:`~spectate.models.Undefined` if the index was not present.

* - ``new``
- * The value that this is now present after the change
* Is :attr:`~spectate.mvc.models.Undefined` if the index was deleted.
* Is :attr:`~spectate.models.Undefined` if the index was deleted.


List
''''

The :class:`~spectate.mvc.models.List` model is a subclass of Python's standard
The :class:`~spectate.models.List` model is a subclass of Python's standard
:class:`list`. This model will produce events when an element of the list changes
or an element changes from one position to another. This may happen when calling
methods like :meth:`list.append` or :meth:`list.remove`, but also when using the
normal syntax to set or delete an item. Events produced by
:class:`~spectate.mvc.models.List` have the following keys:
:class:`~spectate.models.List` have the following keys:

.. list-table::
:widths: 1 10
Expand All @@ -56,20 +56,20 @@ normal syntax to set or delete an item. Events produced by

* - ``old``
- * The value that was present before the change
* Is :attr:`~spectate.mvc.models.Undefined` if the key was not present.
* Is :attr:`~spectate.models.Undefined` if the key was not present.

* - ``new``
- * The value that this is now present after the change
* Is :attr:`~spectate.mvc.models.Undefined` if the key was deleted.
* Is :attr:`~spectate.models.Undefined` if the key was deleted.


Set
'''

The :class:`~spectate.mvc.models.Set` model is a subclass of Python's standard
The :class:`~spectate.models.Set` model is a subclass of Python's standard
:class:`set`. This model will produce events when an element of the set changes.
This may happen when calling methods like :meth:`set.add` or :meth:`set.discard`.
Events produced by :class:`~spectate.mvc.models.Set` have the following keys:
Events produced by :class:`~spectate.models.Set` have the following keys:

.. list-table::
:widths: 1 10
Expand All @@ -88,11 +88,11 @@ Events produced by :class:`~spectate.mvc.models.Set` have the following keys:
Object
''''''

The :class:`~spectate.mvc.models.Object` model is a subclass of Python's standard
The :class:`~spectate.models.Object` model is a subclass of Python's standard
:class:`object`. This model will produce events when an attribute of the object changes
or is deleted. This may happen when using :func:`setattr` or :func:`delattr`, but also
when using the normal syntax to set or delete attributes. Events produced by
:class:`~spectate.mvc.models.Object` have the following keys:
:class:`~spectate.models.Object` have the following keys:

.. list-table::
:widths: 1 10
Expand All @@ -106,8 +106,8 @@ when using the normal syntax to set or delete attributes. Events produced by

* - ``old``
- * The value that was present before the change
* Is :attr:`~spectate.mvc.models.Undefined` if the attribute was not present.
* Is :attr:`~spectate.models.Undefined` if the attribute was not present.

* - ``new``
- * The value that this is now present after the change
* Is :attr:`~spectate.mvc.models.Undefined` if the key was deleted.
* Is :attr:`~spectate.models.Undefined` if the key was deleted.
18 changes: 9 additions & 9 deletions docs/source/usage/create-models.rst
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
Creating Models
===============

Creating models requires you to define a :class:`~spectate.mvc.base.Model` subclass
which has :class:`~spectate.mvc.base.Control` objects assigned to it. Each control
Creating models requires you to define a :class:`~spectate.base.Model` subclass
which has :class:`~spectate.base.Control` objects assigned to it. Each control
object is responsible for observing calls to particular methods on the model class.
For example, if you wanted to know when an element was appended to a list you might
observe the ``append`` method.

To show how this works we will implement a simple counter with the goal of knowing when
the value in the counter has incremented or decremented. To get started we should create
a ``Counter`` class which inherits from :class:`~spectate.mvc.base.Model` and define
a ``Counter`` class which inherits from :class:`~spectate.base.Model` and define
its ``increment`` and ``decrement`` methods normally:

.. code-block:: python
Expand Down Expand Up @@ -41,7 +41,7 @@ Adding Model Controls

Because we know that the value within the ``Counter`` changes whenever ``increment`` or
``decrement`` is called these are the methods that we must observe in order to determine
whether, and by how much it changes. Do do this we should add a :class:`~spectate.mvc.base.Control`
whether, and by how much it changes. Do do this we should add a :class:`~spectate.base.Control`
to the ``Counter`` and pass in the names of the methods it should be tracking.

.. code-block:: python
Expand All @@ -63,8 +63,8 @@ to the ``Counter`` and pass in the names of the methods it should be tracking.
We define the behavior of ``_control_change`` with methods that are triggered before
and/or after the ones being observed. We register these with
:meth:`Control.before() <~spectate.mvc.base.Control.before>`
and :meth:`Control.after() <~spectate.mvc.base.Control.after>`. For now our
:meth:`Control.before() <~spectate.base.Control.before>`
and :meth:`Control.after() <~spectate.base.Control.after>`. For now our
beforeback and afterback will just contain print statements so we can see what they
receive when they are called.

Expand Down Expand Up @@ -200,7 +200,7 @@ Sending Event Notifications
We're now able to use :ref:`"beforebacks" <Model Beforebacks>` and
:ref:`"afterbacks" <Model Afterbacks>` to print out information about a model before
and after a change occures, but what we actually want is to send this same information to
:func:`views <spectate.mvc.base.view>` as we did when we learned :ref:`the basics`.
:func:`views <spectate.base.view>` as we did when we learned :ref:`the basics`.
To accomplish this we use the ``notify`` function passed into the beforeback and
afterback and pass it keyword parameters that can be consumed by views. To keep
things simple we'll just replace our ``print`` statements with calls to ``notify``:
Expand Down Expand Up @@ -287,7 +287,7 @@ Have a signature of ``(call, notify) -> before``
passed to the method have been mapped to argument names. This won't work for builtin
method like :meth:`dict.get` since they're implemented in C.

+ ``notify`` is a function which will distribute an event to :func:`views <spectate.mvc.base.view>`
+ ``notify`` is a function which will distribute an event to :func:`views <spectate.base.view>`

+ ``before`` is a value which gets passed on to its respective :ref:`afterback <Model Afterbacks>`.

Expand All @@ -305,4 +305,4 @@ Have a signature of ``(answer, notify)``

+ ``'before'`` - the value returned by the respective beforeback

+ ``notify`` is a function which will distribute an event to :func:`views <spectate.mvc.base.view>`
+ ``notify`` is a function which will distribute an event to :func:`views <spectate.base.view>`
40 changes: 35 additions & 5 deletions docs/source/usage/events.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Holding Events
--------------

It's often useful to withhold sending notifications until all your changes are complete.
Using the :func:`~spectate.mvc.events.hold` context manager, events created when
Using the :func:`~spectate.events.hold` context manager, events created when
modifying a model won't be distributed until we exit the context:

.. code-block:: python
Expand Down Expand Up @@ -42,7 +42,7 @@ Merging Events

Sometimes there is a block of code in which it's possible to produce duplicate events
or events which could be merged into one. By passing in a ``reducer`` to
:func:`~spectate.mvc.events.hold` you can change the list of events just before they
:func:`~spectate.events.hold` you can change the list of events just before they
are distributed. This is done by having the ``reducer`` return or yield the new events.

.. code-block:: python
Expand Down Expand Up @@ -79,7 +79,7 @@ Rolling Back Events
-------------------

When an error occurs while modifying a model you may not want to distribute events.
Using :func:`~spectate.mvc.events.rollback` you can suppress events that were produced
Using :func:`~spectate.events.rollback` you can suppress events that were produced
in the same context as an error:

.. code-block:: python
Expand All @@ -104,7 +104,7 @@ in the same context as an error:
Rolling Back Changes
''''''''''''''''''''

Suppressing events after an error may not be enough. You can pass :func:`~spectate.mvc.events.rollback`
Suppressing events after an error may not be enough. You can pass :func:`~spectate.events.rollback`
an ``undo`` function which gives you a chances to analyze the events in order to determine
and then return a model to its original state. Any events that you might produce while
modifying a model within the ``undo`` function will be :ref:`muted <Muting Events>`.
Expand Down Expand Up @@ -142,7 +142,7 @@ Muting Events

If you are setting a default state, or returning to one, it may be useful to withhold
events completely. This one's pretty simple compared to the context managers above.
Just use :func:`~spectate.mvc.events.mute` and within its context, no events will
Just use :func:`~spectate.events.mute` and within its context, no events will
be distributed:

.. code-block:: python
Expand All @@ -158,3 +158,33 @@ be distributed:
with mvc.mute(l):
l.append(1)
Force Notifying
---------------

At times, and more likely when writing tests, you may need to forcefully send an event
to a model. This can be achieved using the :func:`~spectate.base.notifier` context
manager which provides a ``notify()`` function identical to the one seen in
:ref:`Model Callbacks`.

.. warning::

While you could use :func:`~spectate.base.notifier` instead of adding
:ref:`Adding Model Controls` to your custom models, this is generall discouraged
because the resulting implementation is resistent to extension in subclasses.

.. code-block:: python
from spectate import mvc
m = mvc.Model()
@mvc.view(m)
def printer(m, events):
for e in events:
print(e)
with mvc.notifier(m) as notify:
# the view should print out this event
notify(x=1, y=2)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ funcsigs;python_version<"3.6"
# Distribution
# ============
twine
wheel
cmarkgfm

# Documentation
Expand Down
Loading

0 comments on commit 8925f2f

Please sign in to comment.