├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src └── CleverAge │ └── Ruler │ ├── Exception │ ├── Exception.php │ └── NotSatisfiedException.php │ ├── Rule │ └── ObjectIsEqual.php │ ├── RuleAbstract.php │ └── RuleInterface.php └── tests ├── CleverAge └── Ruler │ └── Test │ ├── Fixtures │ ├── BarObject.php │ ├── Exception │ │ ├── Custom2Exception.php │ │ └── CustomException.php │ ├── FooChildObject.php │ ├── FooObject.php │ └── Rule │ │ ├── FalsyRule.php │ │ └── TruelyRule.php │ ├── Functional │ └── RulerTest.php │ └── Rule │ └── ObjectIsEqualTest.php └── bootstrap.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | composer.lock 3 | composer.phar -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | 8 | before_script: 9 | - curl -s http://getcomposer.org/installer | php 10 | - php composer.phar install --dev 11 | 12 | script: phpunit 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | v1.0.0 (master) 2 | ===== 3 | * add more tests 4 | * `RuleInterface::doIsSatisfied` and `RuleInterface::doIsNotSatisfied` become protected (previously public) and move to `RuleAbstract` class. 5 | 6 | v0.1.0 : Initial version 7 | ===== -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/cleverage/Ruler.png)](https://travis-ci.org/cleverage/Ruler) 2 | 3 | Ruler 4 | ===== 5 | 6 | cleverage/Ruler is a PHP 5.3 Library. Use it to implement your own business rules, and link them in order to check if you are satisfying the set. 7 | 8 | Exemple : 9 | 10 | You want to check if the current user can activate a feature. For this, you have to check that : 11 | - he is connected, 12 | - he has the premium suscription, 13 | - he has enough money in his account. 14 | 15 | ```php 16 | andRule(new IsSuscriberRule($user, 'PREMIUM')) 21 | ->andRule(new HasMoneyRule($user, 300)) 22 | ->orRule(new IsAdminRule($user)); 23 | 24 | // PHP 5.4 25 | $rule = (new IsConnectedRule($user)) 26 | ->andRule(new IsSuscriberRule($user, 'PREMIUM')) 27 | ->andRule(new HasMoneyRule($user, 300)) 28 | ->orRule(new IsAdminRule($user)); 29 | 30 | try { 31 | if ($rule->isSatisfied()) { 32 | echo 'activated'; 33 | } 34 | } catch (NotConnectedException $e) { 35 | // show connection form 36 | } catch (NotSuscriberException $e) { 37 | // show subscription form 38 | } catch (NotEnoughMoneyException $e) { 39 | echo 'not enough Money'; 40 | } catch(\CleverAge\Ruler\Exception\Exception $e) { 41 | echo 'Failed : '.$e->getMessage(); 42 | } 43 | ``` 44 | 45 | ```php 46 | _user = $user; 57 | } 58 | 59 | public function doIsSatisfied() 60 | { 61 | return $this->_user->isLoggedOn(); 62 | } 63 | } 64 | ``` 65 | 66 | Combination of rules can even be done in a single rule class, in order to simplify your application code and increase maintability. 67 | 68 | ```php 69 | // ActiveFeatureXRule class 70 | class ActiveFeatureXRule extends \CleverAge\Ruler\RuleAbstract 71 | { 72 | public function __construct(\User $user) 73 | { 74 | $this->andRule(new IsSuscriberRule($user, 'PREMIUM')) 75 | ->andRule(new HasMoneyRule($user, 300)) 76 | ->orRule(new IsAdminRule($user)); 77 | } 78 | 79 | public function doIsSatisfied() 80 | { 81 | // method is abstract, and this container rule always satisfies. 82 | return true; 83 | } 84 | } 85 | ``` 86 | 87 | Now, you can use this rule class everywhere you need it, and just change the construct to have th rules reverberated everewhere. 88 | 89 | ## How logic is handled 90 | 91 | The order in which you set OR/AND/NAND rules is not important. At the end, they are grouped by type. 92 | 93 | 1) You want your ruleset satisfied : 94 | 95 | ```php 96 | // A,B,C,D,G,Z are rules 97 | $A->andRule($B) 98 | ->orRule($C->andRule($Z)) 99 | ->andRule($D) 100 | ->nandRule($G) 101 | ->isSatisfied(); 102 | 103 | // PHP =>($A && $B && $D && !$G) || ($C && $Z) 104 | // Binary => (A.B.D.!G)+(C.Z) 105 | ``` 106 | 107 | 2) You want your ruleset not satisfied : 108 | 109 | ```php 110 | // A,B,C,D,G,Z are rules 111 | $A->andRule($B) 112 | ->orRule($C->andRule($Z)) 113 | ->andRule($D) 114 | ->nandRule($G) 115 | ->isNotSatisfied() 116 | 117 | // PHP => (!$A || !$B || !$D || $G) && (!$C || !$Z) 118 | // Binary => (!A+!B+!D+G).(!C+!Z) 119 | ``` 120 | 121 | by default, isNotSatisfied() returns !isSatisfied(). But sometimes, you may want to personnalize the doIsNotSatisfied() method in order to optimize workflow (like SQL queries). 122 | 123 | ## Customization 124 | 125 | ### Setting Exception class and message error 126 | 127 | If you have one generic rule (e.g. : ObjectIsEqual), you may need to have different exception thrown when composing complex rules. 128 | Each Rule has a setter for this : 129 | 130 | ```php 131 | $A = new MyRule(); 132 | $A->setException('My\Name\Space\Ruler\Exceptions\MyException', 'my custom error message'); 133 | 134 | $A->isSatisfied(); 135 | 136 | // If rule is not satisfied 137 | // it throws a new My\Name\Space\Ruler\Exceptions\MyException('my custom error message') exception 138 | ``` 139 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cleverage/ruler", 3 | "description": "A business rules engine", 4 | "keywords": ["rules"], 5 | "homepage": "https://github.com/cleverage/Ruler", 6 | "license": "MIT", 7 | "require": { 8 | "php": ">=5.3.0" 9 | }, 10 | "autoload": { 11 | "psr-0": { "CleverAge\\Ruler": "src/" } 12 | }, 13 | "authors": [ 14 | { 15 | "name": "Florian Vilpoix" 16 | }, 17 | { 18 | "name": "Florian Lonqueu-Brochard" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ./tests/CleverAge/Ruler/Test/ 7 | 8 | 9 | 10 | 11 | 12 | ./src/CleverAge/Ruler/ 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/CleverAge/Ruler/Exception/Exception.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Florian Vilpoix 11 | * @since 2012-10-17 12 | */ 13 | class Exception extends \Exception 14 | { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/CleverAge/Ruler/Exception/NotSatisfiedException.php: -------------------------------------------------------------------------------- 1 | object1 = $object1; 33 | $this->object2 = $object2; 34 | $this->identifierMethod = $identifierMethod; 35 | } 36 | 37 | /** 38 | * {@inheritdoc} 39 | */ 40 | public function doIsSatisfied() 41 | { 42 | $class = is_object($this->object1) ? get_class($this->object1) : false; 43 | 44 | return $class 45 | && (($this->object1 === $this->object2) 46 | || (($this->object2 instanceof $class) 47 | && ($this->object1->{$this->identifierMethod}() 48 | == $this->object2->{$this->identifierMethod}()) 49 | )); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/CleverAge/Ruler/RuleAbstract.php: -------------------------------------------------------------------------------- 1 | 12 | * @author Florian Vilpoix 13 | * @since 2012-10-17 14 | */ 15 | abstract class RuleAbstract implements RuleInterface 16 | { 17 | /** 18 | * @var string Full qualified class name for the exception to throw when the rule must be satisfied but is not. 19 | * Must inherit from CleverAge\Ruler\Exception\Exception 20 | */ 21 | protected $_failure_exception_class = 'CleverAge\Ruler\Exception\NotSatisfiedException'; 22 | 23 | /** 24 | * @var string String to put into the exception thrown when rule is not satisfied when it should. 25 | * Should be a generic label, then use your translation system to replace it 26 | * in your application. 27 | */ 28 | protected $_failure_message; 29 | 30 | /** 31 | * @var string Full qualified class name for the exception to throw when the rule must not be satisfied but is. 32 | */ 33 | protected $_not_failure_exception_class = 'CleverAge\Ruler\Exception\NotSatisfiedException'; 34 | 35 | /** 36 | * @var string String to put into the exception thrown when rule is satisfied when it should not. 37 | * Should be a generic label, then use your translation system to replace it 38 | * in your application. 39 | */ 40 | protected $_not_failure_message; 41 | 42 | /** 43 | * @var array Collection of all OR rules 44 | */ 45 | protected $_or_children = array(); 46 | 47 | /** 48 | * @var array Collection of all AND rules 49 | */ 50 | protected $_and_children = array(); 51 | 52 | /** 53 | * @var array Collection of all NAND rules 54 | */ 55 | protected $_nand_children = array(); 56 | 57 | /** 58 | * Executes the current rule and check that it's satisfied 59 | * 60 | * @return boolean true when satisfied, false otherwise 61 | */ 62 | abstract protected function doIsSatisfied(); 63 | 64 | /** 65 | * Executes the current rule and check that it's not satisfied 66 | * 67 | * @return boolean true when not satisfied, false otherwise 68 | */ 69 | protected function doIsNotSatisfied() 70 | { 71 | return !$this->doIsSatisfied(); 72 | } 73 | 74 | /** 75 | * {@inheritdoc} 76 | */ 77 | public function isSatisfied() 78 | { 79 | $exception_to_throw = null; 80 | 81 | // first, check that current rule and all AND are satisfied, and NAND not 82 | // satisfied. 83 | try { 84 | if (!$this->doIsSatisfied()) { 85 | $this->_throwException(); 86 | } 87 | 88 | foreach ($this->_and_children as $child) { 89 | $child->isSatisfied(); 90 | } 91 | 92 | foreach ($this->_nand_children as $child) { 93 | $child->isNotSatisfied(); 94 | } 95 | } catch (RulerException $e) { 96 | if (is_null($exception_to_throw)) { 97 | $exception_to_throw = $e; 98 | } 99 | } 100 | 101 | // if satisfied, then rule is a success 102 | if (is_null($exception_to_throw)) { 103 | return true; 104 | } 105 | 106 | // if one rule failed before, then check all OR rules. At least one must 107 | // satisfied in order to validate everything. 108 | foreach($this->_or_children as $child) { 109 | try { 110 | $child->isSatisfied(); 111 | return true; 112 | } catch (RulerException $e) { 113 | if (is_null($exception_to_throw)) { 114 | $exception_to_throw = $e; 115 | } 116 | } 117 | } 118 | 119 | // If we are here, no rules group has been satisfied, so throws first 120 | // error found. 121 | throw $exception_to_throw; 122 | } 123 | 124 | /** 125 | * {@inheritdoc} 126 | */ 127 | public function isNotSatisfied() 128 | { 129 | $exception_to_throw = null; 130 | 131 | // first, check that at least one rule bewteen current and AND is not 132 | // satisfied or that one NAND is satisfied 133 | try { 134 | if (!$this->doIsNotSatisfied()) { 135 | $this->_throwNotException(); 136 | } 137 | } catch (RulerException $e) { 138 | if (is_null($exception_to_throw)) { 139 | $exception_to_throw = $e; 140 | } 141 | } 142 | 143 | if (!is_null($exception_to_throw)) { 144 | foreach ($this->_and_children as $child) { 145 | try { 146 | $child->isNotSatisfied(); 147 | } catch (RulerException $e) { 148 | if (is_null($exception_to_throw)) { 149 | $exception_to_throw = $e; 150 | } 151 | } 152 | } 153 | } 154 | 155 | if (!is_null($exception_to_throw)) { 156 | foreach ($this->_nand_children as $child) { 157 | try { 158 | $child->isSatisfied(); 159 | } catch (RulerException $e) { 160 | if (is_null($exception_to_throw)) { 161 | $exception_to_throw = $e; 162 | } 163 | } 164 | } 165 | } 166 | 167 | // if no rule satisfied, then rule is failure 168 | if (!is_null($exception_to_throw)) { 169 | throw $exception_to_throw; 170 | } 171 | 172 | // All OR rules must not satisfied 173 | foreach($this->_or_children as $child) { 174 | $child->isNotSatisfied(); 175 | } 176 | 177 | return true; 178 | } 179 | 180 | /** 181 | * {@inheritdoc} 182 | */ 183 | public function andRule(RuleInterface $rule) 184 | { 185 | $this->_and_children[] = $rule; 186 | return $this; 187 | } 188 | 189 | /** 190 | * {@inheritdoc} 191 | */ 192 | public function orRule(RuleInterface $rule) 193 | { 194 | $this->_or_children[] = $rule; 195 | return $this; 196 | } 197 | 198 | /** 199 | * {@inheritdoc} 200 | */ 201 | public function nandRule(RuleInterface $rule) 202 | { 203 | $this->_nand_children[] = $rule; 204 | return $this; 205 | } 206 | 207 | /** 208 | * @throws CleverAge\Ruler\Exception\Exception 209 | */ 210 | protected function _throwException() 211 | { 212 | $class = $this->_failure_exception_class; 213 | throw new $class($this->_failure_message); 214 | } 215 | 216 | /** 217 | * @throws CleverAge\Ruler\Exception\Exception 218 | */ 219 | protected function _throwNotException() 220 | { 221 | $class = $this->_not_failure_exception_class; 222 | throw new $class($this->_not_failure_message); 223 | } 224 | 225 | /** 226 | * Override the default class used to generate error. 227 | * Use this if you want to use the same Rule but to generate differents 228 | * errors. 229 | * 230 | * @param string $exceptionClass The Full qualified name of the classe. Must inherit from CleverAge\Ruler\Exception\Exception 231 | * @param string $msg The message returned by the exception 232 | * 233 | * @return \CleverAge\Ruler\RuleInterface 234 | */ 235 | public function setException($exceptionClass, $msg = null) 236 | { 237 | $this->_failure_exception_class = $exceptionClass; 238 | $this->_failure_message = $msg; 239 | 240 | return $this; 241 | } 242 | 243 | /** 244 | * @see self::setException() 245 | * 246 | * @param string $exceptionClass 247 | * @param string $msg 248 | * 249 | * @return \CleverAge\Ruler\RuleInterface 250 | */ 251 | public function setNotException($exceptionClass, $msg = null) 252 | { 253 | $this->_not_failure_exception_class = $exceptionClass; 254 | $this->_not_failure_message = $msg; 255 | 256 | return $this; 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /src/CleverAge/Ruler/RuleInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Florian Vilpoix 11 | * @since 2012-10-17 12 | */ 13 | interface RuleInterface 14 | { 15 | /** 16 | * Executes the current rule, and its and|or associated rules. 17 | * 18 | * A->and(B) 19 | * ->or(C->and(Z)) 20 | * ->and(D) 21 | * ->nand(G) 22 | * ->isSatisfied() 23 | * 24 | * => (A.B.D.!G)+(C.Z) 25 | * 26 | * @return boolean true when satisfied, throws exception otherwise. 27 | * @throws \CleverAge\Ruler\Exception\Exception 28 | */ 29 | public function isSatisfied(); 30 | 31 | /** 32 | * Executes the current rule, and its and|or associated rules. Check that 33 | * the rule fail. 34 | * 35 | * A->and(B) 36 | * ->or(C->and(Z)) 37 | * ->and(D) 38 | * ->nand(G) 39 | * ->isNotSatisfied() 40 | * 41 | * => (!A+!B+!D+G).(!C+!Z) 42 | * 43 | * @return boolean true if rule failed, throws exception otherwise 44 | * @throws \CleverAge\Ruler\Exception\Exception 45 | */ 46 | public function isNotSatisfied(); 47 | 48 | /** 49 | * Add a sub-rule to current. Both current and new rule must be satisfied 50 | * 51 | * @param \CleverAge\Ruler\RuleInterface $rule 52 | * @return \CleverAge\Ruler\RuleInterface 53 | */ 54 | public function andRule(RuleInterface $rule); 55 | 56 | /** 57 | * Add a sub-rule to current. 58 | * (Current rule and AND rule) or (new OR rule) must satisfied. 59 | * 60 | * @param \CleverAge\Ruler\RuleInterface $rule 61 | * @return \CleverAge\Ruler\RuleInterface 62 | */ 63 | public function orRule(RuleInterface $rule); 64 | 65 | /** 66 | * Add a sub-rule to current. 67 | * rule must not satisfied to have current rule satisfied. 68 | * 69 | * @param \CleverAge\Ruler\RuleInterface $rule 70 | * @return \CleverAge\Ruler\RuleInterface 71 | */ 72 | public function nandRule(RuleInterface $rule); 73 | } 74 | -------------------------------------------------------------------------------- /tests/CleverAge/Ruler/Test/Fixtures/BarObject.php: -------------------------------------------------------------------------------- 1 | id = $id; 12 | } 13 | 14 | public function getId() 15 | { 16 | return $this->id; 17 | } 18 | } -------------------------------------------------------------------------------- /tests/CleverAge/Ruler/Test/Fixtures/Exception/Custom2Exception.php: -------------------------------------------------------------------------------- 1 | id = $id; 12 | } 13 | 14 | public function getId() 15 | { 16 | return $this->id; 17 | } 18 | 19 | public function setId($id) 20 | { 21 | $this->id = $id; 22 | 23 | return $this; 24 | } 25 | } -------------------------------------------------------------------------------- /tests/CleverAge/Ruler/Test/Fixtures/Rule/FalsyRule.php: -------------------------------------------------------------------------------- 1 | assertTrue($rule->isSatisfied()); 14 | 15 | $this->setExpectedException( 16 | 'CleverAge\Ruler\Test\Fixtures\Exception\CustomException', 17 | 'Hello Pony !' 18 | ); 19 | 20 | $rule = new Example\FalsyRule(); 21 | $rule->isSatisfied(); 22 | } 23 | 24 | public function testIsNotSatisfied() 25 | { 26 | $rule = new Example\FalsyRule(); 27 | $this->assertTrue($rule->isNotSatisfied()); 28 | 29 | $this->setExpectedException( 30 | 'CleverAge\Ruler\Test\Fixtures\Exception\Custom2Exception', 31 | 'Bye Pony !' 32 | ); 33 | 34 | $rule = new Example\TruelyRule(); 35 | $rule->isNotSatisfied(); 36 | } 37 | 38 | public function testCombination1() 39 | { 40 | // 1 . 1 . 1 41 | $rule = new Example\TruelyRule(); 42 | $rule 43 | ->andRule(new Example\TruelyRule()) 44 | ->andRule(new Example\TruelyRule()); 45 | $this->assertTrue($rule->isSatisfied()); 46 | 47 | // 0 . 1 + 1 48 | $rule2 = new Example\FalsyRule(); 49 | $rule2 50 | ->orRule(new Example\TruelyRule()) 51 | ->andRule(new Example\TruelyRule()); 52 | $this->assertTrue($rule2->isSatisfied()); 53 | 54 | // 1 . 1 + 0 55 | $rule3 = new Example\TruelyRule(); 56 | $rule3 57 | ->orRule(new Example\FalsyRule()) 58 | ->andRule(new Example\TruelyRule()); 59 | $this->assertTrue($rule3->isSatisfied()); 60 | 61 | // 0 . 0 + 0 + 1 62 | $rule4 = new Example\FalsyRule(); 63 | $rule4 64 | ->orRule(new Example\FalsyRule()) 65 | ->orRule(new Example\TruelyRule()) 66 | ->andRule(new Example\FalsyRule()); 67 | $this->assertTrue($rule4->isSatisfied()); 68 | 69 | // 1 . !0 + 0 70 | $rule5 = new Example\TruelyRule(); 71 | $rule5 72 | ->orRule(new Example\FalsyRule()) 73 | ->nandRule(new Example\FalsyRule()); 74 | $this->assertTrue($rule5->isSatisfied()); 75 | 76 | $this->setExpectedException('CleverAge\Ruler\Test\Fixtures\Exception\CustomException'); 77 | 78 | // 1 . 1 . 0 79 | $rule6 = new Example\TruelyRule(); 80 | $rule6 81 | ->andRule(new Example\TruelyRule()) 82 | ->andRule(new Example\FalsyRule()); 83 | $rule6->isSatisfied(); 84 | } 85 | 86 | /** 87 | * @expectedException CleverAge\Ruler\Test\Fixtures\Exception\CustomException 88 | */ 89 | public function testCombinationFail1() 90 | { 91 | // 1 . 0 + 0 + 0 92 | $rule = new Example\TruelyRule(); 93 | $rule 94 | ->andRule(new Example\FalsyRule()) 95 | ->orRule(new Example\FalsyRule()); 96 | $rule->isSatisfied(); 97 | } 98 | 99 | /** 100 | * @expectedException CleverAge\Ruler\Test\Fixtures\Exception\CustomException 101 | */ 102 | public function testCombinationFail2() 103 | { 104 | // 1 . 0 + 0 . 1 + 0 105 | $subrule = new Example\TruelyRule(); 106 | $subrule->andRule(new Example\FalsyRule()); 107 | 108 | $rule = new Example\TruelyRule(); 109 | $rule 110 | ->andRule(new Example\FalsyRule()) 111 | ->orRule(new Example\FalsyRule()) 112 | ->orRule($subrule); 113 | 114 | $rule->isSatisfied(); 115 | } 116 | 117 | /** 118 | * @expectedException CleverAge\Ruler\Test\Fixtures\Exception\CustomException 119 | */ 120 | public function testCombinationFail3() 121 | { 122 | // 0 . 1 + 1 . !1 123 | $subrule = new Example\TruelyRule(); 124 | $subrule->nandRule(new Example\TruelyRule()); 125 | 126 | $rule = new Example\FalsyRule(); 127 | $rule 128 | ->andRule(new Example\TruelyRule()) 129 | ->orRule($subrule); 130 | 131 | $rule->isSatisfied(); 132 | } 133 | 134 | /** 135 | * @expectedException CleverAge\Ruler\Test\Fixtures\Exception\Custom2Exception 136 | */ 137 | public function testOverrideException() 138 | { 139 | $rule = new Example\FalsyRule(); 140 | $rule->setException('CleverAge\Ruler\Test\Fixtures\Exception\Custom2Exception'); 141 | $rule->isSatisfied(); 142 | } 143 | } -------------------------------------------------------------------------------- /tests/CleverAge/Ruler/Test/Rule/ObjectIsEqualTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($satisfyingRule->isSatisfied()); 22 | } 23 | 24 | public function satifyingRules() 25 | { 26 | $foo = new Foo(); 27 | 28 | return array( 29 | array(new ObjectIsEqual($foo, $foo)), 30 | array(new ObjectIsEqual($foo, $foo->setId(1))), 31 | array(new ObjectIsEqual(new Foo(2), new Foo(2))), 32 | array(new ObjectIsEqual(new Foo(2), new FooChild(2))), 33 | ); 34 | } 35 | 36 | /** 37 | * @dataProvider unsatifyingRules 38 | * @test 39 | */ 40 | public function it_should_not_be_satisfied($unsatisfyingRule) 41 | { 42 | $this->setExpectedException('CleverAge\Ruler\Exception\NotSatisfiedException'); 43 | 44 | $unsatisfyingRule->isSatisfied(); 45 | } 46 | 47 | public function unsatifyingRules() 48 | { 49 | return array( 50 | array(new ObjectIsEqual(new Foo(), new Bar())), 51 | array(new ObjectIsEqual(new Foo(2), new Bar(2))), 52 | array(new ObjectIsEqual(1, new Bar())), 53 | array(new ObjectIsEqual(new Foo(), 'pony')) 54 | ); 55 | } 56 | 57 | /** 58 | * @test 59 | */ 60 | public function it_should_be_instantiable() 61 | { 62 | $this->assertInstanceOf( 63 | 'CleverAge\Ruler\Rule\ObjectIsEqual', 64 | new ObjectIsEqual(new Foo(), new Bar(), 'getName') 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | add('CleverAge\Ruler\Test', __DIR__); 16 | $loader->register(); --------------------------------------------------------------------------------