73694f0e5fd816679dbdf1d0f82374525b8f640f

Author: chawbacca

Date: 2009-02-05 17:22:45 -0600

Merge from api_generator.git

diff --git a/controllers/api_generator_controller.php b/controllers/api_generator_controller.php index 2fafdae..4297a25 100644 --- a/controllers/api_generator_controller.php +++ b/controllers/api_generator_controller.php @@ -120,7 +120,11 @@ class ApiGeneratorController extends ApiGeneratorAppController { } catch(Exception $e) { $this->_notFound($e->getMessage()); } +<<<<<<< HEAD:controllers/api_generator_controller.php $classIndex = $this->ApiClass->getClassIndex(); +======= + $classIndex = $this->ApiClass->getClassIndex(true); +>>>>>>> f8f31dc4a4af2f47f38261e3371aaafae3fc1e4d:controllers/api_generator_controller.php list($dirs, $files) = $this->ApiFile->read($this->path . $previousPath); if (!empty($docs)) { @@ -184,6 +188,7 @@ class ApiGeneratorController extends ApiGeneratorAppController { * @return void **/ public function search($term = null) { +<<<<<<< HEAD:controllers/api_generator_controller.php $conditions = array(); if (!empty($this->params['url']['query'])) { $term = $this->params['url']['query']; @@ -270,6 +275,23 @@ class ApiGeneratorController extends ApiGeneratorAppController { } $classIndex = $this->ApiClass->getClassIndex(); $this->set(compact('classIndex', 'terms', 'class', 'docs')); +======= + $conditions = array(); + if (!empty($this->params['url']['query'])) { + $term = $this->params['url']['query']; + return $this->redirect(array($term)); + } + $term = trim($term); + $terms = explode(' ', $term); + foreach ($terms as $i => $j) { + if (trim($j) === '') { + unset ($terms[$i]); + } + } + $docs = $this->ApiClass->search($terms); + $classIndex = $this->ApiClass->getClassIndex(); + $this->set(compact('classIndex', 'terms', 'docs')); +>>>>>>> f8f31dc4a4af2f47f38261e3371aaafae3fc1e4d:controllers/api_generator_controller.php } /** * Extract all the useful config info out of the ApiConfig. diff --git a/models/api_class.php b/models/api_class.php index a318214..4c15d04 100644 --- a/models/api_class.php +++ b/models/api_class.php @@ -52,7 +52,19 @@ class ApiClass extends ApiGeneratorAppModel { ) ), ); - +/** + * Flag bitmask for Pseudo classes (files with global functions) + * get a pseudo class assigned to them + * + * @var int + **/ + const PSEUDO_CLASS = 1; +/** + * Concrete class bitmask; + * + * @var string + **/ + const CONCRETE_CLASS = 0; /** * Clears (truncates) the class index. * @@ -82,14 +94,78 @@ class ApiClass extends ApiGeneratorAppModel { $this->set($new); return $this->save(); } +/** + * Save a set of global functions to the ApiClass index. + * Will make one record with a 'class name' derived from the filename. + * + * @param array $functions Array of FunctionDocumentor objects to index. + * @param string $filename Name of file these things are found in. + * @return boolean + **/ + public function savePseudoClassDocs($functions, $filename) { + $methodList = array(); + $name = basename($filename); + $slug = str_replace('_', '-', Inflector::underscore($name)); + foreach ($functions as $func) { + if ($func instanceof FunctionDocumentor) { + $methodList[] = $func->getName(); + } + } + $data = array( + 'name' => $name, + 'slug' => $slug, + 'file_name' => $filename, + 'method_index' => implode($methodList, ' '), + 'flags' => ApiClass::PSEUDO_CLASS, + ); + $this->set($data); + return $this->save(); + } +/** + * search method + * + * Find matching records for the given term or terms + * Find results ordered by those matching in order: class names, method names, properties + * + * @param mixed $terms array of terms or search term + * @return array of matching ApiFile objects + * @access public + */ + function search($terms = array()) { + if (!$terms) { + return array(); + } + $terms = (array)$terms; + $fields = array('DISTINCT ApiClass.id', 'ApiClass.name', 'ApiClass.method_index', + 'ApiClass.property_index', 'file_name'); + $order = 'ApiClass.name'; + + $conditions = array(); + foreach ($terms as $term) { + $conditions['OR'][] = array('ApiClass.slug LIKE' => $term . '%'); + $conditions['OR'][] = array('ApiClass.method_index LIKE' => '% ' . $term . '%'); + $conditions['OR'][] = array('ApiClass.property_index LIKE' => '% ' . $term . '%'); + } + $results = $this->find('all', compact('conditions', 'order', 'fields')); + return $this->_queryFiles($results, $terms); + } /** * Get the class index listing - * + * + * @param boolean $includePseudoClass Whether you want to include 'pseudo' classes (no actual class) * @return array **/ - public function getClassIndex() { - return $this->find('list', array('fields' => array('slug', 'name'), 'order' => 'ApiClass.name ASC')); + public function getClassIndex($includePseudoClass = false) { + $conditions = array(); + if (!$includePseudoClass) { + $conditions['ApiClass.flags'] = ApiClass::CONCRETE_CLASS; + } + return $this->find('list', array( + 'fields' => array('slug', 'name'), + 'order' => 'ApiClass.name ASC', + 'conditions' => $conditions + )); } /** * Generate a search index of methods or properties for the ClassDocumentor Object @@ -104,10 +180,106 @@ class ApiClass extends ApiGeneratorAppModel { foreach ((array)$classDoc->$what as $result) { if ($result['declaredInClass'] != $classDoc->classInfo['name']) { continue; +<<<<<<< HEAD:models/api_class.php } $index[] = $result['name']; } return strtolower(implode($index, ' ')); +======= + } + $index[] = $result['name']; + } + return strtolower(implode($index, ' ')); + } +/** + * filterSearchResults method + * + * Purge results that don't match the search terms + * + * @param array $results + * @param array $terms + * @return array filtered results + * @access protected + */ + protected function _queryFiles($results, $terms) { + $return = $_return = array(); + $ApiFile =& ClassRegistry::init('ApiGenerator.ApiFile'); + foreach ($results as $i => $result) { + $result = $ApiFile->loadFile($result['ApiClass']['file_name'], array('useIndex' => true)); + foreach ($result['class'] as $name => $obj) { + $relevance = 0; + $this->_unsetUnmatching($obj, $terms, 'properties'); + $this->_unsetUnmatching($obj, $terms, 'methods'); + foreach ($terms as $term) { + if (low($name) === $term) { + $relevance += 6; + } elseif (strpos(low($name), $term) === 0) { + $relevance += 3; + } + } + if ($obj->methods) { + foreach ($obj->methods as $method) { + $_name = $method['name']; + foreach ($terms as $term) { + if (low($_name) === $term) { + $relevance += 4; + } elseif (strpos(low($_name), $term) === 0) { + $relevance += 2; + } + } + } + } + if ($obj->properties) { + foreach ($obj->properties as $property) { + $_name = $property['name']; + foreach($terms as $term) { + if (low($_name) === $term) { + $relevance += 4; + } elseif (strpos(low($_name), $term) === 0) { + $relevance += 2; + } + } + } + } + if ($relevance > 0) { + $_return[$relevance][$name]['class'][$name] = $obj; + } + } + } + ksort($_return); + $_return = array_reverse($_return); + foreach ($_return as $result) { + ksort($result); + $return = am($return, $result); + } + return $return; + } +/** + * unsetUnmatching method + * + * @param mixed $obj + * @param array $terms + * @param string $field + * @return void + * @access protected + */ + function _unsetUnmatching(&$obj, $terms = array(), $field = 'properties') { + if (empty($obj->$field)) { + return; + } + foreach ($obj->$field as $j => $prop) { + $delete = true; + foreach($terms as $term) { + if (strpos($prop['name'], $term) === 0) { + $delete = false; + break; + } + } + if ($delete) { + unset ($obj->{$field}[$j]); + } + } +>>>>>>> f8f31dc4a4af2f47f38261e3371aaafae3fc1e4d:models/api_class.php } } ?> \ No newline at end of file diff --git a/tests/cases/models/api_class.test.php b/tests/cases/models/api_class.test.php index 86cd4a2..95fedf8 100644 --- a/tests/cases/models/api_class.test.php +++ b/tests/cases/models/api_class.test.php @@ -137,8 +137,8 @@ class ApiFileTestCase extends CakeTestCase { 'name' => 'ApiClassSampleClass', 'slug' => 'api-class-sample-class', 'file_name' => __FILE__, - 'search_index' => 'apiclasssampleclass doc block foo property test function in sample class first parameter second parameter non-extended method', - + 'property_index' => 'foo', + 'method_index' => 'testfunct extended', 'flags' => 0, 'created' => $now, 'modified' => $now, @@ -157,7 +157,8 @@ class ApiFileTestCase extends CakeTestCase { 'name' => 'ApiClassSampleClassChild', 'slug' => 'api-class-sample-class-child', 'file_name' => __FILE__, - 'search_index' => 'apiclasssampleclass doc block onlyme primary function extended-method this time', + 'property_index' => 'onlyme', + 'method_index' => 'primary extended', 'flags' => 0, 'created' => $now, 'modified' => $now, @@ -165,4 +166,17 @@ class ApiFileTestCase extends CakeTestCase { ); $this->assertEqual($result, $expected); } +/** + * test Saving of pseudo classes + * + * @return void + **/ + function testSavePseudoClassDocs() { + $file = CAKE_CORE_INCLUDE_PATH . DS . CAKE . 'basics.php'; + $ApiFile = ClassRegistry::init('ApiGenerator.ApiFile'); + $docs = $ApiFile->loadFile($file); + + $result = $this->ApiClass->savePseudoClassDocs($docs['function'], $file); + $this->assertTrue($result); + } } \ No newline at end of file diff --git a/tests/fixtures/api_class_fixture.php b/tests/fixtures/api_class_fixture.php index 1743e44..a643287 100644 --- a/tests/fixtures/api_class_fixture.php +++ b/tests/fixtures/api_class_fixture.php @@ -7,7 +7,8 @@ class ApiClassFixture extends CakeTestFixture { '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/vendors/shells/api_index.php b/vendors/shells/api_index.php index 66a3bd4..0cef498 100644 --- a/vendors/shells/api_index.php +++ b/vendors/shells/api_index.php @@ -143,6 +143,12 @@ class ApiIndexShell extends Shell { $this->out('Added docs for ' . $classDocs->name . ' to index'); } } + if (!empty($docsInFile['function'])) { + $this->ApiClass->create(); + if ($this->ApiClass->savePseudoClassDocs($docsInFile['function'], $file)) { + $this->out('Added docs for global functions in ' . $file); + } + } } } diff --git a/views/elements/function_summary.ctp b/views/elements/function_summary.ctp index f759078..edec9b7 100644 --- a/views/elements/function_summary.ctp +++ b/views/elements/function_summary.ctp @@ -36,7 +36,19 @@ <?php endif; ?> <dt><?php __('Function defined in file:'); ?></dt> - <dd><?php echo $apiDoc->fileLink($doc->info['declaredInFile']); ?></dd> + <dd><?php + echo $apiDoc->fileLink($doc->info['declaredInFile']); + $pseudoClass = basename($doc->info['declaredInFile']); + if ($apiDoc->inClassIndex($pseudoClass)): + __(' on line '); + echo $html->link($doc->info['startLine'], array( + 'controller' => 'api_generator', + 'action' => 'view_source', + $pseudoClass, + '#line-'. $doc->info['startLine'] + )); + endif; + ?> </dd> <dt> <?php foreach ($doc->info['comment']['tags'] as $name => $value): ?>