Skip to content

Commit

Permalink
Adding ClassLoader with unit tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
KrisJordan committed Aug 17, 2009
1 parent f47f2f6 commit d5b1810
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 0 deletions.
123 changes: 123 additions & 0 deletions recess/recess/core/ClassLoader.class.php
@@ -0,0 +1,123 @@
<?php
namespace recess\core;

require __DIR__.'/Event.class.php';
require __DIR__.'/Candy.class.php';

/**
* ClassLoader is a simple autoloader for including class files. Class files
* end with a '.class.php' extension and classes must share the same name as
* their containing class file. ClassLoader can be used in conjunction with
* the SPL autoloader chain. Its load function can be candied and wrapped
* with wrapLoad(). After successfully loading a class it will trigger the
* onLoad event.
*
* Usage:
* spl_autoload_register(array('recess\core\ClassLoader','load'));
* use recess\core\ClassLoader;
* // Register a call back with the onLoad Event
* ClassLoader::onLoad()->call(function($class) { echo "$class loaded! "; });
* // Wrap the candied loader
* ClassLoader::wrapLoad(
* function($load, $class) {
* echo "Before load $class!";
* $load($class);
* echo "After load $class!";
* }
* );
* // Load a class explicitely
* ClassLoader::load('a\Class');
* // Output: Before load A\Class! A\Class loaded! After load A\Class!
* // Load a class implicitly
* use some\Class;
* $someClass = new Class;
* // Output: Before load some\Class! some\Class loaded! After load some\Class!
*
* @author Kris Jordan <krisjordan@gmail.com>
* @since Recess 5.3
* @copyright RecessFramework.org 2009
* @license MIT
*/
abstract class ClassLoader {

/**
* @var string
*/
public static $extension = '.class.php';

/**
* @var recess\core\Event
*/
private static $onLoad = null;

/**
* @var recess\core\Candy or \Closure
*/
private static $loader = null;

/**
* Returns a reference to the onLoad Event for interested parties
* to register callbacks with.
* @return recess\core\Event
*/
static public function onLoad() {
if(self::$onLoad === null) {
self::$onLoad = new Event();
}
return self::$onLoad;
}

/**
* Load a class by passing a fully qualified classname.
* @param $class string fully qualified classname
* @return bool
*/
static public function load($class) {
if(self::$loader === null) {
$loader = self::loader();
} else {
$loader = self::$loader;
}
return $loader($class);
}

/**
* Load is candied and can be wrapped by passing a wrapper to this method.
* The wrapper should have two parameters: $load and $class. Usage:
*
* ClassLoader::wrapLoad(function($load,$class) { echo "loading $class"; $load($class); });
*
* @param $wrapper
* @return recess\core\Candy
*/
static public function wrapLoad($wrapper) {
if(self::$loader === null) {
self::$loader = new Candy(self::loader());
}
if(!self::$loader instanceof Candy) {
self::$loader = new Candy(self::$loader);
}
return self::$loader->wrap($wrapper);
}

/**
* Returns a closure for loading class files.
*
* @return \Closure
*/
static private function loader() {
if(self::$loader === null) {
$onLoad = self::onLoad();
$extension = self::$extension;
self::$loader = function($class) use (&$onLoad, &$extension) {
if(!class_exists($class)) {
$classFile = str_replace('\\','/',$class).$extension;
include $classFile;
$onLoad($class);
}
return true;
};
}
return self::$loader;
}
}
59 changes: 59 additions & 0 deletions recess/test/recess/core/ClassLoaderTest.php
@@ -0,0 +1,59 @@
<?php
require_once 'PHPUnit/Framework.php';

include_once __DIR__ . '/../../../recess/core/ClassLoader.class.php';
use recess\core\ClassLoader;

class ClassLoaderTest extends PHPUnit_Framework_TestCase {

function testOnLoad() {
$onLoad = ClassLoader::onLoad();
$this->assertType('recess\core\Event',$onLoad);
$onLoad2 = ClassLoader::onLoad();
$this->assertTrue($onLoad === $onLoad2);
$theClass = '';
ClassLoader::onLoad()->call(function($class) use (&$theClass) { $theClass = $class; });
ClassLoader::load('recess\core\Dummy');
$this->assertEquals('recess\core\Dummy',$theClass);
}

function testWrapLoad() {
$loadedCount = 0;
ClassLoader::wrapLoad(
function($load,$class) use (&$loadedCount) {
if($load($class)) {
$loadedCount += 1;
} else {
$loadedCount -= 1;
}
});
ClassLoader::load('ClassLoaderTest');
ClassLoader::load('ClassLoaderTest');
$this->assertEquals(2,$loadedCount);
}

function testLoadDummy() {
set_include_path(__DIR__.'/../../');
ClassLoader::load('recess\core\Dummy');
$dummy = new recess\core\Dummy;
$this->assertType('recess\core\Dummy',$dummy);
$this->assertEquals('hello world',$dummy->helloWorld());
}

function testWrapAfterLoadDummy() {
set_include_path(__DIR__.'/../../');
ClassLoader::load('recess\core\Dummy');
$loadedCount = 0;
ClassLoader::wrapLoad(
function($load,$class) use (&$loadedCount) {
if($load($class)) {
$loadedCount += 1;
} else {
$loadedCount -= 1;
}
});
ClassLoader::load('ClassLoaderTest');
$this->assertEquals(1,$loadedCount);
}

}
6 changes: 6 additions & 0 deletions recess/test/recess/core/Dummy.class.php
@@ -0,0 +1,6 @@
<?php
namespace recess\core;

class Dummy {
function helloWorld() { return 'hello world'; }
}
2 changes: 2 additions & 0 deletions recess/test/recess/core/RecessCoreAllTests.php
@@ -1,5 +1,6 @@
<?php
require_once 'PHPUnit/Framework.php';
require_once 'recess/core/ClassLoaderTest.php';
require_once 'recess/core/CandyTest.php';
require_once 'recess/core/EventTest.php';

Expand All @@ -9,6 +10,7 @@ public static function suite()
{
$suite = new PHPUnit_Framework_TestSuite('recess\core');

$suite->addTestSuite('ClassLoaderTest');
$suite->addTestSuite('EventTest');
$suite->addTestSuite('CandyTest');

Expand Down

0 comments on commit d5b1810

Please sign in to comment.