convert to autocracy
authorMichael Wallner <mike@php.net>
Fri, 13 Dec 2013 09:42:31 +0000 (10:42 +0100)
committerMichael Wallner <mike@php.net>
Fri, 13 Dec 2013 09:42:31 +0000 (10:42 +0100)
18 files changed:
AUTHORS [new file with mode: 0644]
LICENSE [new file with mode: 0644]
mdref/Action.php [new file with mode: 0644]
mdref/ExceptionHandler.php [new file with mode: 0644]
mdref/Finder.php [new file with mode: 0644]
mdref/Markdown.php [new file with mode: 0644]
mdref/Path.php [new file with mode: 0644]
mdref/RefEntry.php [new file with mode: 0644]
mdref/RefListing.php
mdref/controllers/AppController.php [deleted file]
mdref/controllers/IndexController.php [deleted file]
mdref/controllers/RefController.php [deleted file]
mdref/views/index.phtml [deleted file]
mdref/views/layout.phtml [deleted file]
public/.htaccess [new file with mode: 0644]
public/index.css
public/index.php
views/layout.phtml [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..67bbd91
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Michael Wallner <mike@php.net>
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..816ff40
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2013, Michael Wallner <mike@php.net>.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright 
+      notice, this list of conditions and the following disclaimer in the 
+      documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/mdref/Action.php b/mdref/Action.php
new file mode 100644 (file)
index 0000000..223e532
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+
+namespace mdref;
+
+use http\Controller\Observer;
+
+class Action extends Observer
+{
+       function update(\SplSubject $ctl) {
+               /* @var \http\Controller $ctl */
+               try {
+                       $payload = $ctl->getPayload();
+                       $request = $ctl->getRequest();
+
+                       $finder = new Finder($this->baseUrl, REFS);
+                       $url = new \http\Url($request->getRequestUrl());
+                       if (!$path = $finder->find($url)) {
+                               $path = new Path;
+                       }
+
+                       $payload->baseUrl = $this->baseUrl;
+                       $payload->requestUrl = $url;
+
+                       $payload->listing = new RefListing($path, 
+                                       $finder->glob($path, "/[_a-zA-Z]*.md"));
+
+                       if ($path->isFile()) {
+                               $payload->markdown = new Markdown($path);
+                               $payload->sublisting = new RefListing($path, 
+                                               $finder->glob($path, "/[_a-z]*.md"));
+                       } else if ($path($url)->isFile("")) {
+                               $payload->markdown = $path->toHtml();
+                       } else if (strcmp($url, $this->baseUrl)) {
+                               throw new \http\Controller\Exception(404, "Could not find '$url'");
+                       }
+               } catch (\Exception $e) {
+                       $payload->baseUrl = $this->baseUrl;
+                       $ctl->getPayload()->exception = $e;
+               }
+       }
+}
diff --git a/mdref/ExceptionHandler.php b/mdref/ExceptionHandler.php
new file mode 100644 (file)
index 0000000..d184ea0
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+
+namespace mdref;
+
+use http\Env as HTTP;
+
+class ExceptionHandler
+{
+       function __construct() {
+               set_exception_handler($this);
+               set_error_handler($this);
+       }
+       
+       function __invoke($e, $msg = null) {
+               if ($e instanceof \Exception) {
+                       try {
+                               echo static::html($e);
+                       } catch (\Exception $ignore) {
+                               HTTP::sendStatusCode(500);
+                       }
+               } else {
+                       throw new \Exception($msg, $e);
+               }
+               return true;
+       }
+       
+       static function html(\Exception $e, array $title_tag = ["h1"], array $message_tag = ["p"], array $trace_tag = ["pre", "style='font-size:smaller'"]) {
+               if ($e instanceof \http\Controller\Exception) {
+                       $code = $e->getCode() ?: 500;
+                       foreach ($e->getHeaders() as $key => $val) {
+                               HTTP::sendResponseHeader($key, $val);
+                       }
+               } else {
+                       $code = 500;
+               }
+               HTTP::setResponseCode($code);
+               $name = HTTP::getResponseStatusForCode($code);
+               $html = sprintf("<%s>%s</%s>\n<%s>%s</%s>\n",
+                               implode(" ", $title_tag), $name, $title_tag[0],
+                               implode(" ", $message_tag), $e->getMessage(), $message_tag[0]);
+               if ($trace_tag) {
+                       $html .= sprintf("<%s>%s</%s>\n",
+                                       implode(" ", $trace_tag), $e->getTraceAsString(), $trace_tag[0]);
+               }
+               return $html;
+       }
+}
\ No newline at end of file
diff --git a/mdref/Finder.php b/mdref/Finder.php
new file mode 100644 (file)
index 0000000..9d1c64c
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+namespace mdref;
+
+class Finder
+{
+       /**
+        * Base URL
+        * @var \http\Controller\Url 
+        */
+       protected $baseUrl;
+       
+       /**
+        * Reference paths
+        * @var array
+        */
+       protected $refs = array();
+       
+       /**
+        * @param \http\Controller\Url $baseUrl
+        * @param mixed $paths array or string of paths with markdown references
+        */
+       function __construct(\http\Controller\Url $baseUrl, $paths = ".") {
+               if (!is_array($paths)) {
+                       $paths = explode(PATH_SEPARATOR, $paths);
+               }
+               $this->refs = $paths;
+               $this->baseUrl = $baseUrl;
+       }
+       
+       /**
+        * @param \http\Url $requestUrl
+        * @return Path
+        */
+       function find(\http\Url $requestUrl) {
+               $file = implode(DIRECTORY_SEPARATOR, 
+                               $this->baseUrl->params($requestUrl));
+               
+               foreach ($this->refs as $base) {
+                       $path = new Path($base, $file);
+                       if ($path->isFile()) {
+                               return $path;
+                       }
+               }
+       }
+
+       function glob(Path $path, $pattern, $flags = GLOB_BRACE) {
+               if (strlen($path->getBaseDir())) {
+                       return glob($path->getFullPath($pattern), $flags);
+               }
+               $glob = array();
+               foreach ($this->refs as $ref) {
+                       $glob = array_merge($glob, array_map(function ($fn) use ($ref) {
+                               return substr($fn, strlen($ref));
+                       }, glob($ref . $pattern, $flags)));
+               }
+               return $glob;
+       }
+}
diff --git a/mdref/Markdown.php b/mdref/Markdown.php
new file mode 100644 (file)
index 0000000..6d761c2
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+namespace mdref;
+
+class Markdown
+{
+       /**
+        * @var \mdref\Path
+        */
+       protected $path;
+       
+       /**
+        * @param \mdref\Path $path
+        */
+       function __construct(Path $path) {
+               $this->path = $path;
+       }
+       
+       /**
+        * @return string
+        */
+       function __toString() {
+               try {
+                       $r = fopen($this->path->getFullPath(".md"), "r");
+                       $md = \MarkdownDocument::createFromStream($r);
+                       $md->compile(\MarkdownDocument::AUTOLINK | \MarkdownDocument::TOC);
+                       $html = $md->getHtml();
+                       fclose($r);
+               } catch (\Exception $e) {
+                       $html = ExceptionHandler::html($e);
+               }
+               return $html;
+       }
+}
diff --git a/mdref/Path.php b/mdref/Path.php
new file mode 100644 (file)
index 0000000..b9212d2
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+
+namespace mdref;
+
+class Path
+{
+       /**
+        * Computed path
+        * @var string
+        */
+       protected $path = "";
+       
+       /**
+        * The base directory where path is located
+        * @var string
+        */
+       protected $baseDir = "";
+       
+       function __construct($baseDir = "", $path = "") {
+               $this->baseDir = $baseDir;
+               $this->path = $path;
+       }
+       
+       function __invoke($path) {
+               $that = clone $this;
+               $that->path = $path;
+               return $that;
+       }
+       
+       function __toString() {
+               return $this->getFullPath();
+       }
+
+       function getBaseDir() {
+               return $this->baseDir;
+       }
+       
+       function getPathName() {
+               return $this->path;
+       }
+       
+       function getFullPath($ext = "") {
+               return $this->baseDir . DIRECTORY_SEPARATOR . $this->path . $ext;
+       }
+       
+       function getSubPath($path) {
+               return trim(substr($path, strlen($this->baseDir)), DIRECTORY_SEPARATOR);
+       }
+       
+       function isFile($ext = ".md") {
+               return is_file($this->getFullPath($ext));
+       }
+       
+       function toHtml() {
+               if ($this->isFile()) {
+                       return htmlspecialchars(file_get_contents($this->getFullPath()));
+               } elseif ($this->isFile("")) {
+                       return htmlspecialchars(file_get_contents($this->getFullPath("")));
+               }
+       }
+}
\ No newline at end of file
diff --git a/mdref/RefEntry.php b/mdref/RefEntry.php
new file mode 100644 (file)
index 0000000..f88b43f
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+
+namespace mdref;
+
+class RefEntry
+{
+       /**
+        * @var \mdref\Path
+        */
+       protected $path;
+       
+       /**
+        * @var string
+        */
+       protected $entry;
+       
+       /**
+        * @var resource
+        */
+       protected $file;
+       
+       function __construct(Path $path, $entry = null) {
+               $this->path = $path;
+               $this->entry = $entry ?: $path->getPathName();
+       }
+       
+       function __destruct() {
+               if (is_resource($this->file)) {
+                       fclose($this->file);
+               }
+       }
+       
+       function formatUrl() {
+               return htmlspecialchars($this->entry);
+               return implode("/", explode(DIRECTORY_SEPARATOR, trim(substr(
+                               $this->entry, strlen($this->path->getBaseDir())), 
+                               DIRECTORY_SEPARATOR)));
+       }
+       
+       protected function joinLink(array $parts) {
+               $link = "";
+               $upper = ctype_upper($parts[0][0]);;
+               for ($i = 0; $i < count($parts); ++$i) {
+                       if (!strlen($parts[$i]) || $parts[$i] === ".") {
+                               continue;
+                       }
+                       if (strlen($link)) {
+                               if ($upper && !ctype_upper($parts[$i][0])) {
+                                       $link .= "::";
+                               } else {
+                                       $link .= "\\";
+                               }
+                       }
+                       $link .= $parts[$i];
+                       $upper = ctype_upper($parts[$i][0]);
+               }
+               return $link;
+       }
+
+       function formatLink($basename = false) {
+               $link = "";
+               if (strlen($entry = trim($this->entry, DIRECTORY_SEPARATOR))) {
+                       $parts = explode(DIRECTORY_SEPARATOR, $entry);
+                       $link = $basename ? end($parts) : $this->joinLink($parts);
+               }
+               return htmlspecialchars($link);
+       }
+       
+       protected function openFile() {
+               if (!is_resource($this->file)) {
+                       $path = $this->path;
+                       $file = $path($this->entry);
+                       if (!$file->isFile()) {
+                               throw new \Exception("Not a file: '$this->entry'");
+                       }
+                       if (!$this->file = fopen($file->getFullPath(".md"), "r")) {
+                               throw new \Exception("Could not open {$this->entry}");
+                       }
+               }
+       }
+       
+       function readTitle() {
+               $this->openFile();
+               fseek($this->file, 1, SEEK_SET);
+               return htmlspecialchars(fgets($this->file));
+       }
+       
+       function readDescription() {
+               $this->openFile();
+               fseek($this->file, 0, SEEK_SET);
+               fgets($this->file);
+               fgets($this->file);
+               return htmlspecialchars(fgets($this->file));
+       }
+}
\ No newline at end of file
index 542a3ffe07bffa25c12bc245e271390455fbac9c..d7180906479721f4066d54a6083b769bbf47ee8a 100644 (file)
@@ -1,8 +1,111 @@
 <?php
 
-class RefListing
+namespace mdref;
+
+class RefListing implements \Countable, \Iterator
 {
-       function __construct($dir) {
-               
+       /**
+        * @var \mdref\Path
+        */
+       protected $path;
+       
+       /**
+        * @var array
+        */
+       protected $entries;
+       
+       /**
+        * @param \mdref\Path $path
+        */
+       function __construct(Path $path, array $files) {
+               $this->path = $path;
+               $this->entries = array_map(function($fn) {
+                       return substr(trim($fn, DIRECTORY_SEPARATOR), 0, -3);
+               }, $files);
+       }
+       
+       /**
+        * Copy constructor
+        * @param mixed $filter callable array filter or fnmatch pattern
+        * @return \mdref\RefListing
+        */
+       function __invoke($filter) {
+               die(__METHOD__);
+               $that = clone $this;
+               $that->entries =  array_filter($that->entries, is_callable($filter) 
+                               ? $filter 
+                               : function($fn) use ($filter) {
+                                       return fnmatch($filter, $fn);
+                               }
+               );
+               return $that;
+       }
+       
+       function __toString() {
+               return __METHOD__;
+               return $this->format(substr($this->path, strlen($this->path->getBaseDir())));
+       }
+       
+       function count() {
+               return count($this->entries);
+       }
+       
+       function rewind() {
+               reset($this->entries);
+       }
+       
+       function valid() {
+               return null !== key($this->entries);
+       }
+       
+       function key() {
+               return $this->path->getSubPath(current($this->entries));
+       }
+       
+       function next() {
+               next($this->entries);
+       }
+       
+       function current() {
+               return new RefEntry($this->path, $this->key());//$this->format($this->key());
+       }
+       
+       function getParent() {
+               switch ($parent = dirname($this->path->getPathName())) {
+                       case ".":
+                       case "":
+                               return null;
+                       default:
+                               return new RefEntry($this->path, $parent);
+               }
+       }
+       
+       function getSelf() {
+               return new RefEntry($this->path);
+       }
+       
+       function format($entry) {
+               return __METHOD__;
+               $ns = "";
+               if (strlen($entry = trim($entry, DIRECTORY_SEPARATOR))) {
+                       $upper = ctype_upper($entry[0]);
+                       $parts = explode(DIRECTORY_SEPARATOR, $entry);
+                       
+                       for ($i = 0; $i < count($parts); ++$i) {
+                               if (!strlen($parts[$i]) || $parts[$i] === ".") {
+                                       continue;
+                               }
+                               if (strlen($ns)) {
+                                       if ($upper && !ctype_upper($parts[$i][0])) {
+                                               $ns .= "::";
+                                       } else {
+                                               $ns .= "\\";
+                                       }
+                               }
+                               $ns .= $parts[$i];
+                               $upper = ctype_upper($parts[$i][0]);
+                       }
+               }
+               return $ns;
        }
 }
\ No newline at end of file
diff --git a/mdref/controllers/AppController.php b/mdref/controllers/AppController.php
deleted file mode 100644 (file)
index cb09d8f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-namespace controllers;
-
-use http\Controller\Action;
-
-abstract class AppController extends Action
-{
-       protected function init() {
-               parent::init();
-               
-               $this->payload->title = "mdref";
-               $this->payload->listing = 123;
-       }
-}
\ No newline at end of file
diff --git a/mdref/controllers/IndexController.php b/mdref/controllers/IndexController.php
deleted file mode 100644 (file)
index 771de9f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-
-namespace controllers;
-
-class IndexController extends AppController
-{
-       function indexAction() {
-       }
-}
diff --git a/mdref/controllers/RefController.php b/mdref/controllers/RefController.php
deleted file mode 100644 (file)
index da55bcd..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-
-namespace controllers;
-
-class RefController extends AppController
-{
-       function indexAction() {
-               
-       }
-}
\ No newline at end of file
diff --git a/mdref/views/index.phtml b/mdref/views/index.phtml
deleted file mode 100644 (file)
index b2d525b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-index
\ No newline at end of file
diff --git a/mdref/views/layout.phtml b/mdref/views/layout.phtml
deleted file mode 100644 (file)
index 69c9727..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<!doctype html>
-<html>
- <head>
-  <meta charset="utf-8">
-  <title><?= $title ?></title>
-  <base href="<?= $baseUrl ?>/">
-  <link rel="stylesheet" href="index.css">
-  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
- </head>
- <body>
-  <div class="sidebar">
-   <?= $listing ?>
-  </div>
-
-  <?= $content ?>
-
-  <div id="disqus_thread"></div>
-
-  <footer>
-   <ul>
-       <li><a href="https://github.com/m6w6/mdref">mdref-v<?php readfile("../VERSION")?></a></li>
-       <li><a href="LICENSE">&copy; <?= implode("-", array_unique([2013,idate("Y")]))?></a></li>
-   </ul>
-  </footer>
-  <script src="index.js"></script>
- </body>
-</html>
diff --git a/public/.htaccess b/public/.htaccess
new file mode 100644 (file)
index 0000000..affb2a0
--- /dev/null
@@ -0,0 +1,6 @@
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} -f [OR]
+RewriteCond %{REQUEST_FILENAME} -d [OR]
+RewriteCond %{REQUEST_FILENAME} -l
+RewriteRule ^ - [L]
+RewriteRule ^ index.php [L]
index a48ac00cbe108890578606ee1001f2ed4bf40cd4..754f96cd50e663503306e7f619adee6890c8bc8e 100644 (file)
@@ -32,6 +32,7 @@ body>ul {
 }
 .sidebar ul {
        margin-left: 1em;
+       margin-top: .5em;
        padding: 0;
        list-style-type: none;
 }
@@ -160,3 +161,11 @@ footer li {
        display: inline-block;
        margin: 0 1em;
 }
+
+footer a {
+       text-decoration: none;
+}
+
+footer a:hover {
+       text-decoration: underline;
+}
\ No newline at end of file
index 649bb0aa4963bea552dfc8edbe937f8fa86a49d1..d4518cd3a26691a5387aea740d173ea90cc09703 100644 (file)
@@ -1,32 +1,25 @@
 <?php
-while (ob_get_level() && ob_end_clean());
+
+define("ROOT", dirname(__DIR__));
+define("REFS", getenv("REFPATH") ?: implode(PATH_SEPARATOR, glob(ROOT."/refs/*")));
 
 $loader = require __DIR__ . "/../vendor/autoload.php";
 /* @var $loader \Composer\Autoload\ClassLoader */
-$loader->add("controllers", __DIR__ . "/../mdref");
+$loader->add("mdref", ROOT);
 
 use http\Controller;
 use http\Controller\Url;
-
-use http\Controller\Observer\Callback;
-use http\Controller\Observer\Params;
-use http\Controller\Observer\Action;
-use http\Controller\Observer\View;
 use http\Controller\Observer\Layout;
 
+use mdref\ExceptionHandler;
+use mdref\Action;
 
-$url = new Url;
+new ExceptionHandler;
 
 $ctl = new Controller;
-$ctl->setDependency("baseUrl", $url);
-
-$ctl->attach(new Params\Action);
-$ctl->attach(new Action(["controllerPrefix" => "controllers\\"]));
-$ctl->attach(new Callback(function(\http\Controller $ctl) use ($url) {
-       $ctl->getPayload()->baseUrl = $url;
-}));
-$ctl->attach(new View(["directory" => __DIR__ . "/../mdref/views"]));
-$ctl->attach(new Layout(["directory" => __DIR__ . "/../mdref/views"]));
-
-$response = $ctl->notify()->getResponse();
-$response->send();
+$ctl->setDependency("baseUrl", new Url)
+       ->attach(new Action)
+       ->attach(new Layout)
+       ->notify()
+       ->getResponse()
+       ->send();
diff --git a/views/layout.phtml b/views/layout.phtml
new file mode 100644 (file)
index 0000000..69c9727
--- /dev/null
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+ <head>
+  <meta charset="utf-8">
+  <title><?= $title ?></title>
+  <base href="<?= $baseUrl ?>/">
+  <link rel="stylesheet" href="index.css">
+  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
+ </head>
+ <body>
+  <div class="sidebar">
+   <?= $listing ?>
+  </div>
+
+  <?= $content ?>
+
+  <div id="disqus_thread"></div>
+
+  <footer>
+   <ul>
+       <li><a href="https://github.com/m6w6/mdref">mdref-v<?php readfile("../VERSION")?></a></li>
+       <li><a href="LICENSE">&copy; <?= implode("-", array_unique([2013,idate("Y")]))?></a></li>
+   </ul>
+  </footer>
+  <script src="index.js"></script>
+ </body>
+</html>