Documentation
¶
Overview ¶
Package parser is the configurable parser for the conf package.
The primary type exported by this package is Parser. You can use the default parser:
var DefaultParser = Parser{
Runes: Runes{
Assign: []rune{'='},
Quote: []rune{'\'', '"', '`'},
SectionOpen: []rune{'['},
SectionClose: []rune{']'},
},
}
or create your own:
myParser := parser.Parser{
Runes: Runes{
Assign: []rune{'='},
Quote: []rune{'`'}, // Backtick quotes only.
SectionOpen: []rune{'{'}, // Curly bracket sections.
SectionClose: []rune{'}'},
},
}
The given runes should be mutually exclusive sets when creating a Parser; the behavior for disregarding this rule is undefined.
The Parsed Type ¶
When parsing succeeds a type Parsed is returned. It is a map[string]*SectionBlock. Semantically it is a map["section-name"]*SectionBlock.
Global Section ¶
When parsing the input the default starting section is an unnammed section represented by an empty string. Once a section name is parsed all configuration goes into that section and any following sections. No more configuration can be placed in the global section.
See example Global Section under Parser.
Repeated Sections ¶
A SectionBlock contains two members:
Last Section Slice []Section
The Slice member will contain all sections with the same name in the order they were encountered. The Last member contains the last setion encountered.
The example configuration:
[domain] listen = 0.0.0.0 [domain] listen = example.com
Creates a SectionBlock where:
Slice[0] is the section where listen = 0.0.0.0 Slice[1] is the section where listen = example.com Last is the same section as Slice[1]
Section and its Values ¶
The Section and Value types repeat some of concepts encountered already. A Section is a map[string]Value or semantically a map["key"]Value. A Value contains two members:
Last string Slice []string
The Slice member will contain all key=value lines with the same key-name in the order they were encountered. The Last member contains the last key=value encountered for a specific key-name.
The example configuration:
[domains] listen = 0.0.0.0 listen = example.com
Creates a Section where:
Section["listen"].Slice[0] = 0.0.0.0 Section["listen"].Slice[1] = example.com Section["listen"].Last is the same as Section["listen"].Slice[1]
The End Result ¶
The end result is a convenient configuration syntax that allows repeated sections and repeated key=values without adding any special syntax.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var DefaultParser = Parser{ Runes: Runes{ Assign: []rune{'='}, Quote: []rune{'\'', '"', '`'}, SectionOpen: []rune{'['}, SectionClose: []rune{']'}, }, }
DefaultParser is a Parser with common settings.
Functions ¶
This section is empty.
Types ¶
type IsAssign ¶
IsAssign is a function that returns true if the given rune is used to assign a value to a key.
type Parser ¶
type Parser struct {
Runes
}
Parser parses a string into a Configuration.
Example (GlobalSection) ¶
package main
import (
"fmt"
"github.com/nofeaturesonlybugs/conf/parser"
)
func main() {
s := `
hello = world
foo = bar
`
//
if parsed, err := parser.DefaultParser.Parse(s); err != nil {
fmt.Println(err)
} else if _, ok := parsed[""]; ok {
fmt.Printf("The global section.\n")
fmt.Printf("hello = %v\n", parsed[""].Last["hello"].Last)
fmt.Printf("foo = %v", parsed[""].Last["foo"].Last)
} else {
fmt.Println("Global section not found.")
}
}
Output: The global section. hello = world foo = bar
Example (Options) ¶
package main
import (
"fmt"
"github.com/nofeaturesonlybugs/conf/parser"
)
func main() {
s := `
(main)
message ~ /Hello World!/
`
//
parser := &parser.Parser{
Runes: parser.Runes{
Assign: []rune{'~'},
Quote: []rune{'/'},
SectionOpen: []rune{'('},
SectionClose: []rune{')'},
},
}
if parsed, err := parser.Parse(s); err != nil {
fmt.Println(err)
} else if _, ok := parsed["main"]; ok {
fmt.Printf("Section `main` exists.\n")
fmt.Printf("message = %v\n", parsed["main"].Last["message"].Last)
} else {
fmt.Println("Section `main` not found.")
}
}
Output: Section `main` exists. message = Hello World!
Example (Reader) ¶
package main
import (
"fmt"
"strings"
"github.com/nofeaturesonlybugs/conf/parser"
)
func main() {
s := `
[main]
hello = world
foo = bar
`
reader := strings.NewReader(s)
//
if parsed, err := parser.DefaultParser.ParseReader(reader); err != nil {
fmt.Println(err)
} else if _, ok := parsed["main"]; ok {
fmt.Printf("Section `main` exists.\n")
fmt.Printf("hello = %v\n", parsed["main"].Last["hello"].Last)
fmt.Printf("foo = %v", parsed["main"].Last["foo"].Last)
} else {
fmt.Println("Section `main` not found.")
}
}
Output: Section `main` exists. hello = world foo = bar
Example (String) ¶
package main
import (
"fmt"
"github.com/nofeaturesonlybugs/conf/parser"
)
func main() {
s := `
[main]
hello = world
foo = bar
`
//
if parsed, err := parser.DefaultParser.Parse(s); err != nil {
fmt.Println(err)
} else if _, ok := parsed["main"]; ok {
fmt.Printf("Section `main` exists.\n")
fmt.Printf("hello = %v\n", parsed["main"].Last["hello"].Last)
fmt.Printf("foo = %v\n", parsed["main"].Last["foo"].Last)
} else {
fmt.Println("Section `main` not found.")
}
}
Output: Section `main` exists. hello = world foo = bar
type Runes ¶
type Runes struct {
// Any rune present in SectionOpen begins a configuration section line.
SectionOpen []rune
// Any rune present in SectionClose ends a configuration section line.
SectionClose []rune
// Any rune present in Assign acts as an assignment rune and delimits <key ASSIGN value>.
Assign []rune
// Any rune present in Quote acts as a quotation rune; quoted values must use the same rune
// to start and end the quotation.
Quote []rune
}
Runes defines some important runes for a parser.
func (Runes) IsCloseSection ¶
IsCloseSection returns true if the rune closes a section.
func (Runes) IsOpenSection ¶
IsOpenSection returns true if the rune opens a section.
type SectionBlock ¶
SectionBlock contains a slice of all sections that had the same name as well as the last section that had the name.
func (*SectionBlock) Map ¶
func (me *SectionBlock) Map() []map[string][]string
Map returns the section block as a []map[string][]string.
type State ¶
type State int
State describes the parser state.
type Token ¶
type Token int
Token describes a token type.
type Tokenizer ¶
type Tokenizer interface {
// EOF returns true when the tokenizer has no more tokens to return.
EOF() bool
// Memory records the current Tokenizer position and a call to Rewid() will reset the Tokenizer to
// this position. Use this to make consecutive calls to Peek() or Next() for look-ahead past a single token.
Memory()
// Peek returns the next token and its type without advancing the internal counters; an empty string signals
// the end of the Tokenizer's input.
Peek() (string, Token)
// Next returns the token and its type that would be returned by Peek() but then advances internal
// counters to the next possible token.
Next() (string, Token)
// Rewind resets the Tokenizer to the position recorded by calling Memory() or to the beginning
// of the string if Memory was never called.
Rewind()
}
Tokenizer returns tokens.
func NewTokenizer ¶
NewTokenizer creates a new Tokenizer type.