AnyEvent 5.3 Released

出てました。気がつきませんでした。

このバージョンから AnyEvent::Impl::Cocoa が入りました。これは Cocoa::EventLoop を AnyEvent から使うアダプターで、

use Cocoa::EventLoop;

していると自動的に使われます。したがって、

use AnyEvent;
use Cocoa::EventLoop;

# AnyEventを使用したコード...

と言うように書くと自動的に Cocoa のイベントループで AnyEvent が動作するというわけです。 こうしておけば Cocoa::Growl など、Cocoa::EventLoop を必要とするモジュールをシームレスに AnyEvent 内で使うことが出来て便利です。

なお、AnyEvent::Impl::NSRunLoop は DEPRECATED ってことでとりあえずドキュメントに注意書きを加え、さらに数週間後にはCPANから削除するつもりです。

by typester / at 2011-01-04T10:25:00 / perl · anyevent · osx / Comment

PerlのXSでObjective-Cを使うときに気をつけること

QuickDraw API で定義されている Move マクロが、perl の handy.h の中で定義されているものとコンフリクトするため、

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"

// undefine Move macro, this is conflict to Mac OS X QuickDraw API.
#undef Move

#import <Foundation/Foundation.h>

こんなようにしてperl関係のヘッダーをincludeしたあと#undefしてあげたうえでCocoaのヘッダーをimportするようにすると良い。

なお、 Foundation 以外にリンクするときはまた別の問題があるかもしれない。

基本XS使うときは、まず単体でうごくCやObjective-Cのコードを書いて、XSはそれをつなぐだけという感じで使っているので、ガチでXS内でごりごり処理を実装することはなく、perlのMoveマクロは使ったことないから、それを使いたいときにどうすればいいかは知らない。

memmoveのラッパーみたいだけど、NewxやSafefreeなどのようにこれ使ったほうが良いとかたぶんあるんだろうけど。

by typester / at 2010-12-31T01:46:00 / perl · xs · objc / Comment

AnyEvent::Impl::NSRunLoop

っていう頭おかしいモジュールを作ってるんですが、これについていくつか schmorp (AnyEvent作者)とはなして以下のようにしていくことにした。

  • NSRunLoop の実装は Cocoa::RunLoop と言うモジュールに外だし
  • AE::Impl の方はそれをただ使うだけ
  • Cocoa::RunLoop は AnyEvent に依存しなくても使える
  • AnyEvent は Cocoa::RunLoop がロードされている環境ではバックエンドに Impl::NSRunLoop をつかう

と言うわけで将来的には、Cocoa::Growl とかそれ系のモジュールはシームレスに AnyEvent 内で使えるようになる感じです。

by typester / at 2010-12-17T10:54:00 / perl · anyevent / Comment

ふるいPerlをいれる

perlbrew を導入したのでもりもりテスト環境を作れるようになったわけですが、perl-5.8.8 をいれようとしたら

    Can't open makefile: No such file or directory.
    Can't open x2p/makefile: No such file or directory.
    make: *** No rule to make target `<command-line>', needed by `miniperlmain.o'.  Stop.
    make: *** No rule to make target `<command-line>', needed by `miniperlmain.o'.  Stop.

のように make がこけてしまってインストールできなかった。 ググってみるとどうも新しいgccだと古いPerlはうまくビルドできないらしい。

解決法としては makefile (OSXではGNUmakefile) の command-line を含む行は消してあげるというのでなんとかなるみたい。

以下のようにしてみた:

$ ./Configure -de -Dprefix=$HOME/perl5/perlbrew/perls/5.8.8
$ perl -i~ -nle 'print unless /command-line/' GNUmakefile x2p/GNUmakefile
$ make
$ make test
$ make install

これでちゃんとperlbrewからも認識できてて

$ perlbrew switch 5.8.8

とかでswitchできました。まる。

by typester / at 2010-08-13T09:05:00 / osx · perl / Comment

Text::MicroTemplate::DataSection

__DATA__

__DATA__

@@ index.mt
<html>
 <body>Hello</body>
</html>

@@ bar.mt
? if ($true) {
  Foo
? }

こう言うのが書いてあるとき、Data::Section::Simple を使うと

get_data_section('index.mt');

とすることで該当セクションだけのデータを簡単に取得することができます。 なので普通の Text::MicroTemplate と組み合わせても

render_mt(get_data_section('index.mt'));

って感じで使えてそんなに苦じゃないわけですが、どうせなら中で include とか extends とかで他のセクションのデータとも連携できるようにしたら便利だなーと思い3分クッキングして Text::MicroTemplate::DataSection と言うのを書いてみました。

使い方は簡単、

use Text::MicroTemplate::DataSection 'render_mt';

とすると Text::MicroTemplate::File ベース、

use Text::MicroTemplate::DataSectionEx 'render_mt';

とすると Text::MicroTemplate::Extended ベースの機能が使えるようになります。

あとは render_mt('index.mt') などとすれば __DATA__ からテンプレート出力が行えます。基本ベースクラスのすべての機能がつかえますので、Exを使っている場合は、

? extends 'base';

? block content => sub {
Hello!
? }

とか

?= include 'hoge'

とかもそのまま __DATA__ のなかのテンプレートで使用することができます。Enjoy!

by typester / at 2010-07-03T12:20:00 / perl / Comment

PerlエンジニアのためのObjective-C Blocks入門

OS X 10.6 以降の xcode では Objective-C に Blocks というシンタックスが追加されている。

Blocks Programming Topics: Introduction

Perl でいうところの無名関数(コードブロック)を作ることができる機能で、Perlでいうところの

my $f = sub { ... };
$f->();

void (^f)() = ^{ ... };
f();

のように書ける。書式がきもいのはObjective-Cの定めなのであきらめましょう。 より詳しい書式については上記ドキュメントを見ると良い。

しかしデフォルトではPerlのコードブロックとはレキシカル変数の扱いが異なる。

my $i = 0;
my $f = sub { return $i + 1 };

$i++;

$f->(); # 2 を返す

perlではこのようにレキシカル変数はコードブロック内と共有されるが、Objective-Cの場合は

int i = 0;
int (^f)() = ^{ return i + 1; };

i++;

f(); // 1 を返す

このようになる。これはブロックを作成するときのレキシカル変数がコピーされるからである。 Perlとおなじような挙動を望む場合は __block ストレージタイプを指定すればいいようだ。

__block int i = 0;
int (^f)() = ^{ return i + 1; };

i++;

f(); // 2

ここまでわかればObjective-CでBlockの再帰を書くことができる。

__block void (^f)();
f = ^{ f(); };
f();

これは以下とおなじ、

my $f;
$f = sub { $f->() };
$f->();

というようにPerlエンジニアにとっては割と直感的なコードブロックが使えるようになっております。 書式がきもいことをのぞけばいい感じです。

次回は「PerlエンジニアのためのGrand Central Dispatch」の予定です。

追記@2010-05-11T19:12:48+09:00

はてなブックマーク - PerlエンジニアのためのObjetive-C Blocks - unknownplace.org

lyokato 「Objective-Cの仕様というよりは、Blocks拡張に対応したCコンパイラの仕様かな」

ってことでやってみたら

#include <stdio.h>

int main(int argc, char** argv) {
    void (^f)() = ^{ printf("Hello Blocks!\n"); };
    f();

    return 0;
}

// $ gcc foo.c
// $ ./a.out

でも行けました。gcc の拡張なんですね。あざっす!

by typester / at 2010-05-11T14:29:00 / objc · perl / Comment

qpsmtpd を Server::Starter 化するなど

Perl 製 SMTP サーバーとして qpsmtpd というものがあり、僕もいろいろなところで利用している。主な用途としてはメール連動の Web アプリケーションのメール機能の部分。実際のメール配送などでは使用してない。

フロントに qpsmtpd を置き、アプリで制御する宛先の場合のみ qpsmtpd からジョブキューに流したりする。 それ以外の通常のメールは queue/postfix プラグインなどを使用して裏側の postfix にまかせちゃう。というような使い方をしている。

qpsmtpd 自体は apache.org や perl.org の SMTP として採用されており、パフォーマンスに関しては問題ないのだが、プラグインを書き換えたり設定を変更したりした場合に再起動が必要になるところが、フロントに立てるサーバーとしては不安な部分であった。

なので前々から Server::Starter 対応はしたいとおもっていたが安定動作している既存のサーバーで作業する機会も特になく放置していた。

そしてこのたびめでたく新しく qpsmtpd を設置することになったためいっちょやったるか、となった次第である。

この辺で作業:

http://github.com/typester/qpsmtpd/commits/topic/server_starter

使い方は:

# start_server --port=25 --port=127.0.0.1:20025 -- ./qpsmtpd-async-server-starter

このような感じで、SMTP用のポートと、qpsmtpd 制御用の contig ポートを同時に渡して起動する。その後 Server::Starter の superdaemon にたいし HUP シグナルを送ると graceful restart できる。

古い worker プロセスでは最大 $TIMEOUT 秒(デフォルト60)だけ既存の接続を終了まで待つ、graceful shutdown 機能も併せて実装したので完全にダウンタイムをなくせているはず。

とりあえずあまりテストしきれてないけどドッグフードを食べてがんばろうと思います。

by typester / at 2010-03-24T22:38:00 / perl · qpsmtpd / Comment

yokohama.pm tech talk #5

OpenSocial なモバイルアプリを書く場合、アプリ単体でテストできるようにしてくれる Moxy の OpenSocial プラグインの話と、外部 API 呼び出しを専用に行う非同期なプロクシサーバーの話をしました。

資料はこちら:

OpenSocial mobile application development

前者に関しては、個人的には OpenSocial モバイルアプリ開発には必須なツールなので良い感じにしていきたいところ。 &してくれるひと募集。

後者のプロクシサーバーは「あんまり頭よくない」だけれども、現在のウェブアプリケーションの構成で、API呼び出しの待ち時間をうまく使おうとするときにはこうなるのかなぁと思った。同じようなことをしているところもあるらしい!

個人的にはそれ〜でできるよ!ってのがないかなーと思っていたのだけど、ないっぽいのかなー。

nginx でおしいところまではできるので、モジュール書いたら出来るのか調べてみようと思う。

by typester / at 2010-03-06T13:19:00 / perl · yokohama.pm / Comment

local::lib を切り替える

レガシーなアプリをメンテするのにレガシーな Perl モジュールが必要になることがあり、そのために古いアプリ用には専用の local::lib ディレクトリを切っているわけですが、普段から日常的に local::lib を使用しているため shell が上がったタイミングではデフォルトの local::lib 環境変数がセットされていて切り替えが非常に面倒だった。

これまではそれほど頻繁に使用しなかったので放置していたのだが、ここのところ頻繁に必要になるためいい加減うざくなってきて簡単に local::lib を切り替えられるよう設定をしてみた。

zsh に次のような関数をつくり、それで local::lib を切り替えるようにする。

function locallib () {
    INSTALL_BASE=$1
    if [ -d $INSTALL_BASE ]; then
        eval $(~/bin/use-locallib $INSTALL_BASE)
    fi
}

これは

$ locallib ~/perl5

などのように INSTALL_BASE を指定して使う。指定されたパスが存在したら use-locallib というコマンドを使用して環境変数を切り替えるという内容。

この use-locallib コマンドは以下のようなソースになっていて、古い local::lib の環境変数をクリアするとともに、新しい local::lib の環境変数を print するというものになっている。

#!/usr/bin/env perl

use strict;
use warnings;
use Pod::Usage;

use Config;
use File::Spec;

my $install_base = $ARGV[0]
    or pod2usage(-1);

$install_base = File::Spec->rel2abs($install_base);

my $path     = $ENV{PATH};
my $perl5lib = $ENV{PERL5LIB};

push @INC, File::Spec->catdir($install_base, 'lib', 'perl5');

require local::lib;
my %env = local::lib->build_environment_vars_for($install_base, 1);

# remove $PERL5LIB set by old local::lib if it exists.
if (my $old_base = $ENV{PERL_MM_OPT}) {
    my %mmopt;
    for my $opt (split /:+/, $old_base) {
        my ($k, $v) = split /=/, $opt;
        $mmopt{$k} = $v;
    }

    if (my $old_installbase = $mmopt{INSTALL_BASE}) {
        if ($old_installbase eq $install_base) {
            # do nothing if install_base is equal to old one
            exit;
        }

        my @old_perl5lib = (
            File::Spec->catdir($old_installbase, 'lib', 'perl5'),
            File::Spec->catdir($old_installbase, 'lib', 'perl5', $Config{archname}),
        );

        $env{PERL5LIB} = do {
            my @env;
            ENV: for my $e (grep { $_ } split $Config{path_sep}, $env{PERL5LIB}) {
                for my $old (@old_perl5lib) {
                    next ENV if $old eq $e;
                }
                push @env, $e;
            }
            join $Config{path_sep}, @env;
        };

        my $old_path = File::Spec->catdir($old_installbase, 'bin');
        $env{PATH} = do {
            my @p;
            for my $p (grep {$_} split $Config{path_sep}, $env{PATH}) {
                next if $p eq $old_path;
                push @p, $p;
            }
            join $Config{path_sep}, @p;
        };
    }
}

while (my ($k, $v) = each %env) {
    print qq[export $k="$v"\n];
}

=head1 NAME

use-locallib - set/switch local::lib environment

=head1 SYNOPSIS

use-locallib (MODULE INSTALL BASE)

これで local::lib を簡単に切り替えられるようになるけれど、複数の local::lib 環境を同時に使用しているとどのシェルがどの local::lib を使用しているかわからなくなってしまう。

そのためシェルのプロンプトに INSTALL_BASE を表示されるようにしてしのいだ。

show INSTALL_BASE in terminal prompt

これは単純に以下のような PERL_MM_OPTINSTALL_BASE をプリントするスクリプトを PROMPT 設定から読んでいるだけである。

#!/usr/bin/env perl

use strict;
use warnings;

my %mm_opt;
for my $opt (split /:+/, $ENV{PERL_MM_OPT} || '') {
    my ($k, $v) = split /=/, $opt;
    $mm_opt{$k} = $v;
}

my $install_base = $mm_opt{INSTALL_BASE};
if ($ENV{HOME}) {
    $install_base =~ s/^$ENV{HOME}/~/;
}

print $install_base || 'none';
by typester / at 2010-03-01T17:17:00 / perl · zsh / Comment

Snow Leopard の Perl とアーキテクチャ

Snow Leopard には二つの Perl がインストールされている

  • /usr/bin/perl5.10.0
  • /usr/bin/perl5.8.9

デフォルトの /usr/bin/perl は 5.10.0 のほう。それぞれユニバーサルバイナリになっていて、

$ file /usr/bin/perl5.10.0
/usr/bin/perl5.10.0: Mach-O universal binary with 3 architectures
/usr/bin/perl5.10.0 (for architecture x86_64):  Mach-O 64-bit executable x86_64
/usr/bin/perl5.10.0 (for architecture i386):    Mach-O executable i386
/usr/bin/perl5.10.0 (for architecture ppc7400): Mach-O executable ppc

$ file /usr/bin/perl5.8.9
/usr/bin/perl5.8.9: Mach-O universal binary with 2 architectures
/usr/bin/perl5.8.9 (for architecture i386):     Mach-O executable i386
/usr/bin/perl5.8.9 (for architecture ppc7400):  Mach-O executable ppc

という感じで、5.10 は 64bit 版があるが、5.8 にはない。

で、普通に perl を実行すると perl5.10.0 は x86_64 で実行され、perl5.8.9 は i386 で実行される。

このアーキテクチャの差が結構くせ者で Snow Leopard 上で普通にライブラリなどを make すると x86_64 だけでビルドされてしまうため、そのようにして作ったライブラリはそのままでは perl5.8.9 からは使えないということになる。

デフォルトの 5.10.0 だけ使っている分にはなにも問題はないのだが、残念なことにこの 5.10.0 というのはいろいろな問題があり、開発に使用することはおすすめできない状況。(せめて 5.10.1 にしてくれればいいのに)

したがって無用なトラブルを避けるためにも 5.8.9 の方を使用するか、自前でビルドした perl を使用するのが良い。

またこのように x86_64i386 両方のアーキテクチャの実行ファイルがあり得る Snow Leopard に対して自分でライブラリをインストールする場合それらもユニバーサルバイナリにしておくと良い。

念のため追記@2010-01-08T15:19:23+09:00: もちろんこれは 64bit 対応の CPU の場合の話。そうでない場合はどちらも i386 で実行されるのでこの問題は起こらない。

by typester / at 2010-01-08T10:51:00 / osx · perl / Comment

1 2 3 4 5 6 7 8 9 10

(Page 3 of 30)