Hatena::Groupsubtech

NaN days

2013-02-19

テストが失敗したときに再試行できるようにするモジュールを書きました

| 13:22 |  テストが失敗したときに再試行できるようにするモジュールを書きました - NaN days を含むブックマーク はてなブックマーク -  テストが失敗したときに再試行できるようにするモジュールを書きました - NaN days

Selenium を使ったときなどテストの状態が外部に依存しているような場合、状態が確実に変化するのを待つために sleep などしてみているけれどやりたいのはそういうことじゃないんだ! という訳で、テストが失敗したら少しウェイトを入れて再試行するモジュールを書きました。

motemen/Test-Retry ? GitHub


無意味な例ですが、

use Test::More;
use Test::Retry max => 3, delay => 0.1; # exports retry_test(&)
my $x = 0;

retry_test {
    is $x++, 2, '$x++ == 2';
};

retry_test のブロック内でのテストが失敗しそうな場合、デフォルトでは 0.5 秒待機して最大 5 回リトライします。テストが成功する場合にはそのまま次のへ実行を移し、最大試行数を越えた場合は失敗します。

上の例だと、以下のような出力になります。

# test '$x++ == 2' failing; retry (2 remaining)
#          got: '0'
#     expected: '2'
# test '$x++ == 2' failing; retry (1 remaining)
#          got: '1'
#     expected: '2'

ok 1 - $x++ == 2

また、いちいちブロックで囲んでらんないという人のために、既存のテスト関数を書き換えるような機能も提供しています。

use Test::Retry override => [ 'is' ];

# または以下; prototype ごと変わるので BEGIN で
BEGIN { Test::Retry->override('is') }

is { func_with_some_random_lag(), $expected };

テスト関数に渡される引数を返すブロックを渡すと、以下と同じ動作をします。

retry_test {
    is func_with_some_random_lag(), $expected;
};

たとえば Selenium::Remote::Driver を使ったテストだと

$driver->find_element(...)->click;

retry_test {
    is $driver->get_title, ...;
};

みたいな感じにして、ページ読み込みを待つ手間が省けます。

どうぞご利用ください。

2013-02-15

jQuery のメソッドチェーン呼び出しのコードを簡単に生成できる Perl モジュールを書きました

| 13:25 | jQuery のメソッドチェーン呼び出しのコードを簡単に生成できる Perl モジュールを書きました - NaN days を含むブックマーク はてなブックマーク - jQuery のメソッドチェーン呼び出しのコードを簡単に生成できる Perl モジュールを書きました - NaN days

PhantomJS 1.8 のリリースで まっとうな方法で Perl から PhantomJS の操作ができるようになった おかげで 去年の YAPC::Asia 2012 で発表した Wight はめでたくオワコン化しました……。だけれど Wight のオマケで作っていたモジュールは便利なので、別に分けてみました。

motemen/String-jQuery ? GitHub

SYNOPSIS にある通りですが、このモジュールがエクスポートする jQuery() という関数を起点にして、JavaScriptjQuery を使うようにしてメソッドチェーンを繋ぎ、最後に文字列化すると JavaScript における jQueryAPI 呼び出しとして使える式が得られます。Perl のコード中に文字列で JS を埋め込むよりは読みやすいはず……です。

以下の例を見るのが分かりやすいと思います。.'length' あたりがポイントですね( ╹◡╹)

jQuery();                           # => 'jQuery()'
jQuery('a');                        # => 'jQuery("a")'
jQuery(\'document');                # => 'jQuery(document)'
jQuery('a')->text();                # => 'jQuery("a").text()'
jQuery('a')->text('xxx');           # => 'jQuery("a").text("xxx")'
jQuery('a')->click(sub { e => 'return false' });
                                    # => 'jQuery("a").click(function (e) { return false })'
jQuery('a').'length';               # => 'jQuery("a").length'
jQuery->ajax({ method => 'POST' }); # => 'jQuery.ajax({"method:"POST"})'

Selenium::Remote::Driver を使うにしても、ページ内要素の調査を行うのに jQuery は便利だと思います(このモジュールが jQuery の埋め込みを行うわけではありません)。

my $result = $driver->execute_javascript(
    'return ' . jQuery('#content a')->attr('href')
);

似たようなモジュールには HTML::JQuery というのがありますが、こちらは script 要素全体を出力するもののようです。

2013-02-12

自分だけのオリジナルなフレーズをツイートできる userscript

| 13:24 | 自分だけのオリジナルなフレーズをツイートできる userscript - NaN days を含むブックマーク はてなブックマーク - 自分だけのオリジナルなフレーズをツイートできる userscript - NaN days

「これは新しい! ツイートすれば 100 fav 間違いなし!」なフレーズを思いついたとき、賢明な方々は

  1. 念のため一度 Google 先生にお伺いを立てる
  2. 一件もヒットしなければ満を持してツイート

という手順を踏んでいるかと思います。これをひと手間減らすのが今回ご紹介する userscript。インストールすると以下のように

f:id:motemen:20130212130926p:image

0 件の検索結果にツイートボタンが表示されます。あとはこのボタンをクリックしてツイートウィンドウを開くだけ。簡単ですね!

インストール

tweet-google-unique-query.user.jsリポジトリ)をダウンロードして、chrome://extensions に放り込むとよいです。Chrome でのみ確認していますが、Firefox などのブラウザでも使えるかもしれません。

参考リンク

  • Twitter / Twitterボタン
    • テキストをツイートするだけのボタンを作りたい(URL は要らない)ときは、hashtag 版にしてハッシュタグを指定しないといいみたいです(ひどい)。
  • User Scripts - The Chromium Projects
    • Greasemonkey 由来の @include を使うとインストール時にすべてのウェブサイトに対する権限を要求しようとするので、Chrome 向けのユーザースクリプトを作るときには @match を使うのがよいです。

2013-02-08

Kyoto.js #5 で日本の連休についての発表をしました #kyotojs

| 13:31 | Kyoto.js #5 で日本の連休についての発表をしました #kyotojs - NaN days を含むブックマーク はてなブックマーク - Kyoto.js #5 で日本の連休についての発表をしました #kyotojs - NaN days

先日開催された Kyoto.js #5 で LT をしてきました。

次の連休

今後1年間の3連休が確認できる 次の連休 というサイトとその実装について紹介しました。クライアントサイド JavaScript のみで動いていて、祝日データの取得には Google Calendar API を使っています。

jquery.partyhard

また、このサイトで使用している自作の jQuery プラグイン jquery.partyhard についての紹介もしました。

使い方は簡単で、以下のようにして呼び出すだけで document.body が PARTY HARD 状態になります。

$(document.body).partyhard();

使用例は http://motemen.github.com/jquery-partyhard/demo.html をご覧ください(ロードに少し時間がかかります、あといまちょっと怖い画像が出てくるかもしれないので http://motemen.github.com/jquery-partyhard/demo.html?cat%20gif で猫を見てもよいです)。

Kyoto.js の感想

隔週で開催されていて、こういったしょうもないことも気軽に紹介できる雰囲気がいいですね。京都近辺にいらっしゃる方は是非顔を出してみては?

発表の中では mechairoi さんの Emacs Lisp から Chrome を操作する拡張 が便利そうかつ面白かったです。

2013-02-07

GitHub のリポジトリを管理する小さいツール ghq

| 13:14 | GitHub のリポジトリを管理する小さいツール ghq - NaN days を含むブックマーク はてなブックマーク - GitHub のリポジトリを管理する小さいツール ghq - NaN days

GitHub 上の面白そうなコードは手元に clone してから見るのが普通だと思いますがそれをこんな感じに整理してます。

  • ~/extrepo/@author/project に git clone する(~/extrepo/@motemen/ghq とか)
  • ~/extrepo/project からそこに symlink する(~/extrepo/ghq → ~/extrepo/@motemen/ghq

こうすると ~/extrepo/jquery などでアクセスできて楽です。「あの人のあのプロダクト」って思い出し方をしたいときには ~/extrepo/@motemen を辿っていけばよい。

tree するとこんな感じです。

.
|-- @cho45
|   |-- Config-ENV
:
|   |-- jsdeferred
|   `-- starter.pl
|-- @cloudhead
|   |-- http-console
|   `-- less.js
:
|-- Brownie -> @masaki/Brownie
|-- Class-Accessor-Lite -> @kazuho/p5-Class-Accessor-Lite
:
|-- webiblo -> @mizzy/webiblo
`-- ws -> @einaros/ws

ghq

そしてこれを簡単に行うためのオレオレツールが ghq です。以下のようにして使えます。

clone する
% ghq [-clone] https://github.com/motemen/polka

のようにすると ~/extrepo/@motemen/polka に git clone されて先に伸べたようなシンボリックリンクが作られます。

ディレクトリへ移動する
% ghq [-cd] polka

または

% ghq [-cd] @motemen/polka

とするとそのディレクトリへ cd します。

インストール

zsh のスクリプトで書いてます。

% git clone git://github.com/motemen/ghq.git ghq_dir

したのち

fpath=(ghq_dir/zsh $fpath)
autoload -U ghq
autoload -U compinit; compinit

と .zshrc に書くと、ghq というコマンドと補完(-cd したときなど)が有効になります。clone 先のルートディレクトリは git config ghq.root で変更できます(たぶん)。

あとすでに同名のリポジトリが存在しているときは remote に追加するようにしてみたんだけどそれは余計なお世話だったかもしれない……。

2012-11-28

最近変更されたブランチを列挙する

| 19:25 | 最近変更されたブランチを列挙する - NaN days を含むブックマーク はてなブックマーク - 最近変更されたブランチを列挙する - NaN days

週明けになるとアレ?先週なにしてたっけという気分になるので git-recent-branches というスクリプトを書いて、ここ数日間で変更のあったブランチを一覧しています。

git-rev-parse でコマンドラインオプションを解析してみたかったので、シェルスクリプトになってます。

こんな感じに、7 日以内に更新されたブランチとその最新コミットを一覧できる (node のリポジトリを見てみた):

% git recent-branches --no-merged --days=7 --date=iso     
2012-11-27 18:21:05 -0800 remotes/origin/streams2-net-perf-wip - streams2: Set 'readable' flag on Readable streams [isaacs]
2012-11-27 23:52:49 +0900 remotes/origin/v0.8 - doc: Fix missing link target to 'https.request()' [Ryunosuke SATO]
2012-10-25 13:49:32 -0700 remotes/origin/v0.8.15-release - 2012.11.26, Version 0.8.15 (Stable) [isaacs]

ちなみに一番下の日付が 10-25 なのは、その前のコミットが 11 月だったので一覧に出てきたみたいです。

オプションは以下の通り。実装は単に git-log にいろいろフォーマットを与えているだけです。

  • --no-merged を指定すると現在のブランチにマージ済みのものは表示されない
  • --days=n で何日以内のブランチを見るかを指定
  • --date=format は日付のフォーマット

2012-10-16

みんなで一緒にウェブ上の音楽を聞ける polka というウェブアプリケーションを作りました

| 13:49 | みんなで一緒にウェブ上の音楽を聞ける polka というウェブアプリケーションを作りました - NaN days を含むブックマーク はてなブックマーク - みんなで一緒にウェブ上の音楽を聞ける polka というウェブアプリケーションを作りました - NaN days

Teto というのを作って、これはニコニコ動画の音声をストリーミングして配信する、というようなことをしていたのですが、いかんせん仕組みが複雑で簡単に使える感じじゃないな〜という問題があり、また、オフィスのみんなでひとつのキューを共有しつつ同時に同じ音楽を聞けたらいいな、という要求を、音声の読み込みや再生処理をすべてクライアントサイドで行うことにして実装したのが polka です。

これからは node.js だよねーノードジェスジェス!と思って node.js で何か書いてみようと思って作りはじめたのが最初でした。

https://github.com/motemen/polka

概要

polka はローカルで起動するウェブアプリケーションです。再生キューをひとつだけ持ち、接続してきたブラウザで同時に同じ音楽を聴くことができます。

実装は node.js + socket.io くらいの感じです。

使い方

2012-10-16 18:10 追記: node v0.8 くらいが必要みたいです!

いい感じにパッケージ化する方法がまだわかってないので github から clone して下さい。

% git clone git://github.com/motemen/polka.git
% npm install
% PORT=3000 npm start

で http://{IPアドレス}:3000/ に polka のサーバが立つので、あとはここにアクセスして貰えばよいです。

  • /queue で URL もしくは検索によってトラックを追加し、
  • /play をブラウザで開きっぱなしにしておくことで自動で再生が行われます。

仕組み

音声の再生には YouTubeSoundCloud の埋め込みプレーヤーを利用していて、polka 自体はキューと再生タイミングの管理だけを行っています。polka のページをブラウザで開くと自動で次々とプレーヤーが埋め込まれてゆき、再生されます。

ブラウザの中でも /play ページに最初に接続したものが master と呼ばれ、この人がほかの人 (echo) の再生のタイミングを管理します。master のブラウザでプレーヤーの再生が終了したタイミングで、他のブラウザも一斉に次のトラックへと進みます。

なので master になってる人が埋め込みに失敗したり (YouTube にはリファラを切ってると埋め込めない動画がある) 途中でポーズしたりすると次に進めなくて困るような場合がありますが、その時は /admin にアクセスして next ボタンをクリックすると強制的に次のトラックへと進みます。

対応しているソース

いまのところ埋め込めるのは以下の 2 サービスのみです。

ニコニコ動画の埋め込みプレーヤーは JavaScript によるコントロールができないっぽいので対応していません。ドワンゴさんよろしくお願いします!!

Patches welcome

……というのを社内に設置してみて、まあいろいろと変な挙動はあるかと思いますが、とりあえず一日は普通に使えた感じです。同僚にもいろいろと機能を追加してもらいました。プルリクエストお待ちしております。

2012-10-05

carton bundle を高速化する

| 21:17 | carton bundle を高速化する - NaN days を含むブックマーク はてなブックマーク - carton bundle を高速化する - NaN days

2013-02-08: Carton 本体に bundle 時にデフォルトで carton.lock を参照するような変更 が入りました。以下の内容は古くなってると思います


carton を使ってるプロジェクトで tarball をリポジトリに同梱している場合、依存モジュールが増えるたびに carton bundle することになるのだけど、モジュールの数が増えてくるとこれがすこぶる遅くなってしまう。なんでかというと (cpanfile や Makefile.PL を元に) 依存関係をチェックしなおしているからで、その結果 tarball 追加するだけのつもりが carton.lock まで更新されてしまった、というような事態にもなったりする。

これらの挙動を自分好みというか気楽なふうにするため、--locked というオプションを実装してみました。

https://github.com/motemen/carton/tree/bundle-locked

carton bundle --locked とすると、(cpanfile ではなく) carton.lock の内容をもとに tarball をダウンロードするようになります。こうすることで

  • carton.lock が更新されない
  • carton.lock に記録されているモジュールは依存関係などのチェックがすんでいるので、単純にダウンロードだけを行える

というメリットがあります。

ちなみに [2012-10-24: 以降の内容は bundle-locked-download ブランチに移動しました] cpanminus を起動するときに (本家にはない) --download というオプションが指定されていて、ふつうのバージョンを使っている場合には無視されるのですが、本家にあった pull-req (https://github.com/miyagawa/cpanminus/pull/118) に1コミット追加して (https://github.com/motemen/cpanminus/tree/download) 最新の master にマージしたもの (https://github.com/motemen/cpanminus) を使うと便利なオプションで、--download を指定すると

  • tarball の展開をしない (もともとの pull-req の内容)
  • すでに同名の tarball が存在している場合、ダウンロードしない

という挙動になり、IO が劇的に減るため、2 回目以降の carton bundle が高速化できます (数秒で完了するようになります)。