YAML

昨天已經成功把檔案載入變成 []byte 型態,今天要來讀 YAML 檔了。

分析

昨天有提到會使用 go-yaml 解析 YAML 資料,資料格式參考 Faker,大概會長像下面這樣:

lastNames:
-
-
-
-
-
-
-
-
- ...

characterMale:
-
-
-
-
- ...

characterFemale:
-
-
-
-
- ...

go-yaml 的用法大概如下:

s := NamesProvider{}
yaml.Unmarshal(bytes, s)

fmt.Println(s) // 印出解析完的 struct

這樣應該就可以開始實作了。

開工

開始前,一樣要先重構:把切目錄和讀檔的任務放到最外層(main.go)。

不過因為不大清楚 CLI 套件怎麼做全域的任務,所以不如就把解析 YAML 的任務先放在 resource 裡:

type NamesResource struct {
LastNames []string `yaml:"lastNames"`
CharacterMale []string `yaml:"characterMale"`
CharacterFemale []string `yaml:"characterFemale"`
}

func ParseFile(file string) (res NamesResource, err error) {
r, err := ioutil.ReadFile(file)
if err != nil {
return res, err
}

if err := yaml.Unmarshal(r, &res); err != nil {
return res, err
}

return res, nil
}

其中需注意的是,go-yaml 預設會先把 field 轉全小寫,再去 YAML 的資料裡面找。而 LastNames field 預設會找 lastnames 的欄位,然後就找不到,這時會需要用 yaml:"lastNames" 指定要找的欄位。

其他兩個 Command 開頭先執行吧!之後有空再來想想該怎麼重構:

t, _ := provider.ParseFile(c.GlobalString("provider"))

fmt.Println(t)

今天這樣太簡單了。資料都有了,不如就把亂數取名實作出來吧!

回憶一下之前取名的方法(順便騙版面):

func (generator *Generator) Name() string {
length := len(names)

return names[generator.rand.Intn(length)]
}

這裡是用 generator.rand 取得亂數,再去口袋名單裡面取。但現在口袋名單變成了 NameResource,最簡單的做法就是在 Generator 加一個 Resource field:

type Generator struct {
rand *rand.Rand
Resource NamesResource
}

然後直接在 Command Action 指定:

res, _ := provider.ParseFile(c.GlobalString("provider"))

generator := provider.Create()
generator.Resource = res

這樣裡面就會有資料可以用了。接著參考 Faker 的做法,它會把姓跟名分開,實作如下:

func (generator *Generator) Name() string {
return generator.LastName() + generator.FirstName()
}

func (generator *Generator) LastName() string {
length := len(generator.Resource.LastNames)
randomIndex := generator.rand.Intn(length)

return generator.Resource.LastNames[randomIndex]
}

func (generator *Generator) FirstName() string {
merge := append(generator.Resource.CharacterMale, generator.Resource.CharacterFemale...)
length := len(merge)
randomIndex := generator.rand.Intn(length)

return merge[randomIndex]
}

展示

執行結果如下:

$ go run main.go generate
Generate 10
楊雅
李婷
黃明
劉雅
陳明
楊豪
黃春
劉家
王嬌
趙家

詳細程式可以參考 PR Day 20

參考資料