0ce23593d8a1ebd53a10295186c7b2e1061618cb

Author: chawbacca

Date: 2009-02-04 16:50:05 -0600

Merge from api_generator.git

diff --git a/.gitignore b/.gitignore index 30cbe32..cdc7698 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,9 @@ .DS_Store -api_config.ini \ No newline at end of file +api_config.ini +errors.err +*.swp +*.swo +*~ +config/core.php +config/database.php +tmp/* \ No newline at end of file diff --git a/config/sql/api_generator.php b/config/sql/api_generator.php index 33ea2b5..2e2f0b5 100644 --- a/config/sql/api_generator.php +++ b/config/sql/api_generator.php @@ -20,8 +20,8 @@ * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project * @package cake * @subpackage cake.api_generator.config - * @since - * @version + * @since + * @version * @license http://www.opensource.org/licenses/mit-license.php The MIT License */ /** @@ -40,7 +40,8 @@ class ApiGeneratorSchema extends CakeSchema { 'name' => array('type' => 'string', 'length' => 200, 'null' => false), 'slug' => array('type' => 'string', 'length' => 200, 'null' => false), 'file_name' => array('type' => 'text'), - 'search_index' => array('type' => 'text'), + 'method_index' => array('type' => 'text'), + 'property_index' => array('type' => 'text'), 'flags' => array('type' => 'integer', 'default' => 0, 'length' => 5), 'created' => array('type' => 'datetime'), 'modified' => array('type' => 'datetime'), diff --git a/controllers/api_generator_controller.php b/controllers/api_generator_controller.php index 3b351f0..2fafdae 100644 --- a/controllers/api_generator_controller.php +++ b/controllers/api_generator_controller.php @@ -37,7 +37,7 @@ class ApiGeneratorController extends ApiGeneratorAppController { * * @var array */ - public $uses = array('ApiGenerator.ApiFile'); + public $uses = array('ApiGenerator.ApiFile', 'ApiGenerator.ApiClass'); /** * Components array * @@ -49,7 +49,7 @@ class ApiGeneratorController extends ApiGeneratorAppController { * * @var array **/ - public $helpers = array('ApiGenerator.ApiDoc', 'ApiGenerator.ApiUtils', 'Html', 'Javascript'); + public $helpers = array('ApiGenerator.ApiDoc', 'ApiGenerator.ApiUtils', 'Html', 'Javascript', 'Text'); /** * Browse application files and find things you would like to generate API docs for. * @@ -97,7 +97,6 @@ class ApiGeneratorController extends ApiGeneratorAppController { * @return void **/ public function classes() { - $this->ApiClass = ClassRegistry::init('ApiGenerator.ApiClass'); $classIndex = $this->ApiClass->getClassIndex(); $this->set('classIndex', $classIndex); } @@ -121,7 +120,7 @@ class ApiGeneratorController extends ApiGeneratorAppController { } catch(Exception $e) { $this->_notFound($e->getMessage()); } - $classIndex = ClassRegistry::init('ApiGenerator.ApiClass')->getClassIndex(); + $classIndex = $this->ApiClass->getClassIndex(); list($dirs, $files) = $this->ApiFile->read($this->path . $previousPath); if (!empty($docs)) { @@ -144,7 +143,6 @@ class ApiGeneratorController extends ApiGeneratorAppController { $this->Session->setFlash(__('No class name was given', true)); $this->redirect($this->referer()); } - $this->ApiClass = ClassRegistry::init('ApiGenerator.ApiClass'); $classInfo = $this->ApiClass->findBySlug($classSlug); if (empty($classInfo['ApiClass']['file_name'])) { $this->_notFound(__('No class exists in the index with that name', true)); @@ -171,7 +169,6 @@ class ApiGeneratorController extends ApiGeneratorAppController { * @return void **/ public function view_source($classSlug = null) { - $this->ApiClass = ClassRegistry::init('ApiGenerator.ApiClass'); $classInfo = $this->ApiClass->findBySlug($classSlug); if (empty($classInfo['ApiClass']['file_name'])) { @@ -186,19 +183,93 @@ class ApiGeneratorController extends ApiGeneratorAppController { * * @return void **/ - public function search() { - $this->ApiClass = ClassRegistry::init('ApiGenerator.ApiClass'); + public function search($term = null) { + $conditions = array(); + if (!empty($this->params['url']['query'])) { + $term = $this->params['url']['query']; + return $this->redirect(array($term)); + } + $term = trim($term); + $terms = explode(' ', $term); $conditions = array(); - if (isset($this->params['url']['query'])) { - $query = $this->params['url']['query']; - $conditions = array('ApiClass.search_index LIKE' => '%' . $query . '%'); + $match = false; + foreach ($terms as $i => $j) { + if (trim($j) === '') { + unset ($terms[$i]); + } + } + foreach ($terms as $i => $class) { + $slug = str_replace('_', '-', Inflector::slug(Inflector::underscore($class))); + if ($this->ApiClass->find('count', array('conditions' => array('slug like' => $slug . '%')))) { + $match = $class; + break; + } + } + $fields = array('DISTINCT ApiClass.name', 'ApiClass.method_index', 'ApiClass.property_index', 'file_name'); + $order = 'ApiClass.name'; + if ($match) { + $conditions['ApiClass.slug like'] = $slug . '%'; + $results = $this->ApiClass->find('all', compact('conditions', 'order', 'fields')); + } else { + $results = array(); + } + $conditions = array(); + foreach ($terms as $term) { + $conditions['NOT']['ApiClass.id'] = Set::extract($results, '/ApiClass/id'); + $conditions['OR'][] = array('OR' => array( + 'ApiClass.method_index LIKE' => '% ' . $term . '%', + )); + } + $results = am($results, $this->ApiClass->find('all', compact('conditions', 'order', 'fields'))); + $conditions = array(); + foreach ($terms as $term) { + $conditions['NOT']['ApiClass.id'] = Set::extract($results, '/ApiClass/id'); + $conditions['OR'][] = array('OR' => array( + 'ApiClass.property_index LIKE' => '% ' . $term . '%', + )); + } + $results = am($results, $this->ApiClass->find('all', compact('conditions', 'order', 'fields'))); + $docs = array(); + foreach ($results as $i => $result) { + $docs[$i] = $this->ApiFile->loadFile($result['ApiClass']['file_name'], array('useIndex' => true)); + foreach ($docs[$i]['class'] as $name => &$obj) { + foreach ($obj->properties as $j => $prop) { + $delete = true; + foreach($terms as $term) { + if (strpos($prop['name'], $term) !== false) { + $delete = false; + break; + } + } + if ($delete) { + unset ($obj->properties[$j]); + } + } + foreach ($obj->methods as $j => $method) { + $delete = true; + foreach($terms as $term) { + if (strpos($method['name'], $term) !== false) { + $delete = false; + break; + } + } + if ($delete) { + unset ($obj->methods[$j]); + } + } + if (!$match && !$obj->methods && !$obj->properties) { + unset($docs[$i]['class']); + } + } + if (!$docs[$i]['function']) { + unset ($docs[$i]['function']); + } + if (!$docs[$i]) { + unset ($docs[$i]); + } } - $this->paginate['fields'] = array('DISTINCT ApiClass.name', 'ApiClass.search_index'); - $this->paginate['order'] = 'ApiClass.name ASC'; - $results = $this->paginate($this->ApiClass, $conditions); $classIndex = $this->ApiClass->getClassIndex(); - $this->helpers[] = 'Text'; - $this->set(compact('results', 'classIndex')); + $this->set(compact('classIndex', 'terms', 'class', 'docs')); } /** * Extract all the useful config info out of the ApiConfig. diff --git a/models/api_class.php b/models/api_class.php index 01e92ef..a318214 100644 --- a/models/api_class.php +++ b/models/api_class.php @@ -76,7 +76,8 @@ class ApiClass extends ApiGeneratorAppModel { 'name' => $classDoc->name, 'slug' => $slug, 'file_name' => $classDoc->classInfo['fileName'], - 'search_index' => $this->_generateSearchIndex($classDoc), + 'method_index' => $this->_generateIndex($classDoc, 'methods'), + 'property_index' => $this->_generateIndex($classDoc, 'properties'), ); $this->set($new); return $this->save(); @@ -90,32 +91,23 @@ class ApiClass extends ApiGeneratorAppModel { public function getClassIndex() { return $this->find('list', array('fields' => array('slug', 'name'), 'order' => 'ApiClass.name ASC')); } - /** - * Generate a search index from all the properties and methods - * in a ClassDocumentor Object + * Generate a search index of methods or properties for the ClassDocumentor Object * - * @return string - **/ - protected function _generateSearchIndex($classDoc) { - $index = ''; - $index .= $classDoc->classInfo['comment']['description']; - foreach ((array)$classDoc->properties as $prop) { - if ($prop['declaredInClass'] != $classDoc->classInfo['name']) { - continue; - } - $index .= ' ' . $prop['comment']['description']; - } - foreach ((array)$classDoc->methods as $method) { - if ($method['declaredInClass'] != $classDoc->classInfo['name']) { + * @param mixed $classDoc + * @param string $what + * @return void + * @access protected + */ + protected function _generateIndex(&$classDoc, $what = 'methods') { + $index = array(); + foreach ((array)$classDoc->$what as $result) { + if ($result['declaredInClass'] != $classDoc->classInfo['name']) { continue; } - $description = str_replace("\n", ' ', $method['comment']['description']); - $index .= ' ' . $description; - foreach ($method['args'] as $argument) { - $index .= ' ' . $argument['comment']; - } + $index[] = $result['name']; } - return strtolower($index); + return strtolower(implode($index, ' ')); } -} \ No newline at end of file +} +?> \ No newline at end of file diff --git a/tests/cases/vendors/introspector.test.php b/tests/cases/vendors/introspector.test.php index 573911c..7960fc7 100644 --- a/tests/cases/vendors/introspector.test.php +++ b/tests/cases/vendors/introspector.test.php @@ -127,6 +127,23 @@ EOD; * * This is my long description * + * @return string This is a longer doc string + * for the return string + * more lines + * more lines. + */ +EOD; + $result = Introspector::parseDocBlock($comment); + $expected = 'string This is a longer doc string for the return string more lines more lines.'; + $this->assertEqual($result['tags']['return'], $expected, 'parsing n-line tags failed %s'); + + + $comment = <<<EOD + /** + * This is the title + * + * This is my long description + * * @param string \$foo Foo is an input * @param int \$bar Bar is also an input * @param int \$baz Baz is also an input diff --git a/vendors/css/base.css b/vendors/css/base.css index e27ed29..c19b2d8 100644 --- a/vendors/css/base.css +++ b/vendors/css/base.css @@ -229,7 +229,8 @@ Documentation Page Styles .class-info { margin:3em 0 0; } -.class-info .doc-head h2 { +.class-info .doc-head h2, +.class-info .doc-head h3 { font-size: 28px; line-height: 32px; } @@ -244,7 +245,8 @@ Documentation Page Styles right:10px; top:8px; } -.doc-head h2 { +.doc-head h2, +.doc-head h3 { color: #333348; border-left:7px solid #fff; margin:0; @@ -531,9 +533,22 @@ ol.code li code { padding: 4px 0; } #search-results li { - margin: 20px 10px; + margin: 30px 10px; font-size: 140%; } +#search-results .doc-head { + border: 0; +} +#search-results h3 { + font-size: 18px; +} +#search-results .doc-body { + padding-bottom: 0; + padding-top: 5px; +} +#search-results .doc-body table { + margin: 0; +} #search-results .highlight { background: #C9E2E6; } diff --git a/vendors/introspector.php b/vendors/introspector.php index 360668d..9840301 100644 --- a/vendors/introspector.php +++ b/vendors/introspector.php @@ -99,9 +99,16 @@ class Introspector { if (preg_match('/@([a-z0-9_-]+)\s(.*)$/i', $tmp[$i], $parsedTag)) { // capture continued lines. (indented with 3 spaces or 1 tab) - if (isset($tmp[$i + 1]) && preg_match('/^(?: {1,3}|\t)([^\t]*)$/i', $tmp[$i + 1], $nextLine)) { - $parsedTag[2] .= ' ' . trim($nextLine[1]); - $preprocessed[$i + 1] = true; + $done = false; + $next = $i + 1; + while (!$done) { + if (isset($tmp[$next]) && preg_match('/^(?: {1,3}|\t)([^\t]*)$/i', $tmp[$next], $nextLine)) { + $parsedTag[2] .= ' ' . trim($nextLine[1]); + $preprocessed[$next] = true; + $next++; + } else { + $done = true; + } } if (isset($tags[$parsedTag[1]]) && !is_array($tags[$parsedTag[1]])) { $tags[$parsedTag[1]] = (array)$tags[$parsedTag[1]]; diff --git a/vendors/shells/api_index.php b/vendors/shells/api_index.php index e5646d4..66a3bd4 100644 --- a/vendors/shells/api_index.php +++ b/vendors/shells/api_index.php @@ -305,34 +305,6 @@ class ApiIndexShell extends Shell { } $this->hr(); - $this->out('Usually we can find the dependencies, but '); - $this->out('sometimes we miss. If you have files that are not generating properly'); - $this->out('Input a comma separated list for multiple options'); - $this->out('to continue, just answer "n"'); - $this->hr(); - - $dependencies = null; - while($dependencies == null && $dependencies != 'n') { - $class = $this->in('Class with dependancies', '', 'n'); - if ($class == 'n') { - $dependencies = 'n'; - } else { - $parent = null; - while($parent == null && $parent != 'n') { - $parent = $this->in('Enter the dependencies for ' . $class, ''); - if ($parent != 'n') { - $dependencies = true; - $config['dependencies'][$class] = $parent; - } - } - $stop = $this->in('Add another dependency?', array('y', 'n', 'q'), 'n'); - if ($stop == 'y') { - $dependencies = null; - } - } - } - - $this->hr(); $this->out('Verify the config'); $this->hr(); $string = $this->ApiConfig->toString($config); @@ -363,7 +335,6 @@ class ApiIndexShell extends Shell { $this->out(' Clear the existing class index and regenerate it.'); $this->out(' set_routes'); $this->out(' Add routes for Api generator to your routes file.'); - } } diff --git a/views/api_generator/search.ctp b/views/api_generator/search.ctp index 1adbef6..89e3a83 100644 --- a/views/api_generator/search.ctp +++ b/views/api_generator/search.ctp @@ -3,28 +3,30 @@ * Api Search results * */ - $apiDoc->setClassIndex($classIndex); - ?> -<h1><?php __('Search Results'); ?></h1> -<?php if (empty($results)): ?> +<h1><?php echo sprintf(__('Search Results for "%s"', true), $this->passedArgs[0]); ?></h1> +<?php if (empty($docs)): ?> <p class="error"><?php __('Your search returned no results'); ?></p> -<?php else: ?> +<?php return; +endif; ?> + <ul id="search-results"> - <?php foreach ($results as $result): ?> - <li><h4><?php echo $apiDoc->classLink($result['ApiClass']['name']); ?></h4> - <?php $excerpt = $text->excerpt(strip_tags($result['ApiClass']['search_index']), $this->params['url']['query']); ?> - <p><?php echo $text->highlight($excerpt, strtolower($this->params['url']['query'])); ?></p> +<?php foreach ($docs as $result): + foreach ($result['class'] as $name => $doc): ?> + <li class="doc-block class-info"> + <h2><?php echo $apiDoc->classLink($doc->name, array(), array('class' => false)); ?></h2><?php + if ($doc->properties): + echo $this->element('properties', array('doc' => $doc, 'isSearch' => true)); + endif; + + if ($doc->methods): + echo $this->element('method_summary', array('doc' => $doc, 'isSearch' => true)); + endif; +?> </li> - <?php endforeach;?> -</ul> -<?php endif; ?> -<?php -$paginator->options(array( - 'url' => array( - '?' => array('query' => $this->params['url']['query']) - ) -)); +<?php + endforeach; +endforeach; ?> -<?php echo $this->element('paging'); ?> \ No newline at end of file +</ul> \ No newline at end of file diff --git a/views/elements/class_info.ctp b/views/elements/class_info.ctp index 00d9a63..5b994fd 100644 --- a/views/elements/class_info.ctp +++ b/views/elements/class_info.ctp @@ -37,7 +37,11 @@ <dl> <?php foreach ($doc->classInfo['comment']['tags'] as $name => $value): ?> <dt><?php echo $name; ?></dt> - <dd><?php echo h($value); ?></dd> + <?php if (strtolower($name) == 'link'): + echo '<dd>' . $text->autoLink(h($value)) . '</dd>'; + else: + echo '<dd>' . h($value) . '</dd>'; + endif; ?> <?php endforeach; ?> </dl> </div> diff --git a/views/elements/header_search.ctp b/views/elements/header_search.ctp index 26d010d..9253adf 100644 --- a/views/elements/header_search.ctp +++ b/views/elements/header_search.ctp @@ -1,21 +1,27 @@ <?php /** - * Header search form + * Header search form * */ ?> <div id="header-search"> <?php echo $form->create('ApiClass', array( 'url' => array( - 'plugin' => 'api_generator', 'controller' => 'api_generator', + 'plugin' => 'api_generator', 'controller' => 'api_generator', 'action' => 'search' - ), + ), 'type' => 'get', )); ?> <fieldset id="search-bar"> - <?php +<?php + if ($this->action === 'search' && !empty($this->passedArgs[0])) { + $value = $this->passedArgs[0]; + } else { + $value = ''; + } echo $form->text('Search.query', array( - 'class' => 'query' + 'class' => 'query', + 'value' => $value )); ?> <?php echo $form->submit(__('Search', true), array('div' => false, 'class' => 'submit')); ?> </fieldset> diff --git a/views/elements/method_detail.ctp b/views/elements/method_detail.ctp index 7e3216c..da16170 100644 --- a/views/elements/method_detail.ctp +++ b/views/elements/method_detail.ctp @@ -62,7 +62,11 @@ <dt> <?php foreach ($method['comment']['tags'] as $name => $value): ?> <dt><?php echo $name; ?></dt> - <dd><?php echo h($value); ?></dd> + <?php if (strtolower($name) == 'link'): + echo '<dd>' . $text->autoLink(h($value)) . '</dd>'; + else: + echo '<dd>' . h($value) . '</dd>'; + endif; ?> <?php endforeach; ?> </dt> </div> diff --git a/views/elements/method_summary.ctp b/views/elements/method_summary.ctp index 3ec269e..ed75afd 100644 --- a/views/elements/method_summary.ctp +++ b/views/elements/method_summary.ctp @@ -4,19 +4,23 @@ * */ -$apiUtils->sortByName($doc->methods); ?> +$apiUtils->sortByName($doc->methods); +$title = (empty($isSearch)) ? __('Method Summary:', true) : __('Methods:', true); +?> <div class="doc-block"> <a id="top-<?php echo $doc->name; ?>"></a> - <div class="doc-head"><h2><?php __('Method Summary:'); ?></h2></div> + <div class="doc-head"><h3><?php echo $title; ?></h3></div> <div class="doc-body"> +<?php if (empty($isSearch)): ?> <span class="doc-controls"> <a href="#" id="hide-parent-methods"><?php __('Show/Hide parent methods'); ?></a> </span> +<?php endif; ?> <table class="summary"> <tbody> <?php $i = 0; ?> <?php foreach ($doc->methods as $method): ?> - <?php + <?php if ($apiDoc->excluded($method['access'], 'method')) : continue; endif; @@ -26,10 +30,18 @@ $apiUtils->sortByName($doc->methods); ?> <td class="access <?php echo $method['access']; ?>"><span><?php echo $method['access']; ?></span></td> <td> <?php - echo $html->link($method['signature'], - '#method-' . $doc->name . $method['name'], - array('class' => 'scroll-link') - ); + if (empty($isSearch)): + echo $html->link($method['signature'], + '#method-' . $doc->name . $method['name'], + array('class' => 'scroll-link') + ); + else: + echo $html->link($method['signature'], + array('action' => 'view_class', $apiDoc->slugClassName($doc->name), + '#' => 'method-' . $doc->name . $method['name']), + array('class' => 'scroll-link') + ); + endif; ?> </td> </tr> diff --git a/views/elements/properties.ctp b/views/elements/properties.ctp index 1b0825e..9aaf1ab 100644 --- a/views/elements/properties.ctp +++ b/views/elements/properties.ctp @@ -3,19 +3,21 @@ * Properties Element * */ - -$apiUtils->sortByName($doc->properties); ?> +$apiUtils->sortByName($doc->properties); +?> <div class="doc-block"> - <div class="doc-head"><h2><?php __('Properties:'); ?></h2></div> + <div class="doc-head"><h3><?php __('Properties:'); ?></h3></div> <div class="doc-body"> <?php if (!empty($doc->properties)): ?> +<?php if (empty($isSearch)): ?> <span class="doc-controls"> <a href="#" id="hide-parent-properties"><?php __('Show/Hide parent properties'); ?></a> </span> +<?php endif; ?> <table> <?php $i = 0; ?> <?php foreach ($doc->properties as $prop): ?> - <?php + <?php if ($apiDoc->excluded($prop['access'], 'property')) : continue; endif;