Machine Specification(MSpec)はBDDスタイルのテストフレームワークで、BDDスタイルの開発をするなら至極便利。そのMSpecもReSharperと組み合わせてVisual Studio 2010上で簡易にテスト実行できるようにしておかないとありがたみが失せるので設定方法を紹介しておく。
MSpecのReSharperに対する設定が完了すると、下図のようにVSのテストファイルの左側にポケモンボールのようなアイコンがテスト毎に表示されるようになるし、メニューからReSharper -> Unit Tests -> Run Unit Testsでテストを実行できるようにもなる。
実はNuGetからもMSpecの取得は可能なのでそちらから取得してもかまわない。今回はGitHubから取得したmachine/machine.specificationsを使用する。適当にcloneするなりzipファイルをダウンロードして展開してもらいたい。フォルダが展開できたら直下にあるbuild.cmd(Releaseビルドしたい場合はbuild-release.cmd)を実行しよう。実行するとDOS窓が起動し、うにょうにょとビルドが始まり、テストが実行され、しばらくすると完了する。するとBuildフォルダができているので、そこからDebugかReleaseを自分の好みにあわせて選択してもらいたい。使用するだけならばReleaseでよいだろう。
で、そのDebugかReleaseフォルダ内にあるInstallReshaperRunner%%.batを実行する。%%の部分は自分のReShaperのVersionに置き換えてもらいたい。実行すると下記フォルダにMachine.Specifications.dll、Machine.Specifications.ReSharperRunner.6.0.dllとそれぞれpdbファイルがコピーされる。ここではv6.0のbatファイルを叩いたとする。
%appdata%\JetBrains\ReSharper\v6.0\vs10.0\Plugins
NuGetから取得した場合は前述の2つのDLLを上記のパスに自分でコピーすればよい。コピーする際にフォルダが無い場合は自分で作ろう。
コピーできたらVSを再起動しよう。再起動後は上図のポケモンボールがテストファイルの左側に表示されているはずだ。
一点注意が必要なのが、JetBrains配下にコピーしたMachine.Spedifications.DLLとVSで参照しているMachine.Spedifications.DLLのバージョンなどが違うとどうやらReSharperのほうでMSpecのプラグインを認識してくれないようなので同じファイルを使用するようにしよう。新しい環境を構築する際にMSpecをNuGetで取得したり、JetBrainsのほうへは古いファイルをコピーしたりなどを行ってしまいMSpecのテストが中々認識されなくて苦労したことがあるので注意してもらいたい。
2012年11月24日土曜日
2012年9月12日水曜日
Cross-Origin Resource Sharing(CORS)で外部ドメインからリソースを取得する
今回はCross-Origin Resource Sharing(CORS)で外部ドメインからリソースを取得するお話。実際にどんな用途があるかというとGoogle Analyticsなんかで埋め込むスクリプトは埋め込む先のページのドメイン(仮にwww.matsuo-software.comとする)から違うドメイン(GAではwww.google-analytics.com)へ情報を飛ばしたりする(注1)のでそういう場合に必要となる。
注1:GAのコードを調べたわけではないので実際には不明です。
ではなぜJavascriptから外部ドメインへのアクセスにCORSが必要かというと、ブラウザにはセキュリティのためにSame Origin Policyというのが適用されている。そのPolicyは外部ドメインからのリソースに訳の分からんことをされて悪意のあるデータをPOSTされたりするのを未然に防ぐためにある。で、その防止策の一環で外部ドメインへ向けてのJavascriptを使った単純なAjaxリクエストを行ってもブラウザレベルでアクセスを拒否されてしまうので、その制限をかいくぐるのにCORSの設定が必要となるわけだ。
サンプル
例によってサンプルはNode.js。https://github.com/yooontheearth/cors-sampleからコードは取得してもらいたい。アプリの設定まわりはBackbone.jsでクライントスクリプトをガリガリ組むためのお手軽チュートリアルを参照してもらいたい。
CORSでGETをするのは特に何の問題もなくできるはずなので、今回は少しひっかかるところのあるPOSTを解説している。
解説
今回のサンプルはいたってシンプル。見るべきところは13行目のretrieveNameと25行目のapp.post '/mrnobody'の部分のみ。
これだけでサーバサイドのCORSの設定は完了だ。後はクライアントから通常のAjaxリクエストと同じように処理を行えば正常動作するはずだ。リクエスト時にエラーが出る場合はjQuery.support.cors = true;やcrossDomain:trueの設定をサンプルのcorssample.htmlを参考に同様に処理してもらいたい。
ただこのままで動くのはFirefoxやChromeだけのモダンなブラウザのみ。
INTERNET EXPLORER
Yes, IE! そう、IE。Web開発者の鬼門、IE。CORSでも堂々のお邪魔虫っぷりを十二分に発揮してくれる。本当にいつもいつも鬱陶しいことこの上ない。
IE10未満はXmlHttpRequestでのCORSを許可しておらず、CORSのためにはそれようのオブジェクトを使用する必要がある。XDomainRequestがそれにあたる。それなのでIEの場合はXDomainRequestを使用するようにしなければならない。
というわけで下記ライブラリでXDomainRequestを使ったAjaxリクエストをさくっと行う。
Malvolio / ie.xhr
呼び出しはこんな形になる。
で、これで終わりかと思いきやさすがはIE。さらに鬼門が用意してあってデータをポストしてるのにContet-typeをtext/plainとしてリクエストする。そのため通常ならばapplication/x-www-urlencodedでリクエストされた場合はポスト内容の解析を行ってくれるサーバサイドフレームワークがtext/plainなため内容解析を行わず、前述のreq.body.nameがNullになるというような事態を惹起するのである。そこでretrieveNameで行っているようなリクエストから生のポストデータを取得してkey=valueのペアになっている値を独自に解析する必要があるというわけである。
ここまでやって、やっとIEでもCORSができるようになった。IEでのCORSの詳しい制限事項はXDomainRequest - Restrictions, Limitations and Workaroundsを参照してもらいたい。
注1:GAのコードを調べたわけではないので実際には不明です。
ではなぜJavascriptから外部ドメインへのアクセスにCORSが必要かというと、ブラウザにはセキュリティのためにSame Origin Policyというのが適用されている。そのPolicyは外部ドメインからのリソースに訳の分からんことをされて悪意のあるデータをPOSTされたりするのを未然に防ぐためにある。で、その防止策の一環で外部ドメインへ向けてのJavascriptを使った単純なAjaxリクエストを行ってもブラウザレベルでアクセスを拒否されてしまうので、その制限をかいくぐるのにCORSの設定が必要となるわけだ。
サンプル
例によってサンプルはNode.js。https://github.com/yooontheearth/cors-sampleからコードは取得してもらいたい。アプリの設定まわりはBackbone.jsでクライントスクリプトをガリガリ組むためのお手軽チュートリアルを参照してもらいたい。
NODE_PATH=/usr/local/lib/node_modules coffee app
でNode.jsを起動してからcorssample.htmlをブラウザで開き「Hi Mr. Yoo!」と表示されれば正常に動作している。CORSでGETをするのは特に何の問題もなくできるはずなので、今回は少しひっかかるところのあるPOSTを解説している。
解説
今回のサンプルはいたってシンプル。見るべきところは13行目のretrieveNameと25行目のapp.post '/mrnobody'の部分のみ。
express = require 'express' qs = require 'querystring' app = express.createServer() app.configure -> app.use express.logger('tiny') app.use express.bodyParser() app.use express.methodOverride() app.use app.router app.use express.static(__dirname + '/') app.use express.errorHandler({ dumpExceptions: true, showStack: true }) retrieveName = (req, callback) -> name = req.body.name if name? callback name else data = "" req.on "data", (chunk)-> data += chunk req.on "end", -> parsedData = qs.parse data name = parsedData.name callback name app.post '/mrnobody', (req, res) -> retrieveName req, (name) -> res.header "Access-Control-Allow-Origin", '*' res.header "Access-Control-Max-Age", '86400' # 1 day res.header 'Access-Control-Allow-Methods', 'POST,OPTIONS' res.header "Access-Control-Allow-Headers", "X-Requested-With" res.send "Hi Mr. #{name}!" app.listen 3000 console.log "Express server listening on port #{app.address().port} in #{app.settings.env} mode"retrieveNameはそのままPOSTされたデータ(名前)を取得している。req.body.nameがNullだったら、という処理の理由は後述する。/mrnobodyのリクエストハンドラでCORSに必要なヘッダー情報を設定している。ブラウザはここで設定しているレスポンスのヘッダー情報をもとにCORSが許可されているかの判断を行う。Access-Control-Allow-Originに*を指定するとすべてのドメインからのアクセスを許可することになる。特定のドメインのみ許可したい場合は「http://www.matsuo-software.com」などを指定すればよい。またAccess-Control-Allow-Methods、Access-Control-Allow-Headersでそれぞれ許可するHTTPメソッド、ヘッダーを指定している。許可された以外のアクセスが行われた場合はアクセス拒否されるという寸法だ。それらの許可内容をAccess-Control-Max-Ageで指定した秒数だけブラウザの方でキャッシュされる。
これだけでサーバサイドのCORSの設定は完了だ。後はクライアントから通常のAjaxリクエストと同じように処理を行えば正常動作するはずだ。リクエスト時にエラーが出る場合はjQuery.support.cors = true;やcrossDomain:trueの設定をサンプルのcorssample.htmlを参考に同様に処理してもらいたい。
ただこのままで動くのはFirefoxやChromeだけのモダンなブラウザのみ。
INTERNET EXPLORER
Yes, IE! そう、IE。Web開発者の鬼門、IE。CORSでも堂々のお邪魔虫っぷりを十二分に発揮してくれる。本当にいつもいつも鬱陶しいことこの上ない。
IE10未満はXmlHttpRequestでのCORSを許可しておらず、CORSのためにはそれようのオブジェクトを使用する必要がある。XDomainRequestがそれにあたる。それなのでIEの場合はXDomainRequestを使用するようにしなければならない。
というわけで下記ライブラリでXDomainRequestを使ったAjaxリクエストをさくっと行う。
Malvolio / ie.xhr
呼び出しはこんな形になる。
$.ajax('http://localhost:3000/mrnobody', { data: { name: 'Yoo' }, type: 'post', xhr: window.IEXMLHttpRequest || jQuery.ajaxSettings.xhr, crossDomain: true, success: function (data, textStatus, jqXHR) { $result.text(data); }, error: function (jqXHR, textStatus, errorThrown) { $result.text('Failed to load data.' + errorThrown); } });
で、これで終わりかと思いきやさすがはIE。さらに鬼門が用意してあってデータをポストしてるのにContet-typeをtext/plainとしてリクエストする。そのため通常ならばapplication/x-www-urlencodedでリクエストされた場合はポスト内容の解析を行ってくれるサーバサイドフレームワークがtext/plainなため内容解析を行わず、前述のreq.body.nameがNullになるというような事態を惹起するのである。そこでretrieveNameで行っているようなリクエストから生のポストデータを取得してkey=valueのペアになっている値を独自に解析する必要があるというわけである。
ここまでやって、やっとIEでもCORSができるようになった。IEでのCORSの詳しい制限事項はXDomainRequest - Restrictions, Limitations and Workaroundsを参照してもらいたい。
2012年8月31日金曜日
ASP.NET MVCのキャッシュについてあれこれ
一年半前ぐらいにASP.NET MVC 3のキャッシュ周りについて調べまくったので今更ながらまとめておく。一年以上前の話なのであやふやな部分も少々あるけれどそこはご愛嬌ということで話半分に読んで欲しい。
で、キャッシュについて。キャッシュを有効活用できれば一番手っ取り早くサーバのスループットをあげることができるわけで、もちろんASP.NET MVC 3にもキャッシュ機能はある。
OutputCacheAttribute
OutputCacheAttributeがそれにあたる。この属性をControllerかActionに付与することによってそれらの出力結果をキャッシュしてくれる。使用方法は下記のような感じ。
で、この属性を使う上で一つ注意が必要なのが、さきほども強調表示してあるけれどこの属性は出力結果をキャッシュするようになっている。つまりこの属性を使用するとControllerのアクションは当たり前だけどViewのレンダリングもスキップされることになる。
で、それの何が問題なの?ってのは次の場合。
ドーナツキャッシュ
ログインユーザに「ようこそYooさん」のようなメッセージを表示する会員制のサイトがあったとする。そういう場合にOutputCacheだとディモールト(非常に)都合がよろしくない。というのもOutputCacheは出力結果をキャッシュするので、Yooさんの内容がキャッシュされた状態でSasukeさん(うちの猫)がそのページにアクセスすると「ようこそYooさん」と表示されてしまうのである。じゃぁそういう場合はどうするの?ってのでドーナツキャッシュという手法がある。下図のようにある一箇所だけを除外してキャッシュするのでドーナツキャッシュと呼ばれる。
その除外された箇所の描画用コールバックを用意しておくとそれが後から呼ばれるという寸法だ。で、詳細は下記を参照して欲しい。
Donut Caching in ASP.NET MVC
うん、冒頭のUPDATEを読んでびっくりだと思うけどこの機能はASP.NET MVC 3には組み込まれてない。キャッシュについて調べてたときも上記のサイトの説明を飛ばしてソースコードから入ったので、実装したら動かなくてちゃんと読み直したらびっくりしたね。F***って思ったよ。
で、困ったなーということで自前のキャッシュフィルターを作ることにした。
ResultCache
要するに出力結果をキャッシュされちゃうと柔軟性に欠けるというわけで、それならControllerのアクションの結果(ActionResult)だけをキャッシュして、そのキャッシュしといたActionResultをViewに渡して描画するようにすれば大体の問題は解決できるので下記のようなアクションフィルターを作ろうと思ったら既に作っている人(ASP.NET MVC Result Cache)がいたのでそれを拝借した。
というわけで、サーバリソース節約のためにもキャッシュはガンガン使っていくべきなので機会があれば快適なWebを実現するためにもドシドシ有効にしていただきたい。ただ一点注意が必要なのはなんでもかんでもキャッシュしていると予期せぬ出力結果になることがままあるのでキャッシュが有効になっている箇所の周りを開発する場合はその箇所だけをテストするのではなく、複数人からのリクエストを想定したテストなどを行わないと本番環境にリリースしてから痛い目にあうことがあるのでくれぐれも注意して欲しい。かく言う私もチヌかかり釣りMEGAのスマホ版をリリースしたさいに、ControllerのアクションでPC版とスマホ版のViewを動的に切り替えていたのでActionResultがキャッシュされてしまい予期せぬ動作になりとても焦った。ただその問題は前述のアクションフィルターにスマホ用のキャッシュキーを追加することによってサクッと事なきを得たので良かったけれども。
で、キャッシュについて。キャッシュを有効活用できれば一番手っ取り早くサーバのスループットをあげることができるわけで、もちろんASP.NET MVC 3にもキャッシュ機能はある。
OutputCacheAttribute
OutputCacheAttributeがそれにあたる。この属性をControllerかActionに付与することによってそれらの出力結果をキャッシュしてくれる。使用方法は下記のような感じ。
[OutputCache( Duration = 5, VaryByParam = "fish;angler", VaryByHeader = "X-Requested-With" )] public class ChinuController : Controller{ }Durationで何秒間キャッシュするのかを指定。VaryByParamやVaryByHeaderの指定でQueryStringのパラメータとかヘッダーごとにキャッシュを分けることが可能となっている。その他にもいくつか設定できる項目があるみたいだけれど使ったことがないのでよく分からない。
で、この属性を使う上で一つ注意が必要なのが、さきほども強調表示してあるけれどこの属性は出力結果をキャッシュするようになっている。つまりこの属性を使用するとControllerのアクションは当たり前だけどViewのレンダリングもスキップされることになる。
で、それの何が問題なの?ってのは次の場合。
ドーナツキャッシュ
ログインユーザに「ようこそYooさん」のようなメッセージを表示する会員制のサイトがあったとする。そういう場合にOutputCacheだとディモールト(非常に)都合がよろしくない。というのもOutputCacheは出力結果をキャッシュするので、Yooさんの内容がキャッシュされた状態でSasukeさん(うちの猫)がそのページにアクセスすると「ようこそYooさん」と表示されてしまうのである。じゃぁそういう場合はどうするの?ってのでドーナツキャッシュという手法がある。下図のようにある一箇所だけを除外してキャッシュするのでドーナツキャッシュと呼ばれる。
その除外された箇所の描画用コールバックを用意しておくとそれが後から呼ばれるという寸法だ。で、詳細は下記を参照して欲しい。
Donut Caching in ASP.NET MVC
うん、冒頭のUPDATEを読んでびっくりだと思うけどこの機能はASP.NET MVC 3には組み込まれてない。キャッシュについて調べてたときも上記のサイトの説明を飛ばしてソースコードから入ったので、実装したら動かなくてちゃんと読み直したらびっくりしたね。F***って思ったよ。
で、困ったなーということで自前のキャッシュフィルターを作ることにした。
ResultCache
要するに出力結果をキャッシュされちゃうと柔軟性に欠けるというわけで、それならControllerのアクションの結果(ActionResult)だけをキャッシュして、そのキャッシュしといたActionResultをViewに渡して描画するようにすれば大体の問題は解決できるので下記のようなアクションフィルターを作ろうと思ったら既に作っている人(ASP.NET MVC Result Cache)がいたのでそれを拝借した。
public class ResultCacheAttribute : ActionFilterAttribute { public ResultCacheAttribute() { Duration = 1200; // 20 mins } public string CacheKey{ get; private set; } public CacheDependency Dependency { get; set; } private CacheItemPriority _priority = CacheItemPriority.Default; public CacheItemPriority Priority { get { return _priority; } set { _priority = value; } } public int Duration{ get; set; } public override void OnActionExecuting(ActionExecutingContext filterContext) { var url = filterContext.HttpContext.Request.Url.PathAndQuery; this.CacheKey = "ResultCache-" + url; if (filterContext.HttpContext.Cache[this.CacheKey] != null) { filterContext.Result = (ActionResult)filterContext.HttpContext.Cache[this.CacheKey]; } base.OnActionExecuting(filterContext); } public override void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.Controller.ViewData["CachedStamp"] = DateTime.Now; filterContext.HttpContext.Cache.Add(this.CacheKey, filterContext.Result, Dependency, DateTime.Now.AddSeconds(Duration), System.Web.Caching.Cache.NoSlidingExpiration, Priority, null); base.OnActionExecuted(filterContext); } }リクエストされたURLをキャッシュのキーにしてActionResultを保持しておき、再度同じURLがリクエストされた場合はキャッシュからActionResultを取得してfilterContextのResultに渡すというだけの至極シンプルなフィルター。OnActionExecutingを見て不思議に思うかもしれないけれど、実はfilterContextのResultにActionResultが設定されるとControllerのアクションは呼び出されないのだ。
というわけで、サーバリソース節約のためにもキャッシュはガンガン使っていくべきなので機会があれば快適なWebを実現するためにもドシドシ有効にしていただきたい。ただ一点注意が必要なのはなんでもかんでもキャッシュしていると予期せぬ出力結果になることがままあるのでキャッシュが有効になっている箇所の周りを開発する場合はその箇所だけをテストするのではなく、複数人からのリクエストを想定したテストなどを行わないと本番環境にリリースしてから痛い目にあうことがあるのでくれぐれも注意して欲しい。かく言う私もチヌかかり釣りMEGAのスマホ版をリリースしたさいに、ControllerのアクションでPC版とスマホ版のViewを動的に切り替えていたのでActionResultがキャッシュされてしまい予期せぬ動作になりとても焦った。ただその問題は前述のアクションフィルターにスマホ用のキャッシュキーを追加することによってサクッと事なきを得たので良かったけれども。
2012年8月10日金曜日
Backbone.jsでクライントスクリプトをガリガリ組むためのお手軽チュートリアル
JavascriptでAjaxyなヌルヌル動くUIを作成すると
というわけで、そんな状況を打破するためのクライアントフレームワークがここ2~3年で大変充実してきていて、今回解説するBackbone.js、もちっとお手軽らしいEmber.js、もっともっとシンプルなKnockout.jsなどなど、どれから手にとって良いやら迷うこと必至なほど盛況だ。で、とりあえず選考の一助になればと簡単なサンプルアプリケーションを作成してみた。
今回のアプリケーションの外観は下図。ソースコードはhttps://github.com/yooontheearth/backbone-tutorialから取得可能になっている。
ご覧の通りよくある一般的な尼子十勇士系のアプリケーションだ。左側のリストを選択するとその詳細が右側に表示され、追加、編集、保存が可能となっている。今回のサンプルではBackbon.jsにフォーカスしたかったのでサーバサイドでの永続化処理(DBへの保存など)は行っていない。
アプリケーションの環境
今回のアプリケーションの環境は下記の通り。
Node.jsのセットアップ方法などはNode.jsをUbuntu 11.10にセットアップする ついでにExpress.jsもセットアップするなどを参考にしてもらいたい。
ソースコードをどこか適当な場所に$ git cloneなりダウンロードして展開したら下記コマンドで必要なモジュールをインストールする。
とかなんとか表示されていたら正常に起動できたので下記URLへアクセスしてみよう。
Backbone.jsの解説
Backbone.jsは大きく3つのパートに分けられる。
今回のアプリケーションで設定されているRouteは下図の通り。
Routeの詳細は./app.coffeeに記述されているので参照してもらいたい。
ここから個別にBackbone.jsを使ったコーディングを見ていこう。ソースコードは./public/javascripts/index.coffeeを参照してもらいたい。
データ系
ビュー系
管理系
呼び出し
まとめ
ここまで駆け足で説明してきたけれどいかがだろうか?今回のサンプルではデータの永続化処理を行っていないので微妙な部分も多々あるけれど、Backbone.jsを使うとクライアントとサーバ、ビューとデータ、UI操作とデータ処理の分離が上手に行えるのが分かったかと思う。ただBackbone.jsを使ったとしてもアプリケーションの規模が大きくなってくれば必然的にコード量が増えるのでどうしても管理は煩雑になっていき適切なサブモジュール化などを行う必要が出てくるけれど、そのサブモジュール化自体をBackbone.jsのおかげで容易に行える実感は持てたのではと思う。UI要素とデータの結びつきとデータの更新に伴うUI要素への反映をさっくりとできるBackbone.jsはどのような場面でも非常に有用なので是非活用してもらいたい。
- HTML要素上のデータ
- ブラウザメモリ上のデータ
- サーバサイドのデータ
というわけで、そんな状況を打破するためのクライアントフレームワークがここ2~3年で大変充実してきていて、今回解説するBackbone.js、もちっとお手軽らしいEmber.js、もっともっとシンプルなKnockout.jsなどなど、どれから手にとって良いやら迷うこと必至なほど盛況だ。で、とりあえず選考の一助になればと簡単なサンプルアプリケーションを作成してみた。
今回のアプリケーションの外観は下図。ソースコードはhttps://github.com/yooontheearth/backbone-tutorialから取得可能になっている。
ご覧の通りよくある一般的な尼子十勇士系のアプリケーションだ。左側のリストを選択するとその詳細が右側に表示され、追加、編集、保存が可能となっている。今回のサンプルではBackbon.jsにフォーカスしたかったのでサーバサイドでの永続化処理(DBへの保存など)は行っていない。
アプリケーションの環境
今回のアプリケーションの環境は下記の通り。
- サーバ Ubuntu@12.04
- Webサーバ Node.js@0.6.9
- サーバフレームワーク Express.js@2.5.0
- Viewエンジン Jade@0.26.0
- CSSエンジン Stylus@0.23.0
- クライアントフレームワーク Backbone.js@0.9.2
- CoffeeScript
Node.jsのセットアップ方法などはNode.jsをUbuntu 11.10にセットアップする ついでにExpress.jsもセットアップするなどを参考にしてもらいたい。
ソースコードをどこか適当な場所に$ git cloneなりダウンロードして展開したら下記コマンドで必要なモジュールをインストールする。
$ npm install -d
package.jsonに記述してあるもので必要なモジュールはすべてそろっていると思うけれど、サンプルを作った環境はグローバルにたくさんモジュールをインストールしすぎていて何が必要なのかよく分からなかったので少し適当だ。実行時にエラーが出たらその都度必要なモジュールを追加してほしい。今回はコーディングをCoffeeScriptで行っているので下記コマンドでCoffeeScriptをグローバルにインストールする。$ npm install coffee-script -g
これで準備が整ったので下記コマンドでアプリケーションを実行してみよう。$ NODE_PATH=/usr/local/lib/node_modules coffee app
"Express server listening on port 3000 in development mode"とかなんとか表示されていたら正常に起動できたので下記URLへアクセスしてみよう。
http://localhost:3000/index
先ほどの尼子十勇士的なリストが表示されていたら正常に動作している。Backbone.jsの解説
Backbone.jsは大きく3つのパートに分けられる。
- Model,Collectionのデータ系
- Viewの表示系
- Routerの管理系
今回のアプリケーションで設定されているRouteは下図の通り。
Route | 動詞 | 説明 |
---|---|---|
/index | get | 初期表示を行う |
/list | get | リストデータを取得する。Collection.fetch()でリクエストされる。今回は実装していないけれど本来的にはページングなどを行う |
/busho | post | 武将情報の新規追加を行う。Model.save()時にModelが新規(Model.isNew())に作成されたものの場合はpostリクエストされる |
/busho/:id | put | 武将情報の更新を行う。Model.save()時にModelが新規でないものの場合はputリクエストされる |
/busho/:id | delete | 武将情報の削除を行う。Model.destroy()でリクエストされる |
ここから個別にBackbone.jsを使ったコーディングを見ていこう。ソースコードは./public/javascripts/index.coffeeを参照してもらいたい。
データ系
# 武将モデル Busho = Backbone.Model.extend urlRoot: 'busho' # Bushoモデルがサーバへのリクエストを行うときの基本となる部分の指定 defaults: # templateで使用するプロパティがundefinedだとエラーになるので初期値を設定しておく id:null name:null description:null imageUrl:null initialize: -> @on 'error', @failOnValidation @on 'destroy', @close validate: (attrs) -> if not attrs.name? or attrs.name.length == 0 return '名称は必須です' # 検証に失敗した場合はメッセージを返す failOnValidation: (model, error) -> alert error # 検証に失敗した場合のイベントハンドリング close: -> @off()ここで指定しているurlRootの部分が前述のRouteの部分(/busho, /busho/:id)と対応するようになる。
# 武将モデルコレクション BushoList = Backbone.Collection.extend model: Busho # createを呼び出す場合はmodelの指定は必須 url: 'list' # fetchするときのリクエスト先ここで指定しているurlの部分が前述のRouteの部分(/list)と対応するようになる。
ビュー系
# リストビュー ListView = Backbone.View.extend tagName: 'table' initialize: -> # modelはBushoListなのでBushoListが変更されたときに備えてイベント登録 @model.bind 'reset', @render, this @model.bind 'add', (busho)=> $(@el).append new ListItemView(model:busho).render().el # tableに新しい行を追加する render: -> $(@el).empty() _.each @model.models, (busho) -> # BushoListの内容をtableに行として追加する $(@el).append new ListItemView(model:busho).render().el , this return thisこのビューはリスト=CollectionをModelとして受け取り、Collectionのデータ構造をUI的に表すのと、Collectionの変化(リストの更新、追加など)をUIへと反映させる責任を持つ。またtagNameはビューで作成される要素を表しデフォルトではDIVになり、elはその作成された要素を表す。
# リストビューアイテム ListItemView = Backbone.View.extend tagName: 'tr' template: _.template $('#tpl-list-item').html() initialize: -> # modelはBushoなのでBusho情報が変更されたときに備えてイベント登録 @model.bind 'change', @render, this @model.bind 'destroy', @close, this render: -> $(@el).html @template @model.toJSON() return this events: 'click td':'select' # 行が選択された処理をフックするためにUI要素のイベント登録を行う select: -> $('tr.selected').removeClass('selected') $(@el).addClass('selected') app.navigate "busho/#{@model.id}", true # 詳細情報を表示するためにルーターに通知する close: -> $(@el).off().remove()templateプロパティへビューに表示するHTML要素を設定する。今回はUnderscore.jsのテンプレートを使用しているけれど、もちろんjQueryTemplateでもなんでもかまわない。ただここにHTML要素をだらだらと記述するのは関心の分離を進めるMVC的には正しくないのでテンプレートを使用するようにしよう。eventsプロパティに要素内でフックしたいイベントの記述をする。構文的には'イベント セレクタ':'イベントハンドラ'となる。
# 詳細情報画面 DetailsView = Backbone.View.extend template: _.template $('#tpl-details').html() render: -> $(@el).html @template @model.toJSON() $(@el).find('#delete').hide() if @options.hideDelete return this events: 'change input,textarea':'changeData' # UI要素に入力された情報をモデルに反映するためのイベントハンドリング 'click #save':'save' 'click #delete':'delete' changeData:(event)-> # changeイベントでデータを必ずしも反映させる必要はなく、アプリの要件によっては保存ボタン押下時などにまとめて行っても良い changeDataSet = {} changeDataSet[event.target.name] = event.target.value @model.set changeDataSet, silent:true # silent:trueで検証を無効化している save: -> if @model.isNew() # 新規登録時はリストに追加する app.list.create @model, wait:true success: (model, response) => @model.set 'id', app.list.length # IDの採番は適当。本来ならばサーバからのレスポンスにIDを渡しておいて設定するとか app.navigate '', true error:(model, error)-> # サーバサイドでのエラーはresponseTextを参照、それ以外はクライアントでの検証エラー alert if error.responseText then error.responseText else error else @model.save {}, success: (model, response) -> # とくに処理なし error: (model, error) -> alert if error.responseText then error.responseText else error return false delete: -> return false unless confirm '削除しますか?' @model.destroy success: -> app.navigate '', true return false close: -> $(@el).off().empty()save時に新規の場合はリストに要素を追加したいのでapp.list.createとしているけれど、Backbone.jsの内部的にはModel.save()が呼び出されている。
# ヘッダービュー HeaderView = Backbone.View.extend template: _.template $('#tpl-header').html() render: -> $(@el).html @template() return this events: 'click #refresh':'refresh' 'click #add':'add' refresh: -> app.navigate 'refresh', true return false add: -> app.navigate 'busho/add', true return falseRouterへの通知を行うだけのビュー。
管理系
AppRouter = Backbone.Router.extend routes: 'busho/add':'add' 'busho/:id':'details' 'refresh':'list' '':'closeDetails' initialize: -> @list = new BushoList() @list.reset _bushoList # 初期表示するデータはページロード時に用意してあるのでそちらから取得 @listView = new ListView model:@list $('#list').html @listView.render().el $('#header').html new HeaderView().render().el # ヘッダービューをDOMツリーに反映 add:-> @detailsView.close() if @detailsView @detailsView = new DetailsView model:new Busho() hideDelete:true # 追加なので削除ボタンは不要 $('#details').html @detailsView.render().el # 詳細ビューをDOMツリーに反映 details:(id)-> @detailsView.close() if @detailsView busho = @list.get id # リストから詳細を表示するアイテムを取得 @detailsView = new DetailsView model:busho $('#details').html @detailsView.render().el # 詳細ビューをDOMツリーに反映 list:-> @list.fetch() # リストの更新 # ※fetch({data: {page: 3}}) のような形でQueryStringを渡せるのでページングなどもfetchで行える closeDetails:-> @detailsView.close() if @detailsView # 詳細ビューが開いていたら閉じるroutesプロパティにクライアント側でページの遷移を制御するためのRouteを登録しておく。Routerはroutesプロパティに基づいてリクエストされた処理を行い、クライアントとサーバの仲立ちを行う。
呼び出し
app = null $(document).ready -> app = new AppRouter() Backbone.history.start()使用方法はいたって簡単。AppRouterをインスタンス化するだけ。あとはRouterがよきように取り計らってくれる。
まとめ
ここまで駆け足で説明してきたけれどいかがだろうか?今回のサンプルではデータの永続化処理を行っていないので微妙な部分も多々あるけれど、Backbone.jsを使うとクライアントとサーバ、ビューとデータ、UI操作とデータ処理の分離が上手に行えるのが分かったかと思う。ただBackbone.jsを使ったとしてもアプリケーションの規模が大きくなってくれば必然的にコード量が増えるのでどうしても管理は煩雑になっていき適切なサブモジュール化などを行う必要が出てくるけれど、そのサブモジュール化自体をBackbone.jsのおかげで容易に行える実感は持てたのではと思う。UI要素とデータの結びつきとデータの更新に伴うUI要素への反映をさっくりとできるBackbone.jsはどのような場面でも非常に有用なので是非活用してもらいたい。
2012年6月20日水曜日
Open XMLでExcelを生成する
@ryuichi111std氏からのお仕事紹介でサーバサイドでのExcel出力機能を承り、Excel周りの作業の調査をしたら時代の移り変わりを実感したので解説。
一昔前のExcelのオートメーションと言えば、ExcelのオブジェクトをCOM InteropやらCOM Callable WrapperやらでごにょごにょしてぐりぐりしてどこやらでCellオブジェクトの解放忘れやらシートとブックの解放の順番間違いやらをしてしまいメモリリークという悲劇を生む精根尽き果てる作業というのが筋だったけれど、今やそれも昔。今やOpenXMLという規格があるのでそれに準じた形のXMLを吐き出すことで、あらまOffice 2007/2010対応のファイルができちゃった、という寸法になっている。
で、OpenXMLの初期の初期のころはそんなXMLのフォーマットをごりごりと手動で実装するというキチガイ沙汰の作業が横行していたようだけれど、そんな時代が長く続くはずもなくOpenXMLのフォーマット形式で出力してくれるSDKが登場した。それが下記。
Open XML SDK 2.0 for Microsoft Office
OpenXMLSDKv2.msiの方をインストールしてね。ToolのほうはExcelファイルを渡すとそのファイルを作成するためのコードを生成してくれるというツールなので興味がある人はどうぞ。
で、OpenXMLSDK、実はこいつもかなり使いづらい。かなりどころか、ディモールト(非常に)使いづらい。使いづらいどころかまったくこなれておらず、かなり分かりづらい仕様となっているOpenXMLを単純にそのままラップしたような構成になっているので、とっても廻りくどいしバグが入り込みやすい。
一体OpenXMLSDKを使っての開発がどういうものになるのか、下記のコードを参照してもらうのが一番手っ取り早いと思う。
Using C# and Open XML SDK 2.0 for Microsoft Office to Create an Excel 2007 Document
Creating basic Excel workbook with Open XML
で、めんどくせーなー、と思いつつ実装していたら、di molto(非常に)使いやすいライブラリを発見したのでご紹介。それが下記。
ClosedXML - The easy way to OpenXML
ClosedXMLはOpenXMLSDKをラップして使いやすくしたライブラリで非常に直観的。下記のコードはワークブックを作成してシートを追加してA1セルに値を設定して名前を付けて保存している。下記と同等のコードをOpenXMLSDKだけで行おうとすると50行~100行ほどの実装が必要になる。
ほかにもほとんどのパターンに対応するサンプルコードが豊富にあるので詳細はDOCUMENTATIONを参照してもらいたい。
このプロジェクトが気に入ったらブログで紹介してね、とClosedXMLのサイトにあったのでご紹介。このエントリーをご覧になられた方もどうぞよろしく。
一昔前のExcelのオートメーションと言えば、ExcelのオブジェクトをCOM InteropやらCOM Callable WrapperやらでごにょごにょしてぐりぐりしてどこやらでCellオブジェクトの解放忘れやらシートとブックの解放の順番間違いやらをしてしまいメモリリークという悲劇を生む精根尽き果てる作業というのが筋だったけれど、今やそれも昔。今やOpenXMLという規格があるのでそれに準じた形のXMLを吐き出すことで、あらまOffice 2007/2010対応のファイルができちゃった、という寸法になっている。
で、OpenXMLの初期の初期のころはそんなXMLのフォーマットをごりごりと手動で実装するというキチガイ沙汰の作業が横行していたようだけれど、そんな時代が長く続くはずもなくOpenXMLのフォーマット形式で出力してくれるSDKが登場した。それが下記。
Open XML SDK 2.0 for Microsoft Office
OpenXMLSDKv2.msiの方をインストールしてね。ToolのほうはExcelファイルを渡すとそのファイルを作成するためのコードを生成してくれるというツールなので興味がある人はどうぞ。
で、OpenXMLSDK、実はこいつもかなり使いづらい。かなりどころか、ディモールト(非常に)使いづらい。使いづらいどころかまったくこなれておらず、かなり分かりづらい仕様となっているOpenXMLを単純にそのままラップしたような構成になっているので、とっても廻りくどいしバグが入り込みやすい。
一体OpenXMLSDKを使っての開発がどういうものになるのか、下記のコードを参照してもらうのが一番手っ取り早いと思う。
Using C# and Open XML SDK 2.0 for Microsoft Office to Create an Excel 2007 Document
Creating basic Excel workbook with Open XML
で、めんどくせーなー、と思いつつ実装していたら、di molto(非常に)使いやすいライブラリを発見したのでご紹介。それが下記。
ClosedXML - The easy way to OpenXML
ClosedXMLはOpenXMLSDKをラップして使いやすくしたライブラリで非常に直観的。下記のコードはワークブックを作成してシートを追加してA1セルに値を設定して名前を付けて保存している。下記と同等のコードをOpenXMLSDKだけで行おうとすると50行~100行ほどの実装が必要になる。
var workbook = new XLWorkbook(); var worksheet = workbook.Worksheets.Add("Sample Sheet"); worksheet.Cell("A1").Value = "Hello World!"; workbook.SaveAs("HelloWorld.xlsx");
ほかにもほとんどのパターンに対応するサンプルコードが豊富にあるので詳細はDOCUMENTATIONを参照してもらいたい。
このプロジェクトが気に入ったらブログで紹介してね、とClosedXMLのサイトにあったのでご紹介。このエントリーをご覧になられた方もどうぞよろしく。
2012年5月10日木曜日
正規表現を使って簡単置換 with Visual Studio
jquery.tmplを使って帳票っぽい画面を作っていたら、直接値を表示するのではなく関数を呼び出して値を変更してから表示したくなったんだけど、項目がたくさんあって一個一個手で変更していくのは骨だなぁ、ってことでVisual Studioと正規表現で簡単に置換できる方法を調べたのでその紹介。
下記のようなjquery.tmplを使用しているコードがあるとする。
このprop1~3を下記のようにしたいとする。
数が少なければ手でしゃしゃっと修正してしまうのもありだけれども、大量の項目をこのように置換したい場合はVisual Studioの置換機能と正規表現を使用すれば簡単に変更できる。
Ctrl + h で検索と置換ウィンドウを開いて、検索する文字列に\$\{{.*}\}、置換後の文字列に${callMethod(\1)}と入力する。条件チェックボックスにチェックして正規表現を選択するのを忘れないように。
これで置換ボタンを押下すると予期したように置換されているのが確認できると思う。
簡単に解説すると、検索する文字列で指定した{.*}の部分でprop1~3のマッチングを行っている。そのマッチングした部分を置換後の文字列で指定した\1で使用している。マッチングの部分が複数ある場合は\2, \3のようにすることで対応できる。
ちなみにJavascriptだとマッチングの部分が{}ではなく()だし、\1の部分が$1となっていて、ここらへんは言語によって微妙に異なっているので他の用途で使用する場合は言語仕様をよく確認してほしい。
下記のようなjquery.tmplを使用しているコードがあるとする。
${prop1}${prop2}${prop3}
このprop1~3を下記のようにしたいとする。
${callMethod(prop1)}${callMethod(prop2)}${callMethod(prop3)}
数が少なければ手でしゃしゃっと修正してしまうのもありだけれども、大量の項目をこのように置換したい場合はVisual Studioの置換機能と正規表現を使用すれば簡単に変更できる。
Ctrl + h で検索と置換ウィンドウを開いて、検索する文字列に\$\{{.*}\}、置換後の文字列に${callMethod(\1)}と入力する。条件チェックボックスにチェックして正規表現を選択するのを忘れないように。
これで置換ボタンを押下すると予期したように置換されているのが確認できると思う。
簡単に解説すると、検索する文字列で指定した{.*}の部分でprop1~3のマッチングを行っている。そのマッチングした部分を置換後の文字列で指定した\1で使用している。マッチングの部分が複数ある場合は\2, \3のようにすることで対応できる。
ちなみにJavascriptだとマッチングの部分が{}ではなく()だし、\1の部分が$1となっていて、ここらへんは言語によって微妙に異なっているので他の用途で使用する場合は言語仕様をよく確認してほしい。
ASP.NETでDateTimeをJSONに変換したら不思議な文字列になった場合の対処法
ASP.NETでJavaScriptSerializerを使用してDateTimeをJSONに変換すると下記のような嬉しくない形で出力される。
/Date(1329058800000)/
JSONに変換する前にToString("yyyy/MM/dd")でもして文字列にしてしまえば問題ないけれど、毎回そういうことが可能なわけでもないのでJavaScriptでの対処方法を紹介する。
/Date(1329058800000)/
JSONに変換する前にToString("yyyy/MM/dd")でもして文字列にしてしまえば問題ないけれど、毎回そういうことが可能なわけでもないのでJavaScriptでの対処方法を紹介する。
var date = "/Date(1329058800000)/"; alert(convertToDateTime(date)); function convertToDateTime(value) { var date = new Date(parseInt(value.replace("/Date(", "").replace(")/", ""), 10)); return date.getFullYear() + '/' + fillZero(date.getMonth() + 1, 2) + '/' + fillZero(date.getDate(), 2); } function fillZero(number, width) { width -= number.toString().length; if (width > 0) { return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number; } return number; }上記のコードを実行すると2012/02/13と表示されるのが確認できる。
2012年2月4日土曜日
Node.jsをUbuntu 11.10にセットアップする ついでにExpress.jsもセットアップする その2
Express.jsのインストールもうまくいき、$ expressでテンプレートもできあがったので満足していたら実はまだ問題があったようで下記コマンドを実行したらエラーがもりもりと出てきてしまった。
エラー内容はこちら。
することなすことすべてがエラーで返ってくるので常に心を整えていないとやっていられない。エラー場所として示されているserver.jsの87行目を見てみると
となっている。で、GoogleしてみるとExpress.jsに対応したConnect.jsのバージョンがどうやらインストールされていないらしい。インストールしているExpress.jsのバージョンは1.0.7で、そのバージョンのExpress.jsが対応しているConnect.jsは0.5.10らしい。しかしnpmからインストールするとConnect.jsは1.0.1がインストールされてしまうためにエラーとなっているようだ。なので下記コマンドで古いConnect.jsをインストールする。
これで冒頭のNode.jsのコマンドを実行するとサーバがリッスン状態に突入するので、http://localhost:3000にアクセスしてHello Worldの出力が正常にされているのを確認できた。ちなみに自分の環境にどのモジュールのどのバージョンがインストールされているかを調べるコマンドは下記。
表示されるモジュールの一覧で、Connect.jsのバージョンが0.5.10になっているのが確認できると思う。
$ node app.js
エラー内容はこちら。
node.js:201 throw e; // process.nextTick error, or 'error' event on first tick ^ TypeError: Cannot read property 'prototype' of undefined at Object.(/home/yoo/matsuo-software/sandbox/node-firstapp/node_modules/express/lib/express/server.js:87:44) at Module._compile (module.js:444:26) at Object..js (module.js:462:10) at Module.load (module.js:351:31) at Function._load (module.js:310:12) at Module.require (module.js:357:17) at require (module.js:373:17) at Object. (/home/yoo/matsuo-software/sandbox/node-firstapp/node_modules/express/lib/express/index.js:28:31) at Module._compile (module.js:444:26) at Object..js (module.js:462:10)
することなすことすべてがエラーで返ってくるので常に心を整えていないとやっていられない。エラー場所として示されているserver.jsの87行目を見てみると
Server.prototype.__proto__ = connect.Server.prototype;
となっている。で、GoogleしてみるとExpress.jsに対応したConnect.jsのバージョンがどうやらインストールされていないらしい。インストールしているExpress.jsのバージョンは1.0.7で、そのバージョンのExpress.jsが対応しているConnect.jsは0.5.10らしい。しかしnpmからインストールするとConnect.jsは1.0.1がインストールされてしまうためにエラーとなっているようだ。なので下記コマンドで古いConnect.jsをインストールする。
$ npm install connect@0.5.10
これで冒頭のNode.jsのコマンドを実行するとサーバがリッスン状態に突入するので、http://localhost:3000にアクセスしてHello Worldの出力が正常にされているのを確認できた。ちなみに自分の環境にどのモジュールのどのバージョンがインストールされているかを調べるコマンドは下記。
$ npm ls
表示されるモジュールの一覧で、Connect.jsのバージョンが0.5.10になっているのが確認できると思う。
Node.jsをUbuntu 11.10にセットアップする ついでにExpress.jsもセットアップする
Node.jsを使ってみたかったのでUbuntu 11.10にセットアップしたときのメモ書き。Node.jsのセットアップ自体はさっくりと終わり何事もなかったのだけれども、後述する諸々の事情からExpress.jsのインストールに失敗してしまい、完了するまでやたらと時間がかかったので後続の方のためにも記しておく。
下記の一連のコマンドを実行してもらいたい。
1, Gitから最新のNode.jsコードを取得する
2, コンパイルしてインストールする
3, NPM(Node Package Manager)をインストールする。NPMはNode.jsまわりで必要になるモジュールを簡単にインストールできるとても便利なツールだ
ここまででNode.jsのセットアップが整ったのでExpress.jsのセットアップにとりかかる。
4, Express.jsをインストールする
5, 忘れずにExpress.jsに必要なモジュールもインストールする
これでExpress.jsのインストールが完了したはずなのでExpress.jsを実行してみよう。
6, Express.jsを実行してテンプレートを作成する
すると高確率で意味不明なエラーに遭遇すると思う。しなかったら今回のポストの表題の件は達成したのでアリーベデルチしていただいて結構だ。
エラーは「process.nextTick error, or 'error' event on first tick」という感じのまったく要領を得ない内容で取り付く島がない。で、色々とGoogle & 試行錯誤の結果、どうやらテンプレートエンジンであるJade.jsというのがインストールされていないらしい。
7, なのでJade.jsをインストールする
するとまたエラーになる。エラー内容によるとJade.jsと依存関係にあるCommander.jsがNode.jsの0.7未満までにしか対応しておらず、gitから調子こいて最新のNode.jsをインストールしたばっかりにインストールがうまくいっていないようだ(これが冒頭で述べた諸々の事情)。この時点であまりのうまくいかなさに少し常軌を逸しかけたけれども、幸いかな、優秀な開発者の方々のおかげで簡単にNode.jsのバージョンを変更する手段がすでに用意されていた。ありがとう優秀なみなさん。
8, Node.jsのバージョンを変更するためにnをインストールして、Node.jsのバージョンを0.6.9に変更する
以上でNode.jsとExpress.jsのセットアップの解説は終わりだ。偉そうに解説しておいてなんだけれども、Node.jsは今から開発しようとしている人間なのでNode.jsまわりの知識はほぼゼロに近い、かつLinuxも触り始めたばかりのため疎く間違った解説があるかもしれない。また今回は色々なコマンドを試しながらセットアップしたので正しくない解説 & 不要なコマンドもあるかもしれないが、少しでもセットアップに行き詰った方の一助になれば幸いだ。
今回のセットアップがやたらと大変だったのは、Express.jsの依存関係としてあがってくるconnectとqsのインストールに失敗しているものだとばかり考えていたので、そちらと格闘するのに大幅な時間がとられてしまったせいだと思う。ただJade.jsに目をつけてからは、インストールできない→nのインストール→バージョン変更→Jade.jsのインストール成功→Express.jsの実行成功、ととんとん拍子に進んだので最後のほうは楽だった。これで週末はNode.jsとmongoDBの評価がさっくりとできそうでなによりだ。ふぃ~
下記の一連のコマンドを実行してもらいたい。
1, Gitから最新のNode.jsコードを取得する
$ sudo apt-get update
$ sudo apt-get install git-core curl build-essential openssl libssl-dev
$ git clone https://github.com/joyent/node.git && cd node
Node.jsでSSLを使う場合はopensslが必要なのでついでにインストールしておく。上記のコマンドでnodeフォルダに最新のNode.jsコードがクローンされた。$ sudo apt-get install git-core curl build-essential openssl libssl-dev
$ git clone https://github.com/joyent/node.git && cd node
2, コンパイルしてインストールする
$ ./configure
$ make
$ sudo make install
$ node -v
正常にインストールがされたら一番最後のコマンドのnode -vでインストールされたNode.jsのバージョンが表示されていると思う。ちなみに今日(2012/2/2)現在で0.7.2-preとなっている。$ make
$ sudo make install
$ node -v
3, NPM(Node Package Manager)をインストールする。NPMはNode.jsまわりで必要になるモジュールを簡単にインストールできるとても便利なツールだ
$ curl http://npmjs.org/install.sh | sudo sh
$ npm -v
こちらも今日現在で1.1.0-3となっている。($ npm searchでnpmでインストールできるモジュールの一覧が参照できるので興味がある人は見てみると良いだろう)$ npm -v
ここまででNode.jsのセットアップが整ったのでExpress.jsのセットアップにとりかかる。
4, Express.jsをインストールする
$ npm install -g express
-gはグローバルにインストールするオプションだ。グローバル指定だと/usr/local/bin/あたりにインストールされる。ローカルにだけインストールしたいのなら-gははずそう。ローカル指定にすると現在のディレクトリ直下のnode_modulesにインストールされる。5, 忘れずにExpress.jsに必要なモジュールもインストールする
$ npm install -d
これでExpress.jsのインストールが完了したはずなのでExpress.jsを実行してみよう。
6, Express.jsを実行してテンプレートを作成する
$ express
すると高確率で意味不明なエラーに遭遇すると思う。しなかったら今回のポストの表題の件は達成したのでアリーベデルチしていただいて結構だ。
エラーは「process.nextTick error, or 'error' event on first tick」という感じのまったく要領を得ない内容で取り付く島がない。で、色々とGoogle & 試行錯誤の結果、どうやらテンプレートエンジンであるJade.jsというのがインストールされていないらしい。
7, なのでJade.jsをインストールする
$ npm install -g jade
するとまたエラーになる。エラー内容によるとJade.jsと依存関係にあるCommander.jsがNode.jsの0.7未満までにしか対応しておらず、gitから調子こいて最新のNode.jsをインストールしたばっかりにインストールがうまくいっていないようだ(これが冒頭で述べた諸々の事情)。この時点であまりのうまくいかなさに少し常軌を逸しかけたけれども、幸いかな、優秀な開発者の方々のおかげで簡単にNode.jsのバージョンを変更する手段がすでに用意されていた。ありがとう優秀なみなさん。
8, Node.jsのバージョンを変更するためにnをインストールして、Node.jsのバージョンを0.6.9に変更する
$ npm install -g n
$ sudo n 0.6.9
$ node -v
これでNode.jsが0.6.9になったので、再度7を実行しJade.jsをインストールする。Jade.jsのインストールが成功したら再度6を実行してみよう。ディレクトリの指定がないけどここにつくっていいの?的なことを尋ねられるので yes とタイプすると、直下にviewsとかtestとかのディレクトリをもりもりと作ってくれるはずだ。$ sudo n 0.6.9
$ node -v
以上でNode.jsとExpress.jsのセットアップの解説は終わりだ。偉そうに解説しておいてなんだけれども、Node.jsは今から開発しようとしている人間なのでNode.jsまわりの知識はほぼゼロに近い、かつLinuxも触り始めたばかりのため疎く間違った解説があるかもしれない。また今回は色々なコマンドを試しながらセットアップしたので正しくない解説 & 不要なコマンドもあるかもしれないが、少しでもセットアップに行き詰った方の一助になれば幸いだ。
今回のセットアップがやたらと大変だったのは、Express.jsの依存関係としてあがってくるconnectとqsのインストールに失敗しているものだとばかり考えていたので、そちらと格闘するのに大幅な時間がとられてしまったせいだと思う。ただJade.jsに目をつけてからは、インストールできない→nのインストール→バージョン変更→Jade.jsのインストール成功→Express.jsの実行成功、ととんとん拍子に進んだので最後のほうは楽だった。これで週末はNode.jsとmongoDBの評価がさっくりとできそうでなによりだ。ふぃ~
2012年1月9日月曜日
2011年10月~12月の記事いろいろ
便利
携帯電話とタブレット上でのHtml5とCSS3の互換性表
プログラミング - デザイン
Patterns For Large-Scale JavaScript Application Architecture
API Design Principles
プログラミング - 読みもの
Code like you’re Notch
プログラミング - js
stream.js
新しいデータ構造を提供するライブラリ
デザイン
Clean Up Your Mess
デザイン - css
Just some other awesome CSS3 buttons
デザイン - 笑い
Is this rotating cube interface user-friendly?
マネタイズ
A Hacker’s Guide to Monetizing Free-to-Play Games
The Complete Guide To Freemium Business Models
ツール
Git Is Simpler Than You Think
携帯電話とタブレット上でのHtml5とCSS3の互換性表
プログラミング - デザイン
Patterns For Large-Scale JavaScript Application Architecture
API Design Principles
プログラミング - 読みもの
Code like you’re Notch
プログラミング - js
stream.js
新しいデータ構造を提供するライブラリ
デザイン
Clean Up Your Mess
デザイン - css
Just some other awesome CSS3 buttons
デザイン - 笑い
Is this rotating cube interface user-friendly?
マネタイズ
A Hacker’s Guide to Monetizing Free-to-Play Games
The Complete Guide To Freemium Business Models
ツール
Git Is Simpler Than You Think
2012年1月5日木曜日
Html5でサイトを作る理由
Html5で新しい機能が大量に導入されたためHtml5を使う利点を考えるときには切り口によって色んな見方ができると思う。ブラウザベースのゲームを作っていた人はオーディオがネイティブでサポートされたのとCanvasによってぐりぐりとビジュアルをアニメーションさせることが可能になったので今までのようにプラグインを導入する必要がなくなったのが嬉しいだろうし、Web socketによってサーバとの通信がよりライトウェイトになったおかげで色々とアイディアを思いつく人もいるだろうし、Data StorageとかOffline時の制御やDrag & Dropも導入されたのでブラウザベースだからできないと言って限定されていたものがより普通のアプリのように動作するようになるだろうし、Html5と一口で言ってもこれだけ多種多様な広がる未来がある。
では通常のサイトを作る上でのHtml5を使う利点はなんだろうか。それはセマンティックウェブを意識した新しい要素達にある。以前もIntroducing HTML5を読んでの感想で軽く触れたけれども、Html5ではコンピュータから見て意味のある記述を可能とする新しい要素達がたくさん導入されている。それらを正しく使用することによってより検索エンジンフレンドリーになるし、それによって結果的に効果的なSEOとなるのは明らかだろう。というわけでなんらかのサイトを運営されている方は早めにHtml5で記述し始めたほうがお得というわけだ。
で、タグの紹介とか、タグの使用方法とかを調べるのにざっと見た中で下記のサイトでの解説が大変分かりやすかったのでお勧めだ。IE8以前のブラウザでHtml5のタグを正常に認識させる方法も解説してくれているので参考にしてもらいたい。
HTML5の簡易メモ
では通常のサイトを作る上でのHtml5を使う利点はなんだろうか。それはセマンティックウェブを意識した新しい要素達にある。以前もIntroducing HTML5を読んでの感想で軽く触れたけれども、Html5ではコンピュータから見て意味のある記述を可能とする新しい要素達がたくさん導入されている。それらを正しく使用することによってより検索エンジンフレンドリーになるし、それによって結果的に効果的なSEOとなるのは明らかだろう。というわけでなんらかのサイトを運営されている方は早めにHtml5で記述し始めたほうがお得というわけだ。
で、タグの紹介とか、タグの使用方法とかを調べるのにざっと見た中で下記のサイトでの解説が大変分かりやすかったのでお勧めだ。IE8以前のブラウザでHtml5のタグを正常に認識させる方法も解説してくれているので参考にしてもらいたい。
HTML5の簡易メモ
登録:
投稿 (Atom)