(PDOC-184) generate markdown

This change does a few things:
1. Fixes up new api handler to return the stuff we want
2. Adds all the logic to parse YARD registries into markdown
3. Adds templates for markdown
4. Changes Face cli to use a --format option that can be used for either
markdown or json
This commit is contained in:
Eric Putnam 2018-01-22 16:22:42 -08:00
parent 59aa812cda
commit 1374b67da0
No known key found for this signature in database
GPG Key ID: 3FB595AA224A7751
26 changed files with 1259 additions and 27 deletions

View File

@ -14,7 +14,9 @@ module PuppetStrings
# @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 [String] :format Specify output format (markdown or json)
# @option options [String] :path Write the selected format to a file path
# @option options [Boolean] :stdout Use this switch to pipe the selected format to STDOUT
# @option options [Array<String>] :yard_args The arguments to pass to yard.
# @return [void]
def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {})
@ -27,15 +29,13 @@ module PuppetStrings
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]
if options[:json] || options[:markdown]
file = options[:path]
# 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
args << '-q' unless file
args << '--no-stats' unless file
args << '--no-progress' unless file
end
yard_args = options[:yard_args]
@ -46,10 +46,24 @@ module PuppetStrings
YARD::CLI::Yardoc.run(*args)
# If outputting JSON, render the output
if render_as_json
require 'puppet-strings/json'
PuppetStrings::Json.render(json_file)
if options[:json]
render_json(options[:path])
end
# If outputting Markdown, render the output
if options[:markdown]
render_markdown(options[:path])
end
end
def self.render_json(path)
require 'puppet-strings/json'
PuppetStrings::Json.render(path)
end
def self.render_markdown(path)
require 'puppet-strings/markdown'
PuppetStrings::Markdown.render(path)
end
# Runs the YARD documentation server.

View File

@ -0,0 +1,32 @@
require 'puppet-strings/json'
# module for parsing Yard Registries and generating markdown
module PuppetStrings::Markdown
require_relative 'markdown/puppet_classes'
require_relative 'markdown/puppet_functions'
require_relative 'markdown/puppet_defined_types'
require_relative 'markdown/puppet_resource_types'
require_relative 'markdown/table_of_contents'
# generates markdown documentation
# @return [String] markdown doc
def self.generate
final = "# Reference\n\n"
final << PuppetStrings::Markdown::TableOfContents.render
final << PuppetStrings::Markdown::PuppetClasses.render
final << PuppetStrings::Markdown::PuppetDefinedTypes.render
final << PuppetStrings::Markdown::PuppetResourceTypes.render
final << PuppetStrings::Markdown::PuppetFunctions.render
final
end
def self.render(path = nil)
if path.nil?
puts generate
exit
else
File.open(path, 'w') { |file| file.write(generate) }
end
end
end

View File

@ -0,0 +1,84 @@
require 'puppet-strings'
require 'puppet-strings/json'
require 'puppet-strings/yard'
module PuppetStrings::Markdown
class Base
def initialize(registry, component_type)
@type = component_type
@registry = registry
@tags = registry[:docstring][:tags] || []
end
def name
@registry[:name].to_s unless @registry[:name].nil?
end
def text
@registry[:docstring][:text] unless @registry[:docstring][:text].empty?
end
def return_val
@tags.select { |tag| tag[:tag_name] == 'return' }[0][:text] unless @tags.select { |tag| tag[:tag_name] == 'return' }[0].nil?
end
def return_type
@tags.select { |tag| tag[:tag_name] == 'return' }[0][:types][0] unless @tags.select { |tag| tag[:tag_name] == 'return' }[0].nil?
end
# @return [String] text from @since tag
def since
@tags.select { |tag| tag[:tag_name] == 'since' }[0][:text] unless @tags.select { |tag| tag[:tag_name] == 'since' }[0].nil?
end
# return [Array] array of @see tag hashes
def see
@tags.select { |tag| tag[:tag_name] == 'see' } unless @tags.select { |tag| tag[:tag_name] == 'see' }[0].nil?
end
# return [String] text from @summary tag
def summary
@tags.select { |tag| tag[:tag_name] == 'summary' }[0][:text] unless @tags.select { |tag| tag[:tag_name] == 'summary' }[0].nil?
end
# return [Array] array of parameter tag hashes
def params
@tags.select { |tag| tag[:tag_name] == 'param' } unless @tags.select { |tag| tag[:tag_name] == 'param' }[0].nil?
end
# return [Array] array of example tag hashes
def examples
@tags.select { |tag| tag[:tag_name] == 'example' } unless @tags.select { |tag| tag[:tag_name] == 'example' }[0].nil?
end
def toc_info
{
name: name.to_s,
link: link,
desc: summary || @registry[:docstring][:text].gsub("\n", ". ")
}
end
def link
name.delete('::').strip.gsub(' ','-').downcase
end
def defaults
@registry[:defaults] unless @registry[:defaults].nil?
end
def value_string(value)
to_symbol = %w[undef true false]
if to_symbol.include? value
return "`#{value}`"
else
return value
end
end
def render(template)
file = File.join(File.dirname(__FILE__),"templates/#{template}")
ERB.new(File.read(file), nil, '-').result(binding)
end
end
end

View File

@ -0,0 +1,14 @@
require 'puppet-strings/markdown/base'
module PuppetStrings::Markdown
class PuppetClass < Base
def initialize(registry)
@template = 'puppet_resource.erb'
super(registry, 'class')
end
def render
super(@template)
end
end
end

View File

@ -0,0 +1,27 @@
require_relative 'puppet_class'
module PuppetStrings::Markdown
module PuppetClasses
def self.in_classes
YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash)
end
def self.render
final = "## Classes\n\n"
in_classes.each do |klass|
final << PuppetStrings::Markdown::PuppetClass.new(klass).render
end
final
end
def self.toc_info
final = []
in_classes.each do |klass|
final.push(PuppetStrings::Markdown::PuppetClass.new(klass).toc_info)
end
final
end
end
end

View File

@ -0,0 +1,14 @@
require 'puppet-strings/markdown/base'
module PuppetStrings::Markdown
class PuppetDefinedType < Base
def initialize(registry)
@template = 'puppet_resource.erb'
super(registry, 'defined type')
end
def render
super(@template)
end
end
end

View File

@ -0,0 +1,27 @@
require_relative 'puppet_defined_type'
module PuppetStrings::Markdown
module PuppetDefinedTypes
def self.in_dtypes
YARD::Registry.all(:puppet_defined_type).sort_by!(&:name).map!(&:to_hash)
end
def self.render
final = "## Defined types\n\n"
in_dtypes.each do |type|
final << PuppetStrings::Markdown::PuppetDefinedType.new(type).render
end
final
end
def self.toc_info
final = []
in_dtypes.each do |type|
final.push(PuppetStrings::Markdown::PuppetDefinedType.new(type).toc_info)
end
final
end
end
end

View File

@ -0,0 +1,31 @@
require 'puppet-strings/markdown/base'
module PuppetStrings::Markdown
class PuppetFunction < Base
attr_reader :signatures
def initialize(registry)
@template = 'puppet_function.erb'
super(registry, 'function')
@signatures = []
registry[:signatures].each do |sig|
@signatures.push(Signature.new(sig))
end
end
def render
super(@template)
end
end
class PuppetFunction::Signature < Base
def initialize(registry)
@registry = registry
super(@registry, 'function signature')
end
def signature
@registry[:signature]
end
end
end

View File

@ -0,0 +1,28 @@
require_relative 'puppet_function'
module PuppetStrings::Markdown
module PuppetFunctions
def self.in_functions
YARD::Registry.all(:puppet_function).sort_by!(&:name).map!(&:to_hash)
end
def self.render
final = "## Functions\n\n"
in_functions.each do |func|
final << PuppetStrings::Markdown::PuppetFunction.new(func).render
end
final
end
def self.toc_info
final = []
in_functions.each do |func|
final.push(PuppetStrings::Markdown::PuppetFunction.new(func).toc_info)
end
final
end
end
end

View File

@ -0,0 +1,26 @@
require 'puppet-strings/markdown/base'
module PuppetStrings::Markdown
class PuppetResourceType < Base
def initialize(registry)
@template = 'puppet_resource_type.erb'
super(registry, 'resource type')
end
def render
super(@template)
end
def properties
@registry[:properties]
end
def parameters
@registry[:parameters]
end
def regex_in_data_type?(data_type)
data_type.match(/\w+\[\/.*\/\]/).length > 0
end
end
end

View File

@ -0,0 +1,27 @@
require_relative 'puppet_resource_type'
module PuppetStrings::Markdown
module PuppetResourceTypes
def self.in_rtypes
YARD::Registry.all(:puppet_type).sort_by!(&:name).map!(&:to_hash)
end
def self.render
final = "## Resource types\n\n"
in_rtypes.each do |type|
final << PuppetStrings::Markdown::PuppetResourceType.new(type).render
end
final
end
def self.toc_info
final = []
in_rtypes.each do |type|
final.push(PuppetStrings::Markdown::PuppetResourceType.new(type).toc_info)
end
final
end
end
end

View File

@ -0,0 +1,15 @@
require 'puppet-strings/markdown/puppet_classes'
module PuppetStrings::Markdown
module TableOfContents
def self.render
puppet_classes = PuppetStrings::Markdown::PuppetClasses.toc_info
puppet_defined_types = PuppetStrings::Markdown::PuppetDefinedTypes.toc_info
puppet_resource_types = PuppetStrings::Markdown::PuppetResourceTypes.toc_info
puppet_functions = PuppetStrings::Markdown::PuppetFunctions.toc_info
template = File.join(File.dirname(__FILE__),"templates/table_of_contents.erb")
ERB.new(File.read(template), nil, '-').result(binding)
end
end
end

View File

@ -0,0 +1,24 @@
### <%= name %>
<% signatures.each do |sig| -%>
#### `<%= sig.signature %>`
<% if sig.text -%>
<%= sig.text %>
<% end -%>
<% if sig.return_val -%>
Returns: `<%= sig.return_type %>` <%= sig.return_val %>
<% end -%>
<% if sig.params -%>
<% sig.params.each do |param| -%>
##### `<%= param[:name] %>`
Data type: `<%= param[:types][0] %>`
<%= param[:text] %>
<% end -%>
<% end -%>
<% end -%>

View File

@ -0,0 +1,45 @@
### <%= name %>
<% if since -%>
* **Since** <%= since %>
<% end -%>
<% if see -%>
* **See also**
<% see.each do |sa| -%>
<%= sa[:name] %>
<%= sa[:text] %>
<% end -%>
<% end -%>
<% if examples -%>
#### Examples
<% examples.each do |eg| -%>
##### <%= eg[:name] %>
```puppet
<%= eg[:text] %>
```
<% end -%>
<% end -%>
<% if params %>
#### Parameters
The following parameters are available in the `<%= name %>` <%= @type %>.
<% params.each do |param| -%>
##### `<%= param[:name] %>`
<% if param[:types] -%>
Data type: `<%= param[:types].join(', ') -%>`
<% end -%>
<%= param[:text] %>
<% if defaults && defaults[param[:name]] -%>
Default value: <%= value_string(defaults[param[:name]]) %>
<% end -%>
<% end -%>
<% end -%>

View File

@ -0,0 +1,83 @@
### <%= name %>
<% if since -%>
* **Since** <%= since %>
<% end -%>
<% if see -%>
* **See also**
<% see.each do |sa| -%>
<%= sa[:name] %>
<%= sa[:text] %>
<% end -%>
<% end -%>
<% if text -%>
<%= text %>
<% end %>
<% if examples -%>
#### Examples
<% examples.each do |eg| -%>
##### <%= eg[:name] %>
```puppet
<%= eg[:text] %>
```
<% end -%>
<% end -%>
<% if properties %>
#### Properties
The following properties are available in the `<%= name %>` <%= @type %>.
<% properties.each do |prop| -%>
##### `<%= prop[:name] %>`
<% if prop[:values] -%>
Valid values: <%= prop[:values].map { |value| value_string(value) }.join(', ') %>
<% end -%>
<% if prop[:aliases] -%>
Aliases: <%= prop[:aliases].to_s.delete('{').delete('}') %>
<% end -%>
<% if prop[:data_type] -%>
Data type: `<%= prop[:data_type] %>`
<% end -%>
<%= prop[:description] %>
<% if prop[:default] -%>
Default value: <%= prop[:default] %>
<% end -%>
<% end -%>
<% end -%>
<% if parameters -%>
#### Parameters
The following parameters are available in the `<%= name %>` <%= @type %>.
<% parameters.each do |param| -%>
##### `<%= param[:name] %>`
<% if param[:values] -%>
Valid values: <%= param[:values].map { |value| value_string(value) }.join(', ') %>
<% end -%>
<% if param[:isnamevar] -%>
namevar
<% end -%>
<% if param[:data_type] -%>
Data type: `<%= param[:data_type] %>`<%= "\n_\*this data type contains a regex that may not be accurately reflected in generated documentation_" if regex_in_data_type?(param[:data_type]) %>
<% end -%>
<%= param[:description] %>
<% if param[:default] -%>
Default value: <%= value_string(param[:default]) %>
<% end -%>
<% end -%>
<% end -%>

View File

@ -0,0 +1,24 @@
<% if puppet_classes -%>
## Classes
<% puppet_classes.each do |klassy| -%>
* [`<%= klassy[:name] %>`](#<%= klassy[:link] %>): <%= klassy[:desc] %>
<% end -%>
<% end -%>
<% if puppet_defined_types -%>
## Defined types
<% puppet_defined_types.each do |dtype| -%>
* [`<%= dtype[:name] %>`](#<%= dtype[:link] %>): <%= dtype[:desc] %>
<% end -%>
<% end -%>
<% if puppet_resource_types -%>
## Resource types
<% puppet_resource_types.each do |rtype| -%>
* [`<%= rtype[:name] %>`](#<%= rtype[:link] %>): <%= rtype[:desc] %>
<% end -%>
<% end -%>
<% if puppet_functions -%>
## Functions
<% puppet_functions.each do |func| -%>
* [`<%= func[:name] %>`](#<%= func[:link] %>): <%= func[:desc] %>
<% end -%>
<% end -%>

View File

@ -22,7 +22,7 @@ class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects:
# Represents a resource type parameter.
class Parameter
attr_reader :name, :values, :aliases
attr_accessor :docstring, :isnamevar, :default
attr_accessor :docstring, :isnamevar, :default, :data_type
# Initializes a resource type parameter or property.
# @param [String] name The name of the parameter or property.
@ -31,6 +31,7 @@ class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects:
@name = name
@docstring = docstring || ''
@values = []
@data_type = []
@aliases = {}
@isnamevar = false
@default = nil
@ -59,6 +60,7 @@ class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects:
hash[:name] = name
hash[:description] = docstring unless docstring.empty?
hash[:values] = values unless values.empty?
hash[:data_type] = data_type unless data_type.empty?
hash[:aliases] = aliases unless aliases.empty?
hash[:isnamevar] = true if isnamevar
hash[:default] = default if default

View File

@ -29,7 +29,7 @@ class PuppetStrings::Yard::Handlers::Ruby::Base < YARD::Handlers::Ruby::Base
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
source = lines[1..(lines.last.include?($1[0..-2]) ? -2 : -1)].join("\n") if lines.size > 1
end
source

View File

@ -24,7 +24,7 @@ class PuppetStrings::Yard::Handlers::Ruby::RsapiHandler < PuppetStrings::Yard::H
object = PuppetStrings::Yard::CodeObjects::Type.new(schema['name'])
register object
docstring = schema['docs']
docstring = schema['desc'] || ""
if docstring
register_docstring(object, PuppetStrings::Yard::Util.scrub_string(docstring.to_s), nil)
else
@ -134,7 +134,7 @@ class PuppetStrings::Yard::Handlers::Ruby::RsapiHandler < PuppetStrings::Yard::H
end
def set_values(definition, object)
object.add(definition['type']) if definition.key? 'type'
object.data_type = definition['type'] if definition.key? 'type'
object.default = definition['default'] if definition.key? 'default'
object.isnamevar = definition.key?('behaviour') && definition['behaviour'] == 'namevar'
end

View File

@ -7,11 +7,11 @@ Puppet::Face.define(:strings, '0.0.1') do
action(:generate) do
default
option '--emit-json-stdout' do
summary 'Print JSON representation of the documentation to stdout.'
option '--format OUTPUT_FORMAT' do
summary 'Designate output format, JSON or markdown.'
end
option '--emit-json FILE' do
summary 'Write JSON representation of the documentation to the given file.'
option '--out PATH' do
summary 'Write selected format to PATH. If no path is designated, strings prints to STDOUT.'
end
option '--markup FORMAT' do
summary "The markup format to use for docstring text (defaults to 'markdown')."
@ -96,9 +96,14 @@ Puppet::Face.define(:strings, '0.0.1') do
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]
generate_options[:path] = options[:out] if options[:out]
generate_options[:stdout] = options[:stdout]
format = options[:format] || ""
if format.casecmp 'markdown'
generate_options[:markdown] = true
elsif format.casecmp 'json'
generate_options[:json] = true
end
end
generate_options
end

View File

@ -37,18 +37,18 @@ describe 'Emitting JSON' do
]
}
it 'should emit JSON to stdout when using the --emit-json-stdout option' do
it 'should emit JSON to stdout when using --format json and --stdout' do
test_module_path = get_test_module_path(master, /Module test/)
on master, puppet('strings', 'generate', '--emit-json-stdout', "#{test_module_path}/lib/puppet/parser/functions/function3x.rb") do
on master, puppet('strings', 'generate', '--format json', "#{test_module_path}/lib/puppet/parser/functions/function3x.rb") do
output = stdout.chomp
expect(JSON.parse(output)).to eq(expected)
end
end
it 'should write JSON to a file when using the --emit-json option' do
it 'should write JSON to a file when using --format json and --out' do
test_module_path = get_test_module_path(master, /Module test/)
tmpfile = master.tmpfile('json_output.json')
on master, puppet('strings', 'generate', "--emit-json #{tmpfile}", "#{test_module_path}/lib/puppet/parser/functions/function3x.rb")
on master, puppet('strings', 'generate', '--format json', "--out #{tmpfile}", "#{test_module_path}/lib/puppet/parser/functions/function3x.rb")
output = read_file_on(master, tmpfile)
expect(JSON.parse(output)).to eq(expected)
end

View File

@ -0,0 +1,49 @@
require 'spec_helper_acceptance'
require 'util'
include PuppetStrings::Acceptance::Util
describe 'Generating Markdown' do
expected = <<-EOF
# Reference
## Classes
* [`test`](#test): This class exists to serve as fixture data for testing the puppet strings face
## Classes
### test
#### Examples
```puppet
class { "test": }
```
#### Parameters
##### `package_name`
The name of the package
##### `service_name`
The name of the service
EOF
it 'should render Markdown to stdout when using --format markdown and --stdout' do
test_module_path = get_test_module_path(master, /Module test/)
on master, puppet('strings', 'generate', '--format markdown', "#{test_module_path}/manifests/init.pp") do
output = stdout.chomp
expect(JSON.parse(output)).to eq(expected)
end
end
it 'should write Markdown to a file when using --format markdown and --out' do
test_module_path = get_test_module_path(master, /Module test/)
tmpfile = master.tmpfile('md_output.md')
on master, puppet('strings', 'generate', '--format markdown', "--out #{tmpfile}", "#{test_module_path}/manifests/init.pp")
output = read_file_on(master, tmpfile)
expect(JSON.parse(output)).to eq(expected)
end
end

313
spec/fixtures/unit/markdown/output.md vendored Normal file
View File

@ -0,0 +1,313 @@
# Reference
## Classes
* [`klass`](#klass): A simple class.
## Defined types
* [`klass::dt`](#klassdt): A simple defined type.
## Resource types
* [`apt_key`](#apt_key): Example resource type using the new API.
* [`database`](#database): An example database server resource type.
## Functions
* [`func`](#func): A simple Puppet function.
* [`func4x`](#func4x): An example 4.x function.
* [`func4x_1`](#func4x_1): An example 4.x function with only one signature.
## Classes
### klass
* **Since** 1.0.0
* **See also**
www.puppet.com
#### Examples
##### This is an example
```puppet
class { 'klass':
param1 => 1,
param3 => 'foo',
}
```
#### Parameters
The following parameters are available in the `klass` class.
##### `param1`
Data type: `Integer`
First param.
Default value: 1
##### `param2`
Data type: `Any`
Second param.
Default value: `undef`
##### `param3`
Data type: `String`
Third param.
Default value: 'hi'
## Defined types
### klass::dt
* **Since** 1.1.0
* **See also**
www.puppet.com
#### Examples
##### Here's an example of this type:
```puppet
klass::dt { 'foo':
param1 => 33,
param4 => false,
}
```
#### Parameters
The following parameters are available in the `klass::dt` defined type.
##### `param1`
Data type: `Integer`
First param.
Default value: 44
##### `param2`
Data type: `Any`
Second param.
##### `param3`
Data type: `String`
Third param.
Default value: 'hi'
##### `param4`
Data type: `Boolean`
Fourth param.
Default value: `true`
## Resource types
### apt_key
This type provides Puppet with the capabilities to manage GPG keys needed
by apt to perform package validation. Apt has it's own GPG keyring that can
be manipulated through the `apt-key` command.
**Autorequires**:
If Puppet is given the location of a key file which looks like an absolute
path this type will autorequire that file.
#### Examples
##### here's an example
```puppet
apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F':
source => 'http://apt.puppetlabs.com/pubkey.gpg'
}
```
#### Properties
The following properties are available in the `apt_key` resource type.
##### `ensure`
Data type: `Enum[present, absent]`
Whether this apt key should be present or absent on the target system.
##### `created`
Data type: `String`
Date the key was created, in ISO format.
#### Parameters
The following parameters are available in the `apt_key` resource type.
##### `id`
namevar
Data type: `Variant[Pattern[/A(0x)?[0-9a-fA-F]{8}Z/], Pattern[/A(0x)?[0-9a-fA-F]{16}Z/], Pattern[/A(0x)?[0-9a-fA-F]{40}Z/]]`
_*this data type contains a regex that may not be accurately reflected in generated documentation_
The ID of the key you want to manage.
### database
An example database server resource type.
#### Examples
##### here's an example
```puppet
database { 'foo':
address => 'qux.baz.bar',
}
```
#### Properties
The following properties are available in the `database` resource type.
##### `ensure`
Valid values: present, absent, up, down
Aliases: "up"=>"present", "down"=>"absent"
What state the database should be in.
Default value: up
##### `file`
The database file to use.
##### `log_level`
Valid values: debug, warn, error
The log level to use.
Default value: warn
#### Parameters
The following parameters are available in the `database` resource type.
##### `address`
namevar
The database server name.
##### `encryption_key`
The encryption key to use.
##### `encrypt`
Valid values: `true`, `false`, yes, no
Whether or not to encrypt the database.
Default value: `false`
## Functions
### func
#### `func(Integer $param1, Any $param2, String $param3 = hi)`
A simple Puppet function.
Returns: `Undef` Returns nothing.
##### `param1`
Data type: `Integer`
First param.
##### `param2`
Data type: `Any`
Second param.
##### `param3`
Data type: `String`
Third param.
### func4x
#### `func4x(Integer $param1, Any $param2, Optional[Array[String]] $param3)`
An overview for the first overload.
Returns: `Undef` Returns nothing.
##### `param1`
Data type: `Integer`
The first parameter.
##### `param2`
Data type: `Any`
The second parameter.
##### `param3`
Data type: `Optional[Array[String]]`
The third parameter.
#### `func4x(Boolean $param, Callable &$block)`
An overview for the second overload.
Returns: `String` Returns a string.
##### `param`
Data type: `Boolean`
The first parameter.
##### `&block`
Data type: `Callable`
The block parameter.
### func4x_1
#### `func4x_1(Integer $param1)`
An example 4.x function with only one signature.
Returns: `Undef` Returns nothing.
##### `param1`
Data type: `Integer`
The first parameter.

View File

@ -2,6 +2,8 @@ require 'mocha'
require 'rspec'
require 'puppet/version'
require 'puppet-strings'
require 'puppet-strings/markdown'
require 'puppet-strings/markdown/base'
require 'puppet-strings/yard'
# Explicitly set up YARD once

View File

@ -0,0 +1,133 @@
require 'spec_helper'
describe PuppetStrings::Markdown::Base do
context 'basic class' do
before :each do
YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet)
# An overview
# @summary A simple class.
# @param param1 First param.
# @param param2 Second param.
# @param param3 Third param.
class klass(Integer $param1, $param2, String $param3 = hi) inherits foo::bar {
}
SOURCE
end
let(:reg) { YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash)[0] }
let(:component) { PuppetStrings::Markdown::Base.new(reg, 'class') }
describe '#name' do
it 'returns the expected name' do
expect(component.name).to eq 'klass'
end
end
[ 'examples',
'see',
'since',
'return_val',
'return_type',].each do |method|
describe "##{method}" do
it 'returns nil' do
expect(component.method(method.to_sym).call).to be_nil
end
end
end
describe '#params' do
it 'returns the expected params' do
expect(component.params.size).to eq 3
end
end
describe '#summary' do
it 'returns the expected summary' do
expect(component.summary).to eq 'A simple class.'
end
end
describe '#toc_info' do
let(:toc) { component.toc_info }
it 'returns a hash' do
expect(toc).to be_instance_of Hash
end
it 'prefers the summary for :desc' do
expect(toc[:desc]).to eq 'A simple class.'
end
end
end
context 'less basic class' do
before :each do
YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet)
# An overview
# It's a longer overview
# Ya know?
# @example A simple example.
# class { 'klass::yeah':
# param1 => 1,
# }
# @param param1 First param.
# @param param2 Second param.
# @param param3 Third param.
class klass::yeah(
Integer $param1,
$param2,
String $param3 = hi
) inherits foo::bar {
}
SOURCE
end
let(:reg) { YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash)[0] }
let(:component) { PuppetStrings::Markdown::Base.new(reg, 'class') }
describe '#name' do
it 'returns the expected name' do
expect(component.name).to eq 'klass::yeah'
end
end
['summary',
'see',
'since',
'return_val',
'return_type'].each do |method|
describe "##{method}" do
it 'returns nil' do
expect(component.method(method.to_sym).call).to be_nil
end
end
end
describe '#examples' do
it 'should return one example' do
expect(component.examples.size).to eq 1
end
end
describe '#params' do
it 'returns the expected params' do
expect(component.params.size).to eq 3
end
end
describe '#toc_info' do
let(:toc) { component.toc_info }
it 'returns a hash' do
expect(toc).to be_instance_of Hash
end
it 'uses overview for :desc in absence of summary' do
expect(toc[:desc]).to eq 'An overview. It\'s a longer overview. Ya know?'
end
end
describe '#link' do
it 'returns a valid link' do
expect(component.link).to eq 'klassyeah'
end
end
end
end

View File

@ -0,0 +1,213 @@
require 'spec_helper'
require 'puppet-strings/markdown'
require 'puppet-strings/markdown/puppet_classes'
require 'puppet-strings/markdown/table_of_contents'
require 'tempfile'
describe PuppetStrings::Markdown do
before :each do
# Populate the YARD registry with both Puppet and Ruby source
YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet)
# An overview for a simple class.
# @summary A simple class.
# @since 1.0.0
# @see www.puppet.com
# @example This is an example
# class { 'klass':
# param1 => 1,
# param3 => 'foo',
# }
# @param param1 First param.
# @param param2 Second param.
# @param param3 Third param.
class klass (
Integer $param1 = 1,
$param2 = undef,
String $param3 = 'hi'
) inherits foo::bar {
}
# An overview for a simple defined type.
# @summary A simple defined type.
# @since 1.1.0
# @see www.puppet.com
# @example Here's an example of this type:
# klass::dt { 'foo':
# param1 => 33,
# param4 => false,
# }
# @return shouldn't return squat
# @param param1 First param.
# @param param2 Second param.
# @param param3 Third param.
# @param param4 Fourth param.
define klass::dt (
Integer $param1 = 44,
$param2,
String $param3 = 'hi',
Boolean $param4 = true
) {
}
SOURCE
YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet)
# A simple Puppet function.
# @param param1 First param.
# @param param2 Second param.
# @param param3 Third param.
# @return [Undef] Returns nothing.
function func(Integer $param1, $param2, String $param3 = hi) {
}
SOURCE
YARD::Parser::SourceParser.parse_string(<<-SOURCE, :ruby)
# An example 4.x function.
Puppet::Functions.create_function(:func4x) do
# An overview for the first overload.
# @param param1 The first parameter.
# @param param2 The second parameter.
# @param param3 The third parameter.
# @return Returns nothing.
dispatch :foo do
param 'Integer', :param1
param 'Any', :param2
optional_param 'Array[String]', :param3
return_type 'Undef'
end
# An overview for the second overload.
# @param param The first parameter.
# @param block The block parameter.
# @return Returns a string.
dispatch :other do
param 'Boolean', :param
block_param
return_type 'String'
end
end
# An example 4.x function with only one signature.
Puppet::Functions.create_function(:func4x_1) do
# @param param1 The first parameter.
# @return [Undef] Returns nothing.
dispatch :foobarbaz do
param 'Integer', :param1
end
end
Puppet::Type.type(:database).provide :linux do
desc 'An example provider on Linux.'
confine kernel: 'Linux'
confine osfamily: 'RedHat'
defaultfor :kernel => 'Linux'
defaultfor :osfamily => 'RedHat', :operatingsystemmajrelease => '7'
has_feature :implements_some_feature
has_feature :some_other_feature
commands foo: '/usr/bin/foo'
end
Puppet::Type.newtype(:database) do
desc <<-DESC
An example database server resource type.
@example here's an example
database { 'foo':
address => 'qux.baz.bar',
}
DESC
feature :encryption, 'The provider supports encryption.', methods: [:encrypt]
ensurable do
desc 'What state the database should be in.'
defaultvalues
aliasvalue(:up, :present)
aliasvalue(:down, :absent)
defaultto :up
end
newparam(:address) do
isnamevar
desc 'The database server name.'
end
newparam(:encryption_key, required_features: :encryption) do
desc 'The encryption key to use.'
end
newparam(:encrypt, :parent => Puppet::Parameter::Boolean) do
desc 'Whether or not to encrypt the database.'
defaultto false
end
newproperty(:file) do
desc 'The database file to use.'
end
newproperty(:log_level) do
desc 'The log level to use.'
newvalue(:debug)
newvalue(:warn)
newvalue(:error)
defaultto 'warn'
end
end
Puppet::ResourceApi.register_type(
name: 'apt_key',
desc: <<-EOS,
@summary Example resource type using the new API.
This type provides Puppet with the capabilities to manage GPG keys needed
by apt to perform package validation. Apt has it's own GPG keyring that can
be manipulated through the `apt-key` command.
@example here's an example
apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F':
source => 'http://apt.puppetlabs.com/pubkey.gpg'
}
**Autorequires**:
If Puppet is given the location of a key file which looks like an absolute
path this type will autorequire that file.
EOS
attributes: {
ensure: {
type: 'Enum[present, absent]',
desc: 'Whether this apt key should be present or absent on the target system.'
},
id: {
type: 'Variant[Pattern[/\A(0x)?[0-9a-fA-F]{8}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{16}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{40}\Z/]]',
behaviour: :namevar,
desc: 'The ID of the key you want to manage.',
},
# ...
created: {
type: 'String',
behaviour: :read_only,
desc: 'Date the key was created, in ISO format.',
},
},
autorequires: {
file: '$source', # will evaluate to the value of the `source` attribute
package: 'apt',
},
)
SOURCE
end
let(:filename) { 'output.md' }
let(:baseline_path) { File.join(File.dirname(__FILE__), "../../fixtures/unit/markdown/#{filename}") }
let(:baseline) { File.read(baseline_path) }
describe 'rendering markdown to a file' do
it 'should output the expected markdown content' do
Tempfile.open('md') do |file|
PuppetStrings::Markdown.render(file.path)
expect(File.read(file.path)).to eq(baseline)
end
end
end
describe 'rendering markdown to stdout' do
it 'should output the expected markdown content' do
expect{ PuppetStrings::Markdown.render }.to output(baseline).to_stdout
end
end
end