読者です 読者をやめる 読者になる 読者になる

Thanks Driven Life

日々是感謝

TravisCI 上で「(GNU, BSD) sed & 各 shell」の組み合わせでテストする

成果物

雰囲気こんな感じです。

github.com/gongo/tpdiff/.travis.yml

経緯

gongo.hatenablog.com

  1. 先日書いた sed を、せっかくなので GitHub に置いておこう
  2. せっかく GitHub に置くのだからテストでも書こう

というところから始まりました。

https://github.com/gongo/tpdiff

さてテストを書くぞ!といったところで、何を重点的に見れば良いか:

  1. 使用する shell も人それぞれ違うはず
  2. sed には GNU 版 と BSD 版がある

この2点が特に注意すべきところと考えました。

1番に関しては「POSIX 準拠かどうか」みたいなのを ShellCheck を用いて確認はしているのですが、 やっぱり実際に動作した結果を見たいという気持ちがあります。

2番については、ユーザの使用マシンが Linux だったり OS X (macOS) だったりで sed にも違いが出てくるはずなので、ここも気をつけないといけません。

TraviCI ではこうしました

上記の注意点を踏まえ、TravisCI でテストを実行してもらうために

  1. 実行環境を Linux(Ubuntu) と OS X の2つを指定する
  2. テストしたい Shell をテスト前にインストールする

こんな感じにしました。

os:
  - linux
  - osx

env:
  - SH=mksh
  - SH=dash
  - SH=bash
  - SH=zsh

BSD sed が (TravisCI が用意する) Ubuntu 環境に簡単に用意できれば話は早かったのですが、なかなか難しそうだったので BSD sed を標準で持つ OSX 環境を用意してもらうことで、そこを補うことにしました。

refs: The Build Environment - Travis CI

env に定義したテスト対象のシェル選定理由なんですが、まあ特にこれといった理由はないんですけど、これぐらいカバーしてればいいかなーと。

ちょっとした問題点

TracisCI で OS X を使用すると、さすがに起動が遅くて全体的なテスト実行時間はそこそこ掛かってしまいます。

例えば https://travis-ci.org/gongo/tpdiff/builds/156956287 を見ると

> Elapsed time 21 min 12 sec
> Total time 3 min 51 sec

テストそのものの実行時間は短いのですが、環境を用意するのも併せると 20分ぐらい掛かっているのがわかります。 まあいいかってことで今は気にしてないです。

まとめ

どなたか UbuntuGNU/BSD sed を用意できる方法知りませんか

参考

Pokemon-Emacs 〜あなたが Emacs で開いているファイルに潜んでいるポケモン〜

emacs

TL;DR

f:id:gongoZ:20160715135904p:plain

https://github.com/gongo/pokemon-emacs

経緯

最近は Pokemon Go が流行っているようで、正式サービス開始を待ち望まれているようです。

『Pokémon GO』は、位置情報を活用することにより、現実世界そのものを舞台として、ポケモンを捕まえたり、交換したり、バトルしたりするといった体験をすることのできるゲームです。 このゲームはモニターの中だけで完結せず、プレイヤーは実際に家の外に出てポケモンを探したり、他のプレイヤーと出会ったりしながら楽しむことができます。

面白そうですね。海外でも既にユーザが爆発的に増えており、スマホ片手に街をうろうろする様子などを画像や動画でも目にします。

さて、日本は夏まっさかりであり、暑い日が続いています。そんな中

「私もポケモン探しにいきたいけどまだサービス開始してないし、 そもそも外に出たくない…

という Emacs 使いも多いと思います。

でもよく考えてみてください。ポケモンは何も外だけに居るわけじゃないんです。 昔はゲームボーイにいました。じゃあ Emacs にも居るかもしれないですよね。

Pokemon-Emacs とは

https://github.com/gongo/pokemon-emacs

Emacs のマイナーモードの一つです。効果としては「今開いているファイル名の絶対パス(もしくはバッファ名)で一意に決まるポケモン名を表示する」だけです。

とりあえずいろいろがんばってインストールしてもらったあと

M-x pokemon-emacs-mode

を実行すると、(おそらく)ファイル名の横あたりに、下図っぽい感じでポケモン名が表示されます。

f:id:gongoZ:20160715133107p:plain

この場合は ナッシー が選ばれました。

つまり /Users/gongo/src/github.com/gongo/pokemon-emacs/README.md にはナッシーが潜んでいる。豆知識です。

ちなみに *scratch* にはナゾノクサが居ます。多分。

実装についてちょっとだけ

特に難しいことはしてませんが

  1. ファイル名、もしくはバッファ名を seed として乱数をゲット
    • なのでどの環境でもファイル名が同じ = 同じポケモンが出てくる。はず。
    • (もちろんポケモン一覧 pokemon--monsters が変化したら変わりますが…)
  2. ポケモン一覧から↑の乱数を index としてポケモンをゲット

これだけです。

少し前に Pokemon-Go におけるポケモン出現率*1 みたいな画像を見たので、出現率に併せて「出やすいポケモン」「出にくいポケモン」みたいな実装をしてたんですが、 あの画像自体デマだったみたいなコメントもあったので、まあいいかってことでとりあえず愚直にリストから取るようにしました。

あとはポケモン一覧はとりあえず初代の 151 匹*2をチョイスしました。他のシリーズ追加すれば勝手に出てくるとおもいます

まとめ

/path/to/fooピカチュウが潜んでいたぞ!!」 「ミュウが見つからねえ!!」

みたいな楽しみ方で、エディタ生活に華を添えてください。ポケモン大好き!!

Docker Image がデプロイできるようになった Heroku で、Emacs (elnode) on Alpine Linux を動かす

emacs docker

成果物

(7/21 追記: Docker Hub のリポジトリ名を gongo/docker-emacsgongo/emacs に変更しました)

経緯

Container registry public beta - deploy Docker images to Heroku | Heroku Dev Center


半年ほど前に heroku-docker を使ってみた んですが、 今回の発表は更に熱くて、まさに Docker Image そのものを Heroku にもっていけるということで、早速試してみました。

作成した Docker Image

今回は Alpine Linux をベースに、Emacs や Cask に必要なライブラリ(python など)をインストールしています。

デプロイしてみる

Container Registry and Runtime | Heroku Dev Center の手順通り。 今回はあらかじめ docker build して動作確認したりしていたので、いざデプロイする時には「Pushing an existing image」を行いました。

$ heroku apps:create gongo-docker-emacs
$ docker tag gongo/emacs:example registry.heroku.com/gongo-docker-emacs/web
$ docker push registry.heroku.com/gongo-docker-emacs/web 

そして出来上がったのがこちら(いつか消します)

https://gongo-docker-emacs.herokuapp.com/

まとめ

お手軽感が高いです。 いくつか制限はある らしいですが、まだ Beta ですし、正式リリースされたら解決するかもしれないので、そこらへんはゆったり待ちましょう。

そんなわけでみなさん Emacs を動かしましょう!!

terraform plan の実行結果で、属性値が変更になる行に色付けする sed

TL;DR

readonly escape_ansi=$(printf '\033')

sed -e '/".*" => ".*"$/!b' \
    -e '/^.*: *"\(.*\)" => "\1"$/!s/.*/'"$escape_ansi"'[31m&'"$escape_ansi"'[m/'

f:id:gongoZ:20160702110516p:plain

経緯

毎晩暑い日が続く日本、AWS の各種リソース管理を Terraform で行っている皆様におかれましては、 日々の業務において terraform plan をよくお使いになられていることと存じます*1

そんな中、例えばこのような実行結果が表示されたとします:

..
.. (message)
..

+ aws_security_group.app
    ingress.#:                   "" => "1"
    ingress.0.cidr_blocks.#:     "" => "1"
    ingress.0.cidr_blocks.0:     "" => "192.0.2.0/24"
    ingress.0.from_port:         "" => "80"
    ingress.0.protocol:          "" => "tcp"
    ingress.0.to_port:           "" => "80"

-/+ aws_security_group.db
    ingress.#:                   "2" => "2"
    ingress.0.cidr_blocks.#:     "1" => "1"
    ingress.0.cidr_blocks.0:     "198.51.100.0/24" => "198.51.100.0/24"
    ingress.0.from_port:         "3306" => "3306"
    ingress.0.protocol:          "6" => "tcp"
    ingress.0.to_port:           "3306" => "3306"
    ingress.1.cidr_blocks.#:     "" => "1"
    ingress.1.cidr_blocks.0:     "" => "203.0.113.0/24"
    ingress.1.from_port:         "" => "5432"
    ingress.1.protocol:          "" => "tcp"
    ingress.1.to_port:           "" => "5432"

-/+ aws_security_group.mail
    ingress.#:                   "2" => "1"
    ingress.0.cidr_blocks.#:     "1" => "1"
    ingress.0.cidr_blocks.0:     "198.51.100.0/24" => "198.51.100.0/24"
    ingress.0.from_port:         "587" => "587"
    ingress.0.protocol:          "6" => "tcp"
    ingress.0.to_port:           "587" => "587"
    ingress.1.cidr_blocks.#:     "1" => ""
    ingress.1.cidr_blocks.0:     "198.51.100.0/24" => ""
    ingress.1.from_port:         "995" => ""
    ingress.1.protocol:          "6" => ""
    ingress.1.to_port:           "995" => ""

Apply complete! Resources: 1 added, 2 changed, 0 destroyed.

(実行結果はてきとうです)

各セキュリティーグループのルール数が2、3個なのでまだまだ見えますが、例えばルール数が20個とかになるとかなりの行数が目に入ります。その中で どの行(属性)が変更なのかぱっと見、わかりづらい と思うわけです。思いました。

まあそんなわけで、属性値に変更のある場所がわかりやすく見えればいいな、ということで、いくつか方法はあると思いますが、今回は sed でやってみました。

sed

readonly escape_ansi=$(printf '\033')

sed -e '/".*" => ".*"$/!b' \
    -e '/^.*: *"\(.*\)" => "\1"$/!s/.*/'"$escape_ansi"'[31m&'"$escape_ansi"'[m/'
  1. "xx" => "yy" という文字列(xxとyyは任意)を 含まない 行はスキップして次に進む
  2. "xx" => "xx" という条件に一致しない(つまり左と右の "" 内の値が 同じではない )場合 に、赤で色付けする

こんな感じでできました。パターンは単純なんですが terraform plan の実行結果に対してだけ使うのであれば充分かなと思います。

ついでにこいつをスクリプトに落とすと、雰囲気こんな感じ

#!/bin/sh

readonly escape_ansi=$(printf '\033')
readonly program_name=$0

if [ -p /dev/stdin ] ; then
    cat -
else
    if [ ! $# -ge 1 ] ; then
        echo "$0: [ERROR] You must specify file."
        exit 1;
    fi

    if [ ! -f "$1" ] ; then
        echo "$0: [ERROR] \"$1\" No such file."
        exit 1;
    fi

    cat "$1"
fi | sed -e '/".*" => ".*"$/!b' \
         -e '/^.*: *"\(.*\)" => "\1"$/!s/.*/'"$escape_ansi"'[31m&'"$escape_ansi"'[m/'

てきとうに tpdiff とか名前で保存しておいて

$ terraform plan | tpdiff

こんな感じで、冒頭の画像のように表示されます。多分。

ひとまず

あたりでは動いているようです。

まとめ

sed 難しい

おまけ

当初、sed の色付けする部分を

-e $'/^.*: *"\\(.*\\)" => "\\1"$/!s/.*/\e[31m&\e[m/'

みたいな感じでやってたんですが、 POSIX 準拠してるかってチェックしてくれる shellcheck を使うと

fi | sed -e '/".*" => ".*"$/!b'
         -e $'/^.*: *"\\(.*\\)" => "\\1"$/!s/.*/\e[31m&\e[m/'
            ^-- SC2039: In POSIX sh, $'..' is undefined.

ってな感じで怒られたので、printf 使うようにしました。

*1:手元実行なんかせず、Atlasにお任せしてる人が多いのかもしれない

「Methods & Tools Summer 2016 Magazine」に Turnip について寄稿しました

turnip

A free software development magazine であるところの Methods & Tools に 「Turnip - Gherkin extension for RSpec」というタイトルで寄稿しました。

Methods & Tools - Summer 2016

書いたこと

  1. テストやってますか。受け入れテストどうですか。
  2. Cucumber が人気だよね
  3. だけど人によっては Cucumber のこういう部分がちょっと気になる人いるよね
  4. そこらへんを解決しようとしてるのが Turnip です
  5. Turnip 導入編
  6. Turnip のこういう機能が、3 で挙げた点を解決してるのだー
  7. まとめ

目新しいことは何もなく、Turnip の誕生理由とか Cucumber との軽い比較ぐらいですね。

経緯

Methods & Tools の編集者(なのかな)の Franco さんから「Turnip の紹介記事とか書いてみませんか」みたいなメールが来ました。 正直なところ Methods & Tools の存在をこの時知りました。1999年から続いてる老舗なんですね…

ちなみに Turnip 作者である Jonas さんに「この件どうしましょうかー」って聞いたところ

jonas「書いていいよ」
gongo「お、おう」

という感じで。まあせっかくの機会だしなってことで、私がメインで、英語のおかしい点を jonas さんに見てもらう、という体制で始めました。

できた

この後 jonas さんにめっちゃくちゃ添削してもらった

終わり

今回はただの紹介記事だったのでそれほどの量でもなく、英語も難しい言い回しとかは無かったのですが、 それでもなかなか書けず時間がかかってしまいました。英語すごい。

そんなわけでよろしくお願い致します。

「1時間後に OSX をスリープする」をセットするコマンド

$ sudo pmset schedule sleep "$(date -v +'1H' +'%D %T')"

OSX 10.11 El Capitan および OSX 10.10 Yosemite で動作確認しています。おそらくそれ以下のバージョンでも動くやつは動くと思います。多分。

経緯

私は就寝する時に Mac mini で音楽を鳴らしながら床に就くのですが、つけっぱなしなのもあれなので、毎晩寝る直前に

  1. システム環境設定
  2. 省エネルギー
  3. スケジュール

を経て*1、「今は0時だから、1時にスリープするようにセットして…と…」みたいな感じで設定しています。 だいたい寝る時間は一定なのですが、夜更かしするなどしてスリープ時刻を過ぎてから寝ることもしばしばなので そういう時は上記の設定を毎回行っています。

正直めんどいのでコマンドラインでぱぱっとできないかなと調べてみました。

pmset

遅ればせながら pmset というコマンドの存在を知りました。

スリープモードの変更(hibernateとか)等もできるらしいのですが、今回使うのは pmset schedule です。

pmset schedule

schedule サブコマンドでは引数として

  • sleep
  • wake
  • poweron
  • shutdown
  • wakeorpoweron

これらの type と時刻を受けとります。例えば

$ sudo pmset shceudle wake "07/04/16 20:00:00"

とすれば「2016年7月4日の午後8時 にマシンをスリープから復帰させろ(wake)」になります。便利。

「1時間後」の時刻を取得する

おなじみの date コマンドを使います。

pmset schedule が許容する時刻のフォーマットは MM/dd/yy HH:mm:ss なので

$ date -v +1H +'%D %T'

こうなります *2

最終的に

組合せると、冒頭の

$ sudo pmset schedule sleep "$(date -v +'1H' +'%D %T')"

になります。お疲れ様でした。

余談ですが

しっかり登録されてるかを確認しましょう。

$ date
Wed Apr 20 09:51:24 JST 2016

$ sudo pmset schedule sleep "$(date -v +'1H' +'%D %T')"

$ pmset -g sched
Scheduled power events:
 [0]  sleep at 04/20/16 10:51:27

OK

まとめ

眠い

*1:https://support.apple.com/kb/PH18583

*2:OSX標準の date は BSD date なので、時刻計算のオプションが GNU date と違う。GNU date だと -d '1 hours' みたいな感じ

Turnip 2.1.0 リリースしました

turnip

Release Version 2.1.0 · jnicklas/turnip

Ruby のサポートバージョンポリシー変更

先月24日に Ruby 2.0 が EOL を迎えたということで、それに合わせて Turnip も今後は Ruby 2.1 以上をサポートすることにしました。 Ruby 2.0 お疲れ様でした。Ruby 1.9.3 や Ruby 2.0 で世界はいろいろ動いた気がします。

See: Ruby 2.0.0 および Ruby 2.1 の今後について

カスタムプレースホルダーでデフォルトの値を返す DSL の追加

@ さんからの Pull Request を経て最終的にこうなりました。

placeholder :user_name do
  match /admin: (.*)/ do |user_name|
    User.find_by!(name: user_name, role: :admin)
  end

  default do |user_name|
    User.find_by!(name: user_name)
  end
end

こんなプレースホルダが定義されている時

When admin: gongo がログイン
When wataru がログイン

みたいなステップを書いていると、前者の step ブロックには name = gongo and role = admin を満たす User インスタンスが、 後者には name = wataru を満たす User インスタンスが渡されるという感じです。

まとめ

Ruby 2.0 の EOL と新 DSL の追加ということで 2.0.x から 2.1.0 に上げました。よろしくお願い致します。