tag:blogger.com,1999:blog-65645736873682390342024-03-14T09:16:53.322+09:00strix01Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.comBlogger97125tag:blogger.com,1999:blog-6564573687368239034.post-32796450255559336442016-11-04T23:45:00.000+09:002016-11-04T23:45:58.751+09:00ブログを引っ越しました。<p>
去る2016年1月にブログを引っ越しました。
</p>
<p>
アナウンスがすっかり遅くなってしまいした。もう一年近く経つのですね・・・
このブログを定期的に見てくれている方がいらっしゃったらば、申し訳ございません。
</p>
<p>
新しいブログは、
<a href="http://blog.shimar.me">shimar's blog</a>
がそれになります。
これまでは、Google Bloggerを使っていましたが、jekyll + Github Pagesに乗り換えました。
</p>
<p>
相変わらずの体でやっております。
よろしくお願いいたします。
</p>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-84538952269125498992015-07-31T00:14:00.001+09:002015-07-31T00:14:40.793+09:00[Electron] ElectronでHello,Worldアプリを書いてみる。<section>
<h2>はじめに</h2>
<p>
<a href="http://electron.atom.io/">Electron</a>っていう<a href="https://atom.io/">Atomエディタ</a>のベースを切り離してプラットフォーム化したものがある。コレを使うと、クラスプラットフォームなデスクトップアプリケーションが、HTML、CSS、Javacriptで書けるっていうんで、使っていこうかしらと思案しています。まずは、環境を作って、Hello,Worldでも。
</p>
<p>
ちなみに、環境は、
<ul>
<li>ubuntu 14.04 LTS(32bit)</li>
<li>node.js v0.12.6</li>
</ul>
です。
</p>
</section>
<section>
<h2>Electronのインストール</h2>
<p>
npmでインストールする。
<pre><code class="bash">npm i -g electron-prebuilt
</code></pre>
</p>
</section>
<section>
<h2>プロジェクトの初期化</h2>
<p>
プロジェクトっていうか、アプリのルートディレクリを掘って、npmコマンドで初期化する。
<pre><code class="bash">mkdir hello-electron && cd hello-electron
npm init
</code></pre>
</p>
</section>
<section>
<h2>コード書く</h2>
<p>
browser(main)プロセス用のjavascriptコードと、rendererプロセスによって画面に表示されるhtmlを書く。
<a href="http://electron.atom.io/docs/v0.30.0/tutorial/quick-start/">本家</a>にあるコードそのままを試す。
</p>
</section>
<section>
<h2>動かしてみる</h2>
<p>
<code>electron</code>コマンドで起動する。
<pre><code class="bash">electron .
</code></pre>
すると、Developer Toolsが有効になったChromeっぽいものが起動します。
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI267ZJyK1UKYNvebvrTQPdMEI_i5B_086ZSidd9inMhrkrn_5VZAMy4ydset_5JSf_1PQcYDinimbHLiO3fQ7ouKbpC-9yXUvIr92-uEAi9DsKAGOnqlbY3y20yffGK_KYswPKuOQz1Y/s1600/hello-electron-with-devtool.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI267ZJyK1UKYNvebvrTQPdMEI_i5B_086ZSidd9inMhrkrn_5VZAMy4ydset_5JSf_1PQcYDinimbHLiO3fQ7ouKbpC-9yXUvIr92-uEAi9DsKAGOnqlbY3y20yffGK_KYswPKuOQz1Y/s320/hello-electron-with-devtool.png" /></a></div>
Developer Toolsを隠すと↓みたいな。
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSIRUOEvLCmMBc5ecsbXeQdhl89vSsuTIV0SVjuvTkMaiH7OZ5NlL_LWxkNmI6IWZAy7T3-j7_KppdEVLlMp6XkZXiLxZ-xtRTal0kGQWBil2WwRPPtL1USdZh2vqusty8YrwOAiqa0bg/s1600/hello-electron.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSIRUOEvLCmMBc5ecsbXeQdhl89vSsuTIV0SVjuvTkMaiH7OZ5NlL_LWxkNmI6IWZAy7T3-j7_KppdEVLlMp6XkZXiLxZ-xtRTal0kGQWBil2WwRPPtL1USdZh2vqusty8YrwOAiqa0bg/s320/hello-electron.png" /></a></div>
</p>
</section>
<section>
<h2>終わりに</h2>
<p>
とりあえずウチのへっぽこPCでも動いたので、いろいろ作ってみます。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-49196770222684950662015-03-31T01:17:00.000+09:002015-03-31T01:17:32.592+09:00Epochでリアルタイムなチャートを表示する - Gauge編<section>
<p>
前回の記事「<a href="http://strix01.blogspot.com/2015/03/epoch.html">Epochでリアルタイムなチャートを表示する。</a>」の続き。前回は、D3.jsベースのチャート表示ライブラリ「<a href="http://fastly.github.io/epoch/">Epoch</a>」を使って、時系列なラインチャート、エリアチャート、バーチャートをリアルタイムに描画する方法について書いた。今回は、Gaugeと呼ばれるチャート?を描画する方法について。
</p>
</section>
<section>
<h2>Gauge?</h2>
<p>
gaugeは、カタカナで書くなら「ゲージ」で、「計器」を意味するらしい。実際、
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgI_D6XCKxuQbr-AMNG8_0xDzqvxHrpzT2OLs9xfeg2_-9uVsVfbphUCWAjkG2ZoBoYuMu74Zl75nr-bkH0m0GtNxHIdTKIPSRYe68PmNtP4891uIQPy7SzSeQN8eQ1raaytALIfQCxVvY/s1600/RealtimeChartwithEpoch-Gauge.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgI_D6XCKxuQbr-AMNG8_0xDzqvxHrpzT2OLs9xfeg2_-9uVsVfbphUCWAjkG2ZoBoYuMu74Zl75nr-bkH0m0GtNxHIdTKIPSRYe68PmNtP4891uIQPy7SzSeQN8eQ1raaytALIfQCxVvY/s320/RealtimeChartwithEpoch-Gauge.png" /></a></div>
みたいなのが描画される。
</p>
</section>
<section>
<h2>使い方</h2>
<p>
gaugeを表示するには、
<pre><code class="javascript">var gauge = $('#gauge-chart').epoch({
type: 'time.gauge',
value: 0.1
});
</code></pre>
のように、epochのtypeに<code>time.gauge</code>を指定する。ライン、エリア、バーと異なり、gaugeは時系列なチャートではないので、時間を指定せず、値のみ指定する。
</p>
<p>
そして、値を更新するには、
<pre><code class="javascript">gauge.push(値);
</code></pre>
とするだけ。これで、gauge上の針がアニメーションしながら指定した値に落ち着いていく。<a href="http://simalabs.com/labs/epochjs">ここ</a>にデモがあります。にしても簡単だわ〜。
</p>
</section>
<section>
<h2>終わりに</h2>
<p>
今回はEpochでGaugeチャートの書き方を書きました。後はHeatmapが残っているので、次回あるいはその次あたりに書きたいが・・・。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-51191089943105076332015-03-19T00:46:00.000+09:002015-03-19T00:46:48.277+09:00Epochでリアルタイムなチャートを表示する。<section>
<p>
html上のチャート、ラインチャートとかバーチャートとか、リアルタイムに更新したい、と思って調べていたら、<a href="http://fastly.github.io/epoch/">Epoch</a>なるライブラリを発見したので、使い方を纏めておく。
</p>
</section>
<section>
<h2>Epoch</h2>
<p>
<blockquote>A general purpose real-time charting library for building beautiful, smooth, and high performance visualizations.</blockquote>
とのこと。
で、
<ul>
<li>javascriptライブラリ</li>
<li>d3.jsベース</li>
<li>Line, Area, Bar, Gauge, Heatmapの各チャートをリアルタイムに表示できる</li>
<li>リアルタイムでない通常のチャートもいける</li>
</ul>
という特徴がある。
</p>
</section>
<section>
<h2>導入</h2>
<p>
Epochはjavascriptファイルとcssファイルを提供しているので、そいつらをページに引きこむ。<a href="http://fastly.github.io/epoch/getting-started/">Epoch - Getting Started</a>にあるようにd3.jsも忘れずに。
</p>
</section>
<section>
<h2>LineChart, AreaChart, BarChart</h2>
<p>
これらはx軸が時間、y軸は任意というチャートを描画する。見た目が違うだけでデータの構造は同じ。データの構造は、
<pre><code class="javascript">var data = [
{ label: 'Series1',
values: [{ time: time, y: 100 }, { time: time + 1, y: 1000 }] },
{ label: 'Series2',
values: [{ time: time, y: 200 }, { time: time + 1, y: 200 }] }
];
</code></pre>
という形になる。系列ごとにlabelとデータを定義して、それを配列にする。で、valuesの中のtimeは、<quote>a unix timestamp</quote>である必要がある(故にEpochなのかなぁ)。で、これをEpochに与えるとチャートを表示してくれる。
<pre><code class="html"><div id="line-chart" class="epoch" style="height:160px"></div>
</code></pre>
のようなhtmlを書き、
<pre><code class="javascript">var lineChart = $('#line-chart').epoch({
type: 'time.line',
data: data,
axes: ['left', 'bottom', 'right']
});
</code></pre>
とすると、ラインチャートが表示される。エリアチャート、バーチャートの場合もデータの構造は同じなので、<code>epoch</code>関数のパラメータのtypeを、エリアチャートの場合は<code>time.area</code>、バーチャートの場合は<code>time.bar</code>としてやればよい。
</p>
<p>
で、初期データを食わせたチャートに、後から時々刻々とデータを追加していくことでリアルタイムなチャートになるんだけど、追加するデータの形式は、
<pre><code class="javascript">var current = [
{ time: time, y: Math.random() * 1000 },
{ time: time, y: Math.random() * 1000 }
];
</code></pre>
という形式になる。初期データに比べて<code>label</code>が要らない。この追加データを、
<pre><code class="javascript">lineChart.push(current);</code></pre>
とするだけで、チャートが更新される。なんて楽ちんな。タイマーを使って、周期的にバックエンドからデータを取得してpushしてやるとか、WebSocketを使って、バックエンドから送りつけられたデータをpushする、といった方法でリアルタイムなチャートが表示できる。
</p>
<p>
実際に表示すると↓のようなチャートが表示される。
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_Z9umBIyf3TCM3IX5NzQyL-saGnEyseEKkr62jtrMM0E3yBGJk0VVm0R03LneTU3IjShx4R61Eue1fh1qDWKKI2wbmfjC9h2XmUIZYN2BpTDKlZGCr9m2WlmmqHOFyS1IcWM2oSAVOHE/s1600/RealtimeChartwithEpoch-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_Z9umBIyf3TCM3IX5NzQyL-saGnEyseEKkr62jtrMM0E3yBGJk0VVm0R03LneTU3IjShx4R61Eue1fh1qDWKKI2wbmfjC9h2XmUIZYN2BpTDKlZGCr9m2WlmmqHOFyS1IcWM2oSAVOHE/s400/RealtimeChartwithEpoch-1.png" /></a></div>
で、このチャート表示が動いているのが<a href="http://simalabs.com/labs/epochjs">こちら</a>になります。
</p>
<section>
<section>
<h2>終わりに</h2>
<p>
Epochを使うと、他にもGaugeとかHeatmapもリアルタイムに描画できるけど、力尽きたので次回にまわします。それにしても、Epoch便利だわ。
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-21465758743563995282015-03-05T01:31:00.000+09:002015-03-05T01:31:37.743+09:00Animate.cssで簡単にDOM要素のアニメーションを実現する。<section>
<p>
DOM要素にfadeとかslideとかのアニメーションをつけるのに、jQueryで書くのはまあ簡単ではあるけど、<a href="http://daneden.github.io/animate.css/">Animate.css</a>なるcss3のアニメーションライブラリを知ったので、使い方をメモっておく。シンプルなアニメーションがすごく簡単に実現できる。
</p>
</section>
<section>
<h2>Animate.css</h2>
<p>
<a href="https://github.com/daneden/animate.css/blob/master/README.md">githubのREADME.md</a>には、
<blockquote>
animate.css is a bunch of cool, fun, and cross-browser animations for you to use in your projects.
</blockquote>
とある、つまり、クロスブラウザに対応したクールで楽しいアニメーションの束、ってことっぽい。実際、cssを取り込むだけで、いろんな種類のアニメーションが簡単に実現できちゃう。
</p>
</section>
<section>
<h2>使い方</h2>
<p>
cssをダウンロードするなり、<code>bower install animate.css</code>するなりして、HTMLにcssを埋め込む。
<pre><code class="html"><head>
<link rel="stylesheet" href="path/to/animate.min.css">
</head>
</code></pre>
</p>
<p>
で、アニメーションさせたいDOM要素にclass属性を与えてやる。と。例えば、とあるh2要素に対して、<code>rubberBand</code>(ビヨーーンプルンプルンプン)みたいなアニメーションをつけるには、
<pre><code class="html"><h2 class="animated rubberBand">rubberBand</h2>
</code></pre>
のように書く。動的にアニメーションさせたい、例えばボタンクリック時とか、という場合は、
<pre><code class="javcascript">var target = $('h2');
var button = $('button#some-button');
button.on('click', function(ev) {
target.addClass('animated').addClass('rubberBand');
});
</code></pre>
となる。他にも無限にアニメーションさせるとか、アニメーション終了イベントをハンドリングするとかもできる。
</p>
</section>
<section>
<h2>アニメーションの種類</h2>
<p>
<ul>
<li>Attension Seekers</li>
<li>Bouncing</li>
<li>Fading</li>
<li>Flippers</li>
<li>Lightspeed</li>
<li>Rotating</li>
<li>Specials</li>
<li>Zoom</li>
</ul>
8つのカテゴリに分かれていて、それぞれいくつかのアニメーションを提供している。
</p>
<p>
当然本家のサイトでも試せるんだけど、ドロップダウンでいちいち選択するのが面倒に思って、これらを1つ1つ試すページを<a href="http://simalabs.com/labs/animation/animatecss">ここ</a>に作ってみたので、よかったらどうぞ。
</p>
</section>
<section>
<h2>終わりに</h2>
<p>
animate.css、簡単に使えて効果でかいっていう感じがいいな、と思った。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-54053831752387350722015-02-18T01:40:00.001+09:002015-02-18T01:40:48.782+09:00モックhtmlはyeoman+gulp-webappで。<section>
<p>
2013年の8月に、「<a href="http://strix01.blogspot.com/2013/08/htmljadelesscoffeescriptgruntjs.html">モックhtmlはJade+LESS+CoffeeScript+Grunt.jsで。</a>」という記事をこのブログに書いた。あれから約1年半。Webアプリケーションの開発の仕方やツールなども変わってきて、当時やろうとしていたことが今では随分とスマートにできるようになったので、あらためてモックhtmlをさくさく作る環境について纏めておきます。
</p>
</section>
<section>
<h2>Yeoman</h2>
<p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://raw.githubusercontent.com/yeoman/yeoman.io/master/media/optimized/yeoman-300x200-opaque.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://raw.githubusercontent.com/yeoman/yeoman.io/master/media/optimized/yeoman-300x200-opaque.png" /></a></div>
<a href="http://yeoman.io/">Yeoman</a>を使う。Yeomanは「モダンなWebアプリのscaffoldingツール」。いろいろなWebアプリケーションの構成、例えばAngujarJS+Express.js+MongoDBとか、backborn.js+express.jsとか、に対するアプリケーションのscaffoldを作るツール。で、いろいろな構成に対するgeneratorが提供されていて、必要なgeneratorをインストールして使う、という寸法。
</p>
</section>
<section>
<h2>gulp-webapp</h2>
<p>
<a href="https://github.com/yeoman/generator-gulp-webapp">gulp-webapp</a>は、yeomanが提供する静的サイトのためのgenerator。モックHTMLを作るなら、ズバリこいつがよさげ。gulpのwatchタスクが動くから、コード書きながら結果を見ながらコード直しながら結果を見ながら、っていうのが簡単にできちゃう。
</p>
</section>
<section>
<h2>Jadeとless、あるいは。</h2>
<p>
gulp-webpp、ちょっとまって。Jadeとかlessを使いたい場合はどうすんのさ?って思ったんだけど、よくよくドキュメントを見ると、<a href="https://github.com/yeoman/generator-gulp-webapp/blob/master/docs/recipes/README.md">Recipes</a>ってのがあって、ここに色々書いてあった。Jadeもlessも使えるわ。他にもいろいろあるから読んでみたらいい。
</p>
</section>
<section>
<h2>終わりに</h2>
<p>
YeomanはGrunt+Bowerを全面に押し出してるはずなのに、gulp-webappって…と思わずにいられませんでした。とはいえ、便利ですね。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-27575278214957911552015-01-22T01:09:00.001+09:002015-01-22T01:09:20.723+09:00AngularJSのDIについてDeveloper Guideを読んでみた。<section>
<div class="separator" style="clear: both; text-align: center;"><a href="https://raw.githubusercontent.com/angular/angular.js/master/images/logo/AngularJS-Shield.exports/AngularJS-Shield-medium.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://raw.githubusercontent.com/angular/angular.js/master/images/logo/AngularJS-Shield.exports/AngularJS-Shield-medium.png" /></a></div>
</section>
<section style="margin:20px 0 0 0;">
<p>
<a href="http://strix01.blogspot.com/2015/01/angularjsdi.html"></a>を纏める時に、AngularJSの<a href="https://docs.angularjs.org/guide/di">Developer Guide</a>を読んだわけですが、AngularJSがどのようにDIを実現しているか、についても書かれています。興味あったんで纏めてみます(というか訳してみます、に近いか・・・)。
</p>
</section>
<section>
<p>
コンポーネント(objectやfunction)が依存するブツを得る方法は3つしかない。
<ol>
<li>コンポーネントは依存するブツを生成することができ、一般的にはnew演算子を使う。</li>
<li>コンポーネントはグローバル変数から依存するブツを探すことができる。</li>
<li>コンポーネントはそれが必要となる場所で渡される。</li>
</ol>
</p>
<p>
最初の生成する、とか、探すっていう2つの選択肢は、コンポーネントに依存するブツをハードコードしなきゃいけなくなるので、最適とはいえない。依存するブツを変更することが面倒になってしまう。これは特にテスト用に分離したブツのモックを提供したいといった場面で問題になる。
</p>
<p>
3番目の選択肢は、コンポーネントから依存するブツの場所を知る責務を取り除くのでもっともよさそう。依存するブツは単純にそのコンポーネントに渡されるだけ。
</p>
<p>
<pre><code class="javascript">function SomeClass(greeter) {
this.greeter = greeter;
}
SomeClass.prototype.doSomething = function(name) {
this.greeter.greet(name);
};
</code></pre>
</p>
<p>
上の例のSomeClassはgreeterの生成や場所の特定などには関係していなくて、インスタンスが作成される際に、単純にgreeterを手渡されるだけ。
それはいいんだけど、SomeClassを生成するコード上に依存するブツを得るっていう責務を生んでる。
</p>
<p>
依存するブツを生成するっていう責務を管理するために、angularjsアプリケーションは”injector”を持ってる。injectorは、依存するブツの生成や検索を責務とするサービスロケータである。
</p>
<p>
injectorサービスを使った例を挙げる。
</p>
<p>
<pre><code class="javascript">var myModule = angular.module('myModule', []);
</code></pre>
</p>
<p>
injectorにどうやってgreeterサービスを組み立てるか教えてあげる。greeterは$windowサービスに依存していることに注目しよう。greeterサービスはgreetメソッドを持つオブジェクト。
</p>
<p>
<pre><code class="javascript">myModule.factory('greeter', function($window) {
return {
greet: function(text) {
$window.alert(text);
}
};
});
</code></pre>
</p>
<p>
で、myModuleに定義されたコンポーネントを提供することができる新しいinjectorを生成して、 そいつにgreeterサービスをリクエストする。(これは通常angular bootstrapで自動的に行われる。)
</p>
<p>
<pre><code class="javascript">var injector = angular.injector(['myModule', 'ng']);
var greeter = injector.get('greeter');
</code></pre>
</p>
<p>
ハードコードの問題の解決を望んだら、今度はinjectorがアプリケーション全体を通じて存在する必要性が出ちゃった。injectorを渡すことが「デメテルの法則」を破ってしまう。これを救済するために、下の例のように、コンポーネントを生成する責務をinjectorに移譲するために、HTMLテンプレート上で宣言的な記法を使っている。
</p>
<p>
<pre><code class="html"><div ng-controller="MyController">
<button ng-click="sayHello()">Hello</button>
</div>
</code></pre>
</p>
<p>
<pre><code class="javascript">function MyController($scope, greeter) {
$scope.sayHello = function() {
greeter.greet('Hello World');
};
}
</code></pre>
</p>
<p>
AngularはHTMLをコンパイルする時、injectorに対してコントローラとそれが依存するブツのインスタンスを次々に生成するよう要求しながらng-controllerディレクティブを処理する。
</p>
<p>
<pre><code class="javascript">injector.instantiate(MyController);
</code></pre>
</p>
<p>
これは全て舞台裏で完了する。ng-controllerを使うってことは、これまでにinjectorを知っているコントローラなしで、injectorにそのクラスのインスタンスを生成するよう要求し、MyControllerの全ての依存性を満たすってことに注意しよう。
</p>
<p>
これがベストな結果。アプリケーションコードはinjectorを使ってどうこうするとかなしに、単純に必要な依存性を宣言するだけ。この仕組なら「デメテルの法則」を破らないですむ。
</p>
</section>
<section>
<p>
というようなことが書いてあって、訳しかたがうまくなくて、はっきりと理解できたわけではないが、とりあえずメモとして残しておきます。
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-86307572014141878702015-01-06T23:55:00.000+09:002015-01-06T23:55:15.005+09:00AngularJSのDIの定義の仕方<section>
<div class="separator" style="clear: both; text-align: center;"><a href="https://raw.githubusercontent.com/angular/angular.js/master/images/logo/AngularJS-Shield.exports/AngularJS-Shield-medium.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://raw.githubusercontent.com/angular/angular.js/master/images/logo/AngularJS-Shield.exports/AngularJS-Shield-medium.png" /></a></div>
</section>
<section style="margin:20px 0 0 0;">
AngularJSはDI(Dependency Injection)の機構を提供してるっつーんで、<a href="https://docs.angularjs.org/guide/di">AngularJS: Developer Guide: Dependency Injection</a>を読みつつ、使い方を纏めておくとしよう。
</section>
<section>
<h2>依存するコンポーネントをどう書くか</h2>
<p>
以下の3つの方法がある。
<ul>
<li>inline array annotation (最も好ましい方法)</li>
<li>$inject property annotation</li>
<li>関数のパラメータ名から暗黙的に注入する方法(この方法は注意が必要)</li>
</ul>
</p>
</section>
<section>
<h2>inline array annotation</h2>
<p>
<pre><code class="javascript">someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
// do something.
}]);
</code></pre>
と書くのが<code>inline array annotation</code>だと。この例で言うなら、'$scope'と'greeter'という名前で生成&登録されたオブジェクトが存在する前提で、MyControllerは$scopeとgreeterオブジェクトに依存している、ということを表現している。依存するコンポーネントの名称を文字列で並べつつ、関数のパラメータとして定義する。このとき、配列の要素の順番と関数の引数の順番が一致するよう注意する必要がある。
</p>
</section>
<section>
<h2>$inject array annotation</h2>
<p>
この方法は、仮にミニファイツールなどでコードがミニファイされて、関数のパラメータ名がツールに変更されてしまったとしても、正しく依存するオブジェクトが注入されるようにする方法、だと。
<pre><code class="javascript">var MyController = function($scope, greeter) {
// ...
}
MyController.$inject = ['$scope', 'greeter'];
someModule.controller('MyController', MyController);
</code></pre>
この例は、<code>inline array annotation</code>とよく似ているからわかりやすい。$injectに依存するオブジェクトの名前を設定する、ってことね。これも<code>inline array annotation</code>と同じく、$injectに指定する配列の要素と、関数のパラメータの順序を一致させないとダメよ。
</p>
</section>
<section>
<h2>関数のパラメータ名から暗黙的に注入する方法</h2>
<p>
で、この暗黙の注入が一番簡単なんだけど、問題も有る、と。
コードを書くとすると、
<pre><code class="javascript">someModule.controller('MyController', function($scope, greeter) {
// ...
});
</code></pre>
みたいになって、配列の順序と関数の引数の順序を一致させるとかも気にしなくていい、というメリットはある。だけど、ミニファイツールで関数の引数名が変えられちゃったら、もうAngularは正しく注入できないから、この方法は使わない方がいいみたい。
<blockquote>
However this method will not work with JavaScript minifiers/obfuscators because of how they rename parameters.
Tools like ng-annotate let you use implicit dependency annotations in your app and automatically add inline array annotations prior to minifying. If you decide to take this approach, you probably want to use ng-strict-di.
Because of these caveats, we recommend avoiding this style of annotation.
</blockquote>
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-49935589663385775982015-01-06T00:02:00.000+09:002015-01-06T23:03:25.886+09:00AngularJSのConceptual Overview<section>
<p>
AngularJSの機能やコンセプトなどよくわかってないので、<a href="https://docs.angularjs.org/guide">公式サイトのガイド</a>を読んでいる。そこには、<a href="https://code.angularjs.org/1.3.8/docs/guide/concepts">Conceptual Overview</a>なる一覧があり、例えばAngularJSのFilterとかわかっていない僕には嬉しい一覧であった。ので、自分の備忘録としてここに訳しつつ纏めておく。
</p>
</section>
<section>
<dl>
<dt>Template</dt>
<dd>追加のマークアップを持つHTML</dd>
<dt>Directives</dt>
<dd>カスタム属性、カスタム要素を持つHTMLの拡張</dd>
<dt>Model</dt>
<dd>ユーザがView上で見たり操作するデータ</dd>
<dt>Scope</dt>
<dd>モデルが格納されるコンテキスト。controller、directive、expressionからアクセスできる。</dd>
<dt>Expressions</dt>
<dd>Scopeからアクセスする変数や関数を記述する式</dd>
<dt>Compiler</dt>
<dd>Templateを解析し、directiveやexpressionsをインスタンス化する。</dd>
<dt>Filter</dt>
<dd>式の値をユーザに見せるために整形する。</dd>
<dt>View</dt>
<dd>ユーザが目にするもの。</dd>
<dt>Data Binding</dt>
<dd>Model-View間でデータを同期する。</dd>
<dt>Controller</dt>
<dd>Viewの裏側のビジネスロジック。</dd>
<dt>Dependency Injection</dt>
<dd>オブジェクトと関数を生成し、結び付ける。</dd>
<dt>Injector</dt>
<dd>DIコンテナ</dd>
<dt>Module</dt>
<dd>Injectorを構成するcontroller、service、filter、directiveなどアプリの異なるパーツのためのコンテナ。</dd>
<dt>Service</dt>
<dd>Viewから独立した再利用可能なビジネスロジック</dd>
</dl>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-75413908453338328582015-01-04T14:58:00.001+09:002015-01-04T15:03:44.727+09:00YeomanのAngularJS Full-Stack generatorが提供するジェネレータ<section>
<p>
<a href="https://github.com/DaftMonk/generator-angular-fullstack">AngularJS Full-Stack generator</a>は、アプリケーションのひな形だけでなく、アプリケーションの中身を開発する上で使えるジェネレータをいくつか提供しているってことに気づいたので纏めてみます。
</p>
</section>
<section>
<h2>angular-fullstack</h2>
<p>
アプリケーションそのものを作るジェネレータ。<code>angular-fullstack:app</code>のエイリアス。
</p>
<p>
<pre><code class="bash">$ yo angular-fullstack
</code></pre>
</p>
</section>
<section>
<p>
これ以外のジェネレータには、サーバサイドの機能を作るためのジェネレータと、クライアントサイドの機能を作るためのジェネレータ、そしてデプロイのためのジェネレータがある。
</p>
</section>
<section>
<h2>サーバサイド</h2>
<h3>angular-fullstack:endpoint</h3>
<p>
REST APIのエンドポイントを生成するジェネレータ。例えば、<code>issue</code>というリソースに対するREST APIのエンドポイントを定義する場合は、
<pre><code class="bash">$ yo angular-fullstack:endpoint issue
</code></pre>を実行する。すると、
<pre><code class="bash">? What will the url of your endpoint to be? /api/v1/issues
create server/api/issue/index.js
create server/api/issue/issue.controller.js
create server/api/issue/issue.model.js
create server/api/issue/issue.socket.js
create server/api/issue/issue.spec.js
</code></pre>となる。URLをどうするか聞かれるので、<code>/api/v1/issues</code>と入力した。モデルやコントローラ、specファイルが生成される。
</p>
</section>
<section>
<h2>クライアントサイド</h2>
<h3>angular-fullstack:route</h3>
<p>
あるURLに対するクライアントサイドのリソース一式を生成するジェネレータ。例えば、<code>/issues</code>というURLを有効にするために、
<pre><code class="bash">$ yo angular-fullstack:route issues
</code></pre>
を実行すると、
<pre><code class="bash">? Where would you like to create this route? client/app/
? What will the url of your route be? /issues
create client/app/issues/issues.js
create client/app/issues/issues.controller.js
create client/app/issues/issues.controller.spec.js
create client/app/issues/issues.jade
create client/app/issues/issues.less
</code></pre>
が得られる。
</p>
<h3>angular-fullstack:controller</h3>
<p>
クライアントサイドのコントローラを生成する。
<pre><code class="bash">$ yo angular-fullstack:controller chat
</code></pre>
を実行すると、
<pre><code class="bash">? Where would you like to create this controller? client/app/
create client/app/chat/chat.controller.js
create client/app/chat/chat.controller.spec.js
</code></pre>
が得られる。
</p>
<h3>angular-fullstack:directive</h3>
<p>
AngularJSのdirectiveを生成する。何らかのチャートを表示するためのディレクティブを作るとして、
<pre><code class="bash">$ yo angular-fullstack:directive chart
</code></pre>を実行すると、
<pre><code class="bash">? Where would you like to create this directive? client/app/
? Does this directive need an external html file? Yes
create client/app/chart/chart.directive.js
create client/app/chart/chart.directive.spec.js
create client/app/chart/chart.jade
create client/app/chart/chart.less
</code></pre>が得られる。
</p>
<h3>angular-fullstack:filter</h3>
<p>
filterって何だろう。AngularJS初心者なのでまだ知りません。
でも、
<pre><code class="bash">$ yo angular-fullstack:filter someFilter
</code></pre>を実行すると、filterのためのファイルを生成してくれる、と。
</p>
<h3>angular-fullstack:service</h3>
<p>
AngularJSのserviceを生成する。
例えば、issueというリソースに関するAPIを提供するサービスを作るとして、
<pre><code class="bash">$ yo angular-fullstack:service issue
</code></pre>を実行すると、
<pre><code class="bash">? Where would you like to create this service? client/components
create client/components/issue/issue.service.js
create client/components/issue/issue.service.spec.js
</code></pre>が得られる。同様に、<code>angular-fullstack:factory</code>、<code>angular-fullstack:provider</code>というgeneratorも存在していて、それぞれ、
<pre><code class="javascript">// yo angular-fullstack:service issue
'use strict';
angular.module('teamApp')
.service('issue', function () {
// AngularJS will instantiate a singleton by calling "new" on this function
});
</code></pre>
<pre><code class="javascript">// yo angular-fullstack:factory issue
'use strict';
angular.module('teamApp')
.factory('issue', function () {
// Service logic
// ...
var meaningOfLife = 42;
// Public API here
return {
someMethod: function () {
return meaningOfLife;
}
};
});
</code></pre>
<pre><code class="javascript">// yo angular-fullstack:provider issue
'use strict';
angular.module('teamApp')
.provider('issue', function () {
// Private variables
var salutation = 'Hello';
// Private constructor
function Greeter() {
this.greet = function () {
return salutation;
};
}
// Public API for configuration
this.setSalutation = function (s) {
salutation = s;
};
// Method for instantiating
this.$get = function () {
return new Greeter();
};
});
</code></pre>
を生成する。
</p>
<h3>angular-fullstack:decorator</h3>
<p>
公式サイトには<blockquote>Generates an AngularJS service decorator.</blockquote>とあるが、これもよくわかっていない。が、
<pre><code class="bash">yo angular-fullstack:decorator issue
</code></pre>を実行すると、
<pre><code class="bash">? Where would you like to create this decorator? client/components
create client/components/issue/issue.decorator.js
</code></pre>が得られ、
<pre><code class="javascript">'use strict';
angular.module('teamApp')
.config(function ($provide) {
$provide.decorator('issue', function ($delegate) {
// decorate the $delegate
return $delegate;
});
});
</code></pre>が生成された。
</p>
</section>
<section>
<h2>デプロイ</h2>
<p>
デプロイのためのgeneratorとしては、
<ul>
<li>yo angular-fullstack:openshift</li>
<li>yo angular-fullstack:heroku</li>
</ul>
があって、それぞれOpenShift、Herokuへのデプロイを簡単に行うためのコマンドのようだが、今回は割愛。
</p>
</section>
<section>
<h2>終わりに</h2>
<p>
filterや、service decoratorなどAngularJSを理解していないと使い方がわからないものがあり、使いこなすにはもっと勉強しないと、と感じた。あとは、クライアントサイドのディレクトリ構成を意識するというか、戦略を持たないといけないな。
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-76062427169523220352015-01-01T13:57:00.000+09:002015-01-01T13:57:06.215+09:00YeomanでAngularJS、Express、MongoDB、Node.jsなアプリのひな形を作る。<section>
<p>
<a href="http://yeoman.io/">Yeoman</a>を使ってMEAN(MongoDB、Express、AngularJS、Node.js)なWebアプリケーションのひな形を作ってみます。
</p>
</section>
<section>
<h2>AngularJS Full-Stack generator</h2>
<p>
AngularJS Full-Stack generatorというgeneratorを使用する。
<pre><code class="bash">$ npm install -g generator-angular-fullstack
</code></pre>
でインストールする。<code>-g</code>オプションを付けてglobalなパッケージとしてインストールする。
</p>
</section>
<section>
<h2>AngularJS Full-Stackを実行する。</h2>
<p>
<pre><code class="bash">$ yo angular-fullstack
</code></pre>を実行すると、generatorが次のような質問をしてくるので、適宜答えてあげる。
<ul>
<li>JavaScript、CoffeeScriptのどっちを使う?</li>
<li>HTMLとJade、どっちでマークアップする?</li>
<li>css、sass、stylus、lessのどれでスタイル書く?</li>
<li>AngularのRouterは、ngRouterとuiRouterのどっちを使う?</li>
<li>Twitter Bootstrap使う?</li>
<li>ui-bootstrapを使う?</li>
<li>MongoDBのモデリングにはmongooseを使う?</li>
<li>認証処理のboilerplateを生成する?</li>
<li>Google、Facebook、TwitterのOAuthストラテジを有効にする?</li>
<li>socket.ioを使う?</li>
</ul>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoe2XsOZXQemhg3mLE9eKFJJeZFrMu450yoR-LgQ1zgGD7yClCTATD03hcrBg0GclWbB_f7kyD-t8x048i43mUYERfa4aN8v2Mgro8EdizqnAlRKl67HZfYPYt5pce0Wka4MYS709jQic/s1600/yo10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoe2XsOZXQemhg3mLE9eKFJJeZFrMu450yoR-LgQ1zgGD7yClCTATD03hcrBg0GclWbB_f7kyD-t8x048i43mUYERfa4aN8v2Mgro8EdizqnAlRKl67HZfYPYt5pce0Wka4MYS709jQic/s320/yo10.png" /></a></div>
質問に答えていくと↑のような画面になる。ここから先は、<code>npm install</code>とか<code>bower install</code>とかYoermanが自動で進めてくれる。
</p>
</section>
<section>
<h2>生成したプロジェクト</h2>
<p>
このgeneratorによって生成したプロジェクトは↓のようなディレクトリ構造になる。
<pre><code class="bash">.
├── Gruntfile.js
├── bower.json
├── client
├── e2e
├── karma.conf.js
├── node_modules
├── package.json
├── protractor.conf.js
└── server
</code></pre>
<code>client</code>ディレクトリにはクライアントサイドのコードを、<code>server</code>ディレクトリにはサーバサイドのコードを格納するっていうのが、以前のバージョンから変わったところか。<code>e2e</code>ディレクトリの目的は詳細を調べる必要がある。
</p>
</section>
<section>
<h2>アプリケーションを起動する。</h2>
<p>
<pre><code class="bash">$ grunt serve
</code></pre>でアプリケーションが起動する。
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-70870928909453818212014-12-30T14:55:00.000+09:002014-12-30T14:55:00.669+09:00mean-cliでアプリケーションのひな形を作る。<section>
<p>
mean-cliを使ってアプリケーションのひな形を作るまでの手順を纏めてみます。
</p>
</section>
<section>
<h2>準備</h2>
<h3>NodeJS、MongoDB、Git</h3>
<p>
前提として、NodeJS、MongoDB、Gitが必要。それぞれインストールしておく。
ここでは詳細は割愛。
</p>
<h3>npmのバージョンを上げておく。</h3>
<p>
npmのバージョンが2.xでないとWARNINGが出るので、上げておく。
<pre><code class="bash">$ npm update -g npm
</code></pre>を実行する。
</p>
<h3>Grunt.jsあるいはGulp.jsをインストールしておく</h3>
<p>
meanで作成するプロジェクトは、タスクマネージャとしてGruntかGlupを選択できる。デフォルトはGrunt。両方入れておく。
<pre><code class="bash">$ npm install -g grunt-cli gulp
</code></pre>
</p>
</section>
<section>
<h2>mean-cliをインストールする。</h2>
<p>
インストールするのは、<code>mean-cli</code>。なので、
<pre><code class="bash">$ npm install -g mean-cli
</code></pre>を実行する。
</p>
</section>
<section>
<h2>mean-cliを使ってプロジェクトを作る。</h2>
<p>
インストールしたmean-cliを使って、Webアプリケーションプロジェクトを作成する。例えば、teamというプロジェクトを作るには、
<pre><code class="bash">$ mean init team
</code></pre>
を実行する。すると、アプリケーション名と利用するタスクマネージャ(GruntかGulpか、僕はGulpを選択)を問われ、答えるとプロジェクトディレクトリを生成してくれる。
</p>
</section>
<section>
<h2>npmパッケージのインストール</h2>
<p>
生成されたプロジェクトのルートに移動し、<code>npm install</code>を実行する。
<pre><code class="bash">$ cd /path/to/team
$ npm install
</code></pre>
</p>
</section>
<section>
<h2>アプリケーションの起動</h2>
<p>
アプリケーションを起動してみる。Gulpを使うよう指示したので、gulpのデフォルトタスクを起動するとアプリケーションが起動する。
<pre><code class="bash">$ gulp
</code></pre>
そして、<code>http://localhost:3000</code>にアクセスすると、↓のような画面が表示される。
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdRB3dVKHp1foyLxIvJhzfvdv2eFD5dyzsiUbmi89unzCDep5uUAw8wZqkMzRzlTlxFfHkTkhVK6Tg-CBABYa4GozOm8Xn1zk8p6oT4_17Fq0e-LEMSZbkhq6RTeRCa_mkdR3WVLHq2to/s1600/mean1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdRB3dVKHp1foyLxIvJhzfvdv2eFD5dyzsiUbmi89unzCDep5uUAw8wZqkMzRzlTlxFfHkTkhVK6Tg-CBABYa4GozOm8Xn1zk8p6oT4_17Fq0e-LEMSZbkhq6RTeRCa_mkdR3WVLHq2to/s320/mean1.png" /></a></div>
</p>
<p>
ヘッダの「Join」リンクをつつくと、ユーザ登録ページに遷移する。
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQJxB24vGjniy_EEGeMs6u5dWnqQM15yytEGLjyjXQ-Z2urd1HK6sJlbKkJTG2v8TDALBP6oEgx0QT4jHFJyBRBnQLxT9REmTYaJOghMjq6grI2V25fbGvAHhFvxiTcKLmnedHXoLv2IY/s1600/mean-join.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQJxB24vGjniy_EEGeMs6u5dWnqQM15yytEGLjyjXQ-Z2urd1HK6sJlbKkJTG2v8TDALBP6oEgx0QT4jHFJyBRBnQLxT9REmTYaJOghMjq6grI2V25fbGvAHhFvxiTcKLmnedHXoLv2IY/s320/mean-join.png" /></a></div>
</p>
<p>
また、「Log in」リンクをつつくとログインページに遷移する。
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUSJh85xJhou94Sm-B-iqgADpnn0Kt0G2GDknCN2zM_cFeI42aceoRHqJE71EE_P1jhCWuvwhdL2PUWwdZMdql9UDpAyeRlU9-KxInV5IeObIafjmqDssvBWhjH7x-f3TKedZQdk9Rm10/s1600/mean-login.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUSJh85xJhou94Sm-B-iqgADpnn0Kt0G2GDknCN2zM_cFeI42aceoRHqJE71EE_P1jhCWuvwhdL2PUWwdZMdql9UDpAyeRlU9-KxInV5IeObIafjmqDssvBWhjH7x-f3TKedZQdk9Rm10/s320/mean-login.png" /></a></div>
</p>
</section>
<section>
<p>
初めてmean-cliを使って、アプリケーションのひな形を作るところまでやってみました。
これから実際に何か作ってみます。ちなみに、あのキャラクターは、Daphneっちゅー忍者らしいですね。JenkinsとかYeomanとかキャラがおっさんだったから、ちょっと可愛いなと思いました。どうでもいいですけど。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-59424618796935376102014-11-20T08:30:00.000+09:002014-11-20T08:30:00.623+09:00PM2でnodeなWebアプリをデプロイしてみた<section>
<div class="separator" style="clear: both; text-align: center;"><a href="https://raw.githubusercontent.com/unitech/pm2/master/pres/pm2.20d3ef.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://raw.githubusercontent.com/unitech/pm2/master/pres/pm2.20d3ef.png" /></a></div></section>
<section>
<p>
npmに<a href="https://github.com/Unitech/pm2">PM2</a>というプロセスマネージャツールがあって、プロセスの起動、終了、監視などを便利に行ってくれる。実はPM2にはアプリのデプロイもできちゃうことを知ったので試してみました。
</p>
</section>
<section>
<h2>デプロイのフロー</h2>
<p>
基本的なフローは、<a href="https://github.com/Unitech/PM2/blob/development/ADVANCED_README.md#deployment">PM2/ADVANCED_README.md at development · Unitech/PM2</a>に書いてあるとおりで行けましたんで、流れを纏めておこうと思います。
</p>
</section>
<section>
<h3>ecosystem</h3>
<p>
PM2でデプロイしたいアプリケーションや、デプロイ先の情報は、jsonファイルに記述します。そのファイルのひな形を作るコマンドが、
<pre>
<code class="bash">$ pm2 ecosystem</code>
</pre>
です。このコマンドを叩くと、↓のようなファイルが生成されます。こいつを自分の環境に合わせて編集します。
<pre><code class="json">{
"apps" : [{
"name" : "API",
"script" : "app.js",
"env": {
"COMMON_VARIABLE": "true"
},
"env_production" : {
"NODE_ENV": "production"
}
},{
"name" : "WEB",
"script" : "web.js"
}],
"deploy" : {
"production" : {
"user" : "node",
"host" : "212.83.163.1",
"ref" : "origin/master",
"repo" : "git@github.com:repo.git",
"path" : "/var/www/production",
"post-deploy" : "pm2 startOrRestart ecosystem.json --env production"
},
"dev" : {
"user" : "node",
"host" : "212.83.163.1",
"ref" : "origin/master",
"repo" : "git@github.com:repo.git",
"path" : "/var/www/development",
"post-deploy" : "pm2 startOrRestart ecosystem.json --env dev"
}
}
}
</code></pre>
</p>
</section>
<section>
<h3>setup</h3>
<p>
デプロイ先にsshで接続し、アプリケーション格納ディレクトリを掘ったり何やらかんやらするコマンドが、
<pre>
<code class="bash">$ pm2 deploy ecosystem.json production setup</code>
</pre>
です。上述のecosystem.jsonを指定してdeployのsetupを行います。このままだと、デプロイ先のサーバに対して、22ポートを指定してsshで接続にいきます。sshのポート番号を指定するには、ecosystem.jsonに追記します。
<pre><code class="json">{
"apps" : [{
"name" : "API",
"script" : "app.js",
"env": {
"COMMON_VARIABLE": "true"
},
"env_production" : {
"NODE_ENV": "production"
}
},{
"name" : "WEB",
"script" : "web.js"
}],
"deploy" : {
"production" : {
"user" : "node",
"host" : "212.83.163.1",
"ref" : "origin/master",
"repo" : "git@github.com:repo.git",
"path" : "/var/www/production",
"port" : 99999, // sshポート番号
"post-deploy" : "pm2 startOrRestart ecosystem.json --env production"
},
"dev" : {
"user" : "node",
"host" : "212.83.163.1",
"ref" : "origin/master",
"repo" : "git@github.com:repo.git",
"path" : "/var/www/development",
"post-deploy" : "pm2 startOrRestart ecosystem.json --env dev"
}
}
}
</code></pre>
実際にsetupが成功すると、ecosystem.jsonで指定したpath配下に、次のようなディレクトリが作成されます。
<pre><code class="bash">foo@bar:/var/www/production$ ls -la
total 20
drwxrwxr-x 4 root root 4096 Nov 20 00:48 .
drwxrwxr-x 5 root root 4096 Nov 20 00:48 ..
-rw-rw-r-- 1 node node 48 Nov 20 00:12 .deploys
lrwxrwxrwx 1 node node 20 Nov 20 00:12 current -> /var/www/production/source
drwxrwxr-x 4 node node 4096 Nov 14 00:57 shared
drwxrwxr-x 12 node node 4096 Nov 19 00:03 source
</code></pre>
</p>
</section>
<section>
<h3>deploy</h3>
<p>
実際にデプロイするのは、
<pre>
<code class="bash">$ pm2 deploy ecosystem.json production</code>
</pre>
のコマンドです。これにより、リポジトリからのチェックアウトがなされ、ecosystem.jsonのpost-deployに指定したコマンドを実行します。デフォルトのecosystem.jsonではpm2によるプロセスの起動or再起動を行うコマンドが指定されています。例えば、npmやbowerのパッケージのインストール後に、nodeプロセスの再起動を、という場合は、↓のように書いてできました。
<pre>
<code class="javascript">{
: (省略)
"post-deploy" : "npm install && bower install && pm2 startOrRestart ecosystem.json --env production"
: (省略)
}</code>
</pre>
</p>
</section>
<section>
<h3>その他</h3>
<p>
pm2のデプロイ関連のコマンドを実行すると、/tmp/pm2-deploy.log にログが出力されます。ssh経由で発行したコマンドなども記録されますんで、デバッグやら何やらに参照するとよさそうです。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-84157378534642945992014-06-03T22:27:00.001+09:002014-11-19T00:27:35.238+09:00express.jsでconnect-assetsを使う。<section>
Railsには、asset pipelineという仕組みがあって、クライアントサイドのcoffeescriptやsassのソースを結合・圧縮してクライアントに配信することができるけど、node.js + express.jsのアプリケーションでは、同じようなことができないかな、と思って調べてみた。
</section>
<section>
<h2>connect-assets</h2>
<p>
すると、<a href="https://github.com/adunkman/connect-assets">connect-assets</a>というライブラリを発見した。connect-assetsのREADMEに、<quote>"Transparent file compilation and dependency management for Node’s connect framework in the spirit of the Rails 3.1 asset pipeline."</quote>とあるように、Rails3.1で導入されたasset pipelineの仕組みをnode.jsのconnectフレームワーク上で実現するライブラリのようで、asset pipelineのように、分割されたjavascriptファイルやcssファイルを結合・圧縮してくれる。ソースがcoffeescriptやless、stylus、sassなどを使って書かれている場合でも使える。
</p>
</section>
<section>
<h2>mincer</h2>
<p>
connect-assetsは、内部で<a href="http://nodeca.github.io/mincer/">mincer</a>を使っている。
mincerは、Railsのasset pipelineで使われている<a href="https://github.com/sstephenson/sprockets">sprockets</a>のjavascriptポーティングライブラリ。
mincerの提供する構文に従って依存するライブラリを記述すると、それらをすべて結合したファイルを生成してくれる仕組みを提供する。
mincerは、内部でjavascriptの圧縮、cssの圧縮を行う。
ソースがcoffeescriptや、less、stylus、sassなどで書かれている場合は、コンパイルした上で圧縮することもできる。
connect-assetsのデフォルトだと、mincerに対して、Javascriptの圧縮器として<a href="https://github.com/mishoo/UglifyJS">uguify-js</a>を、cssの圧縮機として<a href="https://github.com/css/csso">csso</a>を指定している。
</p>
</section>
<section>
<h2>使ってみる。</h2>
<p>
というわけで、connect-assetsを使ってみた。環境は、
<ul>
<li>node.js 0.10.28</li>
<li>express.js 4.2.0</li>
<li>connect-assets 3.0.1</li>
</ul>
</p>
</section>
<section>
<h2>インストール</h2>
<p>
npmでインストール。
<pre><code class="bash">$ npm install connect-assets --save
$ npm install less --save
</code>
</pre>
cssにlessを使っているので、lessもインストールした。(less-middlewareは使わない。)
</p>
</section>
<section>
<h2>app.jsの記述</h2>
<p>
app.jsにconnect-assetsの設定を書く。
<script src="https://gist.github.com/shimar/de4df3ccd8162c70d96b.js"></script>
↑のpathsには、ソースファイルのパスを指定する。
assets/jsはjavascriptのソースディレクトリ、assets/cssはCSSのソースディレクトリ(lessファイルもココに置いている)、componentsはbowerでインストールしたパッケージ群が入っている前提。
buildDirは、コンパイル・結合・圧縮後のファイルの出力ディレクトリ。
</p>
</section>
<section>
<h2>依存関係の定義</h2>
<p>
connect-assetsを使う上にあたり、mincerが理解できる形式で依存関係を定義したファイルを作成する必要がある。
mincerに対する依存関係の指定は、次のようなファイルで行う。
<script src="https://gist.github.com/shimar/9627ee206ea5dcd0e734.js"></script>
</p>
</section>
<section>
<h2>HTML(jade)側はどうするか?</h2>
<p>
HTML(jade)側で、connect-assetsが出力するファイルを参照するために、jadeファイルで次のコードを書く必要がある。
<script src="https://gist.github.com/shimar/f7d538077e6f9aec709b.js"></script>
</p>
</section>
<section>
<h2>buildの有無</h2>
<p>
app.jsのconnect-assetsに対する設定で、buildオプションを指定することで、build(=結合・圧縮)の有無を変更できる。<br />
デフォルトだと、
<ul>
<li>開発環境では、build無し</li>
<li>本番環境では、build有り</li>
</ul>
というオプションとなっている。この開発環境や本番環境は、NODE_ENVで切り替える。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com1tag:blogger.com,1999:blog-6564573687368239034.post-21759286010475897952014-05-06T14:33:00.000+09:002014-11-28T00:43:01.967+09:00express.jsなプロジェクトでbowerを使ってパッケージを管理する。<section>
<p>
<a href="http://bower.io/">bower</a>というパッケージ管理ツールがある。これは、Webサイト構築時に利用する様々なJavascriptやらcssといった外部のリソースを、パッケージとして管理するためのオープンソース。例えば、jQueryのバージョンが上がったからダウンロードしなくちゃとか、このライブラリはどこから持ってくればいいのか、とか、どこのディレクトリに配置すればいいの?とか、一度決めてしまえばそれでいいのだろうけど、bowerを使ってbowerの振る舞いに乗っかることで、外部のリソースに関する管理の手間が省けそう。
</p>
<p>
以前<a href="http://strix01.blogspot.com/2014/03/nodeexpressjsbootstrap3npm.html">「node(express.js)でbootstrap3を使う、npmで簡単に。」</a>を書いた際に、終わりの方に課題として、
<quote style="display:block;padding:8px;border:solid 1px #aaa;margin:10px 0 10px 0;background-color:#777;">”bootstrapのJavascriptはどうすんのさ?
これを楽する方法がまだわかっていませんorz。
node_modules/twitter-bootsrap-3.0.0の中にあるjsファイルをpublic/javascripts配下にコピーして使っているけど、これは今後の課題です。”</quote>
と書いたけど、コレ対する解にもなる。
</p>
</section>
<section>
<h2>bowerの使い方。</h2>
<p>
bowerの基本的な使い方は簡単で、npmとかgemとか使ったことのある人なら、すぐに使えると思った。具体的な使い方は、↓のリンクが参考になります。
<ul>
<li><a href="http://bower.io/">Bower - A package manager for the web</a></li>
<li><a href="http://yosuke-furukawa.hatenablog.com/entry/2013/06/01/173308">Bower入門(基礎編)</a></li>
</ul>
</p>
</section>
<section>
<h2>express.jsなプロジェクトでbowerを使う。</h2>
<p>
express.jsだとサーバーサイドで使うライブラリは、packages.jsonに書いてnpmで管理するのが基本的なパッケージ管理手法と思ってる。で、bowerはクライアントサイドで使うJavascriptやらを管理するために使う、ってことになる。
</p>
</section>
<section>
<h2>express.jsなプロジェクトにbowerを適用する。</h2>
<p>
bowerを適用するには、
<pre class="brush:bash">
$ cd express_project_root
$ bower init
</pre>
を実行する。<code>bower init</code>は、最終的にbower.jsonを出力コマンドで、いくつかの設定を対話的に入力していく。実際のbower.jsonは、
<pre><code class="json">{
"name": "プロジェクト名",
"version": "0.0.0",
"homepage": "プロジェクトページヘのURL",
"authors": [
"名前 <メールアドレス>"
],
"moduleType": [
"node"
],
"license": "MIT",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"components",
"test",
"tests"
],
}</code>
</pre>
のようになり、bowerでパッケージを管理する準備が出来た状態。
</p>
</section>
<section>
<h2>パッケージをインストールする。</h2>
<p>
例えば、jqueryを使うとする。bowerでインストールするには、
<pre><code class="bash">$ bower install jquery --save</code>
</pre>
とすると、プロジェクトルートにbower_componentsというディレクトリが生成され、その下にパッケージがインストールされる。また、<code>--save</code>オプションを指定することで、bower.jsonに書き込まれる(この仕組みは、npmと同じですね。)。
<pre><code class="bash">.
├── app.js
├── bin
├── bower.json # <= jqueryへの依存が定義される。
├── bower_components # <= この配下にパッケージがインストールされる。
├── node_modules
├── package.json
├── public
├── routes
└── views</code>
</pre>
したがって、npmやgemと同じ要領で、予め利用するパッケージがわかっているときは、bower.jsonにつらつらと書いてから、<code>bower install</code>すればいいし、後から利用するパッケージを増やす時は、<code>bower install package_name --save</code>とすれば良さそう。
</p>
</section>
<section>
<h2>パッケージのインストール先をbower_componentsを以外にする。</h2>
<p>
bowerはデフォルトで、<code>./bower_components</code>配下にパッケージをインストールする。このままだと、ビューでJavascriptを読み込むのに、<code>bower_components/jquery/dist/jquery.min.js</code>とかがscriptタグのsrc属性に登場することになるけど、bower云々がクライアント側のコードに出てくるのは避けたいので、インストール先のディレクトを変えてみる。具体的には、
<pre><code class="bash">$ less .bowerrc
{
"directory": "components",
"json": "bower.json"
}</code>
</pre>
というファイルを作って、"directory"を指定する(ここでは、componentsというディレクトリ名にしている)。そして、このディレクトをexpress.jsにスタティックなコンテンツを含むディレクトリであることを教えてあげれはよい。app.jsに↓を追記する。
<pre><code class="javascript">app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'components'))); // <= コレを追記する。</code>
</pre>
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-14581082957550868112014-04-24T01:36:00.000+09:002014-11-28T00:47:45.398+09:00three.jsで球を円運動させて太陽系の惑星を描いた。<section>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRM7nEFCLOnpZq78GoKkcP9AAfk9-4oU97QXsjvRVmtitxlhUQUxjOHdyMEV4fiHaobzBv_0c7iV_3NL0_nTd6Wij8ZT2_K31IFRjEBOGVWHUi6mQOCHxBl73754zDNoJtfJ8c7W69KVg/s1600/The+Solar+System+3D.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRM7nEFCLOnpZq78GoKkcP9AAfk9-4oU97QXsjvRVmtitxlhUQUxjOHdyMEV4fiHaobzBv_0c7iV_3NL0_nTd6Wij8ZT2_K31IFRjEBOGVWHUi6mQOCHxBl73754zDNoJtfJ8c7W69KVg/s320/The+Solar+System+3D.png" /></a></div>
<p>
three.jsの勉強中、単純なオブジェクトを円運動させる方法を知りたくて、それなら調べながら、太陽系の惑星たちの公転運動を描いてみようと思い至った。
</p>
</section>
<section>
<h2>球を描く</h2>
<p>
惑星なのでほぼ球だろう、ということでthree.jsが提供してくれているオブジェクトを使って、太陽と水星〜海王星までを球として表現してみた。3Dのオブジェクトを作るには、Geometry、Material、Meshの3つを使うのが基本だと思っていて、今回各天体を球として表現するのに、
<ul>
<li>THREE.MeshLambertMaterial</li>
<li>THREE.SphereGeometry</li>
<li>THREE.Mesh</li>
</ul>
の3つを使った。で、太陽をJavascriptのオブジェクトとして、↓のように書いてみた。
<pre><code class="javascript">Sun = function() {
this.material = new THREE.MeshLambertMaterial({ color: 0xff0000 });
this.geometry = new THREE.SphereGeometry(109, 64, 64);
this._mesh = new THREE.Mesh(this.geometry, this.material);
}
Sun.prototype = {
constractor: Sun,
get mesh() {
return this._mesh;
}
}</code>
</pre>
この太陽を3D空間に配置するには、
<pre><code class="javascript">var sun = new Sun();
scene.add(sun.mesh);</code>
</pre>
とすればいい、と。
</p>
<p>
惑星は、Planetっていうオブジェクトをprototype継承させて個々の惑星を作ってやった。Planetは、
<pre><code class="javascript">Planet = function(radiusRate, orbitalRadiusRate, color, omegaRate) {
this.radiusBase = 4;
this.orbitalRadiusBase = 400;
this.radiusRate = radiusRate !== undefined ? radiusRate : 1.0
this.orbitalRadiusRate = orbitalRadiusRate !== undefined ? orbitalRadiusRate : 1.0;
this.color = color !== undefined ? color : 0x0000ff;
this._omegaRate = omegaRate !== undefined ? omegaRate : 1;
this._material = new THREE.MeshPhongMaterial({ color: this.color });
this._geometry = new THREE.SphereGeometry(this.radiusBase * this.radiusRate, 64, 64);
this._mesh = new THREE.Mesh(this._geometry, this._material);
this._mesh.position.x = - this.orbitRadiusBase * this.orbitalRadiusRate;
this._mesh.position.z = - this.orbitRadiusBase * this.orbitalRadiusRate;
this._circleGeometry = new THREE.CircleGeometry(this.orbitalRadiusBase * this.orbitalRadiusRate, 2560);
this._circleGeometry.vertices.shift();
this._circleMaterial = new THREE.LineBasicMaterial({
color: 0x111111
// opacity: 0.1
// linewidth: 0.01
});
this._circle = new THREE.Line(this._circleGeometry, this._circleMaterial);
this._circle.rotation.x = 90 * Math.PI / 180;
};
Planet.prototype = {
constractor: Planet,
get material () {
return this._material;
},
get geometry () {
return this._geometry;
},
get mesh () {
return this._mesh;
},
get circle() {
return this._circle;
},
pivot: function(time) {
var theta = 1.047 / this._omegaRate * time;
this._mesh.position.x = Math.cos(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
this._mesh.position.z = Math.sin(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
}
};</code>
</pre>
のようなオブジェクトになった。コンストラクタの引数<code>radiusRate</code>と<code>orbitalRadiusRate</code>は、それぞれ地球の半径を1として何倍か、地球の公転軌道半径を1として何倍か、を指定するようにした。それと、omegaRateっていうのは、地球の公転の角速度(rad/s)を1として何倍か、を指定するもので、公転運動の処理で使ってる。さらには、一応公転軌道(=円)を3D空間に表示しようと思って、circleっていう属性を定義した。円を描くのも、例のGeometry,Material,Meshの3点セットが必要だけど、three.jsは円に特化したオブジェクトを定義していて、実際に使ったのは、
<ul>
<li>THREE.CircleGeometry</li>
<li>THREE.LineBasicMaterial</li>
<li>THREE.Line</li>
</ul>
の3つ。これもsceneに追加してあげないと表示されないから、例えば、地球は、
<pre><code class="javascript">Earth = function() {
Planet.call(this, 1.0, 1.0, 0x0000ff, 1.0);
};
Earth.prototype = Object.create(Planet.prototype);</code>
</pre>
というオブジェクトを書いて、
<pre><code class="javascript">var earth = new Earth();
scene.add(earth.mesh);
scene.add(earth.circle);</code>
</pre>
としてあげた。
</p>
<p>
</p>
</section>
<section>
<h2>円運動</h2>
<p>
円運動は、単位時間あたり何ラジアン進むか、が重要。で、今回は試しに1年を1分に見立てて色々と計算してみた。つまり、地球は1分かけて太陽の周りを1周する。その場合の地球の角速度は1.047(rad/sec)になった(あってます?)ので、これを使って瞬間瞬間の座標を計算してオブジェクトの位置を変えていけばよさそうだ、と。
</p>
<p>
で、今回のは、y=0平面上で公転させるってことにすると、xとzの値を時間と角速度と半径から求めることができるなぁ、と思い、結果出来たのが上述のPlanetオブジェクトのpivotというメソッド(↓再掲)。
<pre><code class="javascript">pivot: function(time) {
var theta = 1.047 / this._omegaRate * time;
this._mesh.position.x = Math.cos(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
this._mesh.position.z = Math.sin(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
}</code>
</pre>
</p>
</section>
<section>
<h2>実際に動かしてみる</h2>
<p>
実際に動くページを<a href="http://simalabs.com/labs/3d/solarsystem">The Solar System 3D</a>で公開しました。マウスでグリグリ、コロコロできたり。とりあえず、当初の目的であった、オブジェクトを円運動させる方法はわかったので良かった。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-81200330413015897462014-03-30T23:12:00.000+09:002014-03-30T23:18:03.621+09:00node(express.js)でcsrf対策する。<section>
<p>
node(express.js)でcsrfに対する対策を施す方法について書いてみる。といっても、express.jsはcsrf対策のためのミドルウェアを提供しているので、その使い方の話。(ここで使っているexpress.jsのバージョンは3.4.8です。)
</p>
</section>
<section>
<h2>express.jsのcsrfミドルウェア</h2>
<p>
express.jsが提供するミドルウェアに、<a href="http://expressjs.com/3x/api.html#csrf">csrf</a> っていうのがあってコレを使うと簡単にcsrf対策ができる。
</p>
</section>
<section>
<h2>使い方 - app.js</h2>
<p>
expressコマンドでアプリケーションを作ると、app.jsというファイルが出来て、この中にアプリケーションやサーバの設定を書くんだけど、その中で次のコードを書く。
<pre class="brush:javascript">
// use session support.
app.use(express.session());
// use csrf middleware.
app.use(express.csrf());
app.use(function(req, res, next) {
res.locals._csrf = req.csrfToken();
next();
});
</pre>
前述の<a href="http://expressjs.com/3x/api.html#csrf">このページ</a>にあるとおり、csrfミドルウェアを使うには、session()よりも下に書けってあるので、注意が必要。
</p>
</section>
<section>
<h2>使い方 - view</h2>
<p>
csrfミドルウェアが生成してくれるトークンをformに埋める必要があるので、viewでformを書くときには、
<pre class="brush:javascript">
form(action='/some_action', method='form')
input(type='hidden', name='_csrf', value='#{_csrf}')
:
</pre>
のように、hiddenに_csrfのトークンを埋めておく。(これはテンプレートエンジンにjadeを使った場合の例)
</p>
</section>
<section>
<p>
これで、postなリクエストにcsrfトークンが含まれていなかったり、不正なトークンが含まれていると、expressが検出してエラーを上げてくれるようになる。
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-78375263619011500552014-03-23T14:10:00.000+09:002014-03-23T14:10:11.497+09:00twitter-bootstrapを使う時のベーシックなlayout.jade<section>
twitter-bootstrapをexpressjsなアプリに適用するにあたって、jadeのレイアウト(layout.jade)にbootstrapのcssとjavascriptを埋めます。ベーシックなレイアウトをgistに上げました。
</section>
<script src="https://gist.github.com/shimar/9719033.js"></script>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-9732628480962305272014-03-23T12:52:00.000+09:002014-03-23T12:52:53.638+09:00node(expressjs)なアプリをデプロイする、capistrano3で簡単に。<section>
node(expressjs)なアプリを作って、capistrano2でデプロイしていたのだけど、<a href="http://capistranorb.com/">capistrano3</a>が登場してずいぶんスマートになったとのことで、capistrano3に載せ替えてみた、という話です。
</section>
<section>
<h2>capistranoって何?</h2>
<p>
失礼なほどざっくり言ってしまえば、capistranoはrubyで書かれたデプロイツールで、gitやsvnなどのリポジトリからモジュールを取得、デプロイ先のしかるべきディレクトリに配置し、dbの変更、assetsの生成、プロセスの再起動なんかを自動でやってくれるすぐれものです。
capistrano2っていうのが長く広く使われていたところに、capistrano3が登場していろいろとスマートになったようです。
</p>
</section>
<section>
<h2>capistrano + node</h2>
<p>
nodeなアプリを対象とするにあたり、リモート(デプロイ先)でのnodeのパスを正しく設定したり、npmでライブラリ群をインストールしたり、っていうところをどうやるのか、というのが肝になるのかなぁ、と思っていたら、
<ul>
<li><a href="https://github.com/koenpunt/capistrano-nvm">capistrano-nvm</a></li>
<li><a href="https://github.com/capistrano/npm">capistrano-npm</a></li>
</ul>
っていうのが既にあったので、使わせて頂きました。
</p>
</section>
<section>
<h2>capistrano-nvm</h2>
<p>
capistrano上で動作するnvmタスクを提供してくれる。
ローカルなnvmにも、システムワイドなnvmにも対応している。僕のサーバはnvmをシステムワイドで入れているので助かった。(<a href="http://strix01.blogspot.com/2013/07/node-nvm.html">[node] nvmをシステムワイドに適用する。</a>)
</p>
</section>
<section>
<h2>capistrano-npm</h2>
<p>
capistrano上で動作するnpmタスクを提供してくれる。
Railsアプリのデプロイプロセスでbundle installを実行するように、npm installを走らせる。
もともとcapistrano-npmだけ追加してやったらnpmのパス(、つまりnode関連のパス)が解決できずどうしたものか、とはまっていたところに、capistrano-nvmと併せて使ったらば解決できたので、セットで使うのがいいのかと。
</p>
</section>
<section>
<h2>deploy</h2>
<p>
実際にデプロイするには、
<ol>
<li>リモートホスト(デプロイ先ホスト)の環境設定</li>
<li>capistranoのインストール</li>
<li>capistrano-nvmのインストール</li>
<li>capistrano-npmのインストール</li>
<li>Capfile, deploy.rbの作成</li>
<li>deploy</li>
</ol>
という流れになりますね。
</p>
</section>
<section>
<h2>リモートホスト(デプロイ先ホスト)の環境設定</h2>
<p>
リモートで作業するユーザとSSHの設定が基本になります。
ユーザ作って、ディレクトリ掘って、SSHでフォワードできれば良さそう。
capistranoの本家サイトにある、<a href="http://capistranorb.com/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a>のページのとおりにやりました。
</p>
</section>
<section>
<h2>capistrano,capistrano-nvm,capistrano-npmのインストール</h2>
<p>
gemコマンドでも、bundle経由でもいいと思います。今回はgemコマンド叩いてインストールしてしまいました。
<pre class="brush:bash">
$ gem install capistrano
$ gem install capistrano-nvm
$ gem install capistrano-npm
</pre>
</p>
</section>
<section>
<h2>Capfile, deploy.rbの作成</h2>
<p>
ここがcapistrano2から変わったところの1つで、2の頃はcapifyっていうコマンドがあって、一番最初にcapifyしていたのが、
cap installに変わりました。
cap install すると、Capfileとdeploy.rbとかstaging.rbとかproduction.rbが作られます。環境別の設定ファイルのひな形が生成されます。いわゆるマルチステージに対応しています。stagingっていうのは、順productionというのか、本番の手前っていう位置づけの環境と考えるといいと思います。
</p>
<p>
Capfileではそのプロジェクトにおけるcapistranoの環境を書きます。
deploy.rbとdeploy/*.rbには、デプロイに関する詳細やタスクを書きます。
自作でタスクを作る場合は、lib/capistrano/tasksに拡張子.capを作ります。
</p>
<p>
今回は、カスタムタスクはなしで、Capfile、deploy.rb、production.rbだけ弄って、それぞれ次のように書きました。
<pre class="brush:ruby">
# Capfile
# Load DSL and Setup Up Stages
require 'capistrano/setup'
# Includes default deployment tasks
require 'capistrano/deploy'
# Includes tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
# https://github.com/capistrano/rvm
# https://github.com/capistrano/rbenv
# https://github.com/capistrano/chruby
# https://github.com/capistrano/bundler
# https://github.com/capistrano/rails
#
# require 'capistrano/rvm'
# require 'capistrano/rbenv'
# require 'capistrano/chruby'
# require 'capistrano/bundler'
# require 'capistrano/rails/assets'
# require 'capistrano/rails/migrations'
require 'capistrano/nvm' # <= 追加
require 'capistrano/npm' # <= 追加
# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
</pre>
<pre class="brush:ruby">
# config/deploy.rb
# config valid only for Capistrano 3.1
lock '3.1.0'
set :application, 'application_name'
set :repo_url, 'ssh://hostname.your.repo/path/to/your_repo.git'
# Default branch is :master
# ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }
# Default deploy_to directory is /var/www/my_app
# set :deploy_to, '/var/www/my_app'
set :deploy_to, '/var/www/application_name'
# Default value for :scm is :git
# set :scm, :git
# Default value for :format is :pretty
# set :format, :pretty
# Default value for :log_level is :debug
# set :log_level, :debug
# Default value for :pty is false
# set :pty, true
# Default value for :linked_files is []
# set :linked_files, %w{config/database.yml}
# Default value for linked_dirs is []
# set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
set :linked_dirs, %w{log node_modules}
# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }
# Default value for keep_releases is 5
# set :keep_releases, 5
set :nvm_type, :system
set :nvm_node, 'v0.10.26'
set :nvm_map_bins, %w{node npm}
namespace :deploy do
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
# Your restart mechanism here, for example:
# execute :touch, release_path.join('tmp/restart.txt')
execute :sudo, :restart, 'name_of_upstart_script'
end
end
after :publishing, :restart
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
# Here we can do anything such as:
# within release_path do
# execute :rake, 'cache:clear'
# end
end
end
end
</pre>
</p>
</section>
<section>
<h2>deploy</h2>
<p>
ここまで準備ができたところで、デプロイします。
capistrano2の頃のように、cap deploy:setupとかはもう要らない。いきなり、
cap deployでよい。
<pre class="brush:bash">
$ cap production deploy
</pre>
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-10250306365101216132014-03-14T01:07:00.000+09:002014-03-16T15:54:11.988+09:00node(express.js)でbootstrap3を使う、npmで簡単に。<section>
express.jsを使ったnodeなWebアプリを作っていて、twitter-bootstrap使いたいな、と思った。かつて、bootstrap2の頃、本家からダウンロードして、cssとjavascriptをpublicに置いてできたー、とか思ったこともあったけど、npmとかないのかな?って思って探したらあった、じゃあ使ってみよう、という話です。
</section>
<section>
<h2>less-middlewareとtwitter-bootstrap-3.0.0</h2>
<p>
今回使ってみたのは、
<ul>
<li><a href="https://www.npmjs.org/package/less-middleware">less-middleware</a></li>
<li><a href="https://www.npmjs.org/package/twitter-bootstrap-3.0.0">twitter-bootstrap-3.0.0</a></li>
</ul>
の2つです。
less-middlewareは、express.jsがデフォルトで使用するメタCSS。twitter-bootstrap-3.0.0は、自分でpackage.jsonに書いてインストールしましたよ。
<pre class="brush:javascript">
{
"name": "appname",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "3.4.8",
"jade": "*",
"less-middleware": "*",
"twitter-bootstrap-3.0.0": "*",
:
}
}
</pre>
</p>
</section>
<section>
<h2>app.jsでless-middlewareの設定を書く。</h2>
<p>
twitter-bootstrap-3.0.0がインストールできたらば、app.jsに手を入れます。<br />
いろいろとmiddlewareの登録をしている部分で、
var bootstrapPath = path.join(__dirname, 'node_modules', 'twitter-bootstrap-3.0.0');
<pre class="brush:javascript">
app.use(require('less-middleware')({
src: path.join(__dirname, 'assets', 'less'),
paths: [path.join(bootstrapPath, 'less')],
dest: path.join(__dirname, 'public', 'stylesheets'),
prefix: '/stylesheets'
}));
</pre>
のようにless-middlewareを登録します。この記述は、
<ul>
<li>lessのソースは、assets/less配下に置く。</li>
<li>bootstrapPathの下のlessもlessのコンパイル対象に含める。</li>
<li>コンパイルして出来たcssファイルは、public/stylesheets配下に置く。</li>
<li>prefixは、lessのページに"Path which should be stripped from the public pathname."とあるけど、イマイチよくわかっていません。</li>
</ul>
という具合になります。<br />
これで、bootstrapのlessはnpmに任せられるようになります。bootstrapをカスタマイズするには、assets/lessの下の自前lessファイルに書いていけば、カスタマイズできる、と。
</p>
</section>
<section>
<h2>2014-03-16追記</h2>
<p>
less-middlewareのバージョンが上がると、上述のオプションの指定の仕方が変わるそうで。
<a href="https://github.com/emberfeather/less.js-middleware/wiki/Migration-0.1.x-0.2.0">Migration 0.1.x 0.2.0 · emberfeather/less.js-middleware Wiki</a>に詳しい説明がありますね。0.2.1-betaっていうのが今の時点で使えて、上の指定をするとエラーとなるので、次のように直したら、うまくいった。
<pre class="brush:javascript">
var less = require('less-middleware');
var bootstrapPath = path.join(__dirname, 'node_modules', 'twitter-bootstrap-3.0.0');
app.use(less(path.join(__dirname, 'assets', 'less'),
{ dest: path.join(__dirname, 'public'),
preprocess: {
path: function(pathname, req) {
return pathname.replace('/stylesheets', '');
}
}
},
{ paths: [path.join(bootstrapPath, 'less')] }
));
</pre>
</p>
</section>
<section>
<h2>bootstrapのJavascriptはどうすんのさ?</h2>
<p>
これを楽する方法がまだわかっていませんorz。<br />
node_modules/twitter-bootsrap-3.0.0の中にあるjsファイルをpublic/javascripts配下にコピーして使っているけど、これは今後の課題です。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-35999599040752922722014-01-26T13:32:00.000+09:002014-01-26T13:32:54.681+09:00rails+MySQLでdouble型カラムを扱うモンキーパッチ<section>
<h2>背景</h2>
<p>
ruby2.1とrails4を使ってアプリを作っている。DBはMySQLを使っていて、わけあってあるテーブルの列をdouble型にしたいと思って。
カラムの列を変更するmigrationを作ろうと思った時に、そもそもdouble型のカラムを作るにはどうするんだっけ、ってなって、
Webを調べてみて、解がみつかったので試したところ、ちょっと不都合が生じて、それじゃあモンキーパッチを書いてみよう、という話です。
</p>
</section>
<section>
<h2>MySQLのdouble型を利用するmigration</h2>
<p>
まず、MySQLのdouble型の列を使うには、
<pre class="brush:ruby">
add_column :table_name, :column, :float, limit: 53
</pre>
のようなmigrationを書くとできる。(これは、既存のテーブルにカラムを追加するmigration)
</p>
<p>
型に:floatを指定して、:limitに53を指定する。参考にしたのは、
<ul>
<li><a href="http://stackoverflow.com/questions/3099785/what-is-rails-migration-equivalent-to-mysqls-double-datatype">What is Rails' migration equivalent to MySQL's 'double' datatype? - Stack Overflow</a></li>
<li><a href="http://jblevins.org/log/rails-and-mysql-types">Rails Migrations and MySQL Types</a></li>
</ul>
limit: 53は、MySQLのfloat型に精度を指定して定義する際に、精度が24〜53の場合は倍精度な浮動小数点型として扱われ、すなわちdouble型になるから、という風に理解している。(<a href="http://dev.mysql.com/doc/refman/5.6/en/floating-point-types.html">MySQL :: MySQL 5.6 Reference Manual :: 11.2.3 Floating-Point Types (Approximate Value) - FLOAT, DOUBLE</a>)
</p>
</section>
<section>
<h2>問題点</h2>
<p>
上述のmigrationでカラムを追加すると、確かにdouble型のカラムになる。が、問題点が1つ。<tt>bundle exec rake db:migrate</tt>した時に、<tt>db/schema.rb</tt>が更新されるんだけど、このファイル内の当該カラムには、<tt>limit: 53</tt>が指定されない。結果、<tt>bundle exec rake db:test:prepare</tt>で、テスト環境のスキーマを更新した時に、当該カラムの型は<tt>float</tt>として作成されてしまい、期待どおりにデータが扱えなくなってしまう。
</p>
<p>
ついでにいうと、本来double型を使いたいのに、<tt>:float, limit: 53</tt>って書くのもの、ちょっと違和感ありますね。
</p>
</section>
<section>
<h2>モンキーパッチ</h2>
<p>
db/schema.rbを手で直すってのも、あれなんで、なんとかならないものか、思って調べ始めたら、次のようなページを発見。
<div>
<a href="http://gavin-mulligan.tumblr.com/post/4057986701">Gavin Mulligan • Hacking a Double Column Type into Rails 3</a>
</div>
このページのハックを適用すると、
<pre class="brush:ruby">
#add_column :table_name, :column, :float, limit: 53
# が↓のように書けるようになる。
add_column :table_name, :column, :double
</pre>
となり、問題点の2つ目に対する解になりそう。が、db/schema.rbの問題は解決しないなぁ。もうちょっと調べるか、と思ってrailsのソースをみてたら、<tt>ActiveRecord::ConnectionAdapters::Column</tt>というクラスの<tt>extract_limit(sql_type)</tt>というメソッドをみつけた。このメソッドは、どうやらSQLの型をみて、db/schema.rbを吐き出すときに<tt>:limit</tt>に何を指定するかを判断するものっぽい。各RDBMS用のアダプターでこれらをオーバーライドしているし。
<div>
<a href="https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/column.rb">rails/activerecord/lib/active_record/connection_adapters/column.rb at master · rails/rails</a>
</div>
<div>
<a href="https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb">rails/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb at master · rails/rails</a>
</div>
</p>
<p>
ということで、次のようなモンキーパッチを<tt>config/initializers/add_double_to_activerecord.rb</tt>として、作っておくことに。
<pre class="brush:ruby">
module CustomColumnTypes
def double(*args)
if args.last.is_a? Hash
args.last[:limit] = 53
args.last[:null] = true
end
float *args
end
end
module ColumnWithDouble
def extract_limit(sql_type)
case sql_type
when /double/i
53
else
$1.to_i if sql_type =~ /\((.*)\)/
end
end
end
module ActiveRecord
module ConnectionAdapters
class Table
include CustomColumnTypes
end
class TableDefinition
include CustomColumnTypes
end
class Column
prepend ColumnWithDouble
end
end
end
</pre>
</p>
<p>
これで<tt>db/schema.rb</tt>にも無事に<tt>limit: 53</tt>が出力されるようになった。
</p>
</section>
<section>
<h2>課題</h2>
<p>
上のパッチでは、<tt>ActiveRecord::ConnectionAdapters::Column</tt>に対して振る舞いを変えているんだけど、僕がdoubleをサポートしたいのはMySQLの場合のだけだから、実はうまくない。なので、MySQL用のアダプタをイジる方法に変えるべきだなぁ、と思ってます。
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-39548340621431830512014-01-12T22:23:00.001+09:002014-01-12T22:28:42.143+09:00railsでREST Web APIをつくってrspecでテストする。<section>
<p>
railsでRESTfulなAPIを書いていて、テストはrspecを使うと決めていたのだが、対象がRESTful APIということで、
何か気にすることはあるのだろうか。テストというか、設計というか、これまで実践していたことと、
今回調べて新たに発見したことを合わせて、纏めておく。
</p>
</section>
<section>
<h2>テスト対象</h2>
<p>
テスト対象は、rails4で作ったRESTfulなAPI。全てのAPIはJSONフォーマットのみ対応。
つまり、htmlとかxml形式の応答はしない。今回試したのはRails4。
</p>
</section>
<section>
<h2>rspecとその他のgem</h2>
<p>
テスト環境にいくつかgemを追加して、テストの準備をする。
追加するのは、
<ul>
<li><a href="https://github.com/rspec/rspec-rails">rspec-rails</a></li>
<li><a href="https://github.com/colszowka/simplecov">colszowka/simplecov</a></li>
<li><a href="https://github.com/guard/guard-rspec">guard/guard-rspec</a></li>
<li><a href="https://github.com/rails/spring">rails/spring</a></li>
<li><a href="https://github.com/thoughtbot/factory_girl_rails">facoty_girl_rails</a></li>
</ul>
の各gem。それぞれのgemの用途と設定をちょっと書きます。
</p>
</section>
<section>
<h2>rspec</h2>
<p>
テストを記述する。rspec、railsアプリのrspecでのテストの仕方は、
<ul>
<li><a href="http://magazine.rubyist.net/?0021-Rspec">スはスペックのス 【第 1 回】 RSpec の概要と、RSpec on Rails (モデル編)</a></li>
<li><a href="http://magazine.rubyist.net/?0023-Rspec">スはスペックのス 【第 2 回】 RSpec on Rails (コントローラとビュー編)</a></li>
<li><a href="http://magazine.rubyist.net/?0032-TranslationArticle">海外記事翻訳シリーズ 【第 1 回】 RSpec ベストプラクティス</a></li>
</ul>
が参考になる。
</p>
<h3>railsアプリのテストでrspecを利用するための手順</h3>
<p>
<h3>-T付きでrails newする。</h3>
<p>
デフォルトのrailsアプリのテストは、Test::Unitが使われ、test用のディレクトリが生成される。-TオプションをつけるとTest::Unitが無効になり、testというディレクトリが生成されない(rspecのテストコードは、specディレクトリに入れる。)
<pre class="brush:bash">
$ rails new application_name -T
</pre>
</p>
<h3>Gemfileの記述</h3>
<p>
Gemfileに以下を追加する。
<pre class="brush:ruby">
group :development, :test do
gem 'rspec-rails'
end
</pre>
</p>
<h3>bundle installの実行</h3>
<p>
bundlerを使ってrpsecをインストールする。
<pre class="brush:bash">
$ bundle install
</pre>
</p>
<h3>rspecの初期設定</h3>
<p>
rspecをrailsアプリに組み込むと、railsコマンドのgeneratorにrspec:installが追加される。
追加されているかは、rails g -hを実行すれば確認できる。
<pre class=brush:bash">
$ rails g -h
(略)
Rspec:
rspec:controller
rspec:helper
rspec:install
rspec:integration
rspec:mailer
rspec:model
rspec:observer
rspec:scaffold
rspec:view
(略)
</pre>
rspec:installを実行して、specディレクトリを作るとともに、spec_helper.rbを生成する。
<pre class="brush:bash">
$ rails g rspec:install
</pre>
ここまでが、rails上でrspecを使うためのベーシックな手順。
</p>
</p>
</section>
<section>
<h2>simplecov</h2>
<p>
simplecovは、ruby用のコードカバレッジ計測ツールで、railsでも使える。
rspecとも簡単に連動できるし、生成されるレポートも見やすい。
</p>
<h3>Gemfileの記述</h3>
<p>
Gemfileに以下を追加する。
<pre class="brush:ruby">
group :development, :test do
gem 'simplecov'
end
</pre>
</p>
<h3>bundle installの実行</h3>
<p>
bundlerを使ってsimplecovをインストールする。
<pre class="brush:bash">
$ bundle install
</pre>
</p>
<h3>rspecとsimplecovの連携</h3>
<p>
spec/spec_helper.rbの先頭に次のコードを追加するだけで、rspecが動くたびにカバレッジを計測してくるようになる。
計測結果は、デフォルトではcoverageディレクトリにhtmlファイルとして出力される。
<pre class="brush:ruby">
require 'simplecov'
SimpleCov.start 'rails'
</pre>
</p>
</section>
<section>
<h2>guard-rspec</h2>
<p>
rspecを使ってテストを書いている場合、コードを直してspecを直して、rake specで全てのテストが問題なく通ることを確認して、というサイクルで開発していくことになる(このサイクル自体はrspecを使う場合に限らないけど。)。この時に修正したモジュールに対するspecの実行とか、全てのspecの実行とか、いちいちコマンドを叩いているのが面倒になる。そんなとき、guardを使うとspecの実行を自動化できるようになる。guardは、プロジェクト内のファイルの変更を監視して、変更が発生すると、ある動作を実行する、というもの。なので、rubyファイルやspecファイルをguardに監視させて、変更が発生したらテストを実行する、というように使う。
<div>
<a href="http://railscasts.com/episodes/264-guard?language=ja&view=asciicast">#264 Guard - RailsCasts</a>
</div>
<br />
に詳しい説明があってとても参考になる。
</p>
<h3>Gemfileの記述</h3>
<p>
Gemfileに以下を追加する。
<pre class="brush:ruby">
group :development, :test do
gem 'guard-rspec'
end
</pre>
</p>
<h3>bundle installの実行</h3>
<p>
bundlerを使ってgurad-rspecをインストールする。
<pre class="brush:bash">
$ bundle install
</pre>
</p>
<h3>guardの設定</h3>
<p>
guardは、Guardfileの記述に従って動作する。Guardfileは、
<pre class="brush:bash">
$ bundle exec guard init rspec
</pre>
で生成する。Guardfileに監視対象と、実行するspecの組み合わせを追加していくのだけど、これについては後述する。
</p>
<h3>guardの実行</h3>
<p>
guardを実行するには、
<pre class="brush:bash">
$ bundle exec guard
</pre>
とする。すると、
<pre class="brush:bash">
13:36:21 - INFO - Guard is using NotifySend to send notifications.
13:36:21 - INFO - Guard is using TerminalTitle to send notifications.
13:36:21 - INFO - Guard::RSpec is running
13:36:21 - INFO - Guard is now watching at '監視対象パス'
[1] guard(main)>
</pre>
と表示され、監視が始まる。guardのプロンプトで、"all"(またはEnter)と打つと、全てのspecが実行される。
</p>
</section>
<section>
<h2>spring</h2>
<p>
guardを使ってrspecを動かす手間がかなり省けるようになると、次に気になるのがspecの実行時間。specの量が増えてくると、実行時間が長くなるし、そもそも起動時間も長くなって時間が勿体無く感じてくる。
springを使うと、railsの環境を先読みしてくれるようになるので、様々なプロセスの起動が速くなる。これをguardと組み合わせて使うことで、guardが実行するrspecを高速化することができる。
</p>
<h3>Gemfileの記述</h3>
<p>
Gemfileに以下を追加する。
<pre class="brush:ruby">
group :development, :test do
gem 'spring'
end
</pre>
</p>
<h3>bundle installの実行</h3>
<p>
bundlerを使ってspringをインストールする。
<pre class="brush:bash">
$ bundle install
</pre>
</p>
<h3>guardとspringの連携</h3>
<p>
guardとspringを合わせて使うには、Guardfileをちょっと修正するだけでよい。
<pre class="brush:ruby">
guard :rspec, spring: true do # spring: true を追加する。
:(略)
end
</pre>
</p>
</section>
<section>
<h2>factory_girl</h2>
<p>
railsでrspecを使うときのテストデータに関して面倒なことがある。デフォルトだと、spec/fixturesディレクトリにテーブル(model)単位にymlファイルを作ってテスト時にロードして、っていうやり方になるけど、これだとモデル間のリレーションを考慮したテストデータづくりが非常に面倒くさいし、データが増えると管理できなくなる。この問題は、facotyr_girlを使うことで対応できる。factory_girlは、fixturesに定義していたymlをrubyで記述できるDSLを提供してくれている。そのため、データの定義やデータ間の関連がスッキリ書けるようになる。
</p>
<p>
<ul>
<li><a href="http://strix01.blogspot.jp/2014/01/railsfactorygirl.html">strix01: railsでテストデータの管理にfactory_girlを使うのが良さそう。</a></li>
<li><a href="http://www.func09.com/wordpress/archives/532">[rails]has_manyなフィクスチャを書くのに疲れたらFactory Girlがオススメ! - func09</a></li>
<li><a href="http://blog.livedoor.jp/sasata299/archives/51931175.html">factory_girl で最低限知っておきたい4つの使い方 - (゚∀゚)o彡 sasata299's blog</a></li>
</ul>
などが参考になる。
</p>
<h3>Gemfileの記述</h3>
<p>
Gemfileに以下を追加する。
<pre class="brush:ruby">
group :development, :test do
gem 'factory_girl_rails'
end
</pre>
</p>
<h3>bundle installの実行</h3>
<p>
bundlerを使ってfactory_girlをインストールする。
<pre class="brush:bash">
$ bundle install
</pre>
</p>
</section>
<section>
<h2>JSONを返すRESTなAPI</h2>
<p>
ここまではどちらかというと、あまりJSONとかRESTとかとは直接関係しない、rspecを使ったテストを効率良く進めるための話題。
ここからはJSONを返すRESTなAPIのテストに関する話題。
</p>
<p>
<ul>
<li><a href="http://blog.inouetakuya.info/entry/2013/10/27/200111">Rails でつくる API のテストの書き方(RSpec + FactoryGirl) - 彼女からは、おいちゃんと呼ばれています</a></li>
<li><a href="http://matthewlehner.net/rails-api-testing-guidelines/">Rails API Testing Best Practices With RSpec</a></li>
</ul>
にもろに影響を受けている。
</p>
</section>
<section>
<h2>APIのバージョニングを考慮する。</h2>
<p>
実際に経験したことでは、スマートフォンアプリをクライアントとするAPIを作っていて、アプリの機能を追加・変更して行く過程で、
API自体にバージョンの概念が必要になって、APIのリソースのURLにバージョン番号を埋めた、ってことがある。具体的には、例えばユーザ情報を取得するAPIが、
<pre>
https://api.exapmle.com/users/id.json?id=xxxx
</pre>
のように定義していて、ある時点から応答するデータの内容が大幅に変える必要がある、という場合。やったのは、
<pre>
https://api.exapmle.com/v2/users/id.json?id=xxxx
</pre>
という新しいURLを定義して、元々のAPIと並行して運用するということをした。このやり方(URLにバージョンを埋める)は、Twitter APIやFoursquare APIでも同じようなやり方をしているので、結構メジャーなソリューションなのかと思っている。railsでの実現方法は、
<br />
<div>
<a href="http://railscasts.com/episodes/350-rest-api-versioning?language=ja&view=asciicast">#350 REST API Versioning - RailsCasts</a>
</div>
<br />
が参考になる。
</p>
</section>
<section>
<h2>APIのフォーマットをJSONに限定する。</h2>
<p>
railsのコントローラをgenerateコマンドで定義すると、デフォルトではhtmlを応答するアクションが生成されるけど、APIを作っている場合、htmlを応答することはまず無いし、一度JSONを返すと決めたら、後々xmlだとか他のフォーマットに対応させる、という変更が発生することも少ないのではないか、と思っている。なので、始めからJSONのみに限定したAPIにしてしまえば、設計もテストも楽になると考えた。
</p>
<p>
railsであるURLがデフォルトでJSONのみに対応するようにするには、
<ul>
<li>routes.rb</li>
<li>controller</li>
<li>view</li>
</ul>
を意識的にイジる必要がある。
</p>
<h3>config/routes.rb</h3>
<p>
例えば、ユーザ情報に関するAPIをrailsのresourcesを使いつつ、JSONに限定する場合は、
<pre class="brush:ruby">
namespace :v1, defaults: { format: 'json' } do
resources :users
end
</pre>
としてあげると、通常必要となるURLの最後の".json"が不要となる。
</p>
<h3>controller</h3>
<p>
コントローラ側でJSONのみに対応させるには、
<pre class="brush:ruby">
module V1
class UsersController < ApplicationController
respond_to :json
def show
@user = User.find(id: params[:id])
end
end
end
</pre>
のように、先頭でrespond_toを読んであげれば個々のアクションでrespond_toを書く必要がなくなる。
</p>
<h3>view</h3>
<p>
JSON形式の応答も、独立したviewを作成することができる(知らなかった・・)。rails3.2から導入されたjbuilderというgemを使って、例えば上述のusers#showに対するviewは、app/views/v1/users/show.json.jbuilder というファイルを作ればよい。
</p>
<p>
jbuilderに関する解説もRailsCastの、
<div>
<a href="http://railscasts.com/episodes/320-jbuilder?language=ja&view=asciicast">#320 Jbuilder - RailsCasts</a>
</div>
<br />
がわかりやすい。簡単にJSONのviewが作れるので感動的。
</p>
</section>
<section>
<p>
ここまでは、JSONを返すAPIの設計の話だったけど、次はテストの話。
</p>
</section>
<section>
<h2>テストは、Request Specに書く。</h2>
<p>
前述の「<a href="http://matthewlehner.net/rails-api-testing-guidelines/">Rails API Testing Best Practices With RSpec</a>」によると、APIのテストは、(Controller Specではなく、)Request Specに書くべき、ということらしい。
APIの呼び出しと応答(JSON)をテストする場合は、コントローラ単体というよりは、ルーティング、コントローラ、モデルなど各スタック間のIntegration Testに近いイメージで、rspecのRequest Specは、それがテストできるように設計されているから、ということっぽい。
</p>
</section>
<section>
<h2>JSON Helperをこしらえる。</h2>
<p>
JSONを返すアクションのテストを書くと、確かに
<pre class="brush:ruby">
JSON.parse(response.body)
</pre>
が頻発する。これをテストごとにいちいち書かずに、モジュールを作ってDRYに行こうぜ、と。
<pre class="brush:ruby">
# spec/support/request_helpers.rb
module Requests
module JsonHelpers
def json
@json ||= JSON.parse(response.body)
end
end
end
</pre>
というモジュールを作っておいて、spec_helperで、
<pre class="brush:ruby">
RSpec.configure do |config|
config.include Requests::JsonHelpers, type: :request
end
</pre>
としておけば、簡単にパースされたJSONオブジェクトにアクセスできるようになる。
</p>
</section>
<section>
<h2>まとめ</h2>
<p>
railsでREST Web APIをつくってrspecでテストする、という場合に、テスト関連ライブラリの準備や、APIの設計方法、テストのポイントをグワーっと書いてみました。中身が薄かったり、言葉足らずだったり、まとめきれてない感じもあります。更に精進して、改善していきたいと思います。
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-4785583425516950162014-01-09T00:52:00.001+09:002014-01-09T00:52:28.095+09:00railsでテストデータの管理にfactory_girlを使うのが良さそう。<section>
<p>
RSpecを使ってテストを書いていて、
コードの量が増えるとテストで使うデータの管理が煩わしくなるなぁ、と思っていた。
何しろfixturesをymlで書くので、1対多とか多対多の関連を持つデータを定義、管理するのが面倒。
</p>
<p>
そこで今更ながら知ったのが <a href="https://github.com/thoughtbot/factory_girl">factory_girl</a> というgemです。
<blockquote>A library for setting up Ruby objects as test data.</blockquote>
とあり、RSpecのfixtures地獄から解放してくれるスグレモノっぽい。
</p>
</section>
<section>
<h2>factory_girl導入</h2>
<p>
Gemfileに、
<pre class="brush:ruby">
group :test do
gem 'factory_girl_rails'
end
</pre>
を足して、
<pre class="brush:bash">
$ bundle
</pre>
すると利用可能に。
</p>
</section>
<section>
<h2>データの定義</h2>
<p>
例えば、ymlに、
<pre class="brush:ruby">
default:
id: 1
email: test@test.com
password: password
password_confirmation: password
</pre>
と書いて定義していたレコードが、
<pre class="brush:ruby">
FactoryGirl.define do
factory :user do
id 1
email 'test@test.com'
password 'password'
password_confirmation 'password'
end
end
</pre>
という具合にRubyコードで定義できるようになる。
</p>
</section>
<section>
<h2>データの利用</h2>
<p>
ymlによるfixturesを利用する場合は、各specで、
<pre class="brush:ruby">
fixtures :users
</pre>
でテストデータを投入して、
<pre class="brush:ruby">
before(:each) do
@user = users :default
end
</pre>
とか書いて、データを読み込んでいたが、factory_girlを使うと、
<pre class="brush:ruby">
before(:each) do
@user = FactoryGirl.create(:user)
end
</pre>
ってするだけで、データが読み込める。このcreateは、DBにレコードをinsertし、そのレコードをfindして返すみたいな動作をするけど、
他にも、
<ul>
<li>create</li>
<li>build</li>
<li>attributes_for</li>
<li>build_stubbed</li>
</ul>
というメソッドが用意されていて、テストケースに応じて使い分けることができる。
</p>
</section>
<section>
<p>
詳しいドキュメントは、githubの<a href="https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md">GETTING_STARTED.md</a>にあるので、よく読んで使い方をマスターしたい。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-41525845184716799112014-01-07T00:44:00.000+09:002014-01-07T00:44:06.784+09:00express.jsで自作faviconを使用する。<section>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYva4QTAr4A25ugucbndOYxS6YUgLNcUUJ1RUPscu_H8n5wFfB8ZF5DfsP_HuswqaBghDhiRNEQYbNQQtkPpY-xKDF3fQ-FtVvWjdAdqvl8tzLEv2KEW1BVk85dKhDILZK4g0ZSfXlUfQ/s1600/Express+++node.js+web+application+framework.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYva4QTAr4A25ugucbndOYxS6YUgLNcUUJ1RUPscu_H8n5wFfB8ZF5DfsP_HuswqaBghDhiRNEQYbNQQtkPpY-xKDF3fQ-FtVvWjdAdqvl8tzLEv2KEW1BVk85dKhDILZK4g0ZSfXlUfQ/s320/Express+++node.js+web+application+framework.png" /></a></div>
</section>
<section>
<h2><a href="http://expressjs.com/">express.js</a></h2>
<p>
<a href="http://expressjs.com/">express.js</a> では、デフォルトでexpress.js自身が提供するfaviconを配信するよう、コードが自動生成される。具体的には、express.jsが提供するアプリケーションのひな形を生成するコマンドを、
<pre class="brush:bash">
$ express <app_name>
</pre>
のように実行すると、
<ul>
<li>app.js</li>
</ul>
というファイルが生成され、
<pre class="brush:js">
:(略)
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(require('less-middleware')({ src: path.join(__dirname, 'public') }));
app.use(express.static(path.join(__dirname, 'public')));
:(略)
</pre>
というコードが出力される。上記の、
<pre class="brush:js">
express.favicon()
</pre>
が、デフォルトのfaviconの使用を定義するコード。
</p>
</section>
<section>
<h2>express.favicon()</h2>
<p>
express.favicon()は、nodeアプリのためのミドルウェアで、<a href="http://www.senchalabs.org/connect/">connect</a> というのがあって、こいつが提供する機能の1つ。詳しくは、<a href="http://www.senchalabs.org/connect/favicon.html">ここ</a>にドキュメントがあった。読むと、
<blockquote>By default serves the connect favicon, or the favicon
located by the given path.</blockquote>
とあるので、デフォルトだとconnectのfaviconを配信するし、パスが与えられればそいつを配信するよ、ってことだね。(同じページにソースも載っている。)
</p>
</section>
<section>
<h2>自作のfaviconを配信する。</h2>
<p>
なので、次のように自作favicon.icoへのパスをfavicon()関数に渡してあげればよさそう。
<pre class="brush:js">
app.use(express.favicon(__dirname + '/public/images/favicon.ico', {
maxAge: 2592000000 // キャッシュの有効期限
}));
</pre>
</p>
</section>
Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0tag:blogger.com,1999:blog-6564573687368239034.post-32066467766963456422014-01-05T23:44:00.002+09:002014-01-05T23:44:41.142+09:00three.js + tween.js でMatrixのアレっぽいものを作ってみた。<section>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpNmg1VC4pBQWjiq9dRiKiPev5i8ABUYWA5CBMvU1Cbg8LRUIVZxAc_jpqlgQfNL5GNhPQmICYn8vTTQgIrRs3K4gfpzaHUfHc65FeHDDEuBMCiohgVjBn8nB_lUnJdy28N5pFvS39KI4/s1600/Matrix+++simalabs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpNmg1VC4pBQWjiq9dRiKiPev5i8ABUYWA5CBMvU1Cbg8LRUIVZxAc_jpqlgQfNL5GNhPQmICYn8vTTQgIrRs3K4gfpzaHUfHc65FeHDDEuBMCiohgVjBn8nB_lUnJdy28N5pFvS39KI4/s320/Matrix+++simalabs.png" /></a></div>
<p>
<a href="http://strix01.blogspot.com/2013/12/threejs3d.html">「three.jsでカレンダーを3Dにしてみた。」</a>でthree.jsとtween.jsを使ったカレンダーを作ってみたけど、もうちょっと凝ったカレンダーが作れそうとか思っていて、実験として何か作ってみようということで、<a href="http://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%88%E3%83%AA%E3%83%83%E3%82%AF%E3%82%B9_(%E6%98%A0%E7%94%BB)">映画「マットリックス」</a>に出てくるアレっぽいものを作ってみた。
</p>
</section>
<section>
<p>
tween.jsのonComplete関数を使って、落下するコードを3Dオブジェクトとしても、DOM要素としても消滅させて、新たなコードを生成して、tweenのアニメーション対象として追加する、というコードにしてみたけど、それでいいのかどうか。とりあえず、<a href="http://simalabs.com/labs/3d/matrix">http://simalabs.com/labs/3d/matrix</a>で動かしています(chromeで動作確認済み)。リクエストがあれば、コードを載せますので、コメントいただければと思います。
</p>
</section>Anonymoushttp://www.blogger.com/profile/02877138909394707800noreply@blogger.com0