from s14u.info

26 March 2008

Hash::Merge

Perl でハッシュをマージしたいなと思った。というか Catalyst で config メソッドはどうなっているのか見てみたら、Catalyst::Component の config メソッドで Catalyst::Utils::merge_hashes を呼び出している。merge_hashes($a, $b) としたときに、$a に $b をマージするためにいろいろとごにょごにょしているわけです。そのごにょごにょ(つまり Catalyst::Utils::merge_hashes)を単体で使いたいと思ったけど Catalyst 名前空間のモジュールは依存関係に含めるとちょっと厄介なイメージがあったので、単体で使えるモジュールが CPAN にないか探してみたらありました。

Hash::Merge

名前からしてズバリな感じです。

使い方は perldoc にあるように次の通り。

use Hash::Merge qw( merge );my %a = (    'foo'  => 1,    'bar'  => [ qw( a b e ) ],    'querty' => { 'bob' => 'alice' },);my %b = (    'foo'  => 2,    'bar'  => [ qw(c d) ],    'querty' => { 'ted' => 'margeret' },);

my %c = %{ merge( \%a, \%b ) };

とすると、デフォルトでは %a から %b に上書きする感じになって結果は次のようになります。

$VAR1 = 'bar';$VAR2 = [     'a',     'b',     'e',     'c',     'd'    ];$VAR3 = 'querty';$VAR4 = {     'bob' => 'alice',     'ted' => 'margeret'    };$VAR5 = 'foo';$VAR6 = 1;

ARRAYは結合してくれているし、SCALARは上書きしてくれているし、HASHはマージしてくれている。

で merge メソッドの第二引数を第一引数にかぶせたい場合もあるでしょう。そんなときには Hash::Merge::set_behavior メソッドを使います。
先ほどの上記のコードは以下のようになります。

use Hash::Merge qw( merge );my %a = (    'foo'  => 1,    'bar'  => [ qw( a b e ) ],    'querty' => { 'bob' => 'alice' },);my %b = (    'foo'  => 2,    'bar'  => [ qw(c d) ],    'querty' => { 'ted' => 'margeret' },);

Hash::Merge::set_behavior( 'RIGHT_PRECEDENT' );
my %c = %{ merge( \%a, \%b ) };

とすると結果は次の通りです。

$VAR1 = 'bar';$VAR2 = [     'a',     'b',     'e',     'c',     'd'    ];$VAR3 = 'querty';$VAR4 = {     'bob' => 'alice',     'ted' => 'margeret'    };$VAR5 = 'foo';$VAR6 = 2;

SCALAR である foo が %b の方を採用して 2 になっているのがわかりますね。

merge メソッドの引数の書き方を見れば分かるようにハッシュのリファレンスを渡していますし、merge メソッドの戻り値もハッシュのリファレンスなので次のように書く事もできます。

my $a = {    'foo'  => 1,};my $b = {    'foo'  => 2,};my $c = merge( $a, $b );

そうすれば結果は以下のようにになりますね。

$VAR1 = {     'bar' => [           'a',           'b',           'e',           'c',           'd'          ],     'querty' => {            'bob' => 'alice',            'ted' => 'margeret'           },     'foo' => 2    };

これはいい。Hash::Mergeを採用してみることに決めました。

21 March 2008

テストです。

This is a test. please ignore this entry. thanks.

19 March 2008

xs:choice

今、XML Schema について少し学んでいるのですが、xs:choice について疑問があって調べました。

xs:choice というのは以下の例の場合、foo, bar, baz のいずれか一つを選択しなければなりません。

<xs:choice>  <xs:element name="foo" />  <xs:element name="bar" />  <xs:element name="baz" /></xs:choice>

xs:choice には 2 つの属性があります。

  • minOccurs (デフォルトは1)
  • maxOccurs (デフォルトは1)

なので、<xs:choice minOccurs="1" maxOccurs="1"> ということになるわけです。でも省略されているから、<xs:choice> は必ず一つを選択するということです。
で、<xs:choice minOccurs="0"> とした場合は 1 つ含まれるかもしれないということになるので、選択してもいいし選択しなくてもよくなります。(具体的にはmaxOccurs="1"なので、0か1ということです。)

<xs:choice minOccurs="0">  <xs:element name="foo" />  <xs:element name="bar" />  <xs:element name="baz" /></xs:choice>

foo, bar, baz のうちの1つあるかないかってことですね。

で、当初悩んでいたのが、次の例です。

<xs:choice minOccurs="0" maxOccurs="unbounded">  <xs:element name="foo" />  <xs:element name="bar" />  <xs:element name="baz" /></xs:choice>

unbounded は無制限の意味になります。ではこのときfoo, bar, baz はいくつ選ぶことができるか?
foo, bar, baz の 3 つでも OK ですし、それこそ foo, foo, bar, bar, bar, baz でも OK らしいです。もう choice の意味がないんじゃないか?と思う程。むしろ、xs:choice をやめて以下のようにしてもいいんじゃないか?と思ったり。(おそらく xs:choice にする意味がどこかにあるからこそ、xs:choice を使っているのだと思いますが。。。)

  <xs:element name="foo" minOccurs="0" maxOccurs="unbounded" />  <xs:element name="bar" minOccurs="0" maxOccurs="unbounded" />  <xs:element name="baz" minOccurs="0" maxOccurs="unbounded" />

ま、私は今のところ XML Schema を書くのではなく読む側なので、<xs:choice minOccurs="0" maxOccurs="unbounded"> の意味さえ分かればそれで OK なのですが、それにしても XML Schema は自由すぎて不自由な感じがしました。

ちなみに RelaxNG で書くと以下になります。

( foo | bar | baz )*

ところで、W3C の XML Schema の和訳ってなにげに少ないんですね。。。


参考

13 March 2008

Google Contacts Data API

Google Contacts Data API を使った Movable Type のプラグインを実装しようと思っていたのですが、ブログにユーザ増やしたところであんまり意味が見いだせなくてプラグインの実装はちょっとペンディングなんですが、でもせっかく Contacts Data API を使ったのでサンプルをのせておきます。

今回のポイントは Simon WistowNet::Google::AuthSub です。GData API 系で必ず使う認証の ClientLogin をラップしてくれます。ClientLogin が成功すると Google から戻って来た値をほんの少しごにょっとしなきゃならないのですが、それを隠蔽してくれるので少しきれいなコードになりますね。

このコードを実行するとメールアドレスのリストが取れます。

#!/usr/local/bin/perl

use strict;
use warnings;

use LWP::UserAgent;
use HTTP::Request::Common;
use Net::Google::AuthSub;
use XML::LibXML;
use Data::Dumper;

my $user = 'YOUR_EMAIL_ADDRESS';
my $password = 'YOUR_PASSWORD';
my $authsub = Net::Google::AuthSub->new(service => 'cp');
my $auth_res = $authsub->login($user, $password);
unless ($auth_res->is_success) {
die 'google login is failed.'
}

my $url = "http://www.google.com/m8/feeds/contacts/$user/base";

my $req = HTTP::Request->new(GET => $url);
$req->header($authsub->auth_params);
my $res = LWP::UserAgent->new->request($req);

my $xp = XML::LibXML->new;
my $xml = $xp->parse_string($res->content);
my @emails = $xml->findnodes("/*[local-name()='feed']/*[local-name()='entry']/*[local-name()='email']");
for my $mail (@emails) {
print $mail->findvalue('@address') . "\n";
}

11 March 2008

Perl sprintf の限界?

不思議な現象に出会いました。

0.5 では四捨五入されなかったのですが、
0.51 では 1 になりました。
0.501 でも 1 になりました。
で続けていくと、0.50000000000000001 で再び 0 に戻りました。
これは有効桁数を超えたってことなのかな?
sprintf の限界ってのが有力なんですけどね。。。

[root@colinux ~]# perl -le 'print sprintf "%.f", 0.5'0[root@colinux ~]# perl -le 'print sprintf "%.f", 0.51'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.501'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.5001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.50001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.500001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.5000001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.50000001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.500000001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.5000000001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.50000000001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.500000000001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.5000000000001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.50000000000001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.500000000000001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.5000000000000001'1[root@colinux ~]# perl -le 'print sprintf "%.f", 0.50000000000000001'0[root@colinux ~]# perl -le 'print sprintf "%.f", 0.500000000000000001'0

ちなみに当方、

[root@colinux ~]# perl -vThis is perl, v5.8.8 built for i386-linux-thread-multi

[root@colinux ~]# uname -aLinux colinux 2.6.22-co-0.8.0 #1 PREEMPT Tue Nov 6 00:02:11 CET 2007 i686 i686 i386 GNU/Linux

です。

04 March 2008

OpenID Authentication 2.0 について少し

OpenID Hack-a-thonCodeReposのOpenID対応builder techday などで実装レベルにおける OpenID 2.0 対応が少しずつ身近なものになってきました。OpenID 1.1OpenID 2.0 の違いについては、id:ZIGOROuさんの @IT の記事builder techday での Lightning Talk が参考になると思います。

OpenID 1.1 と OpenID 2.0 の違いを簡単にいえば、

  • Identifier に URL と XRI が使えるようになった
  • Discovery の方式が変わった

といった辺りがポイントでしょうか。


Identifier に URL と XRI が使えるようになった

XRI (EXtensive Resource Identifier) については OpenID 2.0 の仕様書の Normative Reference にあります、[XRIResolution2.0] と [XRISyntax2.0] を参考にすると XRI の仕様が分かります。[XRIResolution2.0] で XRDS (EXtensive Resource Descripter Sequence) 文書を含む XRI を取り囲む仕様が、 [XRISyntax2.0] では XRI のシンタックスについての仕様が書かれています。XML関係で標準化を進める団体 OASIS の下で作成されました。XRI も URL と同様にあるリソースをユニークにするものです。なので、Identifier として利用することが出来るわけです。XRI については仕様をよく読めば理解できるかなと思います。


Discovery の方式が変わった

これは大きな変化です。例えば、fastladder.com で yahoo.com の OpenID を使おうとしたときに(すでに 「Sign in with Yahoo! ID」ボタンがあるのでアレなんですけど)、「yahoo.com」と入力しただけでOpenID プロバイダの認証ページにリダイレクトされるようになります。OpenID 1.1 のころですと、comewalk.livejournal.com のように長い URL の入力が必要でしたが、ドメインだけで充分になっています。OpenID 1.1 のころは comewalk.livejournal.com ならば以下のような Link Discovery が HTML ページのHEAD セクションにありました。

<link rel="openid.server" href="http://www.livejournal.com/openid/server.bml"/><link rel="openid.delegate" href="http://comewalk.livejournal.com/"/>

これが大きく変わります。OpenID 2.0 の仕様の 7.3 Discovery が参考になります。

1. If the identifier is an XRI, [XRI_Resolution_2.0] (Wachob, G., Reed, D., Chasen, L., Tan, W., and S. Churchill, "Extensible Resource Identifier (XRI) Resolution V2.0 - Committee Draft 02," .) will yield an XRDS document that contains the necessary information. It should also be noted that Relying Parties can take advantage of XRI Proxy Resolvers, such as the one provided by XDI.org at http://www.xri.net. This will remove the need for the RPs to perform XRI Resolution locally. 2. If it is a URL, the Yadis protocol (Miller, J., "Yadis Specification 1.0," .) [Yadis] SHALL be first attempted. If it succeeds, the result is again an XRDS document. 3. If the Yadis protocol fails and no valid XRDS document is retrieved, or no Service Elements (OpenID Service Elements) are found in the XRDS document, the URL is retrieved and HTML-Based discovery (HTML-Based Discovery) SHALL be attempted.

意訳すると、1.XRIが入力されたならばXRI Resolutionに従ってXRDS文書を探します。2.URLが入力されたならばYadisプロトコルでXRDS文書を探します。3.Yadisもダメ、XRDS文書もinvalidで、サービス要素である<xsd:Service>もない。ならば、HTMLのlink要素をみてみます。という具合です。

さらに以下の記述も変わります。

<link rel="openid.server" href="http://www.livejournal.com/openid/server.bml" /><link rel="openid.delegate" href="http://comewalk.livejournal.com/" />

OpenID 2.0 対応では次のようになります。サンプルが仕様書にあります。

<link rel="openid2.provider" href="http://www.livejournal.com/openid/server.bml" ><link rel="openid2.local_id" href="http://comewalk.livejournal.com/" />

OpenID 1.1 と OpenID 2.0 を共存させるには、rel属性に両方を書きます。

<link rel="openid2.provider openid.server" href="http://www.livejournal.com/openid/server.bml" /><link rel="openid2.local_id openid.delegate" href="http://comewalk.livejournal.com/" />

ところで、www.yahoo.com の HTML を見ても、OpenID の Discovery らしきものは見当たりません。Yadis の仕様書を見たらこんな記述がありました。

6.2.4 InitiationThe Yadis Protocol is initiated by the Relying Party Agent with an initial HTTP request using theYadis URL.This request MUST be either a GET or a HEAD request.A GET or HEAD request MAY include an HTTP Accept request-header (HTTP 14.1) specifying MIMEmedia type, application/xrds+xml.

GETかHEADで取ると。必要であれば Accept: application/xrds+xml を付けようと。

で試してみました。

comewalk:~ takatsugu$ telnet www.yahoo.com 80Trying 209.131.36.158...Connected to www.yahoo-ht3.akadns.net.Escape character is '^]'.HEAD / HTTP/1.1Host: www.yahoo.comAccept: applilcation/xrds+xmlHTTP/1.1 200 OKDate: Tue, 04 Mar 2008 15:31:02 GMTP3P: policyref="http://p3p.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"Cache-Control: privateVary: User-AgentX-XRDS-Location: http://open.login.yahooapis.com/openid20/www.yahoo.com/xrdsLast-Modified: Tue, 04 Mar 2008 15:22:48 GMTAccept-Ranges: bytesContent-Length: 9533Connection: closeContent-Type: text/html; charset=utf-8

X-XRDS-Location: http://open.login.yahooapis.com/openid20/www.yahoo.com/xrds

というのがかえってきました。yahoo.com は HEAD で取得できるようですね。で、http://open.login.yahooapis.com/openid20/www.yahoo.com/xrds というファイルが XRDS文書なのです。見ると

<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns:openid="http://openid.net/xmlns/1.0" xmlns="xri://$xrd*($v*2.0)"> <xrd>  <Service priority="0">   <Type>http://specs.openid.net/auth/2.0/server</Type>   <Type>http://specs.openid.net/extensions/pape/1.0</Type>   <uri>https://open.login.yahooapis.com/openid/op/auth</uri>  </Service> </xrd></xrds:XRDS>

となっていて XPath でいうと /XRD/Service/URIなところにURLがありますね。そこが OpenID Provider の URL なのです。HTML の link要素から取得しないあたりがもう全然違っていて、面白いですね。これでやっと OpenID 2.0 の Discovery が理解できてきたのでアレをああしてこうできそうです。


まとめ

bradfitzやDavid Recordon、miyagawaさんやkazeburoさんなどのおかげで Net::OpenID::Consumer と Net::OpenID::Server が OpenID 2.0 に対応し、Six Apart の subversion repository から入手することができます。

svn co http://code.sixapart.com/svn/openid/branches/openid2/perl/ openid2

OpenIDの入力が簡単になった。Yahoo! など大手が OpenID Provider になった。あとは開発者の皆さんがご自分のプロダクトで OpenID 対応をすすめることが OpenID が広まるポイントだと思います。さあ、OpenID 2.0 対応をすすめていきましょう。

29 February 2008

Blogging via Flickr is failed.


Blogging via Flickr is failed.
Originally uploaded by shigeta
さっきFlickrからエントリをしたときのこと。さんざんFlickrでは失敗したとのメッセージが出たので連続で何件か投稿したわけですが、なんと全部投稿されていました。おそらくMovable Typeのxmlrpcの戻り値とFlickrが期待する戻り値に違いがあるんだろうな、と想像しつつ。。。
もしFlickr経由でMovable Typeにブログしている人がいらっしゃいましたら、Flickrでエラーが連続で出る場合、パスワードの確認ももちろんですが、一度ブログを確認されるとよろしいかと思います。もしかしたら投稿されているかもしれませんので。。。

OpenID Hack-a-thon


OpenID Hack-a-thon
Originally uploaded by shigeta
本日は Six Apart の赤坂オフィスにて、OpenID Hack-a-thon が開催されました。Mixiの皆様、id:ZIGOROuさん、Yappoさん、グルコースの安達さん、miyagawaさん、David Recordon、Movable Typeのエンジニア、TypePadのエンジニア(私)が参加しました。最初に自己紹介をしてから、19:00頃から23:00頃まで短い時間でしたが皆さんかなり集中してハックされていました。部屋が狭くて、肝心のDavidを囲むことができなくて本当申し訳ありませんでした。でもOpenID 2.0 対応に向けて積極的に取り組みました。昨日のCNETの builder techday が概論編で、今日が実践編といった感じでしょうか。とても濃い時間を過ごせたので楽しかったです。コードを書くのって楽しいですよね。そして分からないことがあればふと聞いてみるとグッドアイデアが出てくる。これもHack-a-thonの醍醐味のひとつです。
今後もSix ApartはOpenIDに限らず様々なテーマでHack-a-thonの場の提供を出来ればいいなと思います。また機会がありましたらぜひご参加ください。
参加された皆さんおつかれさまでした。またお会いしましょう!

私は OpenID 2.0 の Discovery についてもう少し学ぶ必要があります。。。

23 February 2008

microformats vCard and Web::Scraper

Perl microformat parsing というスレッドで「microformats の vCard などを Perl でスクレイピングする」という話題がありましたので、私が Web::Scraper を紹介しましたところ、Web::Scraper の作者の miyagawa さんよりベターな使い方のレスポンスをいただきました。ありがとうございました。

my $scraper = scraper {  process ".vcard", "vcards[]" => scraper {    process ".email", email => '@href';    process ".fn", fullname => "TEXT";    process ".tel", tel => "TEXT";    process ".title", title => "TEXT";  };};my $result = $scraper->scrape($uri);

scrape をネストさせるとは恐れ入りました。。。

この件について builder tech day - open API & beyond で Lightning talk してもいいかなと思いました。microformats と Web::Scraper はかなり親和性が高いのでもっと広まるといいと思います。まだ募集してるかな?

LTに出る出ないに関わらず、builder tech day - open API & beyond は行きます。よろしくお願いします。

30 January 2008

Action Streams プラグイン

Movable Type 4.1リリースされhack-a-thon開催されMovable Type が盛り上がっているわけですが、さらに blogging を進化させた形のプラグインが登場しました。

Action Streams プラグイン

このプラグインはどういうプラグインかというと、Twitter とか del.icio.us とか YouTube とか自分の行動が見えるようになるって感じっすね。百聞は一見にしかず、といいますから次の方々の例をごらんになるとよいと思います。

作業としては、こちらの画像のようにサービスを登録していくこととプラグインのREADMEに書いてあるように cron を設定することですね。

 # Movable Type's scheduled tasks script: 0,30 * * * * cd /path/to/mt; perl ./tools/run-periodic-tasks

私のホスティングでは cron が使えないのでこのプラグインは無理か・・・と思っていましたが、

Activity FeedをBloglines(でも他でもいいけど)に登録しておけば
という助言をいただいたのでそれで試せるかもしれません。(まだやっていないですが)

自分を紹介するのにブログだけでなく周辺のサービスの活動状況もひっくるめるというのは非常にいいですね。すでに多くのプロフィールサービスがこのような UI を提供しているわけですが、やっぱり自分のブログで同じことをやりたいじゃないですか!そんなプロフィールサービスを Movable Type 上で実現しちゃった Movable Type Team はステキすぎる。


参照

Access Ranking

Powered by Six Apart
Sponsored links