-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Use a string builder instead of string to minimize allocations - Use proper doc-comment format With the use of stringBuilder, errors have been introduced into the package. I added the dependency `github.com/pkg/errors` to help handle them, but if we'd prefer to stick with the standard library I think that'd be fair. My thinking was the circumstances that caused strings.Builder.WriteString() to error would warrent a stack trace and metadata, something which is more pragmatically done using `github.com/pkg/errors`.
- Loading branch information
Showing
3 changed files
with
140 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,169 @@ | ||
package gemini | ||
|
||
// DocumentBuilder allows programatic document creation using the builder pattern. | ||
// DocumentBuilder supports the use of headers and footers, which combined with the body at build time. | ||
import ( | ||
"bytes" | ||
"strings" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
// DocumentBuilder allows programmatic document creation using the builder pattern. | ||
// DocumentBuilder supports the use of headers and footers, which are combined with the body at build time. | ||
type DocumentBuilder struct { | ||
header string | ||
body string | ||
header string | ||
body *strings.Builder | ||
footer string | ||
} | ||
|
||
// Instantiate a new DocumentBuilder. | ||
// NewDocumentBuilder creates a DocumentBuilder. | ||
func NewDocumentBuilder() DocumentBuilder { | ||
return DocumentBuilder{} | ||
builder := new(strings.Builder) | ||
return DocumentBuilder{"", builder, ""} | ||
} | ||
|
||
// Ensures any string passed through this function will be terminated with a newline | ||
func ensureNewlineTerminated(text string) string { | ||
if len(text) == 0 || text[len(text)-1] != '\n' { | ||
text += "\n" | ||
} | ||
return text | ||
// SetHeader sets a document header. The header is written before the document body during `Build()`. | ||
func (doc *DocumentBuilder) SetHeader(header string) { | ||
doc.header = header | ||
} | ||
|
||
// Set the document header | ||
func (self *DocumentBuilder) SetHeader(header string) { | ||
self.header = ensureNewlineTerminated(header) | ||
// SetFooter sets a document footer. The footer is written after the document body during `Build()`. | ||
func (doc *DocumentBuilder) SetFooter(footer string) { | ||
doc.footer = footer | ||
} | ||
|
||
// Set the document footer | ||
func (self *DocumentBuilder) SetFooter(footer string) { | ||
self.footer = ensureNewlineTerminated(footer) | ||
} | ||
// AddLine appends a new line to the document. Adds a newline to the end of the line if none is present. | ||
func (doc *DocumentBuilder) AddLine(line string) error { | ||
_, err := doc.body.WriteString(line) | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing to document") | ||
} | ||
|
||
if !strings.HasSuffix(line, "\n") { | ||
_, err = doc.body.WriteString("\n") | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing to document") | ||
} | ||
} | ||
|
||
// Add a new line to the document. Adds a newline to the end of the line if none is present. | ||
func (self *DocumentBuilder) AddLine(line string) { | ||
self.body += ensureNewlineTerminated(line) | ||
return nil | ||
} | ||
|
||
// Add an H1 (#) header line to the document. | ||
func (self *DocumentBuilder) AddH1Header(header string) { | ||
self.AddLine("# " + header) | ||
// AddH1Header appends an H1 (#) header line to the document. | ||
func (doc *DocumentBuilder) AddH1Header(header string) error { | ||
_, err := doc.body.WriteString("# ") | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing to document") | ||
} | ||
|
||
doc.AddLine(header) | ||
return err | ||
} | ||
|
||
// Add an H2 (##) header line to the document. | ||
func (self *DocumentBuilder) AddH2Header(header string) { | ||
self.AddLine("## " + header) | ||
// AddH2Header appends an H2 (##) header line to the document. | ||
func (doc *DocumentBuilder) AddH2Header(header string) error { | ||
_, err := doc.body.WriteString("## ") | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing to document") | ||
} | ||
|
||
err = doc.AddLine(header) | ||
return err | ||
} | ||
|
||
// Add an H3 (###) header line to the document. | ||
func (self *DocumentBuilder) AddH3Header(header string) { | ||
self.AddLine("### " + header) | ||
// AddH3Header appends an H3 (###) header line to the document. | ||
func (doc *DocumentBuilder) AddH3Header(header string) error { | ||
_, err := doc.body.WriteString("### ") | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing header line to document") | ||
} | ||
|
||
err = doc.AddLine(header) | ||
return err | ||
} | ||
|
||
// Add a quote line to the document. | ||
func (self *DocumentBuilder) AddQuote(header string) { | ||
self.AddLine("> " + header) | ||
// AddQuote appends a quote line to the document. | ||
func (doc *DocumentBuilder) AddQuote(header string) error { | ||
_, err := doc.body.WriteString("> ") | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing quote to document") | ||
} | ||
|
||
err = doc.AddLine(header) | ||
return err | ||
} | ||
|
||
// Add an unordered list item to the document. | ||
func (self *DocumentBuilder) AddBullet(header string) { | ||
self.AddLine("* " + header) | ||
// AddBullet appends an unordered list item to the document. | ||
func (doc *DocumentBuilder) AddBullet(header string) error { | ||
_, err := doc.body.WriteString("* ") | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing bullet to document") | ||
} | ||
|
||
err = doc.AddLine(header) | ||
return err | ||
} | ||
|
||
// Add a toggle formatting line to the document. | ||
func (self *DocumentBuilder) ToggleFormatting() { | ||
self.AddLine("```") | ||
// ToggleFormatting appends a toggle formatting line to the document. | ||
func (doc *DocumentBuilder) ToggleFormatting() error { | ||
return doc.AddLine("```") | ||
} | ||
|
||
// Add an aliased link line to the document. | ||
func (self *DocumentBuilder) AddLink(url string, title string) { | ||
self.AddLine("=> " + url + "\t" + title) | ||
// AddLink appends an aliased link line to the document. | ||
func (doc *DocumentBuilder) AddLink(url string, title string) error { | ||
_, err := doc.body.WriteString("=> ") | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing link to document") | ||
} | ||
_, err = doc.body.WriteString(url) | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing link to document") | ||
} | ||
_, err = doc.body.WriteString("\t") | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing link to document") | ||
} | ||
// AddLine to ensure there is a newline | ||
err = doc.AddLine(title) | ||
return err | ||
} | ||
|
||
// Add a link line to the document. | ||
func (self *DocumentBuilder) AddRawLink(url string) { | ||
self.AddLine("=> " + url) | ||
// AddRawLink appends a link line to the document. | ||
func (doc *DocumentBuilder) AddRawLink(url string) error { | ||
_, err := doc.body.WriteString("=> ") | ||
if err != nil { | ||
return errors.Wrap(err, "Error writing raw link to document") | ||
} | ||
err = doc.AddLine(url) | ||
return err | ||
} | ||
|
||
// Build the document into a serialized byte slice. | ||
func (self *DocumentBuilder) Build() []byte { | ||
return []byte(self.header + self.body + self.footer) | ||
// Build builds the document into a serialized byte slice. | ||
func (doc *DocumentBuilder) Build() ([]byte, error) { | ||
buf := bytes.Buffer{} | ||
|
||
// Write header | ||
_, err := buf.WriteString(doc.header) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "Error building document header") | ||
} | ||
if !strings.HasSuffix(doc.header, "\n") { | ||
_, err = buf.WriteString("\n") | ||
if err != nil { | ||
return nil, errors.Wrap(err, "Error building document header") | ||
} | ||
} | ||
|
||
// Write body | ||
_, err = buf.WriteString(doc.body.String()) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "Error building document body") | ||
} | ||
|
||
// Write footer | ||
_, err = buf.WriteString(doc.footer) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "Error building document footer") | ||
} | ||
|
||
return buf.Bytes(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
module github.com/a-h/gemini | ||
|
||
go 1.14 | ||
|
||
require github.com/pkg/errors v0.9.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |