Skip to content

Commit

Permalink
Annotation out of quarantine, and key methods tested.
Browse files Browse the repository at this point in the history
  • Loading branch information
KrisJordan committed Aug 30, 2009
1 parent 8139d2d commit 08b8530
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 11 deletions.
@@ -1,9 +1,6 @@
<?php
namespace recess\lang;

use recess\lang\exceptions\InvalidAnnotationValueException;
use recess\lang\exceptions\UnknownAnnotationException;

/**
* Base class for class, method, and property annotations.
*
Expand All @@ -27,6 +24,8 @@ static public function load() {
protected $errors = array();
protected $values = array();

public $parameters = array();

const FOR_CLASS = 1;
const FOR_METHOD = 2;
const FOR_PROPERTY = 4;
Expand Down Expand Up @@ -160,11 +159,6 @@ protected function exactParameterCount($count) {

/* End validation helper methods */


function init($parameters) {
$this->parameters = array_change_key_case($parameters, CASE_LOWER);
}

function isAValue($value) {
return in_array($value, $this->values);
}
Expand Down Expand Up @@ -250,6 +244,13 @@ function expandAnnotation($class, $reflection, $descriptor) {
$this->expand($class, $reflection, $descriptor);
}

/**
* Initialize the parameters of the annotation by lowering key case
* @param $parameters
*/
function init($parameters) {
$this->parameters = array_change_key_case($parameters, CASE_LOWER);
}

/**
* Given a docstring, returns an array of Recess Annotations.
Expand Down Expand Up @@ -285,16 +286,15 @@ static function parse($docstring) {

@eval('$array = ' . $value);
if(!isset($array)) {
throw new InvalidAnnotationValueException('There is an unparseable annotation value: "!' . $annotation . ': ' . $values[$key] . '"',0,0,'',0,array());
throw new \Exception('There is an unparseable annotation value: "!' . $annotation . ': ' . $values[$key] . '"');
}

$annotationClass = $annotation . 'Annotation';
if(isset(self::$registeredAnnotations[$annotationClass])) {
$annotation = new self::$registeredAnnotations[$annotationClass];
$annotation->init($array);
} else {
print_r(self::$registeredAnnotations);
throw new UnknownAnnotationException('Unknown annotation: "' . $annotation . '"',0,0,'',0,get_defined_vars());
throw new \Exception('Unknown annotation: "' . $annotation . '" It must be loaded with: "' . $annotation .'"::load()');
}

$returns[] = $annotation;
Expand Down
83 changes: 83 additions & 0 deletions recess/test/recess/lang/AnnotationTest.php
@@ -0,0 +1,83 @@
<?php
use made\up\space;
use recess\lang\Annotation;

require_once 'DummyAnnotation.class.php';
use made\up\space\DummyAnnotation;

class AnnotationTest extends PHPUnit_Framework_TestCase {

function testSimpleParse() {
DummyAnnotation::load();
$docstring = "/** !Dummy */";
$annotations = Annotation::parse($docstring);
$this->assertEquals(1,count($annotations));
$this->assertEquals(array(new DummyAnnotation), $annotations);
}

function testParamsParse() {
DummyAnnotation::load();
$docstring = "/** !Dummy a, b, c */";
$annotations = Annotation::parse($docstring);
$this->assertEquals(1, count($annotations));
$expected = new DummyAnnotation;
$expected->parameters = array('a','b','c');
$this->assertEquals(array($expected), $annotations);
}

function testKeyValParamsParse() {
DummyAnnotation::load();
$docstring = "/** !Dummy a: b, c: d */";
$annotations = Annotation::parse($docstring);
$this->assertEquals(1, count($annotations));
$expected = new DummyAnnotation;
$expected->parameters = array('a'=>'b','c'=>'d');
$this->assertEquals(array($expected), $annotations);
}

function testSubArrayParse() {
DummyAnnotation::load();
$docstring = "/** !Dummy a: (b: c, d, e, f: g), h */";
$annotations = Annotation::parse($docstring);
$this->assertEquals(1, count($annotations));
$expected = new DummyAnnotation;
$expected->parameters = array('a'=>array('b'=>'c','d','e','f'=>'g'),'h');
$this->assertEquals(array($expected), $annotations);
}

function testMultiParse() {
DummyAnnotation::load();
$docstring = "/**
* !Dummy a, b, c
* !Dummy d, e, f
*/";
$annotations = Annotation::parse($docstring);
$this->assertEquals(2, count($annotations));
$expectedA = new DummyAnnotation;
$expectedA->parameters = array('a','b','c');
$expectedB = new DummyAnnotation;
$expectedB->parameters = array('d','e','f');
$this->assertEquals(array($expectedA,$expectedB), $annotations);
}

function testUnknownAnnotation() {
$docstring = "/** !Foo */";
try {
$annotations = Annotation::parse($docstring);
$this->assertTrue(false);
} catch (Exception $e) {
$this->assertTrue(true);
}
}

function testInvalidAnnotation() {
$docstring = "/** !Foo 'bar */";
try {
$annotations = Annotation::parse($docstring);
$this->assertTrue(false);
} catch (Exception $e) {
$this->assertTrue(true);
}
}

}
58 changes: 58 additions & 0 deletions recess/test/recess/lang/DummyAnnotation.class.php
@@ -0,0 +1,58 @@
<?php
namespace made\up\space;
use recess\lang\Annotation;
class DummyAnnotation extends Annotation {
/* Begin abstract methods */

/**
* Returns a string representation of the intended usage of an annotation.
*
* @return string
*/
public function usage() {
return "";
}

/**
* Returns an integer representation of the type(s) of PHP language constructs
* the annotation is applicable to. Use the Annotation::FOR_* consts to return
* the desired result.
*
* Examples:
* // Only valid on classes
* function isFor() { return Annotation::FOR_CLASS; }
*
* // Valid on methods or properties
* function isFor() { return Annotation::FOR_METHOD | Annotation::FOR_PROPERTY; }
*
* @return integer
*/
public function isFor() {
return Annotation::FOR_CLASS;
}

/**
* Validate is called just before expansion. Because there may be multiple
* constraints of an annotation the implementation of validate should append
* any error messages to the protected $errors property. Commonly used validations
* helper methods are provided as protected methods on the Annotation class.
*
* @param $class The classname the annotation is on.
*/
protected function validate($class) {
return true;
}

/**
* The expansion step of an annotation gives it an opportunity to manipulate
* a class' descriptor by introducing additional metadata, attach methods, and
* wrap methods.
*
* @param string $class Classname the annotation is applied to.
* @param mixed $reflection The Reflection(Class|Method|Property) object the annotation is applied to.
* @param ClassDescriptor $descriptor The ClassDescriptor being manipulated.
*/
protected function expand($class, $reflection, $descriptor) {

}
}

0 comments on commit 08b8530

Please sign in to comment.