Browse Source

some more documentation is good

pull/16/head
Brett Langdon 11 years ago
parent
commit
6bc38900d9
3 changed files with 136 additions and 144 deletions
  1. +51
    -144
      README.md
  2. +5
    -0
      example_test.go
  3. +80
    -0
      forge.go

+ 51
- 144
README.md View File

@ -5,128 +5,49 @@ forge
Forge is a configuration syntax and parser. Forge is a configuration syntax and parser.
**Note:** This is still under active development, please report any issues or feature requests.
## Installation ## Installation
`git get github.com/brettlangdon/forge` `git get github.com/brettlangdon/forge`
## File format
The format was influenced a lot by nginx configuration file format.
```config
# Global settings
global_key = "string value";
# Sub section
sub_settings {
sub_int = 500;
sub_float = 80.80;
# Sub-Sub Section
sub_sub_settings {
sub_sub_sub_settings {
key = "value";
}
}
}
# Second section
second {
key = "value";
global_reference = sub_settings.sub_float;
local_reference = .key; # References second.key
include "/path/to/other/settings/*.cfg";
}
```
For normal settings the format is the key followed by an equal sign followed by the value and lastly ending with a semicolon.
`<key> = <value>;`
Sections (basically a map) is formatted as the section name with the section's settings wrapped in brackets.
`<section> { <key> = <value>; }`
Comments start with a pound sign `#` and end with a newline. A comment can exist on the same line as settings/sections, but the comment must end the line.
Includes are allowed simply by using the directive `include` followed by a string pointing to the location of the file(s) you want to include.
`include` uses go's [filepath.Match](http://golang.org/pkg/path/filepath/#Glob) functionality to find all files matching the provided pattern.
Each file is included directly where it's `include` statement is called from.
`include "/etc/app/*.cfg";`
## Data types
### Boolean
A boolean value is either `true` or `false` of any case.
`TRUE`, `true`, `True`, `FALSE`, `False`, `false`.
### Null
A null value is allowed as `null` of any case.
`NULL`, `Null`, `null`.
### String
A string value is wrapped by double quotes (single quotes will not work).
`"string value"`, `"single ' quotes ' allowed"`.
As of right now there is no way to escape double quotes within a string's value;
### Number
There are two supported numbers, Integer and Float, both of which are simply numbers with the later having one period.
`500`, `50.56`.
### Section
Sections are essentially maps, that is a setting whose purpose is to hold other settings.
Sections can be used to namespace settings.
## Documentation
`section { setting = "value"; }`.
Documentation can be viewed on godoc: https://godoc.org/github.com/brettlangdon/forge
## Example
### References
References are used to refer to previously defined settings. There are two kinds of references, a global reference and a local reference;
The general format for a reference is a mix of identifiers and periods, for example `production.db.name`.
A global reference is a reference which starts looking for its value from the top most section (global section).
A local reference is a reference whose value starts with a period, this reference will start looking for it's value from the current section it is within (local section).
You can see example usage in the `example` folder.
```config
production {
db {
name = "forge";
``cfg
# example.cfg
# Global directives
global = "global value";
# Primary section
primary {
string = "primary string value";
integer = 500;
float = 80.80;
boolean = true;
negative = FALSE;
nothing = NULL;
# Include external files
include "./include*.cfg";
# Primary-sub section
sub {
key = "primary sub key value";
} }
} }
development {
db {
name = production.db.name;
}
db_name = .db.name;
# Secondary section
secondary {
another = "secondary another value";
global_reference = global;
primary_sub_key = primary.sub.key;
another_again = .another; # References secondary.another
_under = 50;
} }
``` ```
## API
`github.com/brettlangdon/forge`
* `forge.ParseString(data string) (map[string]interface{}, error)`
* `forge.ParseBytes(data []byte) (map[string]interface{}, error)`
* `forge.ParseFile(filename string) (map[string]interface{}, error)`
* `forge.ParseReader(reader io.Reader) (map[string]interface{}, error)`
## Example
You can see example usage in the `example` folder.
```go ```go
package main package main
@ -138,52 +59,38 @@ import (
) )
func main() { func main() {
// Parse the file `example.cfg` as a map[string]interface{}
// Parse a `SectionValue` from `example.cfg`
settings, err := forge.ParseFile("example.cfg") settings, err := forge.ParseFile("example.cfg")
if err != nil { if err != nil {
panic(err) panic(err)
} }
// Convert the settings to JSON for printing
jsonBytes, err := json.Marshal(settings)
if err != nil {
panic(err)
// Get a single value
if settings.Contains("global") {
// Get `global` casted as `StringValue`
value := settings.GetString("global")
fmt.Printf("global = \"%s\"\r\n", value.GetValue())
} }
// Print the parsed settings
fmt.Println(string(jsonBytes))
}
```
## Future Plans
The following features are currently on my bucket list for the future:
// Get a nested value
value, err := settings.Resolve("primary.included_setting")
fmt.Printf("primary.included_setting = \"%s\"\r\n", value.GetValue())
### Operations/Expressions
// You can also traverse down the sections
primary, err := settings.GetSection("primary")
value, err := primary.GetString("included_setting")
fmt.Printf("primary.included_setting = \"%s\"\r\n", value.GetValue())
Would be nice to have Addition/Subtraction/Multiplication/Division:
// Convert settings to a map
settingsMap, err := settings.ToMap()
fmt.Printf("global = \"%s\"\r\n", settingsMap["global"])
```config
whole = 100
half = whole / 2;
double = whole * 2;
one_more = whole + 1;
one_less = whole - 1;
```
Also Concatenation for strings:
```config
domain = "github.com";
username = "brettlangdon";
name = "forge";
repo_url = domain + "/" + username + "/" + name;
// Convert settings to JSON
jsonBytes, err := settings.ToJSON()
fmt.Printf("\r\n\r\n%s\r\n", string(jsonBytes))
}
``` ```
### API
I'll probably revisit the API, I just threw it together quick, want to make sure it right.
### Documentation
## Issues/Requests?
Documentation is a good thing.
Please feel free to open a github issue for any issues you have or any feature requests.

+ 5
- 0
example_test.go View File

@ -25,6 +25,11 @@ func Example() {
value, err := settings.Resolve("primary.included_setting") value, err := settings.Resolve("primary.included_setting")
fmt.Printf("primary.included_setting = \"%s\"\r\n", value.GetValue()) fmt.Printf("primary.included_setting = \"%s\"\r\n", value.GetValue())
// You can also traverse down the sections manually
primary, err := settings.GetSection("primary")
value, err := primary.GetString("included_setting")
fmt.Printf("primary.included_setting = \"%s\"\r\n", value.GetValue())
// Convert settings to a map // Convert settings to a map
settingsMap, err := settings.ToMap() settingsMap, err := settings.ToMap()
fmt.Printf("global = \"%s\"\r\n", settingsMap["global"]) fmt.Printf("global = \"%s\"\r\n", settingsMap["global"])


+ 80
- 0
forge.go View File

@ -1,3 +1,83 @@
// Forge configuration file format and parser.
//
// Config file example:
//
// # example.cfg
// top_level = "a string";
// primary {
// primary_int = 500;
// sub_section {
// sub_float = 50.5; # End of line comment
// }
// }
// secondary {
// secondary_bool = true;
// secondary_null = null;
//
// # Reference other config value
// local_ref = .secondary_null;
// global_ref = primary.sub_section.sub_float;
//
// # Include all files matching the provided pattern
// include "/etc/app/*.cfg";
// }
//
//
// Config file format:
//
// IDENTIFIER: [_a-zA-Z]+
//
// BOOL: 'true' | 'false'
// NULL: 'null'
// INTEGER: [0-9]+
// FLOAT: INTEGER '.' INTEGER
// STRING: '"' .* '"'
// REFERENCE: [IDENTIFIER] ('.' IDENTIFIER)+
// VALUE: BOOL | NULL | INTEGER | FLOAT | STRING | REFERENCE
//
// INCLUDE: 'include ' STRING ';'
// DIRECTIVE: (IDENTIFIER '=' VALUE | INCLUDE) ';'
// SECTION: IDENTIFIER '{' (DIRECTIVE | SECTION)* '}'
// COMMENT: '#' .* NEWLINE '\n'
//
// CONFIG_FILE: (COMMENT | DIRECTIVE | SECTION)*
//
//
// Values
// * String:
// Any value enclosed in double quotes (single quotes not allowed) (e.g. "string")
// * Integer:
// Any number without decimal places (e.g. 500)
// * Float:
// Any number with decimal places (e.g. 500.55)
// * Boolean:
// The identifiers 'true' or 'false' of any case (e.g. TRUE, True, true, FALSE, False, false)
// * Null:
// The identifier 'null' of any case (e.g. NULL, Null, null)
// * Global reference:
// An identifier which may contain periods, the references are resolved from the global
// section (e.g. global_value, section.sub_section.value)
// * Local reference:
// An identifier which main contain periods which starts with a period, the references
// are resolved from the settings current section (e.g. .value, .sub_section.value)
//
//
// Directives
// * Comment:
// A comment is a pound symbol ('#') followed by any text any which ends with a newline (e.g. '# I am a comment\n')
// A comment can either be on a line of it's own or at the end of any line. Nothing can come after the comment
// until after the newline.
// * Directive:
// A directive is a setting, a identifier and a value. They are in the format '<identifier> = <value>;'
// All directives must end in a semicolon. The value can be any of the types defined above.
// * Section:
// A section is a grouping of directives under a common name. They are in the format '<section_name> { <directives> }'.
// All sections must be wrapped in brackets ('{', '}') and must all have a name. They do not end in a semicolon.
// Sections may be left empty, they do not have to contain any directives.
// * Include:
// An include statement tells the config parser to include the contents of another config file where the include
// statement is defined. Includes are in the format 'include "<pattern>";'. The <pattern> can be any glob
// like pattern which is compatible with `path.filepath.Match` http://golang.org/pkg/path/filepath/#Match
package forge package forge
import ( import (


Loading…
Cancel
Save