73694f0e5fd816679dbdf1d0f82374525b8f640f
Author: chawbacca
Date: 2009-02-05 17:22:45 -0600
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): ?>
