diff --git a/lib/puppet/face/strings.rb b/lib/puppet/face/strings.rb index d9f9661..3ae536d 100644 --- a/lib/puppet/face/strings.rb +++ b/lib/puppet/face/strings.rb @@ -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) diff --git a/lib/puppet_x/puppetlabs/strings.rb b/lib/puppet_x/puppetlabs/strings.rb index e857dc5..727bd22 100644 --- a/lib/puppet_x/puppetlabs/strings.rb +++ b/lib/puppet_x/puppetlabs/strings.rb @@ -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 diff --git a/lib/puppet_x/puppetlabs/strings/yard/code_objects/type_object.rb b/lib/puppet_x/puppetlabs/strings/yard/code_objects/type_object.rb new file mode 100644 index 0000000..0ca38b1 --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/code_objects/type_object.rb @@ -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] + attr_accessor :parameters +end diff --git a/lib/puppet_x/puppetlabs/strings/yard/handlers/provider_handler.rb b/lib/puppet_x/puppetlabs/strings/yard/handlers/provider_handler.rb index e48453b..ec118be 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/handlers/provider_handler.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/handlers/provider_handler.rb @@ -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 diff --git a/lib/puppet_x/puppetlabs/strings/yard/handlers/type_handler.rb b/lib/puppet_x/puppetlabs/strings/yard/handlers/type_handler.rb new file mode 100644 index 0000000..d146e6f --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/handlers/type_handler.rb @@ -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 diff --git a/lib/puppet_x/puppetlabs/strings/yard/monkey_patches.rb b/lib/puppet_x/puppetlabs/strings/yard/monkey_patches.rb index 781dca6..a1da734 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/monkey_patches.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/monkey_patches.rb @@ -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 diff --git a/lib/puppet_x/puppetlabs/strings/yard/tags/directives.rb b/lib/puppet_x/puppetlabs/strings/yard/tags/directives.rb index 531af50..dcb60e0 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/tags/directives.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/tags/directives.rb @@ -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 diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/full_list_puppet_type.erb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/full_list_puppet_type.erb new file mode 100644 index 0000000..14748c8 --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/full_list_puppet_type.erb @@ -0,0 +1 @@ +<%= namespace_list(:namespace_types => [:type]) %> diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/setup.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/setup.rb index c6dd7c8..285ef9a 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/setup.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/fulldoc/html/setup.rb @@ -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 = {}) diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/html_helper.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/html_helper.rb index d633fa9..7469083 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/templates/default/html_helper.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/html_helper.rb @@ -15,6 +15,30 @@ class HTMLHelper result.join end + def generate_features features, object + result = [] + + if features + features.each do |feat| + result << "
  • " + result << "#{feat[:name]} " + if feat[:desc] + result << "-

    #{feat[:desc]}

    " + end + if feat[:methods] + result << "

    Methods

    " + result << "" + end + result << "
  • " + 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 << "(" << "" << possible_types.join(", ") << "" << ")" 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 << "(Unknown)" end + if param[:puppet_type] and param[:parameter] + result << " Parameter " + elsif param[:puppet_type] and param[:property] + result << " Property " + end + + if param[:namevar] + result << " Namevar " + end + if param[:default] + result << " Default value: " << param[:default] << " " + end result << "" @@ -76,6 +112,20 @@ class HTMLHelper if param[:desc] result << " -

    #{param[:desc]}

    " end + if param[:allowed_values] and param[:allowed_values] != [] + result << "

    Allowed Values:

    " + result << "" + end + if !param[:exists?] result << "" diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/layout/html/setup.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/layout/html/setup.rb index 62a6369..05d8aeb 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/templates/default/layout/html/setup.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/layout/html/setup.rb @@ -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 diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/command_details.erb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/command_details.erb new file mode 100644 index 0000000..6e9bf56 --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/command_details.erb @@ -0,0 +1,8 @@ +

    Commands Summary

    +
    + +
    diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/command_details.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/command_details.rb new file mode 100644 index 0000000..3d57a79 --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/command_details.rb @@ -0,0 +1,12 @@ +

    Parameter Summary

    +
    + +
    +

    Features

    +
    + +
    diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/confine_details.erb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/confine_details.erb new file mode 100644 index 0000000..fa7b88d --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/confine_details.erb @@ -0,0 +1,10 @@ +

    Confines

    +<% if @confine_details != {} %> +
    + +
    +<% end %> diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/default_details.erb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/default_details.erb new file mode 100644 index 0000000..cc71ded --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/default_details.erb @@ -0,0 +1,10 @@ +

    Defaults

    +<% if @default_details != {} %> +
    + +
    +<% end %> diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/docstring.erb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/docstring.erb index 900985f..da20e29 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/docstring.erb +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/docstring.erb @@ -1,6 +1,6 @@
    -

    <%= htmlify(@class_details[:desc]) %>

    +

    <%= htmlify(Puppet::Util::Docs::scrub(@class_details[:desc])) %>

    diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/feature_details.erb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/feature_details.erb new file mode 100644 index 0000000..6ebfcff --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/feature_details.erb @@ -0,0 +1,10 @@ +

    Features

    +<% if @feature_details != [] %> +
    +
      + <% @feature_details.each do |feature| %> +
    • <%= feature %>
    • + <% end %> +
    +
    +<% end %> diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/setup.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/setup.rb index 3878183..f9cf10c 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/setup.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/setup.rb @@ -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 diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/docstring.erb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/docstring.erb new file mode 100644 index 0000000..da20e29 --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/docstring.erb @@ -0,0 +1,34 @@ +
    +
    +

    <%= htmlify(Puppet::Util::Docs::scrub(@class_details[:desc])) %>

    +
    +
    +
    + <% if @class_details[:examples] != {}%> +
    +

    Examples:

    + <% @class_details[:examples].each do |title, text| %> +

    <%= title %>

    +
    <%= text %>
    + <% end %> +
    + <% end %> + <% if @class_details[:since] %> +

    Since:

    +
      +
    • +
      +

      <%= @class_details[:since] %>

      +
      +
    • +
    + <% end %> + <% if @class_details[:return] %> +

    Return:

    +
      +
    • + <%= @html_helper.generate_return_types(@class_details[:return][1], @class_details[:return][0]) %> +
    • +
    + <% end %> +
    diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/header.erb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/header.erb new file mode 100644 index 0000000..74b3dba --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/header.erb @@ -0,0 +1,5 @@ +
    +

    + <%= @header_text %> +

    +
    diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/parameter_details.erb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/parameter_details.erb similarity index 51% rename from lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/parameter_details.erb rename to lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/parameter_details.erb index d03666e..3d57a79 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/templates/default/provider/html/parameter_details.erb +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/parameter_details.erb @@ -4,3 +4,9 @@ <%= @html_helper.generate_parameters(@param_details, object) %>
    +

    Features

    +
    + +
    diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/provider_details.erb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/provider_details.erb new file mode 100644 index 0000000..779af2d --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/provider_details.erb @@ -0,0 +1,10 @@ +

    Available Providers

    +<% if @providers != [] %> +
    + +
    +<% end %> diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/setup.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/setup.rb new file mode 100644 index 0000000..91e114a --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/html/setup.rb @@ -0,0 +1 @@ +include T('default/module/html') diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/setup.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/setup.rb new file mode 100644 index 0000000..ca8bd9d --- /dev/null +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/type/setup.rb @@ -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 diff --git a/spec/unit/puppet_x/puppetlabs/strings/yard/host_class_handler_spec.rb b/spec/unit/puppet_x/puppetlabs/strings/yard/host_class_handler_spec.rb index 20694ab..57cbb37 100644 --- a/spec/unit/puppet_x/puppetlabs/strings/yard/host_class_handler_spec.rb +++ b/spec/unit/puppet_x/puppetlabs/strings/yard/host_class_handler_spec.rb @@ -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" diff --git a/spec/unit/puppet_x/puppetlabs/strings/yard/provider_handler_spec.rb b/spec/unit/puppet_x/puppetlabs/strings/yard/type_handler_spec.rb similarity index 71% rename from spec/unit/puppet_x/puppetlabs/strings/yard/provider_handler_spec.rb rename to spec/unit/puppet_x/puppetlabs/strings/yard/type_handler_spec.rb index 16f0487..338ce5c 100644 --- a/spec/unit/puppet_x/puppetlabs/strings/yard/provider_handler_spec.rb +++ b/spec/unit/puppet_x/puppetlabs/strings/yard/type_handler_spec.rb @@ -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