github.com/anthonyme00/gomarkdoc@v1.0.0/lang/example.go (about)

     1  package lang
     2  
     3  import (
     4  	"fmt"
     5  	"go/doc"
     6  	"go/printer"
     7  	"strings"
     8  )
     9  
    10  // Example holds a single documentation example for a package or symbol.
    11  type Example struct {
    12  	cfg  *Config
    13  	name string
    14  	doc  *doc.Example
    15  }
    16  
    17  // NewExample creates a new example from the example function's name, its
    18  // documentation example and the files holding code related to the example.
    19  func NewExample(cfg *Config, name string, doc *doc.Example) *Example {
    20  	return &Example{cfg, name, doc}
    21  }
    22  
    23  // Level provides the default level that headers for the example should be
    24  // rendered.
    25  func (ex *Example) Level() int {
    26  	return ex.cfg.Level
    27  }
    28  
    29  // Name provides a pretty-printed name for the specific example, if one was
    30  // provided.
    31  func (ex *Example) Name() string {
    32  	return splitCamel(ex.name)
    33  }
    34  
    35  // Title provides a formatted string to print as the title of the example. It
    36  // incorporates the example's name, if present.
    37  func (ex *Example) Title() string {
    38  	name := ex.Name()
    39  	if name == "" {
    40  		return "Example"
    41  	}
    42  
    43  	return fmt.Sprintf("Example (%s)", name)
    44  }
    45  
    46  // Location returns a representation of the node's location in a file within a
    47  // repository.
    48  func (ex *Example) Location() Location {
    49  	return NewLocation(ex.cfg, ex.doc.Code)
    50  }
    51  
    52  // Summary provides the one-sentence summary of the example's documentation
    53  // comment.
    54  func (ex *Example) Summary() string {
    55  	return extractSummary(ex.doc.Doc)
    56  }
    57  
    58  // Doc provides the structured contents of the documentation comment for the
    59  // example.
    60  func (ex *Example) Doc() *Doc {
    61  	return NewDoc(ex.cfg.Inc(1), ex.doc.Doc)
    62  }
    63  
    64  // Code provides the raw text code representation of the example's contents.
    65  func (ex *Example) Code() (string, error) {
    66  	var codeNode interface{}
    67  	if ex.doc.Play != nil {
    68  		codeNode = ex.doc.Play
    69  	} else {
    70  		codeNode = &printer.CommentedNode{Node: ex.doc.Code, Comments: ex.doc.Comments}
    71  	}
    72  
    73  	var code strings.Builder
    74  	p := &printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}
    75  	err := p.Fprint(&code, ex.cfg.FileSet, codeNode)
    76  	if err != nil {
    77  		return "", err
    78  	}
    79  
    80  	str := code.String()
    81  
    82  	// additional formatting if this is a function body
    83  	if i := len(str); i >= 2 && str[0] == '{' && str[i-1] == '}' {
    84  		// remove surrounding braces
    85  		str = str[1 : i-1]
    86  		// unindent
    87  		str = strings.ReplaceAll(str, "\n\t", "\n")
    88  	}
    89  
    90  	return str, nil
    91  }
    92  
    93  // Output provides the code's example output.
    94  func (ex *Example) Output() string {
    95  	return ex.doc.Output
    96  }
    97  
    98  // HasOutput indicates whether the example contains any example output.
    99  func (ex *Example) HasOutput() bool {
   100  	return ex.doc.Output != "" || ex.doc.EmptyOutput
   101  }