Golang + TOML で環境ごとに異なる設定を扱う

# TOML について

* [公式のREADME](https://github.com/toml-lang/toml)と以下の解説記事が詳しい
  * [設定ファイル記述言語 TOML](http://qiita.com/b4b4r07/items/77c327742fc2256d6cbe)
  * [【個人メモ】設定ファイルフォーマットにはTOMLがいいのかも](http://qiita.com/futoase/items/fd697a708fcbcee104de)

# TOML の簡単な解説

* 以下の TOML と JSON がだいたい一緒

```toml
int1 = 1
float1 = 0.1
bool1 = true
string1 = "string 1"
array1 = [1, 2, 3]

[table1]
col1 = "col 1"

[table1.subtable1]
col2 = "col 2"

[[tables]]
col3 = "col 3a"

[[tables]]
col3 = "col 3b"
```

```json
{
	"int1": 1,
	"float1": 0.1,
	"bool1": true,
	"string1": "string 1",
	"array": [1, 2, 3],
	"table1": {
		"col1": "col 1",
		"subtable1": {
			"col2": "col 2"
		}
	},
	"tables": [
		{
			"col3": "col 3a"
		},
		{
			"col3": "col 3b"
		},
	]
}
```

* 基本の型として Integer, Float, Boolean, String, Datetime が扱える
* Array は `[ ]` にいれてカンマ区切りでインラインでも複数ラインでも扱える
* Table は `[TABLE_NAME]` として定義したら次のテーブルかファイル末尾までの要素が TABLE_NAME テーブルに入る
* `[TABLE_NAME.SUB_TABLE_NAME]` でテーブルをネストできる
* `[[ARRAY_OF_TABLE_NAME]]` でテーブルの配列が宣言できる

# Golang で TOML を扱う

* [公式のREADME](https://github.com/toml-lang/toml) に各言語ごとのパーサーへのリンクがある
* Golang で最新バージョンに対応しているものだと [github.com/naoina/toml](https://github.com/naoina/toml) が一番扱いやすそう

# Golang + TOML で環境ごとに異なる設定を扱う

* Rails とかの設定みたいにデフォルトの値と各環境ごとの値を定義しておいてマージして扱いたい
* `github.com/naoina/toml` でデフォルト設定の構造体と環境ごとの設定の構造体を作ってマージするとかやりたかったが、環境ごと構造体のフィールドがゼロ値の場合に、設定されていないのかゼロ値が明示的に定義されているのかが判別できず目論見が失敗した
* なので自分でいい感じにしてくれる [github.com/nirasan/environment-toml](https://github.com/nirasan/environment-toml) を作ってみた

## `environment-toml` 概要

* `environment-toml` はファイルのパスと実行環境名を渡すことで TOML ファイルを読み込み設定用の構造体にセットする
* キー名 `key` の値を読み込む場合 `実行環境名.key` が定義されていればそちらで上書きされる

## 例1. 基本型の値を環境ごとに上書きする

### TOML ファイル

```toml:config.toml
username = "user"
password = "pass"

[development]
username = "root"

[production]
password = "toolongpassword"
```

### 読み込み実行

```go
import "github.com/nirasan/environment-toml"

type Config struct {
	Username string
	Password string
}

// 実行環境が development の場合
c := &Config{}
toml.Load(c, "config.toml", "development")
fmt.Println(c.Username) //=> root | development.username に上書きされている
fmt.Println(c.Password) //=> pass | password そのまま

// 実行環境が production の場合
c = &Config{}
toml.Load(c, "config.toml", "production")
fmt.Println(c.Username) //=> user            | username そのまま
fmt.Println(c.Password) //=> toolongpassword | production.password に上書きされている
```

## 例2. Table のフィールドの値を環境ごとに上書きする

### TOML ファイル

```toml:config.toml
[database]
username = "user"
password = "pass"

[database.development]
username = "root"

[database.production]
password = "toolongpassword"
```

### 読み込み実行

```go
import "github.com/nirasan/environment-toml"

type Database struct {
	Username string
	Password string
}

type Config struct {
	Database Database
}

// 実行環境が development の場合
c := &Config{}
toml.Load(c, "config.toml", "development")
fmt.Println(c.Database.Username) //=> root | database.development.username に上書きされている
fmt.Println(c.Database.Password) //=> pass | database.password そのまま

// 実行環境が production の場合
c = &Config{}
toml.Load(c, "config.toml", "production")
fmt.Println(c.Database.Username) //=> user            | database.username そのまま
fmt.Println(c.Database.Password) //=> toolongpassword | database.production.password に上書きされている
```

# おわりに

* TOML いい感じなのでドッグフーディングもかねて使っていきたい