Merge pull request #98 from peterhuene/rewrite
(PDOC-63) Code refactoring, fix up, and lots of new functionality.
This commit is contained in:
commit
7ae8e74ec5
|
@ -12,7 +12,7 @@ tmtags
|
|||
|
||||
## VIM
|
||||
*.swp
|
||||
tags
|
||||
/tags
|
||||
|
||||
## BUNDLER
|
||||
.bundle
|
||||
|
@ -24,3 +24,12 @@ Gemfile.lock
|
|||
|
||||
## MODULE BUILDS
|
||||
**/pkg
|
||||
|
||||
## RubyMine
|
||||
/.idea/
|
||||
|
||||
## rvm/rbenv
|
||||
/.ruby-version
|
||||
|
||||
## YARD output
|
||||
/doc/
|
||||
|
|
|
@ -2,7 +2,7 @@ AllCops:
|
|||
Exclude:
|
||||
# Ignore HTML related things
|
||||
- '**/*.erb'
|
||||
- 'lib/puppetx/puppetlabs/strings/yard/templates/**/*'
|
||||
- 'lib/puppet-strings/yard/templates/**/*'
|
||||
|
||||
Lint/ConditionPosition:
|
||||
Enabled: true
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
--exclude lib/puppetx/puppetlabs/strings/yard/templates/
|
||||
--exclude lib/puppetx/puppetlabs/strings/yard/code_objects/host_class_object.rb
|
||||
--exclude lib/puppet-strings/yard/templates/
|
||||
--no-private
|
||||
|
|
|
@ -9,8 +9,8 @@ All related tickets can be found under the [PDOC][PDOC JIRA] JIRA project with t
|
|||
###Features
|
||||
- Support for JSON output **(PDOC-23)**
|
||||
- Strings now has the ability to produce a JSON representation of a given puppet module
|
||||
- The details of the JSON schema can be found [here](https://github.com/puppetlabs/puppetlabs-strings/blob/master/json_dom.md)
|
||||
- For details on how to generate JSON, see the [README](https://github.com/puppetlabs/puppetlabs-strings/blob/master/README.md#running-puppet-strings)
|
||||
- The details of the JSON schema can be found [here](https://github.com/puppetlabs/puppet-strings/blob/master/json_dom.md)
|
||||
- For details on how to generate JSON, see the [README](https://github.com/puppetlabs/puppet-strings/blob/master/README.md#running-puppet-strings)
|
||||
- Migrate to ruby gems as a distribution method **(PDOC-28)**
|
||||
- This is the last release of strings that will be available as a puppet module
|
||||
- The 0.4.0 release will be released concurrently as a ruby gem
|
||||
|
|
|
@ -53,9 +53,9 @@ merged.
|
|||
**security** - Where critical security fixes are merged. These change sets
|
||||
will then be merged into release branches independently from one another. (i.e.
|
||||
no merging up). Please do not submit pull requests against the security branch
|
||||
and instead report all security related issues to security@puppetlabs.com as
|
||||
and instead report all security related issues to security@puppet.com as
|
||||
per our security policy published at
|
||||
[https://puppetlabs.com/security/](https://puppetlabs.com/security/).
|
||||
[https://puppet.com/security/](https://puppet.com/security/).
|
||||
|
||||
Committer Guide
|
||||
====
|
||||
|
@ -84,8 +84,8 @@ applied to earlier minor releases of a major release, but the patches should
|
|||
first be merged into the `security` branch. Security patches should be merged
|
||||
by Puppet Labs staff members. Pull requests should not be submitted with the
|
||||
security branch as the base branch. Please send all security related
|
||||
information or patches to security@puppetlabs.com as per our [Security
|
||||
Policy](https://puppetlabs.com/security/).
|
||||
information or patches to security@puppet.com as per our [Security
|
||||
Policy](https://puppet.com/security/).
|
||||
|
||||
The CI systems are configured to run against `master`. Over time, this branch
|
||||
will refer to different versions, but its name will remain fixed to avoid having
|
||||
|
@ -118,7 +118,7 @@ This section aims to provide guidelines for being a good commit citizen by
|
|||
paying attention to our automated build tools.
|
||||
|
||||
* Don’t push on a broken build. (A broken build is defined as a failing job
|
||||
in the [Puppet FOSS](https://jenkins.puppetlabs.com/view/Puppet%20FOSS/)
|
||||
in [Puppet Strings](https://jenkins.puppetlabs.com/job/platform_puppet-strings_unit-ruby_master/)
|
||||
page.)
|
||||
* Watch the build until your changes have gone through green
|
||||
* Update the ticket status and target version. The target version field in
|
||||
|
@ -143,7 +143,7 @@ First, the committer pulls down the branch using the `hub` gem. This tool
|
|||
automates the process of adding the remote repository and creating a local
|
||||
branch to track the remote branch.
|
||||
|
||||
$ hub checkout https://github.com/puppetlabs/puppetlabs-strings/pull/123
|
||||
$ hub checkout https://github.com/puppetlabs/puppet-strings/pull/123
|
||||
Branch jeffmccune-pdoc-34_fix_foo_error set up to track remote branch pdoc-34-fix_foo_error from jeffmccune.
|
||||
Switched to a new branch 'jeffmccune-pdoc-34_fix_foo_error'
|
||||
|
||||
|
@ -178,7 +178,7 @@ Please note, the checklist should be complete at this point. It's helpful to mak
|
|||
sure your local branches are up to date to avoid one of the branches failing to fast
|
||||
forward while the other succeeds.
|
||||
|
||||
$ git push puppetlabs master:master
|
||||
$ git push origin master:master
|
||||
|
||||
That's it! The committer then updates the pull request, updates the issue in
|
||||
our issue tracker, and keeps an eye on the [build
|
||||
|
|
|
@ -68,7 +68,7 @@ a ticket number.
|
|||
|
||||
## Submitting Changes
|
||||
|
||||
* Sign the [Contributor License Agreement](http://links.puppetlabs.com/cla).
|
||||
* Sign the [Contributor License Agreement](http://links.puppet.com/cla).
|
||||
* Push your changes to a topic branch in your fork of the repository.
|
||||
* Submit a pull request to the repository in the puppetlabs organization.
|
||||
* Update your Jira ticket to mark that you have submitted code and are ready for it to be reviewed (Status: Ready for Merge).
|
||||
|
@ -81,9 +81,9 @@ a ticket number.
|
|||
|
||||
# Additional Resources
|
||||
|
||||
* [More information on contributing](http://links.puppetlabs.com/contribute-to-puppet)
|
||||
* [More information on contributing](http://links.puppet.com/contribute-to-puppet)
|
||||
* [Bug tracker (Jira)](http://tickets.puppetlabs.com)
|
||||
* [Contributor License Agreement](http://links.puppetlabs.com/cla)
|
||||
* [Contributor License Agreement](http://links.puppet.com/cla)
|
||||
* [General GitHub documentation](http://help.github.com/)
|
||||
* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
|
||||
* #puppet-dev IRC channel on freenode.org
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -4,7 +4,7 @@ gemspec
|
|||
|
||||
gem 'rgen'
|
||||
gem 'redcarpet'
|
||||
gem "yard", "~> 0.8.7"
|
||||
gem 'yard', '~> 0.9.5'
|
||||
|
||||
puppetversion = ENV['PUPPET_VERSION']
|
||||
|
||||
|
|
|
@ -0,0 +1,511 @@
|
|||
Puppet Strings JSON Data
|
||||
========================
|
||||
|
||||
Puppet Strings has two flags to the `generate` action that can be used to emit JSON data:
|
||||
|
||||
* `--emit-json <file>`: Emits the JSON data to the given file.
|
||||
* `--emit-json-stdout`: Emits the JSON data to STDOUT.
|
||||
|
||||
Document Schema
|
||||
===============
|
||||
|
||||
At the top level, there are five arrays in the JSON document:
|
||||
|
||||
| Document Key | Description |
|
||||
| ---------------- | ----------------------------------------------------------------------------- |
|
||||
| puppet_classes | The list of Puppet classes that were parsed. |
|
||||
| defined_types | The list of defined types that were parsed. |
|
||||
| resource_types | The list of resource types that were parsed. |
|
||||
| providers | The list of resource providers that were parsed. |
|
||||
| puppet_functions | The list of Puppet functions (3.x, 4.x and Puppet language) that were parsed. |
|
||||
|
||||
Puppet Classes
|
||||
--------------
|
||||
|
||||
Each entry in the `puppet_classes` list is an object with the following attributes:
|
||||
|
||||
| Attribute Key | Description |
|
||||
| ------------- | ----------------------------------------------------- |
|
||||
| name | The name of the Puppet class. |
|
||||
| file | The file defining the Puppet class. |
|
||||
| line | The line where the Puppet class is defined. |
|
||||
| inherits | The name of the Puppet class the class inherits from. |
|
||||
| docstring | The *DocString* object for the class (see below). |
|
||||
| defaults | The map of parameter names to default values. |
|
||||
| source | The Puppet source code for the class. |
|
||||
|
||||
Defined Types
|
||||
-------------
|
||||
|
||||
Each entry in the `defined_types` list is an object with the following attributes:
|
||||
|
||||
| Attribute Key | Description |
|
||||
| ------------- | -------------------------------------------------------- |
|
||||
| name | The name of the defined type. |
|
||||
| file | The file defining the defined type. |
|
||||
| line | The line where the defined type is defined. |
|
||||
| docstring | The *DocString* object for the defined type (see below). |
|
||||
| defaults | The map of parameter names to default values. |
|
||||
| source | The Puppet source code for the defined type. |
|
||||
|
||||
Resource Types
|
||||
--------------
|
||||
|
||||
Each entry in the `resource_types` list is an object with the following attributes:
|
||||
|
||||
| Attribute Key | Description |
|
||||
| ------------- | --------------------------------------------------------- |
|
||||
| name | The name of the resource type. |
|
||||
| file | The file defining the resource type. |
|
||||
| line | The line where the resource type is defined. |
|
||||
| docstring | The *DocString* object for the resource type (see below). |
|
||||
| properties | The list of properties for the resource type (see below). |
|
||||
| parameters | The list of parameters for the resource type (see below). |
|
||||
| features | The list of features for the resource type (see below). |
|
||||
|
||||
Each entry in the `properties` list is an object with the following attributes:
|
||||
|
||||
| Attribute Key | Description |
|
||||
| ------------- | ------------------------------------------------------- |
|
||||
| name | The name of the property. |
|
||||
| description | The description of the property. |
|
||||
| values | The array of acceptable string values for the property. |
|
||||
| aliases | The map of new values aliased to existing values. |
|
||||
| isnamevar | True if the property is a namevar or false if not. |
|
||||
| default | The default value for the property. |
|
||||
|
||||
Each entry in the `parameters` list is an object with the following attributes:
|
||||
|
||||
| Attribute Key | Description |
|
||||
| ------------- | -------------------------------------------------------- |
|
||||
| name | The name of the parameter. |
|
||||
| description | The description of the parameter. |
|
||||
| values | The array of acceptable string values for the parameter. |
|
||||
| aliases | The map of new values aliased to existing values. |
|
||||
| isnamevar | True if the parameter is a namevar or false if not. |
|
||||
| default | The default value for the parameter. |
|
||||
|
||||
Each entry in the `features` list is an object with the following attributes:
|
||||
|
||||
| Attribute Key | Description |
|
||||
| ------------- | ------------------------------- |
|
||||
| name | The name of the feature. |
|
||||
| description | The description of the feature. |
|
||||
|
||||
Providers
|
||||
---------
|
||||
|
||||
Each entry in the `providers` list is an object with the following attributes:
|
||||
|
||||
| Attribute Key | Description |
|
||||
| ------------- | ---------------------------------------------------- |
|
||||
| name | The name of the provider. |
|
||||
| type_name | The name of the resource type of the provider. |
|
||||
| file | The file defining the provider. |
|
||||
| line | The line where the provider is defined. |
|
||||
| docstring | The *DocString* object for the provider (see below). |
|
||||
| confines | The string map of confines for the provider. |
|
||||
| features | The list of features implemented by the provider. |
|
||||
| defaults | The string map of "default for" for the provider. |
|
||||
| commands | The string map of commands for the provider. |
|
||||
|
||||
Puppet Functions
|
||||
----------------
|
||||
|
||||
Each entry in the `puppet_functions` list is an object with the following attributes:
|
||||
|
||||
| Attribute Key | Description |
|
||||
| ------------- | ---------------------------------------------------- |
|
||||
| name | The name of the function. |
|
||||
| file | The file defining the provider. |
|
||||
| line | The line where the provider is defined. |
|
||||
| type | The function type (e.g. ruby3x, ruby4x, puppet). |
|
||||
| signature | The Puppet signature of the function (no overloads). |
|
||||
| docstring | The *DocString* object for the function (see below). |
|
||||
| defaults | The map of parameter names to default values. |
|
||||
| source | The source code for the function. |
|
||||
|
||||
DocString Objects
|
||||
-----------------
|
||||
|
||||
For the above types, their docstrings are represented as an object with the following attributes:
|
||||
|
||||
| Attribute Key | Description DocString |
|
||||
| ------------- | --------------------------------------------------- |
|
||||
| text | The textual part of the DocString. |
|
||||
| tags | The array of tag objects, if any are present. |
|
||||
|
||||
Each entry in the `tags` list is an object with the following properties:
|
||||
|
||||
| Attribute Key | Description |
|
||||
| ------------- | ------------------------------------------------------- |
|
||||
| tag_name | The name of the tag (e.g. param, return, etc.). |
|
||||
| text | The descriptive text of the tag. |
|
||||
| types | The array of types associated with the tag. |
|
||||
| name | The name associated with the tag (e.g. parameter name). |
|
||||
|
||||
For Puppet 4.x functions with overloads, `overload` tags will contain three additional attributes:
|
||||
|
||||
| Attribute Key | Description |
|
||||
| ------------- | ----------------------------------------------- |
|
||||
| signature | The Puppet signature of the overload. |
|
||||
| docstring | The *DocString* object describing the overload. |
|
||||
| defaults | The map of parameter names to default values. |
|
||||
|
||||
|
||||
Example JSON Document
|
||||
---------------------
|
||||
|
||||
An example JSON document describing a Puppet class, defined type, resource type, provider, and Puppet functions:
|
||||
|
||||
```json
|
||||
{
|
||||
"puppet_classes": [
|
||||
{
|
||||
"name": "foo",
|
||||
"file": "site.pp",
|
||||
"line": 5,
|
||||
"inherits": "foo::bar",
|
||||
"docstring": {
|
||||
"text": "A simple class.",
|
||||
"tags": [
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "First param.",
|
||||
"types": [
|
||||
"Integer"
|
||||
],
|
||||
"name": "param1"
|
||||
},
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "Second param.",
|
||||
"types": [
|
||||
"Any"
|
||||
],
|
||||
"name": "param2"
|
||||
},
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "Third param.",
|
||||
"types": [
|
||||
"String"
|
||||
],
|
||||
"name": "param3"
|
||||
}
|
||||
]
|
||||
},
|
||||
"defaults": {
|
||||
"param3": "hi"
|
||||
},
|
||||
"source": "class foo(Integer $param1, $param2, String $param3 = hi) inherits foo::bar {\n}"
|
||||
}
|
||||
],
|
||||
"defined_types": [
|
||||
{
|
||||
"name": "dt",
|
||||
"file": "site.pp",
|
||||
"line": 12,
|
||||
"docstring": {
|
||||
"text": "A simple defined type.",
|
||||
"tags": [
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "First param.",
|
||||
"types": [
|
||||
"Integer"
|
||||
],
|
||||
"name": "param1"
|
||||
},
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "Second param.",
|
||||
"types": [
|
||||
"Any"
|
||||
],
|
||||
"name": "param2"
|
||||
},
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "Third param.",
|
||||
"types": [
|
||||
"String"
|
||||
],
|
||||
"name": "param3"
|
||||
}
|
||||
]
|
||||
},
|
||||
"defaults": {
|
||||
"param3": "hi"
|
||||
},
|
||||
"source": "define dt(Integer $param1, $param2, String $param3 = hi) {\n}"
|
||||
}
|
||||
],
|
||||
"resource_types": [
|
||||
{
|
||||
"name": "database",
|
||||
"file": "database.rb",
|
||||
"line": 43,
|
||||
"docstring": {
|
||||
"text": "An example database server resource type."
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"name": "ensure",
|
||||
"description": "What state the database should be in.",
|
||||
"values": [
|
||||
"present",
|
||||
"absent",
|
||||
"up",
|
||||
"down"
|
||||
],
|
||||
"aliases": {
|
||||
"up": "present",
|
||||
"down": "absent"
|
||||
},
|
||||
"default": "up"
|
||||
},
|
||||
{
|
||||
"name": "file",
|
||||
"description": "The database file to use."
|
||||
},
|
||||
{
|
||||
"name": "log_level",
|
||||
"description": "The log level to use.",
|
||||
"values": [
|
||||
"debug",
|
||||
"warn",
|
||||
"error"
|
||||
],
|
||||
"default": "warn"
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "address",
|
||||
"description": "The database server name.",
|
||||
"isnamevar": true
|
||||
},
|
||||
{
|
||||
"name": "encryption_key",
|
||||
"description": "The encryption key to use."
|
||||
},
|
||||
{
|
||||
"name": "encrypt",
|
||||
"description": "Whether or not to encrypt the database.",
|
||||
"values": [
|
||||
"true",
|
||||
"false",
|
||||
"yes",
|
||||
"no"
|
||||
],
|
||||
"default": "false"
|
||||
}
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "encryption",
|
||||
"description": "The provider supports encryption."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"providers": [
|
||||
{
|
||||
"name": "linux",
|
||||
"type_name": "database",
|
||||
"file": "linux.rb",
|
||||
"line": 33,
|
||||
"docstring": {
|
||||
"text": "An example provider on Linux."
|
||||
},
|
||||
"confines": {
|
||||
"kernel": "Linux",
|
||||
"osfamily": "RedHat"
|
||||
},
|
||||
"features": [
|
||||
"implements_some_feature",
|
||||
"some_other_feature"
|
||||
],
|
||||
"defaults": {
|
||||
"kernel": "Linux"
|
||||
},
|
||||
"commands": {
|
||||
"foo": "/usr/bin/foo"
|
||||
}
|
||||
}
|
||||
],
|
||||
"puppet_functions": [
|
||||
{
|
||||
"name": "func",
|
||||
"file": "site.pp",
|
||||
"line": 20,
|
||||
"type": "puppet",
|
||||
"signature": "func(Integer $param1, Any $param2, String $param3 = hi)",
|
||||
"docstring": {
|
||||
"text": "A simple function.",
|
||||
"tags": [
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "First param.",
|
||||
"types": [
|
||||
"Integer"
|
||||
],
|
||||
"name": "param1"
|
||||
},
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "Second param.",
|
||||
"types": [
|
||||
"Any"
|
||||
],
|
||||
"name": "param2"
|
||||
},
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "Third param.",
|
||||
"types": [
|
||||
"String"
|
||||
],
|
||||
"name": "param3"
|
||||
},
|
||||
{
|
||||
"tag_name": "return",
|
||||
"text": "Returns nothing.",
|
||||
"types": [
|
||||
"Undef"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"defaults": {
|
||||
"param3": "hi"
|
||||
},
|
||||
"source": "function func(Integer $param1, $param2, String $param3 = hi) {\n}"
|
||||
},
|
||||
{
|
||||
"name": "func3x",
|
||||
"file": "func3x.rb",
|
||||
"line": 1,
|
||||
"type": "ruby3x",
|
||||
"signature": "func3x(String $first, Any $second)",
|
||||
"docstring": {
|
||||
"text": "An example 3.x function.",
|
||||
"tags": [
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "The first parameter.",
|
||||
"types": [
|
||||
"String"
|
||||
],
|
||||
"name": "first"
|
||||
},
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "The second parameter.",
|
||||
"types": [
|
||||
"Any"
|
||||
],
|
||||
"name": "second"
|
||||
},
|
||||
{
|
||||
"tag_name": "return",
|
||||
"text": "Returns nothing.",
|
||||
"types": [
|
||||
"Undef"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"source": "Puppet::Parser::Functions.newfunction(:func3x, doc: <<-DOC\nAn example 3.x function.\n@param [String] first The first parameter.\n@param second The second parameter.\n@return [Undef] Returns nothing.\nDOC\n) do |*args|\nend"
|
||||
},
|
||||
{
|
||||
"name": "func4x",
|
||||
"file": "func4x.rb",
|
||||
"line": 11,
|
||||
"type": "ruby4x",
|
||||
"docstring": {
|
||||
"text": "An example 4.x function.",
|
||||
"tags": [
|
||||
{
|
||||
"tag_name": "overload",
|
||||
"signature": "func4x(Integer $param1, Any $param2, Optional[Array[String]] $param3)",
|
||||
"docstring": {
|
||||
"text": "The first overload.",
|
||||
"tags": [
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "The first parameter.",
|
||||
"types": [
|
||||
"Integer"
|
||||
],
|
||||
"name": "param1"
|
||||
},
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "The second parameter.",
|
||||
"types": [
|
||||
"Any"
|
||||
],
|
||||
"name": "param2"
|
||||
},
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "The third parameter.",
|
||||
"types": [
|
||||
"Optional[Array[String]]"
|
||||
],
|
||||
"name": "param3"
|
||||
},
|
||||
{
|
||||
"tag_name": "return",
|
||||
"text": "Returns nothing.",
|
||||
"types": [
|
||||
"Undef"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "func4x"
|
||||
},
|
||||
{
|
||||
"tag_name": "overload",
|
||||
"signature": "func4x(Boolean $param, Callable &$block)",
|
||||
"docstring": {
|
||||
"text": "The second overload.",
|
||||
"tags": [
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "The first parameter.",
|
||||
"types": [
|
||||
"Boolean"
|
||||
],
|
||||
"name": "param"
|
||||
},
|
||||
{
|
||||
"tag_name": "param",
|
||||
"text": "The block parameter.",
|
||||
"types": [
|
||||
"Callable"
|
||||
],
|
||||
"name": "&block"
|
||||
},
|
||||
{
|
||||
"tag_name": "return",
|
||||
"text": "Returns a string.",
|
||||
"types": [
|
||||
"String"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "func4x"
|
||||
}
|
||||
]
|
||||
},
|
||||
"source": "Puppet::Functions.create_function(:func4x) do\n # The first overload.\n # @param param1 The first parameter.\n # @param param2 The second parameter.\n # @param param3 The third parameter.\n # @return [Undef] Returns nothing.\n dispatch :foo do\n param 'Integer', :param1\n param 'Any', :param2\n optional_param 'Array[String]', :param3\n end\n\n # The second overload.\n # @param param The first parameter.\n # @param block The block parameter.\n # @return [String] Returns a string.\n dispatch :other do\n param 'Boolean', :param\n block_param\n end\nend"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
401
README.md
401
README.md
|
@ -1,38 +1,41 @@
|
|||
Puppet Strings
|
||||
=============
|
||||
[](https://travis-ci.org/puppetlabs/puppetlabs-strings) [](https://badge.fury.io/rb/puppet-strings)
|
||||
==============
|
||||
[](https://travis-ci.org/puppetlabs/puppet-strings) [](https://badge.fury.io/rb/puppet-strings)
|
||||
|
||||
A Puppet Face and plugin built on the [YARD Documentation Tool](http://yardoc.org/) and the Puppet 4 Parser. It is uses YARD and the Puppet Parser to generate HTML documentation about Puppet code and Puppet extensions written in Ruby. It will eventually replace the `puppet doc` command once feature parity has been achieved.
|
||||
A Puppet command built on [YARD](http://yardoc.org/).
|
||||
|
||||
Puppet Strings generates HTML documentation for Puppet extensions written in Puppet and Ruby.
|
||||
|
||||
| | |
|
||||
| -------------- |------------------------------------------------------------ |
|
||||
| *Code* | [GitHub][repo] |
|
||||
| *Issues* | [Puppet Labs' JIRA Tracker][JIRA] |
|
||||
| *License* | [Apache 2.0][LICENSE] |
|
||||
| *Change log* | [CHANGELOG.md][changelog] |
|
||||
| *Contributing* | [CONTRIBUTING.md][contributing] and [COMMITTERS.md][committers]|
|
||||
This tool will eventually place the existing `puppet doc` command once feature parity has been achieved.
|
||||
|
||||
| | |
|
||||
| -------------- |---------------------------------------------------------------- |
|
||||
| *Code* | [GitHub][repo] |
|
||||
| *Issues* | [Puppet JIRA Tracker][JIRA] |
|
||||
| *License* | [Apache 2.0][LICENSE] |
|
||||
| *Change log* | [CHANGELOG.md][changelog] |
|
||||
| *Contributing* | [CONTRIBUTING.md][contributing] and [COMMITTERS.md][committers] |
|
||||
|
||||
[repo]: https://github.com/puppetlabs/puppetlabs-strings
|
||||
[repo]: https://github.com/puppetlabs/puppet-strings
|
||||
[JIRA]: https://tickets.puppetlabs.com/browse/PDOC
|
||||
[LICENSE]: https://github.com/puppetlabs/puppetlabs-strings/blob/master/LICENSE
|
||||
[changelog]: https://github.com/puppetlabs/puppetlabs-strings/blob/master/CHANGELOG.md
|
||||
[contributing]: https://github.com/puppetlabs/puppetlabs-strings/blob/master/CONTRIBUTING.md
|
||||
[committers]: https://github.com/puppetlabs/puppetlabs-strings/blob/master/COMMITTERS.md
|
||||
[LICENSE]: https://github.com/puppetlabs/puppet-strings/blob/master/LICENSE
|
||||
[changelog]: https://github.com/puppetlabs/puppet-strings/blob/master/CHANGELOG.md
|
||||
[contributing]: https://github.com/puppetlabs/puppet-strings/blob/master/CONTRIBUTING.md
|
||||
[committers]: https://github.com/puppetlabs/puppet-strings/blob/master/COMMITTERS.md
|
||||
|
||||
Installation
|
||||
Requirements
|
||||
------------
|
||||
|
||||
In order to run strings you need to have the following software installed:
|
||||
|
||||
* Ruby 1.9.3 or newer
|
||||
* Puppet 3.7 or newer
|
||||
* The YARD RubyGem
|
||||
* The `yard` Ruby gem
|
||||
|
||||
Installing the YARD Gem
|
||||
-----------------------
|
||||
**Installing the YARD Gem with Puppet**
|
||||
|
||||
The easiest way to install the YARD gem is with Puppet itself.
|
||||
The easiest way to install the `yard` gem is with Puppet itself:
|
||||
|
||||
For Puppet 4.x:
|
||||
```
|
||||
|
@ -44,11 +47,12 @@ For Puppet 3.x:
|
|||
$ puppet resource package yard provider=gem
|
||||
```
|
||||
|
||||
Installing Strings Itself
|
||||
Installing Puppet Strings
|
||||
-------------------------
|
||||
**PLEASE NOTE** that Strings was previously distributed via the puppetlabs-strings module. This is no longer the preferred method of installation as the module will not longer receive updates. So even though there is still a module on the Puppet Forge, please use the RubyGem.
|
||||
|
||||
Strings can be installed using the [puppet-strings RubyGem](https://rubygems.org/gems/puppet-strings). To ensure it is installed in right place, it is best to install it using Puppet.
|
||||
Strings can be installed using the [puppet-strings](https://rubygems.org/gems/puppet-strings) gem.
|
||||
|
||||
To ensure it is installed in right place, it is best to install it using Puppet:
|
||||
|
||||
For Puppet 4.x:
|
||||
```
|
||||
|
@ -70,30 +74,34 @@ $ cd /path/to/module
|
|||
$ puppet strings
|
||||
```
|
||||
|
||||
This processes `README` and all puppet and ruby files under `manifests/`
|
||||
and `lib/`.
|
||||
This processes `README` and all Puppet and Ruby source files under the `./manifests/`, `./functions/`, and `./lib/`
|
||||
directories by default and creates HTML documentation under the `./doc/` directory.
|
||||
|
||||
To document specific files:
|
||||
|
||||
```
|
||||
$ puppet strings some_manifest.pp [another_if_you_feel_like_it.rb]
|
||||
$ puppet strings generate first.pp second.pp ...
|
||||
```
|
||||
|
||||
Strings can also emit the generated documentation as JSON:
|
||||
To document specific directories:
|
||||
|
||||
```
|
||||
$ puppet strings yardoc some_manifest.pp --emit-json documentation.json
|
||||
$ puppet strings 'modules/foo/lib/**/*.rb' 'modules/foo/manifests/**/*.pp' 'modules/foo/functions/**/*.pp' ...
|
||||
```
|
||||
|
||||
Strings can emit JSON documenting the Puppet extensions:
|
||||
|
||||
```
|
||||
$ puppet strings generate --emit-json documentation.json
|
||||
```
|
||||
|
||||
It can also print the JSON to stdout:
|
||||
|
||||
```
|
||||
$ puppet strings yardoc some_manifest.pp --emit-json-stdout
|
||||
$ puppet strings generate --emit-json-stdout
|
||||
```
|
||||
|
||||
The schema for the JSON which Strings emits is [well documented](https://github.com/puppetlabs/puppetlabs-strings/blob/master/json_dom.md).
|
||||
|
||||
Processing is delegated to the `yardoc` tool so some options listed in `yard help doc` are available. However, Puppet Faces do not support passing arbitrary options through a face so these options must be specified in a `.yardopts` file.
|
||||
The schema for the JSON output is [documented here](https://github.com/puppetlabs/puppet-strings/blob/master/JSON.md).
|
||||
|
||||
In addition to generating a directory full of HTML, you can also serve up documentation for all your modules using the `server` action:
|
||||
|
||||
|
@ -101,157 +109,290 @@ In addition to generating a directory full of HTML, you can also serve up docume
|
|||
$ puppet strings server
|
||||
```
|
||||
|
||||
Writing Compatible Documentation
|
||||
--------------------------------
|
||||
YARD Options
|
||||
------------
|
||||
|
||||
Since the strings module is built around YARD, a few different comment formats can be used. YARD can work with RDoc, meaning it is backwards compatible with previously documented modules. Feel free to try out strings with RDoc, but we are planning to move to Markdown as the standard. You can configure which you would like YARD to use by adding a `.yardopts` file to the root of your module directory which specifies the desired format:
|
||||
YARD options (see `yard help doc`) are supported in a `.yardopts` file in the same directory where `puppet strings` is run.
|
||||
|
||||
```
|
||||
--markup markdown
|
||||
```
|
||||
Puppet Strings automatically sets the `markup` option to `markdown`, allowing your documentation strings to be in Markdown format.
|
||||
|
||||
While we have yet to decide exactly how documentation should work in the future, here are some very basic examples to get you started using the strings module. These are very much subject to change as we continue to work out a style guide.
|
||||
Documenting Puppet Extensions
|
||||
-----------------------------
|
||||
|
||||
### Functions
|
||||
Here's an example of how you might document a 4x function:
|
||||
### Puppet Classes / Defined Types
|
||||
|
||||
```ruby
|
||||
# When given two numbers, returns the one that is larger.
|
||||
# You could have a several line description here if you wanted,
|
||||
# but I don't have much to say about this function.
|
||||
#
|
||||
# @example using two integers
|
||||
# $bigger_int = max(int_one, int_two)
|
||||
#
|
||||
# @return [Integer] the larger of the two parameters
|
||||
#
|
||||
# @param num_a [Integer] the first number to be compared
|
||||
# @param num_b [Integer] the second number to be compared
|
||||
Puppet::Functions.create_function(:max) do
|
||||
def max(num_a, num_b)
|
||||
num_a >= num_b ? num_a : num_b
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Classes / Defined Types
|
||||
|
||||
Here's an example of how you might document a class:
|
||||
To document Puppet classes and defined types, use a YARD docstring before the class or defined type definition:
|
||||
|
||||
```puppet
|
||||
# This class is meant to serve as an example of how one might
|
||||
# want to document a manifest in a way that is compatible.
|
||||
# with the strings module
|
||||
# An example class.
|
||||
#
|
||||
# @example when declaring the example class
|
||||
# This is an example of how to document a Puppet class
|
||||
#
|
||||
# @example Declaring the class
|
||||
# include example
|
||||
#
|
||||
# @param first_arg The first parameter for this class
|
||||
# @param second_arg The second paramter for this class
|
||||
class example (
|
||||
$first_arg = $example::params::first_arg,
|
||||
$second_arg = $exampe::params::second_arg,
|
||||
) { }
|
||||
# @param first The first parameter for this class
|
||||
# @param second The second paramter for this class
|
||||
class example_class(
|
||||
String $first = $example::params::first_arg,
|
||||
Integer $second = $example::params::second_arg,
|
||||
) inherits example::params {
|
||||
# ...
|
||||
}
|
||||
|
||||
# An example defined type.
|
||||
#
|
||||
# This is an example of how to document a defined type.
|
||||
# @param ports The array of port numbers to use.
|
||||
define example_type(
|
||||
Array[Integer] $ports = []
|
||||
) {
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
### Types and Providers
|
||||
Strings will automatically extract the `@doc` provider docstring and any `desc` parameter/property docstrings.
|
||||
***Note: unlike Ruby, Puppet is a typed language; Puppet Strings will automatically use the parameter type information to
|
||||
document the parameters. A warning will be emitted if you document parameter types.***
|
||||
|
||||
Sometimes however, Puppet types use metaprogramming to create parameters and methods automatically. In those cases Strings will not be able to document them automatically (Strings doesn't execute the code that would generate those parameters), so you will need to provide hints on how to document your code. To document a parameter which is automatically created you must use the special directive `@!puppet.type.param` which may take types, the parameter name, and a description.
|
||||
### Resource Types
|
||||
|
||||
To document custom resource types and their parameters/properties, use the `desc` method or assign a value to the `doc` attribute:
|
||||
|
||||
```ruby
|
||||
# @!puppet.type.param my_parameter This parameter needs to be explicitly
|
||||
# documented as it is generated by mk_resource_methods
|
||||
Puppet::Type.newtype(:minifile) do
|
||||
|
||||
@doc = "Manages files, including their content, ownership, and permissions.
|
||||
The provider can manage symbolic links."
|
||||
|
||||
# This function does some metaprogramming on the new type.
|
||||
mk_resource_methods
|
||||
|
||||
newparam(:path) do
|
||||
desc <<-'EOT'
|
||||
The path to the file to manage. Must be fully qualified.
|
||||
EOT
|
||||
# ... do stuff here
|
||||
Puppet::Type.newtype(:example) do
|
||||
desc <<-DESC
|
||||
An example resource type.
|
||||
@example Using the type.
|
||||
example { foo:
|
||||
param => 'hi'
|
||||
}
|
||||
DESC
|
||||
|
||||
newparam(:param) do
|
||||
desc 'An example parameter.'
|
||||
# ...
|
||||
end
|
||||
|
||||
newproperty(:prop) do
|
||||
desc 'An example property.'
|
||||
#...
|
||||
end
|
||||
|
||||
# ...
|
||||
end
|
||||
```
|
||||
|
||||
Puppet Strings documents this way to preserve backwards compatibility with `puppet doc` and existing resource types.
|
||||
|
||||
***Note: Puppet Strings does not evaluate your Ruby code, so only certain static expressions are supported.***
|
||||
|
||||
To document parameters and properties that are dynamically created, use the `#@!puppet.type.param` and `#@!puppet.type.property`
|
||||
directives before the `newtype` call:
|
||||
|
||||
```ruby
|
||||
# @!puppet.type.param [value1, value2, value3] my_param Documentation for a dynamic parameter.
|
||||
# @!puppet.type.property [foo, bar, baz] my_prop Documentation for a dynamic property.
|
||||
Puppet::Type.newtype(:example) do
|
||||
#...
|
||||
end
|
||||
```
|
||||
|
||||
### Providers
|
||||
|
||||
To document providers, use the `desc` method or assign a value to the `doc` attribute:
|
||||
|
||||
```ruby
|
||||
Puppet::Type.type(:example).provide :platform do
|
||||
desc 'An example provider.'
|
||||
|
||||
# ...
|
||||
end
|
||||
|
||||
|
||||
```
|
||||
|
||||
Puppet Strings documents this way to preserve backwards compatibility with `puppet doc` and existing resource types.
|
||||
|
||||
***Note: Puppet Strings does not evaluate your Ruby code, so only certain static expressions are supported.***
|
||||
|
||||
### Functions
|
||||
|
||||
Puppet Strings supports three different ways of defining a function in Puppet: with the Puppet 3.x API, Puppet 4.X API,
|
||||
and in the Puppet language itself.
|
||||
|
||||
## Puppet 3.x API
|
||||
|
||||
To document a function in the Puppet 3.x API, use the `doc` option to `newfunction`:
|
||||
|
||||
```ruby
|
||||
Puppet::Parser::Functions.newfunction(:example, doc: <<-DOC
|
||||
Documentation for an example 3.x function.
|
||||
@param [String] param1 The first parameter.
|
||||
@param [Integer] param2 The second parameter.
|
||||
@return [Undef]
|
||||
@example Calling the function.
|
||||
example('hi', 10)
|
||||
DOC
|
||||
) do |*args|
|
||||
#...
|
||||
end
|
||||
```
|
||||
|
||||
***Note: if parameter types are omitted, a default of the `Any` Puppet type will be used.***
|
||||
|
||||
## Puppet 4.x API
|
||||
|
||||
To document a function in the Puppet 4.x API, use a YARD docstring before the `create_function` call and any `dispatch`
|
||||
calls:
|
||||
|
||||
```ruby
|
||||
# An example 4.x function.
|
||||
Puppet::Functions.create_function(:example) do
|
||||
# @param first The first parameter.
|
||||
# @param second The second parameter.
|
||||
# @return [String] Returns a string.
|
||||
# @example Calling the function
|
||||
# example('hi', 10)
|
||||
dispatch :example do
|
||||
param 'String', :first
|
||||
param 'Integer', :second
|
||||
end
|
||||
|
||||
# ...
|
||||
end
|
||||
```
|
||||
|
||||
***Note: Puppet Strings will automatically use the parameter type information from the `dispatch` block to document
|
||||
the parameters. Only document your parameter types when the Puppet 4.x function contains no `dispatch` calls.***
|
||||
|
||||
If the Puppet 4.x function contains multiple `dispatch` calls, Puppet Strings will automatically create `overload` tags
|
||||
to describe the function's overloads:
|
||||
|
||||
```ruby
|
||||
# An example 4.x function.
|
||||
Puppet::Functions.create_function(:example) do
|
||||
# Overload by string.
|
||||
# @param first The first parameter.
|
||||
# @return [String] Returns a string.
|
||||
# @example Calling the function
|
||||
# example('hi')
|
||||
dispatch :example_string do
|
||||
param 'String', :first
|
||||
end
|
||||
|
||||
# Overload by integer.
|
||||
# @param first The first parameter.
|
||||
# @return [Integer] Returns an integer.
|
||||
# @example Calling the function
|
||||
# example(10)
|
||||
dispatch :example_integer do
|
||||
param 'Integer', :first
|
||||
end
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
The resulting HTML for this example function will document both `example(String $first)` and `example(Integer $first)`.
|
||||
|
||||
## Puppet Language
|
||||
|
||||
To document Puppet functions written in the Puppet language, use a YARD docstring before the function definition:
|
||||
|
||||
```puppet
|
||||
# An example function written in Pupppet.
|
||||
# @param name The name to say hello to.
|
||||
# @return [String] Returns a string.
|
||||
# @example Calling the function
|
||||
# example('world')
|
||||
function example(String $name) {
|
||||
"hello $name"
|
||||
}
|
||||
```
|
||||
|
||||
***Note: Puppet Strings will automatically use the parameter type information from the function's parameters to document
|
||||
the parameters.***
|
||||
|
||||
Additional Resources
|
||||
--------------------
|
||||
|
||||
Here are a few other good resources for getting started with documentation:
|
||||
|
||||
* [Module README Template](https://docs.puppetlabs.com/puppet/latest/reference/modules_documentation.html)
|
||||
* [Module README Template](https://docs.puppet.com/puppet/latest/reference/modules_documentation.html)
|
||||
* [YARD Getting Started Guide](http://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md)
|
||||
* [YARD Tags Overview](http://www.rubydoc.info/gems/yard/file/docs/Tags.md)
|
||||
|
||||
Rake Tasks
|
||||
-----
|
||||
----------
|
||||
|
||||
This module is also available as a Gem and makes three rake tasks (`strings:generate`, `strings:serve`, and `strings:gh_pages`) available in `puppet-strings/rake_tasks`. To add this to your module's CI workflow, be sure to add this module to your `Gemfile`:
|
||||
Puppet Strings comes with two rake tasks: `strings:generate` and `strings:gh_pages:update` available in `puppet-strings/tasks`.
|
||||
|
||||
In addition to generating the usual 'doc' directory of HTML documentation, the `strings:generate` rake task will also drop a strings.json file containing a JSON representation of the module into the directory the rake task was run from.
|
||||
Add the following to your Gemfile to use `puppet-strings`:
|
||||
|
||||
```ruby
|
||||
gem 'puppet-strings', :git => 'https://github.com/puppetlabs/puppetlabs-strings.git'
|
||||
gem 'puppet-strings', :git => 'https://github.com/puppetlabs/puppet-strings.git'
|
||||
```
|
||||
|
||||
To use the rake tasks, `require puppet-strings/rake_tasks` in your `Rakefile`:
|
||||
In your `Rakefile`, add the following to use the `puppet-strings` tasks:
|
||||
|
||||
```ruby
|
||||
require 'puppet-strings/rake_tasks'
|
||||
require 'puppet-strings/tasks'
|
||||
```
|
||||
|
||||
The task `strings:generate` which is provided by including `puppet-strings/rake_tasks` will scan the manifests and lib directory from your single module. If you need to document a complete, or part of a, puppet tree, you can use the `PuppetStrings::RakeTasks::Generate` task. This rake task will by default overwrite strings:generate unless you specify a custom name. See the example below on how you can use it and which options it supports.
|
||||
The `strings:generate` task can be used to generate documentation:
|
||||
|
||||
```ruby
|
||||
require 'puppet-strings/rake_tasks/generate'
|
||||
|
||||
PuppetStrings::RakeTasks::Generate.new(:documentation) do |task|
|
||||
task.paths = ['site/roles','site/profiles','modules/internal']
|
||||
task.excludes = ['/vendor/','/example/']
|
||||
task.options = {} # disables the strings.json output
|
||||
# module_resourcefiles are the patterns of included files. Below is the default.
|
||||
# task.module_resourcefiles = ['manifests/**/*.pp', 'lib/**/*.rb']
|
||||
end
|
||||
```
|
||||
$ rake strings:generate
|
||||
```
|
||||
|
||||
The `strings:gh_pages` task will generate your Strings documentation to be made available via [GitHub Pages](https://pages.github.com/). It will:
|
||||
The task accepts the following parameters:
|
||||
|
||||
1. Create a `doc` directory in the root of your project
|
||||
2. Check out the `gh-pages` branch of the current repository in the `doc` directory (it will create a branch if one does not already exist)
|
||||
3. Generate strings documentation using the `strings:generate` task
|
||||
4. Commit the changes and push them to the `gh-pages` branch **with the `-f` flag**
|
||||
* `patterns`: the search patterns to use for finding files to document (defaults to `manifests/**/*.pp functions/**/*.pp types/**/*.pp lib/**/*.rb`).
|
||||
* `debug`: enables debug output when set to `true`.
|
||||
* `backtrace`: enables backtraces for errors when set to `true`.
|
||||
* `markup`: the markup language to use (defaults to `markdown`).
|
||||
* `yard_args`: additional arguments to pass to YARD.
|
||||
|
||||
This task aims to keep the `gh-pages` branch up to date with the current code and uses the `-f` flag when pushing to the `gh-pages` branch. Please keep this in mind as it **will be destructive** if not used properly.
|
||||
An example of passing arguments to the `strings:generate` Rake task:
|
||||
|
||||
```
|
||||
$ rake strings:generate\['**/*.pp **/*.rb, true, true, markdown, --readme README.md']
|
||||
```
|
||||
|
||||
The `strings:gh_pages:update` task will generate your Puppet Strings documentation to be made available via [GitHub Pages](https://pages.github.com/). It will:
|
||||
|
||||
1. Create a `doc` directory in the root of your project
|
||||
2. Check out the `gh-pages` branch of the current repository in the `doc` directory (it will create a branch if one does not already exist)
|
||||
3. Generate strings documentation using the `strings:generate` task
|
||||
4. Commit the changes and push them to the `gh-pages` branch **with the `--force` flag**
|
||||
|
||||
This task aims to keep the `gh-pages` branch up to date with the current code and uses the `-f` flag when pushing to the `gh-pages` branch.
|
||||
***Please note this operation will be destructive if not used properly.***
|
||||
|
||||
Developing and Contributing
|
||||
-----
|
||||
---------------------------
|
||||
|
||||
We love contributions from the community! If you'd like to contribute to the strings module, check out [CONTRIBUTING.md](https://github.com/puppetlabs/puppetlabs-strings/blob/master/CONTRIBUTING.md) to get information on the contribution process.
|
||||
We love contributions from the community!
|
||||
|
||||
If you'd like to contribute to the strings module, check out [CONTRIBUTING.md](https://github.com/puppetlabs/puppet-strings/blob/master/CONTRIBUTING.md) to get information on the contribution process.
|
||||
|
||||
Running Specs
|
||||
-----
|
||||
-------------
|
||||
|
||||
If you're going to be doing any development with puppet strings, it's essential that you can run the spec tests. You should simply have to do the following:
|
||||
If you plan on developing features or fixing bugs in Puppet Strings, it is essential that you run specs before opening a pull request.
|
||||
|
||||
To run specs, simply execute the `spec` rake task:
|
||||
|
||||
$ bundle install --path .bundle/gems
|
||||
$ bundle exec rake spec
|
||||
|
||||
Support
|
||||
-----
|
||||
Please log tickets and issues at our [JIRA tracker][JIRA]. A [mailing list](https://groups.google.com/forum/?fromgroups#!forum/puppet-users) is available for asking questions and getting help from others. In addition there is an active #puppet channel on Freenode.
|
||||
|
||||
We use semantic version numbers for our releases, and recommend that users stay as up-to-date as possible by upgrading to patch releases and minor releases as they become available.
|
||||
|
||||
Bugfixes and ongoing development will occur in minor releases for the current major version. Security fixes will be backported to a previous major version on a best-effort basis, until the previous major version is no longer maintained.
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
- Documentation blocks must immediately precede the documented code with no whitespace. This is because the comment extractor possesses the elegance and intelligence of a bag of hammers.
|
||||
Please log tickets and issues at our [JIRA tracker][JIRA]. A [mailing list](https://groups.google.com/forum/?fromgroups#!forum/puppet-users)
|
||||
is available for asking questions and getting help from others.
|
||||
|
||||
- This project is very much a work in progress and may very well have undiscovered bugs and pitfalls. If you discover any of these, [please file a ticket](https://tickets.puppetlabs.com/browse/PDOC).
|
||||
There is also an active #puppet channel on the Freenode IRC network.
|
||||
|
||||
We use semantic version numbers for our releases, and recommend that users stay as up-to-date as possible by upgrading to
|
||||
patch releases and minor releases as they become available.
|
||||
|
||||
Bug fixes and ongoing development will occur in minor releases for the current major version.
|
||||
Security fixes will be ported to a previous major version on a best-effort basis, until the previous major version is no longer maintained.
|
||||
|
|
23
Rakefile
23
Rakefile
|
@ -1,18 +1,19 @@
|
|||
require 'rubygems'
|
||||
require 'puppetlabs_spec_helper/rake_tasks'
|
||||
require 'puppet-lint/tasks/puppet-lint'
|
||||
PuppetLint.configuration.send('disable_80chars')
|
||||
PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]
|
||||
|
||||
desc "Validate manifests, templates, and ruby files"
|
||||
# Add our own tasks
|
||||
require 'puppet-strings/tasks'
|
||||
|
||||
PuppetLint.configuration.send('disable_80chars')
|
||||
PuppetLint.configuration.ignore_paths = %w(acceptance/**/*.pp spec/**/*.pp pkg/**/*.pp)
|
||||
|
||||
desc 'Validate Ruby source files and ERB templates.'
|
||||
task :validate do
|
||||
Dir['manifests/**/*.pp'].each do |manifest|
|
||||
sh "puppet parser validate --noop #{manifest}"
|
||||
end
|
||||
Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file|
|
||||
sh "ruby -c #{ruby_file}" unless ruby_file =~ /spec\/fixtures/
|
||||
end
|
||||
Dir['templates/**/*.erb'].each do |template|
|
||||
Dir['lib/puppet-strings/yard/templates/**/*.erb'].each do |template|
|
||||
sh "erb -P -x -T '-' #{template} | ruby -c"
|
||||
end
|
||||
end
|
||||
|
@ -28,16 +29,16 @@ task :acceptance do
|
|||
end
|
||||
|
||||
cli = BeakerHostGenerator::CLI.new([target])
|
||||
nodeset_dir = "spec/acceptance/nodesets"
|
||||
nodeset_dir = 'acceptance/nodesets'
|
||||
nodeset = "#{nodeset_dir}/#{target}.yml"
|
||||
FileUtils.mkdir_p(nodeset_dir)
|
||||
File.open(nodeset, 'w') do |fh|
|
||||
fh.print(cli.execute)
|
||||
end
|
||||
puts nodeset
|
||||
sh "gem build puppet-strings.gemspec"
|
||||
sh "puppet module build spec/unit/puppet/examples/test"
|
||||
sh "BEAKER_set=#{ENV["platform"]} rspec spec/acceptance/*.rb"
|
||||
sh 'gem build puppet-strings.gemspec'
|
||||
sh 'puppet module build acceptance/fixtures/modules/test'
|
||||
sh "BEAKER_set=#{ENV['platform']} rspec acceptance/*.rb"
|
||||
end
|
||||
|
||||
task(:rubocop) do
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
require 'spec_helper_acceptance'
|
||||
require 'json'
|
||||
|
||||
describe 'Generating module documentation using generate action' do
|
||||
def read_file_on(host, filename)
|
||||
on(host, "cat #{filename}").stdout
|
||||
end
|
||||
|
||||
before :all do
|
||||
modules = JSON.parse(on(master, puppet('module', 'list', '--render-as', 'json')).stdout)
|
||||
test_module_info = modules['modules_by_path'].values.flatten.find { |mod_info| mod_info =~ /Module test/ }
|
||||
test_module_path = test_module_info.match(/\(([^)]*)\)/)[1]
|
||||
|
||||
on master, puppet('strings', 'generate', "#{test_module_path}/**/*.{rb,pp}")
|
||||
end
|
||||
|
||||
it 'should generate documentation for manifests' do
|
||||
expect(read_file_on(master, '/root/doc/puppet_classes/test.html')).to include('Class: test')
|
||||
end
|
||||
|
||||
it 'should generate documentation for 3x functions' do
|
||||
expect(read_file_on(master, '/root/doc/puppet_functions_ruby3x/function3x.html')).to include('This is the function documentation for function3x')
|
||||
end
|
||||
|
||||
it 'should generate documentation for 4x functions' do
|
||||
expect(read_file_on(master, '/root/doc/puppet_functions_ruby4x/function4x.html')).to include('This is a function which is used to test puppet strings')
|
||||
end
|
||||
end
|
121
json_dom.md
121
json_dom.md
|
@ -1,121 +0,0 @@
|
|||
The Strings JSON Interchange Schema
|
||||
===================================
|
||||
|
||||
Strings has two flags used to emit json.
|
||||
* `--emit-json $FILE` Saves json to a file.
|
||||
* `--emit-json-stdout` Prints json on stdout.
|
||||
|
||||
Top Level Structure
|
||||
-------------------
|
||||
|
||||
The json outputted by strings is a single object which has 4 keys representing
|
||||
the different types of Puppet code and extension functions Strings reads. The
|
||||
value for each key is a list of json objects representing each puppet class,
|
||||
function, etc.
|
||||
Here is an example of the top level structure:
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
"defined_types": [...],
|
||||
|
||||
"puppet_classes": [...],
|
||||
|
||||
"puppet_functions": [...],
|
||||
|
||||
"puppet_types": [...],
|
||||
|
||||
"puppet_providers": [...]
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Defined Types
|
||||
-------------
|
||||
|
||||
Each defined type or puppet class object has the following properties and values:
|
||||
|
||||
* `name`: A string representing the name of the object.
|
||||
* `file`: The file the object came from. A string.
|
||||
* `line`: The line in the file the object came from. A number.
|
||||
* `docstring`: A string. The docstring describing the object.
|
||||
* `examples`: A list of strings representing the content of the examples in the
|
||||
docstring.
|
||||
* `signatures`: A list of function signatures which may be supported by the
|
||||
object. Each function signature is a json object whose keys are the
|
||||
parameter names, and whose values are the types those parameters may take.
|
||||
This is extracted from the code itself.
|
||||
* `parameters`: An object whose keys are the parameter names and whose values
|
||||
are the parameter's types or null if it has no types. This is extracted from
|
||||
the docstring.
|
||||
|
||||
|
||||
Puppet Functions
|
||||
----------------
|
||||
|
||||
Both puppet 4x and 3x functions are represented as json objects kept in the
|
||||
`puppet_functions` list. Puppet 4x functions have every property that 3x
|
||||
functions have, as well as a few extras.
|
||||
|
||||
Puppet 3x functions have:
|
||||
|
||||
* `name`: A string representing the name of the
|
||||
* `file`: The file the object came from. A string.
|
||||
* `line`: The line in the file the object came from. A number.
|
||||
* `docstring`: A string. The docstring describing our object.
|
||||
* `function_api_version`: the number 3.
|
||||
* `documented_params`: A object whose keys are the parameters which were
|
||||
* documented and whose values are the types they may take, or null.
|
||||
* `examples`: A list of strings representing the content of the examples in the
|
||||
docstring.
|
||||
|
||||
Puppet 4x functions have everything 3x functions do as well as:
|
||||
|
||||
* The `function_api_version` is the number 4, not 3 (surprise!).
|
||||
* `signatures`: A list of function signatures which may be supported by the
|
||||
object. Each function signature is a json object whose keys are the parameter
|
||||
names, and whose values are the types those parameters may take. This is
|
||||
extracted from the code itself.
|
||||
|
||||
Puppet Types
|
||||
------------
|
||||
|
||||
Each puppet type object has the following properties and values:
|
||||
|
||||
* `name`: A string representing the name of the object
|
||||
* `file`: The file the object came from. A string.
|
||||
* `line`: The line in the file the object came from. A number.
|
||||
* `docstring`: A string. The docstring describing our object.
|
||||
* `examples`: A list of strings representing the content of the examples in the
|
||||
docstring.
|
||||
* `parameters`: A list of objects with the following shape:
|
||||
* `allowed_vales`: a list of strings representing the allowed values.
|
||||
* `default`: a string or null.
|
||||
* `docstring`: The docstring.
|
||||
* `name`: the parameter name.
|
||||
* `properties`: A list of objects with a shape very similar to parameters but
|
||||
also including:
|
||||
* `namevar`: A boolean.
|
||||
* `features`: A list of objects representing possible features. They have the
|
||||
following shape:
|
||||
* `docstring`: The description of the feature.
|
||||
* `methods`: null or a list of the available methods as strings.
|
||||
* `name`: The feature's name.
|
||||
|
||||
Puppet Providers
|
||||
----------------
|
||||
Each puppet provider object has the following properties and values:
|
||||
|
||||
* `name`: A string representing the name of the object
|
||||
* `file`: The file the object came from. A string.
|
||||
* `line`: The line in the file the object came from. A number.
|
||||
* `docstring`: A string. The docstring describing the object.
|
||||
* `examples`: A list of strings representing the content of the examples in the
|
||||
docstring.
|
||||
* `commands`: A list of the names of the commands available.
|
||||
* `confines`: An object whose keys are the confine keys and whose values are
|
||||
the confine values.
|
||||
* `defaults`: Similar to above.
|
||||
* `features`: A list of strings representing the features this provider
|
||||
supports.
|
||||
* `type_name`: The type this provider accompanies.
|
|
@ -0,0 +1,63 @@
|
|||
# The root module for Puppet Strings.
|
||||
module PuppetStrings
|
||||
# The glob patterns used to search for files to document.
|
||||
DEFAULT_SEARCH_PATTERNS = %w(
|
||||
manifests/**/*.pp
|
||||
functions/**/*.pp
|
||||
types/**/*.pp
|
||||
lib/**/*.rb
|
||||
).freeze
|
||||
|
||||
# Generates documentation.
|
||||
# @param [Array<String>] search_patterns The search patterns (e.g. manifests/**/*.pp) to look for files.
|
||||
# @param [Hash] options The options hash.
|
||||
# @option options [Boolean] :debug Enable YARD debug output.
|
||||
# @option options [Boolean] :backtrace Enable YARD backtraces.
|
||||
# @option options [String] :markup The YARD markup format to use (defaults to 'markdown').
|
||||
# @option options [String] :json Enables JSON output to the given file. If the file is nil, STDOUT is used.
|
||||
# @option options [Array<String>] :yard_args The arguments to pass to yard.
|
||||
# @return [void]
|
||||
def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {})
|
||||
require 'puppet-strings/yard'
|
||||
PuppetStrings::Yard.setup!
|
||||
|
||||
# Format the arguments to YARD
|
||||
args = ['doc']
|
||||
args << '--debug' if options[:debug]
|
||||
args << '--backtrace' if options[:backtrace]
|
||||
args << "-m#{options[:markup] || 'markdown'}"
|
||||
|
||||
render_as_json = options.key? :json
|
||||
json_file = nil
|
||||
if render_as_json
|
||||
json_file = options[:json]
|
||||
# Disable output and prevent stats/progress when writing to STDOUT
|
||||
args << '-n'
|
||||
args << '-q' unless json_file
|
||||
args << '--no-stats' unless json_file
|
||||
args << '--no-progress' unless json_file
|
||||
end
|
||||
|
||||
yard_args = options[:yard_args]
|
||||
args += yard_args if yard_args
|
||||
args += search_patterns
|
||||
|
||||
# Run YARD
|
||||
YARD::CLI::Yardoc.run(*args)
|
||||
|
||||
# If outputting JSON, render the output
|
||||
if render_as_json
|
||||
require 'puppet-strings/json'
|
||||
PuppetStrings::Json.render(json_file)
|
||||
end
|
||||
end
|
||||
|
||||
# Runs the YARD documentation server.
|
||||
# @param [Array<String>] args The arguments to YARD.
|
||||
def self.run_server(*args)
|
||||
require 'puppet-strings/yard'
|
||||
PuppetStrings::Yard.setup!
|
||||
|
||||
YARD::CLI::Server.run(*args)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,49 @@
|
|||
require 'json'
|
||||
|
||||
# The module for JSON related functionality.
|
||||
module PuppetStrings::Json
|
||||
# Renders the current YARD registry as JSON to the given file (or STDOUT if nil).
|
||||
# @param [String] file The path to the output file to render the registry to. If nil, output will be to STDOUT.
|
||||
# @return [void]
|
||||
def self.render(file = nil)
|
||||
document = {
|
||||
puppet_classes: YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash),
|
||||
defined_types: YARD::Registry.all(:puppet_defined_type).sort_by!(&:name).map!(&:to_hash),
|
||||
resource_types: YARD::Registry.all(:puppet_type).sort_by!(&:name).map!(&:to_hash),
|
||||
providers: YARD::Registry.all(:puppet_provider).sort_by!(&:name).map!(&:to_hash),
|
||||
puppet_functions: YARD::Registry.all(:puppet_function).sort_by!(&:name).map!(&:to_hash),
|
||||
# TODO: Need Ruby documentation?
|
||||
}
|
||||
|
||||
if file
|
||||
File.open(file, 'w') do |f|
|
||||
f.write(JSON.pretty_generate(document))
|
||||
f.write("\n")
|
||||
end
|
||||
else
|
||||
puts JSON.pretty_generate(document)
|
||||
end
|
||||
end
|
||||
|
||||
# Converts a YARD::Docstring (or String) to a docstring hash for JSON output.
|
||||
# @param [YARD::Docstring, String] docstring The docstring to convert to a hash.
|
||||
# @return [Hash] Returns a hash representation of the given docstring.
|
||||
def self.docstring_to_hash(docstring)
|
||||
hash = {}
|
||||
hash[:text] = docstring
|
||||
if docstring.is_a? YARD::Docstring
|
||||
# Skip over the API tags that are public
|
||||
tags = docstring.tags.select { |t| t.tag_name != 'api' || t.text != 'public' }.map do |t|
|
||||
next t.to_hash if t.respond_to?(:to_hash)
|
||||
|
||||
tag = { tag_name: t.tag_name }
|
||||
tag[:text] = t.text if t.text
|
||||
tag[:types] = t.types if t.types
|
||||
tag[:name] = t.name if t.name
|
||||
tag
|
||||
end
|
||||
hash[:tags] = tags unless tags.empty?
|
||||
end
|
||||
hash
|
||||
end
|
||||
end
|
|
@ -1,88 +0,0 @@
|
|||
require 'rake'
|
||||
require 'rake/tasklib'
|
||||
require 'puppet_x/puppetlabs/strings/util'
|
||||
|
||||
module PuppetStrings
|
||||
module RakeTasks
|
||||
# A configurable rake task to generate documentation using puppet-strings.
|
||||
#
|
||||
# @attr [String] name the name of the rake task.
|
||||
# @attr [Array<String>] module_resourcefiles globs used to specify which files to document.
|
||||
# Defaults to {PuppetX::PuppetLabs::Strings::Util::MODULE_SOURCEFILES}
|
||||
# @attr [Array<String>] excludes a list of paths or patterns of files and directories to ignore.
|
||||
# @attr [Array<String>, nil] paths list of paths to generate documentation for.
|
||||
# If this value is nil, uses the default paths for puppet strings.
|
||||
# @attr [Hash] options a hash with options passed through to yardoc.
|
||||
class Generate < ::Rake::TaskLib
|
||||
attr_accessor :name
|
||||
attr_accessor :module_resourcefiles
|
||||
attr_accessor :paths
|
||||
attr_accessor :excludes
|
||||
attr_accessor :options
|
||||
|
||||
# Creates a new instance of the Generate Rake task.
|
||||
# Defaults the name to 'strings:generate which overrides
|
||||
# the namespaced generates task. Also default other attributes to
|
||||
# mimic the current default behaviour.
|
||||
def initialize(*args, &task_block)
|
||||
@name = args.shift || 'strings:generate'
|
||||
@module_sourcefiles = PuppetX::PuppetLabs::Strings::Util::MODULE_SOURCEFILES
|
||||
@paths = nil
|
||||
@options = {emit_json: 'strings.json'}
|
||||
@excludes = []
|
||||
define(args, &task_block)
|
||||
end
|
||||
|
||||
# Creates the actual rake task after calling the task_block.
|
||||
#
|
||||
# @param [Array<String>] args arguments passed to the rake task.
|
||||
# @param [Proc] task_block block to configure the task.
|
||||
# @yield [self, args] configure this rake task.
|
||||
def define(args, &task_block)
|
||||
Rake::Task[@name].clear if Rake::Task.task_defined?(@name)
|
||||
yield(*[self, args].slice(0, task_block.arity)) if task_block
|
||||
|
||||
|
||||
desc 'Generate Puppet documentation with YARD.' unless ::Rake.application.last_description
|
||||
task @name do
|
||||
execute_task(generate_task_args)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Converts all attributes and options to an arguments array that can be passed
|
||||
# through to {PuppetX::PuppetLabs::Strings::Util #generate}.
|
||||
#
|
||||
# If paths is not nil, we expand them with the module_sourcefiles patterns.
|
||||
def generate_task_args
|
||||
@paths = [*@paths] unless @paths.nil?
|
||||
@module_sourcefiles = [*@module_sourcefiles]
|
||||
@excludes = [*@excludes]
|
||||
|
||||
exclude_args = @excludes.map {|x| ["--exclude", x]}.flatten
|
||||
pattern_args = @paths.nil? ? [] : expand_paths(@paths, @module_sourcefiles)
|
||||
|
||||
exclude_args + pattern_args + [@options]
|
||||
end
|
||||
|
||||
# Combine each prefix_path with each pattern with '/**/' glue.
|
||||
#
|
||||
# @example
|
||||
# expand_paths(['a','b'], ['*.rb','*.pp'])
|
||||
# => ["a/**/*.rb", "a/**/*.pp", "b/**/*.rb", "b/**/*.pp"]
|
||||
#
|
||||
# @param [Array<String>] prefix_paths an array with paths
|
||||
# @param [Array<String>] patterns an array with patterns.
|
||||
def expand_paths(prefix_paths, patterns)
|
||||
prefix_paths.map {|path| patterns.map {|p| "#{path}/**/#{p}" } }.flatten
|
||||
end
|
||||
|
||||
# call {PuppetX::PuppetLabs::Strings::Util #generate}
|
||||
# @param [Array<String, Hash>] args Arguments. Last element should be a Hash.
|
||||
def execute_task(args)
|
||||
PuppetX::PuppetLabs::Strings::Util.generate(args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
require 'rake'
|
||||
require 'rake/tasklib'
|
||||
|
||||
module PuppetStrings
|
||||
# The module for Puppet Strings rake tasks.
|
||||
module Tasks
|
||||
require 'puppet-strings/tasks/generate.rb'
|
||||
require 'puppet-strings/tasks/gh_pages.rb'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
require 'puppet-strings'
|
||||
|
||||
# Implements the strings:generate task.
|
||||
namespace :strings do
|
||||
desc 'Generate Puppet documentation with YARD.'
|
||||
task :generate, :patterns, :debug, :backtrace, :markup, :json, :yard_args do |t, args|
|
||||
patterns = args[:patterns]
|
||||
patterns = patterns.split if patterns
|
||||
patterns ||= PuppetStrings::DEFAULT_SEARCH_PATTERNS
|
||||
|
||||
options = {
|
||||
debug: args[:debug] == 'true',
|
||||
backtrace: args[:backtrace] == 'true',
|
||||
markup: args[:markup] || 'markdown',
|
||||
}
|
||||
|
||||
options[:json] = args[:json] if args.key? :json
|
||||
options[:yard_args] = args[:yard_args].split if args.key? :yard_args
|
||||
|
||||
PuppetStrings.generate(patterns, options)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,45 +1,30 @@
|
|||
require 'rake'
|
||||
require 'rake/tasklib'
|
||||
require 'puppet/face'
|
||||
require 'puppet_x/puppetlabs/strings/util'
|
||||
require 'puppet-strings/tasks'
|
||||
|
||||
namespace :strings do
|
||||
desc 'Generate Puppet documentation with YARD.'
|
||||
task :generate do
|
||||
PuppetX::PuppetLabs::Strings::Util.generate([
|
||||
{emit_json: 'strings.json'}
|
||||
])
|
||||
end
|
||||
|
||||
desc 'Serve YARD documentation for modules.'
|
||||
task :serve do
|
||||
PuppetX::PuppetLabs::Strings::Util.serve
|
||||
end
|
||||
|
||||
namespace :gh_pages do
|
||||
git_uri = `git config --get remote.origin.url`.strip
|
||||
|
||||
desc "Checkout the gh-pages branch for doc generation."
|
||||
desc 'Checkout the gh-pages branch for doc generation.'
|
||||
task :checkout do
|
||||
if Dir.exist?('doc')
|
||||
fail "The 'doc' directory (#{File.expand_path('doc')}) is not a Git repository! Remove it and run the Rake task again." unless Dir.exist?('doc/.git')
|
||||
Dir.chdir('doc') do
|
||||
system 'git checkout gh-pages'
|
||||
system 'git reset --hard origin/gh-pages'
|
||||
system 'git pull origin gh-pages'
|
||||
system 'git pull --rebase origin gh-pages'
|
||||
end
|
||||
else
|
||||
git_uri = `git config --get remote.origin.url`.strip
|
||||
fail "Could not determine the remote URL for origin: ensure the current directory is a Git repro with a remote named 'origin'." unless $?.success?
|
||||
|
||||
Dir.mkdir('doc')
|
||||
Dir.chdir('doc') do
|
||||
system 'git init'
|
||||
system "git remote add origin #{git_uri}"
|
||||
system 'git pull'
|
||||
system 'git pull origin gh-pages'
|
||||
system 'git checkout -b gh-pages'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Push new docs to GitHub."
|
||||
desc 'Push new docs to GitHub.'
|
||||
task :push do
|
||||
Dir.chdir('doc') do
|
||||
system 'git add .'
|
||||
|
@ -48,7 +33,7 @@ namespace :strings do
|
|||
end
|
||||
end
|
||||
|
||||
desc "Run checkout, generate, and push tasks."
|
||||
desc 'Run checkout, generate, and push tasks.'
|
||||
task :update => [
|
||||
:checkout,
|
||||
:'strings:generate',
|
|
@ -0,0 +1,96 @@
|
|||
require 'yard'
|
||||
|
||||
# Module for YARD related functionality.
|
||||
module PuppetStrings::Yard
|
||||
require 'puppet-strings/yard/code_objects'
|
||||
require 'puppet-strings/yard/handlers'
|
||||
require 'puppet-strings/yard/tags'
|
||||
require 'puppet-strings/yard/parsers'
|
||||
|
||||
# Sets up YARD for use with puppet-strings.
|
||||
# @return [void]
|
||||
def self.setup!
|
||||
# Register the template path
|
||||
YARD::Templates::Engine.register_template_path(File.join(File.dirname(__FILE__), 'yard', 'templates'))
|
||||
|
||||
# Register the Puppet parser
|
||||
YARD::Parser::SourceParser.register_parser_type(:puppet, PuppetStrings::Yard::Parsers::Puppet::Parser, ['pp'])
|
||||
|
||||
# Register our handlers
|
||||
YARD::Handlers::Processor.register_handler_namespace(:puppet, PuppetStrings::Yard::Handlers::Puppet)
|
||||
YARD::Handlers::Processor.register_handler_namespace(:puppet_ruby, PuppetStrings::Yard::Handlers::Ruby)
|
||||
|
||||
# Register the tag directives
|
||||
PuppetStrings::Yard::Tags::ParameterDirective.register!
|
||||
PuppetStrings::Yard::Tags::PropertyDirective.register!
|
||||
|
||||
# Ignore documentation on Puppet DSL calls
|
||||
# This prevents the YARD DSL parser from emitting warnings for Puppet's Ruby DSL
|
||||
YARD::Handlers::Ruby::DSLHandlerMethods::IGNORE_METHODS['create_function'] = true
|
||||
YARD::Handlers::Ruby::DSLHandlerMethods::IGNORE_METHODS['newtype'] = true
|
||||
end
|
||||
end
|
||||
|
||||
# Monkey patch YARD::CLI::Yardoc#all_objects to return our custom code objects.
|
||||
# @private
|
||||
class YARD::CLI::Yardoc
|
||||
def all_objects
|
||||
YARD::Registry.all(
|
||||
:root,
|
||||
:module,
|
||||
:class,
|
||||
:puppet_class,
|
||||
:puppet_defined_type,
|
||||
:puppet_type,
|
||||
:puppet_provider,
|
||||
:puppet_function
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Monkey patch the stats object to return statistics for our objects.
|
||||
# This is the recommended way to add custom stats.
|
||||
# @private
|
||||
class YARD::CLI::Stats
|
||||
def stats_for_puppet_classes
|
||||
output 'Puppet Classes', *type_statistics_all(:puppet_class)
|
||||
end
|
||||
|
||||
def stats_for_puppet_defined_types
|
||||
output 'Puppet Defined Types', *type_statistics_all(:puppet_defined_type)
|
||||
end
|
||||
|
||||
def stats_for_puppet_types
|
||||
output 'Puppet Types', *type_statistics_all(:puppet_type)
|
||||
end
|
||||
|
||||
def stats_for_puppet_providers
|
||||
output 'Puppet Providers', *type_statistics_all(:puppet_provider)
|
||||
end
|
||||
|
||||
def stats_for_puppet_functions
|
||||
output 'Puppet Functions', *type_statistics_all(:puppet_function)
|
||||
end
|
||||
|
||||
def output(name, data, undoc = nil)
|
||||
# Monkey patch output to accommodate our larger header widths
|
||||
@total += data if data.is_a?(Integer) && undoc
|
||||
@undocumented += undoc if undoc.is_a?(Integer)
|
||||
data =
|
||||
if undoc
|
||||
('%5s (% 5d undocumented)' % [data, undoc])
|
||||
else
|
||||
'%5s' % data
|
||||
end
|
||||
log.puts('%-21s %s' % [name + ':', data])
|
||||
end
|
||||
|
||||
# This differs from the YARD implementation in that it considers
|
||||
# a docstring without text but with tags to be undocumented.
|
||||
def type_statistics_all(type)
|
||||
objs = all_objects.select {|m| m.type == type }
|
||||
undoc = objs.find_all {|m| m.docstring.all.empty? }
|
||||
@undoc_list |= undoc if @undoc_list
|
||||
[objs.size, undoc.size]
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
# The module for custom YARD code objects.
|
||||
module PuppetStrings::Yard::CodeObjects
|
||||
require 'puppet-strings/yard/code_objects/class'
|
||||
require 'puppet-strings/yard/code_objects/defined_type'
|
||||
require 'puppet-strings/yard/code_objects/type'
|
||||
require 'puppet-strings/yard/code_objects/provider'
|
||||
require 'puppet-strings/yard/code_objects/function'
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
# Implements the base code object.
|
||||
class PuppetStrings::Yard::CodeObjects::Base < YARD::CodeObjects::NamespaceObject
|
||||
# Allocates a new code object.
|
||||
# @param [Array] args The arguments to initialize the code object with.
|
||||
# @return Returns the code object.
|
||||
def self.new(*args)
|
||||
# Skip the super class' implementation because it detects :: in names and this will cause namespaces in the output we don't want
|
||||
object = Object.class.instance_method(:new).bind(self).call(*args)
|
||||
existing = YARD::Registry.at(object.path)
|
||||
object = existing if existing && existing.class == self
|
||||
yield(object) if block_given?
|
||||
object
|
||||
end
|
||||
end
|
|
@ -0,0 +1,59 @@
|
|||
require 'puppet-strings/yard/code_objects/group'
|
||||
|
||||
# Implements the group for Puppet classes.
|
||||
class PuppetStrings::Yard::CodeObjects::Classes < PuppetStrings::Yard::CodeObjects::Group
|
||||
# Gets the singleton instance of the group.
|
||||
# @return Returns the singleton instance of the group.
|
||||
def self.instance
|
||||
super(:puppet_classes)
|
||||
end
|
||||
|
||||
# Gets the display name of the group.
|
||||
# @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces.
|
||||
# @return [String] Returns the display name of the group.
|
||||
def name(prefix = false)
|
||||
'Puppet Classes'
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet class code object.
|
||||
class PuppetStrings::Yard::CodeObjects::Class < PuppetStrings::Yard::CodeObjects::Base
|
||||
attr_reader :statement
|
||||
attr_reader :parameters
|
||||
|
||||
# Initializes a Puppet class code object.
|
||||
# @param [PuppetStrings::Parsers::ClassStatement] statement The class statement that was parsed.
|
||||
# @return [void]
|
||||
def initialize(statement)
|
||||
@statement = statement
|
||||
@parameters = statement.parameters.map { |p| [p.name, p.value] }
|
||||
super(PuppetStrings::Yard::CodeObjects::Classes.instance, statement.name)
|
||||
end
|
||||
|
||||
# Gets the type of the code object.
|
||||
# @return Returns the type of the code object.
|
||||
def type
|
||||
:puppet_class
|
||||
end
|
||||
|
||||
# Gets the source of the code object.
|
||||
# @return Returns the source of the code object.
|
||||
def source
|
||||
@statement.source
|
||||
end
|
||||
|
||||
# Converts the code object to a hash representation.
|
||||
# @return [Hash] Returns a hash representation of the code object.
|
||||
def to_hash
|
||||
hash = {}
|
||||
hash[:name] = name
|
||||
hash[:file] = file
|
||||
hash[:line] = line
|
||||
hash[:inherits] = statement.parent_class if statement.parent_class
|
||||
hash[:docstring] = PuppetStrings::Json.docstring_to_hash(docstring)
|
||||
defaults = Hash[*parameters.select{ |p| !p[1].nil? }.flatten]
|
||||
hash[:defaults] = defaults unless defaults.empty?
|
||||
hash[:source] = source unless source && source.empty?
|
||||
hash
|
||||
end
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
require 'puppet-strings/yard/code_objects/group'
|
||||
|
||||
# Implements the group for Puppet defined types.
|
||||
class PuppetStrings::Yard::CodeObjects::DefinedTypes < PuppetStrings::Yard::CodeObjects::Group
|
||||
# Gets the singleton instance of the group.
|
||||
# @return Returns the singleton instance of the group.
|
||||
def self.instance
|
||||
super(:puppet_defined_types)
|
||||
end
|
||||
|
||||
# Gets the display name of the group.
|
||||
# @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces.
|
||||
# @return [String] Returns the display name of the group.
|
||||
def name(prefix = false)
|
||||
'Defined Types'
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet defined type code object.
|
||||
class PuppetStrings::Yard::CodeObjects::DefinedType < PuppetStrings::Yard::CodeObjects::Base
|
||||
attr_reader :statement
|
||||
attr_reader :parameters
|
||||
|
||||
# Initializes a Puppet defined type code object.
|
||||
# @param [PuppetStrings::Parsers::DefinedTypeStatement] statement The defined type statement that was parsed.
|
||||
# @return [void]
|
||||
def initialize(statement)
|
||||
@statement = statement
|
||||
@parameters = statement.parameters.map { |p| [p.name, p.value] }
|
||||
super(PuppetStrings::Yard::CodeObjects::DefinedTypes.instance, statement.name)
|
||||
end
|
||||
|
||||
# Gets the type of the code object.
|
||||
# @return Returns the type of the code object.
|
||||
def type
|
||||
:puppet_defined_type
|
||||
end
|
||||
|
||||
# Gets the source of the code object.
|
||||
# @return Returns the source of the code object.
|
||||
def source
|
||||
@statement.source
|
||||
end
|
||||
|
||||
# Converts the code object to a hash representation.
|
||||
# @return [Hash] Returns a hash representation of the code object.
|
||||
def to_hash
|
||||
hash = {}
|
||||
hash[:name] = name
|
||||
hash[:file] = file
|
||||
hash[:line] = line
|
||||
hash[:docstring] = PuppetStrings::Json.docstring_to_hash(docstring)
|
||||
defaults = Hash[*parameters.select{ |p| !p[1].nil? }.flatten]
|
||||
hash[:defaults] = defaults unless defaults.empty?
|
||||
hash[:source] = source unless source && source.empty?
|
||||
hash
|
||||
end
|
||||
end
|
|
@ -0,0 +1,93 @@
|
|||
require 'puppet-strings/yard/code_objects/group'
|
||||
|
||||
# Implements the group for Puppet functions.
|
||||
class PuppetStrings::Yard::CodeObjects::Functions < PuppetStrings::Yard::CodeObjects::Group
|
||||
# Gets the singleton instance of the group.
|
||||
# @param [Symbol] type The function type to get the group for.
|
||||
# @return Returns the singleton instance of the group.
|
||||
def self.instance(type)
|
||||
super("puppet_functions_#{type}".intern)
|
||||
end
|
||||
|
||||
# Gets the display name of the group.
|
||||
# @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces.
|
||||
# @return [String] Returns the display name of the group.
|
||||
def name(prefix = false)
|
||||
'Puppet Functions'
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet function code object.
|
||||
class PuppetStrings::Yard::CodeObjects::Function < PuppetStrings::Yard::CodeObjects::Base
|
||||
# Identifier for 3.x Ruby API functions
|
||||
RUBY_3X = :ruby3x
|
||||
# Identifier for 4.x Ruby API functions
|
||||
RUBY_4X = :ruby4x
|
||||
# Identifier for Puppet language functions
|
||||
PUPPET = :puppet
|
||||
|
||||
attr_accessor :parameters
|
||||
|
||||
# Initializes a Puppet function code object.
|
||||
# @param [String] name The name of the function.
|
||||
# @param [Symbol] function_type The type of function (e.g. :ruby3x, :ruby4x, :puppet)
|
||||
# @return [void]
|
||||
def initialize(name, function_type)
|
||||
super(PuppetStrings::Yard::CodeObjects::Functions.instance(function_type), name)
|
||||
@parameters = []
|
||||
@function_type = function_type
|
||||
end
|
||||
|
||||
# Gets the type of the code object.
|
||||
# @return Returns the type of the code object.
|
||||
def type
|
||||
:puppet_function
|
||||
end
|
||||
|
||||
# Gets the function type display string.
|
||||
# @return Returns the function type display string.
|
||||
def function_type
|
||||
case @function_type
|
||||
when RUBY_3X
|
||||
'Ruby 3.x API'
|
||||
when RUBY_4X
|
||||
'Ruby 4.x API'
|
||||
else
|
||||
'Puppet Language'
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the Puppet signature of the function (single overload only).
|
||||
# @return [String] Returns the Puppet signature of the function.
|
||||
def signature
|
||||
return '' if self.has_tag? :overload
|
||||
tags = self.tags(:param)
|
||||
args = @parameters.map do |parameter|
|
||||
name, default = parameter
|
||||
tag = tags.find { |tag| tag.name == name } if tags
|
||||
type = tag && tag.types ? "#{tag.type} " : 'Any '
|
||||
prefix = "#{name[0]}" if name.start_with?('*', '&')
|
||||
name = name[1..-1] if prefix
|
||||
default = " = #{default}" if default
|
||||
"#{type}#{prefix}$#{name}#{default}"
|
||||
end.join(', ')
|
||||
@name.to_s + '(' + args + ')'
|
||||
end
|
||||
|
||||
# Converts the code object to a hash representation.
|
||||
# @return [Hash] Returns a hash representation of the code object.
|
||||
def to_hash
|
||||
hash = {}
|
||||
hash[:name] = name
|
||||
hash[:file] = file
|
||||
hash[:line] = line
|
||||
hash[:type] = @function_type.to_s
|
||||
signature = self.signature
|
||||
hash[:signature] = signature unless signature.empty?
|
||||
hash[:docstring] = PuppetStrings::Json.docstring_to_hash(docstring)
|
||||
defaults = Hash[*parameters.select{ |p| !p[1].nil? }.flatten]
|
||||
hash[:defaults] = defaults unless defaults.empty?
|
||||
hash[:source] = source unless source && source.empty?
|
||||
hash
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
require 'puppet-strings/yard/code_objects/base'
|
||||
|
||||
# Implements the base class for "groups".
|
||||
#
|
||||
# A group behaves like a YARD namespace object, but displays differently in the HTML output.
|
||||
class PuppetStrings::Yard::CodeObjects::Group < PuppetStrings::Yard::CodeObjects::Base
|
||||
# Gets the singleton instance of the group.
|
||||
# @param [Symbol] key The key to lookup the group for.
|
||||
# @return Returns the singleton instance of the group.
|
||||
def self.instance(key)
|
||||
instance = P(:root, key)
|
||||
return instance unless instance.is_a?(YARD::CodeObjects::Proxy)
|
||||
instance = self.new(:root, key)
|
||||
instance.visibility = :hidden
|
||||
P(:root).children << instance
|
||||
instance
|
||||
end
|
||||
|
||||
# Gets the path to the group.
|
||||
# @return [String] Returns the path to the group.
|
||||
def path
|
||||
@name.to_s
|
||||
end
|
||||
|
||||
# Gets the type of the group.
|
||||
# @return [Symbol] Returns the type of the group.
|
||||
def type
|
||||
@name
|
||||
end
|
||||
end
|
|
@ -0,0 +1,93 @@
|
|||
require 'puppet-strings/yard/code_objects/group'
|
||||
|
||||
# Implements the group for Puppet providers.
|
||||
class PuppetStrings::Yard::CodeObjects::Providers < PuppetStrings::Yard::CodeObjects::Group
|
||||
# Gets the singleton instance of the group.
|
||||
# @param [String] type The resource type name for the provider.
|
||||
# @return Returns the singleton instance of the group.
|
||||
def self.instance(type)
|
||||
super("puppet_providers_#{type}".intern)
|
||||
end
|
||||
|
||||
# Gets the display name of the group.
|
||||
# @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces.
|
||||
# @return [String] Returns the display name of the group.
|
||||
def name(prefix = false)
|
||||
'Providers'
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet provider code object.
|
||||
class PuppetStrings::Yard::CodeObjects::Provider < PuppetStrings::Yard::CodeObjects::Base
|
||||
attr_reader :type_name, :confines, :features, :defaults, :commands
|
||||
|
||||
# Initializes a Puppet provider code object.
|
||||
# @param [String] type_name The resource type name for the provider.
|
||||
# @param [String] name The name of the provider.s
|
||||
# @return [void]
|
||||
def initialize(type_name, name)
|
||||
@type_name = type_name
|
||||
super(PuppetStrings::Yard::CodeObjects::Providers.instance(type_name), name)
|
||||
end
|
||||
|
||||
# Gets the type of the code object.
|
||||
# @return Returns the type of the code object.
|
||||
def type
|
||||
:puppet_provider
|
||||
end
|
||||
|
||||
# Adds a confine to the provider.
|
||||
# @param [String] key The confine's key.
|
||||
# @param [String] value The confine's value.
|
||||
# @return [void]
|
||||
def add_confine(key, value)
|
||||
return unless key && value
|
||||
@confines ||= {}
|
||||
@confines[key] = value
|
||||
end
|
||||
|
||||
# Adds a feature to the provider.
|
||||
# @param [String] feature The feature to add to the provider.
|
||||
# @return [void]
|
||||
def add_feature(feature)
|
||||
return unless feature
|
||||
@features ||= []
|
||||
@features << feature
|
||||
end
|
||||
|
||||
# Adds a default to the provider.
|
||||
# @param [String] key The default's key.
|
||||
# @param [String] value The default's value.
|
||||
# @return [void]
|
||||
def add_default(key, value)
|
||||
return unless key && value
|
||||
@defaults ||= {}
|
||||
@defaults[key] = value
|
||||
end
|
||||
|
||||
# Adds a command to the provider.
|
||||
# @param [String] key The command's key.
|
||||
# @param [String] value The command's value.
|
||||
# @return [void]
|
||||
def add_command(key, value)
|
||||
return unless key && value
|
||||
@commands ||= {}
|
||||
@commands[key] = value
|
||||
end
|
||||
|
||||
# Converts the code object to a hash representation.
|
||||
# @return [Hash] Returns a hash representation of the code object.
|
||||
def to_hash
|
||||
hash = {}
|
||||
hash[:name] = name
|
||||
hash[:type_name] = type_name
|
||||
hash[:file] = file
|
||||
hash[:line] = line
|
||||
hash[:docstring] = PuppetStrings::Json.docstring_to_hash(docstring)
|
||||
hash[:confines] = confines if confines && !confines.empty?
|
||||
hash[:features] = features if features && !features.empty?
|
||||
hash[:defaults] = defaults if defaults && !defaults.empty?
|
||||
hash[:commands] = commands if commands && !commands.empty?
|
||||
hash
|
||||
end
|
||||
end
|
|
@ -0,0 +1,146 @@
|
|||
require 'puppet-strings/yard/code_objects/group'
|
||||
|
||||
# Implements the group for Puppet resource types.
|
||||
class PuppetStrings::Yard::CodeObjects::Types < PuppetStrings::Yard::CodeObjects::Group
|
||||
# Gets the singleton instance of the group.
|
||||
# @return Returns the singleton instance of the group.
|
||||
def self.instance
|
||||
super(:puppet_types)
|
||||
end
|
||||
|
||||
# Gets the display name of the group.
|
||||
# @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces.
|
||||
# @return [String] Returns the display name of the group.
|
||||
def name(prefix = false)
|
||||
'Resource Types'
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet resource type code object.
|
||||
class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects::Base
|
||||
# Represents a resource type parameter.
|
||||
class Parameter
|
||||
attr_reader :name, :values, :aliases
|
||||
attr_accessor :docstring, :isnamevar, :default
|
||||
|
||||
# Initializes a resource type parameter or property.
|
||||
# @param [String] name The name of the parameter or property.
|
||||
# @param [String] docstring The docstring for the parameter or property.s
|
||||
def initialize(name, docstring = nil)
|
||||
@name = name
|
||||
@docstring = docstring || ''
|
||||
@values = []
|
||||
@aliases = {}
|
||||
@isnamevar = false
|
||||
@default = nil
|
||||
end
|
||||
|
||||
# Adds a value to the parameter or property.
|
||||
# @param [String] value The value to add.
|
||||
# @return [void]
|
||||
def add(value)
|
||||
@values << value
|
||||
end
|
||||
|
||||
# Aliases a value to another value.
|
||||
# @param [String] new The new (alias) value.
|
||||
# @param [String] old The old (existing) value.
|
||||
# @return [void]
|
||||
def alias(new, old)
|
||||
@values << new unless @values.include? new
|
||||
@aliases[new] = old
|
||||
end
|
||||
|
||||
# Converts the parameter to a hash representation.
|
||||
# @return [Hash] Returns a hash representation of the parameter.
|
||||
def to_hash
|
||||
hash = {}
|
||||
hash[:name] = name
|
||||
hash[:description] = docstring unless docstring.empty?
|
||||
hash[:values] = values unless values.empty?
|
||||
hash[:aliases] = aliases unless aliases.empty?
|
||||
hash[:isnamevar] = true if isnamevar
|
||||
hash[:default] = default if default
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
||||
# Represents a resource type property (same attributes as a parameter).
|
||||
class Property < Parameter
|
||||
end
|
||||
|
||||
# Represents a resource type feature.
|
||||
class Feature
|
||||
attr_reader :name, :docstring
|
||||
|
||||
# Initializes a new feature.
|
||||
# @param [String] name The name of the feature.
|
||||
# @param [String] docstring The docstring of the feature.
|
||||
def initialize(name, docstring)
|
||||
@name = name
|
||||
@docstring = docstring
|
||||
end
|
||||
|
||||
# Converts the feature to a hash representation.
|
||||
# @return [Hash] Returns a hash representation of the feature.
|
||||
def to_hash
|
||||
hash = {}
|
||||
hash[:name] = name
|
||||
hash[:description] = docstring unless docstring.empty?
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :properties, :parameters, :features
|
||||
|
||||
# Initializes a new resource type.
|
||||
# @param [String] name The resource type name.
|
||||
# @return [void]
|
||||
def initialize(name)
|
||||
super(PuppetStrings::Yard::CodeObjects::Types.instance, name)
|
||||
end
|
||||
|
||||
# Gets the type of the code object.
|
||||
# @return Returns the type of the code object.
|
||||
def type
|
||||
:puppet_type
|
||||
end
|
||||
|
||||
# Adds a parameter to the resource type
|
||||
# @param [PuppetStrings::Yard::CodeObjects::Type::Parameter] parameter The parameter to add.
|
||||
# @return [void]
|
||||
def add_parameter(parameter)
|
||||
@parameters ||= []
|
||||
@parameters << parameter
|
||||
end
|
||||
|
||||
# Adds a property to the resource type
|
||||
# @param [PuppetStrings::Yard::CodeObjects::Type::Property] property The property to add.
|
||||
# @return [void]
|
||||
def add_property(property)
|
||||
@properties ||= []
|
||||
@properties << property
|
||||
end
|
||||
|
||||
# Adds a feature to the resource type.
|
||||
# @param [PuppetStrings::Yard::CodeObjects::Type::Feature] feature The feature to add.
|
||||
# @return [void]
|
||||
def add_feature(feature)
|
||||
@features ||= []
|
||||
@features << feature
|
||||
end
|
||||
|
||||
# Converts the code object to a hash representation.
|
||||
# @return [Hash] Returns a hash representation of the code object.
|
||||
def to_hash
|
||||
hash = {}
|
||||
hash[:name] = name
|
||||
hash[:file] = file
|
||||
hash[:line] = line
|
||||
hash[:docstring] = PuppetStrings::Json.docstring_to_hash(docstring)
|
||||
hash[:properties] = properties.map(&:to_hash) if properties && !properties.empty?
|
||||
hash[:parameters] = parameters.map(&:to_hash) if parameters && !parameters.empty?
|
||||
hash[:features] = features.map(&:to_hash) if features && !features.empty?
|
||||
hash
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
# The module for custom YARD handlers.
|
||||
module PuppetStrings::Yard::Handlers
|
||||
# The module for custom Ruby YARD handlers.
|
||||
module Ruby
|
||||
require 'puppet-strings/yard/handlers/ruby/type_handler'
|
||||
require 'puppet-strings/yard/handlers/ruby/provider_handler'
|
||||
require 'puppet-strings/yard/handlers/ruby/function_handler'
|
||||
end
|
||||
|
||||
# The module for custom Puppet YARD handlers.
|
||||
module Puppet
|
||||
require 'puppet-strings/yard/handlers/puppet/class_handler'
|
||||
require 'puppet-strings/yard/handlers/puppet/defined_type_handler'
|
||||
require 'puppet-strings/yard/handlers/puppet/function_handler'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
# Implements the base handler for Puppet language handlers.
|
||||
class PuppetStrings::Yard::Handlers::Puppet::Base < YARD::Handlers::Base
|
||||
# Determine sif the handler handles the given statement.
|
||||
# @param statement The statement that was parsed.
|
||||
# @return [Boolean] Returns true if the statement is handled by this handler or false if not.
|
||||
def self.handles?(statement)
|
||||
handlers.any? {|handler| statement.is_a?(handler)}
|
||||
end
|
||||
|
||||
protected
|
||||
# Sets the parameter tag types for the given code object.
|
||||
# This also performs some validation on the parameter tags.
|
||||
# @param object The code object to set the parameter tag types for.
|
||||
# @return [void]
|
||||
def set_parameter_types(object)
|
||||
# Ensure there is an actual parameter for each parameter tag
|
||||
tags = object.tags(:param)
|
||||
tags.each do |tag|
|
||||
next if statement.parameters.find { |p| tag.name == p.name }
|
||||
log.warn "The @param tag for parameter '#{tag.name}' has no matching parameter at #{statement.file}:#{statement.line}."
|
||||
end
|
||||
|
||||
# Assign the types for the parameter
|
||||
statement.parameters.each do |parameter|
|
||||
tag = tags.find { |t| t.name == parameter.name }
|
||||
unless tag
|
||||
log.warn "Missing @param tag for parameter '#{parameter.name}' near #{statement.file}:#{statement.line}." unless object.docstring.empty?
|
||||
|
||||
# Add a tag with an empty docstring
|
||||
object.add_tag YARD::Tags::Tag.new(:param, '', [parameter.type || 'Any'], parameter.name)
|
||||
next
|
||||
end
|
||||
|
||||
# Warn if the parameter is typed and the tag also has a type
|
||||
log.warn "The @param tag for parameter '#{parameter.name}' should not contain a type specification near #{statement.file}:#{statement.line}: ignoring in favor of parameter type information." if parameter.type && tag.types && !tag.types.empty?
|
||||
|
||||
if parameter.type
|
||||
tag.types = [parameter.type]
|
||||
elsif !tag.types
|
||||
tag.types = ['Any']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
require 'puppet-strings/yard/handlers/puppet/base'
|
||||
require 'puppet-strings/yard/parsers'
|
||||
require 'puppet-strings/yard/code_objects'
|
||||
|
||||
# Implements the handler for Puppet classes.
|
||||
class PuppetStrings::Yard::Handlers::Puppet::ClassHandler < PuppetStrings::Yard::Handlers::Puppet::Base
|
||||
handles PuppetStrings::Yard::Parsers::Puppet::ClassStatement
|
||||
|
||||
process do
|
||||
# Register the object
|
||||
object = PuppetStrings::Yard::CodeObjects::Class.new(statement)
|
||||
register object
|
||||
|
||||
# Log a warning if missing documentation
|
||||
log.warn "Missing documentation for Puppet class '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty?
|
||||
|
||||
# Set the parameter types
|
||||
set_parameter_types(object)
|
||||
|
||||
# Mark the class as public if it doesn't already have an api tag
|
||||
object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
require 'puppet-strings/yard/handlers/puppet/base'
|
||||
require 'puppet-strings/yard/parsers'
|
||||
require 'puppet-strings/yard/code_objects'
|
||||
|
||||
# Implements the handler for Puppet defined types.
|
||||
class PuppetStrings::Yard::Handlers::Puppet::DefinedTypeHandler < PuppetStrings::Yard::Handlers::Puppet::Base
|
||||
handles PuppetStrings::Yard::Parsers::Puppet::DefinedTypeStatement
|
||||
|
||||
process do
|
||||
# Register the object
|
||||
object = PuppetStrings::Yard::CodeObjects::DefinedType.new(statement)
|
||||
register object
|
||||
|
||||
# Log a warning if missing documentation
|
||||
log.warn "Missing documentation for Puppet defined type '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty?
|
||||
|
||||
# Set the parameter types
|
||||
set_parameter_types(object)
|
||||
|
||||
# Mark the defined type as public if it doesn't already have an api tag
|
||||
object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
|
||||
end
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
require 'puppet-strings/yard/handlers/puppet/base'
|
||||
require 'puppet-strings/yard/parsers'
|
||||
require 'puppet-strings/yard/code_objects'
|
||||
|
||||
# Implements the handler for Puppet classes.
|
||||
class PuppetStrings::Yard::Handlers::Puppet::FunctionHandler < PuppetStrings::Yard::Handlers::Puppet::Base
|
||||
handles PuppetStrings::Yard::Parsers::Puppet::FunctionStatement
|
||||
|
||||
process do
|
||||
# Register the object
|
||||
object = PuppetStrings::Yard::CodeObjects::Function.new(statement.name, PuppetStrings::Yard::CodeObjects::Function::PUPPET)
|
||||
object.source = statement.source
|
||||
object.source_type = parser.parser_type
|
||||
register object
|
||||
|
||||
# Log a warning if missing documentation
|
||||
log.warn "Missing documentation for Puppet function '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty?
|
||||
|
||||
# Set the parameter tag types
|
||||
set_parameter_types(object)
|
||||
|
||||
# Add a return tag
|
||||
add_return_tag(object)
|
||||
|
||||
# Set the parameters on the object
|
||||
object.parameters = statement.parameters.map { |p| [p.name, p.value] }
|
||||
|
||||
# Mark the class as public if it doesn't already have an api tag
|
||||
object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
|
||||
end
|
||||
|
||||
private
|
||||
def add_return_tag(object)
|
||||
tag = object.tag(:return)
|
||||
if tag
|
||||
tag.types = ['Any'] unless tag.types
|
||||
return
|
||||
end
|
||||
log.warn "Missing @return tag near #{statement.file}:#{statement.line}."
|
||||
object.add_tag YARD::Tags::Tag.new(:return, '', 'Any')
|
||||
end
|
||||
end
|
|
@ -0,0 +1,38 @@
|
|||
require 'ripper'
|
||||
|
||||
# Implements the base handler for Ruby language handlers.
|
||||
class PuppetStrings::Yard::Handlers::Ruby::Base < YARD::Handlers::Ruby::Base
|
||||
# A regular expression for detecting the start of a Ruby heredoc.
|
||||
# Note: the first character of the heredoc start may have been cut off by YARD.
|
||||
HEREDOC_START = /^<?<[\-~]?['"]?(\w+)['"]?[^\n]*[\n]?/
|
||||
|
||||
protected
|
||||
# Converts the given Ruby AST node to a string representation.
|
||||
# @param node The Ruby AST node to convert.
|
||||
# @return [String] Returns a string representation of the node or nil if a string representation was not possible.
|
||||
def node_as_string(node)
|
||||
return nil unless node
|
||||
case node.type
|
||||
when :symbol, :symbol_literal
|
||||
node.source[1..-1]
|
||||
when :label
|
||||
node.source[0..-2]
|
||||
when :dyna_symbol
|
||||
node.source
|
||||
when :string_literal
|
||||
content = node.jump(:tstring_content)
|
||||
return content.source if content != node
|
||||
|
||||
# This attempts to work around a bug in YARD (https://github.com/lsegal/yard/issues/779)
|
||||
# Check to see if the string source appears to have a heredoc open tag (or "most" of one)
|
||||
# If so, remove the first line and the last line (if the latter contains the heredoc tag)
|
||||
source = node.source
|
||||
if source =~ HEREDOC_START
|
||||
lines = source.split("\n")
|
||||
source = lines[1..(lines.last.include?($1) ? -2 : -1)].join("\n") if lines.size > 1
|
||||
end
|
||||
|
||||
source
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,357 @@
|
|||
require 'puppet-strings/yard/handlers/ruby/base'
|
||||
require 'puppet-strings/yard/code_objects'
|
||||
require 'puppet/util/docs'
|
||||
|
||||
# Implements the handler for Puppet functions written in Ruby.
|
||||
class PuppetStrings::Yard::Handlers::Ruby::FunctionHandler < PuppetStrings::Yard::Handlers::Ruby::Base
|
||||
# Represents the list of Puppet 4.x function API methods to support.
|
||||
DISPATCH_METHOD_NAMES = %w(
|
||||
param
|
||||
required_param
|
||||
optional_param
|
||||
repeated_param
|
||||
optional_repeated_param
|
||||
required_repeated_param
|
||||
block_param
|
||||
required_block_param
|
||||
optional_block_param
|
||||
).freeze
|
||||
|
||||
namespace_only
|
||||
handles method_call(:create_function)
|
||||
handles method_call(:newfunction)
|
||||
|
||||
process do
|
||||
# Only accept calls to Puppet::Functions (4.x) or Puppet::Parser::Functions (3.x)
|
||||
return unless statement.count > 1
|
||||
module_name = statement[0].source
|
||||
return unless module_name == 'Puppet::Functions' || module_name == 'Puppet::Parser::Functions'
|
||||
|
||||
# Create and register the function object
|
||||
is_3x = module_name == 'Puppet::Parser::Functions'
|
||||
object = PuppetStrings::Yard::CodeObjects::Function.new(
|
||||
get_name,
|
||||
is_3x ? PuppetStrings::Yard::CodeObjects::Function::RUBY_3X : PuppetStrings::Yard::CodeObjects::Function::RUBY_4X
|
||||
)
|
||||
object.source = statement
|
||||
register object
|
||||
|
||||
# For 3x, parse the doc parameter for the docstring
|
||||
# This must be done after the `register` call above because `register` always uses the statement's docstring
|
||||
if is_3x
|
||||
docstring = get_3x_docstring(object.name)
|
||||
register_docstring(object, docstring, nil) if docstring
|
||||
|
||||
# Default any typeless param tag to 'Any'
|
||||
object.tags(:param).each do |tag|
|
||||
tag.types = ['Any'] unless tag.types && !tag.types.empty?
|
||||
end
|
||||
|
||||
# Populate the parameters and the return tag
|
||||
object.parameters = object.tags(:param).map{ |p| [p.name, nil] }
|
||||
add_return_tag(object, statement.file, statement.line)
|
||||
else
|
||||
# For 4x, auto generate tags based on dispatch docstrings
|
||||
add_tags(object)
|
||||
end
|
||||
|
||||
# Mark the function as public if it doesn't already have an api tag
|
||||
object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
|
||||
end
|
||||
|
||||
private
|
||||
def get_name
|
||||
parameters = statement.parameters(false)
|
||||
raise YARD::Parser::UndocumentableError, "Expected at least one parameter to Puppet::Functions.create_function at #{statement.file}:#{statement.line}." if parameters.empty?
|
||||
name = node_as_string(parameters.first)
|
||||
raise YARD::Parser::UndocumentableError, "Expected a symbol or string literal for first parameter but found '#{parameters.first.type}' at #{statement.file}:#{statement.line}." unless name
|
||||
name
|
||||
end
|
||||
|
||||
def add_tags(object)
|
||||
log.warn "Missing documentation for Puppet function '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty?
|
||||
log.warn "The docstring for Puppet 4.x function '#{object.name}' contains @param tags near #{object.file}:#{object.line}: parameter documentation should be made on the dispatch call." unless object.tags(:param).empty?
|
||||
log.warn "The docstring for Puppet 4.x function '#{object.name}' contains @return tags near #{object.file}:#{object.line}: return value documentation should be made on the dispatch call." unless object.tags(:return).empty?
|
||||
log.warn "The docstring for Puppet 4.x function '#{object.name}' contains @overload tags near #{object.file}:#{object.line}: overload tags are automatically generated from the dispatch calls." unless object.tags(:overload).empty?
|
||||
|
||||
# Delete any existing param/return/overload tags
|
||||
object.docstring.delete_tags(:param)
|
||||
object.docstring.delete_tags(:return)
|
||||
object.docstring.delete_tags(:overload)
|
||||
|
||||
block = statement.block
|
||||
return unless block && block.count >= 2
|
||||
|
||||
# Get the unqualified name of the Puppet function
|
||||
unqualified_name = object.name.to_s.split('::').last
|
||||
|
||||
# Walk the block statements looking for dispatch calls and methods with the same name as the Puppet function
|
||||
default = nil
|
||||
block[1].children.each do |node|
|
||||
if node.is_a?(YARD::Parser::Ruby::MethodCallNode)
|
||||
add_overload_tag(object, node)
|
||||
elsif node.is_a?(YARD::Parser::Ruby::MethodDefinitionNode)
|
||||
default = node if node.method_name && node.method_name.source == unqualified_name
|
||||
end
|
||||
end
|
||||
|
||||
# Create an overload for the default method if there is one
|
||||
overloads = object.tags(:overload)
|
||||
if overloads.empty? && default
|
||||
add_method_overload(object, default)
|
||||
overloads = object.tags(:overload)
|
||||
end
|
||||
|
||||
# If there's only one overload, move the tags to the object itself
|
||||
if overloads.count == 1
|
||||
overload = overloads.first
|
||||
object.parameters = overload.parameters
|
||||
object.add_tag(*overload.tags)
|
||||
object.docstring.delete_tags(:overload)
|
||||
end
|
||||
end
|
||||
|
||||
def add_overload_tag(object, node)
|
||||
# Look for a call to a dispatch method with a block
|
||||
return unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) &&
|
||||
node.method_name &&
|
||||
node.method_name.source == 'dispatch' &&
|
||||
node.parameters(false).count == 1 &&
|
||||
node.block &&
|
||||
node.block.count >= 2
|
||||
|
||||
overload_tag = PuppetStrings::Yard::Tags::OverloadTag.new(object.name, node.docstring || '')
|
||||
param_tags = overload_tag.tags(:param)
|
||||
|
||||
block = nil
|
||||
node.block[1].children.each do |child|
|
||||
next unless child.is_a?(YARD::Parser::Ruby::MethodCallNode) && child.method_name
|
||||
|
||||
method_name = child.method_name.source
|
||||
next unless DISPATCH_METHOD_NAMES.include?(method_name)
|
||||
|
||||
# Check for block
|
||||
if method_name.include?('block')
|
||||
if block
|
||||
log.warn "A duplicate block parameter was found for Puppet function '#{object.name}' at #{child.file}:#{child.line}."
|
||||
next
|
||||
end
|
||||
|
||||
# Store the block; needs to be appended last
|
||||
block = child
|
||||
next
|
||||
end
|
||||
|
||||
# Ensure two parameters to parameter definition
|
||||
parameters = child.parameters(false)
|
||||
unless parameters.count == 2
|
||||
log.warn "Expected 2 arguments to '#{method_name}' call at #{child.file}:#{child.line}: parameter information may not be correct."
|
||||
next
|
||||
end
|
||||
|
||||
add_param_tag(
|
||||
overload_tag,
|
||||
param_tags,
|
||||
node_as_string(parameters[1]),
|
||||
child.file,
|
||||
child.line,
|
||||
node_as_string(parameters[0]),
|
||||
nil, # TODO: determine default from corresponding Ruby method signature?
|
||||
method_name.include?('optional'),
|
||||
method_name.include?('repeated')
|
||||
)
|
||||
end
|
||||
|
||||
# Handle the block parameter after others so it appears last in the list
|
||||
if block
|
||||
parameters = block.parameters(false)
|
||||
if parameters.empty?
|
||||
name = 'block'
|
||||
type = 'Callable'
|
||||
elsif parameters.count == 1
|
||||
name = node_as_string(parameters[0])
|
||||
type = 'Callable'
|
||||
elsif parameters.count == 2
|
||||
type = node_as_string(parameters[0])
|
||||
name = node_as_string(parameters[1])
|
||||
else
|
||||
log.warn "Unexpected number of arguments to block definition at #{block.file}:#{block.line}."
|
||||
end
|
||||
|
||||
if name && type
|
||||
add_param_tag(
|
||||
overload_tag,
|
||||
param_tags,
|
||||
name,
|
||||
block.file,
|
||||
block.line,
|
||||
type,
|
||||
nil, # TODO: determine default from corresponding Ruby method signature?
|
||||
block.method_name.source.include?('optional'),
|
||||
false, # Not repeated
|
||||
true # Is block
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Add a return tag if missing
|
||||
add_return_tag(overload_tag, node.file, node.line)
|
||||
|
||||
# Validate that tags have parameters
|
||||
validate_overload(overload_tag, node.file, node.line)
|
||||
|
||||
object.add_tag overload_tag
|
||||
end
|
||||
|
||||
def add_method_overload(object, node)
|
||||
overload_tag = PuppetStrings::Yard::Tags::OverloadTag.new(object.name, node.docstring || '')
|
||||
param_tags = overload_tag.tags(:param)
|
||||
|
||||
parameters = node.parameters
|
||||
|
||||
# Populate the required parameters
|
||||
params = parameters.unnamed_required_params
|
||||
if params
|
||||
params.each do |parameter|
|
||||
add_param_tag(
|
||||
overload_tag,
|
||||
param_tags,
|
||||
parameter.source,
|
||||
parameter.file,
|
||||
parameter.line
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Populate the optional parameters
|
||||
params = parameters.unnamed_optional_params
|
||||
if params
|
||||
params.each do |parameter|
|
||||
add_param_tag(
|
||||
overload_tag,
|
||||
param_tags,
|
||||
parameter[0].source,
|
||||
parameter.file,
|
||||
parameter.line,
|
||||
nil,
|
||||
parameter[1].source,
|
||||
true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Populate the splat parameter
|
||||
param = parameters.splat_param
|
||||
if param
|
||||
add_param_tag(
|
||||
overload_tag,
|
||||
param_tags,
|
||||
param.source,
|
||||
param.file,
|
||||
param.line,
|
||||
nil,
|
||||
nil,
|
||||
false,
|
||||
true
|
||||
)
|
||||
end
|
||||
|
||||
# Populate the block parameter
|
||||
param = parameters.block_param
|
||||
if param
|
||||
add_param_tag(
|
||||
overload_tag,
|
||||
param_tags,
|
||||
param.source,
|
||||
param.file,
|
||||
param.line,
|
||||
nil,
|
||||
nil,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
)
|
||||
end
|
||||
|
||||
# Add a return tag if missing
|
||||
add_return_tag(overload_tag, node.file, node.line)
|
||||
|
||||
# Validate that tags have parameters
|
||||
validate_overload(overload_tag, node.file, node.line)
|
||||
|
||||
object.add_tag overload_tag
|
||||
end
|
||||
|
||||
def add_param_tag(object, tags, name, file, line, type = nil, default = nil, optional = false, repeated = false, block = false)
|
||||
tag = tags.find { |tag| tag.name == name } if tags
|
||||
log.warn "Missing @param tag for parameter '#{name}' near #{file}:#{line}." unless tag || object.docstring.all.empty?
|
||||
log.warn "The @param tag for parameter '#{name}' should not contain a type specification near #{file}:#{line}: ignoring in favor of dispatch type information." if type && tag && tag.types && !tag.types.empty?
|
||||
|
||||
if repeated
|
||||
name = '*' + name
|
||||
elsif block
|
||||
name = '&' + name
|
||||
end
|
||||
|
||||
unless type
|
||||
type = tag && tag.types ? tag.type : 'Any'
|
||||
end
|
||||
type = optional ? "Optional[#{type}]" : type
|
||||
|
||||
object.parameters << [name, to_puppet_literal(default)]
|
||||
|
||||
if tag
|
||||
tag.name = name
|
||||
tag.types = [type]
|
||||
else
|
||||
object.add_tag YARD::Tags::Tag.new(:param, '', type, name)
|
||||
end
|
||||
end
|
||||
|
||||
def add_return_tag(object, file, line)
|
||||
tag = object.tag(:return)
|
||||
if tag
|
||||
tag.types = ['Any'] unless tag.types
|
||||
return
|
||||
end
|
||||
log.warn "Missing @return tag near #{file}:#{line}."
|
||||
object.add_tag YARD::Tags::Tag.new(:return, '', 'Any')
|
||||
end
|
||||
|
||||
def validate_overload(overload, file, line)
|
||||
# Validate that tags have matching parameters
|
||||
overload.tags(:param).each do |tag|
|
||||
next if overload.parameters.find { |p| tag.name == p[0] }
|
||||
log.warn "The @param tag for parameter '#{tag.name}' has no matching parameter at #{file}:#{line}."
|
||||
end
|
||||
end
|
||||
|
||||
def get_3x_docstring(name)
|
||||
parameters = statement.parameters(false)
|
||||
if parameters.count >= 2
|
||||
parameters[1].each do |kvp|
|
||||
next unless kvp.count == 2
|
||||
next unless node_as_string(kvp[0]) == 'doc'
|
||||
docstring = node_as_string(kvp[1])
|
||||
|
||||
log.error "Failed to parse docstring for 3.x Puppet function '#{name}' near #{statement.file}:#{statement.line}." and return nil unless docstring
|
||||
return Puppet::Util::Docs.scrub(docstring)
|
||||
end
|
||||
end
|
||||
|
||||
# Log a warning for missing docstring
|
||||
log.warn "Missing documentation for Puppet function '#{name}' at #{statement.file}:#{statement.line}."
|
||||
nil
|
||||
end
|
||||
|
||||
def to_puppet_literal(literal)
|
||||
case literal
|
||||
when 'nil'
|
||||
'undef'
|
||||
when ':default'
|
||||
'default'
|
||||
else
|
||||
literal
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,113 @@
|
|||
require 'puppet-strings/yard/handlers/ruby/base'
|
||||
require 'puppet-strings/yard/code_objects'
|
||||
require 'puppet/util/docs'
|
||||
|
||||
# Implements the handler for Puppet providers written in Ruby.
|
||||
class PuppetStrings::Yard::Handlers::Ruby::ProviderHandler < PuppetStrings::Yard::Handlers::Ruby::Base
|
||||
namespace_only
|
||||
handles method_call(:provide)
|
||||
|
||||
process do
|
||||
return unless statement.count >= 2
|
||||
|
||||
# Check that provide is being called on Puppet::Type.type(<name>)
|
||||
type_call = statement[0]
|
||||
return unless type_call.is_a?(YARD::Parser::Ruby::MethodCallNode) && type_call.count >= 3
|
||||
return unless type_call[0].source == 'Puppet::Type'
|
||||
return unless type_call[2].source == 'type'
|
||||
|
||||
# Extract the type name
|
||||
type_call_parameters = type_call.parameters(false)
|
||||
return unless type_call_parameters.count >= 1
|
||||
type_name = node_as_string(type_call_parameters.first)
|
||||
raise YARD::Parser::UndocumentableError, "Could not determine the resource type name for the provider defined at #{statement.file}:#{statement.line}." unless type_name
|
||||
|
||||
# Register the object
|
||||
object = PuppetStrings::Yard::CodeObjects::Provider.new(type_name, get_name)
|
||||
register object
|
||||
|
||||
# Extract the docstring
|
||||
register_provider_docstring object
|
||||
|
||||
# Populate the provider data
|
||||
populate_provider_data object
|
||||
|
||||
# Mark the provider as public if it doesn't already have an api tag
|
||||
object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
|
||||
end
|
||||
|
||||
private
|
||||
def get_name
|
||||
parameters = statement.parameters(false)
|
||||
raise YARD::Parser::UndocumentableError, "Expected at least one parameter to 'provide' at #{statement.file}:#{statement.line}." if parameters.empty?
|
||||
name = node_as_string(parameters.first)
|
||||
raise YARD::Parser::UndocumentableError, "Expected a symbol or string literal for first parameter but found '#{parameters.first.type}' at #{statement.file}:#{statement.line}." unless name
|
||||
name
|
||||
end
|
||||
|
||||
def register_provider_docstring(object)
|
||||
# Walk the tree searching for assignments or calls to desc/doc=
|
||||
statement.traverse do |child|
|
||||
if child.type == :assign
|
||||
ivar = child.jump(:ivar)
|
||||
next unless ivar != child && ivar.source == '@doc'
|
||||
docstring = node_as_string(child[1])
|
||||
log.error "Failed to parse docstring for Puppet provider '#{object.name}' (resource type '#{object.type_name}') near #{child.file}:#{child.line}." and return nil unless docstring
|
||||
register_docstring(object, Puppet::Util::Docs.scrub(docstring), nil)
|
||||
return nil
|
||||
elsif child.is_a?(YARD::Parser::Ruby::MethodCallNode)
|
||||
# Look for a call to a dispatch method with a block
|
||||
next unless
|
||||
child.method_name &&
|
||||
(child.method_name.source == 'desc' || child.method_name.source == 'doc=') &&
|
||||
child.parameters(false).count == 1
|
||||
|
||||
docstring = node_as_string(child.parameters[0])
|
||||
log.error "Failed to parse docstring for Puppet provider '#{object.name}' (resource type '#{object.type_name}') near #{child.file}:#{child.line}." and return nil unless docstring
|
||||
register_docstring(object, Puppet::Util::Docs.scrub(docstring), nil)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
log.warn "Missing a description for Puppet provider '#{object.name}' (resource type '#{object.type_name}') at #{statement.file}:#{statement.line}."
|
||||
end
|
||||
|
||||
def populate_provider_data(object)
|
||||
# Traverse the block looking for confines/defaults/commands
|
||||
block = statement.block
|
||||
return unless block && block.count >= 2
|
||||
block[1].children.each do |node|
|
||||
next unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) && node.method_name
|
||||
|
||||
method_name = node.method_name.source
|
||||
parameters = node.parameters(false)
|
||||
|
||||
if method_name == 'confine'
|
||||
# Add a confine to the object
|
||||
next unless parameters.count >= 1
|
||||
parameters[0].each do |kvp|
|
||||
next unless kvp.count == 2
|
||||
object.add_confine(node_as_string(kvp[0]) || kvp[0].source, node_as_string(kvp[1]) || kvp[1].source)
|
||||
end
|
||||
elsif method_name == 'has_feature' || method_name == 'has_features'
|
||||
# Add the features to the object
|
||||
parameters.each do |parameter|
|
||||
object.add_feature(node_as_string(parameter) || parameter.source)
|
||||
end
|
||||
elsif method_name == 'defaultfor'
|
||||
# Add a default to the object
|
||||
next unless parameters.count >= 1
|
||||
parameters[0].each do |kvp|
|
||||
next unless kvp.count == 2
|
||||
object.add_default(node_as_string(kvp[0]) || kvp[0].source, node_as_string(kvp[1]) || kvp[1].source)
|
||||
end
|
||||
elsif method_name == 'commands'
|
||||
# Add the commands to the object
|
||||
next unless parameters.count >= 1
|
||||
parameters[0].each do |kvp|
|
||||
next unless kvp.count == 2
|
||||
object.add_command(node_as_string(kvp[0]) || kvp[0].source, node_as_string(kvp[1]) || kvp[1].source)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,194 @@
|
|||
require 'puppet-strings/yard/handlers/ruby/base'
|
||||
require 'puppet-strings/yard/code_objects'
|
||||
require 'puppet/util'
|
||||
|
||||
# Implements the handler for Puppet resource types written in Ruby.
|
||||
class PuppetStrings::Yard::Handlers::Ruby::TypeHandler < PuppetStrings::Yard::Handlers::Ruby::Base
|
||||
# The default docstring when ensurable is used without given a docstring.
|
||||
DEFAULT_ENSURABLE_DOCSTRING = 'The basic property that the resource should be in.'.freeze
|
||||
|
||||
namespace_only
|
||||
handles method_call(:newtype)
|
||||
|
||||
process do
|
||||
# Only accept calls to Puppet::Type
|
||||
return unless statement.count > 1
|
||||
module_name = statement[0].source
|
||||
return unless module_name == 'Puppet::Type' || module_name == 'Type'
|
||||
|
||||
object = PuppetStrings::Yard::CodeObjects::Type.new(get_name)
|
||||
register object
|
||||
|
||||
docstring = find_docstring(statement, "Puppet resource type '#{object.name}'")
|
||||
register_docstring(object, docstring, nil) if docstring
|
||||
|
||||
# Populate the parameters/properties/features to the type
|
||||
populate_type_data(object)
|
||||
|
||||
# Set the default namevar
|
||||
set_default_namevar(object)
|
||||
|
||||
# Mark the type as public if it doesn't already have an api tag
|
||||
object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
|
||||
end
|
||||
|
||||
private
|
||||
def get_name
|
||||
parameters = statement.parameters(false)
|
||||
raise YARD::Parser::UndocumentableError, "Expected at least one parameter to Puppet::Type.newtype at #{statement.file}:#{statement.line}." if parameters.empty?
|
||||
name = node_as_string(parameters.first)
|
||||
raise YARD::Parser::UndocumentableError, "Expected a symbol or string literal for first parameter but found '#{parameters.first.type}' at #{statement.file}:#{statement.line}." unless name
|
||||
name
|
||||
end
|
||||
|
||||
def find_docstring(node, kind)
|
||||
# Walk the tree searching for assignments or calls to desc/doc=
|
||||
node.traverse do |child|
|
||||
if child.type == :assign
|
||||
ivar = child.jump(:ivar)
|
||||
next unless ivar != child && ivar.source == '@doc'
|
||||
docstring = node_as_string(child[1])
|
||||
log.error "Failed to parse docstring for #{kind} near #{child.file}:#{child.line}." and return nil unless docstring
|
||||
return Puppet::Util::Docs.scrub(docstring)
|
||||
elsif child.is_a?(YARD::Parser::Ruby::MethodCallNode)
|
||||
# Look for a call to a dispatch method with a block
|
||||
next unless child.method_name &&
|
||||
(child.method_name.source == 'desc' || child.method_name.source == 'doc=') &&
|
||||
child.parameters(false).count == 1
|
||||
|
||||
docstring = node_as_string(child.parameters[0])
|
||||
log.error "Failed to parse docstring for #{kind} near #{child.file}:#{child.line}." and return nil unless docstring
|
||||
return Puppet::Util::Docs.scrub(docstring)
|
||||
end
|
||||
end
|
||||
log.warn "Missing a description for #{kind} at #{node.file}:#{node.line}."
|
||||
nil
|
||||
end
|
||||
|
||||
def populate_type_data(object)
|
||||
# Traverse the block looking for properties/parameters/features
|
||||
block = statement.block
|
||||
return unless block && block.count >= 2
|
||||
block[1].children.each do |node|
|
||||
next unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) &&
|
||||
node.method_name
|
||||
|
||||
method_name = node.method_name.source
|
||||
parameters = node.parameters(false)
|
||||
|
||||
if method_name == 'newproperty'
|
||||
# Add a property to the object
|
||||
next unless parameters.count >= 1
|
||||
name = node_as_string(parameters[0])
|
||||
next unless name
|
||||
object.add_property(create_property(name, node))
|
||||
elsif method_name == 'newparam'
|
||||
# Add a parameter to the object
|
||||
next unless parameters.count >= 1
|
||||
name = node_as_string(parameters[0])
|
||||
next unless name
|
||||
object.add_parameter(create_parameter(name, node))
|
||||
elsif method_name == 'feature'
|
||||
# Add a feature to the object
|
||||
next unless parameters.count >= 2
|
||||
name = node_as_string(parameters[0])
|
||||
next unless name
|
||||
|
||||
docstring = node_as_string(parameters[1])
|
||||
next unless docstring
|
||||
|
||||
object.add_feature(PuppetStrings::Yard::CodeObjects::Type::Feature.new(name, docstring))
|
||||
elsif method_name == 'ensurable'
|
||||
if node.block
|
||||
property = create_property('ensure', node)
|
||||
property.docstring = DEFAULT_ENSURABLE_DOCSTRING if property.docstring.empty?
|
||||
else
|
||||
property = PuppetStrings::Yard::CodeObjects::Type::Property.new('ensure', DEFAULT_ENSURABLE_DOCSTRING)
|
||||
property.add('present')
|
||||
property.add('absent')
|
||||
property.default = 'present'
|
||||
end
|
||||
object.add_property property
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_parameter(name, node)
|
||||
parameter = PuppetStrings::Yard::CodeObjects::Type::Parameter.new(name, find_docstring(node, "Puppet resource parameter '#{name}'"))
|
||||
set_values(node, parameter)
|
||||
parameter
|
||||
end
|
||||
|
||||
def create_property(name, node)
|
||||
property = PuppetStrings::Yard::CodeObjects::Type::Property.new(name, find_docstring(node, "Puppet resource property '#{name}'"))
|
||||
set_values(node, property)
|
||||
property
|
||||
end
|
||||
|
||||
def set_values(node, object)
|
||||
return unless node.block && node.block.count >= 2
|
||||
|
||||
node.block[1].children.each do |child|
|
||||
next unless child.is_a?(YARD::Parser::Ruby::MethodCallNode) && child.method_name
|
||||
|
||||
method_name = child.method_name.source
|
||||
parameters = child.parameters(false)
|
||||
|
||||
if method_name == 'newvalue'
|
||||
next unless parameters.count >= 1
|
||||
object.add(node_as_string(parameters[0]) || parameters[0].source)
|
||||
elsif method_name == 'newvalues'
|
||||
parameters.each do |p|
|
||||
object.add(node_as_string(p) || p.source)
|
||||
end
|
||||
elsif method_name == 'aliasvalue'
|
||||
next unless parameters.count >= 2
|
||||
object.alias(node_as_string(parameters[0]) || parameters[0].source, node_as_string(parameters[1]) || parameters[1].source)
|
||||
elsif method_name == 'defaultto'
|
||||
next unless parameters.count >= 1
|
||||
object.default = node_as_string(parameters[0]) || parameters[0].source
|
||||
elsif method_name == 'isnamevar'
|
||||
object.isnamevar = true
|
||||
elsif method_name == 'defaultvalues' && object.name == 'ensure'
|
||||
object.add('present')
|
||||
object.add('absent')
|
||||
object.default = 'present'
|
||||
end
|
||||
end
|
||||
if object.is_a? PuppetStrings::Yard::CodeObjects::Type::Parameter
|
||||
# Process the options for parameter base types
|
||||
parameters = node.parameters(false)
|
||||
if parameters.count >= 2
|
||||
parameters[1].each do |kvp|
|
||||
next unless kvp.count == 2
|
||||
next unless node_as_string(kvp[0]) == 'parent'
|
||||
if kvp[1].source == 'Puppet::Parameter::Boolean'
|
||||
object.add('true') unless object.values.include? 'true'
|
||||
object.add('false') unless object.values.include? 'false'
|
||||
object.add('yes') unless object.values.include? 'yes'
|
||||
object.add('no') unless object.values.include? 'no'
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def set_default_namevar(object)
|
||||
return unless object.properties || object.parameters
|
||||
default = nil
|
||||
if object.properties
|
||||
object.properties.each do |property|
|
||||
return nil if property.isnamevar
|
||||
default = property if property.name == 'name'
|
||||
end
|
||||
end
|
||||
if object.parameters
|
||||
object.parameters.each do |parameter|
|
||||
return nil if parameter.isnamevar
|
||||
default ||= parameter if parameter.name == 'name'
|
||||
end
|
||||
end
|
||||
default.isnamevar = true if default
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
# The module for custom YARD parsers.
|
||||
module PuppetStrings::Yard::Parsers
|
||||
# The module for custom YARD parsers for the Puppet language.
|
||||
module Puppet
|
||||
require 'puppet-strings/yard/parsers/puppet/parser'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,70 @@
|
|||
require 'puppet'
|
||||
require 'puppet/pops'
|
||||
require 'puppet-strings/yard/parsers/puppet/statement'
|
||||
|
||||
# Implements the Puppet language parser.
|
||||
class PuppetStrings::Yard::Parsers::Puppet::Parser < YARD::Parser::Base
|
||||
attr_reader :file, :source
|
||||
|
||||
# Initializes the parser.
|
||||
# @param [String] source The source being parsed.
|
||||
# @param [String] filename The file name of the file being parsed.
|
||||
# @return [void]
|
||||
def initialize(source, filename)
|
||||
@source = source
|
||||
@file = filename
|
||||
@visitor = ::Puppet::Pops::Visitor.new(self, 'transform')
|
||||
end
|
||||
|
||||
# Parses the source.
|
||||
# @return [void]
|
||||
def parse
|
||||
begin
|
||||
@statements ||= (@visitor.visit(::Puppet::Pops::Parser::Parser.new.parse_string(source)) || []).compact
|
||||
rescue ::Puppet::ParseError => ex
|
||||
log.error "Failed to parse #{@file}: #{ex.message}"
|
||||
@statements = []
|
||||
end
|
||||
@statements.freeze
|
||||
self
|
||||
end
|
||||
|
||||
# Gets an enumerator for the statements that were parsed.
|
||||
# @return Returns an enumerator for the statements that were parsed.
|
||||
def enumerator
|
||||
@statements
|
||||
end
|
||||
|
||||
private
|
||||
def transform_Program(o)
|
||||
# Cache the lines of the source text; we'll use this to locate comments
|
||||
@lines = o.source_text.lines.to_a
|
||||
o.definitions.map { |d| @visitor.visit(d) }
|
||||
end
|
||||
|
||||
def transform_Factory(o)
|
||||
@visitor.visit(o.current)
|
||||
end
|
||||
|
||||
def transform_HostClassDefinition(o)
|
||||
statement = PuppetStrings::Yard::Parsers::Puppet::ClassStatement.new(o, @file)
|
||||
statement.extract_docstring(@lines)
|
||||
statement
|
||||
end
|
||||
|
||||
def transform_ResourceTypeDefinition(o)
|
||||
statement = PuppetStrings::Yard::Parsers::Puppet::DefinedTypeStatement.new(o, @file)
|
||||
statement.extract_docstring(@lines)
|
||||
statement
|
||||
end
|
||||
|
||||
def transform_FunctionDefinition(o)
|
||||
statement = PuppetStrings::Yard::Parsers::Puppet::FunctionStatement.new(o, @file)
|
||||
statement.extract_docstring(@lines)
|
||||
statement
|
||||
end
|
||||
|
||||
def transform_Object(o)
|
||||
# Ignore anything else (will be compacted out of the resulting array)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,146 @@
|
|||
require 'puppet'
|
||||
require 'puppet/pops'
|
||||
|
||||
module PuppetStrings::Yard::Parsers::Puppet
|
||||
# Represents the base Puppet language statement.
|
||||
class Statement
|
||||
# The pattern for parsing docstring comments.
|
||||
COMMENT_REGEX = /^\s*#+\s?/
|
||||
|
||||
attr_reader :source
|
||||
attr_reader :file
|
||||
attr_reader :line
|
||||
attr_reader :docstring
|
||||
attr_reader :comments_range
|
||||
|
||||
# Initializes the Puppet language statement.
|
||||
# @param object The Puppet parser model object for the statement.
|
||||
# @param [String] file The file name of the file containing the statement.
|
||||
def initialize(object, file)
|
||||
@file = file
|
||||
|
||||
adapter = ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(object)
|
||||
@source = adapter.extract_text
|
||||
@line = adapter.line
|
||||
@comments_range = nil
|
||||
end
|
||||
|
||||
# Extracts the docstring for the statement given the source lines.
|
||||
# @param [Array<String>] lines The source lines for the file containing the statement.
|
||||
# @return [void]
|
||||
def extract_docstring(lines)
|
||||
comment = []
|
||||
(0..@line-2).reverse_each do |index|
|
||||
break unless index <= lines.count
|
||||
line = lines[index].strip
|
||||
count = line.size
|
||||
line.gsub!(COMMENT_REGEX, '')
|
||||
# Break out if nothing was removed (wasn't a comment line)
|
||||
break unless line.size < count
|
||||
comment << line
|
||||
end
|
||||
@comments_range = (@line - comment.size - 1..@line - 1)
|
||||
@docstring = YARD::Docstring.new(comment.reverse.join("\n"))
|
||||
end
|
||||
|
||||
# Shows the first line context for the statement.
|
||||
# @return [String] Returns the first line context for the statement.
|
||||
def show
|
||||
"\t#{@line}: #{first_line}"
|
||||
end
|
||||
|
||||
# Gets the full comments of the statement.
|
||||
# @return [String] Returns the full comments of the statement.
|
||||
def comments
|
||||
@docstring.all
|
||||
end
|
||||
|
||||
# Determines if the comments have hash flag.
|
||||
# @return [Boolean] Returns true if the comments have a hash flag or false if not.
|
||||
def comments_hash_flag
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
def first_line
|
||||
@source.split(/\r?\n/).first.strip
|
||||
end
|
||||
end
|
||||
|
||||
# Implements a parameterized statement (a statement that takes parameters).
|
||||
class ParameterizedStatement < Statement
|
||||
# Implements a parameter for a parameterized statement.
|
||||
class Parameter
|
||||
attr_reader :name
|
||||
attr_reader :type
|
||||
attr_reader :value
|
||||
|
||||
# Initializes the parameter.
|
||||
# @param [Puppet::Pops::Model::Parameter] parameter The parameter model object.
|
||||
def initialize(parameter)
|
||||
@name = parameter.name
|
||||
# Take the exact text for the type expression
|
||||
if parameter.type_expr
|
||||
adapter = ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(parameter.type_expr)
|
||||
@type = adapter.extract_text
|
||||
end
|
||||
# Take the exact text for the default value expression
|
||||
if parameter.value
|
||||
adapter = ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(parameter.value)
|
||||
@value = adapter.extract_text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :parameters
|
||||
|
||||
# Initializes the parameterized statement.
|
||||
# @param object The Puppet parser model object that has parameters.
|
||||
# @param [String] file The file containing the statement.
|
||||
def initialize(object, file)
|
||||
super(object, file)
|
||||
@parameters = object.parameters.map { |parameter| Parameter.new(parameter) }
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet class statement.
|
||||
class ClassStatement < ParameterizedStatement
|
||||
attr_reader :name
|
||||
attr_reader :parent_class
|
||||
|
||||
# Initializes the Puppet class statement.
|
||||
# @param [Puppet::Pops::Model::HostClassDefinition] object The model object for the class statement.
|
||||
# @param [String] file The file containing the statement.
|
||||
def initialize(object, file)
|
||||
super(object, file)
|
||||
@name = object.name
|
||||
@parent_class = object.parent_class
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet defined type statement.
|
||||
class DefinedTypeStatement < ParameterizedStatement
|
||||
attr_reader :name
|
||||
|
||||
# Initializes the Puppet defined type statement.
|
||||
# @param [Puppet::Pops::Model::ResourceTypeDefinition] object The model object for the defined type statement.
|
||||
# @param [String] file The file containing the statement.
|
||||
def initialize(object, file)
|
||||
super(object, file)
|
||||
@name = object.name
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet function statement.
|
||||
class FunctionStatement < ParameterizedStatement
|
||||
attr_reader :name
|
||||
|
||||
# Initializes the Puppet function statement.
|
||||
# @param [Puppet::Pops::Model::FunctionDefinition] object The model object for the function statement.
|
||||
# @param [String] file The file containing the statement.
|
||||
def initialize(object, file)
|
||||
super(object, file)
|
||||
@name = object.name
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
# The module for custom YARD tags.
|
||||
module PuppetStrings::Yard::Tags
|
||||
require 'puppet-strings/yard/tags/parameter_directive'
|
||||
require 'puppet-strings/yard/tags/property_directive'
|
||||
require 'puppet-strings/yard/tags/overload_tag'
|
||||
end
|
|
@ -0,0 +1,109 @@
|
|||
# Implements an overload tag for Puppet functions
|
||||
#
|
||||
# This differs from Yard's overload tag in that the signatures are formatted according to Puppet language rules.
|
||||
class PuppetStrings::Yard::Tags::OverloadTag < YARD::Tags::Tag
|
||||
attr_reader :parameters, :docstring
|
||||
|
||||
# Initializes the overload tag.
|
||||
# @param [String, Symbol] name The name of the function being overloaded.
|
||||
# @param [String] docstring The docstring for the overload.
|
||||
# @return [void]
|
||||
def initialize(name, docstring)
|
||||
super(:overload, nil)
|
||||
@name = name.to_s
|
||||
@parameters = []
|
||||
@docstring = YARD::Docstring.new(docstring)
|
||||
end
|
||||
|
||||
# Gets the signature of the overload.
|
||||
# @return [String] Returns the signature of the overload.
|
||||
def signature
|
||||
tags = self.tags(:param)
|
||||
args = @parameters.map do |parameter|
|
||||
name, default = parameter
|
||||
tag = tags.find { |tag| tag.name == name } if tags
|
||||
type = tag && tag.types ? "#{tag.type} " : 'Any '
|
||||
prefix = "#{name[0]}" if name.start_with?('*', '&')
|
||||
name = name[1..-1] if prefix
|
||||
default = " = #{default}" if default
|
||||
"#{type}#{prefix}$#{name}#{default}"
|
||||
end.join(', ')
|
||||
@name + '(' + args + ')'
|
||||
end
|
||||
|
||||
# Adds a tag to the overload's docstring.
|
||||
# @param [YARD::Tag] tag The tag to add to the overload's docstring.
|
||||
# @return [void]
|
||||
def add_tag(tag)
|
||||
@docstring.add_tag(tag)
|
||||
end
|
||||
|
||||
# Gets the first tag of the given name.
|
||||
# @param [String, Symbol] name The name of the tag.
|
||||
# @return [YARD::Tag] Returns the first tag if found or nil if not found.
|
||||
def tag(name)
|
||||
@docstring.tag(name)
|
||||
end
|
||||
|
||||
# Gets all tags or tags of a given name.
|
||||
# @param [String, Symbol] name The name of the tag to get or nil for all tags.
|
||||
# @return [Array<Yard::Tag>] Returns an array of tags.
|
||||
def tags(name = nil)
|
||||
@docstring.tags(name)
|
||||
end
|
||||
|
||||
# Determines if a tag with the given name is present.
|
||||
# @param [String, Symbol] name The tag name.
|
||||
# @return [Boolean] Returns true if there is at least one tag with the given name or false if not.
|
||||
def has_tag?(name)
|
||||
@docstring.has_tag?(name)
|
||||
end
|
||||
|
||||
# Sets the object associated with this tag.
|
||||
# @param [Object] value The object to associate with this tag.
|
||||
# @return [void]
|
||||
def object=(value)
|
||||
super(value)
|
||||
@docstring.object = value
|
||||
@docstring.tags.each {|tag| tag.object = value }
|
||||
end
|
||||
|
||||
# Responsible for forwarding method calls to the associated object.
|
||||
# @param [Symbol] method_name The method being invoked.
|
||||
# @param [Array] args The args passed to the method.
|
||||
# @param block The block passed to the method.
|
||||
# @return Returns what the method call on the object would return.
|
||||
def method_missing(method_name, *args, &block)
|
||||
return object.send(method_name, *args, &block) if object.respond_to? method_name
|
||||
super
|
||||
end
|
||||
|
||||
# Determines if the associated object responds to the give missing method name.
|
||||
# @param [Symbol, String] method_name The name of the method to check.
|
||||
# @param [Boolean] include_all True to include all methods in the check or false for only public methods.
|
||||
# @return [Boolean] Returns true if the object responds to the method or false if not.
|
||||
def respond_to_missing?(method_name, include_all = false)
|
||||
object.respond_to?(method_name, include_all) || super
|
||||
end
|
||||
|
||||
# Gets the type of the object associated with this tag.
|
||||
# @return [Symbol] Returns the type of the object associated with this tag.
|
||||
def type
|
||||
object.type
|
||||
end
|
||||
|
||||
# Converts the overload tag to a hash representation.
|
||||
# @return [Hash] Returns a hash representation of the overload.
|
||||
def to_hash
|
||||
hash = {}
|
||||
hash[:tag_name] = tag_name
|
||||
hash[:text] = text if text
|
||||
hash[:signature] = signature
|
||||
hash[:docstring] = PuppetStrings::Json.docstring_to_hash(docstring) if !docstring.empty?
|
||||
defaults = Hash[*parameters.select{ |p| !p[1].nil? }.flatten]
|
||||
hash[:defaults] = defaults unless defaults.empty?
|
||||
hash[:types] = types if types
|
||||
hash[:name] = name if name
|
||||
hash
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
require 'puppet-strings/yard/code_objects'
|
||||
|
||||
# Implements a parameter directive (e.g. #@!puppet.type.param) for documenting Puppet resource types.
|
||||
class PuppetStrings::Yard::Tags::ParameterDirective < YARD::Tags::Directive
|
||||
# Called to invoke the directive.
|
||||
# @return [void]
|
||||
def call
|
||||
return unless object && object.respond_to?(:add_parameter)
|
||||
# Add a parameter to the resource
|
||||
parameter = PuppetStrings::Yard::CodeObjects::Type::Parameter.new(tag.name, tag.text)
|
||||
if tag.types
|
||||
tag.types.each do |value|
|
||||
parameter.add(value)
|
||||
end
|
||||
end
|
||||
object.add_parameter parameter
|
||||
end
|
||||
|
||||
# Registers the directive with YARD.
|
||||
# @return [void]
|
||||
def self.register!
|
||||
YARD::Tags::Library.define_directive('puppet.type.param', :with_types_and_name, self)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
require 'puppet-strings/yard/code_objects'
|
||||
|
||||
# Implements a parameter directive (e.g. #@!puppet.type.property) for documenting Puppet resource types.
|
||||
class PuppetStrings::Yard::Tags::PropertyDirective < YARD::Tags::Directive
|
||||
# Called to invoke the directive.
|
||||
# @return [void]
|
||||
def call
|
||||
return unless object && object.respond_to?(:add_property)
|
||||
# Add a property to the resource
|
||||
property = PuppetStrings::Yard::CodeObjects::Type::Property.new(tag.name, tag.text)
|
||||
if tag.types
|
||||
tag.types.each do |value|
|
||||
property.add(value)
|
||||
end
|
||||
end
|
||||
object.add_property property
|
||||
end
|
||||
|
||||
# Registers the directive with YARD.
|
||||
# @return [void]
|
||||
def self.register!
|
||||
YARD::Tags::Library.define_directive('puppet.type.property', :with_types_and_name, self)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
<% even = false %>
|
||||
<% @items.each do |item| %>
|
||||
<li id="object_<%=item.path%>" class="<%= even ? 'even' : 'odd' %>">
|
||||
<div class="item">
|
||||
<%= linkify item, h(item.name(true)) %>
|
||||
</div>
|
||||
</li>
|
||||
<% even = !even %>
|
||||
<% end %>
|
|
@ -0,0 +1,9 @@
|
|||
<% even = false %>
|
||||
<% @items.each do |item| %>
|
||||
<li id="object_<%=item.path%>" class="<%= even ? 'even' : 'odd' %>">
|
||||
<div class="item">
|
||||
<%= linkify item, h(item.name(true)) %>
|
||||
</div>
|
||||
</li>
|
||||
<% even = !even %>
|
||||
<% end %>
|
|
@ -0,0 +1,10 @@
|
|||
<% even = false %>
|
||||
<% @items.each do |item| %>
|
||||
<li id="object_<%=item.path%>" class="<%= even ? 'even' : 'odd' %>">
|
||||
<div class="item">
|
||||
<%= linkify item, h(item.name(false)) %>
|
||||
<small><%= item.function_type %></small>
|
||||
</div>
|
||||
</li>
|
||||
<% even = !even %>
|
||||
<% end %>
|
|
@ -0,0 +1,10 @@
|
|||
<% even = false %>
|
||||
<% @items.each do |item| %>
|
||||
<li id="object_<%=item.path%>" class="<%= even ? 'even' : 'odd' %>">
|
||||
<div class="item">
|
||||
<%= linkify item, h(item.name(true)) %>
|
||||
<small>Resource type: <em><%=item.type_name%></em></small>
|
||||
</div>
|
||||
</li>
|
||||
<% even = !even %>
|
||||
<% end %>
|
|
@ -0,0 +1,9 @@
|
|||
<% even = false %>
|
||||
<% @items.each do |item| %>
|
||||
<li id="object_<%=item.path%>" class="<%= even ? 'even' : 'odd' %>">
|
||||
<div class="item">
|
||||
<%= linkify item, h(item.name(true)) %>
|
||||
</div>
|
||||
</li>
|
||||
<% even = !even %>
|
||||
<% end %>
|
|
@ -0,0 +1,64 @@
|
|||
# Generates the searchable Puppet class list.
|
||||
# @return [void]
|
||||
def generate_puppet_class_list
|
||||
@items = Registry.all(:puppet_class).sort_by { |c| c.name.to_s }
|
||||
@list_title = 'Puppet Class List'
|
||||
@list_type = 'puppet_class'
|
||||
generate_list_contents
|
||||
end
|
||||
|
||||
# Generates the searchable Puppet defined type list.
|
||||
# @return [void]
|
||||
def generate_puppet_defined_type_list
|
||||
@items = Registry.all(:puppet_defined_type).sort_by {|dt| dt.name.to_s }
|
||||
@list_title = 'Defined Type List'
|
||||
@list_type = 'puppet_defined_type'
|
||||
generate_list_contents
|
||||
end
|
||||
|
||||
# Generates the searchable Puppet resource type list.
|
||||
# @return [void]
|
||||
def generate_puppet_type_list
|
||||
@items = Registry.all(:puppet_type).sort_by {|t| t.name.to_s }
|
||||
@list_title = 'Resource Type List'
|
||||
@list_type = 'puppet_type'
|
||||
generate_list_contents
|
||||
end
|
||||
|
||||
# Generates the searchable Puppet provider list.
|
||||
# @return [void]
|
||||
def generate_puppet_provider_list
|
||||
@items = Registry.all(:puppet_provider).sort_by {|p| p.name.to_s }
|
||||
@list_title = 'Provider List'
|
||||
@list_type = 'puppet_provider'
|
||||
generate_list_contents
|
||||
end
|
||||
|
||||
# Generates the searchable Puppet function list.
|
||||
# @return [void]
|
||||
def generate_puppet_function_list
|
||||
@items = Registry.all(:puppet_function).sort_by {|f| f.name.to_s }
|
||||
@list_title = 'Puppet Function List'
|
||||
@list_type = 'puppet_function'
|
||||
generate_list_contents
|
||||
end
|
||||
|
||||
# Generates the searchable Ruby method list.
|
||||
# @return [void]
|
||||
def generate_method_list
|
||||
@items = prune_method_listing(Registry.all(:method), false)
|
||||
@items = @items.reject {|m| m.name.to_s =~ /=$/ && m.is_attribute? }
|
||||
@items = @items.sort_by {|m| m.name.to_s }
|
||||
@list_title = 'Ruby Method List'
|
||||
@list_type = 'method'
|
||||
generate_list_contents
|
||||
end
|
||||
|
||||
# Generate a searchable Ruby class list in the output.
|
||||
# @return [void]
|
||||
def generate_class_list
|
||||
@items = options.objects if options.objects
|
||||
@list_title = 'Ruby Class List'
|
||||
@list_type = 'class'
|
||||
generate_list_contents
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
<% unless @objects_by_letter.empty? %>
|
||||
<h2><%= @title %></h2>
|
||||
|
||||
<% i = 0 %>
|
||||
<table>
|
||||
<tr>
|
||||
<td valign='top' width="33%">
|
||||
<% @objects_by_letter.sort_by {|l,o| l.to_s }.each do |letter, objects| %>
|
||||
<% if (i += 1) % 8 == 0 %>
|
||||
</td>
|
||||
<td valign='top' width="33%">
|
||||
<% i = 0 %>
|
||||
<% end %>
|
||||
<ul id="alpha_<%= letter %>" class="alpha">
|
||||
<li class="letter"><%= letter %></li>
|
||||
<ul>
|
||||
<% objects.each do |obj| %>
|
||||
<li>
|
||||
<%= linkify obj, obj.name %>
|
||||
<% if (obj.type == :module || obj.type == :class) && !obj.namespace.root? %>
|
||||
<small>(<%= obj.namespace.path %>)</small>
|
||||
<% elsif obj.type == :puppet_provider %>
|
||||
<small>(Resource type: <%= obj.type_name %>)</small>
|
||||
<% elsif obj.type == :puppet_function %>
|
||||
<small>(<%= obj.function_type %>)</small>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</ul>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<% end %>
|
|
@ -0,0 +1,172 @@
|
|||
# Initializes the template.
|
||||
# @return [void]
|
||||
def init
|
||||
case object
|
||||
when '_index.html'
|
||||
@page_title = options.title
|
||||
sections :layout, [:index, [:listing, [:classes, :defined_types, :types, :providers, :functions, :files, :objects]]]
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Renders the layout section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def layout
|
||||
@nav_url = url_for_list(!@file || options.index ? menu_lists.first[:type] : 'file')
|
||||
|
||||
case object
|
||||
when nil, String
|
||||
@path = nil
|
||||
when @file
|
||||
@path = @file.path
|
||||
when !object.is_a?(YARD::CodeObjects::NamespaceObject)
|
||||
@path = object.parent.path
|
||||
@nav_url = url_for_list('class')
|
||||
when YARD::CodeObjects::ClassObject
|
||||
@path = object.path
|
||||
@nav_url = url_for_list('class')
|
||||
when PuppetStrings::Yard::CodeObjects::Class
|
||||
@nav_url = url_for_list('puppet_class')
|
||||
@page_title = "Puppet Class: #{object.name}"
|
||||
@path = object.path
|
||||
when PuppetStrings::Yard::CodeObjects::DefinedType
|
||||
@nav_url = url_for_list('puppet_defined_type')
|
||||
@page_title = "Defined Type: #{object.name}"
|
||||
@path = object.path
|
||||
when PuppetStrings::Yard::CodeObjects::Type
|
||||
@nav_url = url_for_list('puppet_type')
|
||||
@page_title = "Resource Type: #{object.name}"
|
||||
@path = object.path
|
||||
when PuppetStrings::Yard::CodeObjects::Provider
|
||||
@nav_url = url_for_list('puppet_provider')
|
||||
@page_title = "Provider: #{object.name}"
|
||||
@path = object.path
|
||||
when PuppetStrings::Yard::CodeObjects::Function
|
||||
@nav_url = url_for_list('puppet_function')
|
||||
@page_title = "Puppet Function: #{object.name} (#{object.function_type})"
|
||||
@path = object.path
|
||||
else
|
||||
@path = object.path
|
||||
end
|
||||
|
||||
erb(:layout)
|
||||
end
|
||||
|
||||
# Creates the dynamic menu lists.
|
||||
# @return [Array<Hash>] Returns the dynamic menu list.
|
||||
def create_menu_lists
|
||||
menu_lists = [
|
||||
{
|
||||
type: 'puppet_class',
|
||||
title: 'Puppet Classes',
|
||||
search_title: 'Puppet Classes'
|
||||
},
|
||||
{
|
||||
type: 'puppet_defined_type',
|
||||
title: 'Defined Types',
|
||||
search_title: 'Defined Types',
|
||||
},
|
||||
{
|
||||
type: 'puppet_type',
|
||||
title: 'Resource Types',
|
||||
search_title: 'Resource Types'
|
||||
},
|
||||
{
|
||||
type: 'puppet_provider',
|
||||
title: 'Providers',
|
||||
search_title: 'Providers'
|
||||
},
|
||||
{
|
||||
type: 'puppet_function',
|
||||
title: 'Puppet Functions',
|
||||
search_title: 'Puppet Functions'
|
||||
},
|
||||
{
|
||||
type: 'class',
|
||||
title: 'Ruby Classes',
|
||||
search_title: 'Class List'
|
||||
},
|
||||
{
|
||||
type: 'method',
|
||||
title: 'Ruby Methods',
|
||||
search_title: 'Method List'
|
||||
},
|
||||
]
|
||||
|
||||
menu_lists.delete_if { |e| YARD::Registry.all(e[:type].intern).empty? }
|
||||
|
||||
# We must always return at least one group, so always keep the files list
|
||||
menu_lists << {
|
||||
type: 'file',
|
||||
title: 'Files',
|
||||
search_title: 'File List'
|
||||
} if menu_lists.empty? || !YARD::Registry.all(:file).empty?
|
||||
|
||||
menu_lists
|
||||
end
|
||||
|
||||
# Gets the menu lists to use.
|
||||
# @return [Array<Hash] Returns the menu lists to use.
|
||||
def menu_lists
|
||||
@@lists ||= create_menu_lists.freeze
|
||||
end
|
||||
|
||||
# Builds a list of objects by letter.
|
||||
# @param [Array] types The types of objects to find.
|
||||
# @return [Hash] Returns a hash of first letter of the object name to list of objects.
|
||||
def objects_by_letter(*types)
|
||||
hash = {}
|
||||
objects = Registry.all(*types).sort_by {|o| o.name.to_s }
|
||||
objects = run_verifier(objects)
|
||||
objects.each {|o| (hash[o.name.to_s[0,1].upcase] ||= []) << o }
|
||||
hash
|
||||
end
|
||||
|
||||
# Renders the classes section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def classes
|
||||
@title = 'Puppet Class Listing A-Z'
|
||||
@objects_by_letter = objects_by_letter(:puppet_class)
|
||||
erb(:objects)
|
||||
end
|
||||
|
||||
# Renders the defined types section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def defined_types
|
||||
@title = 'Defined Type Listing A-Z'
|
||||
@objects_by_letter = objects_by_letter(:puppet_defined_type)
|
||||
erb(:objects)
|
||||
end
|
||||
|
||||
# Renders the types section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def types
|
||||
@title = 'Resource Type Listing A-Z'
|
||||
@objects_by_letter = objects_by_letter(:puppet_type)
|
||||
erb(:objects)
|
||||
end
|
||||
|
||||
# Renders the providers section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def providers
|
||||
@title = 'Puppet Provider Listing A-Z'
|
||||
@objects_by_letter = objects_by_letter(:puppet_provider)
|
||||
erb(:objects)
|
||||
end
|
||||
|
||||
# Renders the functions section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def functions
|
||||
@title = 'Puppet Function Listing A-Z'
|
||||
@objects_by_letter = objects_by_letter(:puppet_function)
|
||||
erb(:objects)
|
||||
end
|
||||
|
||||
# Renders the objects section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def objects
|
||||
@title = 'Ruby Namespace Listing A-Z'
|
||||
@objects_by_letter = objects_by_letter(:class, :module)
|
||||
erb(:objects)
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
<div class="box_info">
|
||||
<% if object.statement.parent_class %>
|
||||
<dl>
|
||||
<dt>Inherits:</dt>
|
||||
<dd><%= linkify(Registry["puppet_classes::#{object.statement.parent_class}"], object.statement.parent_class.dup) %></dd>
|
||||
</dl>
|
||||
<% end %>
|
||||
<% if @subclasses && !@subclasses.empty? %>
|
||||
<dl>
|
||||
<dt>Inherited by:</dt>
|
||||
<dd>
|
||||
<% @subclasses.each do |subclass| %>
|
||||
<%= linkify(subclass, subclass.name.to_s) %><br/>
|
||||
<% end %>
|
||||
</dd>
|
||||
</dl>
|
||||
<% end %>
|
||||
<dl>
|
||||
<dt>Defined in:</dt>
|
||||
<dd>
|
||||
<%= object.file %><% if object.files.size > 1 %><span class="defines">,<br />
|
||||
<%= object.files[1..-1].map {|f| f.first }.join(",<br /> ") %></div>
|
||||
<% end %>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
|
@ -0,0 +1 @@
|
|||
<h1>Puppet Class: <%= object.name %></h1>
|
|
@ -0,0 +1,6 @@
|
|||
<h2>Overview</h2>
|
||||
<div class="docstring">
|
||||
<div class="discussion">
|
||||
<%= htmlify(object.docstring) %>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,14 @@
|
|||
# Initializes the template.
|
||||
# @return [void]
|
||||
def init
|
||||
sections :header, :box_info, :overview, T('tags'), :source
|
||||
end
|
||||
|
||||
# Renders the box_info section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def box_info
|
||||
@subclasses = Registry.all(:puppet_class).find_all { |c|
|
||||
c.statement.parent_class == object.name.to_s
|
||||
}
|
||||
erb(:box_info)
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
<div class="method_details_list">
|
||||
<table class="source_code">
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="lines"><%= "\n\n\n" %><%= h format_lines(object) %></pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre class="code"><span class="info file"># File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %></span><%= "\n\n" %><%= html_syntax_highlight object.source %></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
|
@ -0,0 +1,10 @@
|
|||
<div class="box_info">
|
||||
<dl>
|
||||
<dt>Defined in:</dt>
|
||||
<dd>
|
||||
<%= object.file %><% if object.files.size > 1 %><span class="defines">,<br />
|
||||
<%= object.files[1..-1].map {|f| f.first }.join(",<br /> ") %></div>
|
||||
<% end %>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
|
@ -0,0 +1 @@
|
|||
<h1>Defined Type: <%= object.name %></h1>
|
|
@ -0,0 +1,6 @@
|
|||
<h2>Overview</h2>
|
||||
<div class="docstring">
|
||||
<div class="discussion">
|
||||
<%= htmlify(object.docstring) %>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,5 @@
|
|||
# Initializes the template.
|
||||
# @return [void]
|
||||
def init
|
||||
sections :header, :box_info, :overview, T('tags'), :source
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
<div class="method_details_list">
|
||||
<table class="source_code">
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="lines"><%= "\n\n\n" %><%= h format_lines(object) %></pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre class="code"><span class="info file"># File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %></span><%= "\n\n" %><%= html_syntax_highlight object.source %></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
|
@ -0,0 +1,14 @@
|
|||
<div class="box_info">
|
||||
<dl>
|
||||
<dt>Defined in:</dt>
|
||||
<dd>
|
||||
<%= object.file %><% if object.files.size > 1 %><span class="defines">,<br />
|
||||
<%= object.files[1..-1].map {|f| f.first }.join(",<br /> ") %></div>
|
||||
<% end %>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Function type:</dt>
|
||||
<dd><%= object.function_type %></dd>
|
||||
</dl>
|
||||
</div>
|
|
@ -0,0 +1 @@
|
|||
<h1>Puppet Function: <%= object.name %></h1>
|
|
@ -0,0 +1,18 @@
|
|||
<h2>Overview</h2>
|
||||
<div class="method_details first">
|
||||
<% unless object.has_tag? :overload %>
|
||||
<div class="tags overload overload_item">
|
||||
<span class="overload">
|
||||
<span class="overload_item">
|
||||
<span class="signature first" style="margin-left: 0px;"><%= "<strong>#{h(object.signature)}</strong> ⇒ #{signature_types(object, false)}" %></span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="docstring">
|
||||
<div class="discussion">
|
||||
<%= htmlify(object.docstring) %>
|
||||
</div>
|
||||
</div>
|
||||
<%= yieldall %>
|
||||
</div>
|
|
@ -0,0 +1,5 @@
|
|||
# Initializes the template.
|
||||
# @return [void]
|
||||
def init
|
||||
sections :header, :box_info, :overview, [T('tags'), :source]
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
<div class="method_details_list">
|
||||
<table class="source_code">
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="lines"><%= "\n\n\n" %><%= h format_lines(object) %></pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre class="code"><span class="info file"># File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %></span><%= "\n\n" %><%= html_syntax_highlight object.source %></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
|
@ -0,0 +1,14 @@
|
|||
<div class="box_info">
|
||||
<dl>
|
||||
<dt>Defined in:</dt>
|
||||
<dd>
|
||||
<%= object.file %><% if object.files.size > 1 %><span class="defines">,<br />
|
||||
<%= object.files[1..-1].map {|f| f.first }.join(",<br /> ") %></div>
|
||||
<% end %>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Resource type:</dt>
|
||||
<dd><%= linkify(Registry["puppet_types::#{object.type_name}"], object.type_name) %></dd>
|
||||
</dl>
|
||||
</div>
|
|
@ -0,0 +1,10 @@
|
|||
<% if @collection && !@collection.empty? %>
|
||||
<div class="tags">
|
||||
<p class="tag_title"><%= @title %></p>
|
||||
<ul>
|
||||
<% @collection.each do |key, value| %>
|
||||
<li><tt><%= key %> — <%= value %></tt></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
|
@ -0,0 +1,12 @@
|
|||
<% if object.features && !object.features.empty? %>
|
||||
<div class="tags">
|
||||
<p class="tag_title">Features</p>
|
||||
<ul>
|
||||
<% object.features.each do |feature| %>
|
||||
<li>
|
||||
<span class="name"><%= feature %></span>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
|
@ -0,0 +1 @@
|
|||
<h1>Provider: <%= object.name %></h1>
|
|
@ -0,0 +1,6 @@
|
|||
<h2>Overview</h2>
|
||||
<div class="docstring">
|
||||
<div class="discussion">
|
||||
<%= htmlify(object.docstring) %>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,29 @@
|
|||
# Initializes the template.
|
||||
# @return [void]
|
||||
def init
|
||||
sections :header, :box_info, :overview, T('tags'), :features, :confines, :defaults, :commands
|
||||
end
|
||||
|
||||
# Renders the confines section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def confines
|
||||
@title = 'Confines'
|
||||
@collection = object.confines
|
||||
erb(:collection)
|
||||
end
|
||||
|
||||
# Renders the defaults section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def defaults
|
||||
@title = 'Default Provider For'
|
||||
@collection = object.defaults
|
||||
erb(:collection)
|
||||
end
|
||||
|
||||
# Renders the commands section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def commands
|
||||
@title = 'Commands'
|
||||
@collection = object.commands
|
||||
erb(:collection)
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
<div class="box_info">
|
||||
<dl>
|
||||
<dt>Defined in:</dt>
|
||||
<dd>
|
||||
<%= object.file %><% if object.files.size > 1 %><span class="defines">,<br />
|
||||
<%= object.files[1..-1].map {|f| f.first }.join(",<br /> ") %></div>
|
||||
<% end %>
|
||||
</dd>
|
||||
</dl>
|
||||
<% if @providers && !@providers.empty? %>
|
||||
<dl>
|
||||
<dt>Providers:</dt>
|
||||
<dd>
|
||||
<% @providers.each do |provider| %>
|
||||
<%= linkify(provider, provider.name.to_s) %><br/>
|
||||
<% end %>
|
||||
</dd>
|
||||
</dl>
|
||||
<% end %>
|
||||
</div>
|
|
@ -0,0 +1,13 @@
|
|||
<% if object.features && !object.features.empty? %>
|
||||
<div class="tags">
|
||||
<p class="tag_title">Features</p>
|
||||
<ul>
|
||||
<% object.features.each do |feature| %>
|
||||
<li>
|
||||
<span class="name"><%= feature.name %></span>
|
||||
<% unless feature.docstring.empty? %> — <%= htmlify_line(feature.docstring) %><% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
|
@ -0,0 +1 @@
|
|||
<h1>Resource Type: <%= object.name %></h1>
|
|
@ -0,0 +1,6 @@
|
|||
<h2>Overview</h2>
|
||||
<div class="docstring">
|
||||
<div class="discussion">
|
||||
<%= htmlify(object.docstring) %>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,35 @@
|
|||
<% if @parameters && !@parameters.empty? %>
|
||||
<div class="tags">
|
||||
<p class="tag_title"><%= @tag_title %></p>
|
||||
<ul>
|
||||
<% @parameters.each do |parameter| %>
|
||||
<li>
|
||||
<span class="name"><%= parameter.name + (parameter.isnamevar ? ' (namevar)' : '') %></span>
|
||||
<% if parameter.default %>
|
||||
<span class="default"> (defaults to: <em><%= parameter.default %></em>)</span>
|
||||
<% end %>
|
||||
<% unless parameter.docstring.empty? %>
|
||||
<div class="docstring">
|
||||
<div class="discussion">
|
||||
<%= htmlify(parameter.docstring) %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% unless parameter.values.empty? %>
|
||||
<div>
|
||||
Supported values:
|
||||
<ul>
|
||||
<% parameter.values.each do |value| %>
|
||||
<li>
|
||||
<% other = parameter.aliases[value] %>
|
||||
<%= value %><% if other %> (alias for: <em><%= other %></em>)<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
|
@ -0,0 +1,32 @@
|
|||
# Initializes the template.
|
||||
# @return [void]
|
||||
def init
|
||||
sections :header, :box_info, :overview, T('tags'), :properties, :parameters, :features
|
||||
end
|
||||
|
||||
# Renders the box_info section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def box_info
|
||||
@providers = PuppetStrings::Yard::CodeObjects::Providers.instance(object.name).children
|
||||
erb(:box_info)
|
||||
end
|
||||
|
||||
# Renders the properties section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def properties
|
||||
# Properties are the same thing as parameters (from the documentation standpoint),
|
||||
# so reuse the same template but with a different title and data source.
|
||||
@parameters = object.properties || []
|
||||
@parameters.sort_by! { |p| p.name }
|
||||
@tag_title = 'Properties'
|
||||
erb(:parameters)
|
||||
end
|
||||
|
||||
# Renders the parameters section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def parameters
|
||||
@parameters = object.parameters || []
|
||||
@parameters.sort_by! { |p| p.name }
|
||||
@tag_title = 'Parameters'
|
||||
erb(:parameters)
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
<% if object.has_tag?(:overload) && object.tags(:overload).any? {|o| !o.docstring.blank? } %>
|
||||
<p class="tag_title">Overloads:</p>
|
||||
<ul class="overload">
|
||||
<% object.tags(:overload).each_with_index do |overload, index| %>
|
||||
<% next if overload.docstring.blank? %>
|
||||
<li class="overload_item">
|
||||
<span class="signature"><%= "<strong>#{h(overload.signature)}</strong> ⇒ #{signature_types(overload, false)}" %></span>
|
||||
<%= yieldall :object => overload %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
|
@ -0,0 +1,15 @@
|
|||
# Called to return parameter tags.
|
||||
# @return [Array<YARD::Tag>] Returns the parameter tags if the object should have parameters.
|
||||
def param
|
||||
tag(:param) if
|
||||
object.type == :method ||
|
||||
object.type == :puppet_class ||
|
||||
object.type == :puppet_defined_type ||
|
||||
object.type == :puppet_function
|
||||
end
|
||||
|
||||
# Renders the overload section.
|
||||
# @return [String] Returns the rendered section.
|
||||
def overload
|
||||
erb(if object.type == :puppet_function then :puppet_overload else :overload end)
|
||||
end
|
|
@ -1,4 +1,5 @@
|
|||
require 'puppet/application/face_base'
|
||||
|
||||
# Implements the 'puppet strings' application.
|
||||
class Puppet::Application::Strings < Puppet::Application::FaceBase
|
||||
end
|
||||
|
|
|
@ -1,64 +1,105 @@
|
|||
require 'puppet/face'
|
||||
require 'puppet_x/puppetlabs/strings/yard/tags/directives'
|
||||
|
||||
# Implements the 'puppet strings' interface.
|
||||
Puppet::Face.define(:strings, '0.0.1') do
|
||||
summary "Generate Puppet documentation with YARD."
|
||||
summary 'Generate Puppet documentation with YARD.'
|
||||
|
||||
# Ensures that the user has the needed features to use puppet strings
|
||||
def check_required_features
|
||||
unless Puppet.features.yard?
|
||||
raise RuntimeError, "The 'yard' gem must be installed in order to use this face."
|
||||
end
|
||||
|
||||
unless Puppet.features.rgen?
|
||||
raise RuntimeError, "The 'rgen' gem must be installed in order to use this face."
|
||||
end
|
||||
|
||||
if RUBY_VERSION.match(/^1\.8/)
|
||||
raise RuntimeError, "This face requires Ruby 1.9 or greater."
|
||||
end
|
||||
end
|
||||
|
||||
action(:yardoc) do
|
||||
action(:generate) do
|
||||
default
|
||||
|
||||
option "--emit-json-stdout" do
|
||||
summary "Print json representation of the documentation to stdout"
|
||||
option '--emit-json-stdout' do
|
||||
summary 'Print JSON representation of the documentation to stdout.'
|
||||
end
|
||||
option "--emit-json FILE" do
|
||||
summary "Write json representation of the documentation to FILE"
|
||||
option '--emit-json FILE' do
|
||||
summary 'Write JSON representation of the documentation to the given file.'
|
||||
end
|
||||
option '--markup FORMAT' do
|
||||
summary "The markup format to use for docstring text (defaults to 'markdown')."
|
||||
end
|
||||
|
||||
summary "Generate YARD documentation from files."
|
||||
arguments "[manifest_file.pp ...]"
|
||||
summary 'Generate documentation from files.'
|
||||
arguments '[[search_pattern] ...]'
|
||||
|
||||
when_invoked do |*args|
|
||||
check_required_features
|
||||
require 'puppet_x/puppetlabs/strings/util'
|
||||
require 'puppet-strings'
|
||||
|
||||
PuppetX::PuppetLabs::Strings::Util.generate(args)
|
||||
|
||||
# Puppet prints the return value of the action. The return value of this
|
||||
# action is that of the yardoc_actions invocation, which is the boolean
|
||||
# "true". This clutters the statistics yard prints, so instead return the
|
||||
# empty string. Note an extra newline will also be printed.
|
||||
""
|
||||
PuppetStrings::generate(
|
||||
args.count > 1 ? args[0..-2] : PuppetStrings::DEFAULT_SEARCH_PATTERNS,
|
||||
build_generate_options(args.last)
|
||||
)
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# NOTE: Modeled after the `yard gems` command which builds doc indicies
|
||||
# (.yardoc directories) for Ruby Gems. Currently lacks the fine-grained
|
||||
# control over where these indicies are created and just dumps them in the
|
||||
# module roots.
|
||||
|
||||
action(:server) do
|
||||
summary "Serve YARD documentation for modules."
|
||||
option '--markup FORMAT' do
|
||||
summary "The markup format to use for docstring text (defaults to 'markdown')."
|
||||
end
|
||||
|
||||
summary 'Runs a local documentation server for the modules in the current Puppet environment.'
|
||||
arguments '[[module_name] ...]'
|
||||
|
||||
when_invoked do |*args|
|
||||
check_required_features
|
||||
require 'puppet_x/puppetlabs/strings/util'
|
||||
require 'puppet-strings'
|
||||
|
||||
PuppetX::PuppetLabs::Strings::Util.serve(args)
|
||||
modules = args.count > 1 ? args[0..-2] : []
|
||||
|
||||
# Generate documentation for all (or the given) modules
|
||||
module_docs = []
|
||||
environment = Puppet.lookup(:current_environment)
|
||||
environment.modules.each do |mod|
|
||||
next unless modules.empty? || modules.include?(mod.name)
|
||||
db = File.join(mod.path, '.yardoc')
|
||||
patterns = PuppetStrings::DEFAULT_SEARCH_PATTERNS.map do |p|
|
||||
File.join(mod.path, p)
|
||||
end
|
||||
puts "Generating documentation for Puppet module '#{mod.name}'."
|
||||
PuppetStrings.generate(patterns, build_generate_options(args.last, '--db', db))
|
||||
|
||||
# Clear the registry so that the next call to generate has a clean database
|
||||
YARD::Registry.clear
|
||||
|
||||
module_docs << mod.name
|
||||
module_docs << db
|
||||
end
|
||||
|
||||
if module_docs.empty?
|
||||
puts 'No Puppet modules were found to serve documentation for.'
|
||||
return
|
||||
end
|
||||
puts 'Starting YARD documentation server.'
|
||||
PuppetStrings::run_server('-m', *module_docs)
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Checks that the required features are installed.
|
||||
# @return [void]
|
||||
def check_required_features
|
||||
raise RuntimeError, "The 'yard' gem must be installed in order to use this face." unless Puppet.features.yard?
|
||||
raise RuntimeError, "The 'rgen' gem must be installed in order to use this face." unless Puppet.features.rgen?
|
||||
raise RuntimeError, 'This face requires Ruby 1.9 or greater.' if RUBY_VERSION =~ /^1\.8/
|
||||
end
|
||||
|
||||
# Builds the options to PuppetStrings.generate.
|
||||
# @param [Hash] options The Puppet face options hash.
|
||||
# @param [Array] yard_args The additional arguments to pass to YARD.
|
||||
# @return [Hash] Returns the PuppetStrings.generate options hash.
|
||||
def build_generate_options(options = nil, *yard_args)
|
||||
generate_options = {}
|
||||
generate_options[:debug] = Puppet[:debug]
|
||||
generate_options[:backtrace] = Puppet[:trace]
|
||||
generate_options[:yard_args] = yard_args unless yard_args.empty?
|
||||
|
||||
if options
|
||||
markup = options[:markup]
|
||||
generate_options[:markup] = markup if markup
|
||||
json_file = options[:emit_json]
|
||||
generate_options[:json] = json_file if json_file
|
||||
generate_options[:json] = nil if options[:emit_json_stdout]
|
||||
end
|
||||
generate_options
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
require 'puppet'
|
||||
require 'puppet/pops'
|
||||
require 'puppet/util/docs'
|
||||
require 'yard'
|
||||
|
||||
module PuppetX
|
||||
end
|
||||
|
||||
# Nothing to see here except forward declarations.
|
||||
module PuppetX::PuppetLabs
|
||||
module Strings
|
||||
# This submodule contains bits that operate on the Pops module produced by
|
||||
# the Future parser.
|
||||
module Pops
|
||||
require 'puppet_x/puppetlabs/strings/pops/yard_statement'
|
||||
require 'puppet_x/puppetlabs/strings/pops/yard_transformer'
|
||||
end
|
||||
|
||||
# This submodule contains bits that interface with the YARD plugin system.
|
||||
module YARD
|
||||
require 'puppet_x/puppetlabs/strings/yard/monkey_patches'
|
||||
require 'puppet_x/puppetlabs/strings/yard/parser'
|
||||
|
||||
module Tags
|
||||
require 'puppet_x/puppetlabs/strings/yard/tags/directives'
|
||||
end
|
||||
|
||||
# This submodule contains code objects which are used to represent relevant
|
||||
# aspects of puppet code in YARD's Registry
|
||||
module CodeObjects
|
||||
require 'puppet_x/puppetlabs/strings/yard/code_objects/puppet_namespace_object'
|
||||
require 'puppet_x/puppetlabs/strings/yard/code_objects/method_object'
|
||||
require 'puppet_x/puppetlabs/strings/yard/code_objects/defined_type_object'
|
||||
require 'puppet_x/puppetlabs/strings/yard/code_objects/host_class_object'
|
||||
require 'puppet_x/puppetlabs/strings/yard/code_objects/type_object'
|
||||
require 'puppet_x/puppetlabs/strings/yard/code_objects/provider_object'
|
||||
end
|
||||
|
||||
# This submodule contains handlers which are used to extract relevant data about
|
||||
# puppet code from the ASTs produced by the Ruby and Puppet parsers
|
||||
module Handlers
|
||||
# This utility library contains some tools for working with Puppet docstrings
|
||||
require 'puppet_x/puppetlabs/strings/yard/handlers/base'
|
||||
require 'puppet_x/puppetlabs/strings/yard/handlers/defined_type_handler'
|
||||
require 'puppet_x/puppetlabs/strings/yard/handlers/host_class_handler'
|
||||
require 'puppet_x/puppetlabs/strings/yard/handlers/puppet_3x_function_handler'
|
||||
require 'puppet_x/puppetlabs/strings/yard/handlers/puppet_4x_function_handler'
|
||||
require 'puppet_x/puppetlabs/strings/yard/handlers/type_handler'
|
||||
require 'puppet_x/puppetlabs/strings/yard/handlers/provider_handler'
|
||||
end
|
||||
|
||||
::YARD::Parser::SourceParser.register_parser_type(:puppet,
|
||||
PuppetX::PuppetLabs::Strings::YARD::PuppetParser,
|
||||
['pp'])
|
||||
::YARD::Handlers::Processor.register_handler_namespace(:puppet,
|
||||
PuppetX::PuppetLabs::Strings::YARD::Handlers)
|
||||
|
||||
# FIXME: Might not be the best idea to have the template code on the Ruby
|
||||
# LOAD_PATH as the contents of this directory really aren't library code.
|
||||
::YARD::Templates::Engine.register_template_path(
|
||||
File.join(File.dirname(__FILE__), 'strings', 'yard', 'templates'))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,92 +0,0 @@
|
|||
require 'puppet_x/puppetlabs/strings'
|
||||
|
||||
class PuppetX::PuppetLabs::Strings::Actions
|
||||
|
||||
# Creates a new instance of the Actions class by determining
|
||||
# whether or not debug and backtrace arguments should be sent
|
||||
# to YARD
|
||||
def initialize(puppet_debug, puppet_backtrace)
|
||||
@debug = puppet_debug
|
||||
@backtrace = puppet_backtrace
|
||||
end
|
||||
|
||||
# Holds the name of a module and the file path to its YARD index
|
||||
ModuleIndex = Struct.new(:name, :index_path)
|
||||
|
||||
|
||||
# Maps things like the Puppet `--debug` flag to YARD options.
|
||||
def merge_puppet_args!(yard_args)
|
||||
yard_args.unshift '--debug' if @debug
|
||||
yard_args.unshift '--backtrace' if @backtrace
|
||||
|
||||
yard_args
|
||||
end
|
||||
|
||||
# Builds doc indices (.yardoc directories) for modules.
|
||||
# Currently lacks the fine-grained control over where these
|
||||
# indices are created and just dumps them in the module roots.
|
||||
#
|
||||
# @return [Array<Module>] the modules to be documented
|
||||
#
|
||||
# @param [Array<String>] module_names a list of the module source files
|
||||
# @param [Array<String>] module_sourcefiles default list of module files
|
||||
def index_documentation_for_modules(module_names, module_sourcefiles)
|
||||
# NOTE: The return value of the `module` Face seems to have changed in
|
||||
# 3.6.x. This part of the code will blow up if run under an earlier
|
||||
# version of Puppet.
|
||||
modules = Puppet::Face[:module, :current].list
|
||||
module_list = modules[:modules_by_path].values.flatten
|
||||
|
||||
module_list.select! {|m| module_names.include? m.name} unless module_names.empty?
|
||||
|
||||
# Invoke `yardoc` with -n so that it doesn't generate any HTML output but
|
||||
# does build a `.yardoc` index that other tools can generate output from.
|
||||
yard_args = %w[--no-stats -n] + module_sourcefiles
|
||||
merge_puppet_args!(yard_args)
|
||||
|
||||
module_list.each do |m|
|
||||
Dir.chdir(m.path) do
|
||||
YARD::CLI::Yardoc.run(*yard_args)
|
||||
|
||||
# Clear the global Registry so that objects from one module don't
|
||||
# bleed into the next.
|
||||
YARD::Registry.clear
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Extracts the needed information of the modules we're documenting
|
||||
#
|
||||
# @return [Array<ModuleIndex>] An array of representation of the modules
|
||||
# to produce documentation for. Each ModuleIndex contains the module name
|
||||
# and the path to its YARD index
|
||||
#
|
||||
# @param [Array<String>] module_list a list of the module source files
|
||||
def generate_module_tuples(module_list)
|
||||
module_list.map do |mod|
|
||||
name = (mod.forge_name || mod.name).gsub('/', '-')
|
||||
yard_index = File.join(mod.path, '.yardoc')
|
||||
|
||||
ModuleIndex.new(name, yard_index)
|
||||
end
|
||||
end
|
||||
|
||||
# Hands off the needed information to YARD so it may
|
||||
# serve the documentation
|
||||
#
|
||||
# @param [Array<String>] yard_args a list of all the arguments to pass to YARD
|
||||
def serve_documentation(*yard_args)
|
||||
merge_puppet_args!(yard_args)
|
||||
YARD::CLI::Server.run(*yard_args)
|
||||
end
|
||||
|
||||
# Hands off the needed information to YARD so it may
|
||||
# generate the documentation
|
||||
#
|
||||
# @param [Array<String>] yard_args a list of all the arguments to pass to YARD
|
||||
def generate_documentation(*yard_args)
|
||||
merge_puppet_args!(yard_args)
|
||||
YARD::CLI::Yardoc.run(*yard_args)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
require 'ostruct'
|
||||
|
||||
# An adapter class that conforms a Pops model instance + adapters to the
|
||||
# interface expected by YARD handlers.
|
||||
#
|
||||
# FIXME: Inhertiting from OpenStruct is a bit of a hack. It allows attributes
|
||||
# to be declared as needed but in the long run understandibility of the code
|
||||
# would be improved by having a concrete model.
|
||||
class PuppetX::PuppetLabs::Strings::Pops::YARDStatement < OpenStruct
|
||||
attr_reader :pops_obj, :comments
|
||||
|
||||
def initialize(pops_obj)
|
||||
# Initialize OpenStruct
|
||||
super({})
|
||||
|
||||
unless pops_obj.is_a? Puppet::Pops::Model::PopsObject
|
||||
raise ArgumentError, "A YARDStatement can only be initialized from a PopsObject. Got a: #{pops_obj.class}"
|
||||
end
|
||||
|
||||
@pops_obj = pops_obj
|
||||
@pos_adapter = Puppet::Pops::Adapters::SourcePosAdapter.adapt(@pops_obj)
|
||||
# FIXME: Perhaps this should be a seperate adapter?
|
||||
@comments = extract_comments
|
||||
end
|
||||
|
||||
def type
|
||||
pops_obj.class
|
||||
end
|
||||
|
||||
def line
|
||||
@line ||= @pos_adapter.line
|
||||
end
|
||||
|
||||
def source
|
||||
@source ||= @pos_adapter.extract_text
|
||||
end
|
||||
|
||||
# FIXME: I don't know quite what these are supposed to do, but they show up
|
||||
# quite often in the YARD handler code. Figure out whether they are
|
||||
# necessary.
|
||||
alias_method :show, :source
|
||||
def comments_hash_flag; nil end
|
||||
def comments_range; nil end
|
||||
|
||||
private
|
||||
# TODO: This stuff should probably be part of a separate class/adapter.
|
||||
COMMENT_PATTERN = /^\s*#.*\n/
|
||||
|
||||
def extract_comments
|
||||
comments = []
|
||||
program = pops_obj.eAllContainers.find {|c| c.is_a?(Puppet::Pops::Model::Program) }
|
||||
# FIXME: Horribly inefficient. Multiple copies. Generator pattern would
|
||||
# be much better.
|
||||
source_text = program.source_text.lines.to_a
|
||||
|
||||
source_text.slice(0, line-1).reverse.each do |line|
|
||||
if COMMENT_PATTERN.match(line)
|
||||
# FIXME: The gsub trims comments, but is extremely optimistic: It
|
||||
# assumes only one space separates the comment body from the
|
||||
# comment character.
|
||||
# NOTE: We cannot just trim any amount of whitespace as indentation
|
||||
# is sometimes significant in markdown. We would need a real parser.
|
||||
|
||||
# Comments which begin with some whitespace, a hash and then some
|
||||
# tabs and spaces should be scrubbed. Comments which just have a
|
||||
# solitary hash then a newline should keep that newline since newlines
|
||||
# are significant in markdown.
|
||||
comments.unshift line.gsub(/^\s*#[\t ]/, '').gsub(/^\s*#\n/, "\n")
|
||||
else
|
||||
# No comment found on this line. We must be done piecing together a
|
||||
# comment block.
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# Stick everything back together.
|
||||
comments.join
|
||||
end
|
||||
end
|
|
@ -1,47 +0,0 @@
|
|||
# Loosely based on the TreeDumper classes in Pops::Model. The responsibility of
|
||||
# this class is to walk a Pops::Model and output objects that can be consumed
|
||||
# by YARD handlers.
|
||||
#
|
||||
# @note Currently, this class only extracts node, host class and type
|
||||
# definitions.
|
||||
class PuppetX::PuppetLabs::Strings::Pops::YARDTransformer
|
||||
def initialize
|
||||
@transform_visitor = Puppet::Pops::Visitor.new(self, 'transform')
|
||||
end
|
||||
|
||||
def transform(o)
|
||||
@transform_visitor.visit(o)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def transform_Factory(o)
|
||||
transform(o.current)
|
||||
end
|
||||
|
||||
def transform_Program(o)
|
||||
o.definitions.map{|d| transform(d)}
|
||||
end
|
||||
|
||||
# Extract comments from type definitions and class definitions. Wrap them
|
||||
# into YARDStatement objects that provide an interface for YARD handlers.
|
||||
def transform_NamedDefinition(o)
|
||||
obj = PuppetX::PuppetLabs::Strings::Pops::YARDStatement.new(o)
|
||||
obj.parameters = o.parameters.map do |p|
|
||||
param_tuple = [transform(p)]
|
||||
param_tuple << ( p.value.nil? ? nil : transform(p.value) )
|
||||
end
|
||||
|
||||
obj
|
||||
end
|
||||
|
||||
# Catch-all visitor.
|
||||
def transform_Positioned(o)
|
||||
PuppetX::PuppetLabs::Strings::Pops::YARDStatement.new(o)
|
||||
end
|
||||
|
||||
# nil in... nil out!
|
||||
def transform_NilClass(o)
|
||||
nil
|
||||
end
|
||||
end
|
|
@ -1,65 +0,0 @@
|
|||
require 'puppet_x/puppetlabs/strings/actions'
|
||||
|
||||
module PuppetX::PuppetLabs::Strings::Util
|
||||
MODULE_SOURCEFILES = ['manifests/**/*.pp', 'lib/**/*.rb']
|
||||
|
||||
def self.generate(args = [])
|
||||
yardoc_actions = PuppetX::PuppetLabs::Strings::Actions.new(Puppet[:debug], Puppet[:trace])
|
||||
|
||||
# The last element of the argument array should be the options hash.
|
||||
# We don't have any options yet, so for now just pop the hash off and
|
||||
# toss it.
|
||||
#
|
||||
# NOTE: The Puppet Face will throw 'unrecognized option' errors if any
|
||||
# YARD options are passed to it. The best way to approach this problem is
|
||||
# by using the `.yardopts` file. YARD will autoload any options placed in
|
||||
# that file.
|
||||
options = args.pop
|
||||
YARD::Config.options = YARD::Config.options.merge(options) if options
|
||||
|
||||
# For now, assume the remaining positional args are a list of manifest
|
||||
# and ruby files to parse.
|
||||
yard_args = (args.empty? ? MODULE_SOURCEFILES : args)
|
||||
|
||||
# If json is going to be emitted to stdout, suppress statistics.
|
||||
if options && options[:emit_json_stdout]
|
||||
yard_args.push('--no-stats')
|
||||
end
|
||||
|
||||
# This line monkeypatches yard's progress indicator so it doesn't write
|
||||
# all over the terminal. This should definitely not be in real code, but
|
||||
# it's very handy for debugging with pry
|
||||
#class YARD::Logger; def progress(*args); end; end
|
||||
YARD::Tags::Library.define_directive("puppet.type.param",
|
||||
:with_types_and_name,
|
||||
PuppetX::PuppetLabs::Strings::YARD::Tags::PuppetTypeParameterDirective)
|
||||
|
||||
yardoc_actions.generate_documentation(*yard_args)
|
||||
end
|
||||
|
||||
def self.serve(args = [])
|
||||
server_actions = PuppetX::PuppetLabs::Strings::Actions.new(Puppet[:debug], Puppet[:trace])
|
||||
|
||||
args.pop
|
||||
|
||||
module_names = args
|
||||
|
||||
# FIXME: This is pretty inefficient as it forcibly re-generates the YARD
|
||||
# indicies each time the server is started. However, it ensures things are
|
||||
# generated properly.
|
||||
module_list = server_actions.index_documentation_for_modules(module_names, MODULE_SOURCEFILES)
|
||||
|
||||
module_tuples = server_actions.generate_module_tuples(module_list)
|
||||
|
||||
module_tuples.map! do |mod|
|
||||
[mod[:name], mod[:index_path]]
|
||||
end
|
||||
|
||||
# The `-m` flag means a list of name/path pairs will follow. The name is
|
||||
# used as the module name and the path indicates which `.yardoc` index to
|
||||
# generate documentation from.
|
||||
yard_args = %w[-m -q] + module_tuples.flatten
|
||||
|
||||
server_actions.serve_documentation(*yard_args)
|
||||
end
|
||||
end
|
|
@ -1,33 +0,0 @@
|
|||
require 'json'
|
||||
|
||||
class PuppetX::PuppetLabs::Strings::YARD::CodeObjects::DefinedTypeObject < PuppetX::PuppetLabs::Strings::YARD::CodeObjects::PuppetNamespaceObject
|
||||
# A list of parameters attached to this class.
|
||||
# @return [Array<Array(String, String)>]
|
||||
attr_accessor :parameters
|
||||
attr_accessor :type_info
|
||||
|
||||
def to_s
|
||||
name.to_s
|
||||
end
|
||||
|
||||
def to_json(*a)
|
||||
{
|
||||
"name" => @name,
|
||||
"file" => file,
|
||||
"line" => line,
|
||||
"parameters" => Hash[@parameters],
|
||||
"docstring" => Puppet::Util::Docs.scrub(@docstring),
|
||||
"signatures" => @type_info.map do |signature|
|
||||
signature.map do |key, value|
|
||||
{
|
||||
"name" => key,
|
||||
"type" => value,
|
||||
}
|
||||
end
|
||||
end,
|
||||
"examples" => self.tags.map do |tag|
|
||||
tag.text if tag.tag_name == 'example'
|
||||
end.compact,
|
||||
}.to_json(*a)
|
||||
end
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
class PuppetX::PuppetLabs::Strings::YARD::CodeObjects::HostClassObject < PuppetX::PuppetLabs::Strings::YARD::CodeObjects::DefinedTypeObject
|
||||
# The {HostClassObject} that this class inherits from, if any.
|
||||
# @return [HostClassObject, Proxy, nil]
|
||||
attr_accessor :parent_class
|
||||
|
||||
# NOTE: `include_mods` is never used as it makes no sense for Puppet, but
|
||||
# this is called by `YARD::Registry` and it will pass a parameter.
|
||||
def inheritance_tree(include_mods = false)
|
||||
if parent_class.is_a?(PuppetX::PuppetLabs::Strings::YARD::CodeObjects::HostClassObject)
|
||||
# Cool. We got a host class. Return self + parent inheritance tree.
|
||||
[self] + parent_class.inheritance_tree
|
||||
elsif parent_class.is_a?(YARD::CodeObjects::Proxy)
|
||||
# We have a reference to a parent that has not been created yet. Just
|
||||
# return it.
|
||||
[self, parent_class]
|
||||
else
|
||||
# Most likely no parent class. But also possibly an object that we
|
||||
# shouldn't inherit from. Just return self.
|
||||
[self]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,62 +0,0 @@
|
|||
class YARD::CodeObjects::MethodObject
|
||||
|
||||
# Override to_s and to_json methods in Yard's MethodObject so that they
|
||||
# return output formatted as I like for puppet 3x and 4x methods.
|
||||
def to_s
|
||||
if self[:puppet_4x_function] || self[:puppet_3x_function]
|
||||
name.to_s
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def to_json(*a)
|
||||
if self[:puppet_4x_function]
|
||||
{
|
||||
"name" => @name,
|
||||
"file" => file,
|
||||
"line" => line,
|
||||
"function_api_version" => 4,
|
||||
"docstring" => Puppet::Util::Docs.scrub(@docstring),
|
||||
"examples" => self.tags.map do |tag|
|
||||
tag.text if tag.tag_name == 'example'
|
||||
end.compact,
|
||||
"documented_params" => @parameters.map do |tuple|
|
||||
{
|
||||
"name" => tuple[0],
|
||||
"type" => tuple[1],
|
||||
}
|
||||
end,
|
||||
"signatures" => @type_info.map do |signature|
|
||||
signature.map do |key, value|
|
||||
{
|
||||
"name" => key,
|
||||
"type" => value,
|
||||
}
|
||||
end
|
||||
end,
|
||||
}.to_json(*a)
|
||||
elsif self[:puppet_3x_function]
|
||||
{
|
||||
"name" => @name,
|
||||
"file" => file,
|
||||
"line" => line,
|
||||
"function_api_version" => 3,
|
||||
"docstring" => Puppet::Util::Docs.scrub(@docstring),
|
||||
"documented_params" => @parameters.map do |tuple|
|
||||
{
|
||||
"name" => tuple[0],
|
||||
"type" => tuple[1],
|
||||
}
|
||||
end,
|
||||
"examples" => self.tags.map do |tag|
|
||||
tag.text if tag.tag_name == 'example'
|
||||
end.compact,
|
||||
}.to_json(*a)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
class PuppetX::PuppetLabs::Strings::YARD::CodeObjects::ProviderObject < PuppetX::PuppetLabs::Strings::YARD::CodeObjects::PuppetNamespaceObject
|
||||
# A list of parameters attached to this class.
|
||||
# @return [Array<Array(String, String)>]
|
||||
attr_accessor :parameters
|
||||
|
||||
def to_json(*a)
|
||||
{
|
||||
"name" => @name,
|
||||
"type_name" => @type_name,
|
||||
"file" => file,
|
||||
"line" => line,
|
||||
"docstring" => Puppet::Util::Docs.scrub(@docstring),
|
||||
"commands" => @commands,
|
||||
"confines" => @confines,
|
||||
"defaults" => @defaults,
|
||||
"features" => @features,
|
||||
"examples" => self.tags.map do |tag|
|
||||
tag.text if tag.tag_name == 'example'
|
||||
end.compact,
|
||||
}.to_json(*a)
|
||||
end
|
||||
|
||||
|
||||
end
|
|
@ -1,48 +0,0 @@
|
|||
class PuppetX::PuppetLabs::Strings::YARD::CodeObjects::PuppetNamespaceObject < YARD::CodeObjects::NamespaceObject
|
||||
|
||||
attr_accessor :type_info
|
||||
# NOTE: `YARD::Registry#resolve` requires a method with this signature to
|
||||
# be present on all subclasses of `NamespaceObject`.
|
||||
def inheritance_tree(include_mods = false)
|
||||
[self]
|
||||
end
|
||||
|
||||
def to_s
|
||||
name.to_s
|
||||
end
|
||||
|
||||
def to_json(*a)
|
||||
{
|
||||
"name" => @name,
|
||||
"file" => file,
|
||||
"line" => line,
|
||||
"docstring" => @docstring,
|
||||
"examples" => self.tags.map do |tag|
|
||||
tag.text if tag.tag_name == 'example'
|
||||
end.compact,
|
||||
}.to_json(*a)
|
||||
end
|
||||
|
||||
# FIXME: We used to override `self.new` to ensure no YARD proxies were
|
||||
# created for namespaces segments that did not map to a host class or
|
||||
# defined type. Fighting the system in this way turned out to be
|
||||
# counter-productive.
|
||||
#
|
||||
# However, if a proxy is left in, YARD will drop back to namspace-mangling
|
||||
# heuristics that are very specific to Ruby and which produce ugly paths in
|
||||
# the resulting output. Need to find a way to address this.
|
||||
#
|
||||
# Tried:
|
||||
#
|
||||
# - Overriding self.new in the code object. Failed because self.new
|
||||
# overrides are gross and difficult to pull off. Especially when
|
||||
# replacing an existing override.
|
||||
#
|
||||
# - Adding functionality to the base handler to ensure something other
|
||||
# than a proxy occupies each namespace segment. Failed because once a
|
||||
# code object is created with a namespace, it will never update.
|
||||
# Unless that namespace is set to a Proxy.
|
||||
#
|
||||
# def self.new(namespace, name, *args, &block)
|
||||
end
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
class PuppetX::PuppetLabs::Strings::YARD::CodeObjects::TypeObject < PuppetX::PuppetLabs::Strings::YARD::CodeObjects::PuppetNamespaceObject
|
||||
# A list of parameters attached to this class.
|
||||
# @return [Array<Array(String, String)>]
|
||||
attr_accessor :parameters
|
||||
|
||||
def to_json(*a)
|
||||
{
|
||||
"name" => @name,
|
||||
"file" => file,
|
||||
"line" => line,
|
||||
"docstring" => Puppet::Util::Docs.scrub(@docstring),
|
||||
"parameters" => @parameter_details.map do |obj|
|
||||
{
|
||||
"allowed_values" => obj[:allowed_values] ? obj[:allowed_values].flatten : [],
|
||||
"default" => obj[:default],
|
||||
"docstring" => Puppet::Util::Docs.scrub(obj[:desc] || ''),
|
||||
"namevar" => obj[:namevar],
|
||||
"name" => obj[:name],
|
||||
}
|
||||
end,
|
||||
"examples" => self.tags.map do |tag|
|
||||
tag.text if tag.tag_name == 'example'
|
||||
end.compact,
|
||||
"properties" => @property_details.map do |obj|
|
||||
{
|
||||
"allowed_values" => obj[:allowed_values] ? obj[:allowed_values].flatten : [],
|
||||
"default" => obj[:default],
|
||||
"docstring" => Puppet::Util::Docs.scrub(obj[:desc] || ''),
|
||||
"name" => obj[:name],
|
||||
}
|
||||
end,
|
||||
"features" => @features.map do |obj|
|
||||
{
|
||||
"docstring" => Puppet::Util::Docs.scrub(obj[:desc] || ''),
|
||||
"methods" => obj[:methods],
|
||||
"name" => obj[:name],
|
||||
}
|
||||
end,
|
||||
}.to_json(*a)
|
||||
end
|
||||
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
require 'yard'
|
||||
|
||||
require 'puppet_x/puppetlabs/strings'
|
||||
|
||||
# Patch the regular expression used to match namespaces
|
||||
# so it will allow namespace segments that begin with
|
||||
# both uppercase and lowercase letters (i.e. both
|
||||
# Puppet::Namespace and puppet::namespace)
|
||||
YARD::CodeObjects.send(:remove_const, :CONSTANTMATCH)
|
||||
YARD::CodeObjects::CONSTANTMATCH = /[a-zA-Z]\w*/
|
||||
|
||||
# This is a temporary hack until a new version of YARD is
|
||||
# released. We submitted a patch to YARD to add the
|
||||
# CONSTANTSTART constant so that we could patch it and
|
||||
# successfully match our own namesapces. However until
|
||||
# the next version of the YARD gem is released, we must
|
||||
# patch the problematic method itself as it is not yet
|
||||
# using the added variable
|
||||
if defined? YARD::CodeObjects::CONSTANTSTART
|
||||
YARD::CodeObjects.send(:remove_const, :CONSTANTSTART)
|
||||
YARD::CodeObjects::CONSTANTSTART = /^[a-zA-Z]/
|
||||
else
|
||||
class YARD::CodeObjects::Proxy
|
||||
def proxy_path
|
||||
if @namespace.root?
|
||||
(@imethod ? YARD::CodeObjects::ISEP : "") + name.to_s
|
||||
elsif @origname
|
||||
if @origname =~ /^[a-zA-Z]/
|
||||
@origname
|
||||
else
|
||||
[namespace.path, @origname].join
|
||||
end
|
||||
elsif name.to_s =~ /^[a-zA-Z]/ # const
|
||||
name.to_s
|
||||
else # class meth?
|
||||
[namespace.path, name.to_s].join(YARD::CodeObjects::CSEP)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
require 'puppet_x/puppetlabs/strings/yard/core_ext/yard'
|
||||
|
||||
class PuppetX::PuppetLabs::Strings::YARD::Handlers::Base < ::YARD::Handlers::Base
|
||||
# Easy access to Pops model objects for handler matching.
|
||||
include Puppet::Pops::Model
|
||||
# Easy access to custom code objects from which documentation is generated.
|
||||
include PuppetX::PuppetLabs::Strings::YARD::CodeObjects
|
||||
|
||||
def self.handles?(statement)
|
||||
handlers.any? {|h| h == statement.type}
|
||||
end
|
||||
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue