腹パン in Ruby

ついったの一部ではやってたのでたまにはRubyで書いてみようと思って。腹パニスト各位は自分でHarapanistをnewしてゆのっちを監視しまくればいいんじゃないですかね

#!/usr/bin/env ruby -Ku

class Frypan
  def fire
    p "カンカンカン!"
  end

  def name
    return "フライパン"
  end
end

class Yuno
  
  def initialize
    @observers = []
    @weapon = nil
  end
  
  def setWeapon(wep)
    @weapon = wep
  end
  
  def hit(str)
    p str + "に" + @weapon.name + "で攻撃"
    @weapon.fire()
    notifyObservers()
  end

  def notifyObservers
    @observers.each do |o| 
      o.harapan(self)
    end
  end

  def damaged
    p "✖X◡X✖"
  end
  
  def addObserver(obs)
    @observers.push(obs)
  end
end

class Harapanist
  def observe(y)
    y.addObserver(self)
  end

  def harapan(y)
    p "エイエイエイ^^"
    y.damaged
  end
end


jomio = Harapanist.new
nekogata = Harapanist.new

yuno = Yuno.new

jomio.observe(yuno)
nekogata.observe(yuno)

yuno.setWeapon(Frypan.new)
yuno.hit("宮子")

sphinx + blockdiagがとっても最強すぎる件

Yokohama.pmで @tk0miya さんが発表していた sphinx + blockdiag。

sphinxはテキストファイルをWiki記法みたいな書き方で書いてmakeするだけでhtmlとかpdfを生成してくれる魔法のツール。pythonで書かれてる。

blockdiagはテキストファイルから遷移図とかシーケンス図とかネットワーク図とかを生成できるツールで、sphinxのreSTファイル内に埋め込むことができる。

コードに対するドキュメントなどはコードに埋め込んじゃえばいいんだけど(pod,javadoc、いろいろあるよね)、設計に関するドキュメントだとか運用に関するドキュメントは別に書かないといけなくて、ついつい後回しにして、必要になった時には後の祭り…なんてことが結構ある。かと言って、開発初期とプロダクトが成熟してきたときでは仕様に結構な差があったりして、初期に書いたドキュメントの図とかをメンテナンスするたびに(photoshop|cacoo|keynote|powerpoint)をたち上げてちまちまと図を修正して…「もう嫌だ!」ってなることも多い。

でも、sphinx + blockdiagでは、編集の必要があるのがテキストファイルだけだし、普段コード書いてるテキストエディタからシームレスにドキュメントのメンテもできるので、仕様が変わったり設計が変わったり運用のアレが変わったりしたときに、すぐに対応することができる。開発をする際にも、コミットの粒度を小さく保つといろいろと幸せになれるけど、これはドキュメントにも同じことが言えて、sphinx + blockdiagだとドキュメントもとてもLightWeightに書けるので、ドキュメントへのコミットの粒度も小さく保つことが簡単にできることになる。

sphinx + blockdiagでドキュメントを書き始めてから結構しあわせなので、みなさんも使うといいと思います。

Yokohama.pmで発表してきました #yokohamapm

スライドはここにあがってます

Yokohama.pm110513


個人的には、sphinxとblockdiagを明日からでも使おう!という気になりました。ドキュメント、ついつい書かないですませちゃうんですよね…。
Sphinx + blockdiag で始めるドキュメント生活 @ yokohama.pm 2011/05 - TIM Labs


また、懇親会で話題になった、「プロトタイプのつもりで作ったものが普通にサービスとして生き残っちゃって運用が大変になる」って話が、まさに今自分が置かれている状況とまるかぶりで、あらためて「技術的負債を残さずにコーディングすること」の重要性を認識させられました。

懇親会で隣に座られていた id:sfujiwara さん、近くに座られていた id:kazeburo さん、帰りの電車でボードゲーム/カードゲームの話をさせていただいた(今度パンデミックやってみます!) @tomita さんにはためになる話をたくん聴かせていただき大変参考になりました。ありがとうございました。

また、初トークで胃の中身をコアダンプしちゃいそうなくらい緊張していたぼくを暖かく迎えてくださった @clouder さん、本当にありがとうございます。今後もらくがきライブ、ごひいきにしていただければと思いますw。

今後もコンスタントにPerl界隈の集まりには顔を出させていただきたいなぁと思っております。よろしくおねがいします。

AnyEventでJSONを読み書きするサーバをMessagePackを読み書きするサーバに書き換える

JSONを読み書きするサーバを作ってたんだけど、転送量を減らしたかったのでMessagePackを読み書きするように仕様を変更した。

use AnyEvent::MessagePackするとAE::Handleのpush_readとpush_writeにmsgpackが生えるので、ほぼ直しなしで書き換えれる。コードも読みやすいので何やってるかもわかりやすいので良いと思います。

use AnyEvent::MessagePack;

...

$handle->push_read(
    msgpack => sub {
        ...
    }
);

$handle->push_write(
    msgpack => [1,2,3]
);

みたいなかんじ

時間かかるプロセスが終わったときにGrowlで通知してくれるやつ

時間かかる処理(homebrewでなんかインストールしてるとかcpan-outdated | cpanm)してるときに、その処理が終わったタイミングでGrowl通知してくれるといいのになーって思うときがあるのでやっつけで書いた。10秒ごとにチェックしてるのでほんとのリアルタイムではないけど、自分用としてはこれで十分。

./watcher.pl 監視したいプロセスのpid &

みたいな感じで使う。

#!/usr/bin/env perl                                                                                                                         
use strict;
use warnings;

use Proc::ProcessTable;
use Mac::Growl;

my $pid = shift or die "<usage> $0 pid";
die "bad pid" unless $pid !~ m/[^0-9]/;
chomp $pid;
while (1) {
    my $t = Proc::ProcessTable->new;
    my $found = 0;
    foreach (@{$t->table}) {
        $found++ if $_->pid == $pid;
    }
    last unless $found;
    sleep 10;
}

my $appname = "process watcher";
Mac::Growl::RegisterNotifications($appname, ['alert'], ['alert']);

Mac::Growl::PostNotification(
    $appname,
    'alert',
    $appname,
    "pid $pid done",
    0,
    0,
    undef,
);

PSGIアプリのテスト方法

webアプリのテストに関して、Modelについては結構テストしやすいからちゃんとテスト書いてること多いと思うのだけれど、Controllerやviewはテストがしにくいのでテストを書かないなんてことがよくあると思うのだけれど(ぼくだけか?)、PSGIアプリならばTest::TCPPlack::Runnerと任意のHTTPクライアント(LWP::UserAgentでもWWW:::Mechanizeでもお好きなものを)を使ってテストを書けば幸せになれる。

use strict;
use warnings;

use Test::TCP;
use Test::More;

use Plack::Rnnner;
use LWP::UserAgent;

my $server = Test::TCP->new(
    code => sub {
        my $port = shift;
        my $app = sub {
            # your psgi app here
        };

        my $runner = Plack::Runner->new;
        $runner->parse_options("--port" => $port, "-E", "dev", "-s", "HTTP::Server::PSGI");
        $runner->run($app);
    },
);

my $ua = LWP::UserAgent->new;
my $res = $ua->get('http://localhost:'.$server->port);
ok($res->is_success);

こんな感じ。

<追記>
もうちょっと調べたらPlack::Testってのがあるので、これ使うのも良い。っていうかそれ使ったほうが良い。
Plack::Test - Test PSGI applications with various backends - metacpan.org