(PDOC-3) Switch to one line class declarations

Prior to this commit, many of the classes in this project were declared
in two lines. The first line would put them in the context of the module
they belonged to, and the second line would declare the class and deal with
inheritance. In order to make the code more readable and to allow
require statements to be moved to the top level, turn all class declarations
into one line statements.
This commit is contained in:
Hailee Kenney 2014-09-29 15:49:05 -07:00
parent df648a246f
commit f0da72b2b7
13 changed files with 376 additions and 393 deletions

View File

@ -1,5 +1,4 @@
require 'puppet/face'
require 'puppetx/puppetlabs/strings/actions'
Puppet::Face.define(:strings, '0.0.1') do
summary "Generate Puppet documentation with YARD."
@ -34,6 +33,7 @@ Puppet::Face.define(:strings, '0.0.1') do
when_invoked do |*args|
check_required_features
require 'puppetx/puppetlabs/strings/actions'
yardoc_actions = Puppetx::PuppetLabs::Strings::Actions.new(Puppet[:debug], Puppet[:trace])
@ -63,6 +63,7 @@ Puppet::Face.define(:strings, '0.0.1') do
when_invoked do |*args|
check_required_features
require 'puppetx/puppetlabs/strings/actions'
server_actions = Puppetx::PuppetLabs::Strings::Actions.new(Puppet[:debug], Puppet[:trace])

View File

@ -6,6 +6,11 @@ module Puppetx::PuppetLabs
# This submodule contains bits that interface with the YARD plugin system.
module YARD
module Handlers
end
module CodeObjects
end
end
# This submodule contains bits that operate on the Pops module produced by

View File

@ -3,76 +3,73 @@ require 'puppet/pops'
require 'puppetx/puppetlabs/strings'
module Puppetx::PuppetLabs::Strings::Pops
# An adapter class that conforms a Pops model instance + adapters to the
# interface expected by YARD handlers.
#
# FIXME: Inhertiting from OpenStruct is a bit of a hack. It allows attributes
# to be declared as needed but in the long run understandibility of the code
# would be improved by having a concrete model.
class YARDStatement < OpenStruct
attr_reader :pops_obj, :comments
# An adapter class that conforms a Pops model instance + adapters to the
# interface expected by YARD handlers.
#
# FIXME: Inhertiting from OpenStruct is a bit of a hack. It allows attributes
# to be declared as needed but in the long run understandibility of the code
# would be improved by having a concrete model.
class Puppetx::PuppetLabs::Strings::Pops::YARDStatement < OpenStruct
attr_reader :pops_obj, :comments
def initialize(pops_obj)
# Initialize OpenStruct
super({})
def initialize(pops_obj)
# Initialize OpenStruct
super({})
unless pops_obj.is_a? Puppet::Pops::Model::PopsObject
raise ArgumentError, "A YARDStatement can only be initialized from a PopsObject. Got a: #{pops_obj.class}"
unless pops_obj.is_a? Puppet::Pops::Model::PopsObject
raise ArgumentError, "A YARDStatement can only be initialized from a PopsObject. Got a: #{pops_obj.class}"
end
@pops_obj = pops_obj
@pos_adapter = Puppet::Pops::Adapters::SourcePosAdapter.adapt(@pops_obj)
# FIXME: Perhaps this should be a seperate adapter?
@comments = extract_comments
end
def type
pops_obj.class
end
def line
@line ||= @pos_adapter.line
end
def source
@source ||= @pos_adapter.extract_text
end
# FIXME: I don't know quite what these are supposed to do, but they show up
# quite often in the YARD handler code. Figure out whether they are
# necessary.
alias_method :show, :source
def comments_hash_flag; nil end
def comments_range; nil end
private
# TODO: This stuff should probably be part of a separate class/adapter.
COMMENT_PATTERN = /^\s*#.*\n/
def extract_comments
comments = []
program = pops_obj.eAllContainers.find {|c| c.is_a?(Puppet::Pops::Model::Program) }
# FIXME: Horribly inefficient. Multiple copies. Generator pattern would
# be much better.
source_text = program.source_text.lines.to_a
source_text.slice(0, line-1).reverse.each do |line|
if COMMENT_PATTERN.match(line)
# FIXME: The gsub trims comments, but is extremely optimistic: It
# assumes only one space separates the comment body from the
# comment character.
comments.unshift line.gsub(/^\s*#\s/, '')
else
# No comment found on this line. We must be done piecing together a
# comment block.
break
end
@pops_obj = pops_obj
@pos_adapter = Puppet::Pops::Adapters::SourcePosAdapter.adapt(@pops_obj)
# FIXME: Perhaps this should be a seperate adapter?
@comments = extract_comments
end
def type
pops_obj.class
end
def line
@line ||= @pos_adapter.line
end
def source
@source ||= @pos_adapter.extract_text
end
# FIXME: I don't know quite what these are supposed to do, but they show up
# quite often in the YARD handler code. Figure out whether they are
# necessary.
alias_method :show, :source
def comments_hash_flag; nil end
def comments_range; nil end
private
# TODO: This stuff should probably be part of a separate class/adapter.
COMMENT_PATTERN = /^\s*#.*\n/
def extract_comments
comments = []
program = pops_obj.eAllContainers.find {|c| c.is_a?(Puppet::Pops::Model::Program) }
# FIXME: Horribly inefficient. Multiple copies. Generator pattern would
# be much better.
source_text = program.source_text.lines.to_a
source_text.slice(0, line-1).reverse.each do |line|
if COMMENT_PATTERN.match(line)
# FIXME: The gsub trims comments, but is extremely optimistic: It
# assumes only one space separates the comment body from the
# comment character.
comments.unshift line.gsub(/^\s*#\s/, '')
else
# No comment found on this line. We must be done piecing together a
# comment block.
break
end
end
# Stick everything back together.
comments.join
end
# Stick everything back together.
comments.join
end
end

View File

@ -2,52 +2,50 @@ require 'puppet/pops'
require 'puppetx/puppetlabs/strings'
require 'puppetx/puppetlabs/strings/pops/yard_statement'
module Puppetx::PuppetLabs::Strings::Pops
# Loosely based on the TreeDumper classes in Pops::Model. The responsibility of
# this class is to walk a Pops::Model and output objects that can be consumed
# by YARD handlers.
#
# @note Currently, this class only extracts node, host class and type
# definitions.
class YARDTransformer
def initialize
@transform_visitor = Puppet::Pops::Visitor.new(self, 'transform')
# Loosely based on the TreeDumper classes in Pops::Model. The responsibility of
# this class is to walk a Pops::Model and output objects that can be consumed
# by YARD handlers.
#
# @note Currently, this class only extracts node, host class and type
# definitions.
class Puppetx::PuppetLabs::Strings::Pops::YARDTransformer
def initialize
@transform_visitor = Puppet::Pops::Visitor.new(self, 'transform')
end
def transform(o)
@transform_visitor.visit(o)
end
private
def transform_Factory(o)
transform(o.current)
end
def transform_Program(o)
o.definitions.map{|d| transform(d)}
end
# Extract comments from type definitions and class definitions. Wrap them
# into YARDStatement objects that provide an interface for YARD handlers.
def transform_NamedDefinition(o)
obj = Puppetx::PuppetLabs::Strings::Pops::YARDStatement.new(o)
obj.parameters = o.parameters.map do |p|
param_tuple = [transform(p)]
param_tuple << ( p.value.nil? ? nil : transform(p.value) )
end
def transform(o)
@transform_visitor.visit(o)
end
obj
end
private
# Catch-all visitor.
def transform_Positioned(o)
Puppetx::PuppetLabs::Strings::Pops::YARDStatement.new(o)
end
def transform_Factory(o)
transform(o.current)
end
def transform_Program(o)
o.definitions.map{|d| transform(d)}
end
# Extract comments from type definitions and class definitions. Wrap them
# into YARDStatement objects that provide an interface for YARD handlers.
def transform_NamedDefinition(o)
obj = YARDStatement.new(o)
obj.parameters = o.parameters.map do |p|
param_tuple = [transform(p)]
param_tuple << ( p.value.nil? ? nil : transform(p.value) )
end
obj
end
# Catch-all visitor.
def transform_Positioned(o)
YARDStatement.new(o)
end
# nil in... nil out!
def transform_NilClass(o)
nil
end
# nil in... nil out!
def transform_NilClass(o)
nil
end
end

View File

@ -2,10 +2,8 @@ require 'puppet/pops'
require 'puppetx/puppetlabs/strings/yard/code_objects/puppet_namespace_object'
module Puppetx::PuppetLabs::Strings::YARD::CodeObjects
class DefinedTypeObject < PuppetNamespaceObject
# A list of parameters attached to this class.
# @return [Array<Array(String, String)>]
attr_accessor :parameters
end
class Puppetx::PuppetLabs::Strings::YARD::CodeObjects::DefinedTypeObject < Puppetx::PuppetLabs::Strings::YARD::CodeObjects::PuppetNamespaceObject
# A list of parameters attached to this class.
# @return [Array<Array(String, String)>]
attr_accessor :parameters
end

View File

@ -1,26 +1,24 @@
require 'puppetx/puppetlabs/strings/yard/code_objects/defined_type_object'
module Puppetx::PuppetLabs::Strings::YARD::CodeObjects
class HostClassObject < DefinedTypeObject
# The {HostClassObject} that this class inherits from, if any.
# @return [HostClassObject, Proxy, nil]
attr_accessor :parent_class
class Puppetx::PuppetLabs::Strings::YARD::CodeObjects::HostClassObject < Puppetx::PuppetLabs::Strings::YARD::CodeObjects::DefinedTypeObject
# The {HostClassObject} that this class inherits from, if any.
# @return [HostClassObject, Proxy, nil]
attr_accessor :parent_class
# NOTE: `include_mods` is never used as it makes no sense for Puppet, but
# this is called by `YARD::Registry` and it will pass a parameter.
def inheritance_tree(include_mods = false)
if parent_class.is_a?(HostClassObject)
# Cool. We got a host class. Return self + parent inheritance tree.
[self] + parent_class.inheritance_tree
elsif parent_class.is_a?(YARD::CodeObjects::Proxy)
# We have a reference to a parent that has not been created yet. Just
# return it.
[self, parent_class]
else
# Most likely no parent class. But also possibly an object that we
# shouldn't inherit from. Just return self.
[self]
end
# NOTE: `include_mods` is never used as it makes no sense for Puppet, but
# this is called by `YARD::Registry` and it will pass a parameter.
def inheritance_tree(include_mods = false)
if parent_class.is_a?(Puppetx::PuppetLabs::Strings::YARD::CodeObjects::HostClassObject)
# Cool. We got a host class. Return self + parent inheritance tree.
[self] + parent_class.inheritance_tree
elsif parent_class.is_a?(YARD::CodeObjects::Proxy)
# We have a reference to a parent that has not been created yet. Just
# return it.
[self, parent_class]
else
# Most likely no parent class. But also possibly an object that we
# shouldn't inherit from. Just return self.
[self]
end
end
end

View File

@ -1,35 +1,33 @@
require 'yard'
require 'puppetx/puppetlabs/strings'
module Puppetx::PuppetLabs::Strings::YARD::CodeObjects
class PuppetNamespaceObject < YARD::CodeObjects::NamespaceObject
# NOTE: `YARD::Registry#resolve` requires a method with this signature to
# be present on all subclasses of `NamespaceObject`.
def inheritance_tree(include_mods = false)
[self]
end
# FIXME: We used to override `self.new` to ensure no YARD proxies were
# created for namespaces segments that did not map to a host class or
# defined type. Fighting the system in this way turned out to be
# counter-productive.
#
# However, if a proxy is left in, YARD will drop back to namspace-mangling
# heuristics that are very specific to Ruby and which produce ugly paths in
# the resulting output. Need to find a way to address this.
#
# Tried:
#
# - Overriding self.new in the code object. Failed because self.new
# overrides are gross and difficult to pull off. Especially when
# replacing an existing override.
#
# - Adding functionality to the base handler to ensure something other
# than a proxy occupies each namespace segment. Failed because once a
# code object is created with a namespace, it will never update.
# Unless that namespace is set to a Proxy.
#
# def self.new(namespace, name, *args, &block)
class Puppetx::PuppetLabs::Strings::YARD::CodeObjects::PuppetNamespaceObject < YARD::CodeObjects::NamespaceObject
# NOTE: `YARD::Registry#resolve` requires a method with this signature to
# be present on all subclasses of `NamespaceObject`.
def inheritance_tree(include_mods = false)
[self]
end
# FIXME: We used to override `self.new` to ensure no YARD proxies were
# created for namespaces segments that did not map to a host class or
# defined type. Fighting the system in this way turned out to be
# counter-productive.
#
# However, if a proxy is left in, YARD will drop back to namspace-mangling
# heuristics that are very specific to Ruby and which produce ugly paths in
# the resulting output. Need to find a way to address this.
#
# Tried:
#
# - Overriding self.new in the code object. Failed because self.new
# overrides are gross and difficult to pull off. Especially when
# replacing an existing override.
#
# - Adding functionality to the base handler to ensure something other
# than a proxy occupies each namespace segment. Failed because once a
# code object is created with a namespace, it will never update.
# Unless that namespace is set to a Proxy.
#
# def self.new(namespace, name, *args, &block)
end

View File

@ -4,16 +4,14 @@ require 'puppet/pops'
require 'puppetx/puppetlabs/strings'
require 'puppetx/puppetlabs/strings/yard/code_objects'
module Puppetx::PuppetLabs::Strings::YARD::Handlers
class Base < YARD::Handlers::Base
# Easy access to Pops model objects for handler matching.
include Puppet::Pops::Model
# Easy access to custom code objects from which documentation is generated.
include Puppetx::PuppetLabs::Strings::YARD::CodeObjects
def self.handles?(statement)
handlers.any? {|h| h == statement.type}
end
class Puppetx::PuppetLabs::Strings::YARD::Handlers::Base < YARD::Handlers::Base
# Easy access to Pops model objects for handler matching.
include Puppet::Pops::Model
# Easy access to custom code objects from which documentation is generated.
include Puppetx::PuppetLabs::Strings::YARD::CodeObjects
def self.handles?(statement)
handlers.any? {|h| h == statement.type}
end
end

View File

@ -1,18 +1,16 @@
require 'puppetx/puppetlabs/strings/yard/handlers/base'
module Puppetx::PuppetLabs::Strings::YARD::Handlers
class DefinedTypeHandler < Base
handles ResourceTypeDefinition
class Puppetx::PuppetLabs::Strings::YARD::Handlers::DefinedTypeHandler < Puppetx::PuppetLabs::Strings::YARD::Handlers:: Base
handles ResourceTypeDefinition
process do
obj = DefinedTypeObject.new(:root, statement.pops_obj.name) do |o|
o.parameters = statement.parameters.map do |a|
param_tuple = [a[0].pops_obj.name]
param_tuple << ( a[1].nil? ? nil : a[1].source )
end
process do
obj = DefinedTypeObject.new(:root, statement.pops_obj.name) do |o|
o.parameters = statement.parameters.map do |a|
param_tuple = [a[0].pops_obj.name]
param_tuple << ( a[1].nil? ? nil : a[1].source )
end
register obj
end
register obj
end
end

View File

@ -1,24 +1,22 @@
require 'puppetx/puppetlabs/strings/yard/handlers/base'
module Puppetx::PuppetLabs::Strings::YARD::Handlers
class HostClassHandler < Base
handles HostClassDefinition
class Puppetx::PuppetLabs::Strings::YARD::Handlers::HostClassHandler < Puppetx::PuppetLabs::Strings::YARD::Handlers::Base
handles HostClassDefinition
process do
obj = HostClassObject.new(:root, statement.pops_obj.name) do |o|
o.parameters = statement.parameters.map do |a|
param_tuple = [a[0].pops_obj.name]
param_tuple << ( a[1].nil? ? nil : a[1].source )
end
process do
obj = HostClassObject.new(:root, statement.pops_obj.name) do |o|
o.parameters = statement.parameters.map do |a|
param_tuple = [a[0].pops_obj.name]
param_tuple << ( a[1].nil? ? nil : a[1].source )
end
statement.pops_obj.tap do |o|
if o.parent_class
obj.parent_class = P(:root, o.parent_class)
end
end
register obj
end
statement.pops_obj.tap do |o|
if o.parent_class
obj.parent_class = P(:root, o.parent_class)
end
end
register obj
end
end

View File

@ -2,87 +2,86 @@
require 'puppet/util/docs'
require 'puppetx/puppetlabs/strings/yard/code_objects'
module Puppetx::PuppetLabs::Strings::YARD::Handlers
class Puppet3xFunctionHandler < YARD::Handlers::Ruby::Base
include Puppetx::PuppetLabs::Strings::YARD::CodeObjects
class Puppetx::PuppetLabs::Strings::YARD::Handlers::Puppet3xFunctionHandler < YARD::Handlers::Ruby::Base
include Puppetx::PuppetLabs::Strings::YARD::CodeObjects
handles method_call(:newfunction)
handles method_call(:newfunction)
process do
name, options = process_parameters
process do
name, options = process_parameters
obj = MethodObject.new(function_namespace, name)
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')
register obj
if options['doc']
register_docstring(obj, options['doc'], nil)
end
private
# 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)
# 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 ::Puppet3xFunctions, then there will be a clash. Hopefully the name
# is sufficiently uncommon.
obj = P(:root, 'Puppet3xFunctions')
if obj.is_a? Proxy
namespace_obj = PuppetNamespaceObject.new(:root, 'Puppet3xFunctions')
namespace_obj.add_tag YARD::Tags::Tag.new(:api, 'public')
# 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
register namespace_obj
end
private
obj
# 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 ::Puppet3xFunctions, then there will be a clash. Hopefully the name
# is sufficiently uncommon.
obj = P(:root, 'Puppet3xFunctions')
if obj.is_a? Proxy
namespace_obj = PuppetNamespaceObject.new(:root, 'Puppet3xFunctions')
namespace_obj.add_tag YARD::Tags::Tag.new(:api, 'public')
register namespace_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.
obj
end
# 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
# 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.
name = process_element(name)
# 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
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 = process_element(name)
[name, Hash[opts]]
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
# Sometimes the YARD parser returns Heredoc strings that start with `<-`
# instead of `<<-`.
HEREDOC_START = /^<?<-/
[name, Hash[opts]]
end
# Sometimes the YARD parser returns Heredoc strings that start with `<-`
# instead of `<<-`.
HEREDOC_START = /^<?<-/
# Turns an entry in the method parameter list into a string.
#
@ -104,20 +103,19 @@ module Puppetx::PuppetLabs::Strings::YARD::Handlers
end
end
# Cleans up and formats Heredoc contents parsed by YARD.
#
# @param source [String]
# @return [String]
def process_heredoc(source)
source = source.lines.to_a
# Cleans up and formats Heredoc contents parsed by YARD.
#
# @param source [String]
# @return [String]
def process_heredoc(source)
source = source.lines.to_a
# YARD adds a line of source context on either side of the Heredoc
# contents.
source.shift
source.pop
# YARD adds a line of source context on either side of the Heredoc
# contents.
source.shift
source.pop
# This utility method normalizes indentation and trims whitespace.
Puppet::Util::Docs.scrub(source.join)
end
# This utility method normalizes indentation and trims whitespace.
Puppet::Util::Docs.scrub(source.join)
end
end

View File

@ -1,98 +1,97 @@
require 'puppetx/puppetlabs/strings/yard/code_objects'
module Puppetx::PuppetLabs::Strings::YARD::Handlers
# 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 Puppet4xFunctionHandler < YARD::Handlers::Ruby::Base
include Puppetx::PuppetLabs::Strings::YARD::CodeObjects
# 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::Puppet4xFunctionHandler < YARD::Handlers::Ruby::Base
include Puppetx::PuppetLabs::Strings::YARD::CodeObjects
handles method_call(:dispatch)
handles method_call(:dispatch)
process do
return unless owner.is_a?(MethodObject) && owner['puppet_4x_function']
return unless statement.docstring
process do
return unless owner.is_a?(MethodObject) && owner['puppet_4x_function']
return unless statement.docstring
docstring = ::YARD::Docstring.new(statement.docstring, nil)
docstring = ::YARD::Docstring.new(statement.docstring, nil)
# FIXME: This does a wholesale copy of all possible tags. But, we're only
# interested in the @overload tag.
owner.add_tag *docstring.tags
end
# FIXME: This does a wholesale copy of all possible tags. But, we're only
# interested in the @overload tag.
owner.add_tag *docstring.tags
end
end
class Puppet4xFunctionHandler < YARD::Handlers::Ruby::Base
include Puppetx::PuppetLabs::Strings::YARD::CodeObjects
handles method_call(:create_function)
process do
name = process_parameters
obj = MethodObject.new(function_namespace, name)
obj['puppet_4x_function'] = true
register obj
obj.add_tag YARD::Tags::Tag.new(:api, 'public')
blk = statement.block.children.first
parse_block(blk, :owner => obj)
end
class Puppet4xFunctionHandler < YARD::Handlers::Ruby::Base
include Puppetx::PuppetLabs::Strings::YARD::CodeObjects
private
handles method_call(:create_function)
# 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 ::Puppet4xFunctions, then there will be a clash. Hopefully the name
# is sufficiently uncommon.
obj = P(:root, 'Puppet4xFunctions')
if obj.is_a? Proxy
namespace_obj = PuppetNamespaceObject.new(:root, 'Puppet4xFunctions')
process do
name = process_parameters
obj = MethodObject.new(function_namespace, name)
obj['puppet_4x_function'] = true
register obj
obj.add_tag YARD::Tags::Tag.new(:api, 'public')
blk = statement.block.children.first
parse_block(blk, :owner => obj)
register namespace_obj
# FIXME: The docstring has to be cleared. Otherwise, the namespace
# object will be registered using the docstring of the
# `create_function` call that is currently being processed.
#
# Figure out how to properly register the namespace without using the
# function handler object.
register_docstring(namespace_obj, '', nil)
namespace_obj.add_tag YARD::Tags::Tag.new(:api, 'public')
end
private
obj
end
# 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 ::Puppet4xFunctions, then there will be a clash. Hopefully the name
# is sufficiently uncommon.
obj = P(:root, 'Puppet4xFunctions')
if obj.is_a? Proxy
namespace_obj = PuppetNamespaceObject.new(:root, 'Puppet4xFunctions')
# 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.
register namespace_obj
# FIXME: The docstring has to be cleared. Otherwise, the namespace
# object will be registered using the docstring of the
# `create_function` call that is currently being processed.
#
# Figure out how to properly register the namespace without using the
# function handler object.
register_docstring(namespace_obj, '', nil)
namespace_obj.add_tag YARD::Tags::Tag.new(:api, 'public')
end
# 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, _ = statement.parameters(false).compact
obj
end
name = process_element(name)
# 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.
name
end
# 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, _ = statement.parameters(false).compact
name = process_element(name)
name
end
# Sometimes the YARD parser returns Heredoc strings that start with `<-`
# instead of `<<-`.
HEREDOC_START = /^<?<-/
# Sometimes the YARD parser returns Heredoc strings that start with `<-`
# instead of `<<-`.
HEREDOC_START = /^<?<-/
# Turns an entry in the method parameter list into a string.
#
@ -114,20 +113,19 @@ module Puppetx::PuppetLabs::Strings::YARD::Handlers
end
end
# Cleans up and formats Heredoc contents parsed by YARD.
#
# @param source [String]
# @return [String]
def process_heredoc(source)
source = source.lines.to_a
# Cleans up and formats Heredoc contents parsed by YARD.
#
# @param source [String]
# @return [String]
def process_heredoc(source)
source = source.lines.to_a
# YARD adds a line of source context on either side of the Heredoc
# contents.
source.shift
source.pop
# YARD adds a line of source context on either side of the Heredoc
# contents.
source.shift
source.pop
# This utility method normalizes indentation and trims whitespace.
Puppet::Util::Docs.scrub(source.join)
end
# This utility method normalizes indentation and trims whitespace.
Puppet::Util::Docs.scrub(source.join)
end
end

View File

@ -4,29 +4,27 @@ require 'puppet/pops'
require 'puppetx/puppetlabs/strings'
require 'puppetx/puppetlabs/strings//pops/yard_transformer'
module Puppetx::PuppetLabs::Strings::YARD
class PuppetParser < YARD::Parser::Base
attr_reader :file, :source
class Puppetx::PuppetLabs::Strings::YARD::PuppetParser < YARD::Parser::Base
attr_reader :file, :source
def initialize(source, filename)
@source = source
@file = filename
@parser = Puppet::Pops::Parser::Parser.new()
@transformer = Puppetx::PuppetLabs::Strings::Pops::YARDTransformer.new()
end
def parse
@parse_result ||= @parser.parse_string(source)
self
end
def enumerator
statements = @transformer.transform(@parse_result)
# Ensure an array is returned and prune any nil values.
Array(statements).compact
end
def initialize(source, filename)
@source = source
@file = filename
@parser = Puppet::Pops::Parser::Parser.new()
@transformer = Puppetx::PuppetLabs::Strings::Pops::YARDTransformer.new()
end
def parse
@parse_result ||= @parser.parse_string(source)
self
end
def enumerator
statements = @transformer.transform(@parse_result)
# Ensure an array is returned and prune any nil values.
Array(statements).compact
end
end