Skip to content

Commit

Permalink
Address feedback
Browse files Browse the repository at this point in the history
- 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
aThorp96 committed Aug 8, 2021
1 parent 2af1205 commit 42d2ee7
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 49 deletions.
185 changes: 136 additions & 49 deletions document.go
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
}
2 changes: 2 additions & 0 deletions go.mod
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
2 changes: 2 additions & 0 deletions go.sum
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=

0 comments on commit 42d2ee7

Please sign in to comment.