(PDOC-63) Delete the old implementation.
This commit deletes the old implementation to assist in cleaner code reviews of the upcoming reimplementation. This commit also moves YARD to version 0.9.5 and lays down a bare bones implementation of Puppet Strings that currently does nothing.
This commit is contained in:
parent
56f266db4b
commit
ea9dd0c846
|
@ -2,7 +2,7 @@ AllCops:
|
||||||
Exclude:
|
Exclude:
|
||||||
# Ignore HTML related things
|
# Ignore HTML related things
|
||||||
- '**/*.erb'
|
- '**/*.erb'
|
||||||
- 'lib/puppetx/puppet/strings/yard/templates/**/*'
|
- 'lib/puppet-strings/yard/templates/**/*'
|
||||||
|
|
||||||
Lint/ConditionPosition:
|
Lint/ConditionPosition:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
--exclude lib/puppetx/puppet/strings/yard/templates/
|
--exclude lib/puppet-strings/yard/templates/
|
||||||
--exclude lib/puppetx/puppet/strings/yard/code_objects/host_class_object.rb
|
--no-private
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -4,7 +4,7 @@ gemspec
|
||||||
|
|
||||||
gem 'rgen'
|
gem 'rgen'
|
||||||
gem 'redcarpet'
|
gem 'redcarpet'
|
||||||
gem "yard", "~> 0.8.7"
|
gem 'yard', '~> 0.9.5'
|
||||||
|
|
||||||
puppetversion = ENV['PUPPET_VERSION']
|
puppetversion = ENV['PUPPET_VERSION']
|
||||||
|
|
||||||
|
|
22
README.md
22
README.md
|
@ -68,30 +68,36 @@ $ cd /path/to/module
|
||||||
$ puppet strings
|
$ puppet strings
|
||||||
```
|
```
|
||||||
|
|
||||||
This processes `README` and all puppet and ruby files under `manifests/`
|
This processes `README` and all Puppet and Ruby source files under the `./manifests/`, `./functions/`, and `./lib/`
|
||||||
and `lib/`.
|
directories by default.
|
||||||
|
|
||||||
To document specific files:
|
To document specific files:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ puppet strings some_manifest.pp [another_if_you_feel_like_it.rb]
|
$ puppet strings first.pp second.pp ...
|
||||||
|
```
|
||||||
|
|
||||||
|
To document specific directories:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ puppet strings 'modules/foo/lib/**/*.rb' 'modules/foo/manifests/**/*.pp' 'modules/foo/functions/**/*.pp' ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Strings can also emit the generated documentation as JSON:
|
Strings can also emit the generated documentation as JSON:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ puppet strings yardoc some_manifest.pp --emit-json documentation.json
|
$ puppet strings generate manifest.pp --emit-json documentation.json
|
||||||
```
|
```
|
||||||
|
|
||||||
It can also print the JSON to stdout:
|
It can also print the JSON to stdout:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ puppet strings yardoc some_manifest.pp --emit-json-stdout
|
$ puppet strings generate manifest.pp --emit-json-stdout
|
||||||
```
|
```
|
||||||
|
|
||||||
The schema for the JSON which Strings emits is [well documented](https://github.com/puppetlabs/puppet-strings/blob/master/json_dom.md).
|
The schema for the JSON which Strings emits is [documented here](https://github.com/puppetlabs/puppet-strings/blob/master/json_dom.md).
|
||||||
|
|
||||||
Processing is delegated to the `yardoc` tool so some options listed in `yard help doc` are available. However, Puppet Faces do not support passing arbitrary options through a face so these options must be specified in a `.yardopts` file.
|
Processing is delegated to the `yard` tool so some options listed in `yard help doc` are available. However, Puppet Faces do not support passing arbitrary options through a face so these options must be specified in a `.yardopts` file.
|
||||||
|
|
||||||
In addition to generating a directory full of HTML, you can also serve up documentation for all your modules using the `server` action:
|
In addition to generating a directory full of HTML, you can also serve up documentation for all your modules using the `server` action:
|
||||||
|
|
||||||
|
@ -155,7 +161,7 @@ class example (
|
||||||
### Types and Providers
|
### Types and Providers
|
||||||
Strings will automatically extract the `@doc` provider docstring and any `desc` parameter/property docstrings.
|
Strings will automatically extract the `@doc` provider docstring and any `desc` parameter/property docstrings.
|
||||||
|
|
||||||
Sometimes however, Puppet types use metaprogramming to create parameters and methods automatically. In those cases Strings will not be able to document them automatically (Strings doesn't execute the code that would generate those parameters), so you will need to provide hints on how to document your code. To document a parameter which is automatically created you must use the special directive `@!puppet.type.param` which may take types, the parameter name, and a description.
|
Sometimes however, Puppet types use metaprogramming to create parameters and methods automatically. In those cases Strings will not be able to document them automatically (Strings doesn't execute the code that would generate those parameters), so you will need to provide hints on how to document your code. To document a parameter which is automatically created you must use the special directive `@!puppet.type.param` or `@!puppet.type.property` which may take types, the parameter or property name, and a description.
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
# @!puppet.type.param my_parameter This parameter needs to be explicitly
|
# @!puppet.type.param my_parameter This parameter needs to be explicitly
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
# The root module for Puppet Strings.
|
||||||
|
module PuppetStrings
|
||||||
|
# The glob patterns used to search for files to document.
|
||||||
|
DEFAULT_SEARCH_PATTERNS = %w(
|
||||||
|
manifests/**/*.pp
|
||||||
|
functions/**/*.pp
|
||||||
|
types/**/*.pp
|
||||||
|
lib/**/*.rb
|
||||||
|
).freeze
|
||||||
|
|
||||||
|
# Generates documentation.
|
||||||
|
# @param [Array<String>] search_patterns The search patterns (e.g. manifests/**/*.pp) to look for files.
|
||||||
|
# @param [Hash] options The options hash.
|
||||||
|
# @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 [Array<String>] :yard_args The arguments to pass to yard.
|
||||||
|
# @return [void]
|
||||||
|
def self.generate(search_patterns = DEFAULT_SEARCH_PATTERNS, options = {})
|
||||||
|
# Format the arguments to YARD
|
||||||
|
args = ['doc']
|
||||||
|
args << '--debug' if options[:debug]
|
||||||
|
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]
|
||||||
|
# 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
|
||||||
|
end
|
||||||
|
|
||||||
|
yard_args = options[:yard_args]
|
||||||
|
args += yard_args if yard_args
|
||||||
|
args += search_patterns
|
||||||
|
|
||||||
|
# Run YARD
|
||||||
|
YARD::CLI::Yardoc.run(*args)
|
||||||
|
|
||||||
|
# If outputting JSON, render the output
|
||||||
|
if render_as_json
|
||||||
|
# TODO: implement
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Runs the YARD documentation server.
|
||||||
|
# @param [Array<String>] args The arguments to YARD.
|
||||||
|
def self.run_server(*args)
|
||||||
|
YARD::CLI::Server.run(*args)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,58 +0,0 @@
|
||||||
require 'rake'
|
|
||||||
require 'rake/tasklib'
|
|
||||||
require 'puppet/face'
|
|
||||||
require 'puppet_x/puppet/strings/util'
|
|
||||||
|
|
||||||
namespace :strings do
|
|
||||||
desc 'Generate Puppet documentation with YARD.'
|
|
||||||
task :generate do
|
|
||||||
PuppetX::Puppet::Strings::Util.generate([
|
|
||||||
{emit_json: 'strings.json'}
|
|
||||||
])
|
|
||||||
end
|
|
||||||
|
|
||||||
desc 'Serve YARD documentation for modules.'
|
|
||||||
task :serve do
|
|
||||||
PuppetX::Puppet::Strings::Util.serve
|
|
||||||
end
|
|
||||||
|
|
||||||
namespace :gh_pages do
|
|
||||||
git_uri = `git config --get remote.origin.url`.strip
|
|
||||||
|
|
||||||
desc "Checkout the gh-pages branch for doc generation."
|
|
||||||
task :checkout do
|
|
||||||
if Dir.exist?('doc')
|
|
||||||
fail "The 'doc' directory (#{File.expand_path('doc')}) is not a Git repository! Remove it and run the Rake task again." unless Dir.exist?('doc/.git')
|
|
||||||
Dir.chdir('doc') do
|
|
||||||
system 'git checkout gh-pages'
|
|
||||||
system 'git reset --hard origin/gh-pages'
|
|
||||||
system 'git pull origin gh-pages'
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Dir.mkdir('doc')
|
|
||||||
Dir.chdir('doc') do
|
|
||||||
system 'git init'
|
|
||||||
system "git remote add origin #{git_uri}"
|
|
||||||
system 'git pull'
|
|
||||||
system 'git checkout -b gh-pages'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Push new docs to GitHub."
|
|
||||||
task :push do
|
|
||||||
Dir.chdir('doc') do
|
|
||||||
system 'git add .'
|
|
||||||
system "git commit -m '[strings] Generated Documentation Update'"
|
|
||||||
system 'git push origin gh-pages -f'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Run checkout, generate, and push tasks."
|
|
||||||
task :update => [
|
|
||||||
:checkout,
|
|
||||||
:'strings:generate',
|
|
||||||
:push,
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,88 +0,0 @@
|
||||||
require 'rake'
|
|
||||||
require 'rake/tasklib'
|
|
||||||
require 'puppet_x/puppet/strings/util'
|
|
||||||
|
|
||||||
module PuppetStrings
|
|
||||||
module RakeTasks
|
|
||||||
# A configurable rake task to generate documentation using puppet-strings.
|
|
||||||
#
|
|
||||||
# @attr [String] name the name of the rake task.
|
|
||||||
# @attr [Array<String>] module_resourcefiles globs used to specify which files to document.
|
|
||||||
# Defaults to {PuppetX::Puppet::Strings::Util::MODULE_SOURCEFILES}
|
|
||||||
# @attr [Array<String>] excludes a list of paths or patterns of files and directories to ignore.
|
|
||||||
# @attr [Array<String>, nil] paths list of paths to generate documentation for.
|
|
||||||
# If this value is nil, uses the default paths for puppet strings.
|
|
||||||
# @attr [Hash] options a hash with options passed through to yardoc.
|
|
||||||
class Generate < ::Rake::TaskLib
|
|
||||||
attr_accessor :name
|
|
||||||
attr_accessor :module_resourcefiles
|
|
||||||
attr_accessor :paths
|
|
||||||
attr_accessor :excludes
|
|
||||||
attr_accessor :options
|
|
||||||
|
|
||||||
# Creates a new instance of the Generate Rake task.
|
|
||||||
# Defaults the name to 'strings:generate which overrides
|
|
||||||
# the namespaced generates task. Also default other attributes to
|
|
||||||
# mimic the current default behaviour.
|
|
||||||
def initialize(*args, &task_block)
|
|
||||||
@name = args.shift || 'strings:generate'
|
|
||||||
@module_sourcefiles = PuppetX::Puppet::Strings::Util::MODULE_SOURCEFILES
|
|
||||||
@paths = nil
|
|
||||||
@options = {emit_json: 'strings.json'}
|
|
||||||
@excludes = []
|
|
||||||
define(args, &task_block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates the actual rake task after calling the task_block.
|
|
||||||
#
|
|
||||||
# @param [Array<String>] args arguments passed to the rake task.
|
|
||||||
# @param [Proc] task_block block to configure the task.
|
|
||||||
# @yield [self, args] configure this rake task.
|
|
||||||
def define(args, &task_block)
|
|
||||||
Rake::Task[@name].clear if Rake::Task.task_defined?(@name)
|
|
||||||
yield(*[self, args].slice(0, task_block.arity)) if task_block
|
|
||||||
|
|
||||||
|
|
||||||
desc 'Generate Puppet documentation with YARD.' unless ::Rake.application.last_description
|
|
||||||
task @name do
|
|
||||||
execute_task(generate_task_args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# Converts all attributes and options to an arguments array that can be passed
|
|
||||||
# through to {PuppetX::Puppet::Strings::Util #generate}.
|
|
||||||
#
|
|
||||||
# If paths is not nil, we expand them with the module_sourcefiles patterns.
|
|
||||||
def generate_task_args
|
|
||||||
@paths = [*@paths] unless @paths.nil?
|
|
||||||
@module_sourcefiles = [*@module_sourcefiles]
|
|
||||||
@excludes = [*@excludes]
|
|
||||||
|
|
||||||
exclude_args = @excludes.map {|x| ["--exclude", x]}.flatten
|
|
||||||
pattern_args = @paths.nil? ? [] : expand_paths(@paths, @module_sourcefiles)
|
|
||||||
|
|
||||||
exclude_args + pattern_args + [@options]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Combine each prefix_path with each pattern with '/**/' glue.
|
|
||||||
#
|
|
||||||
# @example
|
|
||||||
# expand_paths(['a','b'], ['*.rb','*.pp'])
|
|
||||||
# => ["a/**/*.rb", "a/**/*.pp", "b/**/*.rb", "b/**/*.pp"]
|
|
||||||
#
|
|
||||||
# @param [Array<String>] prefix_paths an array with paths
|
|
||||||
# @param [Array<String>] patterns an array with patterns.
|
|
||||||
def expand_paths(prefix_paths, patterns)
|
|
||||||
prefix_paths.map {|path| patterns.map {|p| "#{path}/**/#{p}" } }.flatten
|
|
||||||
end
|
|
||||||
|
|
||||||
# call {PuppetX::Puppet::Strings::Util #generate}
|
|
||||||
# @param [Array<String, Hash>] args Arguments. Last element should be a Hash.
|
|
||||||
def execute_task(args)
|
|
||||||
PuppetX::Puppet::Strings::Util.generate(args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,4 +1,5 @@
|
||||||
require 'puppet/application/face_base'
|
require 'puppet/application/face_base'
|
||||||
|
|
||||||
|
# Implements the 'puppet strings' application.
|
||||||
class Puppet::Application::Strings < Puppet::Application::FaceBase
|
class Puppet::Application::Strings < Puppet::Application::FaceBase
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,64 +1,105 @@
|
||||||
require 'puppet/face'
|
require 'puppet/face'
|
||||||
require 'puppet_x/puppet/strings/yard/tags/directives'
|
|
||||||
|
|
||||||
|
# Implements the 'puppet strings' interface.
|
||||||
Puppet::Face.define(:strings, '0.0.1') do
|
Puppet::Face.define(:strings, '0.0.1') do
|
||||||
summary "Generate Puppet documentation with YARD."
|
summary 'Generate Puppet documentation with YARD.'
|
||||||
|
|
||||||
# Ensures that the user has the needed features to use puppet strings
|
action(:generate) do
|
||||||
def check_required_features
|
|
||||||
unless Puppet.features.yard?
|
|
||||||
raise RuntimeError, "The 'yard' gem must be installed in order to use this face."
|
|
||||||
end
|
|
||||||
|
|
||||||
unless Puppet.features.rgen?
|
|
||||||
raise RuntimeError, "The 'rgen' gem must be installed in order to use this face."
|
|
||||||
end
|
|
||||||
|
|
||||||
if RUBY_VERSION.match(/^1\.8/)
|
|
||||||
raise RuntimeError, "This face requires Ruby 1.9 or greater."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
action(:yardoc) do
|
|
||||||
default
|
default
|
||||||
|
|
||||||
option "--emit-json-stdout" do
|
option '--emit-json-stdout' do
|
||||||
summary "Print json representation of the documentation to stdout"
|
summary 'Print JSON representation of the documentation to stdout.'
|
||||||
end
|
end
|
||||||
option "--emit-json FILE" do
|
option '--emit-json FILE' do
|
||||||
summary "Write json representation of the documentation to FILE"
|
summary 'Write JSON representation of the documentation to the given file.'
|
||||||
|
end
|
||||||
|
option '--markup FORMAT' do
|
||||||
|
summary "The markup format to use for docstring text (defaults to 'markdown')."
|
||||||
end
|
end
|
||||||
|
|
||||||
summary "Generate YARD documentation from files."
|
summary 'Generate documentation from files.'
|
||||||
arguments "[manifest_file.pp ...]"
|
arguments '[[search_pattern] ...]'
|
||||||
|
|
||||||
when_invoked do |*args|
|
when_invoked do |*args|
|
||||||
check_required_features
|
check_required_features
|
||||||
require 'puppet_x/puppet/strings/util'
|
require 'puppet-strings'
|
||||||
|
|
||||||
PuppetX::Puppet::Strings::Util.generate(args)
|
PuppetStrings::generate(
|
||||||
|
args.count > 1 ? args[0..-2] : PuppetStrings::DEFAULT_SEARCH_PATTERNS,
|
||||||
# Puppet prints the return value of the action. The return value of this
|
build_generate_options(args.last)
|
||||||
# action is that of the yardoc_actions invocation, which is the boolean
|
)
|
||||||
# "true". This clutters the statistics yard prints, so instead return the
|
nil
|
||||||
# empty string. Note an extra newline will also be printed.
|
|
||||||
""
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# NOTE: Modeled after the `yard gems` command which builds doc indicies
|
|
||||||
# (.yardoc directories) for Ruby Gems. Currently lacks the fine-grained
|
|
||||||
# control over where these indicies are created and just dumps them in the
|
|
||||||
# module roots.
|
|
||||||
|
|
||||||
action(:server) do
|
action(:server) do
|
||||||
summary "Serve YARD documentation for modules."
|
option '--markup FORMAT' do
|
||||||
|
summary "The markup format to use for docstring text (defaults to 'markdown')."
|
||||||
|
end
|
||||||
|
|
||||||
|
summary 'Runs a local documentation server for the modules in the current Puppet environment.'
|
||||||
|
arguments '[[module_name] ...]'
|
||||||
|
|
||||||
when_invoked do |*args|
|
when_invoked do |*args|
|
||||||
check_required_features
|
check_required_features
|
||||||
require 'puppet_x/puppet/strings/util'
|
require 'puppet-strings'
|
||||||
|
|
||||||
PuppetX::Puppet::Strings::Util.serve(args)
|
modules = args.count > 1 ? args[0..-2] : []
|
||||||
|
|
||||||
|
# Generate documentation for all (or the given) modules
|
||||||
|
module_docs = []
|
||||||
|
environment = Puppet.lookup(:current_environment)
|
||||||
|
environment.modules.each do |mod|
|
||||||
|
next unless modules.empty? || modules.include?(mod.name)
|
||||||
|
db = File.join(mod.path, '.yardoc')
|
||||||
|
patterns = PuppetStrings::DEFAULT_SEARCH_PATTERNS.map do |p|
|
||||||
|
File.join(mod.path, p)
|
||||||
|
end
|
||||||
|
puts "Generating documentation for Puppet module '#{mod.name}'."
|
||||||
|
PuppetStrings.generate(patterns, build_generate_options(args.last, '--db', db))
|
||||||
|
|
||||||
|
# Clear the registry so that the next call to generate has a clean database
|
||||||
|
YARD::Registry.clear
|
||||||
|
|
||||||
|
module_docs << mod.name
|
||||||
|
module_docs << db
|
||||||
|
end
|
||||||
|
|
||||||
|
if module_docs.empty?
|
||||||
|
puts 'No Puppet modules were found to serve documentation for.'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
puts 'Starting YARD documentation server.'
|
||||||
|
PuppetStrings::run_server('-m', *module_docs)
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Checks that the required features are installed.
|
||||||
|
# @return [void]
|
||||||
|
def check_required_features
|
||||||
|
raise RuntimeError, "The 'yard' gem must be installed in order to use this face." unless Puppet.features.yard?
|
||||||
|
raise RuntimeError, "The 'rgen' gem must be installed in order to use this face." unless Puppet.features.rgen?
|
||||||
|
raise RuntimeError, 'This face requires Ruby 1.9 or greater.' if RUBY_VERSION.match(/^1\.8/)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Builds the options to PuppetStrings.generate.
|
||||||
|
# @param [Hash] options The Puppet face options hash.
|
||||||
|
# @param [Array] yard_args The additional arguments to pass to YARD.
|
||||||
|
# @return [Hash] Returns the PuppetStrings.generate options hash.
|
||||||
|
def build_generate_options(options = nil, *yard_args)
|
||||||
|
generate_options = {}
|
||||||
|
generate_options[:debug] = Puppet[:debug]
|
||||||
|
generate_options[:backtrace] = Puppet[:trace]
|
||||||
|
generate_options[:yard_args] = yard_args unless yard_args.empty?
|
||||||
|
|
||||||
|
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]
|
||||||
|
end
|
||||||
|
generate_options
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
require 'puppet'
|
|
||||||
require 'puppet/pops'
|
|
||||||
require 'puppet/util/docs'
|
|
||||||
require 'yard'
|
|
||||||
|
|
||||||
module PuppetX
|
|
||||||
end
|
|
||||||
|
|
||||||
# Nothing to see here except forward declarations.
|
|
||||||
module PuppetX::Puppet
|
|
||||||
module Strings
|
|
||||||
# This submodule contains bits that operate on the Pops module produced by
|
|
||||||
# the Future parser.
|
|
||||||
module Pops
|
|
||||||
require 'puppet_x/puppet/strings/pops/yard_statement'
|
|
||||||
require 'puppet_x/puppet/strings/pops/yard_transformer'
|
|
||||||
end
|
|
||||||
|
|
||||||
# This submodule contains bits that interface with the YARD plugin system.
|
|
||||||
module YARD
|
|
||||||
require 'puppet_x/puppet/strings/yard/monkey_patches'
|
|
||||||
require 'puppet_x/puppet/strings/yard/parser'
|
|
||||||
|
|
||||||
module Tags
|
|
||||||
require 'puppet_x/puppet/strings/yard/tags/directives'
|
|
||||||
end
|
|
||||||
|
|
||||||
# This submodule contains code objects which are used to represent relevant
|
|
||||||
# aspects of puppet code in YARD's Registry
|
|
||||||
module CodeObjects
|
|
||||||
require 'puppet_x/puppet/strings/yard/code_objects/puppet_namespace_object'
|
|
||||||
require 'puppet_x/puppet/strings/yard/code_objects/method_object'
|
|
||||||
require 'puppet_x/puppet/strings/yard/code_objects/defined_type_object'
|
|
||||||
require 'puppet_x/puppet/strings/yard/code_objects/host_class_object'
|
|
||||||
require 'puppet_x/puppet/strings/yard/code_objects/type_object'
|
|
||||||
require 'puppet_x/puppet/strings/yard/code_objects/provider_object'
|
|
||||||
end
|
|
||||||
|
|
||||||
# This submodule contains handlers which are used to extract relevant data about
|
|
||||||
# puppet code from the ASTs produced by the Ruby and Puppet parsers
|
|
||||||
module Handlers
|
|
||||||
# This utility library contains some tools for working with Puppet docstrings
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/base'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/defined_type_handler'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/host_class_handler'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/puppet_3x_function_handler'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/puppet_4x_function_handler'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/type_handler'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/provider_handler'
|
|
||||||
end
|
|
||||||
|
|
||||||
::YARD::Parser::SourceParser.register_parser_type(:puppet,
|
|
||||||
PuppetX::Puppet::Strings::YARD::PuppetParser,
|
|
||||||
['pp'])
|
|
||||||
::YARD::Handlers::Processor.register_handler_namespace(:puppet,
|
|
||||||
PuppetX::Puppet::Strings::YARD::Handlers)
|
|
||||||
|
|
||||||
# FIXME: Might not be the best idea to have the template code on the Ruby
|
|
||||||
# LOAD_PATH as the contents of this directory really aren't library code.
|
|
||||||
::YARD::Templates::Engine.register_template_path(
|
|
||||||
File.join(File.dirname(__FILE__), 'strings', 'yard', 'templates'))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,92 +0,0 @@
|
||||||
require 'puppet_x/puppet/strings'
|
|
||||||
|
|
||||||
class PuppetX::Puppet::Strings::Actions
|
|
||||||
|
|
||||||
# Creates a new instance of the Actions class by determining
|
|
||||||
# whether or not debug and backtrace arguments should be sent
|
|
||||||
# to YARD
|
|
||||||
def initialize(puppet_debug, puppet_backtrace)
|
|
||||||
@debug = puppet_debug
|
|
||||||
@backtrace = puppet_backtrace
|
|
||||||
end
|
|
||||||
|
|
||||||
# Holds the name of a module and the file path to its YARD index
|
|
||||||
ModuleIndex = Struct.new(:name, :index_path)
|
|
||||||
|
|
||||||
|
|
||||||
# Maps things like the Puppet `--debug` flag to YARD options.
|
|
||||||
def merge_puppet_args!(yard_args)
|
|
||||||
yard_args.unshift '--debug' if @debug
|
|
||||||
yard_args.unshift '--backtrace' if @backtrace
|
|
||||||
|
|
||||||
yard_args
|
|
||||||
end
|
|
||||||
|
|
||||||
# Builds doc indices (.yardoc directories) for modules.
|
|
||||||
# Currently lacks the fine-grained control over where these
|
|
||||||
# indices are created and just dumps them in the module roots.
|
|
||||||
#
|
|
||||||
# @return [Array<Module>] the modules to be documented
|
|
||||||
#
|
|
||||||
# @param [Array<String>] module_names a list of the module source files
|
|
||||||
# @param [Array<String>] module_sourcefiles default list of module files
|
|
||||||
def index_documentation_for_modules(module_names, module_sourcefiles)
|
|
||||||
# NOTE: The return value of the `module` Face seems to have changed in
|
|
||||||
# 3.6.x. This part of the code will blow up if run under an earlier
|
|
||||||
# version of Puppet.
|
|
||||||
modules = Puppet::Face[:module, :current].list
|
|
||||||
module_list = modules[:modules_by_path].values.flatten
|
|
||||||
|
|
||||||
module_list.select! {|m| module_names.include? m.name} unless module_names.empty?
|
|
||||||
|
|
||||||
# Invoke `yardoc` with -n so that it doesn't generate any HTML output but
|
|
||||||
# does build a `.yardoc` index that other tools can generate output from.
|
|
||||||
yard_args = %w[--no-stats -n] + module_sourcefiles
|
|
||||||
merge_puppet_args!(yard_args)
|
|
||||||
|
|
||||||
module_list.each do |m|
|
|
||||||
Dir.chdir(m.path) do
|
|
||||||
YARD::CLI::Yardoc.run(*yard_args)
|
|
||||||
|
|
||||||
# Clear the global Registry so that objects from one module don't
|
|
||||||
# bleed into the next.
|
|
||||||
YARD::Registry.clear
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Extracts the needed information of the modules we're documenting
|
|
||||||
#
|
|
||||||
# @return [Array<ModuleIndex>] An array of representation of the modules
|
|
||||||
# to produce documentation for. Each ModuleIndex contains the module name
|
|
||||||
# and the path to its YARD index
|
|
||||||
#
|
|
||||||
# @param [Array<String>] module_list a list of the module source files
|
|
||||||
def generate_module_tuples(module_list)
|
|
||||||
module_list.map do |mod|
|
|
||||||
name = (mod.forge_name || mod.name).gsub('/', '-')
|
|
||||||
yard_index = File.join(mod.path, '.yardoc')
|
|
||||||
|
|
||||||
ModuleIndex.new(name, yard_index)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Hands off the needed information to YARD so it may
|
|
||||||
# serve the documentation
|
|
||||||
#
|
|
||||||
# @param [Array<String>] yard_args a list of all the arguments to pass to YARD
|
|
||||||
def serve_documentation(*yard_args)
|
|
||||||
merge_puppet_args!(yard_args)
|
|
||||||
YARD::CLI::Server.run(*yard_args)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Hands off the needed information to YARD so it may
|
|
||||||
# generate the documentation
|
|
||||||
#
|
|
||||||
# @param [Array<String>] yard_args a list of all the arguments to pass to YARD
|
|
||||||
def generate_documentation(*yard_args)
|
|
||||||
merge_puppet_args!(yard_args)
|
|
||||||
YARD::CLI::Yardoc.run(*yard_args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
require 'ostruct'
|
|
||||||
|
|
||||||
# An adapter class that conforms a Pops model instance + adapters to the
|
|
||||||
# interface expected by YARD handlers.
|
|
||||||
#
|
|
||||||
# FIXME: Inhertiting from OpenStruct is a bit of a hack. It allows attributes
|
|
||||||
# to be declared as needed but in the long run understandibility of the code
|
|
||||||
# would be improved by having a concrete model.
|
|
||||||
class PuppetX::Puppet::Strings::Pops::YARDStatement < OpenStruct
|
|
||||||
attr_reader :pops_obj, :comments
|
|
||||||
|
|
||||||
def initialize(pops_obj)
|
|
||||||
# Initialize OpenStruct
|
|
||||||
super({})
|
|
||||||
|
|
||||||
unless pops_obj.is_a? Puppet::Pops::Model::PopsObject
|
|
||||||
raise ArgumentError, "A YARDStatement can only be initialized from a PopsObject. Got a: #{pops_obj.class}"
|
|
||||||
end
|
|
||||||
|
|
||||||
@pops_obj = pops_obj
|
|
||||||
@pos_adapter = Puppet::Pops::Adapters::SourcePosAdapter.adapt(@pops_obj)
|
|
||||||
# FIXME: Perhaps this should be a seperate adapter?
|
|
||||||
@comments = extract_comments
|
|
||||||
end
|
|
||||||
|
|
||||||
def type
|
|
||||||
pops_obj.class
|
|
||||||
end
|
|
||||||
|
|
||||||
def line
|
|
||||||
@line ||= @pos_adapter.line
|
|
||||||
end
|
|
||||||
|
|
||||||
def source
|
|
||||||
@source ||= @pos_adapter.extract_text
|
|
||||||
end
|
|
||||||
|
|
||||||
# FIXME: I don't know quite what these are supposed to do, but they show up
|
|
||||||
# quite often in the YARD handler code. Figure out whether they are
|
|
||||||
# necessary.
|
|
||||||
alias_method :show, :source
|
|
||||||
def comments_hash_flag; nil end
|
|
||||||
def comments_range; nil end
|
|
||||||
|
|
||||||
private
|
|
||||||
# TODO: This stuff should probably be part of a separate class/adapter.
|
|
||||||
COMMENT_PATTERN = /^\s*#.*\n/
|
|
||||||
|
|
||||||
def extract_comments
|
|
||||||
comments = []
|
|
||||||
program = pops_obj.eAllContainers.find {|c| c.is_a?(Puppet::Pops::Model::Program) }
|
|
||||||
# FIXME: Horribly inefficient. Multiple copies. Generator pattern would
|
|
||||||
# be much better.
|
|
||||||
source_text = program.source_text.lines.to_a
|
|
||||||
|
|
||||||
source_text.slice(0, line-1).reverse.each do |line|
|
|
||||||
if COMMENT_PATTERN.match(line)
|
|
||||||
# FIXME: The gsub trims comments, but is extremely optimistic: It
|
|
||||||
# assumes only one space separates the comment body from the
|
|
||||||
# comment character.
|
|
||||||
# NOTE: We cannot just trim any amount of whitespace as indentation
|
|
||||||
# is sometimes significant in markdown. We would need a real parser.
|
|
||||||
|
|
||||||
# Comments which begin with some whitespace, a hash and then some
|
|
||||||
# tabs and spaces should be scrubbed. Comments which just have a
|
|
||||||
# solitary hash then a newline should keep that newline since newlines
|
|
||||||
# are significant in markdown.
|
|
||||||
comments.unshift line.gsub(/^\s*#[\t ]/, '').gsub(/^\s*#\n/, "\n")
|
|
||||||
else
|
|
||||||
# No comment found on this line. We must be done piecing together a
|
|
||||||
# comment block.
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Stick everything back together.
|
|
||||||
comments.join
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,47 +0,0 @@
|
||||||
# Loosely based on the TreeDumper classes in Pops::Model. The responsibility of
|
|
||||||
# this class is to walk a Pops::Model and output objects that can be consumed
|
|
||||||
# by YARD handlers.
|
|
||||||
#
|
|
||||||
# @note Currently, this class only extracts node, host class and type
|
|
||||||
# definitions.
|
|
||||||
class PuppetX::Puppet::Strings::Pops::YARDTransformer
|
|
||||||
def initialize
|
|
||||||
@transform_visitor = Puppet::Pops::Visitor.new(self, 'transform')
|
|
||||||
end
|
|
||||||
|
|
||||||
def transform(o)
|
|
||||||
@transform_visitor.visit(o)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def transform_Factory(o)
|
|
||||||
transform(o.current)
|
|
||||||
end
|
|
||||||
|
|
||||||
def transform_Program(o)
|
|
||||||
o.definitions.map{|d| transform(d)}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Extract comments from type definitions and class definitions. Wrap them
|
|
||||||
# into YARDStatement objects that provide an interface for YARD handlers.
|
|
||||||
def transform_NamedDefinition(o)
|
|
||||||
obj = PuppetX::Puppet::Strings::Pops::YARDStatement.new(o)
|
|
||||||
obj.parameters = o.parameters.map do |p|
|
|
||||||
param_tuple = [transform(p)]
|
|
||||||
param_tuple << ( p.value.nil? ? nil : transform(p.value) )
|
|
||||||
end
|
|
||||||
|
|
||||||
obj
|
|
||||||
end
|
|
||||||
|
|
||||||
# Catch-all visitor.
|
|
||||||
def transform_Positioned(o)
|
|
||||||
PuppetX::Puppet::Strings::Pops::YARDStatement.new(o)
|
|
||||||
end
|
|
||||||
|
|
||||||
# nil in... nil out!
|
|
||||||
def transform_NilClass(o)
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,65 +0,0 @@
|
||||||
require 'puppet_x/puppet/strings/actions'
|
|
||||||
|
|
||||||
module PuppetX::Puppet::Strings::Util
|
|
||||||
MODULE_SOURCEFILES = ['manifests/**/*.pp', 'lib/**/*.rb']
|
|
||||||
|
|
||||||
def self.generate(args = [])
|
|
||||||
yardoc_actions = PuppetX::Puppet::Strings::Actions.new(Puppet[:debug], Puppet[:trace])
|
|
||||||
|
|
||||||
# The last element of the argument array should be the options hash.
|
|
||||||
# We don't have any options yet, so for now just pop the hash off and
|
|
||||||
# toss it.
|
|
||||||
#
|
|
||||||
# NOTE: The Puppet Face will throw 'unrecognized option' errors if any
|
|
||||||
# YARD options are passed to it. The best way to approach this problem is
|
|
||||||
# by using the `.yardopts` file. YARD will autoload any options placed in
|
|
||||||
# that file.
|
|
||||||
options = args.pop
|
|
||||||
YARD::Config.options = YARD::Config.options.merge(options) if options
|
|
||||||
|
|
||||||
# For now, assume the remaining positional args are a list of manifest
|
|
||||||
# and ruby files to parse.
|
|
||||||
yard_args = (args.empty? ? MODULE_SOURCEFILES : args)
|
|
||||||
|
|
||||||
# If json is going to be emitted to stdout, suppress statistics.
|
|
||||||
if options && options[:emit_json_stdout]
|
|
||||||
yard_args.push('--no-stats')
|
|
||||||
end
|
|
||||||
|
|
||||||
# This line monkeypatches yard's progress indicator so it doesn't write
|
|
||||||
# all over the terminal. This should definitely not be in real code, but
|
|
||||||
# it's very handy for debugging with pry
|
|
||||||
#class YARD::Logger; def progress(*args); end; end
|
|
||||||
YARD::Tags::Library.define_directive("puppet.type.param",
|
|
||||||
:with_types_and_name,
|
|
||||||
PuppetX::Puppet::Strings::YARD::Tags::PuppetTypeParameterDirective)
|
|
||||||
|
|
||||||
yardoc_actions.generate_documentation(*yard_args)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.serve(args = [])
|
|
||||||
server_actions = PuppetX::Puppet::Strings::Actions.new(Puppet[:debug], Puppet[:trace])
|
|
||||||
|
|
||||||
args.pop
|
|
||||||
|
|
||||||
module_names = args
|
|
||||||
|
|
||||||
# FIXME: This is pretty inefficient as it forcibly re-generates the YARD
|
|
||||||
# indicies each time the server is started. However, it ensures things are
|
|
||||||
# generated properly.
|
|
||||||
module_list = server_actions.index_documentation_for_modules(module_names, MODULE_SOURCEFILES)
|
|
||||||
|
|
||||||
module_tuples = server_actions.generate_module_tuples(module_list)
|
|
||||||
|
|
||||||
module_tuples.map! do |mod|
|
|
||||||
[mod[:name], mod[:index_path]]
|
|
||||||
end
|
|
||||||
|
|
||||||
# The `-m` flag means a list of name/path pairs will follow. The name is
|
|
||||||
# used as the module name and the path indicates which `.yardoc` index to
|
|
||||||
# generate documentation from.
|
|
||||||
yard_args = %w[-m -q] + module_tuples.flatten
|
|
||||||
|
|
||||||
server_actions.serve_documentation(*yard_args)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,33 +0,0 @@
|
||||||
require 'json'
|
|
||||||
|
|
||||||
class PuppetX::Puppet::Strings::YARD::CodeObjects::DefinedTypeObject < PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject
|
|
||||||
# A list of parameters attached to this class.
|
|
||||||
# @return [Array<Array(String, String)>]
|
|
||||||
attr_accessor :parameters
|
|
||||||
attr_accessor :type_info
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
name.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_json(*a)
|
|
||||||
{
|
|
||||||
"name" => @name,
|
|
||||||
"file" => file,
|
|
||||||
"line" => line,
|
|
||||||
"parameters" => Hash[@parameters],
|
|
||||||
"docstring" => Puppet::Util::Docs.scrub(@docstring),
|
|
||||||
"signatures" => @type_info.map do |signature|
|
|
||||||
signature.map do |key, value|
|
|
||||||
{
|
|
||||||
"name" => key,
|
|
||||||
"type" => value,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
"examples" => self.tags.map do |tag|
|
|
||||||
tag.text if tag.tag_name == 'example'
|
|
||||||
end.compact,
|
|
||||||
}.to_json(*a)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,22 +0,0 @@
|
||||||
class PuppetX::Puppet::Strings::YARD::CodeObjects::HostClassObject < PuppetX::Puppet::Strings::YARD::CodeObjects::DefinedTypeObject
|
|
||||||
# The {HostClassObject} that this class inherits from, if any.
|
|
||||||
# @return [HostClassObject, Proxy, nil]
|
|
||||||
attr_accessor :parent_class
|
|
||||||
|
|
||||||
# NOTE: `include_mods` is never used as it makes no sense for Puppet, but
|
|
||||||
# this is called by `YARD::Registry` and it will pass a parameter.
|
|
||||||
def inheritance_tree(include_mods = false)
|
|
||||||
if parent_class.is_a?(PuppetX::Puppet::Strings::YARD::CodeObjects::HostClassObject)
|
|
||||||
# Cool. We got a host class. Return self + parent inheritance tree.
|
|
||||||
[self] + parent_class.inheritance_tree
|
|
||||||
elsif parent_class.is_a?(YARD::CodeObjects::Proxy)
|
|
||||||
# We have a reference to a parent that has not been created yet. Just
|
|
||||||
# return it.
|
|
||||||
[self, parent_class]
|
|
||||||
else
|
|
||||||
# Most likely no parent class. But also possibly an object that we
|
|
||||||
# shouldn't inherit from. Just return self.
|
|
||||||
[self]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,62 +0,0 @@
|
||||||
class YARD::CodeObjects::MethodObject
|
|
||||||
|
|
||||||
# Override to_s and to_json methods in Yard's MethodObject so that they
|
|
||||||
# return output formatted as I like for puppet 3x and 4x methods.
|
|
||||||
def to_s
|
|
||||||
if self[:puppet_4x_function] || self[:puppet_3x_function]
|
|
||||||
name.to_s
|
|
||||||
else
|
|
||||||
super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_json(*a)
|
|
||||||
if self[:puppet_4x_function]
|
|
||||||
{
|
|
||||||
"name" => @name,
|
|
||||||
"file" => file,
|
|
||||||
"line" => line,
|
|
||||||
"function_api_version" => 4,
|
|
||||||
"docstring" => Puppet::Util::Docs.scrub(@docstring),
|
|
||||||
"examples" => self.tags.map do |tag|
|
|
||||||
tag.text if tag.tag_name == 'example'
|
|
||||||
end.compact,
|
|
||||||
"documented_params" => @parameters.map do |tuple|
|
|
||||||
{
|
|
||||||
"name" => tuple[0],
|
|
||||||
"type" => tuple[1],
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
"signatures" => @type_info.map do |signature|
|
|
||||||
signature.map do |key, value|
|
|
||||||
{
|
|
||||||
"name" => key,
|
|
||||||
"type" => value,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
}.to_json(*a)
|
|
||||||
elsif self[:puppet_3x_function]
|
|
||||||
{
|
|
||||||
"name" => @name,
|
|
||||||
"file" => file,
|
|
||||||
"line" => line,
|
|
||||||
"function_api_version" => 3,
|
|
||||||
"docstring" => Puppet::Util::Docs.scrub(@docstring),
|
|
||||||
"documented_params" => @parameters.map do |tuple|
|
|
||||||
{
|
|
||||||
"name" => tuple[0],
|
|
||||||
"type" => tuple[1],
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
"examples" => self.tags.map do |tag|
|
|
||||||
tag.text if tag.tag_name == 'example'
|
|
||||||
end.compact,
|
|
||||||
}.to_json(*a)
|
|
||||||
else
|
|
||||||
super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,24 +0,0 @@
|
||||||
class PuppetX::Puppet::Strings::YARD::CodeObjects::ProviderObject < PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject
|
|
||||||
# A list of parameters attached to this class.
|
|
||||||
# @return [Array<Array(String, String)>]
|
|
||||||
attr_accessor :parameters
|
|
||||||
|
|
||||||
def to_json(*a)
|
|
||||||
{
|
|
||||||
"name" => @name,
|
|
||||||
"type_name" => @type_name,
|
|
||||||
"file" => file,
|
|
||||||
"line" => line,
|
|
||||||
"docstring" => Puppet::Util::Docs.scrub(@docstring),
|
|
||||||
"commands" => @commands,
|
|
||||||
"confines" => @confines,
|
|
||||||
"defaults" => @defaults,
|
|
||||||
"features" => @features,
|
|
||||||
"examples" => self.tags.map do |tag|
|
|
||||||
tag.text if tag.tag_name == 'example'
|
|
||||||
end.compact,
|
|
||||||
}.to_json(*a)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,48 +0,0 @@
|
||||||
class PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject < YARD::CodeObjects::NamespaceObject
|
|
||||||
|
|
||||||
attr_accessor :type_info
|
|
||||||
# NOTE: `YARD::Registry#resolve` requires a method with this signature to
|
|
||||||
# be present on all subclasses of `NamespaceObject`.
|
|
||||||
def inheritance_tree(include_mods = false)
|
|
||||||
[self]
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
name.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_json(*a)
|
|
||||||
{
|
|
||||||
"name" => @name,
|
|
||||||
"file" => file,
|
|
||||||
"line" => line,
|
|
||||||
"docstring" => @docstring,
|
|
||||||
"examples" => self.tags.map do |tag|
|
|
||||||
tag.text if tag.tag_name == 'example'
|
|
||||||
end.compact,
|
|
||||||
}.to_json(*a)
|
|
||||||
end
|
|
||||||
|
|
||||||
# FIXME: We used to override `self.new` to ensure no YARD proxies were
|
|
||||||
# created for namespaces segments that did not map to a host class or
|
|
||||||
# defined type. Fighting the system in this way turned out to be
|
|
||||||
# counter-productive.
|
|
||||||
#
|
|
||||||
# However, if a proxy is left in, YARD will drop back to namspace-mangling
|
|
||||||
# heuristics that are very specific to Ruby and which produce ugly paths in
|
|
||||||
# the resulting output. Need to find a way to address this.
|
|
||||||
#
|
|
||||||
# Tried:
|
|
||||||
#
|
|
||||||
# - Overriding self.new in the code object. Failed because self.new
|
|
||||||
# overrides are gross and difficult to pull off. Especially when
|
|
||||||
# replacing an existing override.
|
|
||||||
#
|
|
||||||
# - Adding functionality to the base handler to ensure something other
|
|
||||||
# than a proxy occupies each namespace segment. Failed because once a
|
|
||||||
# code object is created with a namespace, it will never update.
|
|
||||||
# Unless that namespace is set to a Proxy.
|
|
||||||
#
|
|
||||||
# def self.new(namespace, name, *args, &block)
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
class PuppetX::Puppet::Strings::YARD::CodeObjects::TypeObject < PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject
|
|
||||||
# A list of parameters attached to this class.
|
|
||||||
# @return [Array<Array(String, String)>]
|
|
||||||
attr_accessor :parameters
|
|
||||||
|
|
||||||
def to_json(*a)
|
|
||||||
{
|
|
||||||
"name" => @name,
|
|
||||||
"file" => file,
|
|
||||||
"line" => line,
|
|
||||||
"docstring" => Puppet::Util::Docs.scrub(@docstring),
|
|
||||||
"parameters" => @parameter_details.map do |obj|
|
|
||||||
{
|
|
||||||
"allowed_values" => obj[:allowed_values] ? obj[:allowed_values].flatten : [],
|
|
||||||
"default" => obj[:default],
|
|
||||||
"docstring" => Puppet::Util::Docs.scrub(obj[:desc] || ''),
|
|
||||||
"namevar" => obj[:namevar],
|
|
||||||
"name" => obj[:name],
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
"examples" => self.tags.map do |tag|
|
|
||||||
tag.text if tag.tag_name == 'example'
|
|
||||||
end.compact,
|
|
||||||
"properties" => @property_details.map do |obj|
|
|
||||||
{
|
|
||||||
"allowed_values" => obj[:allowed_values] ? obj[:allowed_values].flatten : [],
|
|
||||||
"default" => obj[:default],
|
|
||||||
"docstring" => Puppet::Util::Docs.scrub(obj[:desc] || ''),
|
|
||||||
"name" => obj[:name],
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
"features" => @features.map do |obj|
|
|
||||||
{
|
|
||||||
"docstring" => Puppet::Util::Docs.scrub(obj[:desc] || ''),
|
|
||||||
"methods" => obj[:methods],
|
|
||||||
"name" => obj[:name],
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
}.to_json(*a)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,39 +0,0 @@
|
||||||
require 'yard'
|
|
||||||
require 'puppet_x/puppet/strings'
|
|
||||||
|
|
||||||
# Patch the regular expression used to match namespaces
|
|
||||||
# so it will allow namespace segments that begin with
|
|
||||||
# both uppercase and lowercase letters (i.e. both
|
|
||||||
# Puppet::Namespace and puppet::namespace)
|
|
||||||
YARD::CodeObjects.send(:remove_const, :CONSTANTMATCH)
|
|
||||||
YARD::CodeObjects::CONSTANTMATCH = /[a-zA-Z]\w*/
|
|
||||||
|
|
||||||
# This is a temporary hack until a new version of YARD is
|
|
||||||
# released. We submitted a patch to YARD to add the
|
|
||||||
# CONSTANTSTART constant so that we could patch it and
|
|
||||||
# successfully match our own namesapces. However until
|
|
||||||
# the next version of the YARD gem is released, we must
|
|
||||||
# patch the problematic method itself as it is not yet
|
|
||||||
# using the added variable
|
|
||||||
if defined? YARD::CodeObjects::CONSTANTSTART
|
|
||||||
YARD::CodeObjects.send(:remove_const, :CONSTANTSTART)
|
|
||||||
YARD::CodeObjects::CONSTANTSTART = /^[a-zA-Z]/
|
|
||||||
else
|
|
||||||
class YARD::CodeObjects::Proxy
|
|
||||||
def proxy_path
|
|
||||||
if @namespace.root?
|
|
||||||
(@imethod ? YARD::CodeObjects::ISEP : "") + name.to_s
|
|
||||||
elsif @origname
|
|
||||||
if @origname =~ /^[a-zA-Z]/
|
|
||||||
@origname
|
|
||||||
else
|
|
||||||
[namespace.path, @origname].join
|
|
||||||
end
|
|
||||||
elsif name.to_s =~ /^[a-zA-Z]/ # const
|
|
||||||
name.to_s
|
|
||||||
else # class meth?
|
|
||||||
[namespace.path, name.to_s].join(YARD::CodeObjects::CSEP)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,13 +0,0 @@
|
||||||
require 'puppet_x/puppet/strings/yard/core_ext/yard'
|
|
||||||
|
|
||||||
class PuppetX::Puppet::Strings::YARD::Handlers::Base < ::YARD::Handlers::Base
|
|
||||||
# Easy access to Pops model objects for handler matching.
|
|
||||||
include Puppet::Pops::Model
|
|
||||||
# Easy access to custom code objects from which documentation is generated.
|
|
||||||
include PuppetX::Puppet::Strings::YARD::CodeObjects
|
|
||||||
|
|
||||||
def self.handles?(statement)
|
|
||||||
handlers.any? {|h| h == statement.type}
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,31 +0,0 @@
|
||||||
class PuppetX::Puppet::Strings::YARD::Handlers::DefinedTypeHandler < PuppetX::Puppet::Strings::YARD::Handlers:: Base
|
|
||||||
handles ResourceTypeDefinition
|
|
||||||
|
|
||||||
process do
|
|
||||||
obj = DefinedTypeObject.new(:root, statement.pops_obj.name) do |o|
|
|
||||||
o.parameters = statement.parameters.map do |a|
|
|
||||||
param_tuple = [a[0].pops_obj.name]
|
|
||||||
param_tuple << ( a[1].nil? ? nil : a[1].source )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
tp = Puppet::Pops::Types::TypeParser.new
|
|
||||||
param_type_info = {}
|
|
||||||
statement.pops_obj.parameters.each do |pop_param|
|
|
||||||
# If the parameter's type expression is nil, default to Any
|
|
||||||
if pop_param.type_expr == nil
|
|
||||||
param_type_info[pop_param.name] = Puppet::Pops::Types::TypeFactory.any()
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
param_type_info[pop_param.name] = tp.interpret_any(pop_param.type_expr)
|
|
||||||
rescue Puppet::ParseError => e
|
|
||||||
# If the type could not be interpreted insert a prominent warning
|
|
||||||
param_type_info[pop_param.name] = "Type Error: #{e.message}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
obj.type_info = [param_type_info]
|
|
||||||
|
|
||||||
|
|
||||||
register obj
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,82 +0,0 @@
|
||||||
class HereDocHelper
|
|
||||||
# NOTE: The following methods duplicate functionality from
|
|
||||||
# Puppet::Util::Reference and Puppet::Parser::Functions.functiondocs
|
|
||||||
#
|
|
||||||
# However, implementing this natively in YARD is a good test for the
|
|
||||||
# feasibility of extracting custom Ruby documentation. In the end, the
|
|
||||||
# existing approach taken by Puppet::Util::Reference may be the best due to
|
|
||||||
# the heavy use of metaprogramming in Types and Providers.
|
|
||||||
|
|
||||||
# Extracts the Puppet function name and options hash from the parsed
|
|
||||||
# definition.
|
|
||||||
#
|
|
||||||
# @return [(String, Hash{String => String})]
|
|
||||||
def process_parameters(statement)
|
|
||||||
# Passing `false` to prameters excludes the block param from the returned
|
|
||||||
# list.
|
|
||||||
name, opts = statement.parameters(false).compact
|
|
||||||
|
|
||||||
name = process_element(name)
|
|
||||||
|
|
||||||
# Don't try to process options if we don't have any
|
|
||||||
if !opts.nil?
|
|
||||||
opts = opts.map do |tuple|
|
|
||||||
# Jump down into the S-Expression that represents a hashrocket, `=>`,
|
|
||||||
# and the values on either side of it.
|
|
||||||
tuple.jump(:assoc).map{|e| process_element(e)}
|
|
||||||
end
|
|
||||||
|
|
||||||
options = Hash[opts]
|
|
||||||
else
|
|
||||||
options = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
[name, options]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Sometimes the YARD parser returns Heredoc strings that start with `<-`
|
|
||||||
# instead of `<<-`.
|
|
||||||
HEREDOC_START = /^<?<-/
|
|
||||||
|
|
||||||
def is_heredoc?(str)
|
|
||||||
HEREDOC_START.match(str)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Turns an entry in the method parameter list into a string.
|
|
||||||
#
|
|
||||||
# @param ele [YARD::Parser::Ruby::AstNode]
|
|
||||||
# @return [String]
|
|
||||||
def process_element(ele)
|
|
||||||
ele = ele.jump(:ident, :symbol, :string_content)
|
|
||||||
|
|
||||||
case ele.type
|
|
||||||
when :ident
|
|
||||||
ele.source
|
|
||||||
when :symbol
|
|
||||||
ele.source[1..-1]
|
|
||||||
when :string_content
|
|
||||||
source = ele.source
|
|
||||||
if is_heredoc? source
|
|
||||||
process_heredoc(source)
|
|
||||||
else
|
|
||||||
source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Cleans up and formats Heredoc contents parsed by YARD.
|
|
||||||
#
|
|
||||||
# @param source [String]
|
|
||||||
# @return [String]
|
|
||||||
def process_heredoc(source)
|
|
||||||
source = source.lines.to_a
|
|
||||||
|
|
||||||
# YARD adds a line of source context on either side of the Heredoc
|
|
||||||
# contents.
|
|
||||||
source.shift
|
|
||||||
source.pop
|
|
||||||
|
|
||||||
# This utility method normalizes indentation and trims whitespace.
|
|
||||||
Puppet::Util::Docs.scrub(source.join)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,55 +0,0 @@
|
||||||
class PuppetX::Puppet::Strings::YARD::Handlers::HostClassHandler < PuppetX::Puppet::Strings::YARD::Handlers::Base
|
|
||||||
handles HostClassDefinition
|
|
||||||
|
|
||||||
process do
|
|
||||||
begin
|
|
||||||
obj = HostClassObject.new(:root, statement.pops_obj.name)
|
|
||||||
|
|
||||||
obj.parameters = statement.parameters.map do |a|
|
|
||||||
param_tuple = [a[0].pops_obj.name]
|
|
||||||
param_tuple << ( a[1].nil? ? nil : a[1].source )
|
|
||||||
end
|
|
||||||
tp = Puppet::Pops::Types::TypeParser.new
|
|
||||||
param_type_info = {}
|
|
||||||
statement.pops_obj.parameters.each do |pop_param|
|
|
||||||
# If the parameter's type expression is nil, default to Any
|
|
||||||
if pop_param.type_expr == nil
|
|
||||||
param_type_info[pop_param.name] = Puppet::Pops::Types::TypeFactory.any()
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
# This is a bit of a hack because we were using a method that was previously
|
|
||||||
# API private. See PDOC-75 for more details
|
|
||||||
if Puppet::Pops::Types::TypeParser.instance_method(:interpret_any).arity == 2
|
|
||||||
param_type_info[pop_param.name] = tp.interpret_any(pop_param.type_expr, nil)
|
|
||||||
else
|
|
||||||
param_type_info[pop_param.name] = tp.interpret_any(pop_param.type_expr)
|
|
||||||
end
|
|
||||||
rescue Puppet::ParseError => e
|
|
||||||
# If the type could not be interpreted insert a prominent warning
|
|
||||||
param_type_info[pop_param.name] = "Type Error: #{e.message}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
obj.type_info = [param_type_info]
|
|
||||||
|
|
||||||
statement.pops_obj.tap do |o|
|
|
||||||
if o.parent_class
|
|
||||||
obj.parent_class = P(:root, o.parent_class)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
register obj
|
|
||||||
rescue StandardError, SystemStackError => e
|
|
||||||
# If we hit this, we've thrown an exception somewhere that should be
|
|
||||||
# addressed but should not break the build.
|
|
||||||
#
|
|
||||||
# SystemStackError is being caught due to a presently untraced bug in
|
|
||||||
# either YARD or the Puppet Parser.
|
|
||||||
#
|
|
||||||
# Note: Documentation will *not* be generated for any item listed here,
|
|
||||||
# but you will get the rest of your documentation!
|
|
||||||
|
|
||||||
$stderr.puts("Ignored: #{e.inspect} at #{obj.title}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,96 +0,0 @@
|
||||||
# Handles `dispatch` calls within a future parser function declaration. For
|
|
||||||
# now, it just treats any docstring as an `@overlaod` tag and attaches the
|
|
||||||
# overload to the parent function.
|
|
||||||
class PuppetX::Puppet::Strings::YARD::Handlers::PuppetProviderHandler < YARD::Handlers::Ruby::Base
|
|
||||||
include PuppetX::Puppet::Strings::YARD::CodeObjects
|
|
||||||
|
|
||||||
handles :command_call, :call
|
|
||||||
|
|
||||||
process do
|
|
||||||
@heredoc_helper = HereDocHelper.new
|
|
||||||
# Puppet types always begin with:
|
|
||||||
# Puppet::Types.newtype...
|
|
||||||
# Therefore, we match the corresponding trees which look like this:
|
|
||||||
# s(:call,
|
|
||||||
# s(:const_path_ref,
|
|
||||||
# s(:var_ref, s(:const, "Puppet", ...), ...),
|
|
||||||
# s(:const, "Type", ...),
|
|
||||||
# You think this is ugly? It's better than the alternative.
|
|
||||||
return unless statement.children.length > 2
|
|
||||||
first = statement.children.first.first
|
|
||||||
return unless (first.source == 'Puppet::Type') ||
|
|
||||||
(first.type == :var_ref &&
|
|
||||||
first.source == 'Type') &&
|
|
||||||
statement[2].source == 'provide'
|
|
||||||
i = statement.index { |s| YARD::Parser::Ruby::AstNode === s && s.type == :ident && s.source == 'provide' }
|
|
||||||
provider_name = statement[i+1].jump(:ident).source
|
|
||||||
type_name = statement.jump(:symbol).first.source
|
|
||||||
provider_name = "#{type_name}:#{provider_name}"
|
|
||||||
|
|
||||||
obj = ProviderObject.new(:root, "#{provider_name}_provider")
|
|
||||||
|
|
||||||
docstring = nil
|
|
||||||
features = []
|
|
||||||
commands = []
|
|
||||||
confines = {}
|
|
||||||
defaults = {}
|
|
||||||
do_block = statement.jump(:do_block)
|
|
||||||
do_block.traverse do |node|
|
|
||||||
if is_a_func_call_named?('desc', node)
|
|
||||||
content = node.jump(:tstring_content)
|
|
||||||
# if we found the string content extract its source
|
|
||||||
if content != node
|
|
||||||
# The docstring is either the source stripped of heredoc
|
|
||||||
# annotations or the raw source.
|
|
||||||
if @heredoc_helper.is_heredoc?(content.source)
|
|
||||||
docstring = @heredoc_helper.process_heredoc content.source
|
|
||||||
else
|
|
||||||
docstring = content.source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elsif is_a_func_call_named?('confine', node)
|
|
||||||
node.traverse do |s|
|
|
||||||
if s.type == :assoc
|
|
||||||
k = s.first.jump(:ident).source
|
|
||||||
v = s[1].first.source
|
|
||||||
confines[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elsif is_a_func_call_named?('has_feature', node)
|
|
||||||
list = node.jump :list
|
|
||||||
if list != nil && list != node
|
|
||||||
features += list.map { |s| s.source if YARD::Parser::Ruby::AstNode === s }.compact
|
|
||||||
end
|
|
||||||
elsif is_a_func_call_named?('commands', node)
|
|
||||||
assoc = node.jump(:assoc)
|
|
||||||
if assoc && assoc != node
|
|
||||||
ident = assoc.jump(:ident)
|
|
||||||
if ident && ident != assoc
|
|
||||||
commands << ident.source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elsif is_a_func_call_named?('defaultfor', node)
|
|
||||||
node.traverse do |s|
|
|
||||||
if s.type == :assoc
|
|
||||||
k = s.first.jump(:ident).source
|
|
||||||
v = s[1].first.source
|
|
||||||
defaults[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
obj.features = features
|
|
||||||
obj.commands = commands
|
|
||||||
obj.confines = confines
|
|
||||||
obj.defaults = defaults
|
|
||||||
obj.type_name = type_name
|
|
||||||
obj.header_name = provider_name
|
|
||||||
|
|
||||||
register_docstring(obj, docstring, nil)
|
|
||||||
register obj
|
|
||||||
end
|
|
||||||
|
|
||||||
def is_a_func_call_named?(name, node)
|
|
||||||
(node.type == :fcall || node.type == :command || node.type == :vcall) && node.children.first.source == name
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,54 +0,0 @@
|
||||||
require File.join(File.dirname(__FILE__),'./heredoc_helper')
|
|
||||||
|
|
||||||
class PuppetX::Puppet::Strings::YARD::Handlers::Puppet3xFunctionHandler < YARD::Handlers::Ruby::Base
|
|
||||||
include PuppetX::Puppet::Strings::YARD::CodeObjects
|
|
||||||
|
|
||||||
handles method_call(:newfunction)
|
|
||||||
|
|
||||||
process do
|
|
||||||
@heredoc_helper = HereDocHelper.new
|
|
||||||
name, options = @heredoc_helper.process_parameters statement
|
|
||||||
|
|
||||||
obj = MethodObject.new(function_namespace, name)
|
|
||||||
obj[:puppet_3x_function] = true
|
|
||||||
|
|
||||||
register obj
|
|
||||||
if options['doc']
|
|
||||||
register_docstring(obj, options['doc'], nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
# This has to be done _after_ register_docstring as all tags on the
|
|
||||||
# object are overwritten by tags parsed out of the docstring.
|
|
||||||
return_type = options['type']
|
|
||||||
return_type ||= 'statement' # Default for newfunction
|
|
||||||
obj.add_tag YARD::Tags::Tag.new(:return, '', return_type)
|
|
||||||
|
|
||||||
# FIXME: This is a hack that allows us to document the Puppet Core which
|
|
||||||
# uses `--no-transitive-tag api` and then only shows things explicitly
|
|
||||||
# tagged with `public` or `private` api. This is kind of insane and
|
|
||||||
# should be fixed upstream.
|
|
||||||
obj.add_tag YARD::Tags::Tag.new(:api, 'public')
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# Returns a {PuppetNamespaceObject} for holding functions. Creates this
|
|
||||||
# object if necessary.
|
|
||||||
#
|
|
||||||
# @return [PuppetNamespaceObject]
|
|
||||||
def function_namespace
|
|
||||||
# NOTE: This tricky. If there is ever a Ruby class or module with the
|
|
||||||
# name ::Puppet3xFunctions, then there will be a clash. Hopefully the name
|
|
||||||
# is sufficiently uncommon.
|
|
||||||
obj = P(:root, 'Puppet3xFunctions')
|
|
||||||
if obj.is_a? Proxy
|
|
||||||
namespace_obj = PuppetNamespaceObject.new(:root, 'Puppet3xFunctions')
|
|
||||||
namespace_obj.add_tag YARD::Tags::Tag.new(:api, 'public')
|
|
||||||
|
|
||||||
register namespace_obj
|
|
||||||
end
|
|
||||||
|
|
||||||
obj
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,234 +0,0 @@
|
||||||
# Handles `dispatch` calls within a future parser function declaration. For
|
|
||||||
# now, it just treats any docstring as an `@overlaod` tag and attaches the
|
|
||||||
# overload to the parent function.
|
|
||||||
class PuppetX::Puppet::Strings::YARD::Handlers::Puppet4xFunctionHandler < YARD::Handlers::Ruby::Base
|
|
||||||
include PuppetX::Puppet::Strings::YARD::CodeObjects
|
|
||||||
|
|
||||||
handles method_call(:dispatch)
|
|
||||||
|
|
||||||
process do
|
|
||||||
return unless owner.is_a?(MethodObject) && owner['puppet_4x_function']
|
|
||||||
return unless statement.docstring
|
|
||||||
|
|
||||||
docstring = ::YARD::Docstring.new(statement.docstring, nil)
|
|
||||||
|
|
||||||
# FIXME: This does a wholesale copy of all possible tags. But, we're only
|
|
||||||
# interested in the @overload tag.
|
|
||||||
owner.add_tag *docstring.tags
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Puppet4xFunctionHandler < YARD::Handlers::Ruby::Base
|
|
||||||
include PuppetX::Puppet::Strings::YARD::CodeObjects
|
|
||||||
|
|
||||||
handles method_call(:create_function)
|
|
||||||
|
|
||||||
# Given a command node which represents code like this:
|
|
||||||
# param 'Optional[Type]', :value_type
|
|
||||||
# Extract the type name and type signature and return them as a array.
|
|
||||||
def extract_type_from_command command
|
|
||||||
return [] if command.children.length < 2 or command.children[1].children.length < 2
|
|
||||||
type_specifier = command.children[1]
|
|
||||||
# the parameter signature is the first child of the specifier and an
|
|
||||||
# identifier. Jump to the content inside the quotes and convert it to a
|
|
||||||
# string.
|
|
||||||
param_signature = type_specifier.children[0].jump(:tstring_content).source
|
|
||||||
# The parameter name is the second child of the specifier and a symbol.
|
|
||||||
# convert it to a string.
|
|
||||||
param_name_ident = type_specifier.jump :ident
|
|
||||||
return [] if param_name_ident == type_specifier
|
|
||||||
param_name = param_name_ident.source
|
|
||||||
[param_name, param_signature]
|
|
||||||
end
|
|
||||||
|
|
||||||
process do
|
|
||||||
name = process_parameters
|
|
||||||
|
|
||||||
method_arguments = []
|
|
||||||
|
|
||||||
# To attach the method parameters to the new code object, traverse the
|
|
||||||
# ruby AST until a node is found which defines a array of parameters.
|
|
||||||
# Then, traverse the children of the parameters, storing each identifier
|
|
||||||
# in the array of method arguments.
|
|
||||||
obj = MethodObject.new(function_namespace, name) do |o|
|
|
||||||
end
|
|
||||||
|
|
||||||
# The data structure for overload_signatures is an array of hashes. Each
|
|
||||||
# hash represents the arguments a single function dispatch (aka overload)
|
|
||||||
# can take.
|
|
||||||
# overload_signatures = [
|
|
||||||
# { # First function dispatch arguments
|
|
||||||
# # argument name, argument type
|
|
||||||
# 'arg0': 'Variant[String,Array[String]]',
|
|
||||||
# 'arg1': 'Optional[Type]'
|
|
||||||
# },
|
|
||||||
# { # Second function dispatch arguments
|
|
||||||
# 'arg0': 'Variant[String,Array[String]]',
|
|
||||||
# 'arg1': 'Optional[Type]',
|
|
||||||
# 'arg2': 'Any'
|
|
||||||
# }
|
|
||||||
# ]
|
|
||||||
# Note that the order for arguments to a function doesn't actually matter
|
|
||||||
# because we allow users flexibility when listing their arguments in the
|
|
||||||
# comments.
|
|
||||||
overload_signatures = []
|
|
||||||
statement.traverse do |node|
|
|
||||||
# Find all of the dispatch methods
|
|
||||||
if node.type == :ident and node.source == 'dispatch'
|
|
||||||
command = node.parent
|
|
||||||
do_block = command.jump :do_block
|
|
||||||
# If the command doesn't have a do_block we can't extract type info
|
|
||||||
if do_block == command
|
|
||||||
next
|
|
||||||
end
|
|
||||||
signature = {}
|
|
||||||
# Iterate through each of the children of the do block and build
|
|
||||||
# tuples of parameter names and parameter type signatures
|
|
||||||
do_block.children.first.children.each do |child|
|
|
||||||
name, type = extract_type_from_command(child)
|
|
||||||
# This can happen if there is a function or something we aren't
|
|
||||||
# expecting.
|
|
||||||
if name != nil and type != nil
|
|
||||||
signature[name] = type
|
|
||||||
end
|
|
||||||
end
|
|
||||||
overload_signatures <<= signature
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# If the overload_signatures list is empty because we couldn't find any
|
|
||||||
# dispatch blocks, then there must be one function named the same as the
|
|
||||||
# name of the function being created.
|
|
||||||
if overload_signatures.length == 0
|
|
||||||
statement.traverse do |node|
|
|
||||||
# Find the function definition with the same name as the puppet
|
|
||||||
# function being created.
|
|
||||||
if (node.type == :def and node.children.first.type == :ident and
|
|
||||||
node.children.first.source == obj.name.to_s)
|
|
||||||
signature = {}
|
|
||||||
# Find its parameters. If they don't exist, fine
|
|
||||||
params = node.jump :params
|
|
||||||
break if params == node
|
|
||||||
params.traverse do |param|
|
|
||||||
if param.type == :ident
|
|
||||||
# The parameters of Puppet functions with no defined dispatch are
|
|
||||||
# as though they are Any type.
|
|
||||||
signature[param[0]] = 'Any'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
overload_signatures <<= signature
|
|
||||||
# Now that the parameters have been found, break out of the traversal
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Preserve this type information. We'll need it later when we look
|
|
||||||
# at the docstring.
|
|
||||||
obj.type_info = overload_signatures
|
|
||||||
|
|
||||||
# The yard docstring parser expects a list of lists, not a list of lists of
|
|
||||||
# lists.
|
|
||||||
obj.parameters = overload_signatures.map { |sig| sig.to_a }.flatten(1)
|
|
||||||
|
|
||||||
obj['puppet_4x_function'] = true
|
|
||||||
|
|
||||||
register obj
|
|
||||||
|
|
||||||
obj.add_tag YARD::Tags::Tag.new(:api, 'public')
|
|
||||||
|
|
||||||
blk = statement.block.children.first
|
|
||||||
parse_block(blk, :owner => obj)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# Returns a {PuppetNamespaceObject} for holding functions. Creates this
|
|
||||||
# object if necessary.
|
|
||||||
#
|
|
||||||
# @return [PuppetNamespaceObject]
|
|
||||||
def function_namespace
|
|
||||||
# NOTE: This tricky. If there is ever a Ruby class or module with the
|
|
||||||
# name ::Puppet4xFunctions, then there will be a clash. Hopefully the name
|
|
||||||
# is sufficiently uncommon.
|
|
||||||
obj = P(:root, 'Puppet4xFunctions')
|
|
||||||
if obj.is_a? Proxy
|
|
||||||
namespace_obj = PuppetNamespaceObject.new(:root, 'Puppet4xFunctions')
|
|
||||||
|
|
||||||
register namespace_obj
|
|
||||||
# FIXME: The docstring has to be cleared. Otherwise, the namespace
|
|
||||||
# object will be registered using the docstring of the
|
|
||||||
# `create_function` call that is currently being processed.
|
|
||||||
#
|
|
||||||
# Figure out how to properly register the namespace without using the
|
|
||||||
# function handler object.
|
|
||||||
register_docstring(namespace_obj, '', nil)
|
|
||||||
namespace_obj.add_tag YARD::Tags::Tag.new(:api, 'public')
|
|
||||||
end
|
|
||||||
|
|
||||||
obj
|
|
||||||
end
|
|
||||||
|
|
||||||
# NOTE: The following methods duplicate functionality from
|
|
||||||
# Puppet::Util::Reference and Puppet::Parser::Functions.functiondocs
|
|
||||||
#
|
|
||||||
# However, implementing this natively in YARD is a good test for the
|
|
||||||
# feasibility of extracting custom Ruby documentation. In the end, the
|
|
||||||
# existing approach taken by Puppet::Util::Reference may be the best due to
|
|
||||||
# the heavy use of metaprogramming in Types and Providers.
|
|
||||||
|
|
||||||
# Extracts the Puppet function name and options hash from the parsed
|
|
||||||
# definition.
|
|
||||||
#
|
|
||||||
# @return [(String, Hash{String => String})]
|
|
||||||
def process_parameters
|
|
||||||
# Passing `false` to parameters excludes the block param from the returned
|
|
||||||
# array.
|
|
||||||
name, _ = statement.parameters(false).compact
|
|
||||||
|
|
||||||
name = process_element(name)
|
|
||||||
|
|
||||||
|
|
||||||
name
|
|
||||||
end
|
|
||||||
|
|
||||||
# Sometimes the YARD parser returns Heredoc strings that start with `<-`
|
|
||||||
# instead of `<<-`.
|
|
||||||
HEREDOC_START = /^<?<-/
|
|
||||||
|
|
||||||
# Turns an entry in the method parameter array into a string.
|
|
||||||
#
|
|
||||||
# @param ele [YARD::Parser::Ruby::AstNode]
|
|
||||||
# @return [String]
|
|
||||||
def process_element(ele)
|
|
||||||
ele = ele.jump(:ident, :string_content, :tstring_content)
|
|
||||||
|
|
||||||
case ele.type
|
|
||||||
when :ident
|
|
||||||
ele.source
|
|
||||||
when :string_content, :tstring_content
|
|
||||||
source = ele.source
|
|
||||||
if HEREDOC_START.match(source)
|
|
||||||
process_heredoc(source)
|
|
||||||
else
|
|
||||||
source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Cleans up and formats Heredoc contents parsed by YARD.
|
|
||||||
#
|
|
||||||
# @param source [String]
|
|
||||||
# @return [String]
|
|
||||||
def process_heredoc(source)
|
|
||||||
source = source.lines.to_a
|
|
||||||
|
|
||||||
# YARD adds a line of source context on either side of the Heredoc
|
|
||||||
# contents.
|
|
||||||
source.shift
|
|
||||||
source.pop
|
|
||||||
|
|
||||||
# This utility method normalizes indentation and trims whitespace.
|
|
||||||
Puppet::Util::Docs.scrub(source.join)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,295 +0,0 @@
|
||||||
# Handles `dispatch` calls within a future parser function declaration. For
|
|
||||||
# now, it just treats any docstring as an `@overlaod` tag and attaches the
|
|
||||||
# overload to the parent function.
|
|
||||||
class PuppetX::Puppet::Strings::YARD::Handlers::PuppetTypeHandler < YARD::Handlers::Ruby::Base
|
|
||||||
include PuppetX::Puppet::Strings::YARD::CodeObjects
|
|
||||||
|
|
||||||
handles :call
|
|
||||||
|
|
||||||
process do
|
|
||||||
@heredoc_helper = HereDocHelper.new
|
|
||||||
# Puppet types always begin with:
|
|
||||||
# Puppet::Types.newtype...
|
|
||||||
# Therefore, we match the corresponding trees which look like this:
|
|
||||||
# s(:call,
|
|
||||||
# s(:const_path_ref,
|
|
||||||
# s(:var_ref, s(:const, "Puppet", ...), ...),
|
|
||||||
# s(:const, "Type", ...),
|
|
||||||
# You think this is ugly? It's better than the alternative.
|
|
||||||
return unless statement.children.length > 2
|
|
||||||
first = statement.children.first
|
|
||||||
return unless (first.type == :const_path_ref and
|
|
||||||
first.source == 'Puppet::Type') or
|
|
||||||
(first.type == :var_ref and
|
|
||||||
first.source == 'Type') and
|
|
||||||
statement.children[1].source == "newtype"
|
|
||||||
|
|
||||||
# Fetch the docstring for the types. The docstring is the string literal
|
|
||||||
# assigned to the @doc parameter or absent, like this:
|
|
||||||
# @doc "docstring goes here"
|
|
||||||
# We assume that docstrings nodes have the following shape in the source
|
|
||||||
# code:
|
|
||||||
# ...
|
|
||||||
# s(s(:assign,
|
|
||||||
# s(:..., s(:ivar, "@doc", ...), ...),
|
|
||||||
# s(:...,
|
|
||||||
# s(:...,
|
|
||||||
# s(:tstring_content,
|
|
||||||
# "Manages files, including their content, etc.", ...
|
|
||||||
# Initialize the docstring to nil, the default value if we don't find
|
|
||||||
# anything
|
|
||||||
docstring = nil
|
|
||||||
# Walk the tree searching for assignments
|
|
||||||
statement.traverse do |node|
|
|
||||||
if node.type == :assign
|
|
||||||
# Once we have found and assignment, jump to the first ivar
|
|
||||||
# (the l-value)
|
|
||||||
# If we can't find an ivar return the node.
|
|
||||||
ivar = node.jump(:ivar)
|
|
||||||
# If we found and ivar and its source reads '@doc' then...
|
|
||||||
if ivar != node and ivar.source == '@doc'
|
|
||||||
# find the next string content
|
|
||||||
content = node.jump(:tstring_content)
|
|
||||||
# if we found the string content extract its source
|
|
||||||
if content != node
|
|
||||||
# The docstring is either the source stripped of heredoc
|
|
||||||
# annotations or the raw source.
|
|
||||||
if @heredoc_helper.is_heredoc? content.source
|
|
||||||
docstring = @heredoc_helper.process_heredoc content.source
|
|
||||||
else
|
|
||||||
docstring = content.source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
# Since we found the @doc parameter (regardless of whether we
|
|
||||||
# successfully extracted its source), we're done.
|
|
||||||
break
|
|
||||||
# But if we didn't find the ivar loop around again.
|
|
||||||
else
|
|
||||||
next
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# The types begin with:
|
|
||||||
# Puppet::Types.newtype(:symbol)
|
|
||||||
# Jump to the first identifier (':symbol') after the third argument
|
|
||||||
# ('(:symbol)') to the current statement
|
|
||||||
name = statement.children[2].jump(:ident).source
|
|
||||||
parameter_details = []
|
|
||||||
property_details = []
|
|
||||||
features = []
|
|
||||||
obj = TypeObject.new(:root, name)
|
|
||||||
obj.parameters = []
|
|
||||||
|
|
||||||
# Find the do block following the Type.
|
|
||||||
do_block = statement.jump(:do_block)
|
|
||||||
# traverse the do block's children searching for function calls whose
|
|
||||||
# identifier is newparam (we're calling the newparam function)
|
|
||||||
do_block.traverse do |node|
|
|
||||||
if is_param? node
|
|
||||||
# The first member of the parameter tuple is the parameter name.
|
|
||||||
# Find the second identifier node under the fcall tree. The first one
|
|
||||||
# is 'newparam', the second one is the function name.
|
|
||||||
# Get its source.
|
|
||||||
# The second parameter is nil because we cannot infer types for these
|
|
||||||
# functions. In fact, that's a silly thing to ask because ruby
|
|
||||||
# types were deprecated with puppet 4 at the same time the type
|
|
||||||
# system was created.
|
|
||||||
|
|
||||||
# Because of a ripper bug a symbol identifier is sometimes incorrectly parsed as a keyword.
|
|
||||||
# That is, the symbol `:true` will be represented as s(:symbol s(:kw, true...
|
|
||||||
param_name = node.children[1].jump(:ident)
|
|
||||||
if param_name == node.children[1]
|
|
||||||
param_name = node.children[1].jump(:kw)
|
|
||||||
end
|
|
||||||
param_name = param_name.source
|
|
||||||
obj.parameters << [param_name, nil]
|
|
||||||
parameter_details << {:name => param_name,
|
|
||||||
:desc => fetch_description(node), :exists? => true,
|
|
||||||
:puppet_type => true,
|
|
||||||
:default => fetch_default(node),
|
|
||||||
:namevar => is_namevar?(node, param_name, name),
|
|
||||||
:parameter => true,
|
|
||||||
:allowed_values => get_parameter_allowed_values(node),
|
|
||||||
}
|
|
||||||
elsif is_prop? node
|
|
||||||
# Because of a ripper bug a symbol identifier is sometimes incorrectly parsed as a keyword.
|
|
||||||
# That is, the symbol `:true` will be represented as s(:symbol s(:kw, true...
|
|
||||||
prop_name = node.children[1].jump(:ident)
|
|
||||||
if prop_name == node.children[1]
|
|
||||||
prop_name = node.children[1].jump(:kw)
|
|
||||||
end
|
|
||||||
prop_name = prop_name.source
|
|
||||||
property_details << {:name => prop_name,
|
|
||||||
:desc => fetch_description(node), :exists? => true,
|
|
||||||
:default => fetch_default(node),
|
|
||||||
:puppet_type => true,
|
|
||||||
:property => true,
|
|
||||||
:allowed_values => get_property_allowed_values(node),
|
|
||||||
}
|
|
||||||
elsif is_feature? node
|
|
||||||
features << get_feature(node)
|
|
||||||
elsif is_a_func_call_named? 'ensurable', node
|
|
||||||
# Someone could call the ensurable method and create an ensure
|
|
||||||
# property. If that happens, they it will be documented twice. Serves
|
|
||||||
# them right.
|
|
||||||
property_details << {:name => 'ensure',
|
|
||||||
:desc => '', :exists? => true,
|
|
||||||
:default => nil,
|
|
||||||
:puppet_type => true,
|
|
||||||
:property => true,
|
|
||||||
:allowed_values => [],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
obj.parameter_details = parameter_details
|
|
||||||
obj.property_details = property_details
|
|
||||||
obj.features = features
|
|
||||||
obj.header_name = name
|
|
||||||
|
|
||||||
register obj
|
|
||||||
# Register docstring after the object. If the object already has a
|
|
||||||
# docstring, or more likely has parameters documented with the type
|
|
||||||
# directive and an empty docstring, we want to override it with the
|
|
||||||
# docstring we found, assuming we found one.
|
|
||||||
register_docstring(obj, docstring, nil) if docstring
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# See:
|
|
||||||
# https://docs.puppet.com/guides/custom_types.html#namevar
|
|
||||||
# node should be a parameter
|
|
||||||
def is_namevar? node, param_name, type_name
|
|
||||||
# Option 1:
|
|
||||||
# Puppet::Type.newtype(:name) do
|
|
||||||
# ...
|
|
||||||
# newparam(:name) do
|
|
||||||
# ...
|
|
||||||
# end
|
|
||||||
if type_name == param_name
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
# Option 2:
|
|
||||||
# newparam(:path, :namevar => true) do
|
|
||||||
# ...
|
|
||||||
# end
|
|
||||||
if node.children.length >= 2
|
|
||||||
node.traverse do |s|
|
|
||||||
if s.type == :assoc and s.jump(:ident).source == 'namevar' and s.jump(:kw).source == 'true'
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
# Option 3:
|
|
||||||
# newparam(:path) do
|
|
||||||
# isnamevar
|
|
||||||
# ...
|
|
||||||
# end
|
|
||||||
do_block = node.jump(:do_block).traverse do |s|
|
|
||||||
if is_a_func_call_named? 'isnamevar', s
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
# Crazy implementations of types may just call #isnamevar directly on the object.
|
|
||||||
# We don't handle this today.
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
def is_param? node
|
|
||||||
is_a_func_call_named? 'newparam', node
|
|
||||||
end
|
|
||||||
def is_prop? node
|
|
||||||
is_a_func_call_named? 'newproperty', node
|
|
||||||
end
|
|
||||||
|
|
||||||
def is_feature? node
|
|
||||||
is_a_func_call_named? 'feature', node
|
|
||||||
end
|
|
||||||
|
|
||||||
def is_a_func_call_named? name, node
|
|
||||||
(node.type == :fcall or node.type == :command or node.type == :vcall) and node.children.first.source == name
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_feature node
|
|
||||||
name = node[1].jump(:ident).source
|
|
||||||
desc = node[1].jump(:tstring_content).source
|
|
||||||
methods = []
|
|
||||||
if node[1].length == 4 and node.children[1][2].jump(:ident).source == 'methods'
|
|
||||||
arr = node[1][2].jump(:array)
|
|
||||||
if arr != node[1][2]
|
|
||||||
arr.traverse do |s|
|
|
||||||
if s.type == :ident
|
|
||||||
methods << s.source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
{
|
|
||||||
:name => name,
|
|
||||||
:desc => desc,
|
|
||||||
:methods => methods != [] ? methods : nil,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_parameter_allowed_values node
|
|
||||||
vals = []
|
|
||||||
node.traverse do |s|
|
|
||||||
if is_a_func_call_named? 'newvalues', s
|
|
||||||
list = s.jump(:list)
|
|
||||||
if list != s
|
|
||||||
vals += list.map { |item| [item.source] if YARD::Parser::Ruby::AstNode === item }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
vals.compact
|
|
||||||
end
|
|
||||||
|
|
||||||
# Calls to newvalue only apply to properties, according to Dan & Nan's
|
|
||||||
# "Puppet Types and Providers", page 30.
|
|
||||||
def get_property_allowed_values node
|
|
||||||
vals = get_parameter_allowed_values node
|
|
||||||
node.traverse do |s|
|
|
||||||
if is_a_func_call_named? 'newvalue', s
|
|
||||||
required_features = nil
|
|
||||||
s.traverse do |ss|
|
|
||||||
if ss.type == :assoc and ss[0].source == ':required_features'
|
|
||||||
required_features = ss[1].source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
list = s.jump(:list)
|
|
||||||
if list != s
|
|
||||||
vals << [list[0].source, required_features].compact
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
vals
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_default node
|
|
||||||
do_block = node.jump(:do_block)
|
|
||||||
do_block.traverse do |s|
|
|
||||||
if is_a_func_call_named? 'defaultto', s
|
|
||||||
return s[-1].source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_description(fcall)
|
|
||||||
fcall.traverse do |node|
|
|
||||||
if is_a_func_call_named? 'desc', node
|
|
||||||
content = node.jump(:string_content)
|
|
||||||
if content != node
|
|
||||||
@heredoc_helper = HereDocHelper.new
|
|
||||||
if @heredoc_helper.is_heredoc? content.source
|
|
||||||
docstring = @heredoc_helper.process_heredoc content.source
|
|
||||||
else
|
|
||||||
docstring = content.source
|
|
||||||
end
|
|
||||||
return docstring
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,85 +0,0 @@
|
||||||
module YARD
|
|
||||||
|
|
||||||
class JsonRegistryStore < RegistryStore
|
|
||||||
def save(merge=true, file=nil)
|
|
||||||
super
|
|
||||||
|
|
||||||
@serializer = Serializers::JsonSerializer.new(@file)
|
|
||||||
|
|
||||||
sdb = Registry.single_object_db
|
|
||||||
if sdb == true || sdb == nil
|
|
||||||
serialize_output_schema(@store)
|
|
||||||
else
|
|
||||||
values(false).each do |object|
|
|
||||||
serialize_output_schema(object)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
# @param obj [Hash] A hash representing the registry or part of the
|
|
||||||
# registry.
|
|
||||||
def serialize_output_schema(obj)
|
|
||||||
|
|
||||||
schema = {
|
|
||||||
:puppet_functions => [],
|
|
||||||
:puppet_providers => [],
|
|
||||||
:puppet_classes => [],
|
|
||||||
:defined_types => [],
|
|
||||||
:puppet_types => [],
|
|
||||||
}
|
|
||||||
|
|
||||||
schema[:puppet_functions] += obj.select do |key, val|
|
|
||||||
val.type == :method and (val['puppet_4x_function'] or
|
|
||||||
val['puppet_3x_function'])
|
|
||||||
end.values
|
|
||||||
|
|
||||||
schema[:puppet_classes] += obj.select do |key, val|
|
|
||||||
val.type == :hostclass
|
|
||||||
end.values
|
|
||||||
|
|
||||||
schema[:defined_types] += obj.select do |key, val|
|
|
||||||
val.type == :definedtype
|
|
||||||
end.values
|
|
||||||
|
|
||||||
schema[:puppet_providers] += obj.select do |key, val|
|
|
||||||
val.type == :provider
|
|
||||||
end.values
|
|
||||||
|
|
||||||
schema[:puppet_types] += obj.select do |key, val|
|
|
||||||
val.type == :type
|
|
||||||
end.values
|
|
||||||
|
|
||||||
@serializer.serialize(schema.to_json)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Override the serializer because it puts the data at a wacky path and, more
|
|
||||||
# importantly, marshals the data with a bunch of non-printable characters.
|
|
||||||
module Serializers
|
|
||||||
class JsonSerializer < YardocSerializer
|
|
||||||
|
|
||||||
def initialize o
|
|
||||||
super
|
|
||||||
@options = {
|
|
||||||
:basepath => '.',
|
|
||||||
:extension => 'json',
|
|
||||||
}
|
|
||||||
@extension = 'json'
|
|
||||||
@basepath = '.'
|
|
||||||
end
|
|
||||||
def serialize(data)
|
|
||||||
|
|
||||||
if YARD::Config.options[:emit_json]
|
|
||||||
path = YARD::Config.options[:emit_json]
|
|
||||||
log.debug "Serializing json to #{path}"
|
|
||||||
File.open!(path, "wb") {|f| f.write data }
|
|
||||||
end
|
|
||||||
if YARD::Config.options[:emit_json_stdout]
|
|
||||||
puts data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,68 +0,0 @@
|
||||||
require 'yard'
|
|
||||||
require File.join(File.dirname(__FILE__), './json_registry_store')
|
|
||||||
|
|
||||||
# TODO: As far as I can tell, monkeypatching is the officially recommended way
|
|
||||||
# to extend these tools to cover custom usecases. Follow up on the YARD mailing
|
|
||||||
# list or IRC to see if there is a better way.
|
|
||||||
|
|
||||||
class YARD::CLI::Yardoc
|
|
||||||
def all_objects
|
|
||||||
YARD::Registry.all(:root, :module, :class, :type, :provider, :puppetnamespace, :hostclass, :definedtype)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class YARD::CLI::Stats
|
|
||||||
def stats_for_hostclasses
|
|
||||||
output 'Puppet Classes', *type_statistics(:hostclass)
|
|
||||||
end
|
|
||||||
|
|
||||||
def stats_for_definedtypes
|
|
||||||
output 'Puppet Defined Types', *type_statistics(:definedtype)
|
|
||||||
end
|
|
||||||
|
|
||||||
def stats_for_puppet_types
|
|
||||||
output 'Puppet Types', *type_statistics(:type)
|
|
||||||
end
|
|
||||||
|
|
||||||
def stats_for_puppet_provider
|
|
||||||
output 'Puppet Providers', *type_statistics(:provider)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class YARD::Logger
|
|
||||||
def show_progress
|
|
||||||
return false if YARD.ruby18? # threading is too ineffective for progress support
|
|
||||||
return false if YARD.windows? # windows has poor ANSI support
|
|
||||||
return false unless io.tty? # no TTY support on IO
|
|
||||||
# Here is the actual monkey patch. A simple fix to an inverted conditional.
|
|
||||||
# Without this Pry is unusable for debugging as the progress bar goes
|
|
||||||
# craaaaaaaazy.
|
|
||||||
return false unless level > INFO # no progress in verbose/debug modes
|
|
||||||
@show_progress
|
|
||||||
end
|
|
||||||
|
|
||||||
# Redirect Yard command line warnings to a log file called .yardwarns
|
|
||||||
# Yard warnings may be irrelevant, spurious, or may not conform with our
|
|
||||||
# styling and UX design. They are also printed on stdout by default.
|
|
||||||
def warn warning
|
|
||||||
f = File.new '.yardwarns', 'a'
|
|
||||||
f.write warning
|
|
||||||
f.close()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# 15:04:42 radens | lsegal: where would you tell yard to use your custom RegistryStore?
|
|
||||||
# 15:09:54 @lsegal | https://github.com/lsegal/yard/blob/master/lib/yard/registry.rb#L428-L435
|
|
||||||
# 15:09:54 @lsegal | you would set that attr on Registry
|
|
||||||
# 15:09:54 @lsegal | it might be worth expanding that API to swap out the store class used
|
|
||||||
# 15:10:49 @lsegal | specifically
|
|
||||||
# | https://github.com/lsegal/yard/blob/master/lib/yard/registry.rb#L190 and
|
|
||||||
# | replace RegistryStore there with a storage_class attr
|
|
||||||
module YARD::Registry
|
|
||||||
class << self
|
|
||||||
def clear
|
|
||||||
self.thread_local_store = YARD::JsonRegistryStore.new
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,30 +0,0 @@
|
||||||
require 'yard'
|
|
||||||
require 'puppet/pops'
|
|
||||||
|
|
||||||
require 'puppet_x/puppet/strings'
|
|
||||||
require 'puppet_x/puppet/strings//pops/yard_transformer'
|
|
||||||
|
|
||||||
class PuppetX::Puppet::Strings::YARD::PuppetParser < YARD::Parser::Base
|
|
||||||
attr_reader :file, :source
|
|
||||||
|
|
||||||
def initialize(source, filename)
|
|
||||||
@source = source
|
|
||||||
@file = filename
|
|
||||||
|
|
||||||
@parser = Puppet::Pops::Parser::Parser.new()
|
|
||||||
@transformer = PuppetX::Puppet::Strings::Pops::YARDTransformer.new()
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse
|
|
||||||
@parse_result ||= @parser.parse_string(source)
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
def enumerator
|
|
||||||
statements = @transformer.transform(@parse_result)
|
|
||||||
|
|
||||||
# Ensure an array is returned and prune any nil values.
|
|
||||||
Array(statements).compact.reverse
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,34 +0,0 @@
|
||||||
<div class="docstring">
|
|
||||||
<div class="discussion">
|
|
||||||
<p><%= htmlify(@class_details[:desc]) %></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tags">
|
|
||||||
<% if @class_details[:examples] != {}%>
|
|
||||||
<div class="examples">
|
|
||||||
<p class="tag_title">Examples:</p>
|
|
||||||
<% @class_details[:examples].each do |title, text| %>
|
|
||||||
<div class="inline"><p><%= title %></p></div>
|
|
||||||
<pre class="example code"><code><span><%= text %></span></code></pre>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<% if @class_details[:since] %>
|
|
||||||
<p class="tag_title">Since:</p>
|
|
||||||
<ul class="since">
|
|
||||||
<li>
|
|
||||||
<div class="inline">
|
|
||||||
<p><%= @class_details[:since] %></p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
||||||
<% if @class_details[:return] %>
|
|
||||||
<p class="tag_title">Return:</p>
|
|
||||||
<ul class="return">
|
|
||||||
<li>
|
|
||||||
<%= @html_helper.generate_return_types(@class_details[:return][1], @class_details[:return][0]) %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<div class='module_header'>
|
|
||||||
<h1>
|
|
||||||
<%= @header_text %>
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<h2>Parameter Summary</h2>
|
|
||||||
<div class="tags">
|
|
||||||
<ul class="param">
|
|
||||||
<%= @html_helper.generate_parameters(@param_details, object) %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
|
@ -1 +0,0 @@
|
||||||
include T('default/module/html')
|
|
|
@ -1,49 +0,0 @@
|
||||||
include T('default/module')
|
|
||||||
|
|
||||||
require File.join(File.dirname(__FILE__),'../html_helper')
|
|
||||||
require File.join(File.dirname(__FILE__),'../template_helper')
|
|
||||||
|
|
||||||
def init
|
|
||||||
sections :header, :box_info, :pre_docstring, :docstring, :parameter_details
|
|
||||||
|
|
||||||
@template_helper = TemplateHelper.new
|
|
||||||
@html_helper = HTMLHelper.new
|
|
||||||
@template_helper.check_parameters_match_docs object
|
|
||||||
params = object.parameters.map { |param| param.first }
|
|
||||||
param_tags = object.tags.find_all{ |tag| tag.tag_name == "param"}
|
|
||||||
param_details = @template_helper.extract_param_details(params, param_tags) unless params.nil?
|
|
||||||
@template_helper.check_types_match_docs object, param_details
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def parameter_details
|
|
||||||
return if object.parameters.empty?
|
|
||||||
|
|
||||||
param_tags = object.tags.find_all{ |tag| tag.tag_name == "param"}
|
|
||||||
params = object.parameters
|
|
||||||
|
|
||||||
@param_details = []
|
|
||||||
|
|
||||||
@param_details = @template_helper.extract_param_details(params, param_tags, true)
|
|
||||||
|
|
||||||
erb(:parameter_details)
|
|
||||||
end
|
|
||||||
|
|
||||||
def header
|
|
||||||
if object.type == :hostclass
|
|
||||||
@header_text = "Puppet Class: #{object.name}"
|
|
||||||
elsif object.type == :definedtype
|
|
||||||
@header_text = "Puppet Defined Type: #{object.name}"
|
|
||||||
else
|
|
||||||
@header_text = "#{object.name}"
|
|
||||||
end
|
|
||||||
|
|
||||||
erb(:header)
|
|
||||||
end
|
|
||||||
|
|
||||||
def docstring
|
|
||||||
|
|
||||||
@class_details = @template_helper.extract_tag_data(object)
|
|
||||||
|
|
||||||
erb(:docstring)
|
|
||||||
end
|
|
|
@ -1,2 +0,0 @@
|
||||||
<li><%= link_object(Registry.root, Registry.root.title, nil, false) %></li>
|
|
||||||
<%= namespace_list %>
|
|
|
@ -1 +0,0 @@
|
||||||
<%= namespace_list(:namespace_types => [:hostclass, :definedtype]) %>
|
|
|
@ -1,21 +0,0 @@
|
||||||
<% unless P(:root, 'Puppet3xFunctions').is_a?(CodeObjects::Proxy) %>
|
|
||||||
<li>
|
|
||||||
<a class='toggle'></a>
|
|
||||||
<%= link_object(P(:root, 'Puppet3xFunctions'), 'Puppet 3x Functions', nil, false) %>
|
|
||||||
<small class='search_info'>Puppet3xFunctions</small>
|
|
||||||
</li>
|
|
||||||
<ul>
|
|
||||||
<%= namespace_list(:root => P(:root,'Puppet3xFunctions'), :namespace_types => [:puppetnamespace, :method]) %>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% unless P(:root, 'Puppet4xFunctions').is_a?(CodeObjects::Proxy) %>
|
|
||||||
<li>
|
|
||||||
<a class='toggle'></a>
|
|
||||||
<%= link_object(P(:root, 'Puppet4xFunctions'), 'Puppet 4x Functions', nil, false) %>
|
|
||||||
<small class='search_info'>Puppet4xFunctions</small>
|
|
||||||
</li>
|
|
||||||
<ul>
|
|
||||||
<%= namespace_list(:root => P(:root,'Puppet4xFunctions'), :namespace_types => [:puppetnamespace, :method]) %>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
|
@ -1 +0,0 @@
|
||||||
<%= namespace_list(:namespace_types => [:provider]) %>
|
|
|
@ -1 +0,0 @@
|
||||||
<%= namespace_list(:namespace_types => [:type]) %>
|
|
|
@ -1,82 +0,0 @@
|
||||||
def generate_class_list
|
|
||||||
@items = options.objects.select{|o| [:module, :class, :root].include? o.type} if options.objects
|
|
||||||
@list_title = "Class List"
|
|
||||||
@list_type = "class"
|
|
||||||
generate_list_contents
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_puppet_manifest_list
|
|
||||||
@items = options.objects.select{|o| [:hostclass, :definedtype].include? o.type} if options.objects
|
|
||||||
@list_title = "Puppet Manifest List"
|
|
||||||
# This is important. It causes some YARD JavaScript bits to hook in and
|
|
||||||
# perform the correct formatting.
|
|
||||||
@list_class = "class"
|
|
||||||
@list_type = "puppet_manifest"
|
|
||||||
generate_list_contents
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_puppet_plugin_list
|
|
||||||
# NOTE: PuppetNamaspaceObject might eventually be used for more than just a
|
|
||||||
# container for plugins...
|
|
||||||
@items = options.objects.select{|o| [:puppetnamespace].include? o.type} if options.objects
|
|
||||||
@list_title = "Puppet Plugin List"
|
|
||||||
# This is important. It causes some YARD JavaScript bits to hook in and
|
|
||||||
# perform the correct formatting.
|
|
||||||
@list_class = "class"
|
|
||||||
@list_type = "puppet_plugin"
|
|
||||||
generate_list_contents
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_puppet_type_list
|
|
||||||
@items = options.objects.select{|o| [:type].include? o.type} if options.objects
|
|
||||||
@list_title = "Puppet Type List"
|
|
||||||
@list_type = "puppet_type"
|
|
||||||
generate_list_contents
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_puppet_provider_list
|
|
||||||
@items = options.objects.select{|o| [:provider].include? o.type} if options.objects
|
|
||||||
@list_title = "Puppet Provider List"
|
|
||||||
@list_type = "puppet_provider"
|
|
||||||
generate_list_contents
|
|
||||||
end
|
|
||||||
|
|
||||||
# A hacked version of class_list that can be instructed to only display certain
|
|
||||||
# namespace types. This allows us to separate Puppet bits from Ruby bits.
|
|
||||||
def namespace_list(opts = {})
|
|
||||||
o = {
|
|
||||||
:root => Registry.root,
|
|
||||||
:namespace_types => [:module, :class]
|
|
||||||
}.merge(opts)
|
|
||||||
|
|
||||||
root = o[:root]
|
|
||||||
namespace_types = o[:namespace_types]
|
|
||||||
|
|
||||||
out = ""
|
|
||||||
children = run_verifier(root.children)
|
|
||||||
if root == Registry.root
|
|
||||||
children += @items.select {|o| o.namespace.is_a?(CodeObjects::Proxy) }
|
|
||||||
end
|
|
||||||
children.reject {|c| c.nil? }.sort_by {|child| child.path }.map do |child|
|
|
||||||
if namespace_types.include? child.type
|
|
||||||
if child.namespace.is_a?(CodeObjects::Proxy)
|
|
||||||
name = child.path
|
|
||||||
elsif child.is_a?(PuppetX::Puppet::Strings::YARD::CodeObjects::TypeObject) || child.is_a?(PuppetX::Puppet::Strings::YARD::CodeObjects::ProviderObject)
|
|
||||||
name = child.header_name
|
|
||||||
else
|
|
||||||
name = child.name
|
|
||||||
end
|
|
||||||
has_children = child.respond_to?(:children) && run_verifier(child.children).any? {|o| o.is_a?(CodeObjects::NamespaceObject) }
|
|
||||||
out << "<li>"
|
|
||||||
out << "<a class='toggle'></a> " if has_children
|
|
||||||
out << linkify(child, name)
|
|
||||||
out << " < #{child.superclass.name}" if child.is_a?(CodeObjects::ClassObject) && child.superclass
|
|
||||||
out << "<small class='search_info'>"
|
|
||||||
out << child.namespace.title
|
|
||||||
out << "</small>"
|
|
||||||
out << "</li>"
|
|
||||||
out << "<ul>#{namespace_list(:root => child, :namespace_types => namespace_types)}</ul>" if has_children
|
|
||||||
end
|
|
||||||
end
|
|
||||||
out
|
|
||||||
end
|
|
|
@ -1,22 +0,0 @@
|
||||||
<% n = 1 %>
|
|
||||||
<dl class="box">
|
|
||||||
<% if object.parent_class %>
|
|
||||||
<dt class="r<%=n%>">Inherits:</dt>
|
|
||||||
<dd class="r<%=n%>">
|
|
||||||
<span class="inheritName"><%= linkify object.parent_class, object.parent_class.path %></span>
|
|
||||||
<ul class="fullTree">
|
|
||||||
<% object.inheritance_tree.reverse.each_with_index do |obj, i| %>
|
|
||||||
<li class="next"><%= obj == object ? obj.path : linkify(obj, obj.path) %></li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
<a href="#" class="inheritanceTree">show all</a>
|
|
||||||
</dd>
|
|
||||||
<% n = 2 %>
|
|
||||||
<% end %>
|
|
||||||
<% unless object.root? %>
|
|
||||||
<dt class="r<%=n%> last">Defined in:</dt>
|
|
||||||
<dd class="r<%=n%> last"><%= erb(:defines) %></dd>
|
|
||||||
<% end %>
|
|
||||||
</dl>
|
|
||||||
<div class="clear"></div>
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
include T('default/definedtype/html')
|
|
|
@ -1,4 +0,0 @@
|
||||||
<div id="subclasses">
|
|
||||||
<h2>Direct Known Subclasses</h2>
|
|
||||||
<p class="children"><%= @subclasses.map {|child| linkify(child, child.path) }.join(", ") %></p>
|
|
||||||
</div>
|
|
|
@ -1,21 +0,0 @@
|
||||||
include T('default/definedtype')
|
|
||||||
|
|
||||||
def init
|
|
||||||
super
|
|
||||||
sections.push :subclasses
|
|
||||||
end
|
|
||||||
|
|
||||||
def subclasses
|
|
||||||
# The naming is a bit weird because Ruby classes use `globals.subclasses`.
|
|
||||||
unless globals.hostsubclasses
|
|
||||||
globals.hostsubclasses = {}
|
|
||||||
list = run_verifier Registry.all(:hostclass)
|
|
||||||
list.each {|o| (globals.hostsubclasses[o.parent_class.path] ||= []) << o if o.parent_class }
|
|
||||||
end
|
|
||||||
|
|
||||||
@subclasses = globals.hostsubclasses[object.path]
|
|
||||||
|
|
||||||
return if @subclasses.nil? || @subclasses.empty?
|
|
||||||
erb(:subclasses)
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
# A class containing helper methods to aid the generation of HTML
|
|
||||||
# given formatted data
|
|
||||||
class HTMLHelper
|
|
||||||
|
|
||||||
# Generates the HTML to format the relevant data about return values
|
|
||||||
def generate_return_types(types, desc = nil)
|
|
||||||
result = []
|
|
||||||
|
|
||||||
result << "(<span class=\"type\"><tt>" << types.join(", ") << "</tt></span>)"
|
|
||||||
|
|
||||||
if !desc.nil?
|
|
||||||
result << "- <div class=\"inline\"><p>#{desc}</p></div>"
|
|
||||||
end
|
|
||||||
|
|
||||||
result.join
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_features features, object
|
|
||||||
result = []
|
|
||||||
|
|
||||||
if features
|
|
||||||
features.each do |feat|
|
|
||||||
result << "<li>"
|
|
||||||
result << "<span class=\"name\">#{feat[:name]} </span>"
|
|
||||||
if feat[:desc]
|
|
||||||
result << "- <br/><div class=\"inline\"><p> #{feat[:desc]} </p></div>"
|
|
||||||
end
|
|
||||||
if feat[:methods]
|
|
||||||
result << "<h3> Methods </h3>"
|
|
||||||
result << "<ul>"
|
|
||||||
feat[:methods].each do |method|
|
|
||||||
result << "<li> <tt>" << method << "</tt> </li>"
|
|
||||||
end
|
|
||||||
result << "</ul>"
|
|
||||||
end
|
|
||||||
result << "</li>"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
result.join
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generates the HTML to format the relevant data about parameters
|
|
||||||
def generate_parameters(params, object)
|
|
||||||
result = []
|
|
||||||
|
|
||||||
params.each do |param|
|
|
||||||
result << "<li>"
|
|
||||||
|
|
||||||
# Parameters which are documented in the comments but not
|
|
||||||
# present in the code itself are given the strike through
|
|
||||||
# styling in order to show the reader that they do not actually
|
|
||||||
# exist
|
|
||||||
if !param[:exists?]
|
|
||||||
result << "<strike>"
|
|
||||||
end
|
|
||||||
|
|
||||||
result << "<span class=\"name\">#{param[:name]} </span>"
|
|
||||||
result << "<span class=\"type\">"
|
|
||||||
|
|
||||||
# If the docstring specifies types, use those
|
|
||||||
if param[:types]
|
|
||||||
result << "(" << "<tt>" << param[:types].join(", ") << "</tt>" << ")"
|
|
||||||
# Otherwise, if typing information could be extracted from the object
|
|
||||||
# itself, use that
|
|
||||||
elsif object.type_info
|
|
||||||
# If the parameter name includes the default value, scrub that.
|
|
||||||
if param[:name].match(/([^=]*)=/)
|
|
||||||
param_name = $1
|
|
||||||
else
|
|
||||||
param_name = param[:name]
|
|
||||||
end
|
|
||||||
# Collect all the possible types from the object. If no such type
|
|
||||||
# exists for this parameter name don't do anything.
|
|
||||||
possible_types = object.type_info.map {
|
|
||||||
|sig| sig[param_name] or nil
|
|
||||||
}.compact
|
|
||||||
|
|
||||||
# If no possible types could be determined, put the type down as
|
|
||||||
# Unknown
|
|
||||||
if possible_types == []
|
|
||||||
result << "(" << "<tt>Unknown</tt>" << ")"
|
|
||||||
else
|
|
||||||
result << "(" << "<tt>" << possible_types.join(", ") << "</tt>" << ")"
|
|
||||||
end
|
|
||||||
# Give up. It can probably be anything.
|
|
||||||
elsif not (param[:puppet_3_func] or param[:puppet_type])
|
|
||||||
result << "(<tt>Unknown</tt>)"
|
|
||||||
end
|
|
||||||
if param[:puppet_type] and param[:parameter]
|
|
||||||
result << "(Parameter) "
|
|
||||||
elsif param[:puppet_type] and param[:property]
|
|
||||||
result << "(Property) "
|
|
||||||
end
|
|
||||||
|
|
||||||
if param[:namevar]
|
|
||||||
result << "(Namevar) "
|
|
||||||
end
|
|
||||||
if param[:default]
|
|
||||||
result << " Default value: <tt>" << param[:default] << "</tt> "
|
|
||||||
end
|
|
||||||
|
|
||||||
result << "</span>"
|
|
||||||
|
|
||||||
# This is only relevant for manifests, not puppet functions
|
|
||||||
# This is due to the fact that the scope of a parameter (as illustrated by
|
|
||||||
# by it's fully qualified name) is not relevant for the parameters in puppet
|
|
||||||
# functions, but may be for components of a manifest (i.e. classes)
|
|
||||||
unless param[:fq_name].nil?
|
|
||||||
result << "<tt> => #{param[:fq_name]}</tt>"
|
|
||||||
end
|
|
||||||
|
|
||||||
if param[:desc]
|
|
||||||
result << " - <div class=\"inline\"><p> #{param[:desc]} </p></div>"
|
|
||||||
end
|
|
||||||
|
|
||||||
if !param[:exists?]
|
|
||||||
result << "</strike>"
|
|
||||||
end
|
|
||||||
|
|
||||||
if param[:allowed_values] and param[:allowed_values] != []
|
|
||||||
result << "\n<b> Allowed Values: </b>"
|
|
||||||
result << "<ul>"
|
|
||||||
param[:allowed_values].each do |value_thing|
|
|
||||||
result << "<li>"
|
|
||||||
result << "<tt>" << value_thing.first << "</tt>"
|
|
||||||
if value_thing[1]
|
|
||||||
result << " only available if " << "<tt>" << value_thing[1] << "</tt>"
|
|
||||||
end
|
|
||||||
result << "</li>"
|
|
||||||
end
|
|
||||||
result << "</ul>\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
result << "</li>"
|
|
||||||
end
|
|
||||||
|
|
||||||
result.join
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,18 +0,0 @@
|
||||||
# TODO: This should be extendable. However, the re-assignment of
|
|
||||||
# @objects_by_letter prevents that. Submit a pull request.
|
|
||||||
def index
|
|
||||||
@objects_by_letter = {}
|
|
||||||
objects = Registry.all(:class, :module, :type, :puppetnamespace, :hostclass, :definedtype, :provider).sort_by {|o| o.name.to_s }
|
|
||||||
objects = run_verifier(objects)
|
|
||||||
objects.each {|o| (@objects_by_letter[o.name.to_s[0,1].upcase] ||= []) << o }
|
|
||||||
erb(:index)
|
|
||||||
end
|
|
||||||
|
|
||||||
def menu_lists
|
|
||||||
[
|
|
||||||
{:type => 'puppet_manifest', :title => 'Puppet Manifests', :search_title => "Puppet Manifest List"},
|
|
||||||
{:type => 'puppet_plugin', :title => 'Puppet Plugins', :search_title => "Puppet Plugin List"},
|
|
||||||
{:type => 'puppet_type', :title => 'Puppet Types', :search_title => "Puppet Type List"},
|
|
||||||
{:type => 'puppet_provider', :title => 'Puppet Providers', :search_title => "Puppet Provider List"},
|
|
||||||
] + super
|
|
||||||
end
|
|
|
@ -1,17 +0,0 @@
|
||||||
<h1>Method: <%= object.path %></h1>
|
|
||||||
<div class="box_info">
|
|
||||||
<dl>
|
|
||||||
<dt class="">Defined in:</dt>
|
|
||||||
<dd class="">
|
|
||||||
<%= object.file %><% if object.files.size > 1 %><span class="defines">,<br />
|
|
||||||
<%= object.files[1..-1].map {|f| f.first }.join(",<br /> ") %></div>
|
|
||||||
<% end %>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="method_details_list">
|
|
||||||
<div id="method_details">
|
|
||||||
<%= yieldall :index => 0 %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,21 +0,0 @@
|
||||||
include T('default/module')
|
|
||||||
require File.join(File.dirname(__FILE__),'../html_helper')
|
|
||||||
require File.join(File.dirname(__FILE__),'../template_helper')
|
|
||||||
|
|
||||||
def init
|
|
||||||
sections :header, [:method_signature, T('docstring'), :source]
|
|
||||||
parents = YARD::Registry.all(:method).reject do |item|
|
|
||||||
item.name == object.name and item.namespace === PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject
|
|
||||||
end
|
|
||||||
if parents.length == 0
|
|
||||||
@template_helper = TemplateHelper.new
|
|
||||||
@template_helper.check_parameters_match_docs object
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def source
|
|
||||||
return if owner != object.namespace
|
|
||||||
return if Tags::OverloadTag === object
|
|
||||||
return if object.source.nil?
|
|
||||||
erb(:source)
|
|
||||||
end
|
|
|
@ -1,2 +0,0 @@
|
||||||
<%= yieldall %>
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
<h2>Commands Summary</h2>
|
|
||||||
<div class="tags">
|
|
||||||
<ul class="command">
|
|
||||||
<% @command_details.each do |command| %>
|
|
||||||
<li><tt><%= command %></tt></li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<h2>Confines</h2>
|
|
||||||
<% if @confine_details != {} %>
|
|
||||||
<div class="tags">
|
|
||||||
<ul class="command">
|
|
||||||
<% @confine_details.each_pair do |key, value| %>
|
|
||||||
<li><tt><%= key %> - <%= value %></tt></li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<h2>Defaults</h2>
|
|
||||||
<% if @default_details != {} %>
|
|
||||||
<div class="tags">
|
|
||||||
<ul class="command">
|
|
||||||
<% @default_details.each_pair do |key, value| %>
|
|
||||||
<li><tt><%= key %> - <%= value %></tt></li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
|
@ -1,34 +0,0 @@
|
||||||
<div class="docstring">
|
|
||||||
<div class="discussion">
|
|
||||||
<p><%= htmlify(Puppet::Util::Docs::scrub(@class_details[:desc])) %></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tags">
|
|
||||||
<% if @class_details[:examples] != {}%>
|
|
||||||
<div class="examples">
|
|
||||||
<p class="tag_title">Examples:</p>
|
|
||||||
<% @class_details[:examples].each do |title, text| %>
|
|
||||||
<div class="inline"><p><%= title %></p></div>
|
|
||||||
<pre class="example code"><code><span><%= text %></span></code></pre>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<% if @class_details[:since] %>
|
|
||||||
<p class="tag_title">Since:</p>
|
|
||||||
<ul class="since">
|
|
||||||
<li>
|
|
||||||
<div class="inline">
|
|
||||||
<p><%= @class_details[:since] %></p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
||||||
<% if @class_details[:return] %>
|
|
||||||
<p class="tag_title">Return:</p>
|
|
||||||
<ul class="return">
|
|
||||||
<li>
|
|
||||||
<%= @html_helper.generate_return_types(@class_details[:return][1], @class_details[:return][0]) %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<h2>Features</h2>
|
|
||||||
<% if @feature_details != [] %>
|
|
||||||
<div class="tags">
|
|
||||||
<ul class="command">
|
|
||||||
<% @feature_details.each do |feature| %>
|
|
||||||
<li><tt><%= feature %></tt></li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<div class='module_header'>
|
|
||||||
<h1>
|
|
||||||
<%= @header_text %>
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
|
@ -1 +0,0 @@
|
||||||
include T('default/module/html')
|
|
|
@ -1,50 +0,0 @@
|
||||||
include T('default/module')
|
|
||||||
|
|
||||||
require File.join(File.dirname(__FILE__),'../html_helper')
|
|
||||||
require File.join(File.dirname(__FILE__),'../template_helper')
|
|
||||||
|
|
||||||
def init
|
|
||||||
sections :header, :box_info, :pre_docstring, :docstring, :command_details, :confine_details, :default_details, :feature_details
|
|
||||||
|
|
||||||
@template_helper = TemplateHelper.new
|
|
||||||
@html_helper = HTMLHelper.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def header
|
|
||||||
@header_text = object.header_name
|
|
||||||
|
|
||||||
erb(:header)
|
|
||||||
end
|
|
||||||
|
|
||||||
def command_details
|
|
||||||
@command_details = object.commands
|
|
||||||
erb(:command_details)
|
|
||||||
end
|
|
||||||
|
|
||||||
def confine_details
|
|
||||||
@confine_details = object.confines
|
|
||||||
erb(:confine_details)
|
|
||||||
end
|
|
||||||
|
|
||||||
def default_details
|
|
||||||
@default_details = object.defaults
|
|
||||||
erb(:default_details)
|
|
||||||
end
|
|
||||||
|
|
||||||
def feature_details
|
|
||||||
@feature_details = object.features
|
|
||||||
erb(:feature_details)
|
|
||||||
end
|
|
||||||
|
|
||||||
def header
|
|
||||||
@header_text = "Puppet Provider: #{object.name}"
|
|
||||||
|
|
||||||
erb(:header)
|
|
||||||
end
|
|
||||||
|
|
||||||
def docstring
|
|
||||||
|
|
||||||
@class_details = @template_helper.extract_tag_data(object)
|
|
||||||
|
|
||||||
erb(:docstring)
|
|
||||||
end
|
|
|
@ -1,11 +0,0 @@
|
||||||
<dl class="box">
|
|
||||||
<dt class="r1 last" style="height: 16px;">Defined in:</dt>
|
|
||||||
<dd class="r1 last">
|
|
||||||
<% @source_files.each do |file| %>
|
|
||||||
<em><%= file[0] %></em>:
|
|
||||||
<%= file[1] %>
|
|
||||||
<br/>
|
|
||||||
<% end %>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
<div class ="clear"></div>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<div class='module_header'>
|
|
||||||
<h1>
|
|
||||||
<%= @header_text %>
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
|
@ -1,53 +0,0 @@
|
||||||
<h2>Function Details</h2>
|
|
||||||
<% @class_details.each do |func| %>
|
|
||||||
<h3 class="signature" id = <%= "#{func[:name]}-instance_method" %>>
|
|
||||||
<strong>
|
|
||||||
<% if func[:return] %>
|
|
||||||
<%= @html_helper.generate_return_types(func[:return][1]) %>
|
|
||||||
<% end %>
|
|
||||||
<%= func[:name] %>
|
|
||||||
</strong>
|
|
||||||
</h3>
|
|
||||||
<div class="docstring">
|
|
||||||
<div class="discussion">
|
|
||||||
<p><%= htmlify(func[:desc]) %></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tags">
|
|
||||||
<% if func[:examples] != {}%>
|
|
||||||
<div class="examples">
|
|
||||||
<p class="tag_title">Examples:</p>
|
|
||||||
<% func[:examples].each do |title, text| %>
|
|
||||||
<div class="inline"><p><%= title %></p></div>
|
|
||||||
<pre class="example code"><code><span><%= text %></span></code></pre>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<% if func[:since] %>
|
|
||||||
<p class="tag_title">Since:</p>
|
|
||||||
<ul class="since">
|
|
||||||
<li>
|
|
||||||
<div class="inline">
|
|
||||||
<p><%= func[:since] %></p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
||||||
<% if func[:return] %>
|
|
||||||
<p class="tag_title">Returns:</p>
|
|
||||||
<ul class="return">
|
|
||||||
<li>
|
|
||||||
<%= @html_helper.generate_return_types(func[:return][1], func[:return][0]) %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
||||||
<% if func[:params] != nil %>
|
|
||||||
<p class="tag_title">Parameters:</p>
|
|
||||||
<div class="tags">
|
|
||||||
<ul class="param">
|
|
||||||
<%= @html_helper.generate_parameters(func[:params], object.child) %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
|
@ -1,20 +0,0 @@
|
||||||
<h2>Available Functions</h2>
|
|
||||||
<ul class="summary">
|
|
||||||
<% @method_details.each do |method| %>
|
|
||||||
<li class = "private">
|
|
||||||
<span class = "summary_signature">
|
|
||||||
<a href =<%= "##{method[:name]}-instance_method"%>>
|
|
||||||
<% if ! method[:return_types].nil? %>
|
|
||||||
<%= @html_helper.generate_return_types(method[:return_types]) %>
|
|
||||||
<% end %>
|
|
||||||
-
|
|
||||||
<strong><%= method[:name] %></strong>
|
|
||||||
</span>
|
|
||||||
</li></a>
|
|
||||||
<span class = "summary_desc">
|
|
||||||
<div class = "inline">
|
|
||||||
<p><%= method[:short_desc] %></p>
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
|
@ -1 +0,0 @@
|
||||||
include T('default/module/html')
|
|
|
@ -1,91 +0,0 @@
|
||||||
include T('default/module')
|
|
||||||
|
|
||||||
require File.join(File.dirname(__FILE__),'../html_helper')
|
|
||||||
require File.join(File.dirname(__FILE__),'../template_helper')
|
|
||||||
|
|
||||||
def init
|
|
||||||
sections :header, :box_info,
|
|
||||||
:method_summary, [:item_summary],
|
|
||||||
:method_details_list, [T('method_details')]
|
|
||||||
|
|
||||||
@methods = object.children
|
|
||||||
@template_helper = TemplateHelper.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def header
|
|
||||||
# The list is expected to only contain one type of function
|
|
||||||
if @methods[0]['puppet_4x_function']
|
|
||||||
@header_text = "Puppet 4 Functions"
|
|
||||||
else
|
|
||||||
@header_text = "Puppet 3 Functions"
|
|
||||||
end
|
|
||||||
|
|
||||||
erb(:header)
|
|
||||||
end
|
|
||||||
|
|
||||||
def box_info
|
|
||||||
@source_files = []
|
|
||||||
|
|
||||||
@methods.each do |method|
|
|
||||||
# extract the file name and line number for each method
|
|
||||||
file_name = method.files[0][0]
|
|
||||||
line_number = method.files[0][1]
|
|
||||||
|
|
||||||
@source_files.push([method.name, "#{file_name} (#{line_number})"])
|
|
||||||
end
|
|
||||||
|
|
||||||
erb(:box_info)
|
|
||||||
end
|
|
||||||
|
|
||||||
def method_summary
|
|
||||||
@method_details = []
|
|
||||||
@html_helper = HTMLHelper.new
|
|
||||||
|
|
||||||
@methods.each do |method|
|
|
||||||
# If there are multiple sentences in the method description, only
|
|
||||||
# use the first one for the summary. If the author did not include
|
|
||||||
# any periods in their summary, include the whole thing
|
|
||||||
first_sentence = method.docstring.match(/^(.*?)\./)
|
|
||||||
brief_summary = first_sentence ? first_sentence : method.docstring
|
|
||||||
|
|
||||||
return_tag = method.tags.find { |tag| tag.tag_name == "return"}
|
|
||||||
return_types = return_tag.nil? ? nil : return_tag.types
|
|
||||||
|
|
||||||
@method_details.push({:name => method.name, :short_desc => brief_summary, :return_types => return_types})
|
|
||||||
end
|
|
||||||
|
|
||||||
erb(:method_summary)
|
|
||||||
end
|
|
||||||
|
|
||||||
def method_details_list
|
|
||||||
@class_details = []
|
|
||||||
@html_helper = HTMLHelper.new
|
|
||||||
|
|
||||||
@methods.each do |object|
|
|
||||||
|
|
||||||
method_info = @template_helper.extract_tag_data(object)
|
|
||||||
param_details = nil
|
|
||||||
param_tags = object.tags.find_all{ |tag| tag.tag_name == "param"}
|
|
||||||
|
|
||||||
if object['puppet_4x_function']
|
|
||||||
# Extract the source code
|
|
||||||
source_code = object.source
|
|
||||||
# Extract the parameters for the source code
|
|
||||||
parameters = source_code.match(/(?:def .*)\((.*?)\)/)
|
|
||||||
# Convert the matched string into an array of strings
|
|
||||||
params = parameters.nil? ? nil : parameters[1].split(/\s*,\s*/)
|
|
||||||
|
|
||||||
param_details = @template_helper.extract_param_details(params, param_tags) unless params.nil?
|
|
||||||
@template_helper.check_types_match_docs object, param_details
|
|
||||||
@template_helper.check_parameters_match_docs object
|
|
||||||
else
|
|
||||||
param_details = @template_helper.comment_only_param_details(param_tags)
|
|
||||||
end
|
|
||||||
|
|
||||||
method_info[:params] = param_details
|
|
||||||
|
|
||||||
@class_details.push(method_info)
|
|
||||||
end
|
|
||||||
|
|
||||||
erb(:method_details_list)
|
|
||||||
end
|
|
|
@ -1,192 +0,0 @@
|
||||||
require "puppet"
|
|
||||||
|
|
||||||
# A class containing helper methods to aid in the extraction of relevant data
|
|
||||||
# from comments and YARD tags
|
|
||||||
class TemplateHelper
|
|
||||||
# Extracts data from comments which include the supported YARD tags
|
|
||||||
def extract_tag_data(object)
|
|
||||||
examples = Hash.new
|
|
||||||
example_tags = object.tags.find_all { |tag| tag.tag_name == "example" }
|
|
||||||
example_tags.each do |example|
|
|
||||||
examples["#{example.name}"] = example.text
|
|
||||||
end
|
|
||||||
|
|
||||||
return_tag = object.tags.find { |tag| tag.tag_name == "return"}
|
|
||||||
return_text = return_tag.nil? ? nil : return_tag.text
|
|
||||||
return_types = return_tag.nil? ? nil : return_tag.types
|
|
||||||
return_details = (return_text.nil? && return_types.nil?) ? nil : [return_text, return_types]
|
|
||||||
|
|
||||||
since_tag = object.tags.find { |tag| tag.tag_name == "since"}
|
|
||||||
since_text = since_tag.nil? ? nil : since_tag.text
|
|
||||||
|
|
||||||
{:name => object.name, :desc => object.docstring, :examples => examples, :since => since_text, :return => return_details}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Given the parameter information and YARD param tags, extracts the
|
|
||||||
# useful information and returns it as an array of hashes which can
|
|
||||||
# be printed and formatted as HTML
|
|
||||||
#
|
|
||||||
# @param parameters [Array] parameter details obtained programmatically
|
|
||||||
# @param tags_hash [Array] parameter details obtained from comments
|
|
||||||
# @param fq_name [Boolean] does this parameter have a fully qualified name?
|
|
||||||
#
|
|
||||||
# @return [Hash] The relevant information about each parameter with the following keys/values:
|
|
||||||
# {:name => [String] The name of the parameter
|
|
||||||
# :fq_name => [String] The fully qualified parameter name
|
|
||||||
# :desc => [String] The description provided in the comment
|
|
||||||
# :types => [Array] The parameter type(s) specified in the comment
|
|
||||||
# :exists => [Boolean] True only if the parameter exists in the documented logic and not just in a comment}
|
|
||||||
def extract_param_details(parameters, tags_hash, fq_name = false)
|
|
||||||
parameter_info = []
|
|
||||||
|
|
||||||
# Extract the information for parameters that exist
|
|
||||||
# as opposed to parameters that are defined only in the comments
|
|
||||||
parameters.each do |param|
|
|
||||||
if fq_name
|
|
||||||
param_name = param[0]
|
|
||||||
fully_qualified_name = param[1]
|
|
||||||
else
|
|
||||||
param_name = param
|
|
||||||
end
|
|
||||||
|
|
||||||
param_tag = tags_hash.find { |tag| tag.name == param_name }
|
|
||||||
|
|
||||||
description = param_tag.nil? ? nil : param_tag.text
|
|
||||||
param_types = param_tag.nil? ? nil : param_tag.types
|
|
||||||
|
|
||||||
param_details = {:name => param_name, :desc => description, :types => param_types, :exists? => true}
|
|
||||||
|
|
||||||
if fq_name
|
|
||||||
param_details[:fq_name] = fully_qualified_name
|
|
||||||
end
|
|
||||||
|
|
||||||
parameter_info.push(param_details)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check if there were any comments for parameters that do not exist
|
|
||||||
tags_hash.each do |tag|
|
|
||||||
param_exists = false
|
|
||||||
parameter_info.each do |parameter|
|
|
||||||
if parameter[:name] == tag.name
|
|
||||||
param_exists = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if !param_exists
|
|
||||||
parameter_info.push({:name => tag.name, :desc => tag.text, :types => tag.types, :exists? => false})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
parameter_info
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generates parameter information in situations where the information can only
|
|
||||||
# come from YARD tags in the comments, not from the code itself. For now the only
|
|
||||||
# use for this is 3x functions. In this case exists? will always be true since we
|
|
||||||
# cannot verify if the parameter exists in the code itself. We must trust the user
|
|
||||||
# to provide information in the comments that is accurate.
|
|
||||||
#
|
|
||||||
# @param param_tags [Array] parameter details obtained from comments
|
|
||||||
#
|
|
||||||
# @return [Hash] The relevant information about each parameter with the following keys/values:
|
|
||||||
# {:name => [String] The name of the parameter
|
|
||||||
# :desc => [String] The description provided in the comment
|
|
||||||
# :types => [Array] The parameter type(s) specified in the comment
|
|
||||||
# :exists => [Boolean] True only if the parameter exists in the documented logic and not just in a comment
|
|
||||||
# :puppet_3_func => [Boolean] Are these parameters for a puppet 3 function? (relevant in HTML generation)}
|
|
||||||
def comment_only_param_details(param_tags)
|
|
||||||
return if param_tags.empty?
|
|
||||||
|
|
||||||
parameter_info = []
|
|
||||||
|
|
||||||
param_tags.each do |tag|
|
|
||||||
parameter_info.push({:name => tag.name, :desc => tag.text, :types => tag.types, :exists? => true, :puppet_3_func => true})
|
|
||||||
end
|
|
||||||
|
|
||||||
parameter_info
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check that any types specified in the docstrings match the actual method
|
|
||||||
# types. This is used by puppet 4x functions and defined types.
|
|
||||||
# @param object the code object to examine for parameters names
|
|
||||||
def check_types_match_docs(object, params_hash)
|
|
||||||
# We'll need this to extract type info from the type specified by the
|
|
||||||
# docstring.
|
|
||||||
type_parser = Puppet::Pops::Types::TypeParser.new
|
|
||||||
type_calculator = Puppet::Pops::Types::TypeCalculator.new
|
|
||||||
|
|
||||||
object.type_info.each do |function|
|
|
||||||
function.keys.each do |key|
|
|
||||||
if function[key].class == String
|
|
||||||
begin
|
|
||||||
instantiated = type_parser.parse function[key]
|
|
||||||
rescue Puppet::ParseError
|
|
||||||
# Likely the result of a malformed type
|
|
||||||
next
|
|
||||||
end
|
|
||||||
else
|
|
||||||
instantiated = function[key]
|
|
||||||
end
|
|
||||||
params_hash.each do |param|
|
|
||||||
if param[:name] == key and param[:types] != nil
|
|
||||||
param[:types].each do |type|
|
|
||||||
param_instantiated = type_parser.parse type
|
|
||||||
if not type_calculator.assignable? instantiated, param_instantiated
|
|
||||||
actual_types = object.type_info.map do |sig|
|
|
||||||
sig[key].to_s if sig[key]
|
|
||||||
end.compact
|
|
||||||
# Get the locations where the object can be found. We only care about
|
|
||||||
# the first one.
|
|
||||||
locations = object.files
|
|
||||||
warning = <<-EOS
|
|
||||||
[warn]: @param tag types do not match the code. The #{param[:name]}
|
|
||||||
parameter is declared as types #{param[:types]} in the docstring,
|
|
||||||
but the code specifies the types #{actual_types}
|
|
||||||
EOS
|
|
||||||
|
|
||||||
# If the locations aren't in the shape we expect then report that
|
|
||||||
# the file number couldn't be determined.
|
|
||||||
if locations.length >= 1 and locations[0].length == 2
|
|
||||||
file = locations[0][0]
|
|
||||||
line = locations[0][1]
|
|
||||||
warning += " in the file #{file} near line #{line}."
|
|
||||||
else
|
|
||||||
warning += " Sorry, the file and line number could " +
|
|
||||||
"not be determined."
|
|
||||||
end
|
|
||||||
$stderr.puts warning
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check that the actual function parameters match what is stated in the docs.
|
|
||||||
# If there is a mismatch, print a warning to stderr.
|
|
||||||
# This is necessary for puppet classes and defined types. This type of
|
|
||||||
# warning will be issued for ruby code by the ruby docstring parser.
|
|
||||||
# @param object the code object to examine for parameters names
|
|
||||||
def check_parameters_match_docs(object)
|
|
||||||
param_tags = object.tags.find_all{ |tag| tag.tag_name == "param"}
|
|
||||||
names = object.parameters.map {|l| l.first.gsub(/\W/, '') }
|
|
||||||
locations = object.files
|
|
||||||
param_tags.each do |tag|
|
|
||||||
if not names.include?(tag.name)
|
|
||||||
if locations.length >= 1 and locations[0].length == 2
|
|
||||||
file_name = locations[0][0]
|
|
||||||
line_number = locations[0][1]
|
|
||||||
$stderr.puts <<-EOS
|
|
||||||
[warn]: The parameter #{tag.name} is documented, but doesn't exist in
|
|
||||||
your code, in file #{file_name} near line #{line_number}.
|
|
||||||
EOS
|
|
||||||
else
|
|
||||||
$stderr.puts <<-EOS
|
|
||||||
[warn]: The parameter #{tag.name} is documented, but doesn't exist in
|
|
||||||
your code. Sorry, the file and line number could not be determined.
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,34 +0,0 @@
|
||||||
<div class="docstring">
|
|
||||||
<div class="discussion">
|
|
||||||
<p><%= htmlify(Puppet::Util::Docs::scrub(@class_details[:desc])) %></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tags">
|
|
||||||
<% if @class_details[:examples] != {}%>
|
|
||||||
<div class="examples">
|
|
||||||
<p class="tag_title">Examples:</p>
|
|
||||||
<% @class_details[:examples].each do |title, text| %>
|
|
||||||
<div class="inline"><p><%= title %></p></div>
|
|
||||||
<pre class="example code"><code><span><%= text %></span></code></pre>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<% if @class_details[:since] %>
|
|
||||||
<p class="tag_title">Since:</p>
|
|
||||||
<ul class="since">
|
|
||||||
<li>
|
|
||||||
<div class="inline">
|
|
||||||
<p><%= @class_details[:since] %></p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
||||||
<% if @class_details[:return] %>
|
|
||||||
<p class="tag_title">Return:</p>
|
|
||||||
<ul class="return">
|
|
||||||
<li>
|
|
||||||
<%= @html_helper.generate_return_types(@class_details[:return][1], @class_details[:return][0]) %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<div class='module_header'>
|
|
||||||
<h1>
|
|
||||||
<%= @header_text %>
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
|
@ -1,12 +0,0 @@
|
||||||
<h2>Parameter Summary</h2>
|
|
||||||
<div class="tags">
|
|
||||||
<ul class="param">
|
|
||||||
<%= @html_helper.generate_parameters(@param_details, object) %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<h2>Features</h2>
|
|
||||||
<div class="tags">
|
|
||||||
<ul class="feature">
|
|
||||||
<%= @html_helper.generate_features(@feature_details, object) %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<h2>Available Providers</h2>
|
|
||||||
<% if @providers != [] %>
|
|
||||||
<div class="tags">
|
|
||||||
<ul class="command">
|
|
||||||
<% @providers.each do |provider| %>
|
|
||||||
<li><a href="<%= provider.name.to_s %>.html"><tt><%= provider.name.to_s %></tt></a></li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
|
@ -1 +0,0 @@
|
||||||
include T('default/module/html')
|
|
|
@ -1,55 +0,0 @@
|
||||||
include T('default/module')
|
|
||||||
|
|
||||||
require File.join(File.dirname(__FILE__),'../html_helper')
|
|
||||||
require File.join(File.dirname(__FILE__),'../template_helper')
|
|
||||||
|
|
||||||
def init
|
|
||||||
sections :header, :box_info, :pre_docstring, :docstring, :parameter_details, :provider_details
|
|
||||||
|
|
||||||
@template_helper = TemplateHelper.new
|
|
||||||
@html_helper = HTMLHelper.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def header
|
|
||||||
@header_text = object.header_name
|
|
||||||
|
|
||||||
erb(:header)
|
|
||||||
end
|
|
||||||
|
|
||||||
def provider_details
|
|
||||||
type_name = object.name.to_s
|
|
||||||
@providers = YARD::Registry.all(:provider).select { |t| t.type_name == type_name }
|
|
||||||
|
|
||||||
erb(:provider_details)
|
|
||||||
end
|
|
||||||
|
|
||||||
def parameter_details
|
|
||||||
params = object.parameter_details.map { |h| h[:name] }
|
|
||||||
# Put properties and parameters in one big list where the descriptions are
|
|
||||||
# scrubbed and htmlified and the namevar is the first element, the ensure
|
|
||||||
# property the second, and the rest are alphabetized.
|
|
||||||
@param_details = (object.parameter_details + object.property_details).each {
|
|
||||||
|h| h[:desc] = htmlify(Puppet::Util::Docs::scrub(h[:desc])) if h[:desc]
|
|
||||||
}.sort { |a, b| a[:name] <=> b[:name] }
|
|
||||||
# Float ensurable and namevars to the top of the list
|
|
||||||
@param_details = @param_details.partition{|a| a[:name] == 'ensure'}.flatten
|
|
||||||
@param_details = @param_details.partition{|a| a[:namevar]}.flatten
|
|
||||||
|
|
||||||
@feature_details = object.features
|
|
||||||
@template_helper.check_parameters_match_docs object
|
|
||||||
|
|
||||||
erb(:parameter_details)
|
|
||||||
end
|
|
||||||
|
|
||||||
def header
|
|
||||||
@header_text = "Puppet Type: #{object.name}"
|
|
||||||
|
|
||||||
erb(:header)
|
|
||||||
end
|
|
||||||
|
|
||||||
def docstring
|
|
||||||
|
|
||||||
@class_details = @template_helper.extract_tag_data(object)
|
|
||||||
|
|
||||||
erb(:docstring)
|
|
||||||
end
|
|
|
@ -18,5 +18,5 @@ Gem::Specification.new do |s|
|
||||||
s.files = `git ls-files`.split("\n") - Dir['.*', '*.gemspec']
|
s.files = `git ls-files`.split("\n") - Dir['.*', '*.gemspec']
|
||||||
|
|
||||||
s.add_runtime_dependency 'puppet', '>= 3.7.0'
|
s.add_runtime_dependency 'puppet', '>= 3.7.0'
|
||||||
s.add_runtime_dependency 'yard', '~> 0.8'
|
s.add_runtime_dependency 'yard', '~> 0.9.5'
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
class PuppetModuleHelper
|
|
||||||
# Helper methods to handle file operations around generating and loading HTML
|
|
||||||
def self.using_module(path, modulename, &block)
|
|
||||||
Dir.mktmpdir do |tmp|
|
|
||||||
module_location = File.join(path, "examples", modulename)
|
|
||||||
FileUtils.cp_r(module_location, tmp)
|
|
||||||
old_dir = Dir.pwd
|
|
||||||
begin
|
|
||||||
Dir.chdir(tmp)
|
|
||||||
yield(tmp)
|
|
||||||
ensure
|
|
||||||
Dir.chdir(old_dir)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.read_html(dir, modulename, file)
|
|
||||||
File.read(File.join(dir, modulename, 'doc', file))
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,42 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
module StringsSpec
|
|
||||||
module Parsing
|
|
||||||
|
|
||||||
# Cleans up the Registry and gives YARD some source code
|
|
||||||
# to generate documentation for
|
|
||||||
def parse(string, parser = :ruby)
|
|
||||||
YARD::Registry.clear
|
|
||||||
YARD::Parser::SourceParser.parse_string(string, parser)
|
|
||||||
end
|
|
||||||
|
|
||||||
# A custom matcher that allows us to compare aspects of a
|
|
||||||
# Code Objects to the specified values. This gives us a
|
|
||||||
# simplified way to ensure that the Code Object added to the
|
|
||||||
# Registry is what we expect when testing handlers
|
|
||||||
RSpec::Matchers.define :document_a do |arguments|
|
|
||||||
match do |actual|
|
|
||||||
@mismatches = compare_values(actual, arguments)
|
|
||||||
@mismatches.empty?
|
|
||||||
end
|
|
||||||
|
|
||||||
failure_message do |actual|
|
|
||||||
@mismatches.collect do |key, value|
|
|
||||||
"Expected #{key} to be <#{value[1]}>, but got <#{value[0]}>."
|
|
||||||
end.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def compare_values(actual, expected)
|
|
||||||
mismatched_arguments = {}
|
|
||||||
expected.each do |key, value|
|
|
||||||
actual_value = actual.send(key)
|
|
||||||
if actual_value != value
|
|
||||||
mismatched_arguments[key] = [actual_value, value]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
mismatched_arguments
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ require 'mocha'
|
||||||
require 'puppet'
|
require 'puppet'
|
||||||
require 'rspec'
|
require 'rspec'
|
||||||
|
|
||||||
require 'puppet_x/puppet/strings'
|
require 'puppet-strings'
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.mock_with :mocha
|
config.mock_with :mocha
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
# function 4x
|
|
||||||
#
|
|
||||||
# This is a function which is used to test puppet strings
|
|
||||||
Puppet::Functions.create_function(:function4x) do
|
|
||||||
end
|
|
|
@ -1,3 +0,0 @@
|
||||||
Puppet::Parser::Functions.newfunction(:function3x, :doc => "This is the
|
|
||||||
function documentation for `function3x`") do |args|
|
|
||||||
end
|
|
|
@ -1,27 +0,0 @@
|
||||||
# Class: test
|
|
||||||
#
|
|
||||||
# This class exists to serve as fixture data for testing the puppet strings face
|
|
||||||
#
|
|
||||||
# @example
|
|
||||||
# class { "test": }
|
|
||||||
#
|
|
||||||
# @param package_name The name of the package
|
|
||||||
# @param service_name The name of the service
|
|
||||||
class test (
|
|
||||||
$package_name = $test::params::package_name,
|
|
||||||
$service_name = $test::params::service_name,
|
|
||||||
|
|
||||||
) inherits test::params {
|
|
||||||
|
|
||||||
# validate parameters here
|
|
||||||
|
|
||||||
class { 'test::install': } ->
|
|
||||||
class { 'test::config': } ~>
|
|
||||||
class { 'test::service': } ->
|
|
||||||
Class['test']
|
|
||||||
|
|
||||||
File {
|
|
||||||
owner => 'user',
|
|
||||||
path => 'some/file/path',
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
# Testing tested classes
|
|
||||||
# docs stuff
|
|
||||||
# @param nameservers [String] Don't ask me what this does!
|
|
||||||
# @param default_lease_time [Integer[1024, 8192]] text goes here
|
|
||||||
# @param max_lease_time does stuff
|
|
||||||
class outer (
|
|
||||||
$dnsdomain,
|
|
||||||
$nameservers,
|
|
||||||
$default_lease_time = 3600,
|
|
||||||
$max_lease_time = 86400
|
|
||||||
) {
|
|
||||||
# @param options [String[5,7]] gives user choices
|
|
||||||
# @param multicast [Boolean] foobar
|
|
||||||
# @param servers yep, that's right
|
|
||||||
class middle (
|
|
||||||
$options = "iburst",
|
|
||||||
$servers,
|
|
||||||
$multicast = false
|
|
||||||
) {
|
|
||||||
class inner (
|
|
||||||
$choices = "uburst",
|
|
||||||
$secenekler = "weallburst",
|
|
||||||
$boxen,
|
|
||||||
$manyspell = true
|
|
||||||
) {}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"name": "username-test",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"author": "username",
|
|
||||||
"license": "Apache 2.0"
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
require 'lib/strings_spec/module_helper'
|
|
||||||
require 'puppet/face/strings'
|
|
||||||
require 'tmpdir'
|
|
||||||
require 'stringio'
|
|
||||||
|
|
||||||
describe Puppet::Face do
|
|
||||||
|
|
||||||
describe "YARDoc action" do
|
|
||||||
it "should raise an error if yard is absent" do
|
|
||||||
Puppet.features.stubs(:yard?).returns(false)
|
|
||||||
expect{Puppet::Face[:strings, :current].yardoc}.to raise_error(RuntimeError, "The 'yard' gem must be installed in order to use this face.")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should raise an error if rgen is absent" do
|
|
||||||
Puppet.features.stubs(:rgen?).returns(false)
|
|
||||||
expect{Puppet::Face[:strings, :current].yardoc}.to raise_error(RuntimeError, "The 'rgen' gem must be installed in order to use this face.")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should raise an error if the Ruby verion is less than 1.9", :if => RUBY_VERSION.match(/^1\.8/) do
|
|
||||||
expect{Puppet::Face[:strings, :current].yardoc}.to raise_error(RuntimeError, "This face requires Ruby 1.9 or greater.")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should invoke Yardoc with MODULE_SOURCEFILES if no arguments are provided" do
|
|
||||||
YARD::CLI::Yardoc.expects(:run).with('manifests/**/*.pp', 'lib/**/*.rb')
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should invoke Yardoc with provided arguments" do
|
|
||||||
YARD::CLI::Yardoc.expects(:run).with('--debug', 'some_file.rb')
|
|
||||||
Puppet::Face[:strings, :current].yardoc('--debug', 'some_file.rb')
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "when generating HTML for documentation" do
|
|
||||||
|
|
||||||
# HACK: In these tests we would like to suppress all output from the yard
|
|
||||||
# logger so we don't clutter up stdout.
|
|
||||||
# However, we do want the yard logger for other tests so we can
|
|
||||||
# assert that the right things are logged. To accomplish this, for
|
|
||||||
# this block of tests we monkeypatch the yard logger to be a generic
|
|
||||||
# stringio instance which does nothing and then we restore the
|
|
||||||
# original afterwards.
|
|
||||||
before(:all) do
|
|
||||||
@tmp = YARD::Logger.instance.io
|
|
||||||
YARD::Logger.instance.io = StringIO.new
|
|
||||||
end
|
|
||||||
|
|
||||||
after(:all) do
|
|
||||||
YARD::Logger.instance.io = @tmp
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should properly generate HTML for manifest comments" do
|
|
||||||
|
|
||||||
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__), 'test') do |tmp|
|
|
||||||
Dir.chdir('test')
|
|
||||||
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
|
|
||||||
expect(PuppetModuleHelper.read_html(tmp, 'test', 'test.html')).to include("Class: test")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should properly generate HTML for 3x function comments" do
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__), 'test') do |tmp|
|
|
||||||
Dir.chdir('test')
|
|
||||||
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
|
|
||||||
expect(PuppetModuleHelper.read_html(tmp, 'test', 'Puppet3xFunctions.html')).to include("This is the function documentation for `function3x`")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should properly generate HTML for 4x function comments" do
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__), 'test') do |tmp|
|
|
||||||
Dir.chdir('test')
|
|
||||||
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
|
|
||||||
expect(PuppetModuleHelper.read_html(tmp, 'test', 'Puppet4xFunctions.html')).to include("This is a function which is used to test puppet strings")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should create correct files for nested classes" do
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__), 'test') do |tmp|
|
|
||||||
Dir.chdir('test')
|
|
||||||
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
|
|
||||||
expect(PuppetModuleHelper.read_html(tmp,
|
|
||||||
'test', 'outer.html')).to include("Puppet Class: outer")
|
|
||||||
expect(PuppetModuleHelper.read_html(tmp, 'test',
|
|
||||||
'outer/middle.html')).to include("Puppet Class: middle")
|
|
||||||
expect(PuppetModuleHelper.read_html(tmp, 'test',
|
|
||||||
'outer/middle/inner.html')).to include("Puppet Class: inner")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should create proper namespace for nested classes" do
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__), 'test') do |tmp|
|
|
||||||
Dir.chdir('test')
|
|
||||||
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
|
|
||||||
expect(PuppetModuleHelper.read_html(tmp,
|
|
||||||
'test', 'outer.html')).to include("Hostclass: outer")
|
|
||||||
expect(PuppetModuleHelper.read_html(tmp, 'test',
|
|
||||||
'outer/middle.html')).to include("Hostclass: outer::middle")
|
|
||||||
expect(PuppetModuleHelper.read_html(tmp, 'test',
|
|
||||||
'outer/middle/inner.html')).to include("Hostclass: outer::middle::inner")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "server action" do
|
|
||||||
it "should raise an error if yard is absent" do
|
|
||||||
Puppet.features.stubs(:yard?).returns(false)
|
|
||||||
expect{Puppet::Face[:strings, :current].server}.to raise_error(RuntimeError, "The 'yard' gem must be installed in order to use this face.")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should raise an error if rgen is absent" do
|
|
||||||
Puppet.features.stubs(:rgen?).returns(false)
|
|
||||||
expect{Puppet::Face[:strings, :current].server}.to raise_error(RuntimeError, "The 'rgen' gem must be installed in order to use this face.")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should raise an error if the Ruby version is less than 1.9", :if => RUBY_VERSION.match(/^1\.8/) do
|
|
||||||
expect{Puppet::Face[:strings, :current].server}.to raise_error(RuntimeError, "This face requires Ruby 1.9 or greater.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
require 'puppet_x/puppet/strings/pops/yard_statement'
|
|
||||||
|
|
||||||
describe PuppetX::Puppet::Strings::Pops do
|
|
||||||
let(:parser) {Puppet::Pops::Parser::Parser.new()}
|
|
||||||
|
|
||||||
describe "YARDstatement class" do
|
|
||||||
let(:manifest) {"#hello world\nclass foo { }"}
|
|
||||||
let(:model) {parser.parse_string(manifest).current.definitions.first}
|
|
||||||
let(:test_statement) {PuppetX::Puppet::Strings::Pops::YARDStatement.new(model)}
|
|
||||||
|
|
||||||
describe "when creating a new instance of YARDStatement" do
|
|
||||||
it "should extract comments from the source code" do
|
|
||||||
expect(test_statement.comments).to match(/^#hello world/)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "YARDTransfomer class" do
|
|
||||||
let(:manifest) {"#hello world\nclass foo($bar) { }"}
|
|
||||||
let(:manifest_default) {"#hello world\nclass foo($bar = 3) { }"}
|
|
||||||
let(:transformer) {PuppetX::Puppet::Strings::Pops::YARDTransformer.new}
|
|
||||||
|
|
||||||
describe "transform method" do
|
|
||||||
it "should perform the correct transformation with parameter defaults" do
|
|
||||||
model = parser.parse_string(manifest_default).current.definitions.first
|
|
||||||
statements = transformer.transform(model)
|
|
||||||
expect(statements.parameters[0][0].class).to be(PuppetX::Puppet::Strings::Pops::YARDStatement)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should perform the correct transofmration without parameter defaults" do
|
|
||||||
model = parser.parse_string(manifest).current.definitions.first
|
|
||||||
statements = transformer.transform(model)
|
|
||||||
expect(statements.parameters[0][1].class).to be(NilClass)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,74 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/defined_type_handler'
|
|
||||||
require 'strings_spec/parsing'
|
|
||||||
|
|
||||||
|
|
||||||
describe PuppetX::Puppet::Strings::YARD::Handlers::DefinedTypeHandler do
|
|
||||||
include StringsSpec::Parsing
|
|
||||||
|
|
||||||
def the_definedtype()
|
|
||||||
YARD::Registry.at("foo::bar")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse single-line documentation strings before a given defined type" do
|
|
||||||
comment = "Definition: foo::bar"
|
|
||||||
puppet_code = <<-PUPPET
|
|
||||||
# #{comment}
|
|
||||||
define foo::bar ($baz) { }
|
|
||||||
PUPPET
|
|
||||||
|
|
||||||
parse(puppet_code, :puppet)
|
|
||||||
|
|
||||||
expect(the_definedtype).to document_a(:type => :definedtype, :docstring => comment)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse multi-line documentation strings before a given defined type" do
|
|
||||||
puppet_code = <<-PUPPET
|
|
||||||
# Definition: foo::bar
|
|
||||||
#
|
|
||||||
# This class does some stuff
|
|
||||||
define foo::bar ($baz) { }
|
|
||||||
PUPPET
|
|
||||||
|
|
||||||
parse(puppet_code, :puppet)
|
|
||||||
|
|
||||||
comment = "Definition: foo::bar\n\nThis class does some stuff"
|
|
||||||
expect(the_definedtype).to document_a(:type => :definedtype, :docstring => comment)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not parse documentation before a function if it is followed by a new line" do
|
|
||||||
puppet_code = <<-PUPPET
|
|
||||||
# Definition: foo::bar
|
|
||||||
|
|
||||||
define foo::bar ($baz) { }
|
|
||||||
PUPPET
|
|
||||||
|
|
||||||
parse(puppet_code, :puppet)
|
|
||||||
|
|
||||||
expect(the_definedtype).to document_a(:type => :definedtype, :docstring => "")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not add anything to the Registry if incorrect puppet code is present" do
|
|
||||||
puppet_code = <<-PUPPET
|
|
||||||
# Definition: foo::bar
|
|
||||||
This is not puppet code
|
|
||||||
PUPPET
|
|
||||||
|
|
||||||
parse(puppet_code, :puppet)
|
|
||||||
|
|
||||||
expect(YARD::Registry.all).to be_empty
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should generate the correct namespace " do
|
|
||||||
puppet_code = <<-PUPPET
|
|
||||||
define puppet_enterprise::mcollective::client::certs { }
|
|
||||||
PUPPET
|
|
||||||
|
|
||||||
parse(puppet_code, :puppet)
|
|
||||||
# If the namespace is not correctly generated, we will not be able to find the
|
|
||||||
# object via this name, meaning namespace will be nil
|
|
||||||
namespace = YARD::Registry.at("puppet_enterprise::mcollective::client::certs").namespace.to_s
|
|
||||||
|
|
||||||
expect(namespace).to_not be_nil
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,18 +0,0 @@
|
||||||
# @param not_a_param [Integer] the first number to be compared
|
|
||||||
# @param also_not_a_param [Integer] the second number to be compared
|
|
||||||
Puppet::Functions.create_function(:max) do
|
|
||||||
dispatch max_1 do
|
|
||||||
param 'Integer[1,2]', :num_a
|
|
||||||
param 'Integer', :num_b
|
|
||||||
end
|
|
||||||
dispatch max_2 {
|
|
||||||
param 'String', :num_c
|
|
||||||
param 'String[1,2]', :num_d
|
|
||||||
}
|
|
||||||
def max_1(num_a, num_b)
|
|
||||||
num_a >= num_b ? num_a : num_b
|
|
||||||
end
|
|
||||||
def max_2(num_a, num_b)
|
|
||||||
num_a >= num_b ? num_a : num_b
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,7 +0,0 @@
|
||||||
# @param not_a_param [Integer[1,2]] the first number to be compared
|
|
||||||
# @param also_not_a_param [Integer[1,2]] the second number to be compared
|
|
||||||
Puppet::Functions.create_function(:max) do
|
|
||||||
def max(num_a, num_b)
|
|
||||||
num_a >= num_b ? num_a : num_b
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,7 +0,0 @@
|
||||||
# @param not_a_param [Integer] the first number to be compared
|
|
||||||
# @param also_not_a_param [Integer] the second number to be compared
|
|
||||||
Puppet::Functions.create_function(:max) do
|
|
||||||
def max(num_a, num_b)
|
|
||||||
num_a >= num_b ? num_a : num_b
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,11 +0,0 @@
|
||||||
# @param [Integer] num_a the first number to be compared
|
|
||||||
# @param num_b [Integer] the second number to be compared
|
|
||||||
Puppet::Functions.create_function(:max) do
|
|
||||||
dispatch max_1 do
|
|
||||||
param 'Integer', :num_a
|
|
||||||
param 'Integer', :num_b
|
|
||||||
end
|
|
||||||
def max_1(num_a, num_b)
|
|
||||||
num_a >= num_b ? num_a : num_b
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,7 +0,0 @@
|
||||||
# @param num_a [Integer[1,2]] the first number to be compared
|
|
||||||
# @param num_b [Integer[1,2]] the second number to be compared
|
|
||||||
Puppet::Functions.create_function(:max)do
|
|
||||||
def max(num_a, num_b)
|
|
||||||
num_a >= num_b ? num_a : num_b
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,7 +0,0 @@
|
||||||
# @param num_a [Integer] the first number to be compared
|
|
||||||
# @param num_b [Integer] the second number to be compared
|
|
||||||
Puppet::Functions.create_function(:max)do
|
|
||||||
def max(num_a, num_b)
|
|
||||||
num_a >= num_b ? num_a : num_b
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,7 +0,0 @@
|
||||||
# @param [Float] ident identification
|
|
||||||
class foo( String $ident = "Bob" , Integer $age = 10, )
|
|
||||||
{
|
|
||||||
notify {'$ident':}
|
|
||||||
notify {'$age':}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
require 'lib/strings_spec/module_helper'
|
|
||||||
require 'puppet/face/strings'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/host_class_handler'
|
|
||||||
require 'strings_spec/parsing'
|
|
||||||
|
|
||||||
describe PuppetX::Puppet::Strings::YARD::Handlers::HostClassHandler do
|
|
||||||
include StringsSpec::Parsing
|
|
||||||
|
|
||||||
def the_hostclass()
|
|
||||||
YARD::Registry.at("foo::bar")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse single-line documentation strings before a given class" do
|
|
||||||
comment = "Class: foo::bar"
|
|
||||||
puppet_code = <<-PUPPET
|
|
||||||
# #{comment}
|
|
||||||
class foo::bar { }
|
|
||||||
PUPPET
|
|
||||||
|
|
||||||
parse(puppet_code, :puppet)
|
|
||||||
|
|
||||||
expect(the_hostclass).to document_a(:type => :hostclass, :docstring => comment)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse multi-line documentation strings before a given class" do
|
|
||||||
puppet_code = <<-PUPPET
|
|
||||||
# Class: foo::bar
|
|
||||||
#
|
|
||||||
# This class does some stuff
|
|
||||||
class foo::bar { }
|
|
||||||
PUPPET
|
|
||||||
|
|
||||||
parse(puppet_code, :puppet)
|
|
||||||
|
|
||||||
comment = "Class: foo::bar\n\nThis class does some stuff"
|
|
||||||
expect(the_hostclass).to document_a(:type => :hostclass, :docstring => comment)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not parse documentation before a class if it is followed by a new line" do
|
|
||||||
puppet_code = <<-PUPPET
|
|
||||||
# Class: foo::bar
|
|
||||||
|
|
||||||
class foo::bar { }
|
|
||||||
PUPPET
|
|
||||||
|
|
||||||
parse(puppet_code, :puppet)
|
|
||||||
|
|
||||||
expect(the_hostclass).to document_a(:type => :hostclass, :docstring => "")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should generate the correct namespace " do
|
|
||||||
puppet_code = <<-PUPPET
|
|
||||||
class puppet_enterprise::mcollective::client::certs { }
|
|
||||||
PUPPET
|
|
||||||
|
|
||||||
parse(puppet_code, :puppet)
|
|
||||||
# If the namespace is not correctly generated, we will not be able to find the
|
|
||||||
# object via this name, meaning namespace will be nil
|
|
||||||
namespace = YARD::Registry.at("puppet_enterprise::mcollective::client::certs")
|
|
||||||
|
|
||||||
expect(namespace).to_not be_nil
|
|
||||||
end
|
|
||||||
it "should not issue just one warning if the parameter types don't match." do
|
|
||||||
YARD::Registry.clear
|
|
||||||
# FIXME The type information here will change with the next version of
|
|
||||||
# puppet. `expected` is the output expected from the stable branch. The
|
|
||||||
# output from the master branch will use this instead:
|
|
||||||
# "...specifies the types [String] in file..."
|
|
||||||
expected_stout = <<-output
|
|
||||||
Files: 1
|
|
||||||
Modules: 0 ( 0 undocumented)
|
|
||||||
Classes: 0 ( 0 undocumented)
|
|
||||||
Constants: 0 ( 0 undocumented)
|
|
||||||
Methods: 0 ( 0 undocumented)
|
|
||||||
Puppet Classes: 1 ( 0 undocumented)
|
|
||||||
Puppet Defined Types: 0 ( 0 undocumented)
|
|
||||||
Puppet Types: 0 ( 0 undocumented)
|
|
||||||
Puppet Providers: 0 ( 0 undocumented)
|
|
||||||
100.00% documented
|
|
||||||
output
|
|
||||||
expected_stderr = "[warn]: @param tag types do not match the code. The ident\n parameter is declared as types [\"Float\"] in the docstring,\n but the code specifies the types [\"String\"]\n in the file manifests/init.pp near line 2.\n"
|
|
||||||
|
|
||||||
expect {
|
|
||||||
expect {
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__),'test') do |tmp|
|
|
||||||
Dir.chdir('test')
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
end
|
|
||||||
}.to output(expected_stderr).to_stderr_from_any_process
|
|
||||||
}.to output(expected_stout).to_stdout_from_any_process
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,63 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/puppet_3x_function_handler'
|
|
||||||
require 'strings_spec/parsing'
|
|
||||||
|
|
||||||
describe PuppetX::Puppet::Strings::YARD::Handlers::Puppet3xFunctionHandler do
|
|
||||||
include StringsSpec::Parsing
|
|
||||||
|
|
||||||
def the_method()
|
|
||||||
YARD::Registry.at("Puppet3xFunctions#the_function")
|
|
||||||
end
|
|
||||||
|
|
||||||
def the_namespace()
|
|
||||||
YARD::Registry.at("Puppet3xFunctions")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse single-line documentation strings before a given function" do
|
|
||||||
comment = "The summary"
|
|
||||||
parse <<-RUBY
|
|
||||||
# #{comment}
|
|
||||||
newfunction(:the_function, :type => rvalue) do |args|
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
|
|
||||||
expect(the_method).to document_a(:type => :method, :docstring => comment)
|
|
||||||
expect(the_namespace).to document_a(:type => :puppetnamespace)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse multi-line documentation strings before a given function" do
|
|
||||||
parse <<-RUBY
|
|
||||||
# The summary
|
|
||||||
#
|
|
||||||
# The longer description
|
|
||||||
newfunction(:the_function, :type => rvalue) do |args|
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
|
|
||||||
comment = "The summary\n\nThe longer description"
|
|
||||||
expect(the_method).to document_a(:type => :method, :docstring => comment)
|
|
||||||
expect(the_namespace).to document_a(:type => :puppetnamespace)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not parse documentation before a function if it is followed by two new lines" do
|
|
||||||
parse <<-RUBY
|
|
||||||
# The summary
|
|
||||||
|
|
||||||
|
|
||||||
newfunction(:the_function, :type => rvalue) do |args|
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
|
|
||||||
expect(the_method).to document_a(:type => :method, :docstring => "")
|
|
||||||
expect(the_namespace).to document_a(:type => :puppetnamespace)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should process documentation if only one option is passed to newfunction" do
|
|
||||||
parse <<-RUBY
|
|
||||||
newfunction(:the_functiion) do |args|
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
|
|
||||||
expect(the_namespace).to document_a(:type => :puppetnamespace)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,150 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
require 'lib/strings_spec/module_helper'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/puppet_4x_function_handler'
|
|
||||||
require 'puppet/face/strings'
|
|
||||||
require 'strings_spec/parsing'
|
|
||||||
|
|
||||||
describe PuppetX::Puppet::Strings::YARD::Handlers::Puppet4xFunctionHandler do
|
|
||||||
include StringsSpec::Parsing
|
|
||||||
|
|
||||||
def the_method()
|
|
||||||
YARD::Registry.at("Puppet4xFunctions#the_function")
|
|
||||||
end
|
|
||||||
|
|
||||||
def the_namespace()
|
|
||||||
YARD::Registry.at("Puppet4xFunctions")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse single-line documentation strings before a given function" do
|
|
||||||
comment = "The summary"
|
|
||||||
parse <<-RUBY
|
|
||||||
# #{comment}
|
|
||||||
Puppet::Functions.create_function(:the_function) do
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
|
|
||||||
expect(the_method).to document_a(:type => :method, :docstring => comment)
|
|
||||||
expect(the_namespace).to document_a(:type => :puppetnamespace)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse multi-line documentation strings before a given function" do
|
|
||||||
parse <<-RUBY
|
|
||||||
# The summary
|
|
||||||
#
|
|
||||||
# The longer description
|
|
||||||
Puppet::Functions.create_function(:the_function) do
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
|
|
||||||
comment = "The summary\n\nThe longer description"
|
|
||||||
expect(the_method).to document_a(:type => :method, :docstring => comment)
|
|
||||||
expect(the_namespace).to document_a(:type => :puppetnamespace)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not parse documentation before a function if it is followed by two new lines" do
|
|
||||||
parse <<-RUBY
|
|
||||||
# The summary
|
|
||||||
#
|
|
||||||
# The longer description
|
|
||||||
|
|
||||||
|
|
||||||
Puppet::Functions.create_function(:the_function) do
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
|
|
||||||
expect(the_method).to document_a(:type => :method, :docstring => "")
|
|
||||||
expect(the_namespace).to document_a(:type => :puppetnamespace)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should issue a warning if the parameter names do not match the docstring" do
|
|
||||||
expected_output_not_a_param = "[warn]: The parameter not_a_param is documented, but doesn't exist in\n your code, in file lib/test.rb near line 3."
|
|
||||||
expected_output_also_not_a_param = "[warn]: The parameter also_not_a_param is documented, but doesn't exist in\n your code, in file lib/test.rb near line 3."
|
|
||||||
expect {
|
|
||||||
expect {
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__),'test-param-names-differ') do |tmp|
|
|
||||||
Dir.chdir('test-param-names-differ')
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
end
|
|
||||||
}.to output(/documented/).to_stdout_from_any_process
|
|
||||||
}.to output("#{expected_output_not_a_param}\n#{expected_output_also_not_a_param}\n").to_stderr_from_any_process
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not issue a warning when the parameter names match the docstring" do
|
|
||||||
expected = ""
|
|
||||||
expect {
|
|
||||||
expect {
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__),'test-param-names-match') do |tmp|
|
|
||||||
Dir.chdir('test-param-names-match')
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
end
|
|
||||||
}.to output(/documented/).to_stdout_from_any_process
|
|
||||||
}.to output(expected).to_stderr_from_any_process
|
|
||||||
|
|
||||||
end
|
|
||||||
it "should not issue a warning when there are parametarized types and parameter names are the same" do
|
|
||||||
expected = ""
|
|
||||||
expect {
|
|
||||||
expect {
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__),'test-param-names-match-with-types') do |tmp|
|
|
||||||
Dir.chdir('test-param-names-match-with-types')
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
end
|
|
||||||
}.to output(/documented/).to_stdout_from_any_process
|
|
||||||
}.to output(expected).to_stderr_from_any_process
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should issue a warning when there are parametarized types and parameter names differ" do
|
|
||||||
expected_output_not_num_a = "[warn]: @param tag has unknown parameter" +
|
|
||||||
" name: not_num_a \n in file `(stdin)' near line 3."
|
|
||||||
expected_output_not_a_param = "[warn]: The parameter not_a_param is documented, but doesn't exist in\n your code, in file lib/test.rb near line 3."
|
|
||||||
expected_output_also_not_a_param = "[warn]: The parameter also_not_a_param is documented, but doesn't exist in\n your code, in file lib/test.rb near line 3."
|
|
||||||
expect {
|
|
||||||
expect {
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__),'test-param-names-differ-with-types') do |tmp|
|
|
||||||
Dir.chdir('test-param-names-differ-with-types')
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
end
|
|
||||||
}.to output(/documented/).to_stdout_from_any_process
|
|
||||||
}.to output("#{expected_output_not_a_param}\n#{expected_output_also_not_a_param}\n").to_stderr_from_any_process
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
it "should issue a warning if the parameter names do not match the docstring in dispatch method" do
|
|
||||||
expected_output_not_a_param = "[warn]: The parameter not_a_param is documented, but doesn't exist in\n your code, in file lib/test.rb near line 3."
|
|
||||||
expected_output_also_not_a_param = "[warn]: The parameter also_not_a_param is documented, but doesn't exist in\n your code, in file lib/test.rb near line 3."
|
|
||||||
expect {
|
|
||||||
expect {
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__),'test-param-names-differ-with-dispatch') do |tmp|
|
|
||||||
Dir.chdir('test-param-names-differ-with-dispatch')
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
end
|
|
||||||
}.to output(/documented/).to_stdout_from_any_process
|
|
||||||
}.to output("#{expected_output_not_a_param}\n#{expected_output_also_not_a_param}\n").to_stderr_from_any_process
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not issue a warning if the parameter names do match the " +
|
|
||||||
"docstring in dispatch method" do
|
|
||||||
expected = ""
|
|
||||||
expect {
|
|
||||||
expect {
|
|
||||||
PuppetModuleHelper.using_module(File.dirname(__FILE__),'test-param-names-match-with-dispatch') do |tmp|
|
|
||||||
Dir.chdir('test-param-names-match-with-dispatch')
|
|
||||||
Puppet::Face[:strings, :current].yardoc
|
|
||||||
end
|
|
||||||
}.to output(/documented/).to_stdout_from_any_process
|
|
||||||
}.to output(expected).to_stderr_from_any_process
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse unusually named functions" do
|
|
||||||
# This should not raise a ParseErrorWithIssue exceptoin
|
|
||||||
parse <<-RUBY
|
|
||||||
Puppet::Functions.create_function :'max' do
|
|
||||||
def max(num_a, num_b)
|
|
||||||
num_a >= num_b ? num_a : num_b
|
|
||||||
end
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,125 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
require 'puppet_x/puppet/strings/yard/templates/default/template_helper'
|
|
||||||
require 'puppet_x/puppet/strings/yard/code_objects/puppet_namespace_object'
|
|
||||||
require 'strings_spec/parsing'
|
|
||||||
|
|
||||||
describe TemplateHelper do
|
|
||||||
it "should not print any warning if the tags and parameters match" do
|
|
||||||
th = TemplateHelper.new
|
|
||||||
|
|
||||||
# Case 0: If the documented tags do include the parameter,
|
|
||||||
# nothing is printed
|
|
||||||
tag0 = YARD::Tags::Tag.new(:param, 'a_parameter')
|
|
||||||
tag0.name = 'a_parameter'
|
|
||||||
obj0 = PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject.new(:root, 'Puppet3xFunctions')
|
|
||||||
obj0.add_tag tag0
|
|
||||||
obj0.parameters = [['a_parameter']]
|
|
||||||
expect { th.check_parameters_match_docs obj0 }.to output("").to_stderr_from_any_process
|
|
||||||
|
|
||||||
# The docstring is still alive between tests. Clear the tags registered with
|
|
||||||
# it so the tags won't persist between tests.
|
|
||||||
obj0.docstring.instance_variable_set("@tags", [])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should print the warning with no location data if the tags and " +
|
|
||||||
"parameters differ and the location data is not properly formed" do
|
|
||||||
th = TemplateHelper.new
|
|
||||||
# Case 1: If the parameter and tag differ and the location is not properly
|
|
||||||
# formed, print out the warning with no location data
|
|
||||||
tag1 = YARD::Tags::Tag.new(:param, 'aa_parameter')
|
|
||||||
tag1.name = 'aa_parameter'
|
|
||||||
obj1 = PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject.new(:root, 'Puppet3xFunctions')
|
|
||||||
obj1.add_tag tag1
|
|
||||||
obj1.parameters = [['b_parameter']]
|
|
||||||
expect { th.check_parameters_match_docs obj1 }.to output("[warn]: The parameter aa_parameter is documented, but doesn't exist in\n your code. Sorry, the file and line number could not be determined.\n").to_stderr_from_any_process
|
|
||||||
|
|
||||||
# The docstring is still alive between tests. Clear the tags registered with
|
|
||||||
# it so the tags won't persist between tests.
|
|
||||||
obj1.docstring.instance_variable_set("@tags", [])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should print the warning with location data if the tags and parameters " +
|
|
||||||
"differ and the location data is properly formed" do
|
|
||||||
th = TemplateHelper.new
|
|
||||||
# Case 2: If the parameter and tag differ and the location is properly
|
|
||||||
# formed, print out the warning with no location data
|
|
||||||
tag2 = YARD::Tags::Tag.new(:param, 'aaa_parameter')
|
|
||||||
tag2.name = 'aaa_parameter'
|
|
||||||
obj2 = PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject.new(:root, 'Puppet3xFunctions')
|
|
||||||
obj2.files = [['some_file.pp', 42]]
|
|
||||||
obj2.add_tag tag2
|
|
||||||
obj2.parameters = [['b_parameter']]
|
|
||||||
expect { th.check_parameters_match_docs obj2 }.to output("[warn]: The parameter aaa_parameter is documented, but doesn't exist in\n your code, in file some_file.pp near line 42.\n").to_stderr_from_any_process
|
|
||||||
|
|
||||||
# The docstring is still alive between tests. Clear the tags registered with
|
|
||||||
# it so the tags won't persist between tests.
|
|
||||||
obj2.docstring.instance_variable_set("@tags", [])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should issue a warning if the parameter types do not match the docstring in dispatch method" do
|
|
||||||
expected_output_not_a_param = "[warn]: @param tag types do not match the" +
|
|
||||||
" code. The arg1\n parameter is declared as types [\"Integer\"] in the " +
|
|
||||||
"docstring,\n but the code specifies the types [\"Optional[String]\"]" +
|
|
||||||
"\n in the file test near line 0.\n"
|
|
||||||
object = PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject.new(:root, 'Puppet4xFunctions')
|
|
||||||
object.files = [['test', 0]]
|
|
||||||
object.type_info = [{
|
|
||||||
'arg0' => 'Variant[String,Array[String]]',
|
|
||||||
'arg1' => 'Optional[String]'
|
|
||||||
}]
|
|
||||||
param_details = [{
|
|
||||||
:name => 'arg0',
|
|
||||||
:types => ['Variant[String,Array[String]]']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
:name => 'arg1',
|
|
||||||
:types => ['Integer']
|
|
||||||
}]
|
|
||||||
template_helper = TemplateHelper.new
|
|
||||||
expect {
|
|
||||||
template_helper.check_types_match_docs(object, param_details)
|
|
||||||
}.to output(expected_output_not_a_param).to_stderr_from_any_process
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not issue a warning if the parameter types do match the docstring in dispatch method" do
|
|
||||||
object = PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject.new(:root, 'Puppet4xFunctions')
|
|
||||||
object.files = [['test', 0]]
|
|
||||||
object.type_info = [{
|
|
||||||
'arg0' => 'Variant[String,Array[String]]',
|
|
||||||
'arg1' => 'Optional[String]'
|
|
||||||
}]
|
|
||||||
param_details = [{
|
|
||||||
:name => 'arg0',
|
|
||||||
:types => ['Variant[String,Array[String]]']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
:name => 'arg1',
|
|
||||||
:types => ['Optional[String]']
|
|
||||||
}]
|
|
||||||
template_helper = TemplateHelper.new
|
|
||||||
expect {
|
|
||||||
template_helper.check_types_match_docs(object, param_details)
|
|
||||||
}.to output("").to_stderr_from_any_process
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not issue a warning if the types in the docstring in dispatch method are assignable to parameter types" do
|
|
||||||
object = PuppetX::Puppet::Strings::YARD::CodeObjects::PuppetNamespaceObject.new(:root, 'Puppet4xFunctions')
|
|
||||||
object.files = [['test', 0]]
|
|
||||||
object.type_info = [{
|
|
||||||
'arg0' => 'Variant[String,Array[String]]',
|
|
||||||
'arg1' => 'Optional[String]'
|
|
||||||
}]
|
|
||||||
param_details = [{
|
|
||||||
:name => 'arg0',
|
|
||||||
:types => ['Variant[String,Array[String]]']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
:name => 'arg1',
|
|
||||||
:types => ['String']
|
|
||||||
}]
|
|
||||||
template_helper = TemplateHelper.new
|
|
||||||
expect {
|
|
||||||
template_helper.check_types_match_docs(object, param_details)
|
|
||||||
}.to output("").to_stderr_from_any_process
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,67 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
require 'puppet_x/puppet/strings/yard/handlers/type_handler'
|
|
||||||
require 'strings_spec/parsing'
|
|
||||||
|
|
||||||
|
|
||||||
describe PuppetX::Puppet::Strings::YARD::Handlers::PuppetTypeHandler do
|
|
||||||
include StringsSpec::Parsing
|
|
||||||
|
|
||||||
def the_type()
|
|
||||||
YARD::Registry.at("file")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should have the proper docstring" do
|
|
||||||
parse <<-RUBY
|
|
||||||
Puppet::Type.newtype(:file) do
|
|
||||||
@doc = "Manages files, including their content, ownership, and perms."
|
|
||||||
newparam(:path) do
|
|
||||||
desc <<-'EOT'
|
|
||||||
The path to the file to manage. Must be fully qualified.
|
|
||||||
EOT
|
|
||||||
end
|
|
||||||
isnamevar
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
|
|
||||||
expect(the_type.docstring).to eq("Manages files, including their " +
|
|
||||||
"content, ownership, and perms.")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should have the proper parameter details" do
|
|
||||||
parse <<-RUBY
|
|
||||||
Puppet::Type.newtype(:file) do
|
|
||||||
@doc = "Manages files, including their content, ownership, and perms."
|
|
||||||
newparam(:file) do
|
|
||||||
desc <<-'EOT'
|
|
||||||
The path to the file to manage. Must be fully qualified.
|
|
||||||
EOT
|
|
||||||
end
|
|
||||||
isnamevar
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
|
|
||||||
expect(the_type.parameter_details).to eq([{ :name => "file",
|
|
||||||
:desc => "The path to the file to manage. Must be fully qualified.",
|
|
||||||
:exists? => true, :puppet_type => true, :namevar => true,
|
|
||||||
:default => nil,
|
|
||||||
:parameter=>true,
|
|
||||||
:allowed_values=>[],
|
|
||||||
}])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should have the proper parameters" do
|
|
||||||
parse <<-RUBY
|
|
||||||
Puppet::Type.newtype(:file) do
|
|
||||||
@doc = "Manages files, including their content, ownership, and perms."
|
|
||||||
newparam(:path) do
|
|
||||||
desc <<-'EOT'
|
|
||||||
The path to the file to manage. Must be fully qualified.
|
|
||||||
EOT
|
|
||||||
end
|
|
||||||
isnamevar
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
|
|
||||||
expect(the_type.parameters).to eq([["path", nil]])
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in New Issue