(PDOC-35) Document types & providers separately

* Dunno, I just plowed through a bunch of features
* Expect puppet provider in stats output
* Fetch default values for Type params and props
* Detect allowed values
* Add allowed values to test
* htmlify scrubbed text
* Add features to Type html output
* Add infrastructure for types
* Add methods for generating lists, etc.
* Add provider code object
* Add provider handler
* Generate list for puppet provider dropdown
* Add puppet provider template
* Add provider details to puppet type template
* Get description properly for types
This commit is contained in:
Ian Kronquist 2015-08-26 16:26:04 -07:00
parent 798cd5b816
commit 0206c78ee0
26 changed files with 618 additions and 123 deletions

View File

@ -56,9 +56,9 @@ Puppet::Face.define(:strings, '0.0.1') do
# 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.provider.param",
YARD::Tags::Library.define_directive("puppet.type.param",
:with_types_and_name,
PuppetX::PuppetLabs::Strings::YARD::Tags::PuppetProviderParameterDirective)
PuppetX::PuppetLabs::Strings::YARD::Tags::PuppetTypeParameterDirective)
yardoc_actions.generate_documentation(*yard_args)

View File

@ -31,6 +31,7 @@ module PuppetX::PuppetLabs
require 'puppet_x/puppetlabs/strings/yard/code_objects/puppet_namespace_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
@ -43,6 +44,7 @@ module PuppetX::PuppetLabs
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

View File

@ -0,0 +1,5 @@
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
end

View File

@ -4,11 +4,11 @@
class PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetProviderHandler < YARD::Handlers::Ruby::Base
include PuppetX::PuppetLabs::Strings::YARD::CodeObjects
handles :call
handles :command_call, :call
process do
@heredoc_helper = HereDocHelper.new
# Puppet providers always begin with:
# Puppet types always begin with:
# Puppet::Types.newtype...
# Therefore, we match the corresponding trees which look like this:
# s(:call,
@ -17,112 +17,78 @@ class PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetProviderHandler < YARD
# s(:const, "Type", ...),
# You think this is ugly? It's better than the alternative.
return unless statement.children.length > 2
first = statement.children.first
return unless first.type == :const_path_ref and
first.children.length == 2 and
first.children.map { |o| o.source } == ["Puppet", "Type"] and
statement.children[1].source == "newtype"
first = statement.children.first.first
return unless (first.source == 'Puppet::Type') or
(first.type == :var_ref and
first.source == 'Type') and
statement[2].source == 'provide'
i = statement.index { |s| YARD::Parser::Ruby::AstNode === s and s.type == :ident and s.source == 'provide' }
provider_name = statement[i+1].jump(:ident).source
type_name = statement.jump(:symbol).first.source
obj = ProviderObject.new(:root, provider_name)
# Fetch the docstring for the provider. The docstring is the string literal
# assigned to the @doc parameter or absent, like this:
# @doc "docstring goes here"
# We assume that docstrings nodes have the following shape in the source
# code:
# ...
# s(s(:assign,
# s(:..., s(:ivar, "@doc", ...), ...),
# s(:...,
# s(:...,
# s(:tstring_content,
# "Manages files, including their content, etc.", ...
# Initialize the docstring to nil, the default value if we don't find
# anything
docstring = nil
# Walk the tree searching for assignments
statement.traverse do |node|
if node.type == :assign
# Once we have found and assignment, jump to the first ivar
# (the l-value)
# If we can't find an ivar return the node.
ivar = node.jump(:ivar)
# If we found and ivar and its source reads '@doc' then...
if ivar != node and ivar.source == '@doc'
# find the next string content
content = node.jump(:tstring_content)
# if we found the string content extract its source
if content != node
# The docstring is either the source stripped of heredoc
# annotations or the raw source.
if @heredoc_helper.is_heredoc? content.source
docstring = @heredoc_helper.process_heredoc content.source
else
docstring = content.source
end
end
# Since we found the @doc parameter (regardless of whether we
# successfully extracted its source), we're done.
break
# But if we didn't find the ivar loop around again.
else
next
end
end
end
# The providers begin with:
# Puppet::Types.newtype(:symbol)
# Jump to the first identifier (':symbol') after the third argument
# ('(:symbol)') to the current statement
name = statement.children[2].jump(:ident).source
parameter_details = []
obj = ProviderObject.new(:root, name) do |o|
# FIXME: This block gets yielded twice for whatever reason
parameter_details = []
o.parameters = []
# Find the de block following the Provider.
do_block = statement.jump(:do_block)
# traverse the do block's children searching for function calls whose
# identifier is newparam (we're calling the newparam function)
do_block.traverse do |node|
if node.type == :fcall and node.children.first.source == 'newparam'
# The first member of the parameter tuple is the parameter name.
# Find the second identifier node under the fcall tree. The first one
# is 'newparam', the second one is the function name.
# Get its source.
# The second parameter is nil because we cannot infer types for these
# functions. In fact, that's a silly thing to ask because ruby
# providers were deprecated with puppet 4 at the same time the type
# system was created.
param_name = node.children[1].jump(:ident).source
o.parameters << [param_name, nil]
parameter_details << {:name => param_name,
:desc => fetch_description(node), :exists? => true,
:provider => true}
end
end
end
obj.parameter_details = parameter_details
register_docstring(obj, docstring, nil)
register obj
end
def fetch_description(fcall)
fcall.traverse do |node|
if node.type == :command and node.children.first.source == 'desc'
content = node.jump(:string_content)
features = []
commands = []
confines = {}
defaults = {}
do_block = statement.jump(:do_block)
do_block.traverse do |node|
if is_a_func_call_named? 'desc', node
content = node.jump(:tstring_content)
# if we found the string content extract its source
if content != node
@heredoc_helper = HereDocHelper.new
# The docstring is either the source stripped of heredoc
# annotations or the raw source.
if @heredoc_helper.is_heredoc? content.source
docstring = @heredoc_helper.process_heredoc content.source
else
docstring = content.source
end
return docstring
end
elsif is_a_func_call_named? 'confine', node
node.traverse do |s|
if s.type == :assoc
k = s.first.jump(:ident).source
v = s[1].first.source
confines[k] = v
end
end
elsif is_a_func_call_named? 'has_feature', node
list = node.jump :list
if list != nil and list != node
features += list.map { |s| s.source if YARD::Parser::Ruby::AstNode === s }.compact
end
elsif is_a_func_call_named? 'commands', node
assoc = node.jump(:assoc)
if assoc and assoc != node
ident = assoc.jump(:ident)
if ident and ident != assoc
commands << ident.source
end
end
elsif is_a_func_call_named? 'defaultfor', node
node.traverse do |s|
if s.type == :assoc
k = s.first.jump(:ident).source
v = s[1].first.source
defaults[k] = v
end
end
end
end
return nil
obj.features = features
obj.commands = commands
obj.confines = confines
obj.defaults = defaults
obj.type_name = type_name
register_docstring(obj, docstring, nil)
register obj
end
def is_a_func_call_named? name, node
(node.type == :fcall or node.type == :command or node.type == :vcall) and node.children.first.source == name
end
end

View File

@ -0,0 +1,283 @@
# Handles `dispatch` calls within a future parser function declaration. For
# now, it just treats any docstring as an `@overlaod` tag and attaches the
# overload to the parent function.
class PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetTypeHandler < YARD::Handlers::Ruby::Base
include PuppetX::PuppetLabs::Strings::YARD::CodeObjects
handles :call
process do
@heredoc_helper = HereDocHelper.new
# Puppet types always begin with:
# Puppet::Types.newtype...
# Therefore, we match the corresponding trees which look like this:
# s(:call,
# s(:const_path_ref,
# s(:var_ref, s(:const, "Puppet", ...), ...),
# s(:const, "Type", ...),
# You think this is ugly? It's better than the alternative.
return unless statement.children.length > 2
first = statement.children.first
return unless (first.type == :const_path_ref and
first.source == 'Puppet::Type') or
(first.type == :var_ref and
first.source == 'Type') and
statement.children[1].source == "newtype"
# Fetch the docstring for the types. The docstring is the string literal
# assigned to the @doc parameter or absent, like this:
# @doc "docstring goes here"
# We assume that docstrings nodes have the following shape in the source
# code:
# ...
# s(s(:assign,
# s(:..., s(:ivar, "@doc", ...), ...),
# s(:...,
# s(:...,
# s(:tstring_content,
# "Manages files, including their content, etc.", ...
# Initialize the docstring to nil, the default value if we don't find
# anything
docstring = nil
# Walk the tree searching for assignments
statement.traverse do |node|
if node.type == :assign
# Once we have found and assignment, jump to the first ivar
# (the l-value)
# If we can't find an ivar return the node.
ivar = node.jump(:ivar)
# If we found and ivar and its source reads '@doc' then...
if ivar != node and ivar.source == '@doc'
# find the next string content
content = node.jump(:tstring_content)
# if we found the string content extract its source
if content != node
# The docstring is either the source stripped of heredoc
# annotations or the raw source.
if @heredoc_helper.is_heredoc? content.source
docstring = @heredoc_helper.process_heredoc content.source
else
docstring = content.source
end
end
# Since we found the @doc parameter (regardless of whether we
# successfully extracted its source), we're done.
break
# But if we didn't find the ivar loop around again.
else
next
end
end
end
# The types begin with:
# Puppet::Types.newtype(:symbol)
# Jump to the first identifier (':symbol') after the third argument
# ('(:symbol)') to the current statement
name = statement.children[2].jump(:ident).source
parameter_details = []
property_details = []
features = []
obj = TypeObject.new(:root, name) do |o|
# FIXME: This block gets yielded twice for whatever reason
parameter_details = []
property_details = []
o.parameters = []
# Find the do block following the Type.
do_block = statement.jump(:do_block)
# traverse the do block's children searching for function calls whose
# identifier is newparam (we're calling the newparam function)
do_block.traverse do |node|
if is_param? node
# The first member of the parameter tuple is the parameter name.
# Find the second identifier node under the fcall tree. The first one
# is 'newparam', the second one is the function name.
# Get its source.
# The second parameter is nil because we cannot infer types for these
# functions. In fact, that's a silly thing to ask because ruby
# types were deprecated with puppet 4 at the same time the type
# system was created.
# Because of a ripper bug a symbol identifier is sometimes incorrectly parsed as a keyword.
# That is, the symbol `:true` will be represented as s(:symbol s(:kw, true...
param_name = node.children[1].jump(:ident)
if param_name == node.children[1]
param_name = node.children[1].jump(:kw)
end
param_name = param_name.source
o.parameters << [param_name, nil]
parameter_details << {:name => param_name,
:desc => fetch_description(node), :exists? => true,
:puppet_type => true,
:default => fetch_default(node),
:namevar => is_namevar?(node, param_name, name),
:parameter => true,
:allowed_values => get_parameter_allowed_values(node),
}
elsif is_prop? node
# Because of a ripper bug a symbol identifier is sometimes incorrectly parsed as a keyword.
# That is, the symbol `:true` will be represented as s(:symbol s(:kw, true...
prop_name = node.children[1].jump(:ident)
if prop_name == node.children[1]
prop_name = node.children[1].jump(:kw)
end
prop_name = prop_name.source
property_details << {:name => prop_name,
:desc => fetch_description(node), :exists? => true,
:default => fetch_default(node),
:puppet_type => true,
:property => true,
:allowed_values => get_property_allowed_values(node),
}
elsif is_feature? node
features << get_feature(node)
end
end
end
obj.parameter_details = parameter_details
obj.property_details = property_details
obj.features = features
register_docstring(obj, docstring, nil)
register obj
end
# See:
# https://docs.puppetlabs.com/guides/custom_types.html#namevar
# node should be a parameter
def is_namevar? node, param_name, type_name
# Option 1:
# Puppet::Type.newtype(:name) do
# ...
# newparam(:name) do
# ...
# end
if type_name == param_name
return true
end
# Option 2:
# newparam(:path, :namevar => true) do
# ...
# end
if node.children.length >= 2
node.traverse do |s|
if s.type == :assoc and s.jump(:ident).source == 'namevar' and s.jump(:kw).source == 'true'
return true
end
end
end
# Option 3:
# newparam(:path) do
# isnamevar
# ...
# end
do_block = node.jump(:do_block).traverse do |s|
if is_a_func_call_named? 'isnamevar', s
return true
end
end
# Crazy implementations of types may just call #isnamevar directly on the object.
# We don't handle this today.
return false
end
def is_param? node
is_a_func_call_named? 'newparam', node
end
def is_prop? node
is_a_func_call_named? 'newproperty', node
end
def is_feature? node
is_a_func_call_named? 'feature', node
end
def is_a_func_call_named? name, node
(node.type == :fcall or node.type == :command or node.type == :vcall) and node.children.first.source == name
end
def get_feature node
name = node[1].jump(:ident).source
desc = node[1].jump(:tstring_content).source
methods = []
if node[1].length == 4 and node.children[1][2].jump(:ident).source == 'methods'
arr = node[1][2].jump(:array)
if arr != node[1][2]
arr.traverse do |s|
if s.type == :ident
methods << s.source
end
end
end
end
{
:name => name,
:desc => desc,
:methods => methods != [] ? methods : nil,
}
end
def get_parameter_allowed_values node
vals = []
node.traverse do |s|
if is_a_func_call_named? 'newvalues', s
list = s.jump(:list)
if list != s
vals += list.map { |item| [item.source] if YARD::Parser::Ruby::AstNode === item }
end
end
end
vals.compact
end
# Calls to newvalue only apply to properties, according to Dan & Nan's
# "Puppet Types and Providers", page 30.
def get_property_allowed_values node
vals = get_parameter_allowed_values node
node.traverse do |s|
if is_a_func_call_named? 'newvalue', s
required_features = nil
s.traverse do |ss|
if ss.type == :assoc and ss[0].source == ':required_features'
required_features = ss[1].source
end
end
list = s.jump(:list)
if list != s
vals << [list[0].source, required_features].compact
end
end
end
vals
end
def fetch_default node
do_block = node.jump(:do_block)
do_block.traverse do |s|
if is_a_func_call_named? 'defaultto', s
return s[-1].source
end
end
nil
end
def fetch_description(fcall)
fcall.traverse do |node|
if is_a_func_call_named? 'desc', node
content = node.jump(:string_content)
if content != node
@heredoc_helper = HereDocHelper.new
if @heredoc_helper.is_heredoc? content.source
docstring = @heredoc_helper.process_heredoc content.source
else
docstring = content.source
end
return docstring
end
end
end
return nil
end
end

View File

@ -6,7 +6,7 @@ require 'yard'
class YARD::CLI::Yardoc
def all_objects
YARD::Registry.all(:root, :module, :class, :provider, :puppetnamespace, :hostclass, :definedtype)
YARD::Registry.all(:root, :module, :class, :type, :provider, :puppetnamespace, :hostclass, :definedtype)
end
end
@ -16,10 +16,14 @@ class YARD::CLI::Stats
end
def stats_for_definedtypes
output 'Puppet Types', *type_statistics(:definedtype)
output 'Puppet Defined Types', *type_statistics(:definedtype)
end
def stats_for_providers
def stats_for_puppet_types
output 'Puppet Types', *type_statistics(:type)
end
def stats_for_puppet_provider
output 'Puppet Providers', *type_statistics(:provider)
end
end

View File

@ -1,9 +1,9 @@
require 'puppet_x/puppetlabs/strings/yard/core_ext/yard'
# Creates a new code object based on the directive
class PuppetX::PuppetLabs::Strings::YARD::Tags::PuppetProviderParameterDirective < YARD::Tags::Directive
class PuppetX::PuppetLabs::Strings::YARD::Tags::PuppetTypeParameterDirective < YARD::Tags::Directive
def call
return if object.nil?
object.parameters << ([tag.text] + tag.types)
object.parameter_details << {:name => tag.name, :desc => tag.text, :exists? => true, :provider => true}
object.parameter_details << {:name => tag.name, :desc => tag.text, :exists? => true, :puppet_type => true}
end
end

View File

@ -0,0 +1 @@
<%= namespace_list(:namespace_types => [:type]) %>

View File

@ -27,6 +27,13 @@ def generate_puppet_plugin_list
generate_list_contents
end
def generate_puppet_type_list
@items = options.objects.select{|o| [:type].include? o.type} if options.objects
@list_title = "Puppet Type List"
@list_type = "puppet_type"
generate_list_contents
end
def generate_puppet_provider_list
@items = options.objects.select{|o| [:provider].include? o.type} if options.objects
@list_title = "Puppet Provider List"
@ -35,6 +42,7 @@ def generate_puppet_provider_list
end
# A hacked version of class_list that can be instructed to only display certain
# namespace types. This allows us to separate Puppet bits from Ruby bits.
def namespace_list(opts = {})

View File

@ -15,6 +15,30 @@ class HTMLHelper
result.join
end
def generate_features features, object
result = []
if features
features.each do |feat|
result << "<li>"
result << "<span class=\"name\">#{feat[:name]} </span>"
if feat[:desc]
result << "- <br/><div class=\"inline\"><p> #{feat[:desc]} </p></div>"
end
if feat[:methods]
result << "<h3> Methods </h3>"
result << "<ul>"
feat[:methods].each do |method|
result << "<li> <tt>" << method << "</tt> </li>"
end
result << "</ul>"
end
result << "</li>"
end
end
result.join
end
# Generates the HTML to format the relevant data about parameters
def generate_parameters(params, object)
result = []
@ -59,9 +83,21 @@ class HTMLHelper
result << "(" << "<tt>" << possible_types.join(", ") << "</tt>" << ")"
end
# Give up. It can probably be anything.
elsif not (param[:puppet_3_func] or param[:provider])
elsif not (param[:puppet_3_func] or param[:puppet_type])
result << "(<tt>Unknown</tt>)"
end
if param[:puppet_type] and param[:parameter]
result << "<b> Parameter </b>"
elsif param[:puppet_type] and param[:property]
result << "<b> Property </b>"
end
if param[:namevar]
result << "<b> Namevar </b>"
end
if param[:default]
result << " Default value: <tt>" << param[:default] << "</tt> "
end
result << "</span>"
@ -76,6 +112,20 @@ class HTMLHelper
if param[:desc]
result << " - <div class=\"inline\"><p> #{param[:desc]} </p></div>"
end
if param[:allowed_values] and param[:allowed_values] != []
result << "<h4> Allowed Values: </h4>"
result << "<ul>"
param[:allowed_values].each do |value_thing|
result << "<li>"
result << "<tt>" << value_thing.first << "</tt>"
if value_thing[1]
result << " only available if " << "<tt>" << value_thing[1] << "</tt>"
end
result << "</li>"
end
result << "</ul>"
end
if !param[:exists?]
result << "</strike>"

View File

@ -2,7 +2,7 @@
# @objects_by_letter prevents that. Submit a pull request.
def index
@objects_by_letter = {}
objects = Registry.all(:class, :module, :provider, :puppetnamespace, :hostclass, :definedtype).sort_by {|o| o.name.to_s }
objects = Registry.all(:class, :module, :type, :puppetnamespace, :hostclass, :definedtype, :provider).sort_by {|o| o.name.to_s }
objects = run_verifier(objects)
objects.each {|o| (@objects_by_letter[o.name.to_s[0,1].upcase] ||= []) << o }
erb(:index)
@ -12,6 +12,7 @@ def menu_lists
[
{:type => 'puppet_manifest', :title => 'Puppet Manifests', :search_title => "Puppet Manifest List"},
{:type => 'puppet_plugin', :title => 'Puppet Plugins', :search_title => "Puppet Plugin List"},
{:type => 'puppet_provider', :title => 'Puppet Providers', :search_title => "Puppet Providers List"}
{:type => 'puppet_type', :title => 'Puppet Types', :search_title => "Puppet Type List"},
{:type => 'puppet_provider', :title => 'Puppet Providers', :search_title => "Puppet Provider List"},
] + super
end

View File

@ -0,0 +1,8 @@
<h2>Commands Summary</h2>
<div class="tags">
<ul class="command">
<% @command_details.each do |command| %>
<li><tt><%= command %></tt></li>
<% end %>
</ul>
</div>

View File

@ -0,0 +1,12 @@
<h2>Parameter Summary</h2>
<div class="tags">
<ul class="param">
<%= @html_helper.generate_parameters(@param_details, object) %>
</ul>
</div>
<h2>Features</h2>
<div class="tags">
<ul class="feature">
<%= @html_helper.generate_features(@feature_details, object) %>
</ul>
</div>

View File

@ -0,0 +1,10 @@
<h2>Confines</h2>
<% if @confine_details != {} %>
<div class="tags">
<ul class="command">
<% @confine_details.each_pair do |key, value| %>
<li><tt><%= key %> - <%= value %></tt></li>
<% end %>
</ul>
</div>
<% end %>

View File

@ -0,0 +1,10 @@
<h2>Defaults</h2>
<% if @default_details != {} %>
<div class="tags">
<ul class="command">
<% @default_details.each_pair do |key, value| %>
<li><tt><%= key %> - <%= value %></tt></li>
<% end %>
</ul>
</div>
<% end %>

View File

@ -1,6 +1,6 @@
<div class="docstring">
<div class="discussion">
<p><%= htmlify(@class_details[:desc]) %></p>
<p><%= htmlify(Puppet::Util::Docs::scrub(@class_details[:desc])) %></p>
</div>
</div>
<div class="tags">

View File

@ -0,0 +1,10 @@
<h2>Features</h2>
<% if @feature_details != [] %>
<div class="tags">
<ul class="command">
<% @feature_details.each do |feature| %>
<li><tt><%= feature %></tt></li>
<% end %>
</ul>
</div>
<% end %>

View File

@ -4,18 +4,30 @@ require File.join(File.dirname(__FILE__),'../html_helper')
require File.join(File.dirname(__FILE__),'../template_helper')
def init
sections :header, :box_info, :pre_docstring, :docstring, :parameter_details
sections :header, :box_info, :pre_docstring, :docstring, :command_details, :confine_details, :default_details, :feature_details
@template_helper = TemplateHelper.new
@html_helper = HTMLHelper.new
end
def parameter_details
params = object.parameter_details.map { |h| h[:name] }
@param_details = object.parameter_details.each { |h| h[:desc] = htmlify(h[:desc]) }
@template_helper.check_parameters_match_docs object
def command_details
@command_details = object.commands
erb(:command_details)
end
erb(:parameter_details)
def confine_details
@confine_details = object.confines
erb(:confine_details)
end
def default_details
@default_details = object.defaults
erb(:default_details)
end
def feature_details
@feature_details = object.features
erb(:feature_details)
end
def header

View File

@ -0,0 +1,34 @@
<div class="docstring">
<div class="discussion">
<p><%= htmlify(Puppet::Util::Docs::scrub(@class_details[:desc])) %></p>
</div>
</div>
<div class="tags">
<% if @class_details[:examples] != {}%>
<div class="examples">
<p class="tag_title">Examples:</p>
<% @class_details[:examples].each do |title, text| %>
<div class="inline"><p><%= title %></p></div>
<pre class="example code"><code><span><%= text %></span></code></pre>
<% end %>
</div>
<% end %>
<% if @class_details[:since] %>
<p class="tag_title">Since:</p>
<ul class="since">
<li>
<div class="inline">
<p><%= @class_details[:since] %></p>
</div>
</li>
</ul>
<% end %>
<% if @class_details[:return] %>
<p class="tag_title">Return:</p>
<ul class="return">
<li>
<%= @html_helper.generate_return_types(@class_details[:return][1], @class_details[:return][0]) %>
</li>
</ul>
<% end %>
</div>

View File

@ -0,0 +1,5 @@
<div class='module_header'>
<h1>
<%= @header_text %>
</h1>
</div>

View File

@ -4,3 +4,9 @@
<%= @html_helper.generate_parameters(@param_details, object) %>
</ul>
</div>
<h2>Features</h2>
<div class="tags">
<ul class="feature">
<%= @html_helper.generate_features(@feature_details, object) %>
</ul>
</div>

View File

@ -0,0 +1,10 @@
<h2>Available Providers</h2>
<% if @providers != [] %>
<div class="tags">
<ul class="command">
<% @providers.each do |provider| %>
<li><a href="<%= provider.name.to_s %>.html"><tt><%= provider.name.to_s %></tt></a></li>
<% end %>
</ul>
</div>
<% end %>

View File

@ -0,0 +1 @@
include T('default/module/html')

View File

@ -0,0 +1,51 @@
include T('default/module')
require File.join(File.dirname(__FILE__),'../html_helper')
require File.join(File.dirname(__FILE__),'../template_helper')
def init
sections :header, :box_info, :pre_docstring, :docstring, :parameter_details, :provider_details
@template_helper = TemplateHelper.new
@html_helper = HTMLHelper.new
end
def provider_details
type_name = object.name.to_s
@providers = YARD::Registry.all(:provider).select { |t| t.type_name == type_name }
erb(:provider_details)
end
def parameter_details
params = object.parameter_details.map { |h| h[:name] }
# Put properties and parameters in one big list where the descriptions are
# scrubbed and htmlified and the namevar is the first element, the ensure
# property the second, and the rest are alphabetized.
@param_details = (object.parameter_details + object.property_details).each {
|h| h[:desc] = htmlify(Puppet::Util::Docs::scrub(h[:desc])) if h[:desc]
}.sort { |a, b| a[:name] <=> b[:name] }
if ensurable = @param_details.index { |h| h[:name] == 'ensure' }
@param_details = @param_details.unshift(@param_details.delete_at(ensurable))
end
if namevar = @param_details.index { |h| h[:namevar] }
@param_details = @param_details.unshift(@param_details.delete_at(namevar))
end
@feature_details = object.features
@template_helper.check_parameters_match_docs object
erb(:parameter_details)
end
def header
@header_text = "Puppet Type: #{object.name}"
erb(:header)
end
def docstring
@class_details = @template_helper.extract_tag_data(object)
erb(:docstring)
end

View File

@ -74,7 +74,9 @@ Classes: 0 ( 0 undocumented)
Constants: 0 ( 0 undocumented)
Methods: 0 ( 0 undocumented)
Puppet Classes: 1 ( 0 undocumented)
Puppet Defined Types: 0 ( 0 undocumented)
Puppet Types: 0 ( 0 undocumented)
Puppet Providers: 0 ( 0 undocumented)
100.00% documented
output
expected_stderr = "@param tag types do not match the code. The ident parameter is declared as types [\"Float\"] in the docstring, but the code specifies the types [Puppet::Pops::Types::PStringType] in file manifests/init.pp near line 2\n"

View File

@ -1,12 +1,12 @@
require 'spec_helper'
require 'puppet_x/puppetlabs/strings/yard/handlers/provider_handler'
require 'puppet_x/puppetlabs/strings/yard/handlers/type_handler'
require 'strings_spec/parsing'
describe PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetProviderHandler do
describe PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetTypeHandler do
include StringsSpec::Parsing
def the_provider()
def the_type()
YARD::Registry.at("file")
end
@ -23,7 +23,7 @@ describe PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetProviderHandler do
end
RUBY
expect(the_provider.docstring).to eq("Manages files, including their " +
expect(the_type.docstring).to eq("Manages files, including their " +
"content, ownership, and perms.")
end
@ -31,7 +31,7 @@ describe PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetProviderHandler do
parse <<-RUBY
Puppet::Type.newtype(:file) do
@doc = "Manages files, including their content, ownership, and perms."
newparam(:path) do
newparam(:file) do
desc <<-'EOT'
The path to the file to manage. Must be fully qualified.
EOT
@ -40,9 +40,13 @@ describe PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetProviderHandler do
end
RUBY
expect(the_provider.parameter_details).to eq([{ :name => "path",
expect(the_type.parameter_details).to eq([{ :name => "file",
:desc => "The path to the file to manage. Must be fully qualified.",
:exists? => true, :provider => true, }])
:exists? => true, :puppet_type => true, :namevar => true,
:default => nil,
:parameter=>true,
:allowed_values=>[],
}])
end
it "should have the proper parameters" do
@ -58,6 +62,6 @@ describe PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetProviderHandler do
end
RUBY
expect(the_provider.parameters).to eq([["path", nil]])
expect(the_type.parameters).to eq([["path", nil]])
end
end