From 1374b67da0cc89df0949aa84da289d9e10a18c91 Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Mon, 22 Jan 2018 16:22:42 -0800 Subject: [PATCH 01/12] (PDOC-184) generate markdown This change does a few things: 1. Fixes up new api handler to return the stuff we want 2. Adds all the logic to parse YARD registries into markdown 3. Adds templates for markdown 4. Changes Face cli to use a --format option that can be used for either markdown or json --- lib/puppet-strings.rb | 36 +- lib/puppet-strings/markdown.rb | 32 ++ lib/puppet-strings/markdown/base.rb | 84 +++++ lib/puppet-strings/markdown/puppet_class.rb | 14 + lib/puppet-strings/markdown/puppet_classes.rb | 27 ++ .../markdown/puppet_defined_type.rb | 14 + .../markdown/puppet_defined_types.rb | 27 ++ .../markdown/puppet_function.rb | 31 ++ .../markdown/puppet_functions.rb | 28 ++ .../markdown/puppet_resource_type.rb | 26 ++ .../markdown/puppet_resource_types.rb | 27 ++ .../markdown/table_of_contents.rb | 15 + .../markdown/templates/puppet_function.erb | 24 ++ .../markdown/templates/puppet_resource.erb | 45 +++ .../templates/puppet_resource_type.erb | 83 +++++ .../markdown/templates/table_of_contents.erb | 24 ++ lib/puppet-strings/yard/code_objects/type.rb | 4 +- lib/puppet-strings/yard/handlers/ruby/base.rb | 2 +- .../yard/handlers/ruby/rsapi_handler.rb | 6 +- lib/puppet/face/strings.rb | 19 +- spec/acceptance/emit_json_options.rb | 8 +- spec/acceptance/generate_markdown_spec.rb | 49 +++ spec/fixtures/unit/markdown/output.md | 313 ++++++++++++++++++ spec/spec_helper.rb | 2 + .../unit/puppet-strings/markdown/base_spec.rb | 133 ++++++++ spec/unit/puppet-strings/markdown_spec.rb | 213 ++++++++++++ 26 files changed, 1259 insertions(+), 27 deletions(-) create mode 100644 lib/puppet-strings/markdown.rb create mode 100644 lib/puppet-strings/markdown/base.rb create mode 100644 lib/puppet-strings/markdown/puppet_class.rb create mode 100644 lib/puppet-strings/markdown/puppet_classes.rb create mode 100644 lib/puppet-strings/markdown/puppet_defined_type.rb create mode 100644 lib/puppet-strings/markdown/puppet_defined_types.rb create mode 100644 lib/puppet-strings/markdown/puppet_function.rb create mode 100644 lib/puppet-strings/markdown/puppet_functions.rb create mode 100644 lib/puppet-strings/markdown/puppet_resource_type.rb create mode 100644 lib/puppet-strings/markdown/puppet_resource_types.rb create mode 100644 lib/puppet-strings/markdown/table_of_contents.rb create mode 100644 lib/puppet-strings/markdown/templates/puppet_function.erb create mode 100644 lib/puppet-strings/markdown/templates/puppet_resource.erb create mode 100644 lib/puppet-strings/markdown/templates/puppet_resource_type.erb create mode 100644 lib/puppet-strings/markdown/templates/table_of_contents.erb create mode 100644 spec/acceptance/generate_markdown_spec.rb create mode 100644 spec/fixtures/unit/markdown/output.md create mode 100644 spec/unit/puppet-strings/markdown/base_spec.rb create mode 100644 spec/unit/puppet-strings/markdown_spec.rb diff --git a/lib/puppet-strings.rb b/lib/puppet-strings.rb index 410d92b..1e1254d 100644 --- a/lib/puppet-strings.rb +++ b/lib/puppet-strings.rb @@ -14,7 +14,9 @@ module PuppetStrings # @option options [Boolean] :debug Enable YARD debug output. # @option options [Boolean] :backtrace Enable YARD backtraces. # @option options [String] :markup The YARD markup format to use (defaults to 'markdown'). - # @option options [String] :json Enables JSON output to the given file. If the file is nil, STDOUT is used. + # @option options [String] :format Specify output format (markdown or json) + # @option options [String] :path Write the selected format to a file path + # @option options [Boolean] :stdout Use this switch to pipe the selected format to STDOUT # @option options [Array] :yard_args The arguments to pass to yard. # @return [void] def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {}) @@ -27,15 +29,13 @@ module PuppetStrings args << '--backtrace' if options[:backtrace] args << "-m#{options[:markup] || 'markdown'}" - render_as_json = options.key? :json - json_file = nil - if render_as_json - json_file = options[:json] + if options[:json] || options[:markdown] + file = options[:path] # Disable output and prevent stats/progress when writing to STDOUT args << '-n' - args << '-q' unless json_file - args << '--no-stats' unless json_file - args << '--no-progress' unless json_file + args << '-q' unless file + args << '--no-stats' unless file + args << '--no-progress' unless file end yard_args = options[:yard_args] @@ -46,10 +46,24 @@ module PuppetStrings YARD::CLI::Yardoc.run(*args) # If outputting JSON, render the output - if render_as_json - require 'puppet-strings/json' - PuppetStrings::Json.render(json_file) + if options[:json] + render_json(options[:path]) end + + # If outputting Markdown, render the output + if options[:markdown] + render_markdown(options[:path]) + end + end + + def self.render_json(path) + require 'puppet-strings/json' + PuppetStrings::Json.render(path) + end + + def self.render_markdown(path) + require 'puppet-strings/markdown' + PuppetStrings::Markdown.render(path) end # Runs the YARD documentation server. diff --git a/lib/puppet-strings/markdown.rb b/lib/puppet-strings/markdown.rb new file mode 100644 index 0000000..d40d35d --- /dev/null +++ b/lib/puppet-strings/markdown.rb @@ -0,0 +1,32 @@ +require 'puppet-strings/json' + +# module for parsing Yard Registries and generating markdown +module PuppetStrings::Markdown + require_relative 'markdown/puppet_classes' + require_relative 'markdown/puppet_functions' + require_relative 'markdown/puppet_defined_types' + require_relative 'markdown/puppet_resource_types' + require_relative 'markdown/table_of_contents' + + # generates markdown documentation + # @return [String] markdown doc + def self.generate + final = "# Reference\n\n" + final << PuppetStrings::Markdown::TableOfContents.render + final << PuppetStrings::Markdown::PuppetClasses.render + final << PuppetStrings::Markdown::PuppetDefinedTypes.render + final << PuppetStrings::Markdown::PuppetResourceTypes.render + final << PuppetStrings::Markdown::PuppetFunctions.render + + final + end + + def self.render(path = nil) + if path.nil? + puts generate + exit + else + File.open(path, 'w') { |file| file.write(generate) } + end + end +end diff --git a/lib/puppet-strings/markdown/base.rb b/lib/puppet-strings/markdown/base.rb new file mode 100644 index 0000000..528180a --- /dev/null +++ b/lib/puppet-strings/markdown/base.rb @@ -0,0 +1,84 @@ +require 'puppet-strings' +require 'puppet-strings/json' +require 'puppet-strings/yard' + +module PuppetStrings::Markdown + class Base + def initialize(registry, component_type) + @type = component_type + @registry = registry + @tags = registry[:docstring][:tags] || [] + end + + def name + @registry[:name].to_s unless @registry[:name].nil? + end + + def text + @registry[:docstring][:text] unless @registry[:docstring][:text].empty? + end + + def return_val + @tags.select { |tag| tag[:tag_name] == 'return' }[0][:text] unless @tags.select { |tag| tag[:tag_name] == 'return' }[0].nil? + end + + def return_type + @tags.select { |tag| tag[:tag_name] == 'return' }[0][:types][0] unless @tags.select { |tag| tag[:tag_name] == 'return' }[0].nil? + end + + # @return [String] text from @since tag + def since + @tags.select { |tag| tag[:tag_name] == 'since' }[0][:text] unless @tags.select { |tag| tag[:tag_name] == 'since' }[0].nil? + end + + # return [Array] array of @see tag hashes + def see + @tags.select { |tag| tag[:tag_name] == 'see' } unless @tags.select { |tag| tag[:tag_name] == 'see' }[0].nil? + end + + # return [String] text from @summary tag + def summary + @tags.select { |tag| tag[:tag_name] == 'summary' }[0][:text] unless @tags.select { |tag| tag[:tag_name] == 'summary' }[0].nil? + end + + # return [Array] array of parameter tag hashes + def params + @tags.select { |tag| tag[:tag_name] == 'param' } unless @tags.select { |tag| tag[:tag_name] == 'param' }[0].nil? + end + + # return [Array] array of example tag hashes + def examples + @tags.select { |tag| tag[:tag_name] == 'example' } unless @tags.select { |tag| tag[:tag_name] == 'example' }[0].nil? + end + + def toc_info + { + name: name.to_s, + link: link, + desc: summary || @registry[:docstring][:text].gsub("\n", ". ") + } + end + + def link + name.delete('::').strip.gsub(' ','-').downcase + end + + def defaults + @registry[:defaults] unless @registry[:defaults].nil? + end + + def value_string(value) + to_symbol = %w[undef true false] + if to_symbol.include? value + return "`#{value}`" + else + return value + end + end + + def render(template) + file = File.join(File.dirname(__FILE__),"templates/#{template}") + ERB.new(File.read(file), nil, '-').result(binding) + end + end +end diff --git a/lib/puppet-strings/markdown/puppet_class.rb b/lib/puppet-strings/markdown/puppet_class.rb new file mode 100644 index 0000000..7907acb --- /dev/null +++ b/lib/puppet-strings/markdown/puppet_class.rb @@ -0,0 +1,14 @@ +require 'puppet-strings/markdown/base' + +module PuppetStrings::Markdown + class PuppetClass < Base + def initialize(registry) + @template = 'puppet_resource.erb' + super(registry, 'class') + end + + def render + super(@template) + end + end +end diff --git a/lib/puppet-strings/markdown/puppet_classes.rb b/lib/puppet-strings/markdown/puppet_classes.rb new file mode 100644 index 0000000..83237d8 --- /dev/null +++ b/lib/puppet-strings/markdown/puppet_classes.rb @@ -0,0 +1,27 @@ +require_relative 'puppet_class' + +module PuppetStrings::Markdown + module PuppetClasses + def self.in_classes + YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash) + end + + def self.render + final = "## Classes\n\n" + in_classes.each do |klass| + final << PuppetStrings::Markdown::PuppetClass.new(klass).render + end + final + end + + def self.toc_info + final = [] + + in_classes.each do |klass| + final.push(PuppetStrings::Markdown::PuppetClass.new(klass).toc_info) + end + + final + end + end +end diff --git a/lib/puppet-strings/markdown/puppet_defined_type.rb b/lib/puppet-strings/markdown/puppet_defined_type.rb new file mode 100644 index 0000000..052052c --- /dev/null +++ b/lib/puppet-strings/markdown/puppet_defined_type.rb @@ -0,0 +1,14 @@ +require 'puppet-strings/markdown/base' + +module PuppetStrings::Markdown + class PuppetDefinedType < Base + def initialize(registry) + @template = 'puppet_resource.erb' + super(registry, 'defined type') + end + + def render + super(@template) + end + end +end diff --git a/lib/puppet-strings/markdown/puppet_defined_types.rb b/lib/puppet-strings/markdown/puppet_defined_types.rb new file mode 100644 index 0000000..7936871 --- /dev/null +++ b/lib/puppet-strings/markdown/puppet_defined_types.rb @@ -0,0 +1,27 @@ +require_relative 'puppet_defined_type' + +module PuppetStrings::Markdown + module PuppetDefinedTypes + def self.in_dtypes + YARD::Registry.all(:puppet_defined_type).sort_by!(&:name).map!(&:to_hash) + end + + def self.render + final = "## Defined types\n\n" + in_dtypes.each do |type| + final << PuppetStrings::Markdown::PuppetDefinedType.new(type).render + end + final + end + + def self.toc_info + final = [] + + in_dtypes.each do |type| + final.push(PuppetStrings::Markdown::PuppetDefinedType.new(type).toc_info) + end + + final + end + end +end diff --git a/lib/puppet-strings/markdown/puppet_function.rb b/lib/puppet-strings/markdown/puppet_function.rb new file mode 100644 index 0000000..cf39e54 --- /dev/null +++ b/lib/puppet-strings/markdown/puppet_function.rb @@ -0,0 +1,31 @@ +require 'puppet-strings/markdown/base' + +module PuppetStrings::Markdown + class PuppetFunction < Base + attr_reader :signatures + + def initialize(registry) + @template = 'puppet_function.erb' + super(registry, 'function') + @signatures = [] + registry[:signatures].each do |sig| + @signatures.push(Signature.new(sig)) + end + end + + def render + super(@template) + end + end + + class PuppetFunction::Signature < Base + def initialize(registry) + @registry = registry + super(@registry, 'function signature') + end + + def signature + @registry[:signature] + end + end +end diff --git a/lib/puppet-strings/markdown/puppet_functions.rb b/lib/puppet-strings/markdown/puppet_functions.rb new file mode 100644 index 0000000..4f0dbd3 --- /dev/null +++ b/lib/puppet-strings/markdown/puppet_functions.rb @@ -0,0 +1,28 @@ +require_relative 'puppet_function' + +module PuppetStrings::Markdown + module PuppetFunctions + def self.in_functions + YARD::Registry.all(:puppet_function).sort_by!(&:name).map!(&:to_hash) + end + + def self.render + final = "## Functions\n\n" + in_functions.each do |func| + final << PuppetStrings::Markdown::PuppetFunction.new(func).render + end + final + end + + def self.toc_info + final = [] + + in_functions.each do |func| + final.push(PuppetStrings::Markdown::PuppetFunction.new(func).toc_info) + end + + final + end + end +end + diff --git a/lib/puppet-strings/markdown/puppet_resource_type.rb b/lib/puppet-strings/markdown/puppet_resource_type.rb new file mode 100644 index 0000000..bb9cc3d --- /dev/null +++ b/lib/puppet-strings/markdown/puppet_resource_type.rb @@ -0,0 +1,26 @@ +require 'puppet-strings/markdown/base' + +module PuppetStrings::Markdown + class PuppetResourceType < Base + def initialize(registry) + @template = 'puppet_resource_type.erb' + super(registry, 'resource type') + end + + def render + super(@template) + end + + def properties + @registry[:properties] + end + + def parameters + @registry[:parameters] + end + + def regex_in_data_type?(data_type) + data_type.match(/\w+\[\/.*\/\]/).length > 0 + end + end +end diff --git a/lib/puppet-strings/markdown/puppet_resource_types.rb b/lib/puppet-strings/markdown/puppet_resource_types.rb new file mode 100644 index 0000000..faee0cb --- /dev/null +++ b/lib/puppet-strings/markdown/puppet_resource_types.rb @@ -0,0 +1,27 @@ +require_relative 'puppet_resource_type' + +module PuppetStrings::Markdown + module PuppetResourceTypes + def self.in_rtypes + YARD::Registry.all(:puppet_type).sort_by!(&:name).map!(&:to_hash) + end + + def self.render + final = "## Resource types\n\n" + in_rtypes.each do |type| + final << PuppetStrings::Markdown::PuppetResourceType.new(type).render + end + final + end + + def self.toc_info + final = [] + + in_rtypes.each do |type| + final.push(PuppetStrings::Markdown::PuppetResourceType.new(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 new file mode 100644 index 0000000..ec9a660 --- /dev/null +++ b/lib/puppet-strings/markdown/table_of_contents.rb @@ -0,0 +1,15 @@ +require 'puppet-strings/markdown/puppet_classes' + +module PuppetStrings::Markdown + module TableOfContents + def self.render + puppet_classes = PuppetStrings::Markdown::PuppetClasses.toc_info + puppet_defined_types = PuppetStrings::Markdown::PuppetDefinedTypes.toc_info + puppet_resource_types = PuppetStrings::Markdown::PuppetResourceTypes.toc_info + puppet_functions = PuppetStrings::Markdown::PuppetFunctions.toc_info + + template = File.join(File.dirname(__FILE__),"templates/table_of_contents.erb") + ERB.new(File.read(template), nil, '-').result(binding) + end + end +end diff --git a/lib/puppet-strings/markdown/templates/puppet_function.erb b/lib/puppet-strings/markdown/templates/puppet_function.erb new file mode 100644 index 0000000..8be04f5 --- /dev/null +++ b/lib/puppet-strings/markdown/templates/puppet_function.erb @@ -0,0 +1,24 @@ +### <%= name %> + +<% signatures.each do |sig| -%> +#### `<%= sig.signature %>` + +<% if sig.text -%> +<%= sig.text %> + +<% end -%> +<% if sig.return_val -%> +Returns: `<%= sig.return_type %>` <%= sig.return_val %> + +<% end -%> +<% if sig.params -%> +<% sig.params.each do |param| -%> +##### `<%= param[:name] %>` + +Data type: `<%= param[:types][0] %>` + +<%= param[:text] %> + +<% end -%> +<% end -%> +<% end -%> diff --git a/lib/puppet-strings/markdown/templates/puppet_resource.erb b/lib/puppet-strings/markdown/templates/puppet_resource.erb new file mode 100644 index 0000000..f3fe15e --- /dev/null +++ b/lib/puppet-strings/markdown/templates/puppet_resource.erb @@ -0,0 +1,45 @@ +### <%= name %> + +<% if since -%> +* **Since** <%= since %> + +<% end -%> +<% if see -%> +* **See also** +<% see.each do |sa| -%> +<%= sa[:name] %> +<%= sa[:text] %> +<% end -%> + +<% end -%> +<% if examples -%> +#### Examples +<% examples.each do |eg| -%> +##### <%= eg[:name] %> +```puppet +<%= eg[:text] %> +``` + +<% end -%> +<% 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 defaults && defaults[param[:name]] -%> +Default value: <%= value_string(defaults[param[:name]]) %> + +<% end -%> +<% end -%> +<% end -%> + diff --git a/lib/puppet-strings/markdown/templates/puppet_resource_type.erb b/lib/puppet-strings/markdown/templates/puppet_resource_type.erb new file mode 100644 index 0000000..c12b8e8 --- /dev/null +++ b/lib/puppet-strings/markdown/templates/puppet_resource_type.erb @@ -0,0 +1,83 @@ +### <%= name %> + +<% if since -%> +* **Since** <%= since %> + +<% end -%> +<% if see -%> +* **See also** +<% see.each do |sa| -%> +<%= sa[:name] %> +<%= sa[:text] %> +<% end -%> + +<% end -%> +<% if text -%> +<%= text %> +<% end %> +<% if examples -%> +#### Examples +<% examples.each do |eg| -%> +##### <%= eg[:name] %> +```puppet +<%= eg[:text] %> +``` +<% end -%> +<% end -%> +<% if properties %> +#### Properties + +The following properties are available in the `<%= name %>` <%= @type %>. + +<% properties.each do |prop| -%> +##### `<%= prop[:name] %>` + +<% if prop[:values] -%> +Valid values: <%= prop[:values].map { |value| value_string(value) }.join(', ') %> + +<% end -%> +<% if prop[:aliases] -%> +Aliases: <%= prop[:aliases].to_s.delete('{').delete('}') %> + +<% end -%> +<% if prop[:data_type] -%> +Data type: `<%= prop[:data_type] %>` + +<% end -%> +<%= prop[:description] %> + +<% if prop[:default] -%> +Default value: <%= prop[:default] %> + +<% end -%> +<% end -%> +<% end -%> +<% if parameters -%> +#### Parameters + +The following parameters are available in the `<%= name %>` <%= @type %>. + +<% parameters.each do |param| -%> +##### `<%= param[:name] %>` + +<% if param[:values] -%> +Valid values: <%= param[:values].map { |value| value_string(value) }.join(', ') %> + +<% end -%> +<% if param[:isnamevar] -%> +namevar + +<% end -%> +<% if param[:data_type] -%> +Data type: `<%= param[:data_type] %>`<%= "\n_\*this data type contains a regex that may not be accurately reflected in generated documentation_" if regex_in_data_type?(param[:data_type]) %> + +<% end -%> +<%= param[:description] %> + +<% if param[:default] -%> +Default value: <%= value_string(param[:default]) %> + +<% end -%> +<% end -%> +<% end -%> + diff --git a/lib/puppet-strings/markdown/templates/table_of_contents.erb b/lib/puppet-strings/markdown/templates/table_of_contents.erb new file mode 100644 index 0000000..ecf0735 --- /dev/null +++ b/lib/puppet-strings/markdown/templates/table_of_contents.erb @@ -0,0 +1,24 @@ +<% if puppet_classes -%> +## Classes +<% puppet_classes.each do |klassy| -%> +* [`<%= klassy[:name] %>`](#<%= klassy[:link] %>): <%= klassy[:desc] %> +<% end -%> +<% end -%> +<% if puppet_defined_types -%> +## Defined types +<% puppet_defined_types.each do |dtype| -%> +* [`<%= dtype[:name] %>`](#<%= dtype[:link] %>): <%= dtype[:desc] %> +<% end -%> +<% end -%> +<% if puppet_resource_types -%> +## Resource types +<% puppet_resource_types.each do |rtype| -%> +* [`<%= rtype[:name] %>`](#<%= rtype[:link] %>): <%= rtype[:desc] %> +<% end -%> +<% end -%> +<% if puppet_functions -%> +## Functions +<% puppet_functions.each do |func| -%> +* [`<%= func[:name] %>`](#<%= func[:link] %>): <%= func[:desc] %> +<% end -%> +<% end -%> diff --git a/lib/puppet-strings/yard/code_objects/type.rb b/lib/puppet-strings/yard/code_objects/type.rb index fe0a4b6..5190368 100644 --- a/lib/puppet-strings/yard/code_objects/type.rb +++ b/lib/puppet-strings/yard/code_objects/type.rb @@ -22,7 +22,7 @@ class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects: # Represents a resource type parameter. class Parameter attr_reader :name, :values, :aliases - attr_accessor :docstring, :isnamevar, :default + attr_accessor :docstring, :isnamevar, :default, :data_type # Initializes a resource type parameter or property. # @param [String] name The name of the parameter or property. @@ -31,6 +31,7 @@ class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects: @name = name @docstring = docstring || '' @values = [] + @data_type = [] @aliases = {} @isnamevar = false @default = nil @@ -59,6 +60,7 @@ class PuppetStrings::Yard::CodeObjects::Type < PuppetStrings::Yard::CodeObjects: hash[:name] = name hash[:description] = docstring unless docstring.empty? hash[:values] = values unless values.empty? + hash[:data_type] = data_type unless data_type.empty? hash[:aliases] = aliases unless aliases.empty? hash[:isnamevar] = true if isnamevar hash[:default] = default if default diff --git a/lib/puppet-strings/yard/handlers/ruby/base.rb b/lib/puppet-strings/yard/handlers/ruby/base.rb index d2fb041..dfc730f 100644 --- a/lib/puppet-strings/yard/handlers/ruby/base.rb +++ b/lib/puppet-strings/yard/handlers/ruby/base.rb @@ -29,7 +29,7 @@ class PuppetStrings::Yard::Handlers::Ruby::Base < YARD::Handlers::Ruby::Base source = node.source if source =~ HEREDOC_START lines = source.split("\n") - source = lines[1..(lines.last.include?($1) ? -2 : -1)].join("\n") if lines.size > 1 + source = lines[1..(lines.last.include?($1[0..-2]) ? -2 : -1)].join("\n") if lines.size > 1 end source diff --git a/lib/puppet-strings/yard/handlers/ruby/rsapi_handler.rb b/lib/puppet-strings/yard/handlers/ruby/rsapi_handler.rb index de3b02d..80f8989 100644 --- a/lib/puppet-strings/yard/handlers/ruby/rsapi_handler.rb +++ b/lib/puppet-strings/yard/handlers/ruby/rsapi_handler.rb @@ -24,7 +24,7 @@ class PuppetStrings::Yard::Handlers::Ruby::RsapiHandler < PuppetStrings::Yard::H object = PuppetStrings::Yard::CodeObjects::Type.new(schema['name']) register object - docstring = schema['docs'] + docstring = schema['desc'] || "" if docstring register_docstring(object, PuppetStrings::Yard::Util.scrub_string(docstring.to_s), nil) else @@ -49,7 +49,7 @@ class PuppetStrings::Yard::Handlers::Ruby::RsapiHandler < PuppetStrings::Yard::H # check that the params of the register_type call are key/value pairs. def kv_arg_list?(params) - params.type == :list && params.children.count > 0 && params.children.first.type == :list && params.children.first.children.count > 0 && statement.parameters.children.first.children.first.type == :assoc + params.type == :list && params.children.count > 0 && params.children.first.type == :list && params.children.first.children.count > 0 && statement.parameters.children.first.children.first.type == :assoc end def extract_schema @@ -134,7 +134,7 @@ class PuppetStrings::Yard::Handlers::Ruby::RsapiHandler < PuppetStrings::Yard::H end def set_values(definition, object) - object.add(definition['type']) if definition.key? 'type' + object.data_type = definition['type'] if definition.key? 'type' object.default = definition['default'] if definition.key? 'default' object.isnamevar = definition.key?('behaviour') && definition['behaviour'] == 'namevar' end diff --git a/lib/puppet/face/strings.rb b/lib/puppet/face/strings.rb index 06d4ce6..5b5f0a3 100644 --- a/lib/puppet/face/strings.rb +++ b/lib/puppet/face/strings.rb @@ -7,11 +7,11 @@ Puppet::Face.define(:strings, '0.0.1') do action(:generate) do default - option '--emit-json-stdout' do - summary 'Print JSON representation of the documentation to stdout.' + option '--format OUTPUT_FORMAT' do + summary 'Designate output format, JSON or markdown.' end - option '--emit-json FILE' do - summary 'Write JSON representation of the documentation to the given file.' + option '--out PATH' do + summary 'Write selected format to PATH. If no path is designated, strings prints to STDOUT.' end option '--markup FORMAT' do summary "The markup format to use for docstring text (defaults to 'markdown')." @@ -96,9 +96,14 @@ Puppet::Face.define(:strings, '0.0.1') do if options markup = options[:markup] generate_options[:markup] = markup if markup - json_file = options[:emit_json] - generate_options[:json] = json_file if json_file - generate_options[:json] = nil if options[:emit_json_stdout] + generate_options[:path] = options[:out] if options[:out] + generate_options[:stdout] = options[:stdout] + format = options[:format] || "" + if format.casecmp 'markdown' + generate_options[:markdown] = true + elsif format.casecmp 'json' + generate_options[:json] = true + end end generate_options end diff --git a/spec/acceptance/emit_json_options.rb b/spec/acceptance/emit_json_options.rb index 3e64874..79c53e8 100644 --- a/spec/acceptance/emit_json_options.rb +++ b/spec/acceptance/emit_json_options.rb @@ -37,18 +37,18 @@ describe 'Emitting JSON' do ] } - it 'should emit JSON to stdout when using the --emit-json-stdout option' do + it 'should emit JSON to stdout when using --format json and --stdout' do test_module_path = get_test_module_path(master, /Module test/) - on master, puppet('strings', 'generate', '--emit-json-stdout', "#{test_module_path}/lib/puppet/parser/functions/function3x.rb") do + on master, puppet('strings', 'generate', '--format json', "#{test_module_path}/lib/puppet/parser/functions/function3x.rb") do output = stdout.chomp expect(JSON.parse(output)).to eq(expected) end end - it 'should write JSON to a file when using the --emit-json option' do + it 'should write JSON to a file when using --format json and --out' do test_module_path = get_test_module_path(master, /Module test/) tmpfile = master.tmpfile('json_output.json') - on master, puppet('strings', 'generate', "--emit-json #{tmpfile}", "#{test_module_path}/lib/puppet/parser/functions/function3x.rb") + on master, puppet('strings', 'generate', '--format json', "--out #{tmpfile}", "#{test_module_path}/lib/puppet/parser/functions/function3x.rb") output = read_file_on(master, tmpfile) expect(JSON.parse(output)).to eq(expected) end diff --git a/spec/acceptance/generate_markdown_spec.rb b/spec/acceptance/generate_markdown_spec.rb new file mode 100644 index 0000000..5562483 --- /dev/null +++ b/spec/acceptance/generate_markdown_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper_acceptance' +require 'util' + +include PuppetStrings::Acceptance::Util + +describe 'Generating Markdown' do + expected = <<-EOF +# Reference + +## Classes +* [`test`](#test): This class exists to serve as fixture data for testing the puppet strings face + +## Classes + +### test + +#### Examples +```puppet +class { "test": } +``` + +#### Parameters + +##### `package_name` + +The name of the package + +##### `service_name` + +The name of the service + +EOF + + it 'should render Markdown to stdout when using --format markdown and --stdout' do + test_module_path = get_test_module_path(master, /Module test/) + on master, puppet('strings', 'generate', '--format markdown', "#{test_module_path}/manifests/init.pp") do + output = stdout.chomp + expect(JSON.parse(output)).to eq(expected) + end + end + + it 'should write Markdown to a file when using --format markdown and --out' do + test_module_path = get_test_module_path(master, /Module test/) + tmpfile = master.tmpfile('md_output.md') + on master, puppet('strings', 'generate', '--format markdown', "--out #{tmpfile}", "#{test_module_path}/manifests/init.pp") + output = read_file_on(master, tmpfile) + expect(JSON.parse(output)).to eq(expected) + end +end diff --git a/spec/fixtures/unit/markdown/output.md b/spec/fixtures/unit/markdown/output.md new file mode 100644 index 0000000..94a4ee2 --- /dev/null +++ b/spec/fixtures/unit/markdown/output.md @@ -0,0 +1,313 @@ +# Reference + +## Classes +* [`klass`](#klass): A simple class. +## 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 resource type. +## Functions +* [`func`](#func): A simple Puppet function. +* [`func4x`](#func4x): An example 4.x function. +* [`func4x_1`](#func4x_1): An example 4.x function with only one signature. +## Classes + +### klass + +* **Since** 1.0.0 + +* **See also** +www.puppet.com + + +#### Examples +##### This is an 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. + +Default value: `undef` + +##### `param3` + +Data type: `String` + +Third param. + +Default value: 'hi' + + +## Defined types + +### klass::dt + +* **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. + +##### `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` resource 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` resource 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 resource type. + +#### Examples +##### here's an example +```puppet +database { 'foo': + address => 'qux.baz.bar', +} +``` + +#### Properties + +The following properties are available in the `database` resource 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` resource type. + +##### `address` + +namevar + +The database server name. + +##### `encryption_key` + +The encryption key to use. + +##### `encrypt` + +Valid values: `true`, `false`, yes, no + +Whether or not to encrypt the database. + +Default value: `false` + + +## Functions + +### func + +#### `func(Integer $param1, Any $param2, String $param3 = hi)` + +A simple Puppet function. + +Returns: `Undef` Returns nothing. + +##### `param1` + +Data type: `Integer` + +First param. + +##### `param2` + +Data type: `Any` + +Second param. + +##### `param3` + +Data type: `String` + +Third param. + +### func4x + +#### `func4x(Integer $param1, Any $param2, Optional[Array[String]] $param3)` + +An overview for the first overload. + +Returns: `Undef` Returns nothing. + +##### `param1` + +Data type: `Integer` + +The first parameter. + +##### `param2` + +Data type: `Any` + +The second parameter. + +##### `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. + +##### `param` + +Data type: `Boolean` + +The first parameter. + +##### `&block` + +Data type: `Callable` + +The block parameter. + +### func4x_1 + +#### `func4x_1(Integer $param1)` + +An example 4.x function with only one signature. + +Returns: `Undef` Returns nothing. + +##### `param1` + +Data type: `Integer` + +The first parameter. + diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0b616ea..73abc3f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,6 +2,8 @@ require 'mocha' require 'rspec' require 'puppet/version' require 'puppet-strings' +require 'puppet-strings/markdown' +require 'puppet-strings/markdown/base' require 'puppet-strings/yard' # Explicitly set up YARD once diff --git a/spec/unit/puppet-strings/markdown/base_spec.rb b/spec/unit/puppet-strings/markdown/base_spec.rb new file mode 100644 index 0000000..6713f2a --- /dev/null +++ b/spec/unit/puppet-strings/markdown/base_spec.rb @@ -0,0 +1,133 @@ +require 'spec_helper' + +describe PuppetStrings::Markdown::Base do + context 'basic class' do + before :each do + YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) +# An overview +# @summary A simple class. +# @param param1 First param. +# @param param2 Second param. +# @param param3 Third param. +class klass(Integer $param1, $param2, String $param3 = hi) inherits foo::bar { +} +SOURCE + end + + let(:reg) { YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash)[0] } + let(:component) { PuppetStrings::Markdown::Base.new(reg, 'class') } + + describe '#name' do + it 'returns the expected name' do + expect(component.name).to eq 'klass' + end + end + + [ 'examples', + 'see', + 'since', + 'return_val', + 'return_type',].each do |method| + describe "##{method}" do + it 'returns nil' do + expect(component.method(method.to_sym).call).to be_nil + end + end + + end + + describe '#params' do + it 'returns the expected params' do + expect(component.params.size).to eq 3 + end + end + + describe '#summary' do + it 'returns the expected summary' do + expect(component.summary).to eq 'A simple class.' + end + end + + describe '#toc_info' do + let(:toc) { component.toc_info } + it 'returns a hash' do + expect(toc).to be_instance_of Hash + end + it 'prefers the summary for :desc' do + expect(toc[:desc]).to eq 'A simple class.' + end + end + end + context 'less basic class' do + before :each do + YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) +# An overview +# It's a longer overview +# Ya know? +# @example A simple example. +# class { 'klass::yeah': +# param1 => 1, +# } +# @param param1 First param. +# @param param2 Second param. +# @param param3 Third param. +class klass::yeah( + Integer $param1, + $param2, + String $param3 = hi +) inherits foo::bar { + +} +SOURCE + end + + let(:reg) { YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash)[0] } + let(:component) { PuppetStrings::Markdown::Base.new(reg, 'class') } + + describe '#name' do + it 'returns the expected name' do + expect(component.name).to eq 'klass::yeah' + end + end + + ['summary', + 'see', + 'since', + 'return_val', + 'return_type'].each do |method| + describe "##{method}" do + it 'returns nil' do + expect(component.method(method.to_sym).call).to be_nil + end + end + end + + describe '#examples' do + it 'should return one example' do + expect(component.examples.size).to eq 1 + end + end + + describe '#params' do + it 'returns the expected params' do + expect(component.params.size).to eq 3 + end + end + + describe '#toc_info' do + let(:toc) { component.toc_info } + it 'returns a hash' do + expect(toc).to be_instance_of Hash + end + it 'uses overview for :desc in absence of summary' do + expect(toc[:desc]).to eq 'An overview. It\'s a longer overview. Ya know?' + end + end + + describe '#link' do + it 'returns a valid link' do + expect(component.link).to eq 'klassyeah' + end + end + end +end diff --git a/spec/unit/puppet-strings/markdown_spec.rb b/spec/unit/puppet-strings/markdown_spec.rb new file mode 100644 index 0000000..18f5909 --- /dev/null +++ b/spec/unit/puppet-strings/markdown_spec.rb @@ -0,0 +1,213 @@ +require 'spec_helper' +require 'puppet-strings/markdown' +require 'puppet-strings/markdown/puppet_classes' +require 'puppet-strings/markdown/table_of_contents' +require 'tempfile' + +describe PuppetStrings::Markdown do + before :each do + # Populate the YARD registry with both Puppet and Ruby source + YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) +# An overview for a simple class. +# @summary A simple class. +# @since 1.0.0 +# @see www.puppet.com +# @example This is an example +# class { 'klass': +# param1 => 1, +# param3 => 'foo', +# } +# @param param1 First param. +# @param param2 Second param. +# @param param3 Third param. +class klass ( + Integer $param1 = 1, + $param2 = undef, + String $param3 = 'hi' +) inherits foo::bar { +} + +# An overview for a simple defined type. +# @summary A simple defined type. +# @since 1.1.0 +# @see www.puppet.com +# @example Here's an example of this type: +# klass::dt { 'foo': +# param1 => 33, +# param4 => false, +# } +# @return shouldn't return squat +# @param param1 First param. +# @param param2 Second param. +# @param param3 Third param. +# @param param4 Fourth param. +define klass::dt ( + Integer $param1 = 44, + $param2, + String $param3 = 'hi', + Boolean $param4 = true +) { +} +SOURCE + + YARD::Parser::SourceParser.parse_string(<<-SOURCE, :puppet) +# A simple Puppet function. +# @param param1 First param. +# @param param2 Second param. +# @param param3 Third param. +# @return [Undef] Returns nothing. +function func(Integer $param1, $param2, String $param3 = hi) { +} +SOURCE + + YARD::Parser::SourceParser.parse_string(<<-SOURCE, :ruby) +# An example 4.x function. +Puppet::Functions.create_function(:func4x) do + # An overview for the first overload. + # @param param1 The first parameter. + # @param param2 The second parameter. + # @param param3 The third parameter. + # @return Returns nothing. + dispatch :foo do + param 'Integer', :param1 + param 'Any', :param2 + optional_param 'Array[String]', :param3 + return_type 'Undef' + end + + # An overview for the second overload. + # @param param The first parameter. + # @param block The block parameter. + # @return Returns a string. + dispatch :other do + param 'Boolean', :param + block_param + return_type 'String' + end +end + +# An example 4.x function with only one signature. +Puppet::Functions.create_function(:func4x_1) do + # @param param1 The first parameter. + # @return [Undef] Returns nothing. + dispatch :foobarbaz do + param 'Integer', :param1 + end +end + +Puppet::Type.type(:database).provide :linux do + desc 'An example provider on Linux.' + confine kernel: 'Linux' + confine osfamily: 'RedHat' + defaultfor :kernel => 'Linux' + defaultfor :osfamily => 'RedHat', :operatingsystemmajrelease => '7' + has_feature :implements_some_feature + has_feature :some_other_feature + commands foo: '/usr/bin/foo' +end + +Puppet::Type.newtype(:database) do + desc <<-DESC +An example database server resource type. +@example here's an example + database { 'foo': + address => 'qux.baz.bar', + } +DESC + feature :encryption, 'The provider supports encryption.', methods: [:encrypt] + ensurable do + desc 'What state the database should be in.' + defaultvalues + aliasvalue(:up, :present) + aliasvalue(:down, :absent) + defaultto :up + end + + newparam(:address) do + isnamevar + desc 'The database server name.' + end + + newparam(:encryption_key, required_features: :encryption) do + desc 'The encryption key to use.' + end + + newparam(:encrypt, :parent => Puppet::Parameter::Boolean) do + desc 'Whether or not to encrypt the database.' + defaultto false + end + + newproperty(:file) do + desc 'The database file to use.' + end + + newproperty(:log_level) do + desc 'The log level to use.' + newvalue(:debug) + newvalue(:warn) + newvalue(:error) + defaultto 'warn' + end +end + +Puppet::ResourceApi.register_type( + name: 'apt_key', + desc: <<-EOS, +@summary Example resource type using the new API. + +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. +@example here's an example + apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F': + source => 'http://apt.puppetlabs.com/pubkey.gpg' + } + +**Autorequires**: +If Puppet is given the location of a key file which looks like an absolute +path this type will autorequire that file. + EOS + attributes: { + ensure: { + type: 'Enum[present, absent]', + desc: 'Whether this apt key should be present or absent on the target system.' + }, + id: { + 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/]]', + behaviour: :namevar, + desc: 'The ID of the key you want to manage.', + }, + # ... + created: { + type: 'String', + behaviour: :read_only, + desc: 'Date the key was created, in ISO format.', + }, + }, + autorequires: { + file: '$source', # will evaluate to the value of the `source` attribute + package: 'apt', + }, +) +SOURCE + end + + let(:filename) { 'output.md' } + 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) + end + end + end + + describe 'rendering markdown to stdout' do + it 'should output the expected markdown content' do + expect{ PuppetStrings::Markdown.render }.to output(baseline).to_stdout + end + end +end From 7c06ed77c4825f35e6ac8b2ca69da690671ef7e2 Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Wed, 7 Feb 2018 15:12:47 -0800 Subject: [PATCH 02/12] (PDOC-184) block pointless output and re-add options This makes sure the markdown doesn't include section headers that have no content. e.g. '## Classes' does not get put in if there are no classes. Also, we should deprecate --emit-json and --emit-json-stdout instead of just killing them. --- lib/puppet-strings.rb | 5 +++-- lib/puppet-strings/markdown/puppet_classes.rb | 4 +++- .../markdown/puppet_defined_types.rb | 4 +++- lib/puppet-strings/markdown/puppet_functions.rb | 4 +++- .../markdown/puppet_resource_types.rb | 4 +++- .../markdown/templates/table_of_contents.erb | 8 ++++---- lib/puppet/face/strings.rb | 16 ++++++++++++++-- 7 files changed, 33 insertions(+), 12 deletions(-) diff --git a/lib/puppet-strings.rb b/lib/puppet-strings.rb index 1e1254d..75567f9 100644 --- a/lib/puppet-strings.rb +++ b/lib/puppet-strings.rb @@ -29,6 +29,7 @@ module PuppetStrings args << '--backtrace' if options[:backtrace] args << "-m#{options[:markup] || 'markdown'}" + file = nil if options[:json] || options[:markdown] file = options[:path] # Disable output and prevent stats/progress when writing to STDOUT @@ -47,12 +48,12 @@ module PuppetStrings # If outputting JSON, render the output if options[:json] - render_json(options[:path]) + render_json(file) end # If outputting Markdown, render the output if options[:markdown] - render_markdown(options[:path]) + render_markdown(file) end end diff --git a/lib/puppet-strings/markdown/puppet_classes.rb b/lib/puppet-strings/markdown/puppet_classes.rb index 83237d8..0818f9f 100644 --- a/lib/puppet-strings/markdown/puppet_classes.rb +++ b/lib/puppet-strings/markdown/puppet_classes.rb @@ -2,12 +2,14 @@ require_relative 'puppet_class' module PuppetStrings::Markdown module PuppetClasses + + # @return [Array] list of classes def self.in_classes YARD::Registry.all(:puppet_class).sort_by!(&:name).map!(&:to_hash) end def self.render - final = "## Classes\n\n" + final = in_classes.length > 0 ? "## Classes\n\n" : "" in_classes.each do |klass| final << PuppetStrings::Markdown::PuppetClass.new(klass).render end diff --git a/lib/puppet-strings/markdown/puppet_defined_types.rb b/lib/puppet-strings/markdown/puppet_defined_types.rb index 7936871..838fb45 100644 --- a/lib/puppet-strings/markdown/puppet_defined_types.rb +++ b/lib/puppet-strings/markdown/puppet_defined_types.rb @@ -2,12 +2,14 @@ require_relative 'puppet_defined_type' module PuppetStrings::Markdown module PuppetDefinedTypes + + # @return [Array] list of defined types def self.in_dtypes YARD::Registry.all(:puppet_defined_type).sort_by!(&:name).map!(&:to_hash) end def self.render - final = "## Defined types\n\n" + final = in_dtypes.length > 0 ? "## Defined types\n\n" : "" in_dtypes.each do |type| final << PuppetStrings::Markdown::PuppetDefinedType.new(type).render end diff --git a/lib/puppet-strings/markdown/puppet_functions.rb b/lib/puppet-strings/markdown/puppet_functions.rb index 4f0dbd3..5b0e177 100644 --- a/lib/puppet-strings/markdown/puppet_functions.rb +++ b/lib/puppet-strings/markdown/puppet_functions.rb @@ -2,12 +2,14 @@ require_relative 'puppet_function' module PuppetStrings::Markdown module PuppetFunctions + + # @return [Array] list of functions def self.in_functions YARD::Registry.all(:puppet_function).sort_by!(&:name).map!(&:to_hash) end def self.render - final = "## Functions\n\n" + final = in_functions.length > 0 ? "## Functions\n\n" : "" in_functions.each do |func| final << PuppetStrings::Markdown::PuppetFunction.new(func).render end diff --git a/lib/puppet-strings/markdown/puppet_resource_types.rb b/lib/puppet-strings/markdown/puppet_resource_types.rb index faee0cb..e67690e 100644 --- a/lib/puppet-strings/markdown/puppet_resource_types.rb +++ b/lib/puppet-strings/markdown/puppet_resource_types.rb @@ -2,12 +2,14 @@ require_relative 'puppet_resource_type' module PuppetStrings::Markdown module PuppetResourceTypes + + # @return [Array] list of resource types def self.in_rtypes YARD::Registry.all(:puppet_type).sort_by!(&:name).map!(&:to_hash) end def self.render - final = "## Resource types\n\n" + final = in_rtypes.length > 0 ? "## Resource types\n\n" : "" in_rtypes.each do |type| final << PuppetStrings::Markdown::PuppetResourceType.new(type).render end diff --git a/lib/puppet-strings/markdown/templates/table_of_contents.erb b/lib/puppet-strings/markdown/templates/table_of_contents.erb index ecf0735..d726b5e 100644 --- a/lib/puppet-strings/markdown/templates/table_of_contents.erb +++ b/lib/puppet-strings/markdown/templates/table_of_contents.erb @@ -1,22 +1,22 @@ -<% if puppet_classes -%> +<% if puppet_classes.length > 0 -%> ## Classes <% puppet_classes.each do |klassy| -%> * [`<%= klassy[:name] %>`](#<%= klassy[:link] %>): <%= klassy[:desc] %> <% end -%> <% end -%> -<% if puppet_defined_types -%> +<% if puppet_defined_types.length > 0 -%> ## Defined types <% puppet_defined_types.each do |dtype| -%> * [`<%= dtype[:name] %>`](#<%= dtype[:link] %>): <%= dtype[:desc] %> <% end -%> <% end -%> -<% if puppet_resource_types -%> +<% if puppet_resource_types.length > 0 -%> ## Resource types <% puppet_resource_types.each do |rtype| -%> * [`<%= rtype[:name] %>`](#<%= rtype[:link] %>): <%= rtype[:desc] %> <% end -%> <% end -%> -<% if puppet_functions -%> +<% if puppet_functions.length > 0 -%> ## Functions <% puppet_functions.each do |func| -%> * [`<%= func[:name] %>`](#<%= func[:link] %>): <%= func[:desc] %> diff --git a/lib/puppet/face/strings.rb b/lib/puppet/face/strings.rb index 5b5f0a3..d86e895 100644 --- a/lib/puppet/face/strings.rb +++ b/lib/puppet/face/strings.rb @@ -16,6 +16,12 @@ Puppet::Face.define(:strings, '0.0.1') do option '--markup FORMAT' do summary "The markup format to use for docstring text (defaults to 'markdown')." end + option '--emit-json-stdout' do + summary 'DEPRECATED: Print JSON representation of the documentation to stdout.' + end + option '--emit-json PATH' do + summary 'DEPRECATED: Write JSON representation of the documentation to the given file.' + end summary 'Generate documentation from files.' arguments '[[search_pattern] ...]' @@ -94,14 +100,20 @@ Puppet::Face.define(:strings, '0.0.1') do generate_options[:yard_args] = yard_args unless yard_args.empty? if options + if options[:emit_json] + $stderr.puts "WARNING: '--emit-json PATH' is deprecated. Use '--format json --out PATH' instead." + end + if options[:emit_json_stdout] + $stderr.puts "WARNING: '--emit-json-stdout' is deprecated. Use '--format json' instead." + end markup = options[:markup] generate_options[:markup] = markup if markup generate_options[:path] = options[:out] if options[:out] generate_options[:stdout] = options[:stdout] format = options[:format] || "" - if format.casecmp 'markdown' + if format.casecmp('markdown') == 0 generate_options[:markdown] = true - elsif format.casecmp 'json' + elsif format.casecmp('json') == 0 || options[:emit_json] || options[:emit_json_stdout] generate_options[:json] = true end end From 3635fe95f08d24006b475066e297f32d30c1f27e Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Wed, 7 Feb 2018 15:20:30 -0800 Subject: [PATCH 03/12] rubocop sucks --- lib/puppet-strings.rb | 4 ++-- lib/puppet/face/strings.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/puppet-strings.rb b/lib/puppet-strings.rb index 75567f9..1e0bfe7 100644 --- a/lib/puppet-strings.rb +++ b/lib/puppet-strings.rb @@ -14,9 +14,9 @@ module PuppetStrings # @option options [Boolean] :debug Enable YARD debug output. # @option options [Boolean] :backtrace Enable YARD backtraces. # @option options [String] :markup The YARD markup format to use (defaults to 'markdown'). - # @option options [String] :format Specify output format (markdown or json) # @option options [String] :path Write the selected format to a file path - # @option options [Boolean] :stdout Use this switch to pipe the selected format to STDOUT + # @option options [Boolean] :markdown From the --format option, is the format Markdown? + # @option options [Boolean] :json Is the format JSON? # @option options [Array] :yard_args The arguments to pass to yard. # @return [void] def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {}) diff --git a/lib/puppet/face/strings.rb b/lib/puppet/face/strings.rb index d86e895..578b681 100644 --- a/lib/puppet/face/strings.rb +++ b/lib/puppet/face/strings.rb @@ -111,9 +111,9 @@ Puppet::Face.define(:strings, '0.0.1') do generate_options[:path] = options[:out] if options[:out] generate_options[:stdout] = options[:stdout] format = options[:format] || "" - if format.casecmp('markdown') == 0 + if format.casecmp('markdown').zero? generate_options[:markdown] = true - elsif format.casecmp('json') == 0 || options[:emit_json] || options[:emit_json_stdout] + elsif format.casecmp('json').zero? || options[:emit_json] || options[:emit_json_stdout] generate_options[:json] = true end end From 56c24cc36247b61cf1ef32f9b464d014b62258fd Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Thu, 8 Feb 2018 12:12:56 -0800 Subject: [PATCH 04/12] (PDOC-184) implement author tag This implements the author tag. We also claim to support the 'raise' and 'option' tags, but I don't know that we need to. This also consolidates some code in base.rb and adds docs --- lib/puppet-strings/markdown/base.rb | 90 +++++++++++++++---- .../markdown/templates/puppet_resource.erb | 4 + .../templates/puppet_resource_type.erb | 6 +- spec/fixtures/unit/markdown/output.md | 8 ++ spec/unit/puppet-strings/markdown_spec.rb | 18 +++- 5 files changed, 108 insertions(+), 18 deletions(-) diff --git a/lib/puppet-strings/markdown/base.rb b/lib/puppet-strings/markdown/base.rb index 528180a..1da38d1 100644 --- a/lib/puppet-strings/markdown/base.rb +++ b/lib/puppet-strings/markdown/base.rb @@ -3,6 +3,49 @@ require 'puppet-strings/json' require 'puppet-strings/yard' module PuppetStrings::Markdown + # This class makes elements in a YARD::Registry hash easily accessible for templates. + # + # Here's an example hash: + #{:name=>:klass, + # :file=>"(stdin)", + # :line=>16, + # :inherits=>"foo::bar", + # :docstring=> + # {:text=>"An overview for a simple class.", + # :tags=> + # [{:tag_name=>"summary", :text=>"A simple class."}, + # {:tag_name=>"since", :text=>"1.0.0"}, + # {:tag_name=>"see", :name=>"www.puppet.com"}, + # {:tag_name=>"example", + # :text=> + # "class { 'klass':\n" + + # " param1 => 1,\n" + + # " param3 => 'foo',\n" + + # "}", + # :name=>"This is an example"}, + # {:tag_name=>"author", :text=>"eputnam"}, + # {:tag_name=>"option", :name=>"opts"}, + # {:tag_name=>"raise", :text=>"SomeError"}, + # {:tag_name=>"param", + # :text=>"First param.", + # :types=>["Integer"], + # :name=>"param1"}, + # {:tag_name=>"param", + # :text=>"Second param.", + # :types=>["Any"], + # :name=>"param2"}, + # {:tag_name=>"param", + # :text=>"Third param.", + # :types=>["String"], + # :name=>"param3"}]}, + # :defaults=>{"param1"=>"1", "param2"=>"undef", "param3"=>"'hi'"}, + # :source=> + # "class klass (\n" + + # " Integer $param1 = 1,\n" + + # " $param2 = undef,\n" + + # " String $param3 = 'hi'\n" + + # ") inherits foo::bar {\n" + + # "}"} class Base def initialize(registry, component_type) @type = component_type @@ -10,18 +53,30 @@ module PuppetStrings::Markdown @tags = registry[:docstring][:tags] || [] end + # generate 1:1 tag methods + # e.g. {:tag_name=>"author", :text=>"eputnam"} + { :return_val => 'return', + :since => 'since', + :summary => 'summary', + :author => 'author', + :raise => 'raise', + :option => 'option' }.each do |method_name, tag_name| + define_method method_name do + @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0][:text] unless @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0].nil? + end + end + + # @return [String] top-level name def name @registry[:name].to_s unless @registry[:name].nil? end + # @return [String] 'Overview' text (untagged text) def text @registry[:docstring][:text] unless @registry[:docstring][:text].empty? end - def return_val - @tags.select { |tag| tag[:tag_name] == 'return' }[0][:text] unless @tags.select { |tag| tag[:tag_name] == 'return' }[0].nil? - end - + # @return [String] data type of return value def return_type @tags.select { |tag| tag[:tag_name] == 'return' }[0][:types][0] unless @tags.select { |tag| tag[:tag_name] == 'return' }[0].nil? end @@ -31,26 +86,27 @@ module PuppetStrings::Markdown @tags.select { |tag| tag[:tag_name] == 'since' }[0][:text] unless @tags.select { |tag| tag[:tag_name] == 'since' }[0].nil? end - # return [Array] array of @see tag hashes + # @return [Array] @see tag hashes def see @tags.select { |tag| tag[:tag_name] == 'see' } unless @tags.select { |tag| tag[:tag_name] == 'see' }[0].nil? end - # return [String] text from @summary tag - def summary - @tags.select { |tag| tag[:tag_name] == 'summary' }[0][:text] unless @tags.select { |tag| tag[:tag_name] == 'summary' }[0].nil? - end - - # return [Array] array of parameter tag hashes + # @return [Array] parameter tag hashes def params @tags.select { |tag| tag[:tag_name] == 'param' } unless @tags.select { |tag| tag[:tag_name] == 'param' }[0].nil? end - # return [Array] array of example tag hashes + # @return [Array] example tag hashes def examples @tags.select { |tag| tag[:tag_name] == 'example' } unless @tags.select { |tag| tag[:tag_name] == 'example' }[0].nil? end + # @return [Array] any defaults found for the component + def defaults + @registry[:defaults] unless @registry[:defaults].nil? + end + + # @return [Hash] information needed for the table of contents def toc_info { name: name.to_s, @@ -59,14 +115,15 @@ module PuppetStrings::Markdown } end + # @return [String] makes the component name suitable for a GitHub markdown link def link name.delete('::').strip.gsub(' ','-').downcase end - def defaults - @registry[:defaults] unless @registry[:defaults].nil? - end - + # Some return, default, or valid values need to be in backticks. Instead of fu in the handler or code_object, this just does the change on the front. + # @param value + # any string + # @return [String] value or value in backticks if it is in a list def value_string(value) to_symbol = %w[undef true false] if to_symbol.include? value @@ -76,6 +133,7 @@ module PuppetStrings::Markdown end end + # @return [String] full markdown rendering of a component def render(template) file = File.join(File.dirname(__FILE__),"templates/#{template}") ERB.new(File.read(file), nil, '-').result(binding) diff --git a/lib/puppet-strings/markdown/templates/puppet_resource.erb b/lib/puppet-strings/markdown/templates/puppet_resource.erb index f3fe15e..02a57f2 100644 --- a/lib/puppet-strings/markdown/templates/puppet_resource.erb +++ b/lib/puppet-strings/markdown/templates/puppet_resource.erb @@ -9,6 +9,10 @@ <% see.each do |sa| -%> <%= sa[:name] %> <%= sa[:text] %> +<% end -%> +<% if author -%> +* **Author** <%= author %> + <% end -%> <% end -%> diff --git a/lib/puppet-strings/markdown/templates/puppet_resource_type.erb b/lib/puppet-strings/markdown/templates/puppet_resource_type.erb index c12b8e8..38b403f 100644 --- a/lib/puppet-strings/markdown/templates/puppet_resource_type.erb +++ b/lib/puppet-strings/markdown/templates/puppet_resource_type.erb @@ -8,13 +8,17 @@ * **See also** <% see.each do |sa| -%> <%= sa[:name] %> -<%= sa[:text] %> + <%= sa[:text] %> <% end -%> <% end -%> <% if text -%> <%= text %> <% end %> +<% if author -%> +* **Author** <%= author %> + +<% end -%> <% if examples -%> #### Examples <% examples.each do |eg| -%> diff --git a/spec/fixtures/unit/markdown/output.md b/spec/fixtures/unit/markdown/output.md index 94a4ee2..d522036 100644 --- a/spec/fixtures/unit/markdown/output.md +++ b/spec/fixtures/unit/markdown/output.md @@ -20,6 +20,8 @@ * **See also** www.puppet.com +* **Author** eputnam + #### Examples ##### This is an example @@ -69,6 +71,8 @@ Default value: 'hi' * **See also** www.puppet.com +* **Author** eputnam + #### Examples ##### Here's an example of this type: @@ -126,6 +130,8 @@ be manipulated through the `apt-key` command. If Puppet is given the location of a key file which looks like an absolute path this type will autorequire that file. +* **Author** eputnam + #### Examples ##### here's an example ```puppet @@ -168,6 +174,8 @@ The ID of the key you want to manage. An example database server resource type. +* **Author** eputnam + #### Examples ##### here's an example ```puppet diff --git a/spec/unit/puppet-strings/markdown_spec.rb b/spec/unit/puppet-strings/markdown_spec.rb index 18f5909..fcca460 100644 --- a/spec/unit/puppet-strings/markdown_spec.rb +++ b/spec/unit/puppet-strings/markdown_spec.rb @@ -17,6 +17,9 @@ describe PuppetStrings::Markdown do # param1 => 1, # param3 => 'foo', # } +# @author eputnam +# @option opts :foo bar +# @raise SomeError # @param param1 First param. # @param param2 Second param. # @param param3 Third param. @@ -37,6 +40,9 @@ class klass ( # param4 => false, # } # @return shouldn't return squat +# @author eputnam +# @option opts :foo bar +# @raise SomeError # @param param1 First param. # @param param2 Second param. # @param param3 Third param. @@ -55,6 +61,9 @@ SOURCE # @param param1 First param. # @param param2 Second param. # @param param3 Third param. +# @author eputnam +# @option opts :foo bar +# @raise SomeError # @return [Undef] Returns nothing. function func(Integer $param1, $param2, String $param3 = hi) { } @@ -64,6 +73,9 @@ SOURCE # An example 4.x function. Puppet::Functions.create_function(:func4x) do # An overview for the first overload. + # @author eputnam + # @option opts :foo bar + # @raise SomeError # @param param1 The first parameter. # @param param2 The second parameter. # @param param3 The third parameter. @@ -109,6 +121,9 @@ end Puppet::Type.newtype(:database) do desc <<-DESC An example database server resource type. +@author eputnam +@option opts :foo bar +@raise SomeError @example here's an example database { 'foo': address => 'qux.baz.bar', @@ -154,7 +169,8 @@ Puppet::ResourceApi.register_type( name: 'apt_key', desc: <<-EOS, @summary Example resource type using the new API. - +@author eputnam +@raise SomeError 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. From f6cd3ff4a881d6c63f27773e6273453b2a707d62 Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Fri, 9 Feb 2018 15:08:18 -0800 Subject: [PATCH 05/12] (PDOC-184) implemented option and raises tags This implements the two remaining tags and removes the author tag. Had to do some deeper plumbing because options per function signature were not being passed along from YARD --- lib/puppet-strings/json.rb | 7 ++++ lib/puppet-strings/markdown/base.rb | 16 +++++++- .../markdown/puppet_function.rb | 21 ++++++++++ .../markdown/puppet_resource_type.rb | 3 +- .../markdown/templates/puppet_function.erb | 16 ++++++++ .../markdown/templates/puppet_resource.erb | 12 ++++-- .../templates/puppet_resource_type.erb | 32 ++++++++++++--- .../yard/code_objects/function.rb | 6 +-- spec/fixtures/unit/markdown/output.md | 41 +++++++++++++++---- spec/unit/puppet-strings/markdown_spec.rb | 29 +++++++------ 10 files changed, 146 insertions(+), 37 deletions(-) diff --git a/lib/puppet-strings/json.rb b/lib/puppet-strings/json.rb index ae433c1..ff85a7e 100644 --- a/lib/puppet-strings/json.rb +++ b/lib/puppet-strings/json.rb @@ -34,6 +34,13 @@ module PuppetStrings::Json next t.to_hash if t.respond_to?(:to_hash) tag = { tag_name: t.tag_name } + # grab nested information for @option tags + if tag[:tag_name] == 'option' + tag[:opt_name] = t.pair.name + tag[:opt_text] = t.pair.text + tag[:opt_types] = t.pair.types + tag[:parent] = t.name + end tag[:text] = t.text if t.text tag[:types] = t.types if t.types tag[:name] = t.name if t.name diff --git a/lib/puppet-strings/markdown/base.rb b/lib/puppet-strings/markdown/base.rb index 1da38d1..1b16e54 100644 --- a/lib/puppet-strings/markdown/base.rb +++ b/lib/puppet-strings/markdown/base.rb @@ -58,8 +58,6 @@ module PuppetStrings::Markdown { :return_val => 'return', :since => 'since', :summary => 'summary', - :author => 'author', - :raise => 'raise', :option => 'option' }.each do |method_name, tag_name| define_method method_name do @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0][:text] unless @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0].nil? @@ -101,6 +99,20 @@ module PuppetStrings::Markdown @tags.select { |tag| tag[:tag_name] == 'example' } unless @tags.select { |tag| tag[:tag_name] == 'example' }[0].nil? end + # @return [Array] example tag hashes + def raises + @tags.select { |tag| tag[:tag_name] == 'raise' } unless @tags.select { |tag| tag[:tag_name] == 'raise' }[0].nil? + end + + def options + @tags.select { |tag| tag[:tag_name] == 'option' } unless @tags.select { |tag| tag[:tag_name] == 'option' }[0].nil? + end + + def options_for_param(parameter_name) + opts_for_p = options.select { |o| o[:parent] == parameter_name } unless options.nil? + opts_for_p unless opts_for_p.nil? || opts_for_p.length == 0 + end + # @return [Array] any defaults found for the component def defaults @registry[:defaults] unless @registry[:defaults].nil? diff --git a/lib/puppet-strings/markdown/puppet_function.rb b/lib/puppet-strings/markdown/puppet_function.rb index cf39e54..d9024a6 100644 --- a/lib/puppet-strings/markdown/puppet_function.rb +++ b/lib/puppet-strings/markdown/puppet_function.rb @@ -16,6 +16,27 @@ module PuppetStrings::Markdown def render super(@template) end + + def type + t = @registry[:type] + if t =~ /ruby4x/ + "Ruby 4.x API" + elsif t =~ /ruby3/ + "Ruby 3.x API" + elsif t =~ /ruby/ + "Ruby" + else + "Puppet Language" + end + end + + def error_type(r) + "`#{r.split(' ')[0]}`" + end + + def error_text(r) + "#{r.split(' ').drop(1).join(' ')}" + end end class PuppetFunction::Signature < Base diff --git a/lib/puppet-strings/markdown/puppet_resource_type.rb b/lib/puppet-strings/markdown/puppet_resource_type.rb index bb9cc3d..3d24fb3 100644 --- a/lib/puppet-strings/markdown/puppet_resource_type.rb +++ b/lib/puppet-strings/markdown/puppet_resource_type.rb @@ -20,7 +20,8 @@ module PuppetStrings::Markdown end def regex_in_data_type?(data_type) - data_type.match(/\w+\[\/.*\/\]/).length > 0 + m = data_type.match(/\w+\[\/.*\/\]/) + m unless m.nil? || m.length.zero? end end end diff --git a/lib/puppet-strings/markdown/templates/puppet_function.erb b/lib/puppet-strings/markdown/templates/puppet_function.erb index 8be04f5..52ae63c 100644 --- a/lib/puppet-strings/markdown/templates/puppet_function.erb +++ b/lib/puppet-strings/markdown/templates/puppet_function.erb @@ -1,4 +1,5 @@ ### <%= name %> +Type: <%= type %> <% signatures.each do |sig| -%> #### `<%= sig.signature %>` @@ -10,6 +11,13 @@ <% if sig.return_val -%> Returns: `<%= sig.return_type %>` <%= sig.return_val %> +<% end -%> +<% if raises -%> +Raises: +<% raises.each do |r| -%> +* <%= error_type(r[:text]) %> <%= error_text(r[:text]) %> +<% end -%> + <% end -%> <% if sig.params -%> <% sig.params.each do |param| -%> @@ -19,6 +27,14 @@ Data type: `<%= param[:types][0] %>` <%= param[:text] %> +<% if sig.options_for_param(param[:name]) -%> +Options: + +<% sig.options_for_param(param[:name]).each do |o| -%> +* **<%= o[:opt_name] %>** `<%= o[:opt_types][0] %>`: <%= o[:opt_text] %> +<% end -%> + +<% end -%> <% end -%> <% end -%> <% end -%> diff --git a/lib/puppet-strings/markdown/templates/puppet_resource.erb b/lib/puppet-strings/markdown/templates/puppet_resource.erb index 02a57f2..8cf528c 100644 --- a/lib/puppet-strings/markdown/templates/puppet_resource.erb +++ b/lib/puppet-strings/markdown/templates/puppet_resource.erb @@ -9,10 +9,6 @@ <% see.each do |sa| -%> <%= sa[:name] %> <%= sa[:text] %> -<% end -%> -<% if author -%> -* **Author** <%= author %> - <% end -%> <% end -%> @@ -40,6 +36,14 @@ 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]]) %> diff --git a/lib/puppet-strings/markdown/templates/puppet_resource_type.erb b/lib/puppet-strings/markdown/templates/puppet_resource_type.erb index 38b403f..12cff6f 100644 --- a/lib/puppet-strings/markdown/templates/puppet_resource_type.erb +++ b/lib/puppet-strings/markdown/templates/puppet_resource_type.erb @@ -8,17 +8,13 @@ * **See also** <% see.each do |sa| -%> <%= sa[:name] %> - <%= sa[:text] %> +<%= sa[:text] %> <% end -%> <% end -%> <% if text -%> <%= text %> <% end %> -<% if author -%> -* **Author** <%= author %> - -<% end -%> <% if examples -%> #### Examples <% examples.each do |eg| -%> @@ -39,17 +35,29 @@ The following properties are available in the `<%= name %>` <%= @type %>. <% if prop[:values] -%> Valid values: <%= prop[:values].map { |value| value_string(value) }.join(', ') %> +<% end -%> +<% if prop[:isnamevar] -%> +namevar + <% end -%> <% if prop[:aliases] -%> Aliases: <%= prop[:aliases].to_s.delete('{').delete('}') %> <% end -%> <% if prop[:data_type] -%> -Data type: `<%= prop[:data_type] %>` +Data type: `<%= prop[:data_type] %>`<%= "\n_\*this data type contains a regex that may not be accurately reflected in generated documentation_" if regex_in_data_type?(prop[:data_type]) %> <% end -%> <%= prop[:description] %> +<% if options_for_param(prop[:name]) -%> +Options: + +<% options_for_param(prop[:name]).each do |o| -%> +* **<%= o[:opt_name] %>** `<%= o[:opt_types][0] %>`: <%= o[:opt_text] %> +<% end -%> + +<% end -%> <% if prop[:default] -%> Default value: <%= prop[:default] %> @@ -71,6 +79,10 @@ Valid values: <%= param[:values].map { |value| value_string(value) }.join(', ') <% if param[:isnamevar] -%> namevar +<% end -%> +<% if param[:aliases] -%> +Aliases: <%= param[:aliases].to_s.delete('{').delete('}') %> + <% end -%> <% if param[:data_type] -%> Data type: `<%= param[:data_type] %>`<%= "\n_\*this data type contains a regex that may not be accurately reflected in generated documentation_" if regex_in_data_type?(param[:data_type]) %> @@ -78,6 +90,14 @@ Data type: `<%= param[:data_type] %>`<%= "\n_\*this data type contains a regex t <% end -%> <%= param[:description] %> +<% 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 param[:default] -%> Default value: <%= value_string(param[:default]) %> diff --git a/lib/puppet-strings/yard/code_objects/function.rb b/lib/puppet-strings/yard/code_objects/function.rb index 4c2edf2..0ea3a93 100644 --- a/lib/puppet-strings/yard/code_objects/function.rb +++ b/lib/puppet-strings/yard/code_objects/function.rb @@ -84,14 +84,14 @@ class PuppetStrings::Yard::CodeObjects::Function < PuppetStrings::Yard::CodeObje hash[:line] = line hash[:type] = @function_type.to_s hash[:signatures] = [] - + if self.has_tag? :overload # loop over overloads and append onto the signatures array self.tags(:overload).each do |o| - hash[:signatures] << { :signature => o.signature, :docstring => PuppetStrings::Json.docstring_to_hash(o.docstring, [:param, :return]) } + hash[:signatures] << { :signature => o.signature, :docstring => PuppetStrings::Json.docstring_to_hash(o.docstring, [:param, :option, :return]) } end else - hash[:signatures] << { :signature => self.signature, :docstring => PuppetStrings::Json.docstring_to_hash(docstring, [:param, :return]) } + hash[:signatures] << { :signature => self.signature, :docstring => PuppetStrings::Json.docstring_to_hash(docstring, [:param, :option, :return]) } end hash[:docstring] = PuppetStrings::Json.docstring_to_hash(docstring) diff --git a/spec/fixtures/unit/markdown/output.md b/spec/fixtures/unit/markdown/output.md index d522036..b7177d5 100644 --- a/spec/fixtures/unit/markdown/output.md +++ b/spec/fixtures/unit/markdown/output.md @@ -20,8 +20,6 @@ * **See also** www.puppet.com -* **Author** eputnam - #### Examples ##### This is an example @@ -32,6 +30,14 @@ class { 'klass': } ``` +##### This is another example +```puppet +class { 'klass': + param1 => 1, + param3 => 'foo', +} +``` + #### Parameters @@ -51,6 +57,11 @@ Data type: `Any` Second param. +Options: + +* **:opt1** `String`: something about opt1 +* **:opt2** `Hash`: a hash of stuff + Default value: `undef` ##### `param3` @@ -71,8 +82,6 @@ Default value: 'hi' * **See also** www.puppet.com -* **Author** eputnam - #### Examples ##### Here's an example of this type: @@ -102,6 +111,11 @@ Data type: `Any` Second param. +Options: + +* **:opt1** `String`: something about opt1 +* **:opt2** `Hash`: a hash of stuff + ##### `param3` Data type: `String` @@ -130,8 +144,6 @@ be manipulated through the `apt-key` command. If Puppet is given the location of a key file which looks like an absolute path this type will autorequire that file. -* **Author** eputnam - #### Examples ##### here's an example ```puppet @@ -174,8 +186,6 @@ The ID of the key you want to manage. An example database server resource type. -* **Author** eputnam - #### Examples ##### here's an example ```puppet @@ -236,6 +246,7 @@ Default value: `false` ## Functions ### func +Type: Puppet Language #### `func(Integer $param1, Any $param2, String $param3 = hi)` @@ -243,6 +254,9 @@ A simple Puppet function. Returns: `Undef` Returns nothing. +Raises: +* `SomeError` this is some error + ##### `param1` Data type: `Integer` @@ -261,7 +275,12 @@ Data type: `String` Third param. +Options: + +* **:param3opt** `Array`: Something about this option + ### func4x +Type: Ruby 4.x API #### `func4x(Integer $param1, Any $param2, Optional[Array[String]] $param3)` @@ -281,6 +300,11 @@ Data type: `Any` The second parameter. +Options: + +* **:option** `String`: an option +* **:option2** `String`: another option + ##### `param3` Data type: `Optional[Array[String]]` @@ -306,6 +330,7 @@ Data type: `Callable` The block parameter. ### func4x_1 +Type: Ruby 4.x API #### `func4x_1(Integer $param1)` diff --git a/spec/unit/puppet-strings/markdown_spec.rb b/spec/unit/puppet-strings/markdown_spec.rb index fcca460..fed6487 100644 --- a/spec/unit/puppet-strings/markdown_spec.rb +++ b/spec/unit/puppet-strings/markdown_spec.rb @@ -17,12 +17,18 @@ describe PuppetStrings::Markdown do # param1 => 1, # param3 => 'foo', # } -# @author eputnam -# @option opts :foo bar +# @example This is another example +# class { 'klass': +# param1 => 1, +# param3 => 'foo', +# } # @raise SomeError # @param param1 First param. # @param param2 Second param. +# @option param2 [String] :opt1 something about opt1 +# @option param2 [Hash] :opt2 a hash of stuff # @param param3 Third param. +# class klass ( Integer $param1 = 1, $param2 = undef, @@ -40,11 +46,11 @@ class klass ( # param4 => false, # } # @return shouldn't return squat -# @author eputnam -# @option opts :foo bar # @raise SomeError # @param param1 First param. # @param param2 Second param. +# @option param2 [String] :opt1 something about opt1 +# @option param2 [Hash] :opt2 a hash of stuff # @param param3 Third param. # @param param4 Fourth param. define klass::dt ( @@ -61,9 +67,8 @@ SOURCE # @param param1 First param. # @param param2 Second param. # @param param3 Third param. -# @author eputnam -# @option opts :foo bar -# @raise SomeError +# @option param3 [Array] :param3opt Something about this option +# @raise SomeError this is some error # @return [Undef] Returns nothing. function func(Integer $param1, $param2, String $param3 = hi) { } @@ -73,11 +78,11 @@ SOURCE # An example 4.x function. Puppet::Functions.create_function(:func4x) do # An overview for the first overload. - # @author eputnam - # @option opts :foo bar - # @raise SomeError + # @raise SomeError this is some error # @param param1 The first parameter. # @param param2 The second parameter. + # @option param2 [String] :option an option + # @option param2 [String] :option2 another option # @param param3 The third parameter. # @return Returns nothing. dispatch :foo do @@ -121,7 +126,6 @@ end Puppet::Type.newtype(:database) do desc <<-DESC An example database server resource type. -@author eputnam @option opts :foo bar @raise SomeError @example here's an example @@ -169,7 +173,6 @@ Puppet::ResourceApi.register_type( name: 'apt_key', desc: <<-EOS, @summary Example resource type using the new API. -@author eputnam @raise SomeError 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 @@ -214,7 +217,7 @@ SOURCE describe 'rendering markdown to a file' do it 'should output the expected markdown content' do - Tempfile.open('md') do |file| + File.open('/Users/eric.putnam/src/puppet-strings/md.md', 'w') do |file| PuppetStrings::Markdown.render(file.path) expect(File.read(file.path)).to eq(baseline) end From 8a34dc7ea4168e4a1a11560f6e38cdd2e39aa47c Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Fri, 9 Feb 2018 15:22:51 -0800 Subject: [PATCH 06/12] rubocop sucks --- lib/puppet-strings/markdown/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet-strings/markdown/base.rb b/lib/puppet-strings/markdown/base.rb index 1b16e54..936e34b 100644 --- a/lib/puppet-strings/markdown/base.rb +++ b/lib/puppet-strings/markdown/base.rb @@ -110,7 +110,7 @@ module PuppetStrings::Markdown def options_for_param(parameter_name) opts_for_p = options.select { |o| o[:parent] == parameter_name } unless options.nil? - opts_for_p unless opts_for_p.nil? || opts_for_p.length == 0 + opts_for_p unless opts_for_p.nil? || opts_for_p.length.zero? end # @return [Array] any defaults found for the component From 176d6d4d8c2c9b1d46e35780d5085783fc44ad28 Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Mon, 12 Feb 2018 16:11:52 -0800 Subject: [PATCH 07/12] (PDOC-184) refactoring because naming is hard --- lib/puppet-strings/markdown.rb | 12 ++++++------ lib/puppet-strings/markdown/base.rb | 9 ++++++--- .../{puppet_resource_type.rb => custom_type.rb} | 6 +++--- .../{puppet_resource_types.rb => custom_types.rb} | 8 ++++---- .../{puppet_defined_type.rb => defined_type.rb} | 4 ++-- .../{puppet_defined_types.rb => defined_types.rb} | 8 ++++---- .../markdown/{puppet_function.rb => function.rb} | 6 +++--- .../markdown/{puppet_functions.rb => functions.rb} | 8 ++++---- lib/puppet-strings/markdown/puppet_class.rb | 2 +- lib/puppet-strings/markdown/table_of_contents.rb | 8 +++----- .../{puppet_resource.erb => classes_and_defines.erb} | 0 .../{puppet_resource_type.erb => custom_type.erb} | 0 .../templates/{puppet_function.erb => function.erb} | 0 spec/fixtures/unit/markdown/output.md | 12 ++++++------ spec/unit/puppet-strings/markdown_spec.rb | 3 +-- 15 files changed, 43 insertions(+), 43 deletions(-) rename lib/puppet-strings/markdown/{puppet_resource_type.rb => custom_type.rb} (77%) rename lib/puppet-strings/markdown/{puppet_resource_types.rb => custom_types.rb} (65%) rename lib/puppet-strings/markdown/{puppet_defined_type.rb => defined_type.rb} (73%) rename lib/puppet-strings/markdown/{puppet_defined_types.rb => defined_types.rb} (66%) rename lib/puppet-strings/markdown/{puppet_function.rb => function.rb} (88%) rename lib/puppet-strings/markdown/{puppet_functions.rb => functions.rb} (67%) rename lib/puppet-strings/markdown/templates/{puppet_resource.erb => classes_and_defines.erb} (100%) rename lib/puppet-strings/markdown/templates/{puppet_resource_type.erb => custom_type.erb} (100%) rename lib/puppet-strings/markdown/templates/{puppet_function.erb => function.erb} (100%) diff --git a/lib/puppet-strings/markdown.rb b/lib/puppet-strings/markdown.rb index d40d35d..909576f 100644 --- a/lib/puppet-strings/markdown.rb +++ b/lib/puppet-strings/markdown.rb @@ -3,9 +3,9 @@ require 'puppet-strings/json' # module for parsing Yard Registries and generating markdown module PuppetStrings::Markdown require_relative 'markdown/puppet_classes' - require_relative 'markdown/puppet_functions' - require_relative 'markdown/puppet_defined_types' - require_relative 'markdown/puppet_resource_types' + require_relative 'markdown/functions' + require_relative 'markdown/defined_types' + require_relative 'markdown/custom_types' require_relative 'markdown/table_of_contents' # generates markdown documentation @@ -14,9 +14,9 @@ module PuppetStrings::Markdown final = "# Reference\n\n" final << PuppetStrings::Markdown::TableOfContents.render final << PuppetStrings::Markdown::PuppetClasses.render - final << PuppetStrings::Markdown::PuppetDefinedTypes.render - final << PuppetStrings::Markdown::PuppetResourceTypes.render - final << PuppetStrings::Markdown::PuppetFunctions.render + final << PuppetStrings::Markdown::DefinedTypes.render + final << PuppetStrings::Markdown::CustomTypes.render + final << PuppetStrings::Markdown::Functions.render final end diff --git a/lib/puppet-strings/markdown/base.rb b/lib/puppet-strings/markdown/base.rb index 936e34b..55456f2 100644 --- a/lib/puppet-strings/markdown/base.rb +++ b/lib/puppet-strings/markdown/base.rb @@ -57,8 +57,7 @@ module PuppetStrings::Markdown # e.g. {:tag_name=>"author", :text=>"eputnam"} { :return_val => 'return', :since => 'since', - :summary => 'summary', - :option => 'option' }.each do |method_name, tag_name| + :summary => 'summary' }.each do |method_name, tag_name| define_method method_name do @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0][:text] unless @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0].nil? end @@ -99,15 +98,19 @@ module PuppetStrings::Markdown @tags.select { |tag| tag[:tag_name] == 'example' } unless @tags.select { |tag| tag[:tag_name] == 'example' }[0].nil? end - # @return [Array] example tag hashes + # @return [Array] raise tag hashes def raises @tags.select { |tag| tag[:tag_name] == 'raise' } unless @tags.select { |tag| tag[:tag_name] == 'raise' }[0].nil? end + # @return [Array] option tag hashes def options @tags.select { |tag| tag[:tag_name] == 'option' } unless @tags.select { |tag| tag[:tag_name] == 'option' }[0].nil? end + # @param parameter_name + # parameter name to match to option tags + # @return [Array] option tag hashes that have a parent parameter_name def options_for_param(parameter_name) opts_for_p = options.select { |o| o[:parent] == parameter_name } unless options.nil? opts_for_p unless opts_for_p.nil? || opts_for_p.length.zero? diff --git a/lib/puppet-strings/markdown/puppet_resource_type.rb b/lib/puppet-strings/markdown/custom_type.rb similarity index 77% rename from lib/puppet-strings/markdown/puppet_resource_type.rb rename to lib/puppet-strings/markdown/custom_type.rb index 3d24fb3..967bb35 100644 --- a/lib/puppet-strings/markdown/puppet_resource_type.rb +++ b/lib/puppet-strings/markdown/custom_type.rb @@ -1,10 +1,10 @@ require 'puppet-strings/markdown/base' module PuppetStrings::Markdown - class PuppetResourceType < Base + class CustomType < Base def initialize(registry) - @template = 'puppet_resource_type.erb' - super(registry, 'resource type') + @template = 'custom_type.erb' + super(registry, 'type') end def render diff --git a/lib/puppet-strings/markdown/puppet_resource_types.rb b/lib/puppet-strings/markdown/custom_types.rb similarity index 65% rename from lib/puppet-strings/markdown/puppet_resource_types.rb rename to lib/puppet-strings/markdown/custom_types.rb index e67690e..b2c9660 100644 --- a/lib/puppet-strings/markdown/puppet_resource_types.rb +++ b/lib/puppet-strings/markdown/custom_types.rb @@ -1,7 +1,7 @@ -require_relative 'puppet_resource_type' +require_relative 'custom_type' module PuppetStrings::Markdown - module PuppetResourceTypes + module CustomTypes # @return [Array] list of resource types def self.in_rtypes @@ -11,7 +11,7 @@ module PuppetStrings::Markdown def self.render final = in_rtypes.length > 0 ? "## Resource types\n\n" : "" in_rtypes.each do |type| - final << PuppetStrings::Markdown::PuppetResourceType.new(type).render + final << PuppetStrings::Markdown::CustomType.new(type).render end final end @@ -20,7 +20,7 @@ module PuppetStrings::Markdown final = [] in_rtypes.each do |type| - final.push(PuppetStrings::Markdown::PuppetResourceType.new(type).toc_info) + final.push(PuppetStrings::Markdown::CustomType.new(type).toc_info) end final diff --git a/lib/puppet-strings/markdown/puppet_defined_type.rb b/lib/puppet-strings/markdown/defined_type.rb similarity index 73% rename from lib/puppet-strings/markdown/puppet_defined_type.rb rename to lib/puppet-strings/markdown/defined_type.rb index 052052c..86e5c14 100644 --- a/lib/puppet-strings/markdown/puppet_defined_type.rb +++ b/lib/puppet-strings/markdown/defined_type.rb @@ -1,9 +1,9 @@ require 'puppet-strings/markdown/base' module PuppetStrings::Markdown - class PuppetDefinedType < Base + class DefinedType < Base def initialize(registry) - @template = 'puppet_resource.erb' + @template = 'classes_and_defines.erb' super(registry, 'defined type') end diff --git a/lib/puppet-strings/markdown/puppet_defined_types.rb b/lib/puppet-strings/markdown/defined_types.rb similarity index 66% rename from lib/puppet-strings/markdown/puppet_defined_types.rb rename to lib/puppet-strings/markdown/defined_types.rb index 838fb45..e23c6a3 100644 --- a/lib/puppet-strings/markdown/puppet_defined_types.rb +++ b/lib/puppet-strings/markdown/defined_types.rb @@ -1,7 +1,7 @@ -require_relative 'puppet_defined_type' +require_relative 'defined_type' module PuppetStrings::Markdown - module PuppetDefinedTypes + module DefinedTypes # @return [Array] list of defined types def self.in_dtypes @@ -11,7 +11,7 @@ module PuppetStrings::Markdown def self.render final = in_dtypes.length > 0 ? "## Defined types\n\n" : "" in_dtypes.each do |type| - final << PuppetStrings::Markdown::PuppetDefinedType.new(type).render + final << PuppetStrings::Markdown::DefinedType.new(type).render end final end @@ -20,7 +20,7 @@ module PuppetStrings::Markdown final = [] in_dtypes.each do |type| - final.push(PuppetStrings::Markdown::PuppetDefinedType.new(type).toc_info) + final.push(PuppetStrings::Markdown::DefinedType.new(type).toc_info) end final diff --git a/lib/puppet-strings/markdown/puppet_function.rb b/lib/puppet-strings/markdown/function.rb similarity index 88% rename from lib/puppet-strings/markdown/puppet_function.rb rename to lib/puppet-strings/markdown/function.rb index d9024a6..5680d9e 100644 --- a/lib/puppet-strings/markdown/puppet_function.rb +++ b/lib/puppet-strings/markdown/function.rb @@ -1,11 +1,11 @@ require 'puppet-strings/markdown/base' module PuppetStrings::Markdown - class PuppetFunction < Base + class Function < Base attr_reader :signatures def initialize(registry) - @template = 'puppet_function.erb' + @template = 'function.erb' super(registry, 'function') @signatures = [] registry[:signatures].each do |sig| @@ -39,7 +39,7 @@ module PuppetStrings::Markdown end end - class PuppetFunction::Signature < Base + class Function::Signature < Base def initialize(registry) @registry = registry super(@registry, 'function signature') diff --git a/lib/puppet-strings/markdown/puppet_functions.rb b/lib/puppet-strings/markdown/functions.rb similarity index 67% rename from lib/puppet-strings/markdown/puppet_functions.rb rename to lib/puppet-strings/markdown/functions.rb index 5b0e177..1996938 100644 --- a/lib/puppet-strings/markdown/puppet_functions.rb +++ b/lib/puppet-strings/markdown/functions.rb @@ -1,7 +1,7 @@ -require_relative 'puppet_function' +require_relative 'function' module PuppetStrings::Markdown - module PuppetFunctions + module Functions # @return [Array] list of functions def self.in_functions @@ -11,7 +11,7 @@ module PuppetStrings::Markdown def self.render final = in_functions.length > 0 ? "## Functions\n\n" : "" in_functions.each do |func| - final << PuppetStrings::Markdown::PuppetFunction.new(func).render + final << PuppetStrings::Markdown::Function.new(func).render end final end @@ -20,7 +20,7 @@ module PuppetStrings::Markdown final = [] in_functions.each do |func| - final.push(PuppetStrings::Markdown::PuppetFunction.new(func).toc_info) + final.push(PuppetStrings::Markdown::Function.new(func).toc_info) end final diff --git a/lib/puppet-strings/markdown/puppet_class.rb b/lib/puppet-strings/markdown/puppet_class.rb index 7907acb..8bf02be 100644 --- a/lib/puppet-strings/markdown/puppet_class.rb +++ b/lib/puppet-strings/markdown/puppet_class.rb @@ -3,7 +3,7 @@ require 'puppet-strings/markdown/base' module PuppetStrings::Markdown class PuppetClass < Base def initialize(registry) - @template = 'puppet_resource.erb' + @template = 'classes_and_defines.erb' super(registry, 'class') end diff --git a/lib/puppet-strings/markdown/table_of_contents.rb b/lib/puppet-strings/markdown/table_of_contents.rb index ec9a660..16f5726 100644 --- a/lib/puppet-strings/markdown/table_of_contents.rb +++ b/lib/puppet-strings/markdown/table_of_contents.rb @@ -1,12 +1,10 @@ -require 'puppet-strings/markdown/puppet_classes' - module PuppetStrings::Markdown module TableOfContents def self.render puppet_classes = PuppetStrings::Markdown::PuppetClasses.toc_info - puppet_defined_types = PuppetStrings::Markdown::PuppetDefinedTypes.toc_info - puppet_resource_types = PuppetStrings::Markdown::PuppetResourceTypes.toc_info - puppet_functions = PuppetStrings::Markdown::PuppetFunctions.toc_info + puppet_defined_types = PuppetStrings::Markdown::DefinedTypes.toc_info + puppet_resource_types = PuppetStrings::Markdown::CustomTypes.toc_info + puppet_functions = PuppetStrings::Markdown::Functions.toc_info template = File.join(File.dirname(__FILE__),"templates/table_of_contents.erb") ERB.new(File.read(template), nil, '-').result(binding) diff --git a/lib/puppet-strings/markdown/templates/puppet_resource.erb b/lib/puppet-strings/markdown/templates/classes_and_defines.erb similarity index 100% rename from lib/puppet-strings/markdown/templates/puppet_resource.erb rename to lib/puppet-strings/markdown/templates/classes_and_defines.erb diff --git a/lib/puppet-strings/markdown/templates/puppet_resource_type.erb b/lib/puppet-strings/markdown/templates/custom_type.erb similarity index 100% rename from lib/puppet-strings/markdown/templates/puppet_resource_type.erb rename to lib/puppet-strings/markdown/templates/custom_type.erb diff --git a/lib/puppet-strings/markdown/templates/puppet_function.erb b/lib/puppet-strings/markdown/templates/function.erb similarity index 100% rename from lib/puppet-strings/markdown/templates/puppet_function.erb rename to lib/puppet-strings/markdown/templates/function.erb diff --git a/spec/fixtures/unit/markdown/output.md b/spec/fixtures/unit/markdown/output.md index b7177d5..0f8db8c 100644 --- a/spec/fixtures/unit/markdown/output.md +++ b/spec/fixtures/unit/markdown/output.md @@ -6,7 +6,7 @@ * [`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 resource type. +* [`database`](#database): An example database server type. ## Functions * [`func`](#func): A simple Puppet function. * [`func4x`](#func4x): An example 4.x function. @@ -154,7 +154,7 @@ apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F': #### Properties -The following properties are available in the `apt_key` resource type. +The following properties are available in the `apt_key` type. ##### `ensure` @@ -170,7 +170,7 @@ Date the key was created, in ISO format. #### Parameters -The following parameters are available in the `apt_key` resource type. +The following parameters are available in the `apt_key` type. ##### `id` @@ -184,7 +184,7 @@ The ID of the key you want to manage. ### database -An example database server resource type. +An example database server type. #### Examples ##### here's an example @@ -196,7 +196,7 @@ database { 'foo': #### Properties -The following properties are available in the `database` resource type. +The following properties are available in the `database` type. ##### `ensure` @@ -222,7 +222,7 @@ Default value: warn #### Parameters -The following parameters are available in the `database` resource type. +The following parameters are available in the `database` type. ##### `address` diff --git a/spec/unit/puppet-strings/markdown_spec.rb b/spec/unit/puppet-strings/markdown_spec.rb index fed6487..1adb923 100644 --- a/spec/unit/puppet-strings/markdown_spec.rb +++ b/spec/unit/puppet-strings/markdown_spec.rb @@ -1,6 +1,5 @@ require 'spec_helper' require 'puppet-strings/markdown' -require 'puppet-strings/markdown/puppet_classes' require 'puppet-strings/markdown/table_of_contents' require 'tempfile' @@ -125,7 +124,7 @@ end Puppet::Type.newtype(:database) do desc <<-DESC -An example database server resource type. +An example database server type. @option opts :foo bar @raise SomeError @example here's an example From db88cd9857cbf7359f2bf2421b1101156241f9f6 Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Tue, 13 Feb 2018 16:15:08 -0800 Subject: [PATCH 08/12] (PDOC-184) custom_type back to resource_type --- lib/puppet-strings/markdown.rb | 4 ++-- .../markdown/{custom_type.rb => resource_type.rb} | 4 ++-- .../markdown/{custom_types.rb => resource_types.rb} | 8 ++++---- lib/puppet-strings/markdown/table_of_contents.rb | 2 +- .../templates/{custom_type.erb => resource_type.erb} | 0 spec/unit/puppet-strings/markdown_spec.rb | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) rename lib/puppet-strings/markdown/{custom_type.rb => resource_type.rb} (86%) rename lib/puppet-strings/markdown/{custom_types.rb => resource_types.rb} (68%) rename lib/puppet-strings/markdown/templates/{custom_type.erb => resource_type.erb} (100%) diff --git a/lib/puppet-strings/markdown.rb b/lib/puppet-strings/markdown.rb index 909576f..6bc3b61 100644 --- a/lib/puppet-strings/markdown.rb +++ b/lib/puppet-strings/markdown.rb @@ -5,7 +5,7 @@ module PuppetStrings::Markdown require_relative 'markdown/puppet_classes' require_relative 'markdown/functions' require_relative 'markdown/defined_types' - require_relative 'markdown/custom_types' + require_relative 'markdown/resource_types' require_relative 'markdown/table_of_contents' # generates markdown documentation @@ -15,7 +15,7 @@ module PuppetStrings::Markdown final << PuppetStrings::Markdown::TableOfContents.render final << PuppetStrings::Markdown::PuppetClasses.render final << PuppetStrings::Markdown::DefinedTypes.render - final << PuppetStrings::Markdown::CustomTypes.render + final << PuppetStrings::Markdown::ResourceTypes.render final << PuppetStrings::Markdown::Functions.render final diff --git a/lib/puppet-strings/markdown/custom_type.rb b/lib/puppet-strings/markdown/resource_type.rb similarity index 86% rename from lib/puppet-strings/markdown/custom_type.rb rename to lib/puppet-strings/markdown/resource_type.rb index 967bb35..3645c93 100644 --- a/lib/puppet-strings/markdown/custom_type.rb +++ b/lib/puppet-strings/markdown/resource_type.rb @@ -1,9 +1,9 @@ require 'puppet-strings/markdown/base' module PuppetStrings::Markdown - class CustomType < Base + class ResourceType < Base def initialize(registry) - @template = 'custom_type.erb' + @template = 'resource_type.erb' super(registry, 'type') end diff --git a/lib/puppet-strings/markdown/custom_types.rb b/lib/puppet-strings/markdown/resource_types.rb similarity index 68% rename from lib/puppet-strings/markdown/custom_types.rb rename to lib/puppet-strings/markdown/resource_types.rb index b2c9660..214a885 100644 --- a/lib/puppet-strings/markdown/custom_types.rb +++ b/lib/puppet-strings/markdown/resource_types.rb @@ -1,7 +1,7 @@ -require_relative 'custom_type' +require_relative 'resource_type' module PuppetStrings::Markdown - module CustomTypes + module ResourceTypes # @return [Array] list of resource types def self.in_rtypes @@ -11,7 +11,7 @@ module PuppetStrings::Markdown def self.render final = in_rtypes.length > 0 ? "## Resource types\n\n" : "" in_rtypes.each do |type| - final << PuppetStrings::Markdown::CustomType.new(type).render + final << PuppetStrings::Markdown::ResourceType.new(type).render end final end @@ -20,7 +20,7 @@ module PuppetStrings::Markdown final = [] in_rtypes.each do |type| - final.push(PuppetStrings::Markdown::CustomType.new(type).toc_info) + final.push(PuppetStrings::Markdown::ResourceType.new(type).toc_info) end final diff --git a/lib/puppet-strings/markdown/table_of_contents.rb b/lib/puppet-strings/markdown/table_of_contents.rb index 16f5726..3afa119 100644 --- a/lib/puppet-strings/markdown/table_of_contents.rb +++ b/lib/puppet-strings/markdown/table_of_contents.rb @@ -3,7 +3,7 @@ module PuppetStrings::Markdown def self.render puppet_classes = PuppetStrings::Markdown::PuppetClasses.toc_info puppet_defined_types = PuppetStrings::Markdown::DefinedTypes.toc_info - puppet_resource_types = PuppetStrings::Markdown::CustomTypes.toc_info + puppet_resource_types = PuppetStrings::Markdown::ResourceTypes.toc_info puppet_functions = PuppetStrings::Markdown::Functions.toc_info template = File.join(File.dirname(__FILE__),"templates/table_of_contents.erb") diff --git a/lib/puppet-strings/markdown/templates/custom_type.erb b/lib/puppet-strings/markdown/templates/resource_type.erb similarity index 100% rename from lib/puppet-strings/markdown/templates/custom_type.erb rename to lib/puppet-strings/markdown/templates/resource_type.erb diff --git a/spec/unit/puppet-strings/markdown_spec.rb b/spec/unit/puppet-strings/markdown_spec.rb index 1adb923..11cfbf3 100644 --- a/spec/unit/puppet-strings/markdown_spec.rb +++ b/spec/unit/puppet-strings/markdown_spec.rb @@ -216,7 +216,7 @@ SOURCE describe 'rendering markdown to a file' do it 'should output the expected markdown content' do - File.open('/Users/eric.putnam/src/puppet-strings/md.md', 'w') do |file| + Tempfile.open('md') do |file| PuppetStrings::Markdown.render(file.path) expect(File.read(file.path)).to eq(baseline) end From 49573ca97cd587a0dca2e7b31403a82fe062584b Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Fri, 16 Feb 2018 10:20:35 -0800 Subject: [PATCH 09/12] Update README --- README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aeddf16..f186f01 100644 --- a/README.md +++ b/README.md @@ -162,17 +162,33 @@ Strings can produce documentation in JSON and then either generate a `.json` fil To generate JSON documentation to a file, run: ``` -$ puppet strings generate --emit-json documentation.json +$ puppet strings generate --format json --out documentation.json ``` To generate and then print JSON documentation to stdout, run: ``` -$ puppet strings generate --emit-json-stdout +$ puppet strings generate --format json ``` For details about Strings JSON output, see [Strings JSON schema](https://github.com/puppetlabs/puppet-strings/blob/master/JSON.md). +### Output documents in Markdown + +Strings can also produce documentation in Markdown and then either generate an `.md` file or print Markdown to stdout. The generated markdown layout has been reviewed and approved by Puppet's tech pubs team and is the same that is used in Puppet Supported modules. + +To generate Markdown documentation to a file, run: + +``` +$ puppet strings generate --format markdown --out REFERENCE.md +``` + +To generate and then print Markdown documentation to stdout, run: + +``` +$ puppet strings generate --format markdown +``` + ### Output documents to GitHub Pages To generate documents and then make them available on [GitHub Pages](https://pages.github.com/), use the Strings rake task `strings:gh_pages:update`. See [Rake tasks](#rake-tasks) for setup and usage details. @@ -285,6 +301,35 @@ end All provider method calls, including `confine`, `defaultfor`, and `commands`, are automatically parsed and documented by Strings. The `desc` method is used to generate the docstring, and can include tags such as `@example` if written as a heredoc. +Document types that use the new [Resource API](https://github.com/puppetlabs/puppet-resource_api). + +```ruby +Puppet::ResourceApi.register_type( + name: 'database', + docs: 'An example database server resource type.', + attributes: { + ensure: { + type: 'Enum[present, absent, up, down]', + desc: 'What state the database should be in.', + default: 'up', + }, + address: { + type: 'String', + desc: 'The database server name.', + behaviour: :namevar, + }, + encrypt: { + type: 'Boolean', + desc: 'Whether or not to encrypt the database.', + default: false, + behaviour: :parameter, + }, + }, +) +``` + +Here, the `docs` key acts like the `desc` method of the traditional resource type. Everything else is the same, except that now everything is a value in the data structure, not passed to methods. + **Note**: Puppet Strings can not evaluate your Ruby code, so only certain static expressions are supported. ### Documenting functions From 4ea43e03aaf540f9b7890bb940220d02ab9548f8 Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Fri, 16 Feb 2018 10:49:23 -0800 Subject: [PATCH 10/12] re-add test for Puppet 3 function --- lib/puppet-strings/markdown/base.rb | 3 ++- .../markdown/templates/function.erb | 4 ++-- spec/fixtures/unit/markdown/output.md | 22 +++++++++++++++++++ spec/unit/puppet-strings/markdown_spec.rb | 13 +++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/lib/puppet-strings/markdown/base.rb b/lib/puppet-strings/markdown/base.rb index 55456f2..8e9792a 100644 --- a/lib/puppet-strings/markdown/base.rb +++ b/lib/puppet-strings/markdown/base.rb @@ -58,8 +58,9 @@ module PuppetStrings::Markdown { :return_val => 'return', :since => 'since', :summary => 'summary' }.each do |method_name, tag_name| + # @return [String] unless the tag is nil or the string.length == 0 define_method method_name do - @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0][:text] unless @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0].nil? + @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0][:text] unless @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0].nil? || @tags.select { |tag| tag[:tag_name] == "#{tag_name}" }[0][:text].length.zero? end end diff --git a/lib/puppet-strings/markdown/templates/function.erb b/lib/puppet-strings/markdown/templates/function.erb index 52ae63c..40a6ca8 100644 --- a/lib/puppet-strings/markdown/templates/function.erb +++ b/lib/puppet-strings/markdown/templates/function.erb @@ -8,8 +8,8 @@ Type: <%= type %> <%= sig.text %> <% end -%> -<% if sig.return_val -%> -Returns: `<%= sig.return_type %>` <%= sig.return_val %> +<% if sig.return_type -%> +Returns: `<%= sig.return_type %>`<% if sig.return_val %> <%= sig.return_val %><% end %> <% end -%> <% if raises -%> diff --git a/spec/fixtures/unit/markdown/output.md b/spec/fixtures/unit/markdown/output.md index 0f8db8c..005277d 100644 --- a/spec/fixtures/unit/markdown/output.md +++ b/spec/fixtures/unit/markdown/output.md @@ -9,6 +9,7 @@ * [`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. ## Classes @@ -279,6 +280,27 @@ Options: * **:param3opt** `Array`: Something about this option +### func3x +Type: Ruby 3.x API + +#### `func3x(String $param1, Integer $param2)` + +Documentation for an example 3.x function. + +Returns: `Undef` + +##### `param1` + +Data type: `String` + +The first parameter. + +##### `param2` + +Data type: `Integer` + +The second parameter. + ### func4x Type: Ruby 4.x API diff --git a/spec/unit/puppet-strings/markdown_spec.rb b/spec/unit/puppet-strings/markdown_spec.rb index 11cfbf3..6eab938 100644 --- a/spec/unit/puppet-strings/markdown_spec.rb +++ b/spec/unit/puppet-strings/markdown_spec.rb @@ -111,6 +111,19 @@ Puppet::Functions.create_function(:func4x_1) do end end +# An example 3.x function +Puppet::Parser::Functions.newfunction(:func3x, doc: <<-DOC + Documentation for an example 3.x function. + @param param1 [String] The first parameter. + @param param2 [Integer] The second parameter. + @return [Undef] + @example Calling the function. + func3x('hi', 10) + DOC + ) do |*args| + #... +end + Puppet::Type.type(:database).provide :linux do desc 'An example provider on Linux.' confine kernel: 'Linux' From 131697582688364721b22e0f8a4cd34733e8a188 Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Tue, 20 Feb 2018 12:12:46 -0800 Subject: [PATCH 11/12] (PDOC-184) revised cli `puppet generate` behavior remains unchanged `puppet generate --format markdown` now defaults to writing to REFERENCE.md and will accept an override from --out `puppet generate --format json` defaults to printing to stdout but will accept the --out param --- README.md | 16 ++++++++-------- lib/puppet-strings.rb | 6 +++++- lib/puppet-strings/markdown.rb | 3 +++ lib/puppet/face/strings.rb | 14 +++++++++----- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f186f01..958f806 100644 --- a/README.md +++ b/README.md @@ -177,18 +177,18 @@ For details about Strings JSON output, see [Strings JSON schema](https://github. Strings can also produce documentation in Markdown and then either generate an `.md` file or print Markdown to stdout. The generated markdown layout has been reviewed and approved by Puppet's tech pubs team and is the same that is used in Puppet Supported modules. -To generate Markdown documentation to a file, run: - -``` -$ puppet strings generate --format markdown --out REFERENCE.md -``` - -To generate and then print Markdown documentation to stdout, run: +To generate REFERENCE.md: ``` $ puppet strings generate --format markdown ``` +To write Markdown documentation to another file, use the --out option: + +``` +$ puppet strings generate --format markdown --out docs/INFO.md +``` + ### Output documents to GitHub Pages To generate documents and then make them available on [GitHub Pages](https://pages.github.com/), use the Strings rake task `strings:gh_pages:update`. See [Rake tasks](#rake-tasks) for setup and usage details. @@ -301,7 +301,7 @@ end All provider method calls, including `confine`, `defaultfor`, and `commands`, are automatically parsed and documented by Strings. The `desc` method is used to generate the docstring, and can include tags such as `@example` if written as a heredoc. -Document types that use the new [Resource API](https://github.com/puppetlabs/puppet-resource_api). +Document types that use the new [Resource API](https://github.com/puppetlabs/puppet-resource_api): ```ruby Puppet::ResourceApi.register_type( diff --git a/lib/puppet-strings.rb b/lib/puppet-strings.rb index 1e0bfe7..31f6338 100644 --- a/lib/puppet-strings.rb +++ b/lib/puppet-strings.rb @@ -31,7 +31,11 @@ module PuppetStrings file = nil if options[:json] || options[:markdown] - file = options[:path] + file = if options[:json] + options[:path] + elsif options[:markdown] + options[:path] || "REFERENCE.md" + end # Disable output and prevent stats/progress when writing to STDOUT args << '-n' args << '-q' unless file diff --git a/lib/puppet-strings/markdown.rb b/lib/puppet-strings/markdown.rb index 6bc3b61..6370099 100644 --- a/lib/puppet-strings/markdown.rb +++ b/lib/puppet-strings/markdown.rb @@ -21,12 +21,15 @@ module PuppetStrings::Markdown final end + # mimicks the behavior of the json render, although path will never be nil + # @param [String] path path to destination file def self.render(path = nil) if path.nil? puts generate exit else File.open(path, 'w') { |file| file.write(generate) } + YARD::Logger.instance.debug "Wrote markdown to #{path}" end end end diff --git a/lib/puppet/face/strings.rb b/lib/puppet/face/strings.rb index 578b681..da1c458 100644 --- a/lib/puppet/face/strings.rb +++ b/lib/puppet/face/strings.rb @@ -110,11 +110,15 @@ Puppet::Face.define(:strings, '0.0.1') do generate_options[:markup] = markup if markup generate_options[:path] = options[:out] if options[:out] generate_options[:stdout] = options[:stdout] - format = options[:format] || "" - if format.casecmp('markdown').zero? - generate_options[:markdown] = true - elsif format.casecmp('json').zero? || options[:emit_json] || options[:emit_json_stdout] - generate_options[:json] = true + format = options[:format] + if format + if format.casecmp('markdown').zero? + generate_options[:markdown] = true + elsif format.casecmp('json').zero? || options[:emit_json] || options[:emit_json_stdout] + generate_options[:json] = true + else + raise RuntimeError, "Invalid format #{options[:format]}. Please select 'json' or 'markdown'." + end end end generate_options From cc7ffae3a5199851de62065a74ce4ceb38b389ea Mon Sep 17 00:00:00 2001 From: Eric Putnam Date: Tue, 20 Feb 2018 14:49:45 -0800 Subject: [PATCH 12/12] (maint) add new resource api output for json_spec --- spec/fixtures/unit/json/output.json | 43 +++++++++++++++++++++++++++ spec/unit/puppet-strings/json_spec.rb | 40 +++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/spec/fixtures/unit/json/output.json b/spec/fixtures/unit/json/output.json index c6f3c2a..c65bb65 100644 --- a/spec/fixtures/unit/json/output.json +++ b/spec/fixtures/unit/json/output.json @@ -81,6 +81,49 @@ } ], "resource_types": [ + { + "name": "apt_key", + "file": "(stdin)", + "line": 92, + "docstring": { + "text": "This type provides Puppet with the capabilities to manage GPG keys needed\nby apt to perform package validation. Apt has it's own GPG keyring that can\nbe manipulated through the `apt-key` command.\n**Autorequires**:\nIf Puppet is given the location of a key file which looks like an absolute\npath this type will autorequire that file.", + "tags": [ + { + "tag_name": "summary", + "text": "Example resource type using the new API." + }, + { + "tag_name": "raise", + "text": "SomeError" + }, + { + "tag_name": "example", + "text": "apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F':\n source => 'http://apt.puppetlabs.com/pubkey.gpg'\n}", + "name": "here's an example" + } + ] + }, + "properties": [ + { + "name": "ensure", + "description": "Whether this apt key should be present or absent on the target system.", + "data_type": "Enum[present, absent]" + }, + { + "name": "created", + "description": "Date the key was created, in ISO format.", + "data_type": "String" + } + ], + "parameters": [ + { + "name": "id", + "description": "The ID of the key you want to manage.", + "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/]]", + "isnamevar": true + } + ] + }, { "name": "database", "file": "(stdin)", diff --git a/spec/unit/puppet-strings/json_spec.rb b/spec/unit/puppet-strings/json_spec.rb index 60f9cd5..c81adf8 100644 --- a/spec/unit/puppet-strings/json_spec.rb +++ b/spec/unit/puppet-strings/json_spec.rb @@ -123,6 +123,46 @@ Puppet::Type.newtype(:database) do defaultto 'warn' end end + +Puppet::ResourceApi.register_type( + name: 'apt_key', + desc: <<-EOS, +@summary Example resource type using the new API. +@raise SomeError +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. +@example here's an example + apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F': + source => 'http://apt.puppetlabs.com/pubkey.gpg' + } + +**Autorequires**: +If Puppet is given the location of a key file which looks like an absolute +path this type will autorequire that file. + EOS + attributes: { + ensure: { + type: 'Enum[present, absent]', + desc: 'Whether this apt key should be present or absent on the target system.' + }, + id: { + 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/]]', + behaviour: :namevar, + desc: 'The ID of the key you want to manage.', + }, + # ... + created: { + type: 'String', + behaviour: :read_only, + desc: 'Date the key was created, in ISO format.', + }, + }, + autorequires: { + file: '$source', # will evaluate to the value of the `source` attribute + package: 'apt', + }, +) SOURCE end