mad

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 10, 2018 License: MIT Imports: 14 Imported by: 0

README

mad

Build Status

This is a literate configuration format library for Go inspired by Markdown.

Read about typical usecases here. In short, mad library is not yet another configuration format. It is not really suitable for this role. Its is main strenght are cases where pieces of structured data or code are needed and there's not much nesting in data.

Installation

  • the prefered way is via the dep
    dep ensure -add github.com/sirkon/mad    
    
  • using go get is not recommended, but still should work
    go get github.com/sirkon/mad
    

Simplest usage

Let we have a

  • some temporary table with preaggregated data and several queries running on this table. Let we call this temporary table creation a prepare.
  • quries may run on a temporary table and they also may use other tables
  • actually, it is rather uncommon situation when we need a preaggregated table. In the majority of cases we will use existing tables. Thus, the prepare process is not mandatory.
  • prepare query creates table. There should be a method to delete it.

In final, we have

  • optional prepare create and delete queries
  • regular queries

Let's express this in a Go structure:

import "github.com/sirkon/mad"
…
var job struct {
	Prepare *struct {
		Create mad.Code `mad:"create"`
		Delete mad.Code `mad:"delete"`
	} `mad:"prepare,syntax=sql"` // syntax will stay in the context of nested fields 
	
	Queries []mad.Code `mad:"queries,syntax=sql"`
}

It can be decoded from file as

if err := mad.UnmarshalFile("file.md", &job, mad.NewContext()); err != nil {
	panic(err)
}

And now how the markdown text would look like for this example:

# prepare

## create
```sql
CREATE TABLE tmp AS SELECT * FROM table
```

## delete
```sql
DROP TABLE tmp;
```


# queries

* total amount of events
```sql
SELECT count(1) FROM tmp;
```

* amount of users who created events
```sql
SELECT uniq(user_id) FROM tmp;
```

But it is not you only get these SQL pieces. You also get their position in the Markdown file:

fmt.Println(job.Prepare.Create.Start())
fmt.Println(job.Prepare.Create.Finish())

will output something like

10 1
14 1
  • You can also consume integers, floating points, strings and booleans using raw code blocks (see advanced example):
  • you need mad.Code type to consume code block
  • you need mad.Comment type to consume comment block
  • comments (everything, that is not header or fenced code block) are normally ignored (this is a bug if they aren't) except the case where you are using mad.Comment

This simple example is not different from what you can used to with stdlib JSON package (except may be only fields tagged with mad:".." can be filled by Decoder). But this is human oriented format and that's why special interfaces were introduced:

  • It is possible to control fragment order in Markdown files (define your mad.Decodable type and write down desired decoding order manually)
  • It is possible to use header as a source of information, fulfilling fields with data from header text (define your mad.Manual type)
  • It is possible to reimplement how scalar types are treated (define your own mad.Unmarshaler type)
  • It is possible to match by regexp, not just by fixed name. Usually mad.Manual is used in these cases as a field value type
  • It is possible to match against several syntax types, for instance, use syntax=python perl to match against perl or python fenced code block

see at the harder example here

Why not to use YAML with text blocks?

Because

  • You don't have same "fenced code blocks" in YAML, thus you don't have syntax highlighting, folding, etc for them
  • The human readable reporting was in mind, thus you can get positions of code blocks and headers. YAML parsers available for go cannot pass this information down to the user.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Unmarshal

func Unmarshal(input []byte, dest interface{}, ctx Context) error

Unmarshal unmarshals data from input with context ctx provided into a dest object. Return error != nil on error. err may be of type mad.LocatedError what provides positional information in (line, column) pair as well as error message.

func UnmarshalFile

func UnmarshalFile(fileName string, dest interface{}, ctx Context) error

UnmarshalFile unmarshals data right from the input file and returns error message in the form of <file>:<lin>:<col>: <msg>

Types

type Code

type Code struct {
	Syntax string
	Code   string
	// contains filtered or unexported fields
}

Code is for code decoding.

func (*Code) Decode

func (c *Code) Decode(d *Decoder, ctx Context) error

Decode ...

func (*Code) Finish

func (c *Code) Finish() (lin int, col int)

Finish implementation for locatable

func (*Code) Start

func (c *Code) Start() (lin int, col int)

Start implementation for locatable

type CodeComment

type CodeComment struct {
	Code    Code
	Comment Comment
}

CodeComment for code prolonged by comment

func (*CodeComment) Decode

func (c *CodeComment) Decode(d *Decoder, ctx Context) error

Decode ...

type CodeList

type CodeList struct {
	// contains filtered or unexported fields
}

CodeList is a list of codes that requires at least one peace of code in a least

func (*CodeList) Codes

func (c *CodeList) Codes() []Code

Codes returns collected code fragments

func (*CodeList) Decode

func (c *CodeList) Decode(d *Decoder, ctx Context) error

Decode ...

type Comment

type Comment string

Comment is for comment decoding

func (*Comment) Decode

func (c *Comment) Decode(d *Decoder, ctx Context) error

Decode decodes comment from source decoder

type CommentCode

type CommentCode struct {
	Comment Comment
	Code    Code
}

CommentCode is for code preceded with comment

func (*CommentCode) Decode

func (c *CommentCode) Decode(d *Decoder, ctx Context) error

Decode ...

type Context

type Context struct {
	// contains filtered or unexported fields
}

Context context provides generational generic storage

func NewContext

func NewContext() Context

NewContext ...

func (Context) Get

func (c Context) Get(key string) (value interface{}, ok bool)

Get gets a value of key from context. Returns value and ok = true in case if a key exists in one of generations and value = nil, ok = false otherwise

func (Context) GetString

func (c Context) GetString(key string, d string) string

GetString gets a string of a key if it exists. Raise assertion panic if key exists but not a string. Returns d(efault) when the key is absent

func (Context) MustGet

func (c Context) MustGet(key string) interface{}

MustGet gets a value from context using the Get. It replicates the Get except it raises the panic if no key has been found

func (Context) New

func (c Context) New() Context

New creates new context generation

func (Context) Set

func (c Context) Set(key string, value interface{})

Set sets a binds a value to a key in a last generation of context

func (Context) Steady

func (c Context) Steady(key string, value interface{})

Steady sets the value into the first level

type Decodable

type Decodable interface {
	Decode(d *Decoder, ctx Context) error
}

Decodable is a type that can decode itself using source decoder d, optionally using context ctx And nullify is a handle for setting the object into nil which is the case for optionals

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

Decoder decodes sequence of tokens into destination object

func NewDecoder

func NewDecoder(r io.Reader) (*Decoder, error)

NewDecoder returns a new decoder that reads from r

func (*Decoder) Decode

func (d *Decoder) Decode(dest interface{}, ctx Context) error

Decode decodes data from underlying tokenizer into the dest the dest must not be nil

type FullTokenizer

type FullTokenizer struct {
	// contains filtered or unexported fields
}

FullTokenizer expands fenced blocks for `raw` syntax into the sequence of header:Value items and 'normalizes' levels. Example of normalization, the following tree structure

1.

5.
2.
2.
  4.

will be translated into

1.

2.
2.
2.
  3.

func NewFullTokenizer

func NewFullTokenizer(t7r Tokenizer) *FullTokenizer

NewFullTokenizer ...

func (*FullTokenizer) Confirm

func (f *FullTokenizer) Confirm()

Confirm confirms confirmation in a confirmative way

func (*FullTokenizer) Err

func (f *FullTokenizer) Err() []error

Err returns stack of errors

func (*FullTokenizer) Next

func (f *FullTokenizer) Next() bool

Next ...

func (*FullTokenizer) Token

func (f *FullTokenizer) Token() Locatable

Token ...

type Locatable

type Locatable interface {
	Start() (lin int, col int)
	Finish() (lin int, col int)
}

Locatable for tokens that can locate itself

type LocatedError

type LocatedError struct {
	Lin int
	Col int
	Err error
}

LocatedError points to a error position

func TokenError

func TokenError(token Locatable, err error) LocatedError

TokenError returns LocatedError using token to find Lin and Col position

func TokenErrorf

func TokenErrorf(token Locatable, format string, a ...interface{}) LocatedError

TokenErrorf returns formatted LocatedError using TokenError

func (LocatedError) Error

func (le LocatedError) Error() string

Error for error implementation

type Location

type Location struct {
	Lin int
	Col int

	// XLin and XCol for token's end
	XLin int
	XCol int
}

Location is a getToken position in an input stream

func Point

func Point(lin, col int) Location

Point points to a position

func (Location) Finish

func (l Location) Finish() (lin int, col int)

Finish to implement loc

func (Location) Start

func (l Location) Start() (lin int, col int)

Start to implement loc

type MDTokenizer

type MDTokenizer struct {
	// contains filtered or unexported fields
}

MDTokenizer is a markdown level tokenizer

func NewTokenizer

func NewTokenizer(input []byte) *MDTokenizer

NewTokenizer ...

func (*MDTokenizer) Confirm

func (ts *MDTokenizer) Confirm()

Confirm confirms token read out

func (*MDTokenizer) Next

func (ts *MDTokenizer) Next() bool

Next moves underlying tokenizer to its next

func (*MDTokenizer) Token

func (ts *MDTokenizer) Token() Locatable

Token returns token from underlying tokenizer

type Manual

type Manual interface {
	Decode(dest interface{}, header String, d *Decoder, ctx Context) (Manual, error)

	// Required must be static function, i.e. must be able to execute on zero instance of a type implementing Manual
	Required() bool
}

Manual types command their processing themselves

type RawStorage

type RawStorage struct {
	// contains filtered or unexported fields
}

RawStorage storage for raw parser output

func NewRawStorage

func NewRawStorage(level int) *RawStorage

NewRawStorage constructor

func (*RawStorage) Boolean

func (rs *RawStorage) Boolean(lin, col, xcol int, value string)

Boolean consumes value as boolean

func (*RawStorage) Data

func (rs *RawStorage) Data() []Locatable

Data returns collected data

func (*RawStorage) Err

func (rs *RawStorage) Err() []error

Err returns collected errors

func (*RawStorage) Header

func (rs *RawStorage) Header(lin, col, xcol int, value string)

Header consumes header

func (*RawStorage) ValueNumber

func (rs *RawStorage) ValueNumber(lin, col, xcol int, value string)

ValueNumber consumes value as number

func (*RawStorage) ValueString

func (rs *RawStorage) ValueString(lin, col, xcol int, value string)

ValueString consumes value as string

type String

type String struct {
	Location
	Value string
}

String ...

func (String) String

func (s String) String() string

String for fmt.Stringer implementation

type Tokenizer

type Tokenizer interface {
	Next() bool
	Token() Locatable
	Confirm()
}

Tokenizer abstraction

type Unmarshaler

type Unmarshaler interface {
	Unmarshal(data string) (err error)
}

Unmarshaler is implemented by types that can unmarshal text, identifier, unsinged, integer, numeric, inline_string or boolean.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL