CPAN::Reporter入れてテスト結果を送るようにした

use Perl | Become a CPAN Tester with CPAN::Reporter

CPAN::Reporter has had over 20 releases since I first announced it here on August 26. Now anyone with an up-to-date CPAN.pm can contribute to CPAN Testers -- no smoke server needed.

ちゃんとテストレポート送っとこうと思い立って設定した。

warnとcarp,dieとcroak

違いをやっと理解した。

perlnewmod - 新しいモジュールを配布するには

Carp モジュールを使うと、エラーメッセージを呼び出し側の視点から出力することが出来ます。そのモジュールではなく、呼び出し側の問題であることを示せるのです。
...
もし die する必要があるなら、croak を使いましょう。ただ、本当にあなたのモジュールの責任によるチェックの場合は、warn や die のままにしておきましょう。

warnだと、

No hostname given at /usr/local/lib/perl5/site_perl/5.6.0/Net/Acme.pm
line 123.

となるが、carpだと

No hostname given at bad_code, line 10.

というふうに、エラーメッセージを呼び出し側の視点から出力することが出来る。

CGI書くときにおまじないのように使っていた、

の謎が解けた。

薬を処方されたので構造を描いてみた

一昨日から下腹部(しかも右)が痛い。うーん、ゲレンデが遠のいているというかちょっとヤバいかなってことで、休みをとって病院に行ってきた。虫垂っぽいんだけど、よくわからんので経過を観察しましょうってことで、薬を処方された。

シプロキサンとセレキノン。

手動かす元気はあるので、以前作ったツールで構造描画でもしてみた。

シプロキサン smi2png -w 200 -h 200 -o Ciprofloxacin.png "C1CC1N2C=C(C(=O)C3=CC(=C(C=C32)N4CCNCC4)F)C(=O)O"

Ciprofloxacin

セレキノンはsmi2pngでもiupac2pngでも構造描画することができなかった。

The Perl Review

The Perl Review

60% off the Online Version: Subscribe to TPR this month to get 60% off the web only version, now available to everyone including those in the US.

購読した。

SporkでHTMLスライドショー

Sporkでプレゼン用のスライドを作ってみた。

インストールは

$ cpan -i Spork

で。あとはKwiki::Cacheなんかも入れておかないといけないような。

スライド作成の流れは以下の通り。

mkdir my-slideshow # スライド用の
cd my-slideshow    # ディレクトリ作成
spork -new         # 新規spork
vim Spork.slides   # スライドファイルを編集
vim config.yaml    # 設定ファイルを編集
spork -make        # スライド作成

スライド作成の文法はKwikiスタイル。サンプルみながら書き換えてみた。テーマはSpork::S5Themeを使ったのがこれ

PowerPointもアウトラインの編集だけで、動作の書式設定できるようにすればいいのに。

Win32::PowerPoint - helps to convert texts to PP slides - search.cpan.org

Win32::PowerPoint mainly aims to help to convert Spork (or Sporx) texts to PowerPoint slides. Though there's no converter at the moment, you can add texts to your new slides/presentation and save it.

確かにWin32::PowerPointでコンバートできたら便利に違いない。

make testで.tの出力はドコに消えるのだろう?

perlのmake testでテストファイルの結果をコンソールで確認したいときはwarnでダンプとかを標準エラー出力に吐いて眺めるのだけど、実際printの出力はドコに行くのだろうか?(/dev/null ?)

古いツールをsystem関数で実行するようなプログラムを書いてSOAPで呼び出したら、malformed header from scriptとかいうエラーがでて、

何がmalformedやねん

って小一時間はまった。結局、実行ログを標準出力に吐くツールだった(標準エラー出力に吐いてるもんだと思っていたので原因を突き止めめるのに時間がかかってしまった)。あほすぎ。

File::TempとFile::chdirでレガシーツールをやっつける

コンピュテーショナルケミストリー関連の昔のツールとかは

  • インプットがファイル渡し
  • アウトプットもファイルに吐く
  • 中間ファイルもバコバコ吐く
  • (しかもカレントディレクトリに)

とかいうのが多くて、ラッパー書くときにテンポラリ作ったり消したりしないといけなかったりして結構面倒だ。

で、File::TempFile::chdirの組み合わせでかなり楽ができそうな感じ。

use File::chdir;

$dir = tempdir( CLEANUP => 1 );
($fh, $filename) = tempfile( DIR => $dir );
print $fh $input_data;

{
    local $CWD = $dir;
    my $str = system("exec_legacy_tool_with_file -i $filename");
    die $str if $str;
}

これで、実行後のテンポラリのファイルとかディレクトリは自動的に消されるし、作業ディレクトリを変更してあれこれやったこともローカル化されているので、スコープ抜けるときに綺麗になるので安心。

Text::CSV::Simple::WithHeader

Text::CSV::Simpleはフィールドを指定してやるとCSV読み込むときにハッシュにしてくれるので DBD::CSVとかDBD::AnyDataよりも便利じゃないかと、こっちばっか使うようになってしまったのだが、Text::CSV::SimpleはCSVにありがちなヘッダー付きのcsvをうまく処理してくれない

仕方ないので、

$parser->field_map(qw/id name null town/);
my @data = $parser->read_file($datafile);
shift @data;

と、フィールド指定をして、ハッシュで受け取ってから、ヘッダーの行(最初の行)をshiftして落とすという処理をさせてた。でも、これだとフィールドが100とか200とかあるとfield_map書くのが面倒でたまらんので、ヘッダー処理するようにしてみた。

こんな感じのヘッダー付きのcsvを用意したら、

name,address,etc
kz,tokyo,1
yu,kyoto,2
ha,mie,3

いつものように、Text::CSV::Simpleのノリで

use strict;
use Text::CSV::Simple::WithHeader;
use Data::Dumper;
my $datafile = "data/test.csv";

  my $parser = Text::CSV::Simple::WithHeader->new;
  my @data = $parser->read_file($datafile);
  print Dumper(\@data);

ちゃんとハッシュになって返ってくる。

$VAR1 = [
          {
            'name' => 'kz',
            'address' => 'tokyo',
            'etc' => '1'
          },
          {
            'name' => 'yu',
            'address' => 'kyoto',
            'etc' => '2'
          },
          {
            'name' => 'ha',
            'address' => 'mie',
            'etc' => '3'
          }
        ];

Text::CSV::Simple::WithHeaderに置いておいたがwant_fieldsには対応させてない。

DBICで多対多

多対多のサンプルとしてTags: Database schemasの“Toxi” solutionをDBICで書いてみる。

関連を表すテーブルに対しては、1対多の関係を設定しておいて、更にmany_to_manyを追加する

図にしてみたらわかりやすくなった。

manytomany

ちなみに、1対多はこちらを、多対多はこちらを参考にしました。

Kzfm::Schema

use 5.008008;
use strict;
use warnings;
use base 'DBIx::Class::Schema';
our $VERSION = '0.01';

__PACKAGE__->load_classes(qw/Tag Bookmark TagMap/);

1;

Kzfm::Schema::Tag

use strict;
use warnings;
use base 'Kzfm::Schema';

__PACKAGE__->load_components(qw/PK::Auto::SQLite Core/);
__PACKAGE__->table('tag');
__PACKAGE__->add_columns(qw/id name/);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->has_many(tagmap => 'Kzfm::Schema::TagMap','tag_id');
__PACKAGE__->many_to_many('bookmarks' => 'tagmap','bookmark_id');

1;

Kzfm::Schema::Bookmark

use strict;
use warnings;
use base 'Kzfm::Schema';

__PACKAGE__->load_components(qw/PK::Auto::SQLite Core/);
__PACKAGE__->table('bookmark');
__PACKAGE__->add_columns(qw/id name uri description time_created/);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->has_many(tagmap => 'Kzfm::Schema::TagMap','bookmark_id');
__PACKAGE__->many_to_many('tags' => 'tagmap','tag_id');

1;

Kzfm::Schema::TagMap

use strict;
use warnings;
use base 'Kzfm::Schema';

__PACKAGE__->load_components(qw/PK::Auto::SQLite Core/);
__PACKAGE__->table('tagmap');
__PACKAGE__->add_columns(qw/id bookmark_id tag_id/);
__PACKAGE__->set_primary_key('id');
__PACKAGE__->belongs_to('bookmark_id' => 'Kzfm::Schema::Bookmark');
__PACKAGE__->belongs_to('tag_id' => 'Kzfm::Schema::Tag');

1;

制約の部分だけ、考えてみる。

__PACKAGE__->belongs_to('カラム名(アクセサ?)' => 'スキーマ(pm)');
__PACKAGE__->has_many(テーブル名 => 'スキーマ(pm)','カラム名(アクセサ?)');
__PACKAGE__->many_to_many('任意のキー名' => 'テーブル名','多対多関係のカラム');
  • belongs_toはまぁわかりやすい。
  • many_to_manyは任意にキー名決められるのにhas_manyはキー値にテーブル名指定しないとエラー吐くのが謎。
  • many_to_manyでテーブル名のとこをKzfm::Schema::TagMapってやるのが駄目な理由がよくわからない。

あと、さらにユーザーを追加する場合に、ユーザーとブックマークも多対多の関係になるけど、こっちも正規化したほうがいいのか、むしろやりすぎないほうがむしろいいのか悩む。

追記 06.12.04

ボケボケだったことに気付いた。

DBICで多対多の設定を

かなりボケボケだった。

こういうことらしい。

DBIx::Class::Relationship - Inter-table relationships - search.cpan.org

PACKAGE>$method_name('relname', 'Foreign::Class', $cond, $attrs);

というわけで、こんな感じの理解で。

__PACKAGE__->belongs_to(アクセサ名(任意) => 
    '従うクラス','従うクラスのIDを持つ属性名');
__PACKAGE__->has_many(アクセサ名(任意) => 
    'クラス','自分のクラスのIDをもつ属性名');
__PACKAGE__->many_to_many(アクセサ名(任意) => 
    'has_manyでのアクセサ名','belongs_toでのアクセサ名');

データベースを指しているのかクラスを属性を指してるのか良く分かってなかった。というかO/RマッパーでDBのカラム名っておかしいよって何で気づかなかったんだろう。

  • many_to_manyは任意にキー名決められるのにhas_manyはキー値にテーブル名指定しないとエラー吐くのが謎。
  • has_many(アクセサ名(任意) => 'クラス','カラム名')でOK
  • many_to_manyでテーブル名のとこをKzfm::Schema::TagMapってやるのが駄目な理由がよくわからない。
  • has_manyで指定したアクセサ名が必要なのでダメ。

なんとなくこんな感じか。