Pārlūkot izejas kodu

документация и пример

kpmy 10 gadi atpakaļ
vecāks
revīzija
d57edfbd13

+ 31 - 0
demo2/demo2.go

@@ -0,0 +1,31 @@
+package main
+
+import (
+	"odf/generators"
+	"odf/mappers"
+	"odf/model"
+	_ "odf/model/stub" //don't forget pimpl
+	"odf/xmlns"
+	"os"
+)
+
+func main() {
+	if output, err := os.Create("demo2.odf"); err == nil {
+		//we need an empty model
+		m := model.ModelFactory()
+		//standard formatter
+		fm := &mappers.Formatter{}
+		//couple them
+		fm.ConnectTo(m)
+		//we want text
+		fm.MimeType = xmlns.MimeText
+		//yes we can
+		fm.Init()
+		//pretty simple
+		fm.WriteString("Hello, World!")
+		//store file
+		generators.GeneratePackage(m, nil, output, fm.MimeType)
+		//cleanup
+		defer output.Close()
+	}
+}

+ 5 - 0
generators/gen.go

@@ -13,18 +13,22 @@ import (
 	"odf/xmlns/urn"
 )
 
+//Embeddable is any object that can provide []byte data for embedding in document package file (pictures for example)
 type Embeddable interface {
 	MimeType() xmlns.Mime
 	Reader() io.Reader
 }
 
+//Parts is a list of root "files" of document package
 type Parts map[string]*bytes.Buffer
 
+//Entry is a part of Manifest
 type Entry struct {
 	MediaType string `xml:"manifest:media-type,attr"`
 	FullPath  string `xml:"manifest:full-path,attr"`
 }
 
+//Manifest file structure, contains descriptors for any parts of document
 type Manifest struct {
 	XMLName xml.Name
 	NS      string  `xml:"xmlns:manifest,attr"`
@@ -62,6 +66,7 @@ func docParts(m model.Model) (ret Parts) {
 	return
 }
 
+//GeneratePackage builds a zip-archived content of document model and embedded files and writes content to target Writer
 func GeneratePackage(m model.Model, embed map[string]Embeddable, out io.Writer, mimetype xmlns.Mime) {
 	z := zip.NewWriter(out)
 	mime := &zip.FileHeader{Name: xmlns.Mimetype, Method: zip.Store} //файл mimetype не надо сжимать, режим Store

+ 7 - 0
mappers/attr.go

@@ -11,6 +11,7 @@ import (
 	"strconv"
 )
 
+//Attr holds a number of style nodes of document model and writes attributes. Also it holds cache of recently used attributes for reuse
 type Attr struct {
 	doc     model.Model
 	ds      model.Leaf //document styles
@@ -37,6 +38,7 @@ func (a *Attr) reset() {
 	a.current = make(map[string]attr.Attributes)
 }
 
+//Init called when empty document is initialized
 func (a *Attr) Init(m model.Model) {
 	a.doc = m
 	wr := a.doc.NewWriter()
@@ -56,6 +58,7 @@ func (a *Attr) Init(m model.Model) {
 	a.reset()
 }
 
+//Fit finds appropriate attributes for given name and calls closure for applying attributes
 func (a *Attr) Fit(n model.LeafName, callback func(a attr.Attributes)) {
 	fit := make(map[model.LeafName]attr.Attributes)
 	for _, v := range a.current {
@@ -66,6 +69,7 @@ func (a *Attr) Fit(n model.LeafName, callback func(a attr.Attributes)) {
 	}
 }
 
+//RegisterFont writes font entry to Font Face Declaration section
 func (a *Attr) RegisterFont(name, fontface string) {
 	if a.fonts[name] == nil {
 		wr := a.doc.NewWriter()
@@ -81,6 +85,7 @@ func (a *Attr) RegisterFont(name, fontface string) {
 	}
 }
 
+//Flush writes styles to document model
 func (a *Attr) Flush() {
 	if !a.stored {
 		wr := a.doc.NewWriter()
@@ -100,6 +105,7 @@ func (a *Attr) Flush() {
 	}
 }
 
+//OldAttr return already written attributes for new attribute if their contents equals
 func (a *Attr) OldAttr(n attr.Attributes) attr.Attributes {
 	for _, v := range a.old {
 		if v.Equal(n) {
@@ -109,6 +115,7 @@ func (a *Attr) OldAttr(n attr.Attributes) attr.Attributes {
 	return nil
 }
 
+//SetDefaults sets default attributes of document, only TextAttributes and ParagraphAttributes supported by now
 func (a *Attr) SetDefaults(al ...attr.Attributes) {
 	wr := a.doc.NewWriter()
 	wr.Pos(a.ds)

+ 2 - 0
mappers/attr/base.go

@@ -5,8 +5,10 @@ import (
 	"odf/model"
 )
 
+//New is shortcut for factory function model.ModelFactory
 var New func(name model.LeafName) model.Leaf
 
+//Attributes interface that is supported by current version of mappers.Attr container
 type Attributes interface {
 	Name(...string) string
 	Equal(Attributes) bool

+ 1 - 0
mappers/attr/extra.go

@@ -7,6 +7,7 @@ import (
 	"strconv"
 )
 
+//Border style of table cell
 type Border struct {
 	Width float64
 	Color color.Color

+ 4 - 0
mappers/attr/para.go

@@ -7,6 +7,7 @@ import (
 	"odf/xmlns/text"
 )
 
+//ParagraphAttributes is ODF Paragraph Family style fluent builder
 type ParagraphAttributes struct {
 	named
 	easy
@@ -28,16 +29,19 @@ func (p *ParagraphAttributes) Write(wr model.Writer) {
 	p.apply(wr)
 }
 
+//AlignRight on page
 func (p *ParagraphAttributes) AlignRight() *ParagraphAttributes {
 	p.put(fo.TextAlign, fo.Right, nil)
 	return p
 }
 
+//AlignCenter on page
 func (p *ParagraphAttributes) AlignCenter() *ParagraphAttributes {
 	p.put(fo.TextAlign, fo.Center, nil)
 	return p
 }
 
+//PageBreak with new paragraph written (it will be first on new page)
 func (p *ParagraphAttributes) PageBreak() *ParagraphAttributes {
 	p.put(fo.BreakBefore, true, func(v value) {
 		if x := v.data.(bool); x {

+ 12 - 0
mappers/attr/table.go

@@ -7,6 +7,7 @@ import (
 	"odf/xmlns/table"
 )
 
+//TableAttributes is a Table Family style fluent builder
 type TableAttributes struct {
 	named
 	easy
@@ -28,31 +29,37 @@ func (t *TableAttributes) Write(wr model.Writer) {
 	t.apply(wr)
 }
 
+//BorderModel of table (table.BorderModelCollapsing, table.BorderModelSeparating
 func (t *TableAttributes) BorderModel(m string) *TableAttributes {
 	t.put(table.BorderModel, m, nil)
 	return t
 }
 
+//AlignLeft table on page
 func (t *TableAttributes) AlignLeft() *TableAttributes {
 	t.put(table.Align, table.AlignLeft, nil)
 	return t
 }
 
+//AlignRight table on page
 func (t *TableAttributes) AlignRight() *TableAttributes {
 	t.put(table.Align, table.AlignRight, nil)
 	return t
 }
 
+//AlignCenter table on page
 func (t *TableAttributes) AlignCenter() *TableAttributes {
 	t.put(table.Align, table.AlignCenter, nil)
 	return t
 }
 
+//Width of whole table
 func (t *TableAttributes) Width(w float64) *TableAttributes {
 	t.put(style.Width, w, nil)
 	return t
 }
 
+//TableRowAttributes represents Table Row Family style fluent builder
 type TableRowAttributes struct {
 	named
 	easy
@@ -74,6 +81,7 @@ func (t *TableRowAttributes) Write(wr model.Writer) {
 	t.apply(wr)
 }
 
+//UseOptimalRowHeight allows to auto-height rows when displayed
 func (t *TableRowAttributes) UseOptimalRowHeight() *TableRowAttributes {
 	t.put(style.UseOptimalRowHeight, true, triggerBoolAttr(style.UseOptimalRowHeight))
 	return t
@@ -84,6 +92,7 @@ type TableColumnAttributes struct {
 	easy
 }
 
+//TableColumnAttributes represents Table Column Family style fluent builder
 func (t *TableColumnAttributes) Equal(_a Attributes) (ok bool) {
 	a, ok := _a.(*TableColumnAttributes)
 	if ok {
@@ -100,11 +109,13 @@ func (t *TableColumnAttributes) Write(wr model.Writer) {
 	t.apply(wr)
 }
 
+//UseOptimalColumnWidth allows to auto-width columns when displayed
 func (t *TableColumnAttributes) UseOptimalColumnWidth() *TableColumnAttributes {
 	t.put(style.UseOptimalColumnWidth, true, triggerBoolAttr(style.UseOptimalColumnWidth))
 	return t
 }
 
+//TableCellAttributes represents Table Cell Family style fluent builder
 type TableCellAttributes struct {
 	named
 	easy
@@ -126,6 +137,7 @@ func (t *TableCellAttributes) Write(wr model.Writer) {
 	t.apply(wr)
 }
 
+//Border sets attributes for all borders (left, right, top, bottom)
 func (t *TableCellAttributes) Border(b Border) *TableCellAttributes {
 	t.put(fo.BorderRight, b.String(), nil)
 	t.put(fo.BorderLeft, b.String(), nil)

+ 6 - 0
mappers/attr/text.go

@@ -8,6 +8,7 @@ import (
 	"odf/xmlns/text"
 )
 
+//TextAttributes is a Text Family fluent style builder
 type TextAttributes struct {
 	fontFace string
 	size     int
@@ -45,26 +46,31 @@ func (t *TextAttributes) Write(wr model.Writer) {
 	}
 }
 
+//Size of text in points
 func (t *TextAttributes) Size(s int) *TextAttributes {
 	t.size = s
 	return t
 }
 
+//FontFace of text (font-faces are registered in mappers.Formatter
 func (t *TextAttributes) FontFace(name string) *TextAttributes {
 	t.fontFace = name
 	return t
 }
 
+//Color of text
 func (t *TextAttributes) Color(col color.Color) *TextAttributes {
 	t.col = col
 	return t
 }
 
+//Bold style of text
 func (t *TextAttributes) Bold() *TextAttributes {
 	t.bold = true
 	return t
 }
 
+//Italic style of text
 func (t *TextAttributes) Italic() *TextAttributes {
 	t.italic = true
 	return t

+ 4 - 2
mappers/embed.go

@@ -14,11 +14,13 @@ import (
 	"time"
 )
 
+//Draw holds image data and it's mimetype
 type Draw struct {
 	rd   io.Reader
 	mime xmlns.Mime
 }
 
+//NewDraw constructor
 func NewDraw(source io.Reader, _mime xmlns.Mime) *Draw {
 	return &Draw{rd: source, mime: _mime}
 }
@@ -36,7 +38,7 @@ func nextUrl() (ret string) {
 	return
 }
 
-//generators.Embeddable
+//Reader implements generators.Embeddable
 func (d *Draw) Reader() io.Reader {
 	return d.rd
 }
@@ -45,7 +47,7 @@ func (d *Draw) MimeType() xmlns.Mime {
 	return d.mime
 }
 
-//запись изображения
+//WriteTo writes image (link to image) to document model, don't forget to pass Draw as Embeddable to package generator
 func (d *Draw) WriteTo(fm *Formatter, name string, w, h interface{}) string {
 	fm.defaultParaMapper.makePara()
 	wr := fm.m.NewWriter()

+ 13 - 0
mappers/fmt.go

@@ -10,8 +10,13 @@ import (
 	"reflect"
 )
 
+//New is shortcut for model.ModelFactory or wrapper
 var New func(name model.LeafName) model.Leaf
 
+//Formatter holds model of document and manages attributes and simple text mapper
+//Main goal of Formatter conception is setting attributes before writing content. This allows to optimize the real attributes storage in document model
+//Anyway, document model can be modified with any other tools, Formatter is my vision of this kind of tools.
+//Represents Mapper in CRM pattern
 type Formatter struct {
 	m                 model.Model
 	MimeType          xmlns.Mime
@@ -21,6 +26,7 @@ type Formatter struct {
 	defaultParaMapper *ParaMapper
 }
 
+//ConnectTo document model, for now it can be only newly created model, Formatter does not make existing content analise
 func (f *Formatter) ConnectTo(m model.Model) {
 	assert.For(m.Root().NofChild() == 0, 20, "only new documents for now")
 	f.m = m
@@ -28,6 +34,7 @@ func (f *Formatter) ConnectTo(m model.Model) {
 	f.ready = false
 }
 
+//Init document model with empty content basing on MimeType
 func (f *Formatter) Init() {
 	assert.For(f.MimeType != "", 20)
 	wr := f.m.NewWriter()
@@ -52,20 +59,24 @@ func (f *Formatter) Init() {
 	f.ready = true
 }
 
+//WritePara writes text in new paragraph with the most latest text and paragraph attributes set
 func (f *Formatter) WritePara(s string) {
 	assert.For(f.ready, 20)
 	f.defaultParaMapper.WritePara(s)
 }
 
+//WriteLn writes a line break
 func (f *Formatter) WriteLn() {
 	f.WriteString("\n")
 }
 
+//WriteString writes a text within existing paragraph or creates new paragraph if symbol \r met
 func (f *Formatter) WriteString(s string) {
 	assert.For(f.ready, 20)
 	f.defaultParaMapper.WriteString(s)
 }
 
+//SetAttr sets any type of attributes to be used in future, only one instance of any typed attributes supported. Attributes are flushed only when real content is written. SetAttr can accept nil value for dropping all attributes
 func (f *Formatter) SetAttr(a attr.Attributes) *Formatter {
 	assert.For(f.ready, 20)
 	if a != nil {
@@ -85,10 +96,12 @@ func (f *Formatter) SetAttr(a attr.Attributes) *Formatter {
 	return f
 }
 
+//RegisterFont sets the Font Face Declaration item, name later can be used in attr.TextAttributes
 func (f *Formatter) RegisterFont(name, fontface string) {
 	f.attr.RegisterFont(name, fontface)
 }
 
+//Sets the default attributes, that will be used by odf consumer to display non-attributed content (after SetAttr(nil))
 func (f *Formatter) SetDefaults(a ...attr.Attributes) {
 	f.attr.SetDefaults(a...)
 }

+ 5 - 0
mappers/para.go

@@ -7,6 +7,7 @@ import (
 	"odf/xmlns/text"
 )
 
+//ParaMapper writes and controls text content in document model
 type ParaMapper struct {
 	fm    *Formatter
 	rider model.Writer
@@ -23,12 +24,14 @@ func (p *ParaMapper) makePara() {
 	})
 }
 
+//ConnectTo Formatter that holds document model
 func (p *ParaMapper) ConnectTo(fm *Formatter) {
 	p.fm = fm
 	p.rider = fm.m.NewWriter()
 	p.rider.Pos(fm.root)
 }
 
+//WritePara writes text in new paragraph with the most latest text and paragraph attributes set to connected Formatter
 func (p *ParaMapper) WritePara(s string) {
 	if pos := p.rider.Pos(); pos.Name() == text.P {
 		p.rider.Pos(pos.Parent())
@@ -41,6 +44,8 @@ func (p *ParaMapper) WritePara(s string) {
 	p.WriteString(s)
 
 }
+
+//WriteString writes a text within existing paragraph or creates new paragraph if symbol \r met
 func (p *ParaMapper) WriteString(_s string) {
 	assert.For(p.fm.ready, 20)
 

+ 10 - 0
mappers/table.go

@@ -7,6 +7,7 @@ import (
 	"odf/xmlns/table"
 )
 
+//Table structure holds the table structure and identifies it for TableMapper
 type Table struct {
 	Rows                int
 	Columns             int
@@ -15,11 +16,13 @@ type Table struct {
 	cellCache           [][]model.Leaf
 }
 
+//TableMapper writes and manages tables in document model
 type TableMapper struct {
 	List map[string]*Table
 	fm   *Formatter
 }
 
+//Ready or not
 func (t *TableMapper) Ready() bool {
 	return t.fm != nil && t.fm.ready
 }
@@ -28,11 +31,13 @@ func (t *TableMapper) newWriter(old ...model.Writer) model.Writer {
 	return t.fm.m.NewWriter(old...)
 }
 
+//ConnectTo any valid Formatter and it's document model
 func (t *TableMapper) ConnectTo(fm *Formatter) {
 	t.fm = fm
 	t.List = make(map[string]*Table)
 }
 
+//Write a Table with given name and dimensions, table object is stored internally and can be accessed by name, latest set TableAttributes, TableRowAttributes, TableColumnAttributes and TableCellAttributes are used
 func (t *TableMapper) Write(name string, rows, cols int) {
 	assert.For(t.Ready(), 20)
 	assert.For(name != "" && t.List[name] == nil, 21)
@@ -77,6 +82,7 @@ func (t *TableMapper) Write(name string, rows, cols int) {
 	}
 }
 
+//WriteRows to existing table latest set TableRowAttributes and TableCellAttributes are used
 func (t *TableMapper) WriteRows(this *Table, rows int) {
 	assert.For(t.Ready(), 20)
 	t.fm.attr.Flush()
@@ -102,6 +108,7 @@ func (t *TableMapper) WriteRows(this *Table, rows int) {
 	}
 }
 
+//WriteColumns to existing table latest set TableColumnAttributes and TableCellAttributes are used
 func (t *TableMapper) WriteColumns(this *Table, cols int) {
 	assert.For(t.Ready(), 20)
 	t.fm.attr.Flush()
@@ -125,6 +132,7 @@ func (t *TableMapper) WriteColumns(this *Table, cols int) {
 	}
 }
 
+//Write cells to existing table latest set TableCellAttributes are used
 func (t *TableMapper) WriteCells(this *Table, _row int, cells int) {
 	assert.For(t.Ready(), 20)
 	t.fm.attr.Flush()
@@ -143,6 +151,7 @@ func (t *TableMapper) WriteCells(this *Table, _row int, cells int) {
 	}
 }
 
+//Span merges visually
 func (t *TableMapper) Span(this *Table, row, col int, rowspan, colspan int) {
 	assert.For(t.Ready(), 20)
 	assert.For(rowspan > 0, 21)
@@ -153,6 +162,7 @@ func (t *TableMapper) Span(this *Table, row, col int, rowspan, colspan int) {
 	wr.Attr(table.NumberColumnsSpanned, colspan)
 }
 
+//Pos sets mapper to the cell with given coordinates
 func (t *TableMapper) Pos(this *Table, row, col int) *ParaMapper {
 	ret := new(ParaMapper)
 	ret.ConnectTo(t.fm)

+ 7 - 3
model/c.go

@@ -1,6 +1,10 @@
 package model
 
-type AttrName string
-type LeafName string
-
+//LeafFactory for pimpl, creates nodes by specified name (names in xmlns/* package and corellate to ODF description
 var LeafFactory func(LeafName) Leaf
+
+//ModelFactory for pimpl that creates model
+var ModelFactory func() Model
+
+//Text is special leaf constructor because Text Leaf has no name in ODF document model
+var Text func(s string) Leaf

+ 2 - 0
model/stub/simple_tree.go

@@ -1,3 +1,5 @@
+//Package stub is an implementation of document model, nodes, attributes and riders, it's a lightweight analog of DOM
+//There is no need to create separate type for each ODF document node, because most of them are defined only by it's name, that's why we build a simle tree model where only root nodel of document are special, because they are translated into files of document-package. But they still support Node interface and may be used in other implementations as regular nodes
 package stub
 
 /*

+ 11 - 3
model/tree.go

@@ -1,15 +1,21 @@
 package model
 
+type AttrName string
+type LeafName string
+
+//Attribute of node
 type Attribute interface {
 	String() string
 }
 
+//Leaf is node without children nodes
 type Leaf interface {
 	Name() LeafName
 	Attr(AttrName, ...Attribute) Attribute
 	Parent(...Node) Node
 }
 
+//Node holds chidlren nodes, Carrier in CRM pattern
 type Node interface {
 	Leaf
 	Child(int) Leaf
@@ -17,12 +23,15 @@ type Node interface {
 	NofChild() int
 }
 
+//Model holds root node and constructs special riders
 type Model interface {
 	Root() Node
 	NewReader(...Reader) Reader
 	NewWriter(...Writer) Writer
 }
 
+//Reader is a reading rider in CRM pattern
+//Reader stands on node and runs above it's child nodes
 type Reader interface {
 	InitFrom(Reader)
 	Base() Model
@@ -31,6 +40,8 @@ type Reader interface {
 	Pos(...Leaf) Leaf
 }
 
+//Writer is a modifying rider in CRM pattern
+//Writer stands on node and modifies it's children and attributes
 type Writer interface {
 	InitFrom(Writer)
 	Base() Model
@@ -40,6 +51,3 @@ type Writer interface {
 	Attr(AttrName, interface{}) Writer //for fluid interface
 	Delete(Leaf)
 }
-
-var ModelFactory func() Model
-var Text func(s string) Leaf

+ 2 - 0
xmlns/x.go

@@ -1,3 +1,5 @@
+//Package xmlns contains any constants related to ODF project, and also string names and values of ODF document nodes and attributes
+//Also it contains some validation routines and value format descriptions
 package xmlns
 
 import (