Skip to content

Commit

Permalink
docs: update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
u8slvn committed Feb 2, 2024
1 parent d69d79c commit 64fd30e
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 14 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,21 @@ class Fruit:
self.bitter = bitter


class FruitIsBitter(Specification):
class FruitIsBitter(Specification[Fruit]):
description = 'The given fruit must be bitter.'

def is_satisfied_by(self, fruit: Fruit) -> bool:
return fruit.bitter is True


class FruitIsSweet(Specification):
class FruitIsSweet(Specification[Fruit]):
description = 'The given fruit must be sweet.'

def is_satisfied_by(self, fruit: Fruit) -> bool:
return fruit.sweet is True


class FruitIsYellow(Specification):
class FruitIsYellow(Specification[Fruit]):
description = 'The given fruit must be yellow.'

def is_satisfied_by(self, fruit: Fruit) -> bool:
Expand All @@ -68,7 +68,7 @@ True

### Operators

Bitwise operators are overload to provide simple syntax.
**Sutoppu** uses bitwise operator overloading to provide simplified syntax.

And:

Expand All @@ -90,7 +90,7 @@ Not:

### Lighter syntax

If you do not find the `is_satisfied_by` method very convenient you can also directly call the specification as below.
If you find the `is_satisfied_by` method inconvenient you can alternatively call the specification as shown below.

```python
>>> lemon = Fruit(color='yellow', sweet=False, bitter=True)
Expand All @@ -101,8 +101,8 @@ False

### Error reporting

It can be difficult to know which specification failed in a complex rule. Sutoppu allows to list all the failed specifications by getting the `errors` attribute after use.
The `errors` attribute is reset each time the specification is used. For each failed specification, it returns a dict with the name of the specification class for key and the description provide in the class for value. In the case where the specification failed with a `not` condition, the description is prefixed with `Not ~`.
It can be difficult to know which specification failed in complex concatenated rules. Sutoppu allows to list all the failed specifications by getting the `errors` attribute after use.
The `errors` attribute is reset each time the specification is used. For each failed specification, it returns a dict with the name of the specification class as key and the description provided in the class as value. In the case where the specification failed with a `not` condition, the description is prefixed with `Not ~`.

```python
>>> apple = Fruit(color='red', sweet=True, bitter=False)
Expand Down
16 changes: 9 additions & 7 deletions src/sutoppu.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@


class _SpecificationMeta(ABCMeta):
"""Add a little bit of magic, _SpecificationMeta automatically apply the
"""Specification metaclass
Add a little bit of magic, _SpecificationMeta automatically apply the
class method '_report_errors' as decorator for the 'is_satisfied_by'
method. It allows to simplify Specification declaration by declaring only
'is_satisfied_by' without paying attention of the '_report_errors'
Expand All @@ -46,8 +48,9 @@ def __new__(


class Specification(Generic[T], metaclass=_SpecificationMeta):
"""Specification base class, each domain specification must inherit from
this class.
"""Specification base class
Each domain specification must inherit from this class.
"""

description = "No description provided."
Expand Down Expand Up @@ -93,7 +96,7 @@ def __invert__(self) -> _NotSpecification[T]: # not
return _NotSpecification(self)

def __call__(self, candidate: Any) -> bool:
"""Extra syntax for more facilities."""
"""Additional syntax for ease of use."""
return self.is_satisfied_by(candidate)

def __repr__(self) -> str:
Expand All @@ -109,9 +112,8 @@ def __init__(self, spec_a: Specification[T], spec_b: Specification[T]) -> None:

def _report_error(self, _: bool) -> None:
"""Gets the children spec errors and merge them into its own.
The goal behind this it to propagate the errors through all the
parents specifications.
The result argument is useless in this case.
Allows to propagate errors through all parents specifications.
The result parameter is ignored in this case.
"""
for spec in self._specs:
self.errors = {**self.errors, **spec.errors}
Expand Down

0 comments on commit 64fd30e

Please sign in to comment.