From 55d5e542cb9b8ed10e49e0ec832bb43ce4076574 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Wed, 4 Mar 2015 09:43:51 -0600 Subject: [PATCH 1/4] begin new config schema --- src/Config/IndexConfig.php | 50 ++++++++++++++++++++++---- tests/BookFixture.php | 12 +++---- tests/Config/ConfigFactoryTest.php | 10 +++--- tests/Config/IndexConfigTest.php | 42 +++++++++++----------- tests/Config/RootConfigTest.php | 30 ++++++++-------- tests/Service/ProcessorBuilderTest.php | 14 ++++---- tests/Service/ProcessorTest.php | 12 +++---- 7 files changed, 103 insertions(+), 67 deletions(-) diff --git a/src/Config/IndexConfig.php b/src/Config/IndexConfig.php index 1a46728..52e17dd 100644 --- a/src/Config/IndexConfig.php +++ b/src/Config/IndexConfig.php @@ -56,23 +56,59 @@ protected function initTitle() protected function initContent() { - $this->content = empty($this->json->content) + $content = empty($this->json->content) ? array() - : (array) $this->json->content; + : $this->json->content; - if (! $this->content) { + if (! $content) { throw new Exception("No content listed in '{$this->file}'."); } - if (isset($this->content['index'])) { - throw new Exception("Disallowed 'index' content in {$this->file}."); + if (! is_array($content)) { + throw new Exception("Content must be an array in '{$this->file}'."); } - foreach ($this->content as $name => $origin) { - $this->content[$name] = $this->fixPath($origin); + foreach ($content as $key => $val) { + $this->initContentItem($val); } } + protected function initContentItem($origin) + { + if (is_object($origin)) { + $spec = (array) $origin; + $name = key($spec); + $origin = current($spec); + return $this->addContent($name, $origin); + } + + $name = basename($origin); + if (substr($name, -13) == 'bookdown.json') { + $name = basename(dirname($name)); + return $this->addContent($name, $origin); + } + + $name = basename($origin); + $pos = strrpos($name, '.'); + if ($pos !== false) { + $name = substr($name, 0, $pos); + } + return $this->addContent($name, $origin); + } + + protected function addContent($name, $origin) + { + if ($name == 'index') { + throw new Exception("Disallowed 'index' content name in {$this->file}."); + } + + if (isset($this->content[$name])) { + throw new Exception("Content name '{$name}' already set in {$this->file}."); + } + + $this->content[$name] = $this->fixPath($origin); + } + protected function fixPath($path) { if (strpos($path, '://') !== false) { diff --git a/tests/BookFixture.php b/tests/BookFixture.php index baeca93..0685314 100644 --- a/tests/BookFixture.php +++ b/tests/BookFixture.php @@ -10,9 +10,9 @@ class BookFixture public $rootConfigFile = '/path/to/bookdown.json'; public $rootConfigData = '{ "title": "Example Book", - "content": { - "chapter": "chapter/bookdown.json" - }, + "content": [ + {"chapter": "chapter/bookdown.json"} + ], "target": "/_site", "templates": { "foo": "/foo.php" @@ -24,9 +24,9 @@ class BookFixture public $indexConfigFile = '/path/to/chapter/bookdown.json'; public $indexConfigData = '{ "title": "Chapter", - "content": { - "section": "section.md" - } + "content": [ + {"section": "section.md"} + ] }'; public $indexConfig; public $indexPage; diff --git a/tests/Config/ConfigFactoryTest.php b/tests/Config/ConfigFactoryTest.php index 5467378..596503a 100644 --- a/tests/Config/ConfigFactoryTest.php +++ b/tests/Config/ConfigFactoryTest.php @@ -11,11 +11,11 @@ class ConfigFactoryTest extends \PHPUnit_Framework_TestCase protected $data = '{ "title": "Example Title", - "content": { - "foo": "foo.md", - "bar": "/bar.md", - "baz": "http://example.com/baz.md" - }, + "content": [ + {"foo": "foo.md"}, + {"bar": "/bar.md"}, + {"baz": "http://example.com/baz.md"} + ], "target": "/_site" }'; diff --git a/tests/Config/IndexConfigTest.php b/tests/Config/IndexConfigTest.php index f5d5f5b..99c9efa 100644 --- a/tests/Config/IndexConfigTest.php +++ b/tests/Config/IndexConfigTest.php @@ -1,48 +1,48 @@ setExpectedException( 'Bookdown\Bookdown\Exception', - "Disallowed 'index' content in /path/to/bookdown.json." + "Disallowed 'index' content name in /path/to/bookdown.json." ); $config = $this->newIndexConfig('/path/to/bookdown.json', $this->jsonContentIndex); } diff --git a/tests/Config/RootConfigTest.php b/tests/Config/RootConfigTest.php index 2746ea8..48b9580 100644 --- a/tests/Config/RootConfigTest.php +++ b/tests/Config/RootConfigTest.php @@ -7,11 +7,11 @@ class RootConfigTest extends \PHPUnit_Framework_TestCase protected $maxRootJson = '{ "title": "Example Title", - "content": { - "foo": "foo.md", - "bar": "/bar.md", - "baz": "http://example.com/baz.md" - }, + "content": [ + {"foo": "foo.md"}, + {"bar": "/bar.md"}, + {"baz": "http://example.com/baz.md"} + ], "target": "my/target", "template": "../templates/master.php", "conversionProcess": "My\\\\Conversion\\\\Builder", @@ -23,21 +23,21 @@ class RootConfigTest extends \PHPUnit_Framework_TestCase protected $minRootJson = '{ "title": "Example Title", - "content": { - "foo": "foo.md", - "bar": "/bar.md", - "baz": "http://example.com/baz.md" - }, + "content": [ + {"foo": "foo.md"}, + {"bar": "/bar.md"}, + {"baz": "http://example.com/baz.md"} + ], "target": "_site" }'; protected $missingTargetJson = '{ "title": "Example Title", - "content": { - "foo": "foo.md", - "bar": "/bar.md", - "baz": "http://example.com/baz.md" - } + "content": [ + {"foo": "foo.md"}, + {"bar": "/bar.md"}, + {"baz": "http://example.com/baz.md"} + ] }'; protected function newRootConfig($file, $data) diff --git a/tests/Service/ProcessorBuilderTest.php b/tests/Service/ProcessorBuilderTest.php index 64afdd4..7605022 100644 --- a/tests/Service/ProcessorBuilderTest.php +++ b/tests/Service/ProcessorBuilderTest.php @@ -1,5 +1,5 @@ fsio->put('/path/to/bookdown.json', '{ "title": "Example Book", - "content": { - "chapter-1": "chapter-1/bookdown.json" - }, + "content": [ + {"chapter-1": "chapter-1/bookdown.json"} + ], "target": "/_site" }'); $this->fsio->put('/path/to/chapter-1/bookdown.json', '{ "title": "Chapter 1", - "content": { - "section-1": "section-1.md" - } + "content": [ + {"section-1": "section-1.md"} + ] }'); } From 21b900cdb5007d6d923f0f43375b6b9b592a980b Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Wed, 4 Mar 2015 10:08:06 -0600 Subject: [PATCH 2/4] update tests --- src/Config/IndexConfig.php | 6 +-- tests/Config/IndexConfigTest.php | 85 +++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/src/Config/IndexConfig.php b/src/Config/IndexConfig.php index 52e17dd..271a4e4 100644 --- a/src/Config/IndexConfig.php +++ b/src/Config/IndexConfig.php @@ -84,7 +84,7 @@ protected function initContentItem($origin) $name = basename($origin); if (substr($name, -13) == 'bookdown.json') { - $name = basename(dirname($name)); + $name = basename(dirname($origin)); return $this->addContent($name, $origin); } @@ -99,11 +99,11 @@ protected function initContentItem($origin) protected function addContent($name, $origin) { if ($name == 'index') { - throw new Exception("Disallowed 'index' content name in {$this->file}."); + throw new Exception("Disallowed 'index' content name in '{$this->file}'."); } if (isset($this->content[$name])) { - throw new Exception("Content name '{$name}' already set in {$this->file}."); + throw new Exception("Content name '{$name}' already set in '{$this->file}'."); } $this->content[$name] = $this->fixPath($origin); diff --git a/tests/Config/IndexConfigTest.php b/tests/Config/IndexConfigTest.php index 99c9efa..18d205b 100644 --- a/tests/Config/IndexConfigTest.php +++ b/tests/Config/IndexConfigTest.php @@ -5,7 +5,7 @@ class IndexConfigTest extends \PHPUnit_Framework_TestCase { protected $config; - protected $validLocalJson = '{ + protected $jsonValidLocal = '{ "title": "Example Title", "content": [ {"foo": "foo.md"}, @@ -14,7 +14,7 @@ class IndexConfigTest extends \PHPUnit_Framework_TestCase ] }'; - protected $validRemoteJson = '{ + protected $jsonValidRemote = '{ "title": "Example Title", "content": [ {"zim": "zim.md"}, @@ -35,16 +35,39 @@ class IndexConfigTest extends \PHPUnit_Framework_TestCase protected $jsonMissingContent = '{ "title": "Example Title", - "content" : [] + "content": [] }'; protected $jsonContentIndex = '{ "title": "Example Title", - "content" : [ + "content": [ {"index": "index.md"} ] }'; + protected $jsonContentNotArray = '{ + "title": "Example Title", + "content": "not an array" + }'; + + protected $jsonContentConvenience = '{ + "title": "Example Title", + "content": [ + "foo.md", + "bar/bookdown.json", + "http://example.com/baz.md", + "http://example.dom/dib/bookdown.json" + ] + }'; + + protected $jsonReusedContentName = '{ + "title": "Example Title", + "content": [ + "foo.md", + "foo/bookdown.json" + ] + }'; + protected function newIndexConfig($file, $data) { return new IndexConfig($file, $data); @@ -77,18 +100,27 @@ public function testMissingContent() $config = $this->newIndexConfig('/path/to/bookdown.json', $this->jsonMissingContent); } + public function testContentNotArray() + { + $this->setExpectedException( + 'Bookdown\Bookdown\Exception', + "Content must be an array in '/path/to/bookdown.json'." + ); + $config = $this->newIndexConfig('/path/to/bookdown.json', $this->jsonContentNotArray); + } + public function testContentIndex() { $this->setExpectedException( 'Bookdown\Bookdown\Exception', - "Disallowed 'index' content name in /path/to/bookdown.json." + "Disallowed 'index' content name in '/path/to/bookdown.json'." ); $config = $this->newIndexConfig('/path/to/bookdown.json', $this->jsonContentIndex); } - public function testValidLocalJson() + public function testValidLocal() { - $config = $this->newIndexConfig('/path/to/bookdown.json', $this->validLocalJson); + $config = $this->newIndexConfig('/path/to/bookdown.json', $this->jsonValidLocal); $this->assertSame('/path/to/bookdown.json', $config->getFile()); $this->assertSame('/path/to/', $config->getDir()); @@ -101,11 +133,11 @@ public function testValidLocalJson() $this->assertSame($expect, $config->getContent()); } - public function testValidRemoteJson() + public function testValidRemote() { $config = $this->newIndexConfig( 'http://example.net/path/to/bookdown.json', - $this->validRemoteJson + $this->jsonValidRemote ); $this->assertSame('http://example.net/path/to/bookdown.json', $config->getFile()); @@ -118,7 +150,38 @@ public function testValidRemoteJson() $this->assertSame($expect, $config->getContent()); } - public function testInvalidRemoteJson() + public function testContentConvenience() + { + $config = $this->newIndexConfig( + '/path/to/bookdown.json', + $this->jsonContentConvenience + ); + + $this->assertSame('/path/to/bookdown.json', $config->getFile()); + + $expect = array( + 'foo' => '/path/to/foo.md', + 'bar' => '/path/to/bar/bookdown.json', + 'baz' => 'http://example.com/baz.md', + 'dib' => 'http://example.dom/dib/bookdown.json', + ); + + $this->assertSame($expect, $config->getContent()); + } + + public function testReusedContentName() + { + $this->setExpectedException( + 'Bookdown\Bookdown\Exception', + "Content name 'foo' already set in '/path/to/bookdown.json'." + ); + $config = $this->newIndexConfig( + '/path/to/bookdown.json', + $this->jsonReusedContentName + ); + } + + public function testInvalidRemote() { $this->setExpectedException( 'Bookdown\Bookdown\Exception', @@ -126,7 +189,7 @@ public function testInvalidRemoteJson() ); $config = $this->newIndexConfig( 'http://example.net/path/to/bookdown.json', - $this->validLocalJson + $this->jsonValidLocal ); } } From 694f167b09dc52fd756993a385a8a198b6f1c030 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Wed, 4 Mar 2015 10:18:54 -0600 Subject: [PATCH 3/4] make sure content origin is string or object --- src/Config/IndexConfig.php | 7 +++++-- tests/Config/IndexConfigTest.php | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Config/IndexConfig.php b/src/Config/IndexConfig.php index 271a4e4..2c9bf84 100644 --- a/src/Config/IndexConfig.php +++ b/src/Config/IndexConfig.php @@ -82,8 +82,11 @@ protected function initContentItem($origin) return $this->addContent($name, $origin); } - $name = basename($origin); - if (substr($name, -13) == 'bookdown.json') { + if (! is_string($origin)) { + throw new Exception("Content origin must be object or string in '{$this->file}'."); + } + + if (substr($origin, -13) == 'bookdown.json') { $name = basename(dirname($origin)); return $this->addContent($name, $origin); } diff --git a/tests/Config/IndexConfigTest.php b/tests/Config/IndexConfigTest.php index 18d205b..3abd222 100644 --- a/tests/Config/IndexConfigTest.php +++ b/tests/Config/IndexConfigTest.php @@ -50,6 +50,13 @@ class IndexConfigTest extends \PHPUnit_Framework_TestCase "content": "not an array" }'; + protected $jsonContentItemNotStringOrObject = '{ + "title": "Example Title", + "content": [ + ["neither string", "nor object"] + ] + }'; + protected $jsonContentConvenience = '{ "title": "Example Title", "content": [ @@ -109,6 +116,15 @@ public function testContentNotArray() $config = $this->newIndexConfig('/path/to/bookdown.json', $this->jsonContentNotArray); } + public function testContentItemNotStringOrObject() + { + $this->setExpectedException( + 'Bookdown\Bookdown\Exception', + "Content origin must be object or string in '/path/to/bookdown.json'." + ); + $config = $this->newIndexConfig('/path/to/bookdown.json', $this->jsonContentItemNotStringOrObject); + } + public function testContentIndex() { $this->setExpectedException( From 92b11b8597a4d6725f88ad7023489f98f989bad7 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Wed, 4 Mar 2015 13:42:12 -0600 Subject: [PATCH 4/4] add subtitle element --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 51eccdb..8c9afae 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ Bookdown has 100% test coverage. To run the tests, install [PHPUnit](http://phpu - `"afterToc"`: indicates a Markdown file to place on the index page after the TOC + - `"subtitle"`: indicates a subtitle on an index page + - navigational elements - sidebar of siblings at the current level