public function testParamTag() { $comment = "/**\n * Lithium is cool\n * @param string \$str Some string\n */"; $expected = array('description' => 'Lithium is cool', 'text' => '', 'tags' => array('params' => array('$str' => array('type' => 'string', 'text' => 'Some string')))); $result = Docblock::comment($comment); $this->assertEqual($expected, $result); }
public function testDocblockNewlineHandling() { $doc = " * This line as well as the line below it,\r\n"; $doc .= " * are part of the description.\r\n *\r\n * This line isn't."; $result = Docblock::comment($doc); $description = "This line as well as the line below it,\nare part of the description."; $this->assertEqual($description, $result['description']); $this->assertEqual('This line isn\'t.', $result['text']); }
/** * Detailed source code identifier analysis * * Analyzes a passed $identifier for more detailed information such * as method/property modifiers (e.g. `public`, `private`, `abstract`) * * @param string $identifier The identifier to be analyzed * @param array $info Optionally restrict or expand the default information * returned from the `info` method. By default, the information returned * is the same as the array keys contained in the `$_methodMap` property of * Inspector. * @return array An array of the parsed meta-data information of the given identifier. */ public static function info($identifier, $info = array()) { $info = $info ?: array_keys(static::$_methodMap); $type = static::type($identifier); $result = array(); $class = null; if ($type == 'method' || $type == 'property') { list($class, $identifier) = explode('::', $identifier); try { $classInspector = new ReflectionClass($class); } catch (Exception $e) { return null; } if ($type == 'property') { $identifier = substr($identifier, 1); $accessor = 'getProperty'; } else { $identifier = str_replace('()', '', $identifier); $accessor = 'getMethod'; } try { $inspector = $classInspector->{$accessor}($identifier); } catch (Exception $e) { return null; } $result['modifiers'] = static::_modifiers($inspector); } elseif ($type == 'class') { $inspector = new ReflectionClass($identifier); } else { return null; } foreach ($info as $key) { if (!isset(static::$_methodMap[$key])) { continue; } if (method_exists($inspector, static::$_methodMap[$key])) { $setAccess = ($type == 'method' || $type == 'property') && array_intersect($result['modifiers'], array('private', 'protected')) != array() && method_exists($inspector, 'setAccessible'); if ($setAccess) { $inspector->setAccessible(true); } $result[$key] = $inspector->{static::$_methodMap[$key]}(); if ($setAccess) { $inspector->setAccessible(false); $setAccess = false; } } } if ($type == 'property' && !$classInspector->isAbstract()) { $inspector->setAccessible(true); try { $result['value'] = $inspector->getValue(static::_class($class)); } catch (Exception $e) { return null; } } if (isset($result['start']) && isset($result['end'])) { $result['length'] = $result['end'] - $result['start']; } if (isset($result['comment'])) { $result += Docblock::comment($result['comment']); } return $result; }
protected static function _codeToDoc($code) { $tokens = token_get_all($code); $display = array(); $current = ''; foreach ($tokens as $i => $token) { if ($i == 0 || $token[0] == T_CLOSE_TAG && $i + 1 == count($tokens)) { continue; } if ($token[0] == T_DOC_COMMENT) { if (preg_match('/@copyright/', $token[1])) { continue; } if (!trim($current)) { $current = ''; } if ($current) { $display[] = "{{{\n{$current}}}}"; $current = ''; } $doc = Docblock::comment($token[1]); foreach (array('text', 'description') as $key) { $doc[$key] = Code::embed($doc[$key]); } $display[] = $doc; continue; } $current .= is_array($token) ? $token[1] : $token; } if ($current) { $display[] = "{{{\n{$current}}}}"; } return $display; }
/** * Get the properties for the class * * @param string $class * @param array $options * @return array */ protected function _properties($class, $options = array()) { $defaults = array('name' => null); $options += $defaults; $properties = Inspector::properties($class); $results = array(); foreach ($properties as &$property) { $comment = Docblock::comment($property['docComment']); $description = trim($comment['description']); $type = isset($comment['tags']['var']) ? strtok($comment['tags']['var'], ' ') : null; $name = str_replace('_', '-', Inflector::underscore($property['name'])); $usage = $type == 'boolean' ? "-{$name}" : "--{$name}=" . strtoupper($name); $results[$name] = compact('name', 'description', 'type', 'usage'); if ($name == $options['name']) { return array($name => $results[$name]); } } return $results; }
public function _parseClass($class) { $data = array(); // $methods = Inspector::methods($class, null, array('public' => false)); $methods = get_class_methods($class); $properties = array_keys(get_class_vars($class)); $ident = $class; $info = Inspector::info($ident); $info = Docblock::comment($info['comment']); $data = $this->_merge($data, array('id' => $info['description'], 'comments' => array($ident))); $this->_merge($data, array('id' => $info['text'], 'comments' => array($class))); foreach ($methods as $method) { $ident = "{$class}::{$method}()"; $info = Inspector::info($ident); $info = Docblock::comment($info['comment']); $this->_merge($data, array('id' => $info['description'], 'comments' => array($ident))); $this->_merge($data, array('id' => $info['text'], 'comments' => array($ident))); if (isset($info['tags']['return'])) { $this->_merge($data, array('id' => $info['tags']['return'], 'comments' => array($ident))); } foreach (Set::extract($info, '/tags/params/text') as $text) { $this->_merge($data, array('id' => $text, 'comments' => array($ident))); } } foreach ($properties as $property) { $ident = "{$class}::\${$property}"; $info = Inspector::info($ident); $info = Docblock::comment($info['comment']); $data = $this->_merge($data, array('id' => $info['description'], 'comments' => array($ident))); $data = $this->_merge($data, array('id' => $info['text'], 'comments' => array($ident))); } return $data; }