Zaimからスプレッドシートへの転記に使えるChrome Extension
Zaimの履歴をGoogleスプレッドシートやExcelなどに転記するためのChrome Extension「zaimsheet」を作りました。
zaimsheetをインストールすると、Zaim Web版の履歴画面に「スプレッドシート形式」というボタンが追加されます。このボタンをクリックすると以下のような表が表示されます。
表を選択してコピーすると、GoogleスプレッドシートやExcelなどに貼り付けられます。
まだ初版なのでアイコンや説明文などもちゃんと設定していないのですが、そのうち直します。ソースコードは https://github.com/int128/zaimsheet で公開しています。
我が家は独立採算制を採用しているため、Zaimに入力した履歴から家庭内共通費を月次で集計しています。Zaimに社内取引のような概念があるとよいのですが、今のところスプレッドシートで集計しています。
uber-go/dig を使う
GoのDIコンテナ実装である uber-go/dig を使ってみました。
基本的な使い方はGoDocに書いてあります。あえて3行にまとめると以下になります。
c := dig.New() c.Provide(func (/* 生成に必要な型... */) /* 生成される型 */ { /* 生成処理 */ }) c.Invoke(func (/* 実行に必要な型 */) { /* 実行処理 */ })
例えば、以下のように Provide
メソッドを記述すると、 interface GetUserUsecase
を実装するオブジェクトを生成するには interface UserRepository
が必要であると宣言できます。
c := dig.New() c.Provide(func (r UserRepository) GetUserUsecase { return &GetUserUsecaseImpl{UserRepository: r} })
Springでいうconfiguration classの @Bean
と同じです。
// これはJava/Springの例 @Bean public GetUserUsecase(UserRepository r) GetUserUsecase { return new UserRepositoryImpl(r) }
依存関係に基づいて実際に値を取得するには Invoke
メソッドを実行します。例えば、以下のように記述すると interface GetUserUsecase
を実装するオブジェクトを取得して実行できます。
c.Invoke(func (u GetUserUsecase) {
u.Do()
})
Provide
で宣言した依存関係は再帰的に解決されます。例えば、以下のように記述すると interface GetUserUsecase
→ interface UserRepository
→ interface UserAPIClient
の依存関係を宣言できます。
c := dig.New() c.Provide(func (r UserRepository) GetUserUsecase { return &GetUserUsecaseImpl{UserRepository: r} }) c.Provide(func (c UserAPIClient) UserRepository { return &UserRepositoryImpl{UserAPIClient: c} })
実践的な使い方としては、依存関係を別のパッケージに切り出すとよいでしょう。
package di func New() (*dig.Container, error) { c := dig.New() if err := c.Provide(func (r UserRepository) GetUserUsecase { return &GetUserUsecaseImpl{UserRepository: r} }); err != nil { return nil, errors.WithStack(err) } if err := c.Provide(func (c UserAPIClient) UserRepository { return &UserRepositoryImpl{UserAPIClient: c} }); err != nil { return nil, errors.WithStack(err) } return c, nil }
宣言した依存関係が正しく解決できるかテストを書いておくとよいでしょう。
package di_test func TestInvoke(t *testing.T) { c, err := di.New() if err != nil { t.Fatalf("error while di.New: %+v", err) } if err := c.Invoke(func(u GetUserUsecase) { t.Logf("%+v", u) }); err != nil { t.Fatalf("error while c.Invoke: %+v", err) } }
構造体に dig.In
を埋め込むと構造体のメンバに定義されている型を解決して代入してくれます。この方法を使うと Provide
に渡す関数を簡潔に書けます。
type GetUserUsecaseImpl struct { dig.In UserRepository UserRepository FooRepository FooRepository BarRepository BarRepository }
c.Provide(func (i GetUserUsecaseImpl) GetUserUsecase { return &i })
Springでいう @Autowired
に近いですね。
// これはJava/Springの例 public class GetUserUsecaseImpl { @Autowired private UserRepository userRepository @Autowired private FooRepository fooRepository @Autowired private BarRepository barRepository }
なお、小規模なアプリケーションの場合は、digを使わずに手作業で依存関係を解決する方法もあります。例えば、以下のようにmainにすべての依存関係を書いてしまいます。
func main() { u := &GetUserUsecaseImpl{ UserRepository: &UserRepositoryImpl{ UserAPIClient: &UserAPIClientImpl{ Client: http.DefaultClient, }, }, } if err := u.Do(context.Background()); err != nil { log.Fatalf("Error: %s", err) } }
依存関係が単純な場合は手作業による解決でも十分ですが、複雑になってきた場合はdigのようなDIコンテナの導入を検討するとよいでしょう。
Cloud Buildで任意のシェルスクリプトを実行する
Google Cloud Buildでは公式のイメージが数多く提供されており、コマンドに対応するイメージを指定する形になっている。例えば、gcloud
コマンドを使いたい場合は以下のように gcr.io/cloud-builders/gcloud
イメージを指定すればよい。
steps: - name: gcr.io/cloud-builders/gcloud args: - app - deploy
このように基本的な操作を行う場合はとてもシンプルに記述できるが、条件分岐や文字列置換などの複雑な操作はサポートされていない。そのような複雑な操作を行いたい場合はbashでシェルスクリプトを実行すればよい。
例えば、以下のように entrypoint
を記述すると bash -c
を経由してシェルスクリプトを実行できる。
steps: - name: gcr.io/cloud-builders/gcloud env: - TAG_NAME=$TAG_NAME entrypoint: bash args: - -c - | gcloud app deploy --version="${TAG_NAME//./-}"
この例では、タグ名のピリオドをハイフンに置換した上で、App Engineにアプリケーションをデプロイしている。Cloud BuildのYAMLではサポートされていない文字列置換を使いたい場合はbashを利用すればよい。