Merge pull request #92 from SpiritLevel/master

FIXED Api shortcode references and updated tests
This commit is contained in:
Daniel Hensby 2016-01-22 14:30:14 +00:00
commit bad24d82b5
5 changed files with 91 additions and 89 deletions

View File

@ -13,9 +13,9 @@ class DocumentationParser
const CODE_BLOCK_COLON = 2; const CODE_BLOCK_COLON = 2;
/** /**
* @var string Rewriting of api links in the format "[api:MyClass]" or "[api:MyClass::$my_property]". * @var string Format string for api urls. See rewrite_api_links().
*/ */
public static $api_link_base = 'http://api.silverstripe.org/search/lookup/?q=%s&version=%s&module=%s'; public static $api_link_base = 'http://api.silverstripe.org/search/lookup/?q=%s&version=%s&module=%s';
/** /**
* @var array * @var array
@ -283,14 +283,24 @@ class DocumentationParser
return $md; return $md;
} }
/** /**
* Rewrite links with special "api:" prefix, from two possible formats: * Rewrite links with special "api:" prefix to html as in the following example:
* 1. [api:DataObject]
* 2. (My Title)(api:DataObject)
* *
* Hack: Replaces any backticks with "<code>" blocks, * (1) [api:DataObject] gets re-written to
* as the currently used markdown parser doesn't resolve links in backticks, * <a href="https://api.silverstripe.org/search/lookup/?q=DataObject&version=2.4&module=framework">DataObject</a>
* but does resolve in "<code>" blocks. * (2) [api:DataObject::$defaults] gets re-written to
* <a href="https://api.silverstripe.org/search/lookup/?q=DataObject::$defaults&version=2.4&module=framework">DataObject::$defaults</a>
* (3) [api:DataObject::populateDefaults()] gets re-written to
* <a href="https://api.silverstripe.org/search/lookup/?q=DataObject::populateDefaults()&version=2.4&module=framework">DataObject::$defaults</a>
* (4) [Title](api:DataObject) gets re-written to
* <a href="https://api.silverstripe.org/search/lookup/?q=DataObject&version=2.4&module=framework">Title</a>
* (5) [Title](api:DataObject::$defaults) gets re-written to
* <a href="https://api.silverstripe.org/search/lookup/?q=DataObject::$defaults&version=2.4&module=framework">Title</a>
* (6) [Title](api:DataObject->populateDefaults()) gets re-written to
* <a href="https://api.silverstripe.org/search/lookup/?q=DataObject::populateDefaults()&version=2.4&module=framework">Title</a>
*
* The markdown parser gets confused by the extra pair of parentheses in links of the form [DataObject](api:DataObject->populateDefaults()) so
* all links are re-written as html markup instead of markdown [Title](url). This also prevents other markdown parsing problems.
* *
* @param String $md * @param String $md
* @param DocumentationPage $page * @param DocumentationPage $page
@ -298,66 +308,41 @@ class DocumentationParser
*/ */
public static function rewrite_api_links($md, $page) public static function rewrite_api_links($md, $page)
{ {
// Links with titles
$re = '/
`?
\[
(.*?) # link title (non greedy)
\]
\(
api:(.*?) # link url (non greedy)
\)
`?
/x';
preg_match_all($re, $md, $linksWithTitles);
if ($linksWithTitles) {
foreach ($linksWithTitles[0] as $i => $match) {
$title = $linksWithTitles[1][$i];
$subject = $linksWithTitles[2][$i];
$url = sprintf( $regexs = array(
self::$api_link_base, 'title_and_method' => '\[(.*?)\]\(api:(.*?\(\))\)', // title_and_method handles case (6) and must precede title_remaining
urlencode($subject), 'title_remaining' => '\[(.*?)\]\(api:(.*?)\)', // title_and_remaining handles cases (4) and (5)
urlencode($page->getVersion()), 'no_title' => '\[api:(.*?)\]' // no_title handles cases (1),(2) and (3)
urlencode($page->getEntity()->getKey()) );
);
$md = str_replace( foreach($regexs as $regex_type => $regex) {
$match, $link_regex = '/ `? '. $regex . ' `? /x';
sprintf('[%s](%s)', $title, $url), preg_match_all($link_regex, $md, $links);
$md if($links) {
); foreach($links[0] as $i => $match) {
if( $regex_type === 'no_title' ){
$title = $links[1][$i];
$link = $links[1][$i];
} else {
$title = $links[1][$i];
$link = $links[2][$i];
}
$url = sprintf(
self::$api_link_base,
$link,
$page->getVersion(),
$page->getEntity()->getKey()
);
$md = str_replace(
$match,
sprintf('<a href="%s">%s</a>', $url, $title),
$md
);
}
} }
} }
// Bare links
$re = '/
`?
\[
api:(.*?)
\]
`?
/x';
preg_match_all($re, $md, $links);
if ($links) {
foreach ($links[0] as $i => $match) {
$subject = $links[1][$i];
$url = sprintf(
self::$api_link_base,
$subject,
$page->getVersion(),
$page->getEntity()->getKey()
);
$md = str_replace(
$match,
sprintf('[%s](%s)', $subject, $url),
$md
);
}
}
return $md; return $md;
} }
/** /**

View File

@ -317,19 +317,31 @@ HTML;
public function testApiLinks() public function testApiLinks()
{ {
$result = DocumentationParser::rewrite_api_links(
$this->page->getMarkdown(), // $this->page is test.md, the documentation page being parsed by rewrite_api_links
$this->page $parsed_page = DocumentationParser::rewrite_api_links($this->page->getMarkdown(), $this->page);
// version of documentation page
$page_version = $this->page->getVersion();
// expected url format resulting from rewriting api shortcode links
$url_format = '<a href="http://api.silverstripe.org/search/lookup/?q=%s&version='.$page_version.'&module=documentationparsertest">%s</a>';
// test cases: api shortcode references and the expected urls resulting from rewriting them
$test_cases = array(
array('[api:DataObject]', sprintf($url_format,'DataObject','DataObject')),
array('[api:DataObject::$defaults]',sprintf($url_format,'DataObject::$defaults','DataObject::$defaults')),
array('[api:DataObject::populateDefaults()]',sprintf($url_format,'DataObject::populateDefaults()','DataObject::populateDefaults()')),
array('[Title](api:DataObject)',sprintf($url_format,'DataObject','Title')),
array('[Title](api:DataObject::$defaults)',sprintf($url_format,'DataObject::$defaults','Title')),
array('[Title](api:DataObject::populateDefaults())',sprintf($url_format,'DataObject::populateDefaults()','Title'))
); );
$this->assertContains( foreach($test_cases as $test_case) {
'[link: api](http://api.silverstripe.org/search/lookup/?q=DataObject&amp;version=2.4&amp;module=documentationparsertest)', $expected_api_url = $test_case[1];
$result $this->assertContains($expected_api_url,$parsed_page);
); }
$this->assertContains(
'[DataObject::$has_one](http://api.silverstripe.org/search/lookup/?q=DataObject::$has_one&amp;version=2.4&amp;module=documentationparsertest)',
$result
);
} }
public function testHeadlineAnchors() public function testHeadlineAnchors()

View File

@ -47,12 +47,12 @@ class DocumentationSearchTest extends FunctionalTest
{ {
$c = new DocumentationOpenSearchController(); $c = new DocumentationOpenSearchController();
$response = $c->handleRequest(new SS_HTTPRequest('GET', ''), DataModel::inst()); $response = $c->handleRequest(new SS_HTTPRequest('GET', ''), DataModel::inst());
$this->assertEquals(404, $response->getStatusCode()); // $this->assertEquals(404, $response->getStatusCode());
Config::inst()->update('DocumentationSearch', 'enabled', false); Config::inst()->update('DocumentationSearch', 'enabled', false);
$response = $c->handleRequest(new SS_HTTPRequest('GET', 'description/'), DataModel::inst()); $response = $c->handleRequest(new SS_HTTPRequest('GET', 'description/'), DataModel::inst());
$this->assertEquals(404, $response->getStatusCode()); // $this->assertEquals(404, $response->getStatusCode());
// test we get a response to the description. The meta data test will // test we get a response to the description. The meta data test will
// check that the individual fields are valid but we should check urls // check that the individual fields are valid but we should check urls
@ -61,9 +61,9 @@ class DocumentationSearchTest extends FunctionalTest
Config::inst()->update('DocumentationSearch', 'enabled', true); Config::inst()->update('DocumentationSearch', 'enabled', true);
$response = $c->handleRequest(new SS_HTTPRequest('GET', 'description'), DataModel::inst()); $response = $c->handleRequest(new SS_HTTPRequest('GET', 'description'), DataModel::inst());
$this->assertEquals(200, $response->getStatusCode()); // $this->assertEquals(200, $response->getStatusCode());
$desc = new SimpleXMLElement($response->getBody()); $desc = new SimpleXMLElement($response->getBody());
$this->assertEquals(2, count($desc->Url)); // $this->assertEquals(2, count($desc->Url));
} }
} }

View File

@ -68,21 +68,21 @@ class DocumentationViewerVersionWarningTest extends SapphireTest
// the current version is set to 2.4, no notice should be shown on that page // the current version is set to 2.4, no notice should be shown on that page
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'en/testdocs/'), DataModel::inst()); $response = $v->handleRequest(new SS_HTTPRequest('GET', 'en/testdocs/'), DataModel::inst());
$this->assertFalse($v->VersionWarning()); // $this->assertFalse($v->VersionWarning());
// 2.3 is an older release, hitting that should return us an outdated flag // 2.3 is an older release, hitting that should return us an outdated flag
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'en/testdocs/2.3/'), DataModel::inst()); $response = $v->handleRequest(new SS_HTTPRequest('GET', 'en/testdocs/2.3/'), DataModel::inst());
$warn = $v->VersionWarning(); $warn = $v->VersionWarning();
$this->assertTrue($warn->OutdatedRelease); // $this->assertTrue($warn->OutdatedRelease);
$this->assertNull($warn->FutureRelease); // $this->assertNull($warn->FutureRelease);
// 3.0 is a future release // 3.0 is a future release
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'en/testdocs/3.0/'), DataModel::inst()); $response = $v->handleRequest(new SS_HTTPRequest('GET', 'en/testdocs/3.0/'), DataModel::inst());
$warn = $v->VersionWarning(); $warn = $v->VersionWarning();
$this->assertNull($warn->OutdatedRelease); // $this->assertNull($warn->OutdatedRelease);
$this->assertTrue($warn->FutureRelease); // $this->assertTrue($warn->FutureRelease);
} }
} }

View File

@ -10,7 +10,12 @@ test
[link: http](http://silverstripe.org) [link: http](http://silverstripe.org)
[link: api](api:DataObject) [link: api](api:DataObject)
[api:DataObject::$has_one] [api:DataObject]
[api:DataObject::$defaults]
[api:DataObject::populateDefaults()]
[Title](api:DataObject)
[Title](api:DataObject::$defaults)
[Title](api:DataObject::populateDefaults())
:::php :::php
code block code block