Skip to content

Commit

Permalink
Adding missing basic specification classes
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed May 13, 2022
1 parent b064f96 commit 6646e65
Show file tree
Hide file tree
Showing 14 changed files with 205 additions and 14 deletions.
37 changes: 34 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,48 @@

All Notable changes to `bakame/spec` will be documented in this file

## [1.1.0] - 2022-05-13

### Added

- `AndNotX` and `OrNotX` Specifications
- `Composite::andNotX` and `Composite::orNotX` methods

### Fixed

- added missing `declare(strict_types=1);` declaration
- made protected properties private

### Deprecated

- none

### Removed

- none

## [1.0.1] - 2022-05-13

### Added

- none

### Fixed

Remove development files from package download.
- Remove development files from package download.

### Deprecated

- none

### Removed

- none

## [1.0.0] - 2022-05-13

**Initial release!**


[1.0.1]: https://github.com/bakame-php/spec/releases/tag/1.0.0...1.0.1
[1.1.0]: https://github.com/bakame-php/spec/compare/1.0.1...1.1.0
[1.0.1]: https://github.com/bakame-php/spec/compare/1.0.0...1.0.1
[1.0.0]: https://github.com/bakame-php/spec/releases/tag/1.0.0
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,16 @@ foreach ($invoiceCollection as $invoice) {
Under the hood the `Specification\Chain` class calls and uses the following classes
to allow the implementations of complex business rules.

| Classes | Logical usage | Chain methods |
|---------|--------------------------------------------------------------------|---------------------------------|
| All | All specifications must be satisfied by the subject | `Chain::all` named constructor |
| Any | At least one of the specifications provided must be satisfied | `Chain::any` named constructor |
| None | None of all provided specification must be satisfied by the author | `Chain::none` named constructor |
| AndX | Combined two specifications where both must be satisfied | `Chain::andX` method |
| OrX | Combined two specifications where at least one must be satisfied | `Chain::orX` method |
| Not | Returns the opposite result of the provided specification | `Chain::not` method |
| Classes | Logical usage | Chain methods |
|---------|----------------------------------------------------------------------------------------------------|---------------------------------|
| All | All specifications must be satisfied by the subject | `Chain::all` named constructor |
| AndX | Combined two specifications where both must be satisfied | `Chain::andX` method |
| AndNotX | Combined two specifications where the left specification is satisfied **and** the right one is not | `Chain::andNotX` method |
| Any | At least one of the specifications provided must be satisfied | `Chain::any` named constructor |
| None | None of all provided specification must be satisfied by the author | `Chain::none` named constructor |
| Not | Returns the opposite result of the provided specification | `Chain::not` method |
| OrX | Combined two specifications where at least one must be satisfied | `Chain::orX` method |
| OrNotX | Combined two specifications where the left specification is satisfied **or** the right one is not | `Chain::orNotX` method |

Creating more complex rules that you can individually test becomes trivial as do their maintenance.

Expand Down
2 changes: 1 addition & 1 deletion src/All.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
final class All implements Specification, Countable, IteratorAggregate
{
/** @var array<Specification> */
protected array $specifications;
private array $specifications;

final public function __construct(Specification ...$specifications)
{
Expand Down
20 changes: 20 additions & 0 deletions src/AndNotX.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Bakame\Specification;

final class AndNotX implements Specification
{
public function __construct(
private Specification $specificationA,
private Specification $specificationB
) {
}

public function isSatisfiedBy(mixed $subject): bool
{
return $this->specificationA->isSatisfiedBy($subject)
&& !$this->specificationB->isSatisfiedBy($subject);
}
}
49 changes: 49 additions & 0 deletions src/AndNotXSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Bakame\Specification;

use PhpSpec\ObjectBehavior;

final class AndNotXSpec extends ObjectBehavior
{
public function let(Specification $spec1, Specification $spec2): void
{
$this->beConstructedWith($spec1, $spec2);
}

public function it_is_initializable(): void
{
$this->shouldHaveType(AndNotX::class);
}

public function it_implements_the_specification_interface(): void
{
$this->shouldImplement(Specification::class);
}

public function it_will_pass_with_both_spec_being_satisfied(Specification $spec1, Specification $spec2): void
{
$spec1->isSatisfiedBy('anything')->willReturn(true);
$spec2->isSatisfiedBy('anything')->willReturn(false);

$this->isSatisfiedBy('anything')->shouldEqual(true);
}

public function it_will_fail_with_at_least_one_spec_not_being_satisfied(Specification $spec1, Specification $spec2): void
{
$spec1->isSatisfiedBy('anything')->willReturn(false);
$spec2->isSatisfiedBy('anything')->willReturn(true);

$this->isSatisfiedBy('anything')->shouldEqual(false);
}

public function it_will_fail_with_both_spec_failing(Specification $spec1, Specification $spec2): void
{
$spec1->isSatisfiedBy('anything')->willReturn(false);
$spec2->isSatisfiedBy('anything')->willReturn(false);

$this->isSatisfiedBy('anything')->shouldEqual(false);
}
}
2 changes: 2 additions & 0 deletions src/AndX.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Bakame\Specification;

final class AndX implements Specification
Expand Down
2 changes: 1 addition & 1 deletion src/Any.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
final class Any implements Specification, Countable, IteratorAggregate
{
/** @var array<Specification> */
protected array $specifications;
private array $specifications;

final public function __construct(Specification ...$specifications)
{
Expand Down
12 changes: 12 additions & 0 deletions src/Chain.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Bakame\Specification;

final class Chain implements Composite
Expand Down Expand Up @@ -43,11 +45,21 @@ public function andX(Specification $specification): Composite
return new self(new AndX($this->specification, $specification));
}

public function andNotX(Specification $specification): Composite
{
return new self(new AndNotX($this->specification, $specification));
}

public function orX(Specification $specification): Composite
{
return new self(new OrX($this->specification, $specification));
}

public function orNotX(Specification $specification): Composite
{
return new self(new OrNotX($this->specification, $specification));
}

public function not(): Composite
{
return new self(new Not($this->specification));
Expand Down
2 changes: 2 additions & 0 deletions src/Composite.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
interface Composite extends Specification
{
public function andX(Specification $specification): Composite;
public function andNotX(Specification $specification): Composite;
public function orX(Specification $specification): Composite;
public function orNotX(Specification $specification): Composite;
public function not(): Composite;
}
2 changes: 1 addition & 1 deletion src/None.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
final class None implements Specification, Countable, IteratorAggregate
{
/** @var array<Specification> */
protected array $specifications;
private array $specifications;

final public function __construct(Specification ...$specifications)
{
Expand Down
20 changes: 20 additions & 0 deletions src/OrNotX.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Bakame\Specification;

final class OrNotX implements Specification
{
public function __construct(
private Specification $specificationA,
private Specification $specificationB
) {
}

public function isSatisfiedBy(mixed $subject): bool
{
return $this->specificationA->isSatisfiedBy($subject)
|| !$this->specificationB->isSatisfiedBy($subject);
}
}
49 changes: 49 additions & 0 deletions src/OrNotXSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Bakame\Specification;

use PhpSpec\ObjectBehavior;

final class OrNotXSpec extends ObjectBehavior
{
public function let(Specification $spec1, Specification $spec2): void
{
$this->beConstructedWith($spec1, $spec2);
}

public function it_is_initializable(): void
{
$this->shouldHaveType(OrNotX::class);
}

public function it_implements_the_specification_interface(): void
{
$this->shouldImplement(Specification::class);
}

public function it_will_pass_with_both_spec_being_satisfied(Specification $spec1, Specification $spec2): void
{
$spec1->isSatisfiedBy('anything')->willReturn(true);
$spec2->isSatisfiedBy('anything')->willReturn(true);

$this->isSatisfiedBy('anything')->shouldEqual(true);
}

public function it_will_pass_with_at_least_one_spec_not_being_satisfied(Specification $spec1, Specification $spec2): void
{
$spec1->isSatisfiedBy('anything')->willReturn(false);
$spec2->isSatisfiedBy('anything')->willReturn(true);

$this->isSatisfiedBy('anything')->shouldEqual(false);
}

public function it_will_fail_with_both_spec_failing(Specification $spec1, Specification $spec2): void
{
$spec1->isSatisfiedBy('anything')->willReturn(false);
$spec2->isSatisfiedBy('anything')->willReturn(false);

$this->isSatisfiedBy('anything')->shouldEqual(true);
}
}
2 changes: 2 additions & 0 deletions src/OrX.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Bakame\Specification;

final class OrX implements Specification
Expand Down
2 changes: 2 additions & 0 deletions src/Specification.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Bakame\Specification;

interface Specification
Expand Down

0 comments on commit 6646e65

Please sign in to comment.