Skip to content

Latest commit

 

History

History
70 lines (51 loc) · 2.64 KB

README.md

File metadata and controls

70 lines (51 loc) · 2.64 KB

Generating Go Code

Unicorn is able to generate code in golang that contains a struct to parse configuration data into as well as functions that will open configuration (JSON or YAML) files and parse their contents into the configuration struct provided.

To instruct Unicorn to generate such a file, simply pass the -go <filename> flag.

The generated Go source code file will be prescribed the package config and will contain:

  1. A Configuration struct
  2. A LoadConfigJson(string) (Configuration, error) function that accepts a JSON file name
  3. A LoadConfigYaml(string) (Configuration, error) function that accepts a YAML file name

As demonstrated in program.go, after placing a generated config.go file in a config config/ directory, we can simply import the config package and parse a generated config/config.json file into an instance of config.Configuration.

This Example

The configuration data in this example was generated by running Unicorn on the Fig file config/test.fig using the command (from this directory)

../../unicorn -json config/out.json -yaml config/out.yaml -go config/config.go config/test.fig

The Fig file in question defines some information about a hypothetical API that our fictional program.go service might want to invoke, as well as some information about the service itself (such as the port and address it should run on).

Caveat

Due to the way variables are handled in the Unicorn interpreter and some limitations of Go's type system, generated Configuration structs cannot be typed as accurately as one might like. Here's a breakdown of what your Configuraion struct is likely to contain:

  1. Integers are always typed int64
  2. Floats are always typed float64
  3. Strings are always typed string
  4. Booleans are always typed bool
  5. Lists are typed []interface{}
  6. Maps are typed map[string]interface{}

Since lists and maps are generic containers in Fig, Unicorn has to rely on the interface{} type to be able to contain any kind of value. That mean that, in order to operate on the contents of a list or a value in a map, you must type cast interface{} to one of the four base types used.

First approach:

If you know the type ahead of time (i.e. it's clear from the Fig code), you can just directly cast a value. For example:

DoSomething(configuration.SomeList[0].(bool))

Second approach:

Determine the type of the value before casting it.

value := configuration.SomeMap["someKey"]
switch value.(type) {
case int64:
    HandleInt(value.(int64))
case float64:
    HandleFloat(value.(float64))
default:
    panic("Oh noes! A value doesn't have a numeric type!")
}