# This utility library contains some tools for working with Puppet docstrings. require 'puppet/util/docs' require_relative '../code_objects' module Puppetx::Strings::YARD::Handlers class ParserFunctionHandler < YARD::Handlers::Ruby::Base include Puppetx::Strings::YARD::CodeObjects handles method_call(:newfunction) process do name, options = process_parameters obj = MethodObject.new(function_namespace, name) register obj if options['doc'] register_docstring(obj, options['doc'], nil) end # This has to be done _after_ register_docstring as all tags on the # object are overwritten by tags parsed out of the docstring. return_type = options['type'] return_type ||= 'statement' # Default for newfunction obj.add_tag YARD::Tags::Tag.new(:return, '', return_type) # FIXME: This is a hack that allows us to document the Puppet Core which # uses `--no-transitive-tag api` and then only shows things explicitly # tagged with `public` or `private` api. This is kind of insane and # should be fixed upstream. obj.add_tag YARD::Tags::Tag.new(:api, 'public') end private # Returns a {PuppetNamespaceObject} for holding functions. Creates this # object if necessary. # # @return [PuppetNamespaceObject] def function_namespace # NOTE: This tricky. If there is ever a Ruby class or module with the # name ::ParserFunctions, then there will be a clash. Hopefully the name # is sufficiently uncommon. obj = P(:root, 'ParserFunctions') if obj.is_a? Proxy namespace_obj = PuppetNamespaceObject.new(:root, 'ParserFunctions') namespace_obj.add_tag YARD::Tags::Tag.new(:api, 'public') register namespace_obj end obj end # NOTE: The following methods duplicate functionality from # Puppet::Util::Reference and Puppet::Parser::Functions.functiondocs # # However, implementing this natively in YARD is a good test for the # feasibility of extracting custom Ruby documentation. In the end, the # existing approach taken by Puppet::Util::Reference may be the best due to # the heavy use of metaprogramming in Types and Providers. # Extracts the Puppet function name and options hash from the parsed # definition. # # @return [(String, Hash{String => String})] def process_parameters # Passing `false` to prameters excludes the block param from the returned # list. name, opts = statement.parameters(false).compact name = process_element(name) opts = opts.map do |tuple| # Jump down into the S-Expression that represents a hashrocket, `=>`, # and the values on either side of it. tuple.jump(:assoc).map{|e| process_element(e)} end [name, Hash[opts]] end # Sometimes the YARD parser returns Heredoc strings that start with `<-` # instead of `<<-`. HEREDOC_START = /^