Thanks Driven Life

日々是感謝

「Methods & Tools Summer 2016 Magazine」に 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 リリースしました

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 に上げました。よろしくお願い致します。

Ruby 2.x 環境で magic comment 無しファイルを開くと flycheck で "invalid multibyte char (us-ascii)" と言われる場合

結論から言うと

(setenv "LC_ALL" "ja_JP.UTF-8")

;; or

(setenv "LANG" "ja_JP.UTF-8")

を試しましょう

経緯

こんなファイルのことです。

p 'あいうえお'

f:id:gongoZ:20160210091618p:plain

メッセージ自体はお馴染のものなので

といった情報がググるとすぐ出てきます。確かに ↑ のファイルに # coding: utf-8 を追加したらメッセージは出なくなりました。

ですが私が使っているマシンにはもはや Ruby 1.9 は入っていないので、このメッセージが出るのがおかしい。ってことで謎は深まっておりました。

原因

そんなときに @ さんより

といったアドバイスを頂いたので

(setenv "LC_ALL" "ja_JP.UTF-8")

を実行してみると

f:id:gongoZ:20160210092451g:plain

消えました。やったぜ。@ さんありがとうございました!

まとめ

以前から https://github.com/purcell/exec-path-from-shell は使っていて GOPATH とか RBENV_ROOT は取り込むようにしていましたが、 LC_ALL とかのことは忘れていました。要注意。

「Serverspec で期待値を直書きしてる部分、Puppet の hiera から持ってこれるけどどうする?」

Puppet や Serverspec に限らず、Chef でも Itamae でも awspec でも自前スクリプトでも何でもいい話なんですが。 つまり テストコードに書く期待値を、構成管理ツールで使っているパラメータファイルから取ってきたほうがいいのか という話題。

結論から言うと「何をテストしたいのか」によって Yes/No が変わるんじゃないかな、と思います。

前置き: 例えばこんなこと

hiera でこう書いてたとして

---

packages:
  - emacs
  - vim

manifest でこう書いてたとすると

$packages = hiera('packages')
package { $packages:
  ensure => latest
}

Serverspec ではこう書くと思います

describe package('vim') do
  it { should be_installed }
end

describe package('emacs') do
  it { should be_installed }
end

ある日、こんな要望がありました

  1. PHP 追加したいから hiera に書いといて
  2. emacs 必要無くなったから hiera から消しといて
 packages:
-  - emacs
   - vim
+  - php-common

このとき、テストコードでは describe package('xxx') の部分を一つずつ直していくことになるでしょう。 数はまだ少ないですが、もしパッケージ数が5個とか10個とかになるとどうでしょうか。 また、パッケージだけならともかく、service だったり iptables だったり、その他細々としたものを書き換える度に

「よっしゃ、manifest 書いてデプロイ完了したぜっってテスト落ちてる…あーはいはい、テストコードの部分を更新し忘れてましたね…」

となることはないでしょうか*1。 その時にアナタはこう思うでしょうか。


「テストコードも hiera を参照してくれれば変更点1箇所で済むのに」


すると、アナタはこんな感じでがんばるかもしれません

hiera = Hiera.new(config: '/path/to/hiera.yaml')
hiera.config[:yaml][:datadir] = '/path/to/hiera/hiera_data'
packages = hiera.lookup('packages', nil, {}) # ['vim', 'php5-common']

packages.each do |pkg|
  describe package(pkg) do
    it { should be_installed }
  end
end

こうすることで

  1. パラメータの変更を hiera に反映する
  2. puppet apply
  3. rspec

という形で サーバの仕様変更におけるパラメータ編集箇所 が1箇所に集約できるメリットが生まれました

本題: これでいいのかどうか

これまでの流れからすると、おそらく Puppet でサーバを構築しつつ Serverspec でテストしているこの人は

さきほど修正した hiera が、ちゃんとサーバに apply されているかどうか

というのを一番チェックしたいと考えていると思います。

f:id:gongoZ:20160115162912p:plain

これ自体は特に問題ないと思っていて、ちゃんとテスト流してて素晴しいですよねみたいな未来です。


ですがこれはあくまで視点の一つで、おそらくもう一つ、下図のような見方をすることもあると考えています。

f:id:gongoZ:20160115162916p:plain

つまり直前にテストしたかどうか、とかは関係なく、純粋に 現時点でのサーバが期待した状態(つまり仕様)を保っているか を中心とするテストです。

この場合、逆に hiera の値をテストコードに使うのはよくなくて

  1. hiera で php を追加するつもりが ruby を追加してしまった
  2. 気づかずに apply
  3. rspec
  4. 本当は php がインストールされていてほしいが、hiera 上は ruby が正義なので PASS

ここもレビューをしっかりしていれば防げるかもしれません。しかし、往々にして人は見逃してしまうものなので、ありえない未来じゃないなと思っています。

まとめ

私が業務で触っている部分では

  • Puppet
  • Terraform

に対して

  • Serverspec
  • infrataster
  • awspec

のテストを用意していて、それぞれのディレクトリも似たような構成にしています。 そのため、hiera ファイルをそのまま使えちゃうので、どうしても「テストコードにも書くのめんどいわー」みたいなことが、無くも無いです。

最終的にはどちらが良い悪い、ということではなくて「何をテストしたいか」っていう当たり前のことを忘れないでいてくれれば10年後の8月また元気で出会えるんじゃないかなと思います。

*1:マニフェストとテストコードをしっかり同時にレビューしてると、こういうのは無さそうですが…

Turnip 2.0.2, turnip_formatter 0.4.0, gnawrnip 0.4.0 リリースしました

新機能追加したわけじゃないです

Turnip 2.0.2

これまで gherkin3 という名前で開発が進んでいた gherkin の version3 が gherkin に rename されました。

https://github.com/cucumber/gherkin/commit/d47add1a5e1a835af8c5dd9f55f7fe7a4916c7dd

これにより、例えば Turnip 2.0.1 の gemspec のように

s.add_runtime_dependency "gherkin", ">= 2.5"

こう書いていると gherkin2 と互換性のない gherkin3 がインストールされるようになった というわけです。 issue で教えてもらいました。感謝 https://github.com/jnicklas/turnip/issues/169

turnip_formatter, gnawrnip 0.4.0

turnip_formatter は Turnip 2.0.2 に、gnawrnipturnip_formatter 0.4.0 に それぞれ追従する形で gemspec 直したりテスト対象の RSpec のバージョン直したりしてました。 たぶん動くと思います。

Gherkin3 について

将来的には Gherkin3 への対応をしようかなと考えてたりします。

Use Gherkin3 · Issue #171 · jnicklas/turnip

いつになるかはわかりませんが。

2015年を振り返って

f:id:gongoZ:20151231190704p:plain

gongo.hatenablog.com

ふりかえり〜

OSS活動

2014年に Turnip のオーナー権を貰って から、ちょくちょく活動しています。 今年の作業としては、RSpec のバージョンを結構新しめ限定にするという Turnip 2.0.0 をリリースできたのが良かったです。

[Proposal] RSpec support policy · Issue #158 · jnicklas/turnip

社外でこのような提案する機会は今までなかったので、良い経験でした。

発表

今年は珍しく発表する機会がありました。

最初で最後だった YAPC Asia はやはり印象深いです。よく、あの規模の会場の壇上にあがって Perl にまったくカスらない内容を発表できたなーと。 発表のネタに繋がる作業は割とマジメに取り組んでいたんですが、結果的に笑い取れたので今年勝利したことにしておきます。

その他

久々に Advent Calendar に参加したり、ちょくちょく Vue.js 触ったり、ぐらいでしょうか。 2014年のふりかえり と見比べると、だいたい同じことしてるなという感想です。

まとめ

2016年もよろしくお願い致します。