プログラムを書いているさい、スペルミスで恥をかいたことがある人は多いと思います。 特に日本人の方は普段馴染ないため、違和感に気付きにくかったりします。
emacs ではデフォルトでスペルチェックを行なう機能が搭載されていますが、プログラムのように実際の単語ではない単語や書き方が多いと大量に余計なものにヒットしてしまい鬱陶しいです。
そこで、go の linter として使ったりもする、misspell という Go のツールを使用していい感じにできないかを考えました。
emacs で misspell の使用 探したら、すでにやっている人がいました。考えることは一緒ですね。
https://syohex.hatenablog.com/entry/2016/02/15/105101
ただ、これだとバッファが立ち上がってうざいので、minibuffer に結果が出るようにして最初は運用していました。 また、コードを書いている最中に何度もコマンドを実行して確認するのも面倒なので、save-hook に入れて楽をしようと考えました。
(defun run-lint () (interactive) (let ((current (file-name-nondirectory (buffer-file-name)))) (let ((err (with-temp-buffer (call-process "misspell" nil (current-buffer) nil current) (buffer-string)))) (message (string-trim err))))) (add-hook 'after-save-hook 'run-lint) しかし、interactive に呼ぶときはいいのですが、save-hook で呼ばれるときは、体感一瞬しか表示されないので、すごい見辛く感じました。
間違えている箇所のハイライト そこで、今度は間違えている所をハイライトして、目視で確認しやすくしようと考えました。 以下のようなハイライトコードを用意します。
(defun highlight-word (line col) "Highlight Word" (interactive) (save-excursion (goto-line line) (let* ((begin (progn (forward-char col) (point))) (end (progn (forward-word) (point))) (overlay-highlight (make-overlay begin end))) (overlay-put overlay-highlight 'face '(:background "OrangeRed4")) (overlay-put overlay-highlight 'line-highlight-overlay-marker t)))) (defun remove-all-highlight () "remove all line highlight" (interactive) (remove-overlays (point-min) (point-max))) 次に misspell から行と列の情報を抜き出して上記の関数に食わせます。これをフックさせる感じです。...
モチベーション pubsub トリガーの cloud function は非同期にリクエストを投げるため、同期的な API と比べ自動テストを行なうのが困難です(成功失敗のレスポンスが帰ってこないため)。 また、今回僕が作成した function は特に gcp 上でテストを行ないたいものだったため、この問題を真剣に考える必要がありました。
pubsub のリクエストの確認 まず、テストを導入するにあたって、テストで topic を push するさいの方法を確認します。 以下のような形で topic の push をします。
$ gcloud pubsub topics publish sample-topic messageIds: - '2134505983662900' 上記のようにレスポンスで返ってくるのは message の ID のみです。 この情報からどのように cloud function の成功失敗を取ってくるかが肝になります。
cloud function に渡される情報 次に cloud function を見ていきます。cloud function で実行される関数は以下のようなものです。
type pubSubMessage struct { Data []byte `json:"data"` } func ExampleFunction(ctx context.Context, m pubSubMessage) error { // 処理... return nil } この ctx から metadata 関数を使用することで、EventID を取得することができます。 これが先程の messageIds の値と一致します。...
モチベーション 絵文字を作成する際は、普段こちらで行なっているのですが、できるならコマンドで実行したいなとか、もっとランダム要素あった方が楽しいのにな、と思ったので自分で作成してみました。
作成物 今回はコマンドと api のどちらでも動くものが作りたかったため、Go 言語で作成しました。作成したものはこちらです。 どんな感じの挙動になるかをぱっと見たい方は、https://wordimg-otho5yxlgq-an.a.run.app/wordimg を叩くと分かりやすいと思います。以下で軽く使い方の説明をやっていきます。
Http README に書いてある URL に対してクエリとして text を設定するとその text に設定した文字が絵文字として生成されます。試しに以下の URL を叩いてみると分かりやすいと思います。
https://wordimg-otho5yxlgq-an.a.run.app/wordimg?text=helloworld
アクセスするたびに違う画像が表示されるはずです。下の画像も見る人によって変わるはずです。この見る人によって変わる画像ってのが面白そうっていう気持ちだけで作成しました。
他にもいくつかクエリを用意したので、試しに色々試してもらえるといいかもです。 ちなみに特定の行に文字サイズを収めたい時は size=j${line} のように指定して下さい。size=j1 と指定すると 1 行に、size=j2 と指定すると 2 行に収まるように文字サイズが決定されます。
CLI こちらは結構癖があります。適当に go のお作法でインストールしたら、使えるといわけでもありません。
go get github.com/komem3/wordimg/cmd/wordimg 絵文字の生成にはフォントのデータが必要です。デフォルトでは go のライブラリの goregular という中に含まれているフォントデータを使用して絵文字の作成を行ないます。そのため、当然のように日本語なんか文字化けします。 絵文字は日本の文化のため、絵文字を作成する方は日本語を使いたい方が多いと思います。その場合、適当な日本語が含まれるフォントファイル(ttf) を用意して引数で指定してください。
$ wordimg -m "こんにちは世界" -f ./SawarabiGothic-Regular.ttf アルファベットしか含まない文字の場合はフォントを指定する必要がないので以下だけで問題なくいけます。
$ wordimg -m "hello world" ちなみに、こちらも 1 行とかで収めたい場合は、size に j1 などと指定すると、収まるように文字サイズが決定されます。
$ wordimg -m "hello world" --size j1 感想 Go で絵文字作るのすごい面倒でした。ドキュメント無いに等しくて手探りすぎて辛かったです。昔 php でやったことあったので、ちょろちょろってできるかなって思ったんですが、いやーさすが go って気持ちになりました。 いつもお世話になっているサイトにはまだまだ機能が及ばないので、もう少し機能性豊かにできたらいいなと思っています。...
なぜ絞り込む必要があるか PR Times の RSS は一日 300 件近くニュースが飛んできます。これを普通の RSS リーダに登録すると PR Times で全て埋まります。テロです。 実際 slack に登録してみたところ、1 時間おきとかに、通知が 10 件飛んできて、とてもじゃないけど見る気になりませんでした。この中から絞り込んで欲しい情報だけの RSS にしたいというのが今回の目標です。
他の絞り込みツール こちらの記事が参考になります。この記事を読んでわかることは、PR Times やばいです。 実際にこの記事のツールを試してみましたが、PR Times がやばすぎて、zapier の上限に達したりとなかなか上手くいかなかったです。
Cloud Function で絞り込む そこで最後の手段の自作です。
流れとしては以下のような流れで絞り込みを行ないます。
今回は Go 言語の、RSS をパースするツールの mmcdole/gofeed と RSS を作成する gorilla/feedsを使用しています。
コードの全体はこんな感じ
package rssfilter import ( "context" "log" "net/http" "regexp" "time" "github.com/gorilla/feeds" "github.com/mmcdole/gofeed" "github.com/pkg/errors" ) const feedURL = "https://prtimes.jp/index.rdf" var searchText = regexp.MustCompile(`Cloud|cloud|クラウド|IOT|DX|テクノロジー|GCP|Google`) func FilterRss(w http.ResponseWriter, r *http.Request) { if err := filterRss(w, r); err !...
トップページのお知らせ欄を管理画面より変更できるようにしました。アーキテクチャはざっと以下のような感じになっています。今回はこの構成にした理由と、よかったポイントを書いていきたいと思います。
構成理由 フロントエンドを nuxt.js で作成したため、BFF でサービスにアクセスして、news サービス自体は非公開な構成にしたかったのが一番の理由です。
fronend 以外は非公開な構成のため、news サービスは news を操作することのみに集中できていているのがよく感じています。また、frontend の BFF サーバは更新エンドポイントを知らないため、一般ユーザがお知らせを更新してしまう心配もありません。
管理画面は認証を行なう必要があるため、今回は pomerium を使用して、cloud run に IAP を立てる方法で構築を行ないました。firebase などによる認証もありでしたが、開発環境などで既に pomeirum IAP はやっていたので、その知見を流用して行ないました。
よかったポイント nuxtjs の BFF は面倒でしたが、news サービス単体で御知らせの管理をできるようになったのが、やっぱり良いポイントです。処理がまとまっていて自分でも管理しやすいです。
また、今回は各通信を gRPC を用いて行ないました。これがすごいよかったです。導入やコネクション辺りはちょっと苦戦しましたが、コードの自動生成や分かりやすいスキーマ定義により、サービス間の通信はかなりスムーズに進みました。 swagger 書くよりも何倍も楽に書けて、その上自動生成のコードも swagger の何倍も分かりやすいとか、gRPC よすぎない…?
感想 結構時間はかかりましたが、自分が自由に遊べる環境という名目でサイトを立てたので、その意義を十分に感じられる作業でした。 次は wysiwyg エディターを使ったブログスペースを作成したいなって思っていますがいつになるのかなぁ。 その前に問い合わせフォーム作りたいや。(いらないと思うけど…)
Slide 解説 それぞれの問題の解説を軽くしていきます。今回参考にしたのは以下の仕様です。json.org よりも以下のサイトの方が分かりやすかったのです。
https://www.crockford.com/mckeeman.html
1 問目 オブジェクト型の最後の値の後にはカンマが付かないという問題です。初めて JSON を触ったばかりの頃に一度はやったことがあるミスだと思います。 仕様書の抜粋は以下です。
object '{' ws '}' '{' members '}' members member member ',' members 以上の定義より、最後にカンマがつかないことが分かると思います。仕様書で見ると普通ですが、実際に書くとむかつく定義だと思います。以下だったら最後にカンマいけたのに…
members member ',' member ',' members 2 問目 オブジェクト型の各宣言の間に改行は入るか?という問題です。これは、空白の宣言に改行が入っていることを知っていれば簡単な問題です。 オブジェクトの member 定義は以下のようになっています。
member ws string ws ':' element element ws value ws ws "" '0020' ws '000A' ws '000D' ws '0009' ws 000A が改行にあたるため、改行がいくあらあっても問題ないことがわかります。
3 問目 数字型がどのような表現が可能か?という問題でした。数字型に関する構文木はちょっと面倒です。
number integer fraction exponent integer digit onenine digits '-' digit '-' onenine digits digits digit digit digits digit '0' onenine onenine '1' ....