詩と創作・思索のひろば (Poetry, Writing and Contemplation)

ドキドキギュンギュンダイアリーです!!

Vagrant を使って複数の環境で Go のプログラムをコンパイルする(ファイルの変更監視つき)

書くコードがさまざまな OS で動くことを初めから想定しているような場合には、実際にその環境で動かしてみたい。タイトルのとおり Vagrant仮想マシンを複数立ち上げて、それぞれの中でコンパイルおよびテストができればよいわけです。というので書いてみたのがこちら:

https://github.com/motemen/go-multi-vagrant

とはいえ別に golang に限った何かがあるというわけではないです。

*file というファイル名が並んでいてかっこいいのですが、それぞれ以下のような役割を果たしています。

  • Rakefile: Vagrant セットアップを含めた作業フロー
  • Makefile: プログラムのビルド
  • Berksfile: 仮想マシンに適用する chef レシピ
  • Gemfile: ゲム〜

rake

% rake -T
rake init                               # Initialize required tools (required once, a bit slow)
rake setup                              # Setup required libraries
rake vagrant:make[machine,target]       # Run make on virtual machines
rake vagrant:make_fast[machine,target]  # Run make without starting up machines
rake vagrant:up[machine]                # Start virtual machines
rake vagrant:watch[machine,target]      # Watch local files to invoke make on virtual machines

rakerake default)を実行すると

  1. 必要なプラグインおよびライブラリのインストールがおこなわれ(rake init, rake setup
  2. 仮想マシンが起動し(rake vagrant:up
  3. それぞれの仮想マシンの中で make が実行される結果、テストとビルドが走ります(rake vagrant:make)。

make

  • vagrant ssh して各マシンで make を実行してます。GOPATH の設定のために sh -l してるのがポイントというくらいです。
  • 仮想マシンを扱う rake タスクでは MACHINE 環境変数を設定することで特定のマシンのみを対象とすることができます。
  • rake からは TARGET 環境変数で make のタスクを指定できます。
  • vagrant:make は毎回仮想マシンの起動をしようとするため少し遅くなっていますが、一度起動してしまったあとは vagrant:make_fast を使うようにすると起動処理をすっ飛ばすようになり、こちらのほうが早いです。
% rake vagrant:make MACHINE='precise64 centos-6.5'
bundle install --quiet
bundle exec berks install --path=.vendor/cookbooks
Installing golang (1.3.0) from git: 'git://github.com/NOX73/chef-golang.git' with branch: 'master' at ref: 'b062a3226a2ca1a14f0e62187a6ea870281988fc'
Using build-essential (1.4.2)
vagrant up precise64
Bringing machine 'precise64' up with 'virtualbox' provider...
==> precise64: Checking if box 'hashicorp/precise64' is up to date...
==> precise64: VirtualBox VM is already running.
vagrant up centos-6.5
Bringing machine 'centos-6.5' up with 'virtualbox' provider...
==> centos-6.5: Checking if box 'chef/centos-6.5' is up to date...
==> centos-6.5: VirtualBox VM is already running.
---> Running on precise64
vagrant ssh precise64 -- $SHELL -l -c 'cd /vagrant && make  2>&1 | sed "s/^/[precise64] /"'
---> Running on centos-6.5
vagrant ssh centos-6.5 -- $SHELL -l -c 'cd /vagrant && make  2>&1 | sed "s/^/[centos-6.5] /"'
[precise64] go get -d ./...
[precise64] go test ./...
[precise64] ok          _/vagrant       0.014s
[precise64] go build -o build/main.precise64.vagrant.dominica.local ./...
[centos-6.5] go get -d ./...
[centos-6.5] go test ./...
[centos-6.5] ok         _/vagrant       0.002s
[centos-6.5] go build -o build/main.centos-6.5.vagrant.dominica.local ./...

ファイル監視

ここまで整えるとファイルの変更を監視してビルドを行いたくなるものですが、Vagrant のファイル共有はゲスト側で変更イベントを発生させないらしい。最近のだと rsync ってのもあるけど明示的に実行しないと同期されないので思わぬところでハマりそうなのと仮想マシンそれぞれに変更監視ツールを入れるのも面倒だ……というわけでホスト側で変更を監視し、ゲストはそれを受けて make するだけ、という風にしてみました。

vagrant:watch とすると手元でファイルの変更が監視され、変更された時にそれぞれのマシンで make が走ります。仕組みは見たら分かりますが、標準入出力でイベントを伝えるというシンプルな実装です。

% rake vagrant:watch
---> Listening to changes on precise64
---> Listening to changes on precise32
---> Listening to changes on centos-6.5
---> Files changed: main.go
[centos-6.5] make 
[precise64] make 
[precise32] make 
[precise64] go get -d ./...
[precise64] go test ./...
[precise64] ok          _/vagrant       0.006s
[precise64] go build -o build/main.precise64.vagrant.dominica.local ./...
[precise32] go get -d ./...
[precise32] go test ./...
[precise32] ok          _/vagrant       0.002s
[precise32] go build -o build/main.precise32.vagrant.dominica.local ./...
[centos-6.5] go get -d ./...
[centos-6.5] go test ./...
[centos-6.5] ok         _/vagrant       0.003s
[centos-6.5] go build -o build/main.centos-6.5.vagrant.dominica.local ./...

ウェブ上の任意の画像の貼り付けタグを Markdown としてクリップボードにコピーできる Chrome 拡張

f:id:motemen:20140407095231p:plain

Pusheen Explorer紹介記事)は素晴らしいサイトですがこれをプルリクエストの応酬に利用するにはただ一点の難がありました。いい画像を見つけてもそれを Markdown としてコメントに含めるのが難しいことです。そこで作った Chrome 拡張がこちら。

Chrome Web Store - Quote Image As Textリポジトリ

画像を右クリックした際のコンテキストメニューに「Quote image as text」というのが追加されて、これをクリックするとクリップボードにその画像を貼り付けるタグと、画像が表示されているページ(またはその画像がリンクになっている場合は、リンク先のページ)へのリンクが Markdown 記法でコピーされます。あとはテキストエリアに貼り付けるだけ。簡単ですね!

スクリーンショットと例

f:id:motemen:20140407094922p:plain

上のような場合だと、生成される Markdown は

[![](http://upload.wikimedia.org/wikipedia/commons/3/38/JPEG_example_JPG_RIP_001.jpg)](http://en.wikipedia.org/wiki/JPEG)

となり、展開すると以下のようになります。

はてなブックマークのエントリページでブクマ数を favicon に表示する userscript

f:id:motemen:20140328135411p:plain

タイトルのとおり。このように はてブのエントリページfavicon を書き換えてくれ、便利です。はてブの色づかいをそのまま使っているので見た目もよいです。

URL に #autoupdate とつけると、10 分おきに はてなブックマーク件数取得API にアクセスして favicon だけを更新してくれるので、エントリの伸びを見たいようなときにタブのリロードも不要です。API の返す数は少しキャッシュが効いてるようで数が減ってるように見えることもあるようなので注意。

"Hatena Bookmark Count Favicon" userscript

700を越えるJavaScriptライブラリを自由に試せるページを作った

こちらです ☞ JavaScript Libraries PlaygroundjQuery 2.1.0 と underscore の例

jQuery や underscore などの JavaScript ライブラリをインタラクティブに試したいとき、最近はブラウザで自分のブログ(ここ)や GitHub など、当該のライブラリがロードされていることを知っているページを開いておもむろに ⎇⌘JChrome)! していたのですがこれは直接的ではないなと思ってそれ専用のページを作った次第です。

冒頭の例にもあるように location.search 部に library[@version],… 形式でライブラリを与えてやればページに <script> 要素が追加されて、あとは開発者コンソールなりでお楽しみください、という仕組みになっています。

cdnjs にはかなり多くのライブラリがホストされており(700 を越える、というのもこの数)ロードするのはこれを使うことにして、ライブラリ名から URL へのマッピングをいかにするかが問題だったのですが、GitHub にパッケージ情報 があるので、これを GitHub APIJSONP (!) で取りにいってます。

Introducing Pusheen Explorer

Japanese follows English.(日本人は英語をたどる。*

Pusheen! Meet the world's cutest cat at pusheen.com, who is also famous by her stickers available in facebook messenger. If you have not seen her, take a look at her cute animated gifs, and you will soon like her. There are so many pictures of Pusheen, however, that you are easily in lost while searching for a picture you know you have seen before.

Pusheen Explorer helps! If you remember the text fragment drawn in the picture you are searching for, type it in the search box and Pusheen Explore immediately finds it for you. If it does not work for you (probably because of text recognition not going well), I am sorry, but every visiting Pusheen Explorer] will show you a number of randomly selected Pusheen pictures. Among these you may happen to find it.

Visit now: Pusheen Explorer

facebook メッセンジャーのスタンプになってることでも有名な(ぼくはこれを使うためだけにメッセンジャーを使ってるのですが)プシーンの画像を検索できるサイト Pusheen Explorer を作りました。さまざまなバリエーションがあるため、コードレビューのコメントに貼って雰囲気をやわらげるのにも役立ちそうですね。

実装

TumblrAPI で取得してきたエントリの一覧から tesseract-ocr で画像の OCR をおこなって(英語アルファベットだけなので精度はわりと高い)、あとは AngularJS で表示しているだけです(なのでブログが更新されたら JSON を生成しなおす必要がある)。

Masonry での画像のタイル表示がちょっと難しかったけれど、DOM 反映のタイミングで処理をおこなうことができなそうなので、$timeout で無理矢理やってます。angular-masonry というのもあるらしいが今回は簡単のため見送り。

protractor でのテストも試してみたけれど、簡単で面白かった。テストの実行は make test となんか旧弊なかんじですが。

https://github.com/motemen/pusheen-explorer

I Am Pusheen the Cat

I Am Pusheen the Cat

Play Framework で `rails runner` 的なことを実現する

Play Framework 2.2.x の話です。分かりよいだろうというので rails runner を引き合いに出したのだけど、つまり何をやりたいかというと、アプリケーション本体のコード(Play も含めて)を利用して、オペレーションやメンテナンス用のタスク(バッチ処理)を書きたい。初心者なのでフレームワークに乗っからないとデータベースへの接続もできないのです。

適当に Scala の object を作って sbt runMain してやれば任意のコードを実行することはできるけれど、最終的にビルドしたときにアプリケーション本体には含めたくないので、分けて置いておきたい。フレームワークにそういうサポートがあるのじゃないかと考えていろいろ調べてみたけれど結局わからなかったので、こういう風にやってみた。

  • "tasks" というディレクトリを作り、ここに実行したいタスクを main() を備えた object として書く。
  • sbt の設定(build.sbt)で、tasks という、ルートプロジェクトに依存したサブプロジェクトを定義する。
  • 個々のタスクは sbt 'tasks/runMain {taskObject} {args}' で実行する。

不完全な例を挙げると、以下のようになります:

`rails runner` in Play framework

ウェブアプリケーションとして稼働していない場合に Play の API を叩きたいときには、play.core.StaticApplication というのを使えばよいらしいです。また、暗黙の Application を導入するために current をインポートするのと、最後に Play.stop() するのを忘れずに。

ポケモンのタイプ相性を確認できるウェブアプリケーションを作りました

久しぶりにポケモンをプレイしてみたらタイプがだいぶ増えていた。相手のタイプはなんとなく分かるんだけど手元のポケモンから何を出したらいいか分からない……。何このフェアリーって? そんなオッサンのためのウェブアプリケーションを作りました。1 ページの HTML に JS で実装されてるだけですが。

ポケモンタイプ相性チェッカ(XY対応)

上部で相手ポケモンのタイプを選ぶと、こちらの攻撃にどんなタイプのわざを繰り出すと効果的かが確認できる。データはせっせと行列を書いたのでたぶん合ってると思うけど間違ってたら教えてください。スマホンでも見られるようにしているので、ブックマークしておくと便利。

勉強がてら AngularJS で書いてみた。最初はかなり素朴に書いていて、スコープの値をもとに相性を計算する function をスコープに持たせて、その呼び出しを expression として HTML に埋め込んでた……といっても分かりづらいので小さな再現例を挙げると(これは入力の数値にあわせて object を増減させる例):

https://gist.github.com/8884912

これであー動く簡単簡単って思ったけど、コンソールを開いてみたら "10 $digest() iterations reached. Aborting!" ってエラーが出ている。AngularJS: What are Scopes? に詳しいけれど、ユーザからの入力によりスコープに $digest の再計算が促され、それで計算結果(この例だと gen())が変化するので、また $digest がおこなわれ……と収束しない状態になってるみたいだった(ちなみに gen() の結果がオブジェクトでなくプリミティブな値だと収束する)。

よくわからなかったので同僚に聞いてみたところ、こういう場合は $watch を使ってやると:

https://gist.github.com/8884912

こうすると計算結果がスコープの $digest を引き起こさないので、思ったとおりに動くっぽい。AngularJS 的なセオリーはどうなのか、まだわかってないです。

ポケットモンスター X

ポケットモンスター X

ポケットモンスター Y

ポケットモンスター Y