DBIx::Handler と mysql_enable_utf8 と utf8mb42013年06月10日 21時52分

Perl で MySQL サーバーに接続するとき、DBIx::Handler を使っています。

my $handler = DBIx::Handler->new(
    $dsn, $username, $password,
    {
        RaiseError        => 1,
        RootClass         => 'My::DBI',
        mysql_enable_utf8 => 1,
    },
);

しかし、これだと "𠮷" (U+20BB7、いわゆる「つちよし」) など BMP 外の文字を保存しようとしたとき、テーブルの文字コードが utf8mb4 であっても "????" (疑問符 4 文字) に化けてしまいます。

ググったところ、mysql_enable_utf8 => 1 を指定した時点で DBD::mysql が接続時の文字コードを utf8 にしてしまうのが問題だそうです。(cf. おそらくはそれさえも平凡な日々: DBD::mysqlでmysql_enable_utf8しつつutf8mb4使いたいとき)

接続時に文字コードを utf8mb4 に指定しなおせばいいとのことですが、DBIx::Handler ではどうするのだろうとソースコードを眺めていたところ、new メソッドの第 5 引数の存在を知りました。

my $handler = DBIx::Handler->new(
    $dsn, $username, $password,
    {
        RaiseError        => 1,
        RootClass         => 'My::DBI',
        mysql_enable_utf8 => 1,
    },
    {
        on_connect_do     => ['SET NAMES utf8mb4'],
    },
);

これで BMP 外の文字も文字化けせず保存・取得できるようになったのですが、この第 5 引数は (DBIx::Handler 0.07 時点では) 文書化されていないので、使っていいものか心配です。

Callbacks を使っても期待通り動作するようなので、そちらのほうがよかったりするのでしょうか。

my $handler = DBIx::Handler->new(
    $dsn, $username, $password,
    {
        RaiseError        => 1,
        RootClass         => 'My::DBI',
        mysql_enable_utf8 => 1,
        Callbacks         => {
            connected => sub {
                $_[0]->do('SET NAMES utf8mb4');
                return;
            },
        },
    },
);

(SET NAMES をつかってはいけないという話もありますが、追いきれていません。)

追悼 E4X (仮) 発表資料2013年05月27日 21時49分

Firefox 21 で E4X のサポートが削除されたのを受け、「追悼 E4X (仮)」というイベントが開催されました。東京での開催だったのですが、私自身仕様の邦訳を手がけるなど E4X には並々ならぬ想いがあり、京都から駆けつけた次第です。

来たからにはと私も「E4X と autovivification」という題で LT をしてきました。Perl でいうところの autovivification という機能が E4X にも備わっているという話です。ほかに「私と E4X」という発表 (むしろ自分語り) もしたのですが、こちらはその場限りのオフレコです。

追悼というだけあって皆さん E4X に対する熱い思いを語っていましたが、特に感心したのが Vimperator の対応の話です。それまで E4X を使っていた部分を、ECMAScript 6 での採用が検討されているテンプレートリテラルに置き換えたものの、それ自体現在の SpiderMonkey では実装されていません。そこで、chrome://liberator/....js と JavaScript ファイルを読み込んでいたのを、liberator://....js と独自プロトコルを介した読み込みに変更し、そのプロトコルハンドラの中でソースコード変換を行っているとのことでした。

私も製品のコード中で E4X を使っており、結果として後進に負の遺産を残すこととなってしまったのですが、一方で E4X があったから今の私があるというのもひとつの真実であり、E4X 仕様及びそれを実装した Mozilla に深く感謝します。

jQuery のバグを見つけてから修正されるまで2013年01月28日 02時17分

1 月 24 日に開催された Kyoto.js meetup 4 で「jQuery のバグを見つけてから修正されるまで」と題した発表を行いました。

jQuery へのコミットに関して 2 行でまとめるとすれば次のようになるでしょうか。

  1. jQuery のソースコードはショートコーディングの嵐なので心してかかる
  2. Contributing to jQueryjQuery Core Style Guidelines は必読

発表の筋書きは以下の通りです。


jQuery のバグを見つけてから修正されるまで


フォロー・ミー

  • nanto_vi (TOYAMA Nao)
  • 株式会社はてな アプリケーションエンジニア
    • クライアントサイド (JavaScript)
    • サーバーサイド (Perl)
  • jQuery をバリバリ使っている
    • Deferred
    • イベント
    • DOM 操作

ある日どこかで

街中にクリスマスの装飾が灯り始めるころ

うんうん、変わったよね

……


そういえば Deferred を使ったとき this の値はどうなるんだったっけ?

$.Deferred().done(function () {
    this // ← ココとか
}).then().done(function () {
    this // ← ココの値は?
});

jQuery 1.8.3 と jQuery 1.9 Beta 1 で結果が違う!

汚れなき悪戯

ふむふむ…… (コードを読む)

ふむふむ…… (コードを読む)

ふむふむ…… あれ?


これ、自分の書いたコードが動かなくなる?

$.Deferred().then(function () {
    // ここでの this が
    return $.Deferred().resolveWith(this, arguments);
}).done(function () {
    // ここにも引き継がれてほしい
    this
});

……


まずい!

バック・トゥ・ザ・フューチャー

どこを直せば自分のコードが動くのか

コードとにらめっこ

にらめっこ

にらめっこ

……


問題なのはここ、でもここを変えると先の変更の意味が失われるから……


こことここか!

羊たちの沈黙

直すならテストを書かないと

テストを書くならテストを走らせないと

テストを走らせるなら jQuery のビルド環境を作らないと

grunt? Node.js なら入ってるし楽勝でしょ

……


うわあ、この Node.js バージョンが古い!

うわあ、この OS バージョンが古い!

うわあ、この Python (ry

……


沈黙


そしてクリスマスが過ぎ、正月が過ぎた

風と共に去りぬ

やっぱり正月松の内は休まないとね

ってなになに……


げげー、1.9-stable ブランチ!


もはや一刻の猶予も許されない

禁じられた遊び

ビルド環境がないならテスト環境を作ればいいじゃない

俺にはこの SpiderMonkey JavaScript Shell がある!


秘技、テストのコピペ改変!

荒野の用心棒

nanto_vi 「これ直さへんとあかんちゃう?」

J 「プルリクエストにしてーな」

nanto_viプルレクったでー

D 「ここ冗長やろ。もっと削れるやろ

nanto_vi (そない言われても…… これ以上どう切り詰めろいうんや……)

nanto_vi (しゃあないな、この条件分岐をもっと前に持ってきて……)

nanto_vi (あれ、この変数、フラグに流用できるちゃうか……)

nanto_viどや!

D 「まあええんちゃうか」

素晴らしき哉、人生!

D 「修正取り込んだで。おーきに」

J 「僕と契約して貢献者になってよ!


めでたしめでたし


※ この物語は実話を基にしたフィクションです。

jQuery で HTTP 接続するときの書き方2012年12月16日 19時41分

12 月 13 日に Kyoto.js の第 3 回 meetup で、「jQuery で HTTP 接続するときの書き方」と題した 5 分間のライトニングトークを行いました。以下にその内容を一部再構成して収録します。


こんにちは、nanto_vi です。今日は jQuery で HTTP 接続をするときの書き方について話します。

皆さん jQuery を使うことも多いかと思います。jQuery で HTTP 接続をするとき、古いサンプルだと次のような書き方が載っています。

$.ajax({
    url: '/foo/bar',
    data: { baz: 'qux' },
    success: function (data) {
        console.log(data);
    },
});

接続完了時の処理をコールバック関数として $.ajax() に渡してやる形ですね。しかし、現在この書き方は非推奨となっており、替わりに次のように書きます。

$.ajax({
    url: '/foo/bar',
    data: { baz: 'qux' },
}).done(function (data) {
    console.log(data);
});

$.ajax() の返り値に対して、done メソッドで接続完了後の処理を登録する形です。この書き方の何がいいかといえば、返り値を使いまわしたり done メソッドを複数回呼び出したりして、完了後の処理を後から追加できるところです。昔の書き方では完了後の処理がコールバック関数として $.ajax() の内部に格納されていましたが、現在は「完了後の処理」だけを $.ajax() の外部に (「プロミス」として) 取り出すことが可能になったわけですね。

今「内部の処理を外部に取り出す」と言いましたが、この言葉はどこかで聞き覚えがありませんか。そう、内部イテレータと外部イテレータです。

内部イテレータは、オブジェクトが個々の要素に対する処理を受け取り、オブジェクト内部で自身の各要素に適用させる形、

// 内部イテレータの使用例
$('p').each(function () {
    doSomethingWith(this);
});

外部イテレータは、オブジェクトから「各要素を列挙する」という機能だけをオブジェクト外部に取り出す形です。

// 外部イテレータの実装例と使用例
$.fn.iterator = function () {
    var i = 0, n = this.length, self = this;
    return {
        hasNext: function () { return i < n; },
        next: function () { return self[i++]; }
    };
};

var iterator = $('p').iterator();
while (iterator.hasNext()) {
    var element = iterator.next();
    doSomethingWith(element);
}

JavaScript 1.7 以降ではジェネレータという機能により、内部イテレータのような書き方で外部イテレータを生成することができます。

さて、「処理を内部に持ってしまっている」というのは、イベントハンドラの登録も同じですね。

$(document).on('click', function (event) {
    ...
});

イベント発生時の処理をコールバック関数として jQuery オブジェクト内部に渡していますが、これを外部に持ち出すことはできないのでしょうか。

実はそれを可能にするものとして Reactive Extensions (Rx) があります。Rx 入門記事の図にもあるように、Rx を使うと空間にまたがる要素 (配列など) の列挙と時間にまたがる要素 (イベントなど) の列挙を統一的に扱うことができます。

Reactive Extensions は主に .NET Framework 上で利用されていますが、JavaScript での実装として RxJS が公開されています。

ObserverパターンとIteratorパターンは同じだったんだよ!なんだってー!

neue cc - .NET Reactive Framework メソッド探訪第一回:FromEvent

そう、ObserverパターンとIteratorパターンは同じなのだよ、ナンダッテー!

neue cc - Reactive Extensions for JavaScript

(このあたりで時間切れ)

はてなでコードを書くときに気をつけていること2011年12月18日 14時37分

こんにちは、はてなでアプリケーションエンジニアをしている nanto_vi です。この記事は Hatena::Staff Advent Calendar 2011 の一環として書いています。Advent Calendar の会場ははてなブログとなっていますが、主催の antipop さんに尋ねたところ何でもよいというような返答があったのでここで書きます。

はじめに謝っておきますが、この記事ははてなとほとんど関係がありません。タイトルに「はてな」と入っているのは Advent Calendar の要件を満たすための目くらましあり、内容はといえばはてなのノウハウでもなんでもない、私が最近個人的に心がけていることです。ごめんなさい。

できれば明示的に

業務で書くコードは複数人により読み書きされメンテナンスされるので、わかりやすさが重要になってきます。わかりやすさを保つためには暗黙的に行われる操作を減らし、明示的にコードに表した方がよいと感じます。たとえば、Perl では、

use Encode;

# encode_utf8 関数は Encode モジュールで定義されている
my $octets = encode_utf8 $string;

のようにモジュール読み込み時に自動的に関数をインポートすることができますが、それよりも、

use Encode qw/encode_utf8/;

my $octets = encode_utf8 $string;

のようにインポートする関数を明示的に指定したほうが、その関数がどこで定義されているのかわかりやすいでしょう。

個人的には、関数や変数の名前で grep をかけてその定義(外部で定義されている場合は宣言)を探し出せることが、「明示的」であるための最低線ではないかと思います。

入力には正規化を、出力には符号化を

アプリケーションを作るうえで入出力の扱いは避けて通れません。入力元はユーザーだったりバッチ処理スクリプトの引数だったり、出力先はユーザーだったりデータベースサーバーだったりしますが、いずれにおいても入力には正規化処理を、出力には符号化処理を、それぞれ施すことになります。

正規化は一般に不可逆です。空白文字類をすべてスペースに置換した後はもともとスペース以外の空白文字が含まれていたのかわかりませんし、数値「42」を生み出した入力は "42" でも "42.0" でも、はたまた "0x2A" でもありえます。

符号化は一般に可逆です。あるデータをユーザーのもとへ送り届けるのに、そのデータを HTML のテキストとして扱えるよう一部文字を文字参照の形に符号化し、その HTML ソース全体を文字符号化方式 UTF-8 をもって符号化し、さらには HTTP メッセージに、TCP のセッションに、IP のパケットにと符号化を重ねていきますが、それらすべては符号化規則を逆に適用することで元の形式へ復元できます。

たとえば HTML として解析され、その結果が JavaScript の文字列として、HTML として、URI としてと順に解析されるデータを Template-Toolkit で出力する場合、解析の逆順でそれぞの形式に応じた符号化を施す必要があります。

<script type="text/javascript">
document.write('<a href="/search?q=[% word | uri | html | js %]">検索<\/a>');
</script>

script 要素の内容は CDATA 型であり文字参照は解決されないので、最後に html フィルタをかけることはしません。また、そもそもこのような多重にフィルタをかける事態は避けたほうが賢明でしょう。

入出力いずれにおいても、データがどういう形式で扱われるのかを意識し、それに応じた正規化処理または符号化処理を施すことで、意図しない入力が致命的な挙動を引き起こすこともある程度は防げるのではないかと考えます。

次は hitode909 さんです。