Skip to content
37 changes: 26 additions & 11 deletions lib/puppet-strings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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] :path Write the selected format to a file path
# @option options [Boolean] :markdown From the --format option, is the format Markdown?
# @option options [Boolean] :json Is the format JSON?
# @option options [Array<String>] :yard_args The arguments to pass to yard.
# @return [void]
def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {})
Expand All @@ -27,15 +29,14 @@ def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {})
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]
file = nil
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]
Expand All @@ -46,10 +47,24 @@ def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {})
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(file)
end

# If outputting Markdown, render the output
if options[:markdown]
render_markdown(file)
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.
Expand Down
7 changes: 7 additions & 0 deletions lib/puppet-strings/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ def self.tags_to_hashes(tags)
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
Expand Down
32 changes: 32 additions & 0 deletions lib/puppet-strings/markdown.rb
Original file line number Diff line number Diff line change
@@ -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
154 changes: 154 additions & 0 deletions lib/puppet-strings/markdown/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
require 'puppet-strings'
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
@registry = registry
@tags = registry[:docstring][:tags] || []
end

# generate 1:1 tag methods
# e.g. {:tag_name=>"author", :text=>"eputnam"}
{ :return_val => 'return',
:since => 'since',
:summary => 'summary',
: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

# @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

# @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] @see tag hashes
def see
@tags.select { |tag| tag[:tag_name] == 'see' } unless @tags.select { |tag| tag[:tag_name] == 'see' }[0].nil?
end

# @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] 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] 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?
end

# @return [Hash] information needed for the table of contents
def toc_info
{
name: name.to_s,
link: link,
desc: summary || @registry[:docstring][:text].gsub("\n", ". ")
}
end

# @return [String] makes the component name suitable for a GitHub markdown link
def link
name.delete('::').strip.gsub(' ','-').downcase
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
return "`#{value}`"
else
return value
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)
end
end
end
14 changes: 14 additions & 0 deletions lib/puppet-strings/markdown/puppet_class.rb
Original file line number Diff line number Diff line change
@@ -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
29 changes: 29 additions & 0 deletions lib/puppet-strings/markdown/puppet_classes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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 = in_classes.length > 0 ? "## 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
14 changes: 14 additions & 0 deletions lib/puppet-strings/markdown/puppet_defined_type.rb
Original file line number Diff line number Diff line change
@@ -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
29 changes: 29 additions & 0 deletions lib/puppet-strings/markdown/puppet_defined_types.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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 = in_dtypes.length > 0 ? "## 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
Loading