Repository: urfave/cli
Pull request #1227 (2021-01-25 13:29:24)

make the man page section selectable
## What type of PR is this?

- [ ] bug
- [ ] cleanup  
- [ ] documentation
- [x] feature

## What this PR does / why we need it:

The section number of the man page is fixed to 8.
This number can take other values depending on the usage.

https://www.man7.org/linux/man-pages/man7/man-pages.7.html

This fix adds a new argument to the `ToMarkdown` and `ToMan` methods so that they can be set to arbitrary values.
If you prefer other implementation, please let me know.


## Testing

Existing test code has been reused.

## Release Notes

```release-note
adds a new argument to the `ToMarkdown` and `ToMan` methods so that they can be set to arbitrary section number.
```


nmi: @lynncyrin I respect your opinion about the default section number.

Since Go does not support the optional argument, I would like to work on one of the following implementations.
Which one is preferable?

- In addition to `ToMan()`, add a function like `ToManWithSection(section int)`
- Add an attribute to the struct `app` to represent the section number
- Other implementations
lynncyrin: @nmi

> In addition to `ToMan()`, add a function like `ToManWithSection(section int)`

This one sounds best!
nmi: @lynncyrin Thanks! I've submitted a new patch.

Patch:
diff --git a/docs.go b/docs.go
index dc16fc8..4c0e1f6 100644
--- a/docs.go
+++ b/docs.go
@@ -15,31 +15,39 @@ import (
 // The function errors if either parsing or writing of the string fails.
 func (a *App) ToMarkdown() (string, error) {
 	var w bytes.Buffer
-	if err := a.writeDocTemplate(&w); err != nil {
+	if err := a.writeDocTemplate(&w, 8); err != nil {
 		return "", err
 	}
 	return w.String(), nil
 }
 
-// ToMan creates a man page string for the `*App`
+// ToMan creates a man page string with section number for the `*App`
 // The function errors if either parsing or writing of the string fails.
-func (a *App) ToMan() (string, error) {
+func (a *App) ToManWithSection(sectionNumber int) (string, error) {
 	var w bytes.Buffer
-	if err := a.writeDocTemplate(&w); err != nil {
+	if err := a.writeDocTemplate(&w, sectionNumber); err != nil {
 		return "", err
 	}
 	man := md2man.Render(w.Bytes())
 	return string(man), nil
 }
 
+// ToMan creates a man page string for the `*App`
+// The function errors if either parsing or writing of the string fails.
+func (a *App) ToMan() (string, error) {
+	man, err := a.ToManWithSection(8)
+	return man, err
+}
+
 type cliTemplate struct {
 	App          *App
+	SectionNum   int
 	Commands     []string
 	GlobalArgs   []string
 	SynopsisArgs []string
 }
 
-func (a *App) writeDocTemplate(w io.Writer) error {
+func (a *App) writeDocTemplate(w io.Writer, sectionNum int) error {
 	const name = "cli"
 	t, err := template.New(name).Parse(MarkdownDocTemplate)
 	if err != nil {
@@ -47,6 +55,7 @@ func (a *App) writeDocTemplate(w io.Writer) error {
 	}
 	return t.ExecuteTemplate(w, name, &cliTemplate{
 		App:          a,
+		SectionNum:   sectionNum,
 		Commands:     prepareCommands(a.Commands, 0),
 		GlobalArgs:   prepareArgsWithValues(a.VisibleFlags()),
 		SynopsisArgs: prepareArgsSynopsis(a.VisibleFlags()),
diff --git a/template.go b/template.go
index 31c03f8..317cc88 100644
--- a/template.go
+++ b/template.go
@@ -74,7 +74,7 @@ OPTIONS:
    {{end}}{{end}}
 `
 
-var MarkdownDocTemplate = `% {{ .App.Name }} 8
+var MarkdownDocTemplate = `% {{ .App.Name }} {{ .SectionNum }}
 
 # NAME
 


Test patch:
diff --git a/docs_test.go b/docs_test.go
index 46e38dc..fac106f 100644
--- a/docs_test.go
+++ b/docs_test.go
@@ -2,6 +2,7 @@ package cli
 
 import (
 	"bytes"
+	"errors"
 	"io/ioutil"
 	"testing"
 )
@@ -147,3 +148,30 @@ func TestToMan(t *testing.T) {
 	expect(t, err, nil)
 	expectFileContent(t, "testdata/expected-doc-full.man", res)
 }
+
+func TestToManParseError(t *testing.T) {
+	// Given
+	app := testApp()
+
+	// When
+	// temporarily change the global variable for testing
+	tmp := MarkdownDocTemplate
+	MarkdownDocTemplate = `{{ .App.Name`
+	_, err := app.ToMan()
+	MarkdownDocTemplate = tmp
+
+	// Then
+	expect(t, err, errors.New(`template: cli:1: unclosed action`))
+}
+
+func TestToManWithSection(t *testing.T) {
+	// Given
+	app := testApp()
+
+	// When
+	res, err := app.ToManWithSection(8)
+
+	// Then
+	expect(t, err, nil)
+	expectFileContent(t, "testdata/expected-doc-full.man", res)
+}