From 3c3ea3c7674631482d5fe7371dbd432fb730f8f3 Mon Sep 17 00:00:00 2001 From: Erik Winter Date: Sat, 11 Jun 2022 09:30:22 +0200 Subject: [PATCH] improved package api --- adoc.go | 33 ++++++++++------- document/document.go | 22 ++++++++++++ element/codeblock_test.go | 12 +++---- element/header_test.go | 10 +++--- element/link_test.go | 4 +-- element/list_test.go | 4 +-- element/paragraph_test.go | 10 +++--- element/styles_test.go | 4 +-- element/subtitle_test.go | 4 +-- format/text.go | 16 --------- {format => formatter}/asciidoc.go | 34 ++++++++++-------- {format => formatter}/asciidoc_test.go | 50 +++++++++++++------------- formatter/formatter.go | 11 ++++++ {format => formatter}/html.go | 32 ++++++++++------- {format => formatter}/html_test.go | 8 ++--- formatter/text.go | 29 +++++++++++++++ {format => formatter}/text_test.go | 6 ++-- parser/parser.go | 8 ++--- parser/parser_test.go | 8 ++--- 19 files changed, 184 insertions(+), 121 deletions(-) create mode 100644 document/document.go delete mode 100644 format/text.go rename {format => formatter}/asciidoc.go (55%) rename {format => formatter}/asciidoc_test.go (82%) create mode 100644 formatter/formatter.go rename {format => formatter}/html.go (60%) rename {format => formatter}/html_test.go (94%) create mode 100644 formatter/text.go rename {format => formatter}/text_test.go (72%) diff --git a/adoc.go b/adoc.go index 2551f3d..a9c0507 100644 --- a/adoc.go +++ b/adoc.go @@ -1,22 +1,29 @@ package adoc import ( - "time" + "io" - "ewintr.nl/adoc/element" + "ewintr.nl/adoc/document" + "ewintr.nl/adoc/formatter" + "ewintr.nl/adoc/parser" ) -type ADoc struct { - Title string - Attributes map[string]string - Author string - Date time.Time - Content []element.Element +func NewDocument() *document.Document { + return document.New() } -func New() *ADoc { - return &ADoc{ - Attributes: map[string]string{}, - Content: []element.Element{}, - } +func NewParser(reader io.Reader) *parser.Parser { + return parser.New(reader) +} + +func NewTextFormatter() *formatter.Text { + return formatter.NewText() +} + +func NewAsciiDocFormatter() *formatter.AsciiDoc { + return formatter.NewAsciiDoc() +} + +func NewHTMLFormatter() *formatter.HTML { + return formatter.NewHTML() } diff --git a/document/document.go b/document/document.go new file mode 100644 index 0000000..1a82278 --- /dev/null +++ b/document/document.go @@ -0,0 +1,22 @@ +package document + +import ( + "time" + + "ewintr.nl/adoc/element" +) + +type Document struct { + Title string + Attributes map[string]string + Author string + Date time.Time + Content []element.Element +} + +func New() *Document { + return &Document{ + Attributes: map[string]string{}, + Content: []element.Element{}, + } +} diff --git a/element/codeblock_test.go b/element/codeblock_test.go index 7d63e48..e27f130 100644 --- a/element/codeblock_test.go +++ b/element/codeblock_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" "ewintr.nl/adoc/parser" "ewintr.nl/go-kit/test" @@ -14,13 +14,13 @@ func TestCodeBlock(t *testing.T) { for _, tc := range []struct { name string input string - exp *adoc.ADoc + exp *document.Document }{ { name: "empty", input: `---- ----`, - exp: &adoc.ADoc{ + exp: &document.Document{ Attributes: map[string]string{}, Content: []element.Element{element.CodeBlock{}}, }, @@ -32,7 +32,7 @@ code more ----`, - exp: &adoc.ADoc{ + exp: &document.Document{ Attributes: map[string]string{}, Content: []element.Element{element.CodeBlock{ element.Word("code"), @@ -48,7 +48,7 @@ more code ---- `, - exp: &adoc.ADoc{ + exp: &document.Document{ Attributes: map[string]string{}, Content: []element.Element{element.CodeBlock{ element.Word("code"), @@ -63,7 +63,7 @@ code more `, - exp: &adoc.ADoc{ + exp: &document.Document{ Attributes: map[string]string{}, Content: []element.Element{ element.Paragraph{[]element.Element{ diff --git a/element/header_test.go b/element/header_test.go index c74c90b..2f6ad39 100644 --- a/element/header_test.go +++ b/element/header_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" "ewintr.nl/adoc/parser" "ewintr.nl/go-kit/test" @@ -15,12 +15,12 @@ func TestHeader(t *testing.T) { for _, tc := range []struct { name string input string - exp *adoc.ADoc + exp *document.Document }{ { name: "just title", input: "= Title", - exp: &adoc.ADoc{ + exp: &document.Document{ Title: "Title", Attributes: map[string]string{}, Content: []element.Element{}, @@ -29,7 +29,7 @@ func TestHeader(t *testing.T) { { name: "empty title", input: "= ", - exp: adoc.New(), + exp: document.New(), }, { name: "full header", @@ -40,7 +40,7 @@ Author Name :key2: value2 First paragraph`, - exp: &adoc.ADoc{ + exp: &document.Document{ Title: "Title with words", Date: time.Date(2022, time.Month(3), 4, 0, 0, 0, 0, time.UTC), Author: "Author Name", diff --git a/element/link_test.go b/element/link_test.go index ff2ffc8..e53bd53 100644 --- a/element/link_test.go +++ b/element/link_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" "ewintr.nl/adoc/parser" "ewintr.nl/go-kit/test" @@ -49,7 +49,7 @@ func TestLink(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { par := parser.New(strings.NewReader(tc.input)) - exp := &adoc.ADoc{ + exp := &document.Document{ Attributes: map[string]string{}, Content: tc.exp, } diff --git a/element/list_test.go b/element/list_test.go index ee18aca..2b5a94d 100644 --- a/element/list_test.go +++ b/element/list_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" "ewintr.nl/adoc/parser" "ewintr.nl/go-kit/test" @@ -69,7 +69,7 @@ and some text`, } { t.Run(tc.name, func(t *testing.T) { par := parser.New(strings.NewReader(tc.input)) - exp := &adoc.ADoc{ + exp := &document.Document{ Attributes: map[string]string{}, Content: tc.exp, } diff --git a/element/paragraph_test.go b/element/paragraph_test.go index 101d7a6..99abd27 100644 --- a/element/paragraph_test.go +++ b/element/paragraph_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" "ewintr.nl/adoc/parser" "ewintr.nl/go-kit/test" @@ -14,12 +14,12 @@ func TestParagraph(t *testing.T) { for _, tc := range []struct { name string input string - exp *adoc.ADoc + exp *document.Document }{ { name: "single paragraph", input: "some text", - exp: &adoc.ADoc{ + exp: &document.Document{ Attributes: map[string]string{}, Content: []element.Element{ element.Paragraph{Elements: []element.Element{ @@ -36,7 +36,7 @@ func TestParagraph(t *testing.T) { paragraph one paragraph two`, - exp: &adoc.ADoc{ + exp: &document.Document{ Title: "Title", Attributes: map[string]string{}, Content: []element.Element{ @@ -61,7 +61,7 @@ two three `, - exp: &adoc.ADoc{ + exp: &document.Document{ Attributes: map[string]string{}, Content: []element.Element{ element.Paragraph{Elements: []element.Element{element.Word("one")}}, diff --git a/element/styles_test.go b/element/styles_test.go index 53ac533..5529d16 100644 --- a/element/styles_test.go +++ b/element/styles_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" "ewintr.nl/adoc/parser" "ewintr.nl/go-kit/test" @@ -93,7 +93,7 @@ func TestStyles(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { par := parser.New(strings.NewReader(tc.input)) - exp := &adoc.ADoc{ + exp := &document.Document{ Attributes: map[string]string{}, Content: tc.exp, } diff --git a/element/subtitle_test.go b/element/subtitle_test.go index e0a0f7d..825e3b6 100644 --- a/element/subtitle_test.go +++ b/element/subtitle_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" "ewintr.nl/adoc/parser" "ewintr.nl/go-kit/test" @@ -38,7 +38,7 @@ func TestSubTitle(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - exp := &adoc.ADoc{ + exp := &document.Document{ Attributes: map[string]string{}, Content: tc.exp, } diff --git a/format/text.go b/format/text.go deleted file mode 100644 index 2c59c8e..0000000 --- a/format/text.go +++ /dev/null @@ -1,16 +0,0 @@ -package format - -import ( - "fmt" - - "ewintr.nl/adoc" -) - -func Text(doc *adoc.ADoc) string { - txt := fmt.Sprintf("%s\n\n", doc.Title) - for _, el := range doc.Content { - txt += fmt.Sprintf("%s\n\n", el.Text()) - } - - return txt -} diff --git a/format/asciidoc.go b/formatter/asciidoc.go similarity index 55% rename from format/asciidoc.go rename to formatter/asciidoc.go index 0175f15..139958c 100644 --- a/format/asciidoc.go +++ b/formatter/asciidoc.go @@ -1,17 +1,23 @@ -package format +package formatter import ( "fmt" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" ) -func AsciiDoc(doc *adoc.ADoc) string { - return fmt.Sprintf("%s\n%s", AsciiDocHeader(doc), AsciiDocFragment(doc.Content...)) +type AsciiDoc struct{} + +func NewAsciiDoc() *AsciiDoc { + return &AsciiDoc{} } -func AsciiDocHeader(doc *adoc.ADoc) string { +func (ad *AsciiDoc) Format(doc *document.Document) string { + return fmt.Sprintf("%s\n%s", asciiDocHeader(doc), ad.FormatFragments(doc.Content...)) +} + +func asciiDocHeader(doc *document.Document) string { header := fmt.Sprintf("= %s\n", doc.Title) if doc.Author != "" { header += fmt.Sprintf("%s\n", doc.Author) @@ -26,16 +32,16 @@ func AsciiDocHeader(doc *adoc.ADoc) string { return header } -func AsciiDocFragment(els ...element.Element) string { +func (ad *AsciiDoc) FormatFragments(els ...element.Element) string { var asciiDoc string for _, el := range els { - asciiDoc += asciiDocElement(el) + asciiDoc += ad.asciiDocElement(el) } return asciiDoc } -func asciiDocElement(el element.Element) string { +func (ad *AsciiDoc) asciiDocElement(el element.Element) string { switch v := el.(type) { case element.SubTitle: return fmt.Sprintf("== %s\n\n", v.Text()) @@ -46,19 +52,19 @@ func asciiDocElement(el element.Element) string { for _, i := range v { items = append(items, i) } - return fmt.Sprintf("%s\n", AsciiDocFragment(items...)) + return fmt.Sprintf("%s\n", ad.FormatFragments(items...)) case element.ListItem: - return fmt.Sprintf("* %s\n", AsciiDocFragment(v...)) + return fmt.Sprintf("* %s\n", ad.FormatFragments(v...)) case element.CodeBlock: return fmt.Sprintf("----\n%s\n----\n\n", v.Text()) case element.Paragraph: - return fmt.Sprintf("%s\n\n", AsciiDocFragment(v.Elements...)) + return fmt.Sprintf("%s\n\n", ad.FormatFragments(v.Elements...)) case element.Strong: - return fmt.Sprintf("*%s*", AsciiDocFragment(v...)) + return fmt.Sprintf("*%s*", ad.FormatFragments(v...)) case element.Emphasis: - return fmt.Sprintf("_%s_", AsciiDocFragment(v...)) + return fmt.Sprintf("_%s_", ad.FormatFragments(v...)) case element.Code: - return fmt.Sprintf("`%s`", AsciiDocFragment(v...)) + return fmt.Sprintf("`%s`", ad.FormatFragments(v...)) case element.Link: return fmt.Sprintf("%s[%s]", v.URL, v.Title) case element.Word: diff --git a/format/asciidoc_test.go b/formatter/asciidoc_test.go similarity index 82% rename from format/asciidoc_test.go rename to formatter/asciidoc_test.go index c425038..bb2a5fd 100644 --- a/format/asciidoc_test.go +++ b/formatter/asciidoc_test.go @@ -1,48 +1,46 @@ -package format_test +package formatter_test import ( - "strings" "testing" "time" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" - "ewintr.nl/adoc/format" - "ewintr.nl/adoc/parser" + "ewintr.nl/adoc/formatter" "ewintr.nl/go-kit/test" ) func TestAsciiDoc(t *testing.T) { - input := `= A Title - -Some document - -With some text. - -` - - doc := parser.New(strings.NewReader(input)).Parse() - test.Equals(t, input, format.AsciiDoc(doc)) -} - -func TestAsciiDocHeader(t *testing.T) { - input := &adoc.ADoc{ - Title: "title", - Author: "author", - Date: time.Date(2022, time.Month(6), 11, 12, 0, 0, 0, time.UTC), + input := &document.Document{ + Title: "A Title", + Author: "Author", + Date: time.Date(2022, time.Month(6), 11, 0, 0, 0, 0, time.UTC), Attributes: map[string]string{ "key1": "value 1", "key2": "value 2", }, + Content: []element.Element{ + element.Paragraph{ + Elements: []element.Element{ + element.Word("some"), + element.WhiteSpace(" "), + element.Word("text"), + }, + }, + }, } - exp := `= title -author + + exp := `= A Title +Author 2022-06-11 :key1: value 1 :key2: value 2 + +some text + ` - test.Equals(t, exp, format.AsciiDocHeader(input)) + test.Equals(t, exp, formatter.NewAsciiDoc().Format(input)) } func TestAsciiDocFragment(t *testing.T) { @@ -172,7 +170,7 @@ some text }, } { t.Run(tc.name, func(t *testing.T) { - test.Equals(t, tc.exp, format.AsciiDocFragment(tc.input)) + test.Equals(t, tc.exp, formatter.NewAsciiDoc().FormatFragments(tc.input)) }) } } diff --git a/formatter/formatter.go b/formatter/formatter.go new file mode 100644 index 0000000..9945ceb --- /dev/null +++ b/formatter/formatter.go @@ -0,0 +1,11 @@ +package formatter + +import ( + "ewintr.nl/adoc/document" + "ewintr.nl/adoc/element" +) + +type Formatter interface { + Format(doc *document.Document) string + FormatFragments(els ...element.Element) string +} diff --git a/format/html.go b/formatter/html.go similarity index 60% rename from format/html.go rename to formatter/html.go index 020546a..e5ce24b 100644 --- a/format/html.go +++ b/formatter/html.go @@ -1,10 +1,10 @@ -package format +package formatter import ( "fmt" "html" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" "ewintr.nl/go-kit/slugify" ) @@ -19,20 +19,26 @@ const htmlPageTemplate = ` ` -func HTML(doc *adoc.ADoc) string { - return fmt.Sprintf(htmlPageTemplate, html.EscapeString(doc.Title), HTMLFragment(doc.Content...)) +type HTML struct{} + +func NewHTML() *HTML { + return &HTML{} } -func HTMLFragment(els ...element.Element) string { +func (h *HTML) Format(doc *document.Document) string { + return fmt.Sprintf(htmlPageTemplate, html.EscapeString(doc.Title), h.FormatFragments(doc.Content...)) +} + +func (h *HTML) FormatFragments(els ...element.Element) string { var html string for _, el := range els { - html += htmlElement(el) + html += h.htmlElement(el) } return html } -func htmlElement(el element.Element) string { +func (h *HTML) htmlElement(el element.Element) string { switch v := el.(type) { case element.SubTitle: return fmt.Sprintf("

%s

\n", slugify.Slugify(v.Text()), html.EscapeString(v.Text())) @@ -43,19 +49,19 @@ func htmlElement(el element.Element) string { for _, i := range v { items = append(items, i) } - return fmt.Sprintf("\n", HTMLFragment(items...)) + return fmt.Sprintf("\n", h.FormatFragments(items...)) case element.ListItem: - return fmt.Sprintf("
  • %s
  • \n", HTMLFragment(v...)) + return fmt.Sprintf("
  • %s
  • \n", h.FormatFragments(v...)) case element.CodeBlock: return fmt.Sprintf("
    %s
    ", html.EscapeString(v.Text())) case element.Paragraph: - return fmt.Sprintf("

    %s

    \n", HTMLFragment(v.Elements...)) + return fmt.Sprintf("

    %s

    \n", h.FormatFragments(v.Elements...)) case element.Strong: - return fmt.Sprintf("%s", HTMLFragment(v...)) + return fmt.Sprintf("%s", h.FormatFragments(v...)) case element.Emphasis: - return fmt.Sprintf("%s", HTMLFragment(v...)) + return fmt.Sprintf("%s", h.FormatFragments(v...)) case element.Code: - return fmt.Sprintf("%s", HTMLFragment(v...)) + return fmt.Sprintf("%s", h.FormatFragments(v...)) case element.Link: return fmt.Sprintf("%s", v.URL, html.EscapeString(v.Title)) case element.Word: diff --git a/format/html_test.go b/formatter/html_test.go similarity index 94% rename from format/html_test.go rename to formatter/html_test.go index 12e3ac4..5da2c79 100644 --- a/format/html_test.go +++ b/formatter/html_test.go @@ -1,11 +1,11 @@ -package format_test +package formatter_test import ( "strings" "testing" "ewintr.nl/adoc/element" - "ewintr.nl/adoc/format" + "ewintr.nl/adoc/formatter" "ewintr.nl/adoc/parser" "ewintr.nl/go-kit/test" ) @@ -29,7 +29,7 @@ With some text.` ` doc := parser.New(strings.NewReader(input)).Parse() - test.Equals(t, exp, format.HTML(doc)) + test.Equals(t, exp, formatter.NewHTML().Format(doc)) } func TestHTMLFragment(t *testing.T) { @@ -160,7 +160,7 @@ func TestHTMLFragment(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - test.Equals(t, tc.exp, format.HTMLFragment(tc.input)) + test.Equals(t, tc.exp, formatter.NewHTML().FormatFragments(tc.input)) }) } } diff --git a/formatter/text.go b/formatter/text.go new file mode 100644 index 0000000..134648a --- /dev/null +++ b/formatter/text.go @@ -0,0 +1,29 @@ +package formatter + +import ( + "fmt" + + "ewintr.nl/adoc/document" + "ewintr.nl/adoc/element" +) + +type Text struct{} + +func NewText() *Text { + return &Text{} +} + +func (t *Text) Format(doc *document.Document) string { + txt := fmt.Sprintf("%s\n\n", doc.Title) + txt += t.FormatFragments(doc.Content...) + return txt +} + +func (t *Text) FormatFragments(els ...element.Element) string { + var text string + for _, el := range els { + text += fmt.Sprintf("%s\n\n", el.Text()) + } + + return text +} diff --git a/format/text_test.go b/formatter/text_test.go similarity index 72% rename from format/text_test.go rename to formatter/text_test.go index 1f53b67..a58ce5f 100644 --- a/format/text_test.go +++ b/formatter/text_test.go @@ -1,10 +1,10 @@ -package format_test +package formatter_test import ( "strings" "testing" - "ewintr.nl/adoc/format" + "ewintr.nl/adoc/formatter" "ewintr.nl/adoc/parser" "ewintr.nl/go-kit/test" ) @@ -25,5 +25,5 @@ With some text. ` doc := parser.New(strings.NewReader(input)).Parse() - test.Equals(t, exp, format.Text(doc)) + test.Equals(t, exp, formatter.NewText().Format(doc)) } diff --git a/parser/parser.go b/parser/parser.go index 1534e14..9277feb 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -3,13 +3,13 @@ package parser import ( "io" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" "ewintr.nl/adoc/token" ) type Parser struct { - doc *adoc.ADoc + doc *document.Document tr *token.TokenReader els []element.Element } @@ -21,13 +21,13 @@ func New(reader io.Reader) *Parser { func NewParserFromChannel(toks chan token.Token) *Parser { return &Parser{ - doc: adoc.New(), + doc: document.New(), tr: token.NewTokenReader(toks), els: []element.Element{}, } } -func (p *Parser) Parse() *adoc.ADoc { +func (p *Parser) Parse() *document.Document { result, ok := element.NewHeaderFromTokens(p.tr) if ok { if h, ok := result.Element.(element.Header); ok { diff --git a/parser/parser_test.go b/parser/parser_test.go index f4d8699..15bf7af 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "ewintr.nl/adoc" + "ewintr.nl/adoc/document" "ewintr.nl/adoc/element" "ewintr.nl/adoc/parser" "ewintr.nl/go-kit/test" @@ -14,11 +14,11 @@ func TestParser(t *testing.T) { for _, tc := range []struct { name string input string - exp *adoc.ADoc + exp *document.Document }{ { name: "empty", - exp: adoc.New(), + exp: document.New(), }, { name: "codeblock paragraph edge", @@ -29,7 +29,7 @@ a code block ---- And then some text`, - exp: &adoc.ADoc{ + exp: &document.Document{ Title: "some title", Attributes: map[string]string{}, Content: []element.Element{