File
文字清單如果都寫死在程式裡的話,擴充性就太差了,預期它應該要可以從檔案抓出文字清單。
分析
基本的檔案操作應該不大會有問題,要思考的會是,該要用什麼樣的格式來存放文字清單?
另外程式應該要從哪載入文字清單?固定位置?或是 Flags 參數帶給程式?
格式的部分,會以好閱讀與修改為主,因此會選擇 YAML,套件使用 go-yaml
,載入路徑會使用 Flags 參數帶入。
go-yaml
試了一下,它支援輸出 Struct 或是 Map。Struct 的參數必須要定義公開,而且要跟 YAML 格式相符,不然會存放失敗,Map 則是進來什麼都吃,沒有這些限制。目前情境還很單純,使用 Struct 是個可行的選擇。
但它只吃字串,所以必須要寫一段讀檔程式,今天就來試試 Flags 參數加讀檔串接吧。
開工
因為 command 要做的事,目前是硬塞到 main.go
裡,這樣會違反單一職責原則。在開始前先重構,把職責分離清楚,不然後面應該會更難搞。
做法很簡單:開一個 command
的目錄,新增兩個 generate.go
與 status.go
,把 Command 原本要給的值,換到這兩個檔案裡面定義即可。
command/generate.go
的內容如下:
var ( |
command/status.go
的內容目前只是樣版,如下:
package command |
這樣 main.go
就會變得非常簡單:
package main |
詳細重構程式可以參考 PR Day 19 前重構
下面開始實作參數與讀檔。撞了很多牆後,參考別人的做法,發現應該是需要先 os.Chdir()
後,再 os.Stat()
就能找得到了,來試看看:
先建立 names.yml
檔案,然後在 command/status.go
的 Action 輸入下面的程式
os.Chdir(".") |
輸出:
&{names.yml 5 420 {579465000 63650306753 0x121e060} {16777220 33188 1 7295335 673970142 1079850989 0 [0 0 0 0] {1514709976 915571588} {1514709953 579465000} {1514709953 579483767} {1514709952 195533478} 5 8 4194304 0 0 0 [0 0]}} <nil> |
看來是可行的,接著使用 io/ioutil
來取得 byte 資料:
os.Chdir(".") |
輸出:
------ File Content Start ------ |
下一步把傳入的檔案參數化,使用 string
格式:
Flags: []cli.Flag{ |
最後 Action 的函式會長這樣:
Action: func(c *cli.Context) error { |
大功告成!
詳細程式可以參考 PR Day 19
問題
讀檔應該會是全域的設定功能,因此下次要開始前,必須要先重構這部分的程式。
參考資料
- [SOLID 之 單一職責原則(Single responsibility principle)][Refactoring Day 7] - 看到 code 寫成這樣我也是醉了,不如試試重構?