Documentation ¶
Overview ¶
Package scl is an implementation of a parser for the Sepia Configuration Language.
SCL is a simple, declarative, self-documenting, semi-functional language that extends HCL (as in https://github.com/hashicorp/hcl) in the same way that Sass extends CSS. What that means is, any properly formatted HCL is valid SCL. If you really enjoy HCL, you can keep using it exclusively: under the hood, SCL ‘compiles’ to HCL. The difference is that now you can explicitly include files, use ‘mixins’ to quickly inject boilerplate code, and use properly scoped, natural variables. The language is designed to accompany Sepia (and, specifically, Sepia plugins) but it's a general purpose language, and can be used for pretty much any configurational purpose.
Full documenation for the language itself, including a language specification, tutorials and examples, is available at https://github.com/homemade/scl/wiki.
Example (Basic) ¶
package main import ( "github.com/homemade/scl" ) func main() { myConfigObject := struct { SomeVariable int `hcl:"some_variable"` }{} if err := scl.DecodeFile(&myConfigObject, "/path/to/a/config/file.scl"); err != nil { // handle error } // myConfigObject is now populated! }
Output:
Example (Parser) ¶
package main import ( "fmt" "log" "github.com/hashicorp/hcl" "github.com/homemade/scl" ) func main() { parser, err := scl.NewParser(scl.NewDiskSystem()) if err != nil { log.Fatal(err) } if err := parser.Parse("myfile.scl"); err != nil { log.Fatal(err) } myConfig := struct { SomeThing string `hcl:"some-thing"` }{} if err := hcl.Decode(&myConfig, parser.String()); err != nil { log.Fatal(err) } fmt.Println(myConfig) }
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DecodeFile ¶
DecodeFile reads the given input file and decodes it into the structure given by `out`.
Types ¶
type FileSystem ¶
type FileSystem interface { Glob(pattern string) ([]string, error) ReadCloser(path string) (content io.ReadCloser, lastModified time.Time, err error) }
A FileSystem is a representation of entities with names and content that can be listed using stangard glob syntax and read by name. The typical implementation for this is a local disk filesystem, but it could be anything – records in a database, objects on AWS S3, the contents of a zip file, virtual files stored inside a binary, and so forth. A FileSystem is required to instantiate the standard Parser implementation.
func NewDiskSystem ¶
func NewDiskSystem(basePath ...string) FileSystem
NewDiskSystem creates a filesystem that uses the local disk, at an optional base path. The default base path is the current working directory.
type MixinDoc ¶
type MixinDoc struct { Name string File string Line int Reference string Signature string Docs string Children MixinDocs }
MixinDoc documents a mixin from a particular SCL file. Since mixins can be nested, it also includes a tree of all child mixins.
type Parser ¶
type Parser interface { Parse(fileName string) error Documentation(fileName string) (MixinDocs, error) SetParam(name, value string) AddIncludePath(name string) String() string }
A Parser takes input in the form of filenames, variables values and include paths, and transforms any SCL into HCL. Generally, a program will only call Parse() for one file (the configuration file for that project) but it can be called on any number of files, each of which will add to the Parser's HCL output.
Variables and includes paths are global for all files parsed; that is, if you Parse() multiple files, each of them will have access to the same set of variables and use the same set of include paths. The parser variables are part of the top-level scope: if a file changes them while it's being parsed, the next file will have the same variable available with the changed value. Similarly, if a file declares a new variable or mixin on the root scope, then the next file will be able to access it. This can become confusing quickly, so it's usually best to parse only one file and let it explicitly include and other files at the SCL level.
SCL is an auto-documenting language, and the documentation is obtained using the Parser's Documentation() function. Only mixins are currently documented. Unlike the String() function, the documentation returned for Documentation() only includes the nominated file.
Example ¶
package main import ( "fmt" "log" "github.com/homemade/scl" ) func main() { parser, err := scl.NewParser(scl.NewDiskSystem()) if err != nil { log.Fatal(err) } if err := parser.Parse("myfile.scl"); err != nil { // This is a language error, which will include // the filename and line of the error, as well // as an explanatory message. log.Fatal(err) } fmt.Println("myfile.scl as HCL:", parser.String()) }
Output:
Example (Documentation) ¶
package main import ( "fmt" "log" "github.com/homemade/scl" ) func main() { parser, err := scl.NewParser(scl.NewDiskSystem()) if err != nil { log.Fatal(err) } documentation, err := parser.Documentation("myfile.scl") if err != nil { log.Fatal(err) } for i, mixin := range documentation { fmt.Printf("Mixin %d: %+v", i, mixin) } }
Output:
Example (IncludePaths) ¶
package main import ( "fmt" "log" "github.com/homemade/scl" ) func main() { parser, err := scl.NewParser(scl.NewDiskSystem()) if err != nil { log.Fatal(err) } parser.AddIncludePath("path/to/library") if err := parser.Parse("myfile.scl"); err != nil { log.Fatal(err) } fmt.Println("myfile.scl as HCL:", parser.String()) }
Output:
Example (Variables) ¶
package main import ( "fmt" "log" "github.com/homemade/scl" ) func main() { parser, err := scl.NewParser(scl.NewDiskSystem()) if err != nil { log.Fatal(err) } parser.SetParam("my-variable", "my value") if err := parser.Parse("myfile.scl"); err != nil { log.Fatal(err) } fmt.Println("myfile.scl as HCL:", parser.String()) }
Output:
func NewParser ¶
func NewParser(fs FileSystem) (Parser, error)
NewParser creates a new, standard Parser given a FileSystem. The most common FileSystem is the DiskFileSystem, but any will do. The parser opens all files and reads all includes using the FileSystem provided.