2012-01-09
■[Doma][Java] Doma 1.20.1
Doma 1.20.1 をリリースしました。今回はバグ修正のみのメンテナンスリリースです。
ダウンロードはこちらからどうぞ。
Mavenをご利用の方はこちらを参照ください。
以前のバージョンから移行するには移行ガイドを参照ください。
リリースノート
Bug
■[JavaScript][deku.js] deku.js - パイプライン処理に焦点をあてたJavaScriptのテンプレートライブラリ
以前、tempura.jsという名前で作っていたライブラリですが、新しくdeku.jsという名前で作り替えました。
deku.jsの最大の特徴は、タイトルにある通り、パイプライン処理です。データをテンプレートに書き付ける際にパイプラインの仕組みで任意のデータ変換を実現します。値のフォーマットやコンバートを宣言的に行い、ロジックとビューをきれいに分離しやすくすることを目的としています(この機能については、tempura.jsのときと本質的に同じです)。
READMEに例としてのせていますが、次のように重さをg(グラム)に変換して表示することをテンプレート上でわかりやすく記述できます。
{{ weight | g }}
大きく作り替えたのは、パフォーマンスに関してです。handlebars.jsやhogan.jsのようにテンプレートをJavaScriptのコードにコンパイルするようにし、handlebars.jsやhogan.jsに匹敵できるようなパフォーマンスを目指しました。(まだまだhandlebars.jsには及びませんが、もう少し追いつきたいと思っています。handlebars.jsが速すぎるんだよなあ)
-
http://jsperf.com/deku-vs-other-templating-engines - http://jsperf.com/deku-vs-other-templating-engines/2
(追記: handlebars.jsと同程度のパフォーマンスがでるようになりました!)
それから、これもhandlebars.jsやhogan.jsと同様に事前にテンプレートをコンパイルするためのツールを用意しました。オプションでAMD形式のjsを生成できるようにしたところが、他とはちがうちょっとした特徴かもしれません。ドキュメントが足りていないですが、npmで-gをつけてインストールするとdekuというスクリプトが使えるようになります。
npm install -g deku
こんな感じで使います。
deku -a ./deku -f hello.js hello.deku
さらに、これもhandlebars.jsやhogan.jsを参考にしたわけですが、事前コンパイルされたテンプレートしか使わない場合を想定し、コンパイルするためだけにしか使わないコードを除去した軽量版のjsファイルも提供するようにしました(minifyしたもので3.5kbくらい)。ダウンロードページに置いてあります(deku.runtime-0.0.5dev.min.js)。
ぜひ、お試しください。
ちなみに、名前を変えた理由ですが、tempuraとtemplateという変数が同時に登場する場合に字面があまりに似すぎていてどうしても混同してしまうからというしょーもない理由です。とほほ。
2011-12-19
■[JavaScript][tempura] ブラウザでもNode.jsでも動くテンプレートライブラリ
これは JavaScript Advent Calendar 2011 (Node.js/WebSocketsコース) の19日目の記事です。
JavaScriptで作られたテンプレートライブラリってたくさんありますよね。今日もこんなブログみかけました。
ここに挙がっているものだけでも聞いたことがないものが結構ありました。おそらく、世の中にはここに挙がっているもの以外にもまだまだたくさんあると思います。とにかく多いです。テンプレートのライブラリに限らない話かもしれないですけどね。
テンプレートライブラリに必要な機能って何?
テンプレートライブラリに必要な機能や特徴って何でしょう?条件分岐や繰り返しなど基本的なものは除外するとして、自分がテンプレートのライブラリに求めるものを3つ挙げてみます。
- HTMLのエンコードをデフォルトで行う
- ロジックの記述を認めない
- 数値や日付をフォーマットがしやすい
1. HTMLのエンコードはデフォルトで行う
ちょっとしたエンコード忘れでXSSが起きるのはさけたいですよね。デフォルトで安全がうれしい。
2. ロジックの記述を認めない
ここでのロジックとは、ifの条件とかforの条件を表すJavaScriptの式などのコード片を想定しています。テンプレートにロジックがでてくると、ごちゃごちゃして見通しが悪くなります。employees.length > 0 みたいな式はテンプレートに出さないのが自分の好みにあっています。
3. 数値や日付のフォーマットがしやすい
数値にカンマを入れたり、日付をスラッシュ区切りにしたりよくやりますよね。ただ、自分としては、毎回毎回 同じような記述(yyyy/MM/ddみたいの)を値ごとにテンプレートに書いたり、値ごとにフォーマット関数を用意したりするのは面倒です。アプリによりますが、日付のフォーマットっていったらアプリの中で2、3種類に定まると思うんですよね。だったら、できるだけ宣言的に記述したい。
1番目と2番目については、mustache.js がとても優れています。しかも、mustache.jsはシンプル、そこも魅力的です。ただ、3番目のフォーマットに関する機能がないんですよね。フォーマット済みの値を返す関数をデータとなるオブジェクトにつけてあげればいいのですが、それはちょっと面倒でわかりにくい気がします。
そ、こ、で、tempuraの登場
フォーマットの機能に主眼を置いて自分で作ってみることにしました。その名もtempura(てんぷら)。あれ、昨日のエントリとかぶっているような? 気にしないでー。
tempuraは、ブラウザでもNode.jsでも動くテンプレートライブラリです。mustache.jsをベースに自分があったらいいなと思う機能を追加し、自分にとって必要性がいまいちな機能はざっくり落としています。
インストール
npm install tempura
tempuraの特徴は、何と言ってもパイプ。シェルとかででてくるアレです。フォーマットに主眼を置いているといいながら、実はフォーマットの機能そのものは持っていません。フォーマットをしやすくするための仕組みを提供します。それがパイプです。
フォーマットについては、利用者にまかせています。アプリごとにどうフォーマットしたいか違うはずですし、アプリが使うライブラリによってフォーマット方法も異なるはずだからです。
では、例をみていきます。ここでは、日付のフォーマットを取り上げますが、momentというライブラリを使用します。
まずは、requireでmomentとtempuraを使えるようにします。
var moment = require('moment'); var tempura = require('tempura');
次は、パイプの関数を定義します。名前づけのルールはありませんが、識別しやすいようにここでは%を名前の先頭につけておきます。あ、1つルールがありました。| は予約語です。名前には使わないようにしてください。それから、ここでは、全てのテンプレートから参照できるようにtempuraオブジェクトに関数を登録していますが、テンプレートごとやデータごとに固有の関数を定義することもできます。
tempura.mergeSettings({ pipes: { '%date': function(value) { return value.format('YYYY/MM/DD'); }, '%diffUntilXmas': function(value) { var xmas = moment([value.year(), 11, 25]); return xmas.diff(value, 'days'); } } });
それから、テンプレートに流し込むオブジェクトを用意します。moment()で現在時刻がとれます。
var data = { today: moment(), weather: '晴れ' };
そして、次はテンプレートを用意します。{{ と }} を使ってデータを参照するのは mustache.js と同じなのですが、{{today|%date}} のようにプロパティの名前とパイプの関数の名前を | で連結しているところがtempura独自の機能になります。意味するところは、todayが参照する値を%date関数の引数として処理しその結果を返すよ、というものになります。パイプという名前が示すように関数は | で何個でも連結できます。
var tmpl = tempura.prepare([ '今日は{{today|%date}}、{{weather}}。', 'クリスマスまであと{{today|%diffUntilXmas}}日!' ].join('\n'));
最後は、テンプレートにデータを流し込んで結果を取得しコンソールに出力します。
var result = tmpl.render(data);
console.log(result);
出力はこうなります。
今日は2011/12/19、晴れ。 クリスマスまであと5日!
ということで、クリスマスまであと5日。待ち遠しいですね。
さてさて、Advent Calendar、次の方は? なんとか続くといいですね。
補足
上のコード片ですが、まとめるとこうなります。
var moment = require('moment'); var tempura = require('tempura'); tempura.mergeSettings({ pipes: { '%date': function(value) { return value.format('YYYY/MM/DD'); }, '%diffUntilXmas': function(value) { var xmas = moment([value.year(), 11, 25]); return xmas.diff(value, 'days'); } } }); var data = { today: moment(), weather: '晴れ' }; var tmpl = tempura.prepare([ '今日は{{today|%date}}、{{weather}}。', 'クリスマスまであと{{today|%diffUntilXmas}}日!' ].join('\n')); var result = tmpl.render(data); console.log(result);
2011-12-18
■[JavaScript][tempura] JavaScript用テンプレートライブラリ tempura
JavaScriptのテンプレートライブラリを作りました。その名もtempura(てんぷら)。はい、、語呂だけで選びました。
リポジトリ
Backbone.jsと組み合わせることを想定して作りましたが、特にほかのライブラリには依存していません。サーバーサイドでも動きます。値の参照は、mustache.jsのように{{name}}と書きます。シンタックスの大部分はmustache.jsを踏襲しています。
特徴はというと、値の変換やフォーマットの機能そのものは持っていないのですが、変換やフォーマットを組み込みやすい仕組みをもっています。サンプルコードをみるとわかりやすいです。
var data = { name: 'hoge', enclose: function(value) { return '[' + value + ']';} }; var result = tempura.prepare('Hi, {{ name | enclose }}!').render({name: 'hoge'}); console.log(result);
出力はこうなります。
Hi, [hoge]!
ポイントは {{ と }} で囲まれている | です。パイプですね。つまり、nameプロパティの値をenclose関数で処理し、その結果をテンプレートに書いて結果を返しているということをしています。パイプの関数は{{value|f1|f2|f3|…}}と何個でもかけます。
ここでの例は、単に括弧でくくっただけですが、実際にはフォーマットが得意なライブラリを使って日時や数値を処理するのがおすすめです。
ほかにもいくつか特徴あるのですが、ドキュメント(githubのREADME)を書いたのでそちらを参照ください。jsfiddleにいくつかサンプルをおいたので実際に動かしてみるのも簡単です。
それから、せっかくなのでnpmにも登録してみました。node.jsで動きます。
npm install -g tempura
でインストールし、
var tempura = require('tempura');
という感じで使えます。
2011-12-02
2011-11-22
■[Doma][Java] Doma 1.20.0 リリース
Daoフレームワーク Doma 1.20.0 をリリースしました。
ダウンロードはこちらからできます。
Mavenをご利用の方はこちらを参照ください。
以前のバージョンから移行するには移行ガイドを参照ください。
リリースノート
Improvement
■[Doma][Java] Doma 1.20.0 の機能改善について
今回のリリースは、バグ修正は1つもなく、すべて機能改善です。簡単に内容を紹介します。いずれも使い勝手が向上する修正になっていると思います。
aptで生成するメタクラスのコードの改善
エンティティのプロパティごとに2つの内部クラスを生成するコードになっていたのですが、コンパイルに時間がかかったりjarサイズが増大するといった問題点を指摘していただいたため(Domaのドメインクラスが嬉しかった話と欠点の話)、コードを改めました。具体的には、必要最低限リフレクションを活用するようにして、プロパティに対して内部クラスを生成するのをやめました。
この結果、問題点は解決されました。
エンティティのプロパティのフィールドにprivate指定可能に
これまで、非privateしか認めていなかったのですが、privateにできるようになりました。上述のメタクラスのコードの改善で、Fieldのアクセスにリフレクションを使うようにしたため、その副産物のようなものです。
こう書けるようになりました。
@Entity(naming = NamingType.SNAKE_UPPER_CASE) public class Employee { @Id private Integer employeeId; private Integer employeeNo; ... }
@AnnotateWithを柔軟に利用可能に
主にEJB 3.1で使いやすくするためのものです。