Skip to content

Commit 98bd5dd

Browse files
committed
(PUP-12064) Add task to generate function reference
bundle exec rake references:function This task uses puppet strings to generate references/function.md. The task requires the puppet-strings gems, so add it to the documentation bundler group. Since the group is optional, check to see if the gem is present before trying to load it, similar to how we handle ronn. If there are both 3.x and 4.x functions with the same name, we ignore the 3.x version and document the 4.x version. This code is adapted from puppet-docs. The old code had a bug as it used to replace /####\s/ with '###\s' resulting in a literal '\s' in the header for some functions. If `puppet-strings` gem is installed, then the man page generation will include strings as a new application type. Since we don't actually ship strings in puppet, hide it from man page generation.
1 parent 97b15f3 commit 98bd5dd

File tree

6 files changed

+5634
-0
lines changed

6 files changed

+5634
-0
lines changed

Gemfile

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ end
7575
group(:documentation, optional: true) do
7676
gem 'gettext-setup', '~> 1.0', require: false, platforms: [:ruby]
7777
gem 'ronn', '~> 0.7.3', require: false, platforms: [:ruby]
78+
gem 'puppet-strings', require: false, platforms: [:ruby]
7879
end
7980

8081
if File.exist? "#{__FILE__}.local"

rakelib/generate_references.rake

+44
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ METAPARAMETER_ERB = File.join(__dir__, 'references/metaparameter.erb')
77
METAPARAMETER_MD = File.join(OUTPUT_DIR, 'metaparameter.md')
88
REPORT_ERB = File.join(__dir__, 'references/report.erb')
99
REPORT_MD = File.join(OUTPUT_DIR, 'report.md')
10+
FUNCTIONS_TEMPLATE_ERB = File.join(__dir__, 'references/functions_template.erb')
11+
FUNCTION_ERB = File.join(__dir__, 'references/function.erb')
12+
FUNCTION_MD = File.join(OUTPUT_DIR, 'function.md')
1013

1114
def render_erb(erb_file, variables)
1215
# Create a binding so only the variables we specify will be visible
@@ -56,4 +59,45 @@ namespace :references do
5659
body = puppet_doc('report')
5760
generate_reference('report', REPORT_ERB, body, REPORT_MD)
5861
end
62+
63+
desc "Generate function reference"
64+
task :function do
65+
# Locate puppet-strings
66+
begin
67+
require 'puppet-strings'
68+
require 'puppet-strings/version'
69+
rescue LoadError
70+
abort("Run `bundle config set with documentation` and `bundle update` to install the `puppet-strings` gem.")
71+
end
72+
73+
strings_data = {}
74+
Tempfile.create do |tmpfile|
75+
puts "Running puppet strings #{PuppetStrings::VERSION}"
76+
PuppetStrings.generate(['lib/puppet/{functions,parser/functions}/**/*.rb'], json: true, path: tmpfile.path)
77+
strings_data = JSON.load_file(tmpfile.path)
78+
end
79+
80+
# Based on https://github.com/puppetlabs/puppet-docs/blob/1a13be3fc6981baa8a96ff832ab090abc986830e/lib/puppet_references/puppet/functions.rb#L24-L56
81+
functions = strings_data['puppet_functions']
82+
83+
# Deal with the duplicate 3.x and 4.x functions
84+
# 1. Figure out which functions are duplicated.
85+
names = functions.map { |func| func['name'] }
86+
duplicates = names.uniq.select { |name| names.count(name) > 1 }
87+
# 2. Reject the 3.x version of any dupes.
88+
functions = functions.reject do |func|
89+
duplicates.include?(func['name']) && func['type'] != 'ruby4x'
90+
end
91+
92+
# renders the list of functions
93+
body = render_erb(FUNCTIONS_TEMPLATE_ERB, functions: functions)
94+
95+
# This substitution could potentially make things a bit brittle, but it has to be done because the jump
96+
# From H2s to H4s is causing issues with the DITA-OT, which sees this as a rule violation. If it
97+
# Does become an issue, we should return to this and figure out a better way to generate the functions doc.
98+
body.gsub!(/#####\s(.*?:)/,'**\1**').gsub!(/####\s/,'### ').chomp!
99+
100+
# renders the preamble and list of functions
101+
generate_reference('function', FUNCTION_ERB, body, FUNCTION_MD)
102+
end
59103
end

rakelib/manpages.rake

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ task :gen_manpages do
99
bins = Dir.glob(%w{bin/*})
1010
non_face_applications = helpface.legacy_applications
1111
faces = Puppet::Face.faces.map(&:to_s)
12+
# exclude puppet-strings
13+
faces.delete('strings')
1214
apps = non_face_applications + faces
1315

1416
ronn_args = '--manual="Puppet manual" --organization="Puppet, Inc." --roff'

rakelib/references/function.erb

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
layout: default
3+
built_from_commit: <%= sha %>
4+
title: Built-in function reference
5+
canonical: "/puppet/latest/function.html"
6+
toc_levels: 2
7+
toc: columns
8+
---
9+
10+
# Built-in function reference
11+
12+
> **NOTE:** This page was generated from the Puppet source code on <%= now %>
13+
14+
15+
16+
This page is a list of Puppet's built-in functions, with descriptions of what they do and how to use them.
17+
18+
Functions are plugins you can call during catalog compilation. A call to any function is an expression that resolves to a value. For more information on how to call functions, see [the language reference page about function calls.](lang_functions.dita)
19+
20+
Many of these function descriptions include auto-detected _signatures,_ which are short reminders of the function's allowed arguments. These signatures aren't identical to the syntax you use to call the function; instead, they resemble a parameter list from a Puppet [class](lang_classes.dita), [defined resource type](lang_defined_types.dita), [function](lang_write_functions_in_puppet.dita), or [lambda](lang_lambdas.dita). The syntax of a signature is:
21+
22+
```
23+
<FUNCTION NAME>(<DATA TYPE> <ARGUMENT NAME>, ...)
24+
```
25+
26+
The `<DATA TYPE>` is a [Puppet data type value](lang_data_type.dita), like `String` or `Optional[Array[String]]`. The `<ARGUMENT NAME>` is a descriptive name chosen by the function's author to indicate what the argument is used for.
27+
28+
* Any arguments with an `Optional` data type can be omitted from the function call.
29+
* Arguments that start with an asterisk (like `*$values`) can be repeated any number of times.
30+
* Arguments that start with an ampersand (like `&$block`) aren't normal arguments; they represent a code block, provided with [Puppet's lambda syntax.](lang_lambdas.dita)
31+
32+
## `undef` values in Puppet 6
33+
34+
In Puppet 6, many Puppet types were moved out of the Puppet codebase, and into modules on the Puppet Forge. The new functions handle `undef` values more strictly than their stdlib counterparts. In Puppet 6, code that relies on `undef` values being implicitly treated as other types will return an evaluation error. For more information on which types were moved into modules, see the [Puppet 6 release notes](https://puppet.com/docs/puppet/6.0/release_notes_puppet.html#select-types-moved-to-modules).
35+
36+
37+
<%= body %>
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<% functions.sort{|a,b| a['name'] <=> b['name'] }.each do |func| -%>
2+
## `<%= func['name'] %>`
3+
4+
<%= func['docstring']['text'] %>
5+
6+
<% func_signatures = func['signatures']
7+
multiple_signatures = func_signatures.count > 1
8+
if func_signatures
9+
func['signatures'].each_with_index do |signature, index| -%>
10+
11+
<% if multiple_signatures -%>
12+
Signature <%= index+1 %>
13+
14+
<% end -%>
15+
`<%= signature['signature'] %>`
16+
<% has_parameters = signature.dig('docstring', 'tags')&.detect {|tag| tag['tag_name'] == 'param' && tag['text'] != '' && tag['text'] != nil } || false
17+
if has_parameters -%>
18+
19+
### Parameters
20+
21+
<% signature['docstring']['tags'].select {|tag| tag['tag_name'] == 'param' && tag['text'] != '' && tag['text'] != nil}.each do |param| -%>
22+
23+
* `<%= param['name'] %>` --- <%= param['text'] %>
24+
<% end # each param
25+
26+
return_types = signature['docstring']['tags'].detect {|tag| tag['tag_name'] == 'return'}
27+
if return_types -%>
28+
29+
Return type(s): <%= return_types['types'].map {|t| "`#{t}`"}.join(', ') %>. <%= return_types['text'] %>
30+
<% end # if return_types
31+
has_examples = signature['docstring']['tags'].detect {|tag| tag['tag_name'] == 'example' && tag['text'] != '' && tag['text'] != nil }
32+
if has_examples %>
33+
34+
### Examples
35+
36+
<% signature['docstring']['tags'].select {|tag| tag['tag_name'] == 'example' && tag['text'] != '' && tag['text'] != nil}.each do |example| -%>
37+
<%= example['name'] %>
38+
39+
<%= example['text'] %>
40+
41+
<% end # each example
42+
end # if has_examples
43+
end-%>
44+
<% end # each signature
45+
end -%>
46+
47+
<% end -%>

0 commit comments

Comments
 (0)