diff --git a/JSON.md b/JSON.md
index 66e35ba39..0f446c8e9 100644
--- a/JSON.md
+++ b/JSON.md
@@ -9,17 +9,19 @@ puppet strings generate --format json
Document Schema
===============
-At the top level, there are seven arrays in the JSON document:
-
-| Document Key | Description |
-| ---------------- | ----------------------------------------------------------------------------- |
-| puppet_classes | The list of Puppet classes that were parsed. |
-| defined_types | The list of defined types that were parsed. |
-| resource_types | The list of resource types that were parsed. |
-| providers | The list of resource providers that were parsed. |
-| puppet_functions | The list of Puppet functions (4.x, 4.x and Puppet language) that were parsed. |
-| puppet_tasks | The list of Puppet tasks that were parsed. |
-| puppet_plans | The list of Puppet plans that were parsed. |
+At the top level, there are nine arrays in the JSON document:
+
+| Document Key | Description |
+| ----------------- | ----------------------------------------------------------------------------- |
+| puppet_classes | The list of Puppet classes that were parsed. |
+| data_types | The list of data types that were parsed. |
+| data_type_aliases | | The list of data types that were parsed. |
+| defined_types | The list of defined types that were parsed. |
+| resource_types | The list of resource types that were parsed. |
+| providers | The list of resource providers that were parsed. |
+| puppet_functions | The list of Puppet functions (4.x, 4.x and Puppet language) that were parsed. |
+| puppet_tasks | The list of Puppet tasks that were parsed. |
+| puppet_plans | The list of Puppet plans that were parsed. |
Puppet Classes
--------------
@@ -36,6 +38,34 @@ Each entry in the `puppet_classes` list is an object with the following attribut
| defaults | The map of parameter names to default values. |
| source | The Puppet source code for the class. |
+Data Types
+----------
+
+Each entry in the `data_types` list is an object with the following attributes:
+
+| Attribute Key | Description |
+| ------------- | ----------------------------------------------------------- |
+| name | The name of the data type. |
+| file | The file defining the data type. |
+| line | The line where the data type is data. |
+| docstring | The *DocString* object for the data type (see below). |
+| defaults | The map of parameter names to default values. |
+| source | The ruby source code for the data type. (Not Implemented) |
+
+Data Type Aliases
+-----------------
+
+Each entry in the `data_type_aliases` list is an object with the following attributes:
+
+| Attribute Key | Description |
+| ------------- | ----------------------------------------------------------------- |
+| name | The name of the data type. |
+| file | The file defining the data type. |
+| line | The line where the data type is defined. |
+| docstring | The *DocString* object for the data type (see below). |
+| alias_of | The actual type this is an alias of. |
+| source | The Puppet source code for the data type alias. (Not Implemented) |
+
Defined Types
-------------
diff --git a/lib/puppet-strings/json.rb b/lib/puppet-strings/json.rb
index be0266ade..ec8cfd022 100644
--- a/lib/puppet-strings/json.rb
+++ b/lib/puppet-strings/json.rb
@@ -8,6 +8,8 @@ module PuppetStrings::Json
def self.render(file = nil)
document = {
puppet_classes: YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash),
+ data_types: YARD::Registry.all(:puppet_data_type).sort_by!(&:name).map!(&:to_hash),
+ data_type_aliases: YARD::Registry.all(:puppet_data_type_alias).sort_by!(&:name).map!(&:to_hash),
defined_types: YARD::Registry.all(:puppet_defined_type).sort_by!(&:name).map!(&:to_hash),
resource_types: YARD::Registry.all(:puppet_type).sort_by!(&:name).map!(&:to_hash),
providers: YARD::Registry.all(:puppet_provider).sort_by!(&:name).map!(&:to_hash),
diff --git a/lib/puppet-strings/markdown.rb b/lib/puppet-strings/markdown.rb
index 6a9f33ccd..5a2bca9da 100644
--- a/lib/puppet-strings/markdown.rb
+++ b/lib/puppet-strings/markdown.rb
@@ -5,6 +5,7 @@ module PuppetStrings::Markdown
require_relative 'markdown/puppet_classes'
require_relative 'markdown/functions'
require_relative 'markdown/defined_types'
+ require_relative 'markdown/data_types'
require_relative 'markdown/resource_types'
require_relative 'markdown/puppet_tasks'
require_relative 'markdown/puppet_plans'
@@ -20,6 +21,7 @@ def self.generate
final << PuppetStrings::Markdown::DefinedTypes.render
final << PuppetStrings::Markdown::ResourceTypes.render
final << PuppetStrings::Markdown::Functions.render
+ final << PuppetStrings::Markdown::DataTypes.render
final << PuppetStrings::Markdown::PuppetTasks.render
final << PuppetStrings::Markdown::PuppetPlans.render
diff --git a/lib/puppet-strings/markdown/data_type.rb b/lib/puppet-strings/markdown/data_type.rb
new file mode 100644
index 000000000..903559e3a
--- /dev/null
+++ b/lib/puppet-strings/markdown/data_type.rb
@@ -0,0 +1,18 @@
+require 'puppet-strings/markdown/base'
+
+module PuppetStrings::Markdown
+ # This class encapsualtes ruby data types and puppet type aliases
+ class DataType < Base
+ attr_reader :alias_of
+
+ def initialize(registry)
+ @template = 'data_type.erb'
+ super(registry, 'data type')
+ @alias_of = registry[:alias_of] unless registry[:alias_of].nil?
+ end
+
+ def render
+ super(@template)
+ end
+ end
+end
diff --git a/lib/puppet-strings/markdown/data_types.rb b/lib/puppet-strings/markdown/data_types.rb
new file mode 100644
index 000000000..7a0fe317e
--- /dev/null
+++ b/lib/puppet-strings/markdown/data_types.rb
@@ -0,0 +1,41 @@
+require_relative 'data_type'
+
+module PuppetStrings::Markdown
+ module DataTypes
+
+ # @return [Array] list of data types
+ def self.in_dtypes
+ arr = YARD::Registry.all(:puppet_data_type).map!(&:to_hash)
+ arr.concat(YARD::Registry.all(:puppet_data_type_alias).map!(&:to_hash))
+
+ arr.sort! { |a,b| a[:name] <=> b[:name] }
+ arr.map! { |a| PuppetStrings::Markdown::DataType.new(a) }
+ end
+
+ def self.contains_private?
+ result = false
+ unless in_dtypes.nil?
+ in_dtypes.find { |type| type.private? }.nil? ? false : true
+ end
+ end
+
+ def self.render
+ final = in_dtypes.length > 0 ? "## Data types\n\n" : ""
+ in_dtypes.each do |type|
+ final << type.render unless type.private?
+ end
+ final
+ end
+
+
+ def self.toc_info
+ final = ["Data types"]
+
+ in_dtypes.each do |type|
+ final.push(type.toc_info)
+ end
+
+ final
+ end
+ end
+end
diff --git a/lib/puppet-strings/markdown/table_of_contents.rb b/lib/puppet-strings/markdown/table_of_contents.rb
index 6db5facbd..54aaa5bca 100644
--- a/lib/puppet-strings/markdown/table_of_contents.rb
+++ b/lib/puppet-strings/markdown/table_of_contents.rb
@@ -7,6 +7,7 @@ def self.render
PuppetStrings::Markdown::DefinedTypes,
PuppetStrings::Markdown::ResourceTypes,
PuppetStrings::Markdown::Functions,
+ PuppetStrings::Markdown::DataTypes,
PuppetStrings::Markdown::PuppetTasks,
PuppetStrings::Markdown::PuppetPlans].each do |r|
toc = r.toc_info
diff --git a/lib/puppet-strings/markdown/templates/data_type.erb b/lib/puppet-strings/markdown/templates/data_type.erb
new file mode 100644
index 000000000..6306b69d2
--- /dev/null
+++ b/lib/puppet-strings/markdown/templates/data_type.erb
@@ -0,0 +1,78 @@
+### <%= name %>
+
+<% if text -%>
+<%= text %>
+<% elsif summary -%>
+<%= summary %>
+<% else -%>
+<%= "The #{name} data type." %>
+<% end -%>
+
+<% if todo -%>
+* **TODO** <%= todo %>
+
+<% end -%>
+<% if note -%>
+* **Note** <%= note %>
+
+<% end -%>
+<% if since -%>
+* **Since** <%= since %>
+
+<% end -%>
+<% if see -%>
+* **See also**
+<% see.each do |sa| -%>
+<% if sa[:name] -%>
+<%= sa[:name] %>
+<% end -%>
+<% if sa[:text] -%>
+<%= sa[:text] %>
+<% end -%>
+<% end -%>
+
+<% end -%>
+<% if examples -%>
+#### Examples
+
+<% examples.each do |eg| -%>
+##### <%= eg[:name] %>
+
+```puppet
+<%= eg[:text] %>
+```
+
+<% end -%>
+<% end -%>
+<% if alias_of -%>
+Alias of `<%= alias_of %>`
+
+<% end -%>
+<% if params -%>
+#### Parameters
+
+The following parameters are available in the `<%= name %>` <%= @type %>.
+
+<% params.each do |param| -%>
+##### `<%= param[:name] %>`
+
+<% if param[:types] -%>
+Data type: `<%= param[:types].join(', ') -%>`
+
+<% end -%>
+<%= param[:text] %>
+
+<% if options_for_param(param[:name]) -%>
+Options:
+
+<% options_for_param(param[:name]).each do |o| -%>
+* **<%= o[:opt_name] %>** `<%= o[:opt_types][0] %>`: <%= o[:opt_text] %>
+<% end -%>
+
+<% end -%>
+<% if defaults && defaults[param[:name]] -%>
+Default value: <%= value_string(defaults[param[:name]]) %>
+
+<% end -%>
+<% end -%>
+<% end -%>
diff --git a/lib/puppet-strings/yard.rb b/lib/puppet-strings/yard.rb
index 155a64aca..56ea11145 100644
--- a/lib/puppet-strings/yard.rb
+++ b/lib/puppet-strings/yard.rb
@@ -46,6 +46,8 @@ def all_objects
:module,
:class,
:puppet_class,
+ :puppet_data_type,
+ :puppet_data_type_alias,
:puppet_defined_type,
:puppet_type,
:puppet_provider,
@@ -64,6 +66,14 @@ def stats_for_puppet_classes
output 'Puppet Classes', *type_statistics_all(:puppet_class)
end
+ def stats_for_puppet_data_types
+ output 'Puppet Data Types', *type_statistics_all(:puppet_data_type)
+ end
+
+ def stats_for_puppet_data_type_aliases
+ output 'Puppet Data Type Aliases', *type_statistics_all(:puppet_data_type_alias)
+ end
+
def stats_for_puppet_defined_types
output 'Puppet Defined Types', *type_statistics_all(:puppet_defined_type)
end
diff --git a/lib/puppet-strings/yard/code_objects.rb b/lib/puppet-strings/yard/code_objects.rb
index 0d3ecd44c..f4f6f92b9 100644
--- a/lib/puppet-strings/yard/code_objects.rb
+++ b/lib/puppet-strings/yard/code_objects.rb
@@ -1,6 +1,8 @@
# The module for custom YARD code objects.
module PuppetStrings::Yard::CodeObjects
require 'puppet-strings/yard/code_objects/class'
+ require 'puppet-strings/yard/code_objects/data_type'
+ require 'puppet-strings/yard/code_objects/data_type_alias'
require 'puppet-strings/yard/code_objects/defined_type'
require 'puppet-strings/yard/code_objects/type'
require 'puppet-strings/yard/code_objects/provider'
diff --git a/lib/puppet-strings/yard/code_objects/data_type.rb b/lib/puppet-strings/yard/code_objects/data_type.rb
new file mode 100644
index 000000000..ee6d0be79
--- /dev/null
+++ b/lib/puppet-strings/yard/code_objects/data_type.rb
@@ -0,0 +1,80 @@
+require 'puppet-strings/yard/code_objects/group'
+require 'puppet-strings/yard/util'
+
+# Implements the group for Puppet DataTypes.
+class PuppetStrings::Yard::CodeObjects::DataTypes < PuppetStrings::Yard::CodeObjects::Group
+ # Gets the singleton instance of the group.
+ # @return Returns the singleton instance of the group.
+ def self.instance
+ super(:puppet_data_types)
+ end
+
+ # Gets the display name of the group.
+ # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces.
+ # @return [String] Returns the display name of the group.
+ def name(prefix = false)
+ 'Puppet Data Types'
+ end
+end
+
+# Implements the Puppet DataType code object.
+class PuppetStrings::Yard::CodeObjects::DataType < PuppetStrings::Yard::CodeObjects::Base
+ # Initializes a Puppet class code object.
+ # @param [String] The name of the Data Type
+ # @return [void]
+ def initialize(name)
+ super(PuppetStrings::Yard::CodeObjects::DataTypes.instance, name)
+ @parameters = []
+ @defaults = {}
+ end
+
+ # Gets the type of the code object.
+ # @return Returns the type of the code object.
+ def type
+ :puppet_data_type
+ end
+
+ # Gets the source of the code object.
+ # @return Returns the source of the code object.
+ def source
+ # Not implemented, but would be nice!
+ nil
+ end
+
+ def parameter_exist?(name)
+ !docstring.tags(:param).find { |item| item.name == name }.nil?
+ end
+
+ def add_parameter(name, type, default)
+ tag = docstring.tags(:param).find { |item| item.name == name }
+ if tag.nil?
+ tag = YARD::Tags::Tag.new(:param, '', nil, name)
+ docstring.add_tag(tag)
+ end
+ type = [type] unless type.is_a?(Array)
+ tag.types = type if tag.types.nil?
+ set_parameter_default(name, default)
+ end
+
+ def set_parameter_default(param_name, default)
+ defaults.delete(param_name)
+ defaults[param_name] = default unless default.nil?
+ end
+
+ def parameters
+ docstring.tags(:param).map { |tag| [tag.name, defaults[tag.name]] }
+ end
+
+ # Converts the code object to a hash representation.
+ # @return [Hash] Returns a hash representation of the code object.
+ def to_hash
+ hash = {}
+ hash[:name] = name
+ hash[:file] = file
+ hash[:line] = line
+ hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
+ hash[:defaults] = defaults unless defaults.empty?
+ hash[:source] = source unless source && source.empty?
+ hash
+ end
+end
diff --git a/lib/puppet-strings/yard/code_objects/data_type_alias.rb b/lib/puppet-strings/yard/code_objects/data_type_alias.rb
new file mode 100644
index 000000000..324145628
--- /dev/null
+++ b/lib/puppet-strings/yard/code_objects/data_type_alias.rb
@@ -0,0 +1,58 @@
+require 'puppet-strings/yard/code_objects/group'
+require 'puppet-strings/yard/util'
+
+# Implements the group for Puppet DataTypeAliases.
+class PuppetStrings::Yard::CodeObjects::DataTypeAliases < PuppetStrings::Yard::CodeObjects::Group
+ # Gets the singleton instance of the group.
+ # @return Returns the singleton instance of the group.
+ def self.instance
+ super(:puppet_data_type_aliases)
+ end
+
+ # Gets the display name of the group.
+ # @param [Boolean] prefix whether to show a prefix. Ignored for Puppet group namespaces.
+ # @return [String] Returns the display name of the group.
+ def name(prefix = false)
+ 'Puppet Data Type Aliases'
+ end
+end
+
+# Implements the Puppet DataTypeAlias code object.
+class PuppetStrings::Yard::CodeObjects::DataTypeAlias < PuppetStrings::Yard::CodeObjects::Base
+ attr_reader :statement
+ attr_accessor :alias_of
+
+ # Initializes a Puppet data type alias code object.
+ # @param [PuppetStrings::Parsers::DataTypeAliasStatement] statement The data type alias statement that was parsed.
+ # @return [void]
+ def initialize(statement)
+ @statement = statement
+ @alias_of = statement.alias_of
+ super(PuppetStrings::Yard::CodeObjects::DataTypeAliases.instance, statement.name)
+ end
+
+ # Gets the type of the code object.
+ # @return Returns the type of the code object.
+ def type
+ :puppet_data_type_alias
+ end
+
+ # Gets the source of the code object.
+ # @return Returns the source of the code object.
+ def source
+ # Not implemented, but would be nice!
+ nil
+ end
+
+ # Converts the code object to a hash representation.
+ # @return [Hash] Returns a hash representation of the code object.
+ def to_hash
+ hash = {}
+ hash[:name] = name
+ hash[:file] = file
+ hash[:line] = line
+ hash[:docstring] = PuppetStrings::Yard::Util.docstring_to_hash(docstring)
+ hash[:alias_of] = alias_of
+ hash
+ end
+end
diff --git a/lib/puppet-strings/yard/handlers.rb b/lib/puppet-strings/yard/handlers.rb
index 7229523b6..705dcd48e 100644
--- a/lib/puppet-strings/yard/handlers.rb
+++ b/lib/puppet-strings/yard/handlers.rb
@@ -2,6 +2,7 @@
module PuppetStrings::Yard::Handlers
# The module for custom Ruby YARD handlers.
module Ruby
+ require 'puppet-strings/yard/handlers/ruby/data_type_handler'
require 'puppet-strings/yard/handlers/ruby/type_handler'
require 'puppet-strings/yard/handlers/ruby/type_extras_handler'
require 'puppet-strings/yard/handlers/ruby/rsapi_handler'
@@ -17,6 +18,7 @@ module JSON
# The module for custom Puppet YARD handlers.
module Puppet
require 'puppet-strings/yard/handlers/puppet/class_handler'
+ require 'puppet-strings/yard/handlers/puppet/data_type_alias_handler'
require 'puppet-strings/yard/handlers/puppet/defined_type_handler'
require 'puppet-strings/yard/handlers/puppet/function_handler'
require 'puppet-strings/yard/handlers/puppet/plan_handler'
diff --git a/lib/puppet-strings/yard/handlers/puppet/data_type_alias_handler.rb b/lib/puppet-strings/yard/handlers/puppet/data_type_alias_handler.rb
new file mode 100644
index 000000000..39eb9a6ad
--- /dev/null
+++ b/lib/puppet-strings/yard/handlers/puppet/data_type_alias_handler.rb
@@ -0,0 +1,24 @@
+require 'puppet-strings/yard/handlers/helpers'
+require 'puppet-strings/yard/handlers/puppet/base'
+require 'puppet-strings/yard/parsers'
+require 'puppet-strings/yard/code_objects'
+
+# Implements the handler for Puppet Data Type Alias.
+class PuppetStrings::Yard::Handlers::Puppet::DataTypeAliasHandler < PuppetStrings::Yard::Handlers::Puppet::Base
+ handles PuppetStrings::Yard::Parsers::Puppet::DataTypeAliasStatement
+
+ process do
+ # Register the object
+ object = PuppetStrings::Yard::CodeObjects::DataTypeAlias.new(statement)
+ register object
+
+ # Log a warning if missing documentation
+ log.warn "Missing documentation for Puppet type alias '#{object.name}' at #{statement.file}:#{statement.line}." if object.docstring.empty? && object.tags.empty?
+
+ # Mark the class as public if it doesn't already have an api tag
+ object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
+
+ # Warn if a summary longer than 140 characters was provided
+ PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary
+ end
+end
diff --git a/lib/puppet-strings/yard/handlers/ruby/data_type_handler.rb b/lib/puppet-strings/yard/handlers/ruby/data_type_handler.rb
new file mode 100644
index 000000000..a7750a0f0
--- /dev/null
+++ b/lib/puppet-strings/yard/handlers/ruby/data_type_handler.rb
@@ -0,0 +1,236 @@
+require 'puppet-strings/yard/handlers/helpers'
+require 'puppet-strings/yard/handlers/ruby/base'
+require 'puppet-strings/yard/code_objects'
+require 'puppet-strings/yard/util'
+
+# Implements the handler for Puppet Data Types written in Ruby.
+class PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler < PuppetStrings::Yard::Handlers::Ruby::Base
+ namespace_only
+ handles method_call(:create_type)
+
+ process do
+ return unless statement.count > 1
+ ruby_module_name = statement[0].source
+ return unless ruby_module_name == 'Puppet::DataTypes' || ruby_module_name == 'DataTypes' # rubocop:disable Style/MultipleComparison This reads better
+ object = get_datatype_yard_object(get_name(statement, 'Puppet::DataTypes.create_type'))
+
+ actual_params = extract_params_for_data_type # populate_data_type_data(object)
+
+ # Mark the data type as public if it doesn't already have an api tag
+ object.add_tag YARD::Tags::Tag.new(:api, 'public') unless object.has_tag? :api
+
+ validate_tags!(object, actual_params)
+
+ # Set the default values for all parameters
+ actual_params.each { |name, data| object.set_parameter_default(name, data[:default]) }
+
+ # Default any typeless param tag to 'Any'
+ object.tags(:param).each do |tag|
+ tag.types = ['Any'] unless tag.types && !tag.types.empty?
+ end
+
+ # Warn if a summary longer than 140 characters was provided
+ PuppetStrings::Yard::Handlers::Helpers.validate_summary_tag(object) if object.has_tag? :summary
+ end
+
+ private
+
+ def get_datatype_yard_object(name)
+ # Have to guess the path - if we create the object to get the true path from the code,
+ # it also shows up in the .at call - self registering?
+ guess_path = "puppet_data_types::#{name}"
+ object = YARD::Registry.at(guess_path)
+
+ return object unless object.nil?
+
+ # Didn't find, create instead
+ object = PuppetStrings::Yard::CodeObjects::DataType.new(name)
+ register object
+ object
+ end
+
+ def extract_params_for_data_type
+ params = {}
+ # Traverse the block looking for interface
+ block = statement.block
+ return unless block && block.count >= 2
+ block[1].children.each do |node|
+ next unless node.is_a?(YARD::Parser::Ruby::MethodCallNode) &&
+ node.method_name
+
+ method_name = node.method_name.source
+ parameters = node.parameters(false)
+ if method_name == 'interface'
+ next unless parameters.count >= 1
+ interface_string = node_as_string(parameters[0])
+ next unless interface_string
+ # Ref - https://github.com/puppetlabs/puppet/blob/ba4d1a1aba0095d3c70b98fea5c67434a4876a61/lib/puppet/datatypes.rb#L159
+ parsed_interface = Puppet::Pops::Parser::EvaluatingParser.new.parse_string("{ #{interface_string} }").body
+ next unless parsed_interface
+
+ # Now that we parsed the Puppet code (as a string) into a LiteralHash PCore type (Puppet AST),
+ #
+ # We need to convert the LiteralHash into a conventional ruby hash of strings. The
+ # LazyLiteralEvaluator does this by traversing the AST tree can converting objects to strings
+ # where possible and ignoring object types which cannot (thus the 'Lazy' name)
+ #
+ # Once we have it as a standard ruby hash we can then look at the keys and populate the YARD
+ # Code object with the correct attributes etc.
+ literal_eval = LazyLiteralEvaluator.new
+ populate_data_type_params_from_literal_hash!(literal_eval.literal(parsed_interface), params)
+ end
+ end
+ params
+ end
+
+ # Lazily evaluates a Pops object, ignoring any objects that cannot
+ # be converted to a literal value. Based on the Puppet Literal Evaluator
+ # Ref - https://github.com/puppetlabs/puppet/blob/ba4d1a1aba0095d3c70b98fea5c67434a4876a61/lib/puppet/pops/evaluator/literal_evaluator.rb
+ #
+ # Literal values for:
+ # String (not containing interpolation)
+ # Numbers
+ # Booleans
+ # Undef (produces nil)
+ # Array
+ # Hash
+ # QualifiedName
+ # Default (produced :default)
+ # Regular Expression (produces ruby regular expression)
+ # QualifiedReference e.g. File, FooBar
+ # AccessExpression
+ #
+ # Anything else is ignored
+ class LazyLiteralEvaluator
+ def initialize
+ @literal_visitor ||= ::Puppet::Pops::Visitor.new(self, "literal", 0, 0)
+ end
+
+ def literal(ast)
+ @literal_visitor.visit_this_0(self, ast)
+ end
+
+ # ----- The following methods are different/additions from the original Literal_evaluator
+ def literal_Object(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ # Ignore any other object types
+ end
+
+ def literal_AccessExpression(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ # Extract the raw text of the Access Expression
+ ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(o).extract_text
+ end
+
+ def literal_QualifiedReference(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ # Extract the raw text of the Qualified Reference
+ ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(o).extract_text
+ end
+
+ # ----- The following methods are the same as the original Literal_evaluator
+ def literal_Factory(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ literal(o.model)
+ end
+
+ def literal_Program(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ literal(o.body)
+ end
+
+ def literal_LiteralString(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ o.value
+ end
+
+ def literal_QualifiedName(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ o.value
+ end
+
+ def literal_LiteralNumber(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ o.value
+ end
+
+ def literal_LiteralBoolean(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ o.value
+ end
+
+ def literal_LiteralUndef(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ nil
+ end
+
+ def literal_LiteralDefault(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ :default
+ end
+
+ def literal_LiteralRegularExpression(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ o.value
+ end
+
+ def literal_ConcatenatedString(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ # use double quoted string value if there is no interpolation
+ throw :not_literal unless o.segments.size == 1 && o.segments[0].is_a?(Model::LiteralString)
+ o.segments[0].value
+ end
+
+ def literal_LiteralList(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ o.values.map {|v| literal(v) }
+ end
+
+ def literal_LiteralHash(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ o.entries.reduce({}) do |result, entry|
+ result[literal(entry.key)] = literal(entry.value)
+ result
+ end
+ end
+ end
+
+ def populate_data_type_params_from_literal_hash!(hash, params_hash)
+ return if hash.nil?
+ # Exit early if there are no entries in the hash
+ return if hash['attributes'].nil? || hash['attributes'].count.zero?
+
+ hash['attributes'].each do |key, value|
+ data_type = nil
+ default = nil
+ case value
+ when String
+ data_type = value
+ when Hash
+ data_type = value['type'] unless value['type'].nil?
+ default = value['value'] unless value['value'].nil?
+ end
+ data_type = [data_type] unless data_type.nil? || data_type.is_a?(Array)
+ params_hash[key] = { :types => data_type, :default => default }
+ end
+ end
+
+ def validate_tags!(object, actual_params_hash)
+ actual_param_names = actual_params_hash.keys
+ tagged_param_names = object.tags(:param).map(&:name)
+ # Log any errors
+ # Find attributes which are not documented
+ (actual_param_names - tagged_param_names).each do |item|
+ log.warn "Missing @param tag for attribute '#{item}' near #{object.file}:#{object.line}."
+ end
+ # Find param tags with no matching attribute
+ (tagged_param_names - actual_param_names).each do |item|
+ log.warn "The @param tag for '#{item}' has no matching attribute near #{object.file}:#{object.line}."
+ end
+ # Find param tags with a type that is different from the actual definition
+ object.tags(:param).reject { |tag| tag.types.nil? }.each do |tag|
+ next if actual_params_hash[tag.name].nil?
+ actual_data_type = actual_params_hash[tag.name][:types]
+ next if actual_data_type.nil?
+ log.warn "The @param tag for '#{tag.name}' has a different type definition than the actual attribute near #{object.file}:#{object.line}." if tag.types != actual_data_type
+ end
+
+ # Automatically fix missing @param tags
+ (actual_param_names - tagged_param_names).each do |name|
+ object.add_parameter(name, actual_params_hash[name][:types], actual_params_hash[name][:default])
+ end
+ # Remove extra param tags
+ object.docstring.delete_tag_if { |item| item.tag_name == 'param' && !actual_param_names.include?(item.name) }
+
+ # Set the type in the param tag
+ object.tags(:param).each do |tag|
+ next if actual_params_hash[tag.name].nil?
+ tag.types = actual_params_hash[tag.name][:types]
+ end
+ end
+end
diff --git a/lib/puppet-strings/yard/parsers/puppet/parser.rb b/lib/puppet-strings/yard/parsers/puppet/parser.rb
index 819057d2f..13a20cf16 100644
--- a/lib/puppet-strings/yard/parsers/puppet/parser.rb
+++ b/lib/puppet-strings/yard/parsers/puppet/parser.rb
@@ -76,6 +76,12 @@ def transform_PlanDefinition(o) # rubocop:disable Naming/UncommunicativeMethodPa
statement
end
+ def transform_TypeAlias(o) # rubocop:disable Naming/UncommunicativeMethodParamName
+ statement = PuppetStrings::Yard::Parsers::Puppet::DataTypeAliasStatement.new(o, @file)
+ statement.extract_docstring(@lines)
+ statement
+ end
+
def transform_Object(o) # rubocop:disable Naming/UncommunicativeMethodParamName
# Ignore anything else (will be compacted out of the resulting array)
end
diff --git a/lib/puppet-strings/yard/parsers/puppet/statement.rb b/lib/puppet-strings/yard/parsers/puppet/statement.rb
index eea04a744..e5233229c 100644
--- a/lib/puppet-strings/yard/parsers/puppet/statement.rb
+++ b/lib/puppet-strings/yard/parsers/puppet/statement.rb
@@ -165,4 +165,29 @@ def initialize(object, file)
end
end
+ # Implements the Puppet data type alias statement.
+ class DataTypeAliasStatement < Statement
+ attr_reader :name
+ attr_reader :alias_of
+
+ # Initializes the Puppet data type alias statement.
+ # @param [Puppet::Pops::Model::TypeAlias] object The model object for the type statement.
+ # @param [String] file The file containing the statement.
+ def initialize(object, file)
+ super(object, file)
+
+ type_expr = object.type_expr
+ case type_expr
+ when Puppet::Pops::Model::AccessExpression
+ # TODO: I don't like rebuilding the source from the AST, but AccessExpressions don't expose the original source
+ @alias_of = ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(type_expr.left_expr).extract_text + '['
+ @alias_of << type_expr.keys.map { |key| ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(key).extract_text }.join(', ')
+ @alias_of << ']'
+ else
+ adapter = ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(type_expr)
+ @alias_of = adapter.extract_text
+ end
+ @name = object.name
+ end
+ end
end
diff --git a/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_data_type.erb b/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_data_type.erb
new file mode 100644
index 000000000..3e253da81
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/fulldoc/html/full_list_puppet_data_type.erb
@@ -0,0 +1,10 @@
+<% even = false %>
+<% @items.each do |item| %>
+
+
+ <%= linkify item, h(item.name(false)) %>
+ <% if item.type == :puppet_data_type_alias %>Alias<% end %>
+
+
+ <% even = !even %>
+<% end %>
diff --git a/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb b/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb
index 5a3425f6f..4087e9d9c 100644
--- a/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb
+++ b/lib/puppet-strings/yard/templates/default/fulldoc/html/setup.rb
@@ -7,6 +7,15 @@ def generate_puppet_class_list
generate_list_contents
end
+# Generates the searchable Puppet data type list.
+# @return [void]
+def generate_puppet_data_type_list
+ @items = Registry.all(:puppet_data_type, :puppet_data_type_alias).sort_by {|dt| dt.name.to_s }
+ @list_title = 'Data Type List'
+ @list_type = 'puppet_data_type'
+ generate_list_contents
+end
+
# Generates the searchable Puppet defined type list.
# @return [void]
def generate_puppet_defined_type_list
diff --git a/lib/puppet-strings/yard/templates/default/layout/html/objects.erb b/lib/puppet-strings/yard/templates/default/layout/html/objects.erb
index afc6356d7..d9d90732e 100644
--- a/lib/puppet-strings/yard/templates/default/layout/html/objects.erb
+++ b/lib/puppet-strings/yard/templates/default/layout/html/objects.erb
@@ -23,6 +23,8 @@
(Resource type: <%= obj.type_name %>)
<% elsif obj.type == :puppet_function %>
(<%= obj.function_type %>)
+ <% elsif obj.type == :puppet_data_type_alias %>
+ (Alias)
<% end %>
<% end %>
diff --git a/lib/puppet-strings/yard/templates/default/layout/html/setup.rb b/lib/puppet-strings/yard/templates/default/layout/html/setup.rb
index 8a5aaa1a6..0750fce36 100644
--- a/lib/puppet-strings/yard/templates/default/layout/html/setup.rb
+++ b/lib/puppet-strings/yard/templates/default/layout/html/setup.rb
@@ -4,7 +4,7 @@ def init
case object
when '_index.html'
@page_title = options.title
- sections :layout, [:index, [:listing, [:classes, :defined_types, :types, :providers, :functions, :tasks, :plans, :files, :objects]]]
+ sections :layout, [:index, [:listing, [:classes, :data_types, :defined_types, :types, :providers, :functions, :tasks, :plans, :files, :objects]]]
else
super
end
@@ -30,6 +30,10 @@ def layout
@nav_url = url_for_list('puppet_class')
@page_title = "Puppet Class: #{object.name}"
@path = object.path
+ when PuppetStrings::Yard::CodeObjects::DataType, PuppetStrings::Yard::CodeObjects::DataTypeAlias
+ @nav_url = url_for_list('puppet_data_type')
+ @page_title = "Data Type: #{object.name}"
+ @path = object.path
when PuppetStrings::Yard::CodeObjects::DefinedType
@nav_url = url_for_list('puppet_defined_type')
@page_title = "Defined Type: #{object.name}"
@@ -76,6 +80,11 @@ def create_menu_lists
title: 'Puppet Classes',
search_title: 'Puppet Classes'
},
+ {
+ type: 'puppet_data_type',
+ title: 'Data Types',
+ search_title: 'Data Types',
+ },
{
type: 'puppet_defined_type',
title: 'Defined Types',
@@ -155,6 +164,14 @@ def classes
erb(:objects)
end
+# Renders the data types section.
+# @return [String] Returns the rendered section.
+def data_types
+ @title = 'Data Type Listing A-Z'
+ @objects_by_letter = objects_by_letter(:puppet_data_type, :puppet_data_type_alias)
+ erb(:objects)
+end
+
# Renders the defined types section.
# @return [String] Returns the rendered section.
def defined_types
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type/html/box_info.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/box_info.erb
new file mode 100644
index 000000000..49a646067
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/box_info.erb
@@ -0,0 +1,10 @@
+
+
+ - Defined in:
+ -
+ <%= object.file %><% if object.files.size > 1 %>,
+ <%= object.files[1..-1].map {|f| f.first }.join(",
") %>
+ <% end %>
+
+
+
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type/html/header.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/header.erb
new file mode 100644
index 000000000..7850ace8e
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/header.erb
@@ -0,0 +1 @@
+Puppet Data Type: <%= object.name %>
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type/html/note.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/note.erb
new file mode 100644
index 000000000..88c9ffb1e
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/note.erb
@@ -0,0 +1,6 @@
+<% object.tags(:note).each do |tag| %>
+
+ Note:
+ <%= htmlify_line tag.text %>
+
+<% end %>
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type/html/overview.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/overview.erb
new file mode 100644
index 000000000..a5b527a30
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/overview.erb
@@ -0,0 +1,6 @@
+Overview
+
+
+ <%= htmlify(object.docstring) %>
+
+
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type/html/setup.rb b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/setup.rb
new file mode 100644
index 000000000..d3dbefbe8
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/setup.rb
@@ -0,0 +1,5 @@
+# Initializes the template.
+# @return [void]
+def init
+ sections :header, :box_info, :summary, :overview, :note, :todo, T('tags'), :source
+end
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type/html/source.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/source.erb
new file mode 100644
index 000000000..0fd3c5e35
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/source.erb
@@ -0,0 +1,12 @@
+
+
+
+
+ <%= "\n\n\n" %><%= h format_lines(object) %>
+ |
+
+ # File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %><%= "\n\n" %><%= html_syntax_highlight object.source %>
+ |
+
+
+
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type/html/summary.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/summary.erb
new file mode 100644
index 000000000..75e98677a
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/summary.erb
@@ -0,0 +1,4 @@
+<% if object.docstring.has_tag?(:summary) %>
+ Summary
+ <%= object.docstring.tag(:summary).text %>
+<% end %>
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type/html/todo.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/todo.erb
new file mode 100644
index 000000000..8f91636fb
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type/html/todo.erb
@@ -0,0 +1,6 @@
+<% object.tags(:todo).each do |tag| %>
+
+ TODO:
+ <%= htmlify_line tag.text %>
+
+<% end %>
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/alias_of.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/alias_of.erb
new file mode 100644
index 000000000..956f1ab01
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/alias_of.erb
@@ -0,0 +1,10 @@
+<% if @alias_of && !@alias_of.empty? %>
+
+<% end %>
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/box_info.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/box_info.erb
new file mode 100644
index 000000000..49a646067
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/box_info.erb
@@ -0,0 +1,10 @@
+
+
+ - Defined in:
+ -
+ <%= object.file %><% if object.files.size > 1 %>,
+ <%= object.files[1..-1].map {|f| f.first }.join(",
") %>
+ <% end %>
+
+
+
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/header.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/header.erb
new file mode 100644
index 000000000..1929e8d92
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/header.erb
@@ -0,0 +1 @@
+Puppet Data Type Alias: <%= object.name %>
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/note.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/note.erb
new file mode 100644
index 000000000..88c9ffb1e
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/note.erb
@@ -0,0 +1,6 @@
+<% object.tags(:note).each do |tag| %>
+
+ Note:
+ <%= htmlify_line tag.text %>
+
+<% end %>
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/overview.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/overview.erb
new file mode 100644
index 000000000..a5b527a30
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/overview.erb
@@ -0,0 +1,6 @@
+Overview
+
+
+ <%= htmlify(object.docstring) %>
+
+
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/setup.rb b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/setup.rb
new file mode 100644
index 000000000..14d9d9002
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/setup.rb
@@ -0,0 +1,17 @@
+# Initializes the template.
+# @return [void]
+def init
+ sections :header, :box_info, :summary, :overview, :alias_of, :note, :todo, T('tags'), :source
+end
+
+# Renders the alias_of section.
+# @return [String] Returns the rendered section.
+def alias_of
+ # Properties are the same thing as parameters (from the documentation standpoint),
+ # so reuse the same template but with a different title and data source.
+ #@parameters = object.properties || []
+ #@parameters.sort_by! { |p| p.name }
+ @tag_title = 'Alias of'
+ @alias_of = object.alias_of
+ erb(:alias_of)
+end
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/source.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/source.erb
new file mode 100644
index 000000000..0fd3c5e35
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/source.erb
@@ -0,0 +1,12 @@
+
+
+
+
+ <%= "\n\n\n" %><%= h format_lines(object) %>
+ |
+
+ # File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %><%= "\n\n" %><%= html_syntax_highlight object.source %>
+ |
+
+
+
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/summary.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/summary.erb
new file mode 100644
index 000000000..75e98677a
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/summary.erb
@@ -0,0 +1,4 @@
+<% if object.docstring.has_tag?(:summary) %>
+ Summary
+ <%= object.docstring.tag(:summary).text %>
+<% end %>
diff --git a/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/todo.erb b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/todo.erb
new file mode 100644
index 000000000..8f91636fb
--- /dev/null
+++ b/lib/puppet-strings/yard/templates/default/puppet_data_type_alias/html/todo.erb
@@ -0,0 +1,6 @@
+<% object.tags(:todo).each do |tag| %>
+
+ TODO:
+ <%= htmlify_line tag.text %>
+
+<% end %>
diff --git a/lib/puppet-strings/yard/templates/default/tags/setup.rb b/lib/puppet-strings/yard/templates/default/tags/setup.rb
index 4e3f281dc..482438c2d 100644
--- a/lib/puppet-strings/yard/templates/default/tags/setup.rb
+++ b/lib/puppet-strings/yard/templates/default/tags/setup.rb
@@ -4,6 +4,7 @@ def param
tag(:param) if
object.type == :method ||
object.type == :puppet_class ||
+ object.type == :puppet_data_type ||
object.type == :puppet_defined_type ||
object.type == :puppet_function ||
object.type == :puppet_task ||
diff --git a/spec/acceptance/emit_json_options_spec.rb b/spec/acceptance/emit_json_options_spec.rb
index 5e661f47a..b6da4bf8a 100644
--- a/spec/acceptance/emit_json_options_spec.rb
+++ b/spec/acceptance/emit_json_options_spec.rb
@@ -9,6 +9,8 @@
let(:expected) do
{
"puppet_classes" => [],
+ "data_types" => [],
+ "data_type_aliases" => [],
"defined_types" => [],
"resource_types" => [],
"providers" => [],
diff --git a/spec/acceptance/running_strings_generate_spec.rb b/spec/acceptance/running_strings_generate_spec.rb
index 7190b1040..cd35352d6 100644
--- a/spec/acceptance/running_strings_generate_spec.rb
+++ b/spec/acceptance/running_strings_generate_spec.rb
@@ -59,4 +59,20 @@ def expect_file_contain(path, expected_contents)
'database — /usr/bin/database',
])
end
+
+ it 'should generate documentation for puppet data types' do
+ expect_file_contain('doc/puppet_types/database.html', [
+ 'Resource Type: database',
+ 'type/database.rb',
+ 'An example server resource type.',
+ ])
+ end
+
+ it 'should generate documentation for puppet data type aliases' do
+ expect_file_contain('doc/puppet_data_type_aliases/Test_3A_3AElephant.html', [
+ 'Data Type: Test::Elephant',
+ 'types/elephant.pp',
+ 'A simple elephant type.',
+ ])
+ end
end
diff --git a/spec/fixtures/acceptance/modules/test/types/elephant.pp b/spec/fixtures/acceptance/modules/test/types/elephant.pp
new file mode 100644
index 000000000..14e465cd0
--- /dev/null
+++ b/spec/fixtures/acceptance/modules/test/types/elephant.pp
@@ -0,0 +1,2 @@
+# A simple elephant type.
+type Test::Elephant = String[2]
diff --git a/spec/fixtures/unit/markdown/output_with_data_types.md b/spec/fixtures/unit/markdown/output_with_data_types.md
new file mode 100644
index 000000000..e53416f96
--- /dev/null
+++ b/spec/fixtures/unit/markdown/output_with_data_types.md
@@ -0,0 +1,553 @@
+# Reference
+
+
+## Table of Contents
+
+**Classes**
+
+_Public Classes_
+
+* [`klass`](#klass): A simple class.
+
+_Private Classes_
+
+* `noparams`: Overview for class noparams
+
+**Defined types**
+
+* [`klass::dt`](#klassdt): A simple defined type.
+
+**Resource types**
+
+* [`apt_key`](#apt_key): Example resource type using the new API.
+* [`database`](#database): An example database server type.
+
+**Functions**
+
+* [`func`](#func): A simple Puppet function.
+* [`func3x`](#func3x): Documentation for an example 3.x function.
+* [`func4x`](#func4x): An example 4.x function.
+* [`func4x_1`](#func4x_1): An example 4.x function with only one signature.
+
+**Data types**
+
+* [`Amodule::ComplexAlias`](#amodulecomplexalias): Documentation for Amodule::ComplexAlias
+* [`Amodule::SimpleAlias`](#amodulesimplealias): Documentation for Amodule::SimpleAlias
+* [`UnitDataType`](#unitdatatype): An example Puppet Data Type in Ruby.
+
+**Tasks**
+
+* [`(stdin)`](#(stdin)): Allows you to backup your database to local file.
+
+## Classes
+
+### klass
+
+An overview for a simple class.
+
+* **TODO** Do a thing
+
+* **Note** some note
+
+* **Since** 1.0.0
+
+* **See also**
+www.puppet.com
+
+#### Examples
+
+##### This is an example
+
+```puppet
+class { 'klass':
+ param1 => 1,
+ param3 => 'foo',
+}
+```
+
+##### This is another example
+
+```puppet
+class { 'klass':
+ param1 => 1,
+ param3 => 'foo',
+}
+```
+
+#### Parameters
+
+The following parameters are available in the `klass` class.
+
+##### `param1`
+
+Data type: `Integer`
+
+First param.
+
+Default value: 1
+
+##### `param2`
+
+Data type: `Any`
+
+Second param.
+
+Options:
+
+* **:opt1** `String`: something about opt1
+* **:opt2** `Hash`: a hash of stuff
+
+Default value: `undef`
+
+##### `param3`
+
+Data type: `String`
+
+Third param.
+
+Default value: 'hi'
+
+## Defined types
+
+### klass::dt
+
+An overview for a simple defined type.
+
+* **Since** 1.1.0
+
+* **See also**
+www.puppet.com
+
+#### Examples
+
+##### Here's an example of this type:
+
+```puppet
+klass::dt { 'foo':
+ param1 => 33,
+ param4 => false,
+}
+```
+
+#### Parameters
+
+The following parameters are available in the `klass::dt` defined type.
+
+##### `param1`
+
+Data type: `Integer`
+
+First param.
+
+Default value: 44
+
+##### `param2`
+
+Data type: `Any`
+
+Second param.
+
+Options:
+
+* **:opt1** `String`: something about opt1
+* **:opt2** `Hash`: a hash of stuff
+
+##### `param3`
+
+Data type: `String`
+
+Third param.
+
+Default value: 'hi'
+
+##### `param4`
+
+Data type: `Boolean`
+
+Fourth param.
+
+Default value: `true`
+
+## Resource types
+
+### apt_key
+
+This type provides Puppet with the capabilities to manage GPG keys needed
+by apt to perform package validation. Apt has it's own GPG keyring that can
+be manipulated through the `apt-key` command.
+**Autorequires**:
+If Puppet is given the location of a key file which looks like an absolute
+path this type will autorequire that file.
+
+#### Examples
+
+##### here's an example
+
+```puppet
+apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F':
+ source => 'http://apt.puppetlabs.com/pubkey.gpg'
+}
+```
+
+#### Properties
+
+The following properties are available in the `apt_key` type.
+
+##### `ensure`
+
+Data type: `Enum[present, absent]`
+
+Whether this apt key should be present or absent on the target system.
+
+##### `created`
+
+Data type: `String`
+
+Date the key was created, in ISO format.
+
+#### Parameters
+
+The following parameters are available in the `apt_key` type.
+
+##### `id`
+
+namevar
+
+Data type: `Variant[Pattern[/A(0x)?[0-9a-fA-F]{8}Z/], Pattern[/A(0x)?[0-9a-fA-F]{16}Z/], Pattern[/A(0x)?[0-9a-fA-F]{40}Z/]]`
+_*this data type contains a regex that may not be accurately reflected in generated documentation_
+
+The ID of the key you want to manage.
+
+### database
+
+An example database server type.
+
+#### Examples
+
+##### here's an example
+
+```puppet
+database { 'foo':
+ address => 'qux.baz.bar',
+}
+```
+
+#### Properties
+
+The following properties are available in the `database` type.
+
+##### `ensure`
+
+Valid values: present, absent, up, down
+
+Aliases: "up"=>"present", "down"=>"absent"
+
+What state the database should be in.
+
+Default value: up
+
+##### `file`
+
+The database file to use.
+
+##### `log_level`
+
+Valid values: debug, warn, error
+
+The log level to use.
+
+Default value: warn
+
+#### Parameters
+
+The following parameters are available in the `database` type.
+
+##### `address`
+
+namevar
+
+The database server name.
+
+##### `encryption_key`
+
+The encryption key to use.
+
+Required features: encryption.
+
+##### `encrypt`
+
+Valid values: `true`, `false`, yes, no
+
+Whether or not to encrypt the database.
+
+Default value: `false`
+
+## Functions
+
+### func
+
+Type: Puppet Language
+
+A simple Puppet function.
+
+#### Examples
+
+##### Test
+
+```puppet
+$result = func(1, 2)
+```
+
+#### `func(Integer $param1, Any $param2, String $param3 = hi)`
+
+A simple Puppet function.
+
+Returns: `Undef` Returns nothing.
+
+Raises:
+* `SomeError` this is some error
+
+##### Examples
+
+###### Test
+
+```puppet
+$result = func(1, 2)
+```
+
+##### `param1`
+
+Data type: `Integer`
+
+First param.
+
+##### `param2`
+
+Data type: `Any`
+
+Second param.
+
+##### `param3`
+
+Data type: `String`
+
+Third param.
+
+Options:
+
+* **:param3opt** `Array`: Something about this option
+
+### func3x
+
+Type: Ruby 3.x API
+
+Documentation for an example 3.x function.
+
+#### Examples
+
+##### Calling the function.
+
+```puppet
+func3x('hi', 10)
+```
+
+#### `func3x(String $param1, Integer $param2)`
+
+Documentation for an example 3.x function.
+
+Returns: `Undef`
+
+##### Examples
+
+###### Calling the function.
+
+```puppet
+func3x('hi', 10)
+```
+
+##### `param1`
+
+Data type: `String`
+
+The first parameter.
+
+##### `param2`
+
+Data type: `Integer`
+
+The second parameter.
+
+### func4x
+
+Type: Ruby 4.x API
+
+An example 4.x function.
+
+#### Examples
+
+##### Calling the function
+
+```puppet
+$result = func4x(1, 'foo')
+```
+
+##### Calling the function with all args
+
+```puppet
+$result = func4x(1, 'foo', ['bar'])
+```
+
+#### `func4x(Integer $param1, Any $param2, Optional[Array[String]] $param3)`
+
+An overview for the first overload.
+
+Returns: `Undef` Returns nothing.
+
+##### Examples
+
+###### Calling the function foo
+
+```puppet
+$result = func4x(1, 'foooo')
+```
+
+##### `param1`
+
+Data type: `Integer`
+
+The first parameter.
+
+##### `param2`
+
+Data type: `Any`
+
+The second parameter.
+
+Options:
+
+* **:option** `String`: an option
+* **:option2** `String`: another option
+
+##### `param3`
+
+Data type: `Optional[Array[String]]`
+
+The third parameter.
+
+#### `func4x(Boolean $param, Callable &$block)`
+
+An overview for the second overload.
+
+Returns: `String` Returns a string.
+
+##### Examples
+
+###### Calling the function bar
+
+```puppet
+$result = func4x(1, 'bar', ['foo'])
+```
+
+##### `param`
+
+Data type: `Boolean`
+
+The first parameter.
+
+##### `&block`
+
+Data type: `Callable`
+
+The block parameter.
+
+### func4x_1
+
+Type: Ruby 4.x API
+
+An example 4.x function with only one signature.
+
+#### `func4x_1(Integer $param1)`
+
+An example 4.x function with only one signature.
+
+Returns: `Undef` Returns nothing.
+
+##### `param1`
+
+Data type: `Integer`
+
+The first parameter.
+
+## Data types
+
+### Amodule::ComplexAlias
+
+Documentation for Amodule::ComplexAlias
+
+Alias of `Struct[{
+ value_type => Optional[ValueType],
+ merge => Optional[MergeType]
+}]`
+
+### Amodule::SimpleAlias
+
+Documentation for Amodule::SimpleAlias
+
+Alias of `Variant[Numeric, String[1,20]]`
+
+### UnitDataType
+
+An example Puppet Data Type in Ruby.
+
+#### Parameters
+
+The following parameters are available in the `UnitDataType` data type.
+
+##### `param1`
+
+Data type: `Variant[Numeric, String[1,2]]`
+
+A variant parameter.
+
+##### `param2`
+
+Data type: `Optional[String[1]]`
+
+Optional String parameter.
+
+Default value: param2
+
+## Tasks
+
+### (stdin)
+
+Allows you to backup your database to local file.
+
+**Supports noop?** false
+
+#### Parameters
+
+##### `database`
+
+Data type: `Optional[String[1]]`
+
+Database to connect to
+
+##### `user`
+
+Data type: `Optional[String[1]]`
+
+The user
+
+##### `password`
+
+Data type: `Optional[String[1]]`
+
+The password
+
+##### `sql`
+
+Data type: `String[1]`
+
+Path to file you want backup to
+
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index f62c1d33e..56a151d34 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -36,6 +36,9 @@
# Enable testing of Plans if Puppet version is greater than 5.0.0
TEST_PUPPET_PLANS = Puppet::Util::Package.versioncmp(Puppet.version, "5.0.0") >= 0
+# Enable testing of Data Types if Puppet version is greater than 4.1.0
+TEST_PUPPET_DATATYPES = Puppet::Util::Package.versioncmp(Puppet.version, "4.1.0") >= 0
+
RSpec.configure do |config|
config.mock_with :mocha
diff --git a/spec/unit/puppet-strings/json_spec.rb b/spec/unit/puppet-strings/json_spec.rb
index e1faf3e13..79afb2de1 100644
--- a/spec/unit/puppet-strings/json_spec.rb
+++ b/spec/unit/puppet-strings/json_spec.rb
@@ -43,6 +43,20 @@ class klass(Integer $param1, $param2, String $param3 = hi) inherits foo::bar {
}
SOURCE
+ # Only include Puppet types for 5.0+
+ YARD::Parser::SourceParser.parse_string(<<-SOURCE, :ruby) if TEST_PUPPET_DATATYPES
+# Basic Puppet Data Type in Ruby
+#
+# @param msg A message parameter
+Puppet::DataTypes.create_type('RubyDataType') do
+ interface <<-PUPPET
+ attributes => {
+ msg => String[1]
+ }
+ PUPPET
+end
+SOURCE
+
YARD::Parser::SourceParser.parse_string(<<-SOURCE, :json)
{
"description": "Allows you to backup your database to local file.",
@@ -209,6 +223,11 @@ class klass(Integer $param1, $param2, String $param3 = hi) inherits foo::bar {
expect(json_output).to include_json(puppet_class_json)
end
+ it 'should include data for Puppet Data Types' do
+ data_types_json = YARD::Registry.all(:puppet_data_type).sort_by!(&:name).map!(&:to_hash).to_json
+ expect(json_output).to include_json(data_types_json)
+ end
+
it 'should include data for Puppet Defined Types' do
defined_types_json = YARD::Registry.all(:puppet_defined_type).sort_by!(&:name).map!(&:to_hash).to_json
diff --git a/spec/unit/puppet-strings/markdown_spec.rb b/spec/unit/puppet-strings/markdown_spec.rb
index 4f4599315..8510f4528 100644
--- a/spec/unit/puppet-strings/markdown_spec.rb
+++ b/spec/unit/puppet-strings/markdown_spec.rb
@@ -4,7 +4,7 @@
require 'tempfile'
describe PuppetStrings::Markdown do
- before :each do
+ def parse_shared_content
# Populate the YARD registry with both Puppet and Ruby source
YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet)
# An overview for a simple class.
@@ -64,14 +64,6 @@ class noparams () {}
String $param3 = 'hi',
Boolean $param4 = true
) {
-}
- SOURCE
- YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) if TEST_PUPPET_PLANS
-# A simple plan.
-# @param param1 First param.
-# @param param2 Second param.
-# @param param3 Third param.
-plan plann(String $param1, $param2, Integer $param3 = 1) {
}
SOURCE
@@ -275,21 +267,90 @@ class noparams () {}
SOURCE
end
- let(:filename) do
- if TEST_PUPPET_PLANS
- 'output_with_plan.md'
- else
- 'output.md'
- end
+ def parse_plan_content
+ YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet)
+# A simple plan.
+# @param param1 First param.
+# @param param2 Second param.
+# @param param3 Third param.
+plan plann(String $param1, $param2, Integer $param3 = 1) {
+}
+ SOURCE
+ end
+
+ def parse_data_type_content
+ YARD::Parser::SourceParser.parse_string(<<-SOURCE, :ruby)
+# An example Puppet Data Type in Ruby.
+#
+# @param param1 A variant parameter.
+# @param param2 Optional String parameter.
+Puppet::DataTypes.create_type('UnitDataType') do
+ interface <<-PUPPET
+ attributes => {
+ param1 => Variant[Numeric, String[1,2]],
+ param2 => { type => Optional[String[1]], value => "param2" }
+ }
+ PUPPET
+end
+ SOURCE
+
+ YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet)
+# Documentation for Amodule::SimpleAlias
+type Amodule::SimpleAlias = Variant[Numeric,String[1,20]]
+
+# Documentation for Amodule::ComplexAlias
+type Amodule::ComplexAlias = Struct[{
+ value_type => Optional[ValueType],
+ merge => Optional[MergeType]
+}]
+ SOURCE
end
let(:baseline_path) { File.join(File.dirname(__FILE__), "../../fixtures/unit/markdown/#{filename}") }
let(:baseline) { File.read(baseline_path) }
describe 'rendering markdown to a file' do
- it 'should output the expected markdown content' do
- Tempfile.open('md') do |file|
- PuppetStrings::Markdown.render(file.path)
- expect(File.read(file.path)).to eq(baseline)
+ before(:each) do
+ parse_shared_content
+ end
+
+ context 'with common Puppet and ruby content' do
+ let(:filename) { 'output.md' }
+
+ it 'should output the expected markdown content' do
+ Tempfile.open('md') do |file|
+ PuppetStrings::Markdown.render(file.path)
+ expect(File.read(file.path)).to eq(baseline)
+ end
+ end
+ end
+
+ describe 'with Puppet Plans', :if => TEST_PUPPET_PLANS do
+ let(:filename) { 'output_with_plan.md' }
+
+ before(:each) do
+ parse_plan_content
+ end
+
+ it 'should output the expected markdown content' do
+ Tempfile.open('md') do |file|
+ PuppetStrings::Markdown.render(file.path)
+ expect(File.read(file.path)).to eq(baseline)
+ end
+ end
+ end
+
+ describe 'with Puppet Data Types', :if => TEST_PUPPET_DATATYPES do
+ let(:filename) { 'output_with_data_types.md' }
+
+ before(:each) do
+ parse_data_type_content
+ end
+
+ it 'should output the expected markdown content' do
+ Tempfile.open('md') do |file|
+ PuppetStrings::Markdown.render(file.path)
+ expect(File.read(file.path)).to eq(baseline)
+ end
end
end
end
diff --git a/spec/unit/puppet-strings/yard/handlers/puppet/data_type_alias_handler_spec.rb b/spec/unit/puppet-strings/yard/handlers/puppet/data_type_alias_handler_spec.rb
new file mode 100644
index 000000000..07da863f1
--- /dev/null
+++ b/spec/unit/puppet-strings/yard/handlers/puppet/data_type_alias_handler_spec.rb
@@ -0,0 +1,65 @@
+require 'spec_helper'
+require 'puppet-strings/yard'
+
+describe PuppetStrings::Yard::Handlers::Puppet::DataTypeAliasHandler, if: TEST_PUPPET_DATATYPES do
+ subject {
+ YARD::Parser::SourceParser.parse_string(source, :puppet)
+ YARD::Registry.all(:puppet_data_type_alias)
+ }
+
+ describe 'parsing source without a type alias definition' do
+ let(:source) { 'notice hi' }
+
+ it 'no aliases should be in the registry' do
+ expect(subject.empty?).to eq(true)
+ end
+ end
+
+ describe 'parsing source with a syntax error' do
+ let(:source) { 'type Testype =' }
+
+ it 'should log an error' do
+ expect{ subject }.to output(/\[error\]: Failed to parse \(stdin\): Syntax error at end of (file|input)/).to_stdout_from_any_process
+ expect(subject.empty?).to eq(true)
+ end
+ end
+
+ describe 'parsing a data type alias with a missing docstring' do
+ let(:source) { 'type Testype = String[1]' }
+
+ it 'should log a warning' do
+ expect{ subject }.to output(/\[warn\]: Missing documentation for Puppet type alias 'Testype' at \(stdin\):1\./).to_stdout_from_any_process
+ end
+ end
+
+ describe 'parsing a data type alias with a summary' do
+ context 'when the summary has fewer than 140 characters' do
+ let(:source) { <<-SOURCE
+ # A simple foo type.
+ # @summary A short summary.
+ type Testype = String[1]
+ SOURCE
+ }
+
+ it 'should parse the summary' do
+ expect{ subject }.to output('').to_stdout_from_any_process
+ expect(subject.size).to eq(1)
+ summary = subject.first.tags(:summary)
+ expect(summary.first.text).to eq('A short summary.')
+ end
+ end
+
+ context 'when the summary has more than 140 characters' do
+ let(:source) { <<-SOURCE
+ # A simple foo type.
+ # @summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!!
+ type Testype = String[1]
+ SOURCE
+ }
+
+ it 'should log a warning' do
+ expect{ subject }.to output(/\[warn\]: The length of the summary for puppet_data_type_alias 'Testype' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process
+ end
+ end
+ end
+end
diff --git a/spec/unit/puppet-strings/yard/handlers/ruby/data_type_handler_spec.rb b/spec/unit/puppet-strings/yard/handlers/ruby/data_type_handler_spec.rb
new file mode 100644
index 000000000..1291f531a
--- /dev/null
+++ b/spec/unit/puppet-strings/yard/handlers/ruby/data_type_handler_spec.rb
@@ -0,0 +1,232 @@
+require 'spec_helper'
+require 'puppet-strings/yard'
+
+describe PuppetStrings::Yard::Handlers::Ruby::DataTypeHandler, if: TEST_PUPPET_DATATYPES do
+ subject {
+ YARD::Parser::SourceParser.parse_string(source, :ruby)
+ YARD::Registry.all(:puppet_data_type)
+ }
+
+ before(:each) do
+ # Tests may suppress logging to make it easier to read results,
+ # so remember the logging object prior to running the test
+ @original_yard_logging_object = YARD::Logger.instance.io
+ end
+
+ after(:each) do
+ # Restore the original logging IO object
+ YARD::Logger.instance.io = @original_yard_logging_object
+ end
+
+ def suppress_yard_logging
+ YARD::Logger.instance.io = nil
+ end
+
+ describe 'parsing source without a data type definition' do
+ let(:source) { 'puts "hi"' }
+
+ it 'no data types should be in the registry' do
+ expect(subject.empty?).to eq(true)
+ end
+ end
+
+ describe 'parsing an empty data type definition' do
+ let(:source) { <<-SOURCE
+Puppet::DataTypes.create_type('RubyDataType') do
+end
+SOURCE
+ }
+
+ it 'should register a data type object with no param tags' do
+ expect(subject.size).to eq(1)
+ object = subject.first
+ expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType)
+ expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DataTypes.instance)
+ expect(object.name).to eq(:RubyDataType)
+ expect(object.docstring).to eq('')
+ expect(object.docstring.tags.size).to eq(1)
+ tags = object.docstring.tags(:api)
+ expect(tags.size).to eq(1)
+ expect(tags[0].text).to eq('public')
+
+ expect(object.parameters.size).to eq(0)
+ end
+ end
+
+ describe 'parsing a data type definition with missing param tags' do
+ let(:source) { <<-SOURCE
+# An example Puppet Data Type in Ruby.
+Puppet::DataTypes.create_type('RubyDataType') do
+ interface <<-PUPPET
+ attributes => {
+ msg => String[1],
+ }
+ PUPPET
+end
+SOURCE
+ }
+
+ it 'should output a warning' do
+ expect{ subject }.to output(/\[warn\]: Missing @param tag for attribute 'msg' near \(stdin\):2/).to_stdout_from_any_process
+ end
+
+ it 'should register a data type object with all param tags' do
+ suppress_yard_logging
+
+ expect(subject.size).to eq(1)
+ object = subject.first
+ expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType)
+ expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DataTypes.instance)
+ expect(object.name).to eq(:RubyDataType)
+ expect(object.docstring).to eq('An example Puppet Data Type in Ruby.')
+ expect(object.docstring.tags.size).to eq(2)
+ tags = object.docstring.tags(:api)
+ expect(tags.size).to eq(1)
+ expect(tags[0].text).to eq('public')
+
+ # Check that the param tags are created
+ tags = object.docstring.tags(:param)
+ expect(tags.size).to eq(1)
+ expect(tags[0].name).to eq('msg')
+ expect(tags[0].text).to eq('')
+ expect(tags[0].types).to eq(['String[1]'])
+
+ # Check for default values for parameters
+ expect(object.parameters.size).to eq(1)
+ expect(object.parameters[0]).to eq(['msg', nil])
+ end
+ end
+
+ describe 'parsing a data type definition with extra param tags' do
+ let(:source) { <<-SOURCE
+# An example Puppet Data Type in Ruby.
+# @param msg A message parameter.
+# @param arg1 Optional String parameter. Defaults to 'param'.
+Puppet::DataTypes.create_type('RubyDataType') do
+ interface <<-PUPPET
+ attributes => {
+ msg => Numeric,
+ }
+ PUPPET
+end
+SOURCE
+ }
+
+ it 'should output a warning' do
+ expect{ subject }.to output(/\[warn\]: The @param tag for 'arg1' has no matching attribute near \(stdin\):4/).to_stdout_from_any_process
+ end
+
+ it 'should register a data type object with extra param tags removed' do
+ suppress_yard_logging
+
+ expect(subject.size).to eq(1)
+ object = subject.first
+ expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType)
+ expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DataTypes.instance)
+ expect(object.name).to eq(:RubyDataType)
+ expect(object.docstring).to eq('An example Puppet Data Type in Ruby.')
+ expect(object.docstring.tags.size).to eq(2)
+ tags = object.docstring.tags(:api)
+ expect(tags.size).to eq(1)
+ expect(tags[0].text).to eq('public')
+
+ # Check that the param tags are removed
+ tags = object.docstring.tags(:param)
+ expect(tags.size).to eq(1)
+ expect(tags[0].name).to eq('msg')
+ expect(tags[0].text).to eq('A message parameter.')
+ expect(tags[0].types).to eq(['Numeric'])
+
+ # Check that only the actual attributes appear
+ expect(object.parameters.size).to eq(1)
+ expect(object.parameters[0]).to eq(['msg', nil])
+ end
+ end
+
+ describe 'parsing a valid data type definition' do
+ let(:source) { <<-SOURCE
+# An example Puppet Data Type in Ruby.
+#
+# @param msg A message parameter5.
+# @param arg1 Optional String parameter5. Defaults to 'param'.
+Puppet::DataTypes.create_type('RubyDataType') do
+ interface <<-PUPPET
+ attributes => {
+ msg => Variant[Numeric, String[1,2]],
+ arg1 => { type => Optional[String[1]], value => "param" }
+ }
+ PUPPET
+end
+SOURCE
+ }
+
+ it 'should register a data type object' do
+ expect(subject.size).to eq(1)
+ object = subject.first
+ expect(object).to be_a(PuppetStrings::Yard::CodeObjects::DataType)
+ expect(object.namespace).to eq(PuppetStrings::Yard::CodeObjects::DataTypes.instance)
+ expect(object.name).to eq(:RubyDataType)
+ expect(object.docstring).to eq('An example Puppet Data Type in Ruby.')
+ expect(object.docstring.tags.size).to eq(3)
+ tags = object.docstring.tags(:api)
+ expect(tags.size).to eq(1)
+ expect(tags[0].text).to eq('public')
+
+ # Check that the param tags are removed
+ tags = object.docstring.tags(:param)
+ expect(tags.size).to eq(2)
+ expect(tags[0].name).to eq('msg')
+ expect(tags[0].text).to eq('A message parameter5.')
+ expect(tags[0].types).to eq(['Variant[Numeric, String[1,2]]'])
+ expect(tags[1].name).to eq('arg1')
+ expect(tags[1].text).to eq('Optional String parameter5. Defaults to \'param\'.')
+ expect(tags[1].types).to eq(['Optional[String[1]]'])
+
+ # Check for default values
+ expect(object.parameters.size).to eq(2)
+ expect(object.parameters[0]).to eq(['msg', nil])
+ expect(object.parameters[1]).to eq(['arg1', 'param'])
+ end
+ end
+
+ describe 'parsing a data type with a summary' do
+ context 'when the summary has fewer than 140 characters' do
+ let(:source) { <<-SOURCE
+# An example Puppet Data Type in Ruby.
+#
+# @summary A short summary.
+Puppet::DataTypes.create_type('RubyDataType') do
+ interface <<-PUPPET
+ attributes => { }
+ PUPPET
+end
+SOURCE
+ }
+
+ it 'should parse the summary' do
+ expect{ subject }.to output('').to_stdout_from_any_process
+ expect(subject.size).to eq(1)
+ summary = subject.first.tags(:summary)
+ expect(summary.first.text).to eq('A short summary.')
+ end
+ end
+
+ context 'when the summary has more than 140 characters' do
+ let(:source) { <<-SOURCE
+# An example Puppet Data Type in Ruby.
+#
+# @summary A short summary that is WAY TOO LONG. AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH this is not what a summary is for! It should be fewer than 140 characters!!
+Puppet::DataTypes.create_type('RubyDataType') do
+ interface <<-PUPPET
+ attributes => { }
+ PUPPET
+end
+SOURCE
+ }
+
+ it 'should log a warning' do
+ expect{ subject }.to output(/\[warn\]: The length of the summary for puppet_data_type 'RubyDataType' exceeds the recommended limit of 140 characters./).to_stdout_from_any_process
+ end
+ end
+ end
+end
diff --git a/spec/unit/puppet-strings/yard/parsers/puppet/parser_spec.rb b/spec/unit/puppet-strings/yard/parsers/puppet/parser_spec.rb
index f0ddb0152..1e83314f9 100644
--- a/spec/unit/puppet-strings/yard/parsers/puppet/parser_spec.rb
+++ b/spec/unit/puppet-strings/yard/parsers/puppet/parser_spec.rb
@@ -206,4 +206,46 @@ class bar {
expect(statement.type).to eq("Struct\[{'a' => Integer[1, 10]}\]")
end
end
+
+ describe 'parsing type alias definitions', if: TEST_PUPPET_DATATYPES do
+ context 'given a type alias on a single line' do
+ let(:source) { <<-SOURCE
+# A simple foo type.
+type Module::Typename = Variant[Stdlib::Windowspath, Stdlib::Unixpath]
+SOURCE
+ }
+
+ it 'should parse the puppet type statement' do
+ subject.parse
+ expect(subject.enumerator.size).to eq(1)
+ statement = subject.enumerator.first
+ expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::DataTypeAliasStatement)
+ expect(statement.docstring).to eq('A simple foo type.')
+ expect(statement.name).to eq('Module::Typename')
+ expect(statement.alias_of).to eq('Variant[Stdlib::Windowspath, Stdlib::Unixpath]')
+ end
+ end
+
+ context 'given a type alias over multiple lines' do
+ let(:source) { <<-SOURCE
+# A multiline foo type
+# with long docs
+type OptionsWithoutName = Struct[{
+ value_type => Optional[ValueType],
+ merge => Optional[MergeType]
+}]
+SOURCE
+ }
+
+ it 'should parse the puppet type statement' do
+ subject.parse
+ expect(subject.enumerator.size).to eq(1)
+ statement = subject.enumerator.first
+ expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::DataTypeAliasStatement)
+ expect(statement.docstring).to eq("A multiline foo type\nwith long docs")
+ expect(statement.name).to eq('OptionsWithoutName')
+ expect(statement.alias_of).to eq("Struct[{\n value_type => Optional[ValueType],\n merge => Optional[MergeType]\n}]")
+ end
+ end
+ end
end