Perlの最近のブログ記事

タイトルの問題ですが、自分はよく以下のような関数でやります。
HTML::TreeBuilderのas_HTML()がうまいことやってくれます。
(実際にはHTML::Element::as_HTML()ですが)
sub _complement_html {
    my $broken_html = shift;
    my $html = do {
        no strict 'refs';
        no warnings 'redefine';
        local *HTML::Entities::encode_entities = sub {};
        local *HTML::Entities::decode = sub {};
        my $tree = HTML::TreeBuilder->new;
        $tree->parse( $broken_html );
        $tree->as_HTML;
    };
    $html =~ s#<html><head></head><body>##g;
    $html =~ s#</body></html>##g;
    $html =~ s#<div>(?:\&nbsp;)?</div>##ig;
    return $html;
}
この関数を使って
<div align="right">foo<font color="#000000">black text
のような閉じてないタグをもったHTMLを渡すと
<div align="right">foo<font color="#000000">black text</font></div>
こんな感じに補完してくれます。

もっと良い方法あるんですかね。
あったら教えて欲しいっす。
% ack --thpppt foo lib
_   /|
\'o.O'
=(___)=
   U    ack --thpppt!
--help みたら --thpppt ってのがあったのでなんだろうと思ったら、こんなのがでた。
それだけです。

2010-03-05に行われたYokohama.pm #5でData::ObjectDriverについて発表したプレゼンを公開します。少しわかりづらい部分を加筆・修正したり、あとなんとなく英語にしてみました。

個人的にD::ODは、やれることは少ないけど、その分ソースが少ないので処理の全部を把握できるし、キャッシュやパーティショニングもサポートしてて使いやすいので、好きなORMの1つです。
興味がある方は是非使ってみてください。

二日目はちょっと仕事があって午後からの参加になってしまったのですが感想をば。


まずは、見たかったけど時間的に見られなかったものとしては

  • 大規模画像配信を支えるPerl‎(id:kazeburoさん)
  • Asynchronous Programming for (A)synchronous Communication‎(id:malaさん)

かなぁ。
他にもいくつかあるけど、その辺はあとで録画を見ようと思います。


次に見たもので印象深いのはYuvalのKiokuDBですね。前々から使おうと思って使ってなかったので、これを機会にちょっといじってみようと思います。
あとはmiyagawaさんの「Remedie: Building a desktop app using Perl, SQLite and jQuery‎」を途中から見たのですが、今までデスクトップアプリは作ったことないんですがなんか作りたくなりました。その時はこれを参考にしようかと思います。


で、最後のLTの感想ですが、yusukebeがあいかわらず面白かったのとtypesterがemacs使おうよって言ってたのが笑えた。emacs好きとしてはtypesterのLTはとても嬉しかったなぁ。ほんとemacsいいのでみんな使いましょうよ。


毎回YAPC::Asiaが終わると思うんだけど、いろいろな刺激を受けるいい機会になってますよね。あーこれ使いたかったんだよねとか、へーこういうことやってる人いるんだとか、そういう人とリアルに話せたりするのはとても重要と感じます。

多くのエンジニアの熱気を空気を肌で感じて、コードを書くモチベーションを上げられて、YAPC::Asiaはとても有意義な場所になってるなぁと思いました。


ちなみに、YAPC::Asia 2009で印象に残ってるトーク以外の話としては下のようなことがありました。

  • 前夜祭で少しだけYAPC::Asia 2009に貢献できた
    ほんとに少しですが貢献できて嬉しかったです。
  • 懇親会でFukuoka.pmShibuya.pmYokohama.pmのリーダで集まって話せた
    機会があったら今度Fukuoka.pmも参加してみたいなぁと思った。
  • raflにTシャツのデザインで話し掛けられた
    来ていたTシャツは下のやつです。
    どうやらこのTシャツはおとぎ話のものらしく、それについて話をしてたんですが英語がなかなか出てこなく、いろいろ話したいのになかなかコミュニケーションできず悔しい思いをしました。もっと話しておけばよかったなぁと後悔しています。
    yapcasia2009_tshirts.jpg
  • オライリーさんのガチャガチャで本が当った
    次の日にZIGOROuさんが、前回の記事を読んで600円(?)すっちゃったYO!と言ってたのが忘れられない。


そんなこんなのYAPC::Asia 2009でした。
いやー楽しかった。

前夜祭のYokohama.pmはそつがなく終わり、ほっとしたのも束の間。
YAPC::Asia 2009 1日目が本日行われました。


いろいろなセッションを見させて頂きましたが、その中でも個人的に面白かったものとしては LT、Ficia、PSGI/Plack、そしてAnyEvent ですかね。


LT以外は単純に自分が知らないものの話ということで大変興味深く聞かせて頂きました。
Ficiaは今迄あまり弄っていないmod_perl2のチューニングや設定うんぬん。PSGI/Plackはこれから期待の内容。AnyEventは今後いろいろと実務でも遊びでも使えそうということで、これからじっくりいじってみようと思いました。


あと懇親会は、去年以上に多くの方とリアルで話すことでいろいろと刺激を受けることができました。
やっぱりこういうのは必要だなぁと思った。


明日は2日目。そして最終日となりますのが今から楽しみです。
といいつつ午前中は参加できないんですけどね...。


あ、あとオライリーさんの販売所の横にあるガチャガチャでバッジが300円でゲットできるということで、やってみたら「当たり」の紙切れがでてきた!


なんとその場にある本の中で好きなものを1冊もらえるというじゃありませんか。


ということで、普段ならば自分ではなかなか買えないであろう「LINUXカーネル」という分厚い本を頂きました!(他の欲しい本はだいたい持っていたというのもありますが...)


オライリーさん太っ腹!
ということで明日はみんなもガチャガチャやったらいいんじゃないでしょうか。


yapcasia2009_oreilly.jpg

YAPC::Asia 2009のチケット販売が開始したようです。

詳しくはこちらをご覧になってみてください。

受領書に配送先って書いてあるんだけど、
なんか配送されてくるのかしら。
間違って旧住所で購入しちゃったのでちょっとドキドキしている。
KiokuDBがちょっと前から気になってて、そしたらたまたまid:tokuhiromがブログで使い方などを書いてたので、それを見ながら試してみようと思いインストールしていたら、requiredに入ってるProc::InvokeEditorというモジュールが目につきました。なにをするモジュールだろと思って調べてみたら便利そうだったので紹介。

これ、なにをするモジュールかと言うとよくcvsとかsvnとかgitとかでコミットする際に「-m」でコメント指定しないとエディタが開いて編集させたりすると思うんですが、その挙動を簡単に記述できるようになるモジュールです。

use Proc::InvokeEditor;

my $unedited_text = '元々のテキスト';
my $edited_text = Proc::InvokeEditor->edit($unedited_text);
warn $edited_text; # 編集後のテキスト

こんな感じで、ものすごく簡単にあれと同じ挙動をさせられます。

あと使うエディタは自分で指定することもできるし、環境変数から拾ったりもできるようです。

デフォルトは下のような順番になってますね。
$ENV{'VISUAL'}, $ENV{'EDITOR'}, '/usr/bin/vi', '/bin/vi', '/bin/ed'

コマンドラインで動かすアプリがあったら今度使ってみようと思った。

Yokohama.pm #4

Yokohama.pm #4に行ってきました。


会場は前回と同様。あの会場は駅近でとてもいいのですが開始時間を考えると、やはり東京組には距離的に大変ですね。ZIGOROuさんも書いてますが、次回からはもうちょっと時間を後ろにして参加しやすい時間にした方がいいかなぁと思いました。


今回はlopnorさんという映像担当がいて、かつikasam_aさんが分配器的なものを持ってきてくれたため前より質の高いustもができたのがとてもよかったです。ありがとうございました!


それで肝心のトークについてですが、今回は「オレオレ○○」の会と言われるように自分プロダクトの紹介が多めだったのですが、これはちょっと使ってみようかなというのがあり見ていて楽しかったです。あとやっぱりyoheiさんのCAPは普段実装ベースのトークが多い中、あぁいったものが聞ける機会が少ないためとても面白かったです。


あと今回嬉しかったのは懇親会の歳にcraftworksさんとnekoyaさんが話しに来てくれて「Yokohama.pmはとてもいい雰囲気ですねー」と言われました。これからもそう感じてもらえるようにいろいろと検討していきたいと思ってるので、いろいろとご意見を頂けたらと思います。


最後に司会のZIGOROuさん、受け付けのtomyheroさん、懇親会担当のkdaibaさん、タイムキーパーのoverlastさん、ありがとうございました。


そういえば懇親会でdannさんのDI講座があってとてもためになりました。dannさんありがとうございました。

antipopさんのApp::SocialSKKをさっそくインストールして使ってみた。
これは素晴しすぎる!

使えるまでを軽く説明しておく(Macの場合)。

まずインストール。

# cpan App::SocialSKK
この際 socialskk.pl も同時にインストールされます。
次に $HOME/.socialskk に

plugins:
  - name: SocialIME
  - name: HatenaBookmark
  - name: Wikipedia
こんな感じに書く。
あとはsocialskk.plを起動するだけでApp::SocialSKK使える状態になります。

AquaSKK側での設定は「環境設定」の「辞書」タブで「+」を押して辞書を追加し、辞書の種類を「外部 skkserv 辞書」にし、場所を「localhost:1179」にするだけです。
(ちなみにいままでMacではMacUIMを使っていたのですが、現状のMacUIMだとskkservとskkの辞書を同時に設定できないっぽいので2年ぶりぐらいにAquaSKKに乗り換えました。そしたらAquaSKKがめっちゃ進化していてびびった)

とりあえず「ほってんとり」って書いて変換したら

料理のススメ:これから料理をしようと思っているひとへ - Money does not hurt your heart
ってでた。はてブからうまく取れてるようですね。
まぁ、これはネタとして。

その他にもSocialIMEには郵便番号とかも登録されてるっぽくて、日本語入力モードで「/0000000」(0000000はちゃんとした郵便番号ね)と打って変換を押すとその郵便番号の住所が出てきました(昔は郵便番号データベースをファイルに落したりしてたのを思い出した)。

っていうか実はSocialIMEに郵便番号が登録されてること知らなくてApp::SocialSKK::Plugin::ZipCodeとか作っちまった。悔しい...。

悔しいからソースを公開しておく。

package App::SocialSKK::Plugin::ZipCode;

use strict;
use warnings;
use base qw( App::SocialSKK::Plugin );
use XML::Simple ();
use URI;
use Encode ();

sub get_candidates {
    my ($self, $text) = @_;
    return if !defined $text || $text !~ /^\d{7}$/;

    my $uri = URI->new( 'http://zip.cgis.biz/xml/zip.php' );
    $uri->query_form( zn => $text );
    my $res = $self->ua->get( $uri->as_string );
    if ($res->is_success) {
        eval {
            my $xml = XML::Simple::XMLin(
                $res->content, ValueAttr => [ qw(state_kana city_kana address_kana company_kana
                                                 state city address company) ]
            );
            my @candidates;
            for my $seq ( [ 4..7 ], [ 0..3 ] ) {
                my $val = join( '', map {
                    my $v = $xml->{ ADDRESS_value }->{ value }->[ $_ ];
                    $v ne 'none' ? $v : '';
                } @$seq );
                push @candidates, Encode::encode(
                    'euc-jp',
                    Encode::is_utf8( $val ) ? $val : Encode::decode( 'utf8', $val ),
                );
            }
            return @candidates;
        };
    }
}

1;

__END__

=head1 NAME

App::SocialSKK::Plugin::ZipCode - Retrieves Candidates from Zip Code API

=head1 SYNOPSIS

  # Add a line like below into your .socialskk:
  plugins:
    - name: ZipCode

=head1 DESCRIPTION

App::SocialSKK::Plugin::ZipCode performs retrieval of
candidates from Zip Code API

=head1 SEE ALSO

=over 4

=item * Zip Code API

http://zip.cgis.biz/

=back

=head1 AUTHOR

Yoshiki Kurihara E<lt>kurihara __at__ cpan.orgE<gt>

あ、本題を忘れそうになってしまった。
socialskk.plをログインしたら毎回起動するのはめんどうなのでlaunchdで起動するようにしといた。これはMac OS X 10.5.6でしか動作確認してませんのであしからず。

設定は簡単。$HOME/Library/LaunchAgents/socialskk.plist ってファイルを作って下記の内容にで保存したあとMacを再起動すると socialskk.pl が自動で起動しているはず。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>socialskk</string>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/local/bin/socialskk.pl</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>StandardErrorPath</key>
        <string>/dev/null</string>
        <key>StandardOutPath</key>
        <string>/dev/null</string>
</dict>
</plist>


まだXSのことをよくわかってないのですが、XSモジュール用のModule::Setupのflavorを作ってみました。

このflavorを使うには、記事下にあるコードをXSFlavor.pmって名前でファイルに保存して、

% module-setup --init --flavor-class=+XSFlavor xs

でflavorを展開したら、あとは以下のようにするだけでXSモジュールの雛形ができあがります。

% module-setup Your::Module xs

このflaverでできる雛形のXSには、newとincrementっていう関数が最初から追加されているので、いらない場合はてきとうに編集してください。


このflavorを最初はModule::Starterで作ろうと思ってたんだけど、module-starterコマンドではflavorの使い分ける機能がないんですね。自分でそういうコマンドラインのを作ればいいんだけど、もうその機能が備わってるModule::Setupに切り替えちゃいました。

Module::Setupのflavor機能は素晴しいすなぁ。

以下がFlavorになります。

package XSFlavor;
use strict;
use warnings;
use base 'Module::Setup::Flavor';
1;

=head1

XSFlavor - pack from xs

=head1 SYNOPSIS

  XSFlavor-setup --init --flavor-class=+XSFlavor new_flavor

=cut

__DATA__

---
file: .shipit
template: |
  steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN
  svk.tagpattern = release-%v
---
file: ____var-module_file-var____.xs
template: |
  #ifdef __cplusplus
  extern "C" {
  #endif
  #include "EXTERN.h"
  #include "perl.h"
  #include "XSUB.h"
  #include "ppport.h"
  #ifdef __cplusplus
  }
  #endif
  
  typedef SV * [% module.replace('::', '_')%];
  
  MODULE = [% module %]		PACKAGE = [% module %]		
  
  [% module.replace('::', '_') %]
  new(...)
      INIT:
      	char *classname;
  	/* get the class name if called as an object method */
  	if ( sv_isobject(ST(0)) ) {
  	    classname = HvNAME(SvSTASH(SvRV(ST(0))));
  	}
  	else {
  	    classname = (char *)SvPV_nolen(ST(0));
  	}
  
      CODE:
      	/* This is a standard hash-based object */
      	RETVAL = ([% module.replace('::', '_') %])newHV();
  
  	/* Single init value */
  	if ( items == 2 ) 
  	    hv_store((HV *)RETVAL, "value", 5, newSVsv(ST(1)), 0);
  	/* name/value pairs */
  	else if ( (items-1)%2 == 0 ) {
  	    int i;
  	    for ( i=1; i < items; i += 2 ) {
  		hv_store_ent((HV *)RETVAL, ST(i), newSVsv(ST(i+1)), 0);
  	    }
  	}
  	/* odd number of parameters */
  	else {
  	    Perl_croak(aTHX_
  		"Usage: [% module %]->new()\n"
  		"    or [% module %]->new(number)\n"
  		"    or [% module %]->new(key => value, ...)\n"
  	    );
  	}
  
      OUTPUT:
      	RETVAL
  
  IV
  increment(obj)
      [% module.replace('::', '_') %] obj
  
      INIT:
         RETVAL = 0;
         if ( items > 1 )
             Perl_croak(aTHX_ "Usage: [% module %]->increment()");
  
      CODE:
         SV **svp;
         if ((svp = hv_fetch((HV*)obj, "value", 5, FALSE))) {
             RETVAL = SvIV(*svp);
             RETVAL++;
             hv_store((HV *)obj, "value", 5, newSViv(RETVAL), 0);
         }
      OUTPUT:
         RETVAL
---
file: Changes
template: |
  Revision history for Perl extension [% module %]
  
  0.01    [% localtime %]
          - original version
---
file: Makefile.PL
template: |+
  use inc::Module::Install;
  
  name     '[% dist %]';
  all_from 'lib/[% module_path %].pm';
  
  # requires '';
  
  tests 't/*.t';
  author_tests 'xt';
  
  cc_inc_paths '.';
  can_cc or die 'This module requires a C compiler';
  
  build_requires 'Test::More';
  use_test_base;
  auto_include;
  WriteAll;
  
  sub MY::post_constants {
      return <<"POST_CONST";
  XSUBPPARGS += -typemap typemap
  POST_CONST
  }

---
file: MANIFEST.SKIP
template: |
  \bRCS\b
  \bCVS\b
  ^MANIFEST\.
  ^Makefile$
  ~$
  ^#
  \.old$
  ^blib/
  ^pm_to_blib
  ^MakeMaker-\d
  \.gz$
  \.cvsignore
  ^t/9\d_.*\.t
  ^t/perlcritic
  ^tools/
  \.svn/
  ^[^/]+\.yaml$
  ^[^/]+\.pl$
  ^\.shipit$
---
file: README
template: |
  This is Perl module [% module %].
  
  INSTALLATION
  
  [% module %] installation is straightforward. If your CPAN shell is set up,
  you should just be able to do
  
      % cpan [% module %]
  
  Download it, unpack it, then build it as per the usual:
  
      % perl Makefile.PL
      % make && make test
  
  Then install it:
  
      % make install
  
  DOCUMENTATION
  
  [% module %] documentation is available as in POD. So you can do:
  
      % perldoc [% module %]
  
  to read the documentation online with your favorite pager.
  
  [% config.author %]
---
file: typemap
template: |
  ###############################################################################
  ##
  ##    Typemap for [% module %] objects
  ##
  ##    Copyright (c) [% config.author %]
  ##    All rights reserved.
  ##
  ##    This typemap is designed specifically to make it easier to handle
  ##    Perl-style blessed objects in XS.  In particular, it takes care of
  ##    blessing the object into the correct class (even for derived classes).
  ##
  ##
  ###############################################################################
  ## vi:et:sw=4 ts=4
  
  TYPEMAP
  
  [% module.replace('::', '_') %] T_PTROBJ_SPECIAL
  
  INPUT
  T_PTROBJ_SPECIAL
      if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")) {
  	$var = SvRV($arg);
      }
      else
  	croak(\"$var is not of type ${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")
  
  OUTPUT
  T_PTROBJ_SPECIAL
      /* inherited new() */
      if ( strcmp(classname,\"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\") != 0 )
  	$arg = sv_bless(newRV_noinc($var),
  	    gv_stashpv(classname,TRUE));
      else
  	$arg = sv_bless(newRV_noinc($var),
  	    gv_stashpv(\"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\",TRUE));
---
file: lib/____var-module_path-var____.pm
template: |
  package [% module %];
  
  use strict;
  use warnings;
  #use base qw(Exporter);
  #our @EXPORT_OK = ();
  
  our $VERSION = '0.01';
  
  require XSLoader;
  XSLoader::load(__PACKAGE__, $VERSION);
  
  1;
  __END__
  
  =head1 NAME
  
  [% module %] -
  
  =head1 SYNOPSIS
  
    use [% module %];
  
  =head1 DESCRIPTION
  
  [% module %] is
  
  =head1 AUTHOR
  
  [% config.author %] E<lt>[% config.email %]E<gt>
  
  =head1 SEE ALSO
  
  =head1 LICENSE
  
  This library is free software; you can redistribute it and/or modify
  it under the same terms as Perl itself.
  
  =cut
---
file: t/00_compile.t
template: |
  use strict;
  use Test::More tests => 1;
  
  BEGIN { use_ok '[% module %]' }
---
file: xt/01_podspell.t
template: |
  use Test::More;
  eval q{ use Test::Spelling };
  plan skip_all => "Test::Spelling is not installed." if $@;
  add_stopwords(map { split /[\s\:\-]/ } <DATA>);
  $ENV{LANG} = 'C';
  all_pod_files_spelling_ok('lib');
  __DATA__
  [% config.author %]
  [% config.email %]
  [% module %]
---
file: xt/02_perlcritic.t
template: |
  use strict;
  use Test::More;
  eval {
      require Test::Perl::Critic;
      Test::Perl::Critic->import( -profile => 'xt/perlcriticrc');
  };
  plan skip_all => "Test::Perl::Critic is not installed." if $@;
  all_critic_ok('lib');
---
file: xt/03_pod.t
template: |
  use Test::More;
  eval "use Test::Pod 1.00";
  plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
  all_pod_files_ok();
---
file: xt/perlcriticrc
template: |
  [TestingAndDebugging::ProhibitNoStrict]
  allow=refs
---
plugin: plugin.pm
template: |
  package XSFlavor::Plugin;
  use strict;
  use warnings;
  use base 'Module::Setup::Plugin';
  use Devel::PPPort;
  use File::Spec;
  
  sub register {
      my $self = shift;
      $self->add_trigger( after_create_skeleton => \&create_ppport_process );
      $self->add_trigger( after_setup_template_vars => \&add_template_vars );
  }
  
  sub create_ppport_process {
      my $self = shift;
      $self->log( "Creating ppport.h" );
      Devel::PPPort::WriteFile(
          File::Spec->catfile( $self->distribute->dist_path, 'ppport.h' )
      );
  }
  
  sub add_template_vars {
      my ( $self, $template_vars ) = @_;
      my ( $module_file ) = $template_vars->{ module } =~ m#(?:.*::)?(.*)$#;
      $template_vars->{ module_file } = $module_file;
  }
  
  1;
---
config:
  plugins:
    - Config::Basic
    - Template
    - Test::Makefile
    - Additional
    - +XSFlavor::Plugin

検索

広告

OpenID対応しています OpenIDについて
Powered by Movable Type 4.22-ja