<commit_before><?php
/**
 * Simple Router
 * 
 * This source file is subject to the MIT license that is bundled
 * with this package in the file LICENSE.txt.
 *
 * @category   Spark
 * @package    Spark_Util
 * @author     <NAME> <<EMAIL>>
 * @copyright  Copyright (c) 2010 <NAME>
 * @license    MIT License
 */
namespace Spark;

require_once('Util.php');

autoload('Spark\Router\Scope',     __DIR__ . '/Router/Scope.php');
autoload('Spark\Router\Exception', __DIR__ . '/Router/Exception.php');

require_once('Router/Route.php');
require_once('Router/RestRoute.php');

use Spark\Router\RestRoute, 
    Spark\HttpRequest,
    SplStack;

class Router
{
    protected $routes;
    
    function __construct(Array $options = array())
    {
        $this->routes  = new SplStack;
        $this->setOptions($options);
    }
    
    function setOptions(Array $options)
    {
        Util\Options::setOptions($this, $options);
        return $this;
    }
    
    function route(HttpRequest $request)
    {
        $matched = false;
        
        foreach ($this->routes as $route) {
            $params = $route->match($request);
            
            if (false !== $params) {
                $matched = true;
                break;
            }
        }
        
        if (!$matched) {
            throw new Controller\Exception("No Route matched");
        }
        
        foreach ($params as $param => $value) {
            $request->setMetadata($param, $value);
        }
        return $request->getMetadata("callback");
    }
    
    function scope($scope, $block)
    {
        if (!block_given(func_get_args())) {
            throw new \InvalidArgumentException("Second argument must be "
                . " a lambda expression");
        }
        $block(new Router\Scope($scope, $this));
        return $this;
    }
    
    function addRoute(Router\Route $route)
    {
        $this->routes->push($route);
        return $this;
    }
    
    function resource($resource, $callback, Array $options = array())
    {
        $resource = trim($resource, '/');
        $new      = $resource . '/new';
        $route    = $resource . '/:id';
        $edit     = $route    . '/edit';
        
        $this->get($new,  $callback, array_merge($options, array('action' => 'new')));
        $this->get($edit, $callback, array_merge($options, array('action' => 'edit')));
        
        $this->post($resource, $callback, $options);
        
        $this->get    ($route, $callback, $options);
        $this->put    ($route, $callback, $options);
        $this->delete ($route, $callback, $options);
        
        return $this;
    }
    
    function map($routeSpec, $callback, Array $options = array())
    {
        return $this->addRoute(new RestRoute(null, $routeSpec, $callback, $options));
    }
    <commit_msg>Router now throws "No Route matched" exception now with code 404, fixed Router::resource()<commit_after><?php
/**
 * Simple Router
 * 
 * This source file is subject to the MIT license that is bundled
 * with this package in the file LICENSE.txt.
 *
 * @category   Spark
 * @package    Spark_Util
 * @author     <NAME> <<EMAIL>>
 * @copyright  Copyright (c) 2010 <NAME>
 * @license    MIT License
 */
namespace Spark;

require_once('Util.php');

autoload('Spark\Router\Scope',     __DIR__ . '/Router/Scope.php');
autoload('Spark\Router\Exception', __DIR__ . '/Router/Exception.php');

require_once('Router/Route.php');
require_once('Router/RestRoute.php');

use Spark\Router\RestRoute, 
    Spark\HttpRequest,
    SplStack;

class Router
{
    protected $routes;
    
    function __construct(Array $options = array())
    {
        $this->routes  = new SplStack;
        $this->setOptions($options);
    }
    
    function setOptions(Array $options)
    {
        Util\Options::setOptions($this, $options);
        return $this;
    }
    
    function route(HttpRequest $request)
    {
        $matched = false;
        
        foreach ($this->routes as $route) {
            $params = $route->match($request);
            
            if (false !== $params) {
                $matched = true;
                break;
            }
        }
        
        if (!$matched) {
            throw new Controller\Exception("No Route matched", 404);
        }
        
        foreach ($params as $param => $value) {
            $request->setMetadata($param, $value);
        }
        return $request->getMetadata("callback");
    }
    
    function scope($scope, $block)
    {
        if (!block_given(func_get_args())) {
            throw new \InvalidArgumentException("Second argument must be "
                . " a lambda expression");
        }
        $block(new Router\Scope($scope, $this));
        return $this;
    }
    
    function addRoute(Router\Route $route)
    {
        $this->routes->push($route);
        return $this;
    }
    
    function resource($resource, $callback, Array $options = array())
    {
        $resource = trim($resource, '/');
        $new      = $resource . '/new';
        $route    = $resource . '/:id';
        $edit     = $route    . '/edit';
        
        $this->get($new,  $callback, array_merge($options, array('action' => 'new')));
        $this->get($edit, $callback, array_merge($options, array('action' => 'edit')));
        
        $this->post($resource, $callback, $options);
        
        $this->get($route, $callback, array_merge($options, array("id" => null)));
        $this->put($route, $callback, $options);
        $this->delete($route, $callback, $options);
        
        return $this;
    }
    
    function map($routeSpec, $callback, Array $options = array())
    {
        return $this->addRoute(new RestRoute(null, $routeSpec, $callback, $options));
    }
    
{'fraction_non_alphanumeric': 0.1494890005196605, 'fraction_numerical': 0.002425082279577343, 'mean_word_length': 2.100966702470462, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 48, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3352688', 'n_tokens_mistral': 1700, 'n_tokens_neox': 1673, 'n_words': 382}