2013/12/30

テンプレートエンジンjadeのmixinを使ってDRYを促進する。

jadeとは?

express.jsの標準テンプレートエンジンとして採用されているのが jade 。Rails上のerbとかもそうですが、うっかりすると同じようなテンプレートをいちいち繰り返して書いていることに気づいて、悲しい気持ちになるのだけど、jadeのmixinという機能を使うことで、全てではないけど悲しい事態がある程度解消できた、という話です。

mixin

リファレンスには、

Mixins allow you to create reusable blocks of jade.
と書いてあって、つまり、再利用可能なjadeブロックを作ることができる、ということ。

mixinを定義する

mixinを定義するには、


mixin name1
  block

mixin name2(args)
  block

のように、mixinキーワードを使う。定義したmixinを使うには、
+ name1
+ name2('foo')
のように、+mixin名という形で使う。 mixinの定義内には、jadeの構文が書けるし、jadeのブロックが渡せるので、
mixin article(title)
  .article
    h1= title
    block
と定義しておいて、
+article3('Title')
  p This is a description
とすると、

Title

This is a description

とレンダリングされる。

mixin適用前の悲しいテンプレート

jadeを使って作っているサイトで、mixinを知らずに書いていた残念なコードがこちら。

div.row-fluid
  div.span8.offset2
    div.row-fluid
      div.span6.well
        h3
          a(href='/labs/jscharts') JSCharts
        p.
          experiments using JSCharts.
      div.span6.well
        h3
          a(href='/labs/smoothiejs') Smoothie Charts
        p.
          experiments using Smoothie Charts.

    div.row-fluid
      div.span6.well
        h3
          a(href='/labs/chartjs') Chart.js
        p.
          experiments using Chart.js
リンク、タイトル、概要のセットで構成されたブロックが3つあるんだけど、同じ構造を3回繰り返し書いていて、DRYじゃない。

mixin適用後の美しい?テンプレート

↑のテンプレートにmininを定義してやって、DRYな形でリファクタリングしたコードがこちら。

// mixinの定義
mixin article(href, title, desc)
  div.span6.well
    h3
      a(href=href)= title
    p= desc

// mixin使用
div.row-fluid
  div.span8.offset2
    div.row-fluid
      +article('/labs/jscharts', 'JSCharts', 'experiments using JSCharts.')
      +article('/labs/smoothiejs', 'Smoothie Charts', 'experiments using Smoothie Charts.')

    div.row-fluid
      +article('/labs/chartjs', 'Chart.js', 'experiments using Chart.js.')

まったく同じコンテンツをレンダリングするjadeのコードが、よりシンプルかつエレガントになった。mixinをうまく使うことで、jadeテンプレートがDRYになることがわかる。実際にリファクタリングしたページは、こちらで公開しています。

2013/12/27

tween.jsでアニメーション - DOM要素を落下させてみる。

tween.js

githubのreadmeに、

Javascript Tweening Engine
とあるとおり、トゥイーンとするライブラリで、DOMオブジェクトのアニメーションが簡単に作れるっぽい。以前、three.jsでカレンダーを3Dにしてみた。で作ったページでも使っているけど、その時はtween.jsで何ができるか詳しく調べていなかったので、今回tween.jsに注目してちょっと試してみた。

DOM要素を順番に落下させる。

↓のようなサンプルを作ってみた。

ページ上にいくつかある青いのは<span>要素なんだけど、これを並べておいて、左から順番に落下させるというアニメーション。 実際に動くページは、こちら

ソース

htmlは(bootsrap2.3を使ってる)、

01
02
03
:
で、横並びの数字バッヂを作った。

Javascriptは、

function init() {
  var boxes = $('box');
  for (var i = 0; i < boxes.length; i++) {
    var box = $(boxes[i]);
    box.css('position', 'relative');
    var elem = { y: 0, box: box };
    var clallback = function () {
      this.box.css('top', this.y + 'px');
    };
    var tween = new TWEEN.Tween(elem)
          .to({ y: 400 }, 2000)            // 2000msかけてyを400まで持っていく。
          .easing(TWEEN.Easing.Bounce.Out) // Bounce.Outを使ってバウンドさせる。
          .onUpdate(callback)              // アップデート時のコールバックを指定。
          .delay(1000 + i * 200)           // となりの要素よりも200ms遅れて動き出す。
          .start();
  }
};

function animate() {
  requestAnimationFrame(animate);
  TWEEN.update();
};

$(function() {
  init();
  animate();
});
のようにした。あ、jQueryも使ってます。対象の動かし方を決めるTWEEN.Easingにはたくさん種類があって、今ひとつどれがどれなのか把握できていないので、別の機会に全部試してみようと思ってる。あと、TWEEN.Tweenはチェーンが組めるので、いろいろなアニメーションをつなげることで、結構複雑なアニメーションが実現できる。チェーンを使ったサンプルは、本家の例にもある。

2013/12/22

nginxのhttp_geoip_moduleでアクセスログにクライアントIPの地理情報を出力する。

http_geoip_module

nginxのhttp_geoip_moduleを使うとクライアントのIPアドレスから地理情報を取得できる、と知ったので試してみた。nginxのドキュメントは、ここにあります。

http_geoip_moduleは、MaxMind社が公開するIPアドレス-地理情報マッピングデータベースを利用する、ということで、http_geoip_moduleを利用するには、同社のデータファイルやもろもろのツールなどをインストール必要があるらしい。

geoip-databaseとlibgeoip-dev

Debian系のOSでは、aptでgeoip-databaseとlibgeoip-devをインストールできる。やってみると、geoip-databaseは予めインストールされとった。(ちなみに、Ubuntuっす。)

$ sudo apt-get install geoip-database
Reading package lists... Done
Building dependency tree       
Reading state information... Done
geoip-database is already the newest version.
0 upgraded, 0 newly installed, 0 to remove and 12 not upgraded.
## もう入ってた・・
$ sudo apt-get install libgeoip-dev
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  geoip-bin
The following NEW packages will be installed:
  geoip-bin libgeoip-dev
0 upgraded, 2 newly installed, 0 to remove and 12 not upgraded.
Need to get 227 kB of archives.
After this operation, 1021 kB of additional disk space will be used.
Do you want to continue [Y/n]? y
Get:1 http://jp.archive.ubuntu.com/ubuntu/ precise/main geoip-bin amd64 1.4.8+dfsg-2 [42.4 kB]
Get:2 http://jp.archive.ubuntu.com/ubuntu/ precise/main libgeoip-dev amd64 1.4.8+dfsg-2 [185 kB]
Fetched 227 kB in 0s (641 kB/s)      
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
 LANGUAGE = "en_US:",
 LC_ALL = (unset),
 LC_CTYPE = "ja_JP.UTF-8",
 LC_COLLATE = "ja_JP.UTF-8",
 LC_MESSAGES = "ja_JP.UTF-8",
 LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
Selecting previously unselected package geoip-bin.
(Reading database ... 52114 files and directories currently installed.)
Unpacking geoip-bin (from .../geoip-bin_1.4.8+dfsg-2_amd64.deb) ...
Selecting previously unselected package libgeoip-dev.
Unpacking libgeoip-dev (from .../libgeoip-dev_1.4.8+dfsg-2_amd64.deb) ...
Processing triggers for man-db ...
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
Setting up geoip-bin (1.4.8+dfsg-2) ...
Setting up libgeoip-dev (1.4.8+dfsg-2) ...

GeoIPデータファイル

geoip-databaseが予めインストールされていたため、IPアドレス-国情報マッピングファイル(GeoIP.dat)は、/usr/share/GeoIP/にすでにファイルがあったのだけど、これだけだと都市名の情報が引けないので、GeoLiteCity.datとというファイルを別途ダウンロードする必要がある。そして、GeoIP.datと同じディレクトリに置く。

$ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
$ gnuzip GeoLiteCity.dat.gz
$ sudo mv GeoLiteCity.dat.gz /usr/share/GeoIP/

nginx

nginxは、cofigureの時点でhttp_geoip_moduleを有効化しないといけない。なので、今回は最新の安定版のソースをダウンロードしてきて、ビルドしなおした。(↓の./configure時のオプションは、実際は他にも色々指定してます。)

$ cd /usr/local/src
$ sudo wget http://nginx.org/download/nginx-1.4.4.tar.gz
$ tar zxf nginx-1.4.4.tar.gz
$ sudo ./configure --prefix='/usr/local/nginx' --with-http_geoip_module
$ sudo make
$ sudo make install

nginx.conf

http_geoip_moduleを利用するために、nginx.confにちょっと追記した。

geoip_countryディレクティブ
GeoIP.datのパスを指定して、$geoip_country_code、$geoip_country_code3、$geoip_country_nameを有効にする。
geoip_cityディレクティブ
GeoLiteCity.datのパスを指定して、$geoip_cityや$geoip_latitude、$geoip_longitudeなどを有効にする。

この2つのディレクティブは、ファイルパスを指定するのだけど、ここの例のようにファイル名だけ指定すると、ファイルオープンエラーとなるので、絶対パスを指定した(ら、うまく動きました。) で、$geoip_xxxxxという一連の変数が利用可能になるので、これらをアクセスログフォーマットに埋めてあげると、ログに出力されるようなる。今回設定したnginxは、fluentdでmongodbに蓄積させるためにltsv形式でログを出力しているので、geoip関連もltsv形式でログフォーマットに追加した。修正したnginx.confは、↓のようになった。
:

http {
    :
  geoip_country /usr/share/GeoIP/GeoIP.dat;
  geoip_city    /usr/share/GeoIP/GeoLiteCity.dat;
    :

  log_format ltsv "time:$time_local"
                  "\thost:$remote_addr"
                  "\tforwardedfor:$http_x_forwarded_for"
                  "\tuser:$remote_user"
                  "\treq:$request"
                  "\tmethod:$request_method"
                  "\turi:$request_uri"
                  "\tstatus:$status"
                  "\tsize:$body_bytes_sent"
                  "\treferer:$http_referer"
                  "\tua:$http_user_agent"
                  "\treqtime:$request_time"
                  "\tcache:$upstream_http_x_cache"
                  "\truntime:$upstream_http_x_runtime"
                  "\tapptime:$upstream_response_time"
                  "\tvhost:$host"
                  "\tgeoip_country_name:$geoip_city_country_name"    # <= 国名
                  "\tgeoip_country_code3:$geoip_city_country_code3"  # <= JPNとかUSAとか
                  "\tgeoip_city:$geoip_city"                         # <= 都市名
                  "\tgeoip_latitude:$geoip_latitude"                 # <= 緯度
                  "\tgeoip_longitude:$geoip_longitude";              # <= 経度
    :
}
:
nginx再起動して、何やらアクセスすると、ログとfluendが出力してくれるmongodbのドキュメントにも、地理情報が出力された。

2013/12/19

three.jsでカレンダーを3Dにしてみた。

Javascriptの3Dライブラリであるthree.jsのexampleに、元素周期表を3Dで表示するっていうカッコイイのがあります。

これを参考に何か作れないかな、と思ってカレンダーを作ってみよう、となり、出来たのがこちらのページです。

これらは、次のような特徴があります。

  • THREE.CSS3DObjectというオブジェクトを利用している。
  • tween.jsを利用している。

THREE.CSS3DObject

three.jsのドキュメントには無いので、githubのソースを読もうと思ってます。

tween.js

Javascriptのアニメーションライブラリです。カレンダーでは、全然使いこなせていませんが、かなり凝ったアニメーションが簡単に作れるスグレモノみたいです。

three.jsのCSS3DObjectとtween.jsを組み合わせるだけで、相当カッコイイものが作れそうなんで、調べつつ試しつつしていこうと思っています。

2013/11/30

Rails4+kaminari+bootstrap3なページング

Railsにおけるページングライブラリといったらkaminariでいいですね。Rails4でも使えました。で、twitter-bootstrap3のページングUIと合わせて使えるのかやってみました。

kaminariの導入

Railsアプリこさえて、Gemfileに

  gem 'kaminari'
を追加して、
$ bundle
しますね。2013年11月28日現在では、kaminari (0.15.0) が入りました。ちなみに、Railsは4.0です。

bootstrap3の導入

同じく、Gemfileに
gem 'anjlab-bootstrap-rails',
:require => 'bootstrap-rails',
:github  => 'anjlab/bootstrap-rails'
を追加して、
$ bundle
します。

bootstrapのページング

bootstrapのページング(ページネーション)は、Components · Bootstrapに説明があります。kaminariのページングに、このUIを適用したい、っていうのがこの記事の根幹です。

rails generate kaminari:views bootstrap

kaminariにはthemeっていう概念があって、アプリにテーマを適用するには、

$ rails generate kaminari:views [theme]
を実行すると、[theme]が適用されたerbセットを作ってくれるんですね。で、[theme]に何指定したらいいの?ってことで、
$ rails g kaminari:views --help
をやったら、出てきました。
Usage:
  rails g kaminari:views THEME [options]

    Copies all paginator partial templates to your application.
    You can choose a template THEME by specifying one from the list below:

        - default
            The default one.
            This one is used internally while you don't override the partials.
        - bootstrap
            Pagination for Twitter Bootstrap 2.0.
            http://twitter.github.com/bootstrap/
        - github
            A very simple one with only "Older" and "Newer" links.
        - google
            A googlish one.
            Try with this option  :window => 10, :outer_window => -1

Options:
      [--skip-namespace]                   # Skip namespace (affects only isolated applications)
  -e, [--template-engine=TEMPLATE_ENGINE]  # Template engine for the views. Available options are "erb", "haml", and "slim".
                                           # Default: erb

Runtime options:
  -f, [--force]    # Overwrite files that already exist
  -p, [--pretend]  # Run but do not make any changes
  -q, [--quiet]    # Suppress status output
  -s, [--skip]     # Skip files that already exist
なんだ、bootstrapサポートされてるじゃない、ってことでTHEMEにbootstrapを指定して、
$ rails g kaminari:views bootstrap
を実行して、次のファイルたちを得たわけです。
  • app/views/kaminari/_first_page.html.erb
  • app/views/kaminari/_gape.html.erb
  • app/views/kaminari/_last_page.html.erb
  • app/views/kaminari/_next_page.html.erb
  • app/views/kaminari/_page.html.erb
  • app/views/kaminari/_paginator.html.erb
  • app/views/kaminari/_prev_page.html.erb

_paginator.html.erbの修正

上のヘルプの内容を見ると、bootstrap2.0用のテーマなんですね。じゃあ、bootstrap3用にするには、どうするかってことなんですが、試したところ、_paginator.html.erbを、↓のように修正することで対応出来ました。

diff --git a/app/views/kaminari/_paginator.html.erb b/app/views/kaminari/_paginator.html.erb
index 03d508e..01e7195 100644
--- a/app/views/kaminari/_paginator.html.erb
+++ b/app/views/kaminari/_paginator.html.erb
@@ -1,17 +1,19 @@
 <%= paginator.render do -%>
-  <div class="pagination">
-    <ul>
-      <%= first_page_tag unless current_page.first? %>
-      <%= prev_page_tag unless current_page.first? %>
-      <% each_page do |page| -%>
-        <% if page.left_outer? || page.right_outer? || page.inside_window? -%>
-          <%= page_tag page %>
-        <% elsif !page.was_truncated? -%>
-          <%= gap_tag %>
+  <div class="row">
+    <div class="col-md-12 text-center">
+      <ul class="pagination">
+        <%= first_page_tag unless current_page.first? %>
+        <%= prev_page_tag unless current_page.first? %>
+        <% each_page do |page| -%>
+          <% if page.left_outer? || page.right_outer? || page.inside_window? -%>
+            <%= page_tag page %>
+          <% elsif !page.was_truncated? -%>
+            <%= gap_tag %>
+          <% end -%>
         <% end -%>
-      <% end -%>
-      <%= next_page_tag unless current_page.last? %>
-      <%= last_page_tag unless current_page.last? %>
-    </ul>
+        <%= next_page_tag unless current_page.last? %>
+        <%= last_page_tag unless current_page.last? %>
+      </ul>
+    </div>
   </div>
 <% end -%>

2013/11/26

Javascriptのグラフ描画ライブラリJSChartsを試してみた。

Webページ上にチャートを描画するJavascriptライブラリに JSCharts というのがある。シンプルなAPIかつ、綺麗なチャートが描画できそうだったので試してみた。

JSCharts

JSChartsは、http://www.jumpeyecomponents.com/というサイトで公開されているソフトウェアライブラリの1つ。このサイトは、有償ソフトウェアを販売しているっぽくて、JSChartsも有償。ただ、同サイトにユーザ登録をし、JSChartsで描画するチャートにウォータマークを表示する、という条件で無料で利用できる。今回試したのは無料版。

価格

ちなみに、JSChartsの価格は2013年11月末現在、http://www.jscharts.com/free-downloadにあるように、1ドメインでの非商用利用で$39、商用利用で$79というお値段。

チャート

JSチャートがサポートするチャートは、

  • Line Chart
  • Bar Chart
  • Pie Chart
の3種類。チャートの種類は少ないけど、色が設定やツールチップや凡例の表示が細かくできる点が強いところに見える。チャートの例や具体的なAPIは本家のサイトに詳しく書いてあるのでここには書かないけど、実際にチャートを描画したイメージを張っておく。

画像、もしくは実際のサイト上の描画(http://simalabs.com/labs/jscharts)をよく見るとわかるんだけど、各チャートの左上に「JSCharts」っていう画像が表示されていて、これがそのウォータマークってやつ。これを表示させないためには、お金払ってね、ということ。けど、実際にWebページ上に敢えてチャート出す時って、軸や値の数値も見れた方が嬉しい、という人のほうが多いと思うし、4,000円乃至8,000円は払っても損はないかなと思います。以前試したChart.jsよりは個人的にはJSChartsの方が使いたいと思ってる。(Javascriptのグラフ描画ライブラリChart.jsを試してみた。参照)

2013/11/24

Javascriptのストリーミングデータ用チャートライブラリSmoothie Chartsを試してみた。

Javascriptのチャートライブラリを調べていて、ちょっと変わったライブラリをみつけたので試してみた。
今回試したのは、Smoothie Chartsというもので、ストリーミングデータを時系列なラインチャートとして表示するもの。MITラインセンスのオープンソースで、githubにホスティングされてる。

リアルタイムな時系列チャートを描く

このライブラリを使うと、簡単にリアルタイムな時系列チャートが描画できる。使い方は、チュートリアルがあり、本当に簡単すぎる・・・

ポイントとしては、

  • canvasタグを利用する。
  • setInterval関数を使ってリアルタイムにチャートを更新する。
というところか。

実際にページ上で使ってみた例が、このキャプチャになります。

ここに動くページを作ってみたよ。

2013/10/26

Rails4からActiveRecordのorderにハッシュを渡せるようなった。

以前、[rails]ActiveRecordのソートという記事を書いた。あれからおよそ1年半の間にRails4がリリースされ、まさにこのソートの機能も改良されたっぽい。

order(*args)

ActiveRecordのソート処理は、ActiveRecord::QueryMethods.orderで実装されている。これまでは、

User.order('name')
=> SELECT "users".* FROM "users" ORDER BY name

User.order('name DESC')
=> SELECT "users".* FROM "users" ORDER BY name DESC

User.order('name DESC, email')
=> SELECT "users".* FROM "users" ORDER BY name DESC, email

User.order(:name)
=> SELECT "users".* FROM "users" ORDER BY "users"."name" ASC

しかなかったのに対し、Rails4から、
User.order(email: :desc)
=> SELECT "users".* FROM "users" ORDER BY "users"."email" DESC

User.order(:name, email: :desc)
=> SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC

のように、ハッシュでソート条件を指定できるようになった。
おかけで、降順もスマートに指定できるね。

2013/09/29

Javascriptのグラフ描画ライブラリChart.jsを試してみた。


Javascriptによるグラフ表示用のライブラリってたくさんある。まとめサイトもたくさんある。実際に触ってみると良し悪しがよりわかる。 ということで、1つ試してみた。
今回試したのは、Chart.jsです。canvasタグを使ったHTML5のチャートライブラリ。 MITライセンスなオープンソース。https://github.com/nnnick/Chart.jsにソースがあります。

描画できるチャートの種類

Chart.jsがサポートしているのは、
  • Line Chart
  • Bar Chart
  • Radar Chart
  • Polar Area Chart
  • Pie Chart
  • Doughnut Chart
の6種類。Polar Area Chartっていうのはあまり見ないなぁ。

使ってみた。

6つのチャートを全部表示してみたけど、簡単だった。APIに統一感があって、チャートの種類によらない感じがいい。 具体的な使い方は、ドキュメント読んだら一目瞭然なので、ここには書きません。


実際に試したらば、←のようになった。実物は、http://simalabs.com/labs/chartjsを見てみて下さい。 それと、Chart.jsでは、
  • 凡例を表示することができない。
  • チャートの値をhoverしてtipを出すとかもできない。
ということができない、ってことは気にしておくベきかなと思った。




2013/09/19

Rからmongodbにアクセスするrmongodbをインストールした。

Rで統計解析しようと思っていた元ネタをmongodbに格納していて、今まではrubyでmongodbに突っ込んで、 Rにデータを渡すのに、CSVファイルをrubyで作って、みたいなことをやっていた。が、 MongoDBの集計機能が便利過ぎて泣けてくるお話し を読んで、 rmongodb というRのパッケージの存在を知ったので、インストールしてみた。

rmongodbのインストール

sudoでRを起動し、install.packagesするだけ。簡単。

> install.packages("rmongodb")
 パッケージを ‘/usr/local/lib/R/site-library’ 中にインストールします 
 (‘lib’ が指定されていないので) 
 URL 'http://cran.ism.ac.jp/src/contrib/rmongodb_1.0.5.tar.gz' を試しています 
Content type 'application/x-gzip' length 112861 bytes (110 Kb)
 開かれた URL 
==================================================
downloaded 110 Kb

* installing *source* package ‘rmongodb’ ...
**  パッケージ ‘rmongodb’ の解凍およびMD5サムの検証に成功しました 
** libs
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c api.c -o api.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c api_bson.c -o api_bson.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c api_gridfs.c -o api_gridfs.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c api_mongo.c -o api_mongo.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c bson.c -o bson.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c encoding.c -o encoding.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c env.c -o env.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c gridfs.c -o gridfs.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c md5.c -o md5.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c mongo.c -o mongo.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c numbers.c -o numbers.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c symbols.c -o symbols.o
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -D_MONGO_USE_GETADDRINFO -DR_SAFETY_NET -fpic  -O2 -pipe -g  -c utility.c -o utility.o
gcc -std=gnu99 -shared -o rmongodb.so api.o api_bson.o api_gridfs.o api_mongo.o bson.o encoding.o env.o gridfs.o md5.o mongo.o numbers.o symbols.o utility.o -L/usr/lib/R/lib -lR
 以下にインストール中:  /usr/local/lib/R/site-library/rmongodb/libs
** R
** demo
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
rmongodb package (mongo-r-driver) loaded
Use 'help("mongo")' to get started.


* DONE (rmongodb)

 ダウンロードされたパッケージは、以下にあります 
  ‘/tmp/RtmpDFyqNs/downloaded_packages’ 
> 
> 

Rからmongodbにつないでみる。

> library(rmongodb)
rmongodb package (mongo-r-driver) loaded
Use 'help("mongo")' to get started.

> mongo <- mongo.create()
> mongo.is.connected(mongo)
[1] TRUE
> mongo.count(mongo, 'ドキュメント名.コレクション名')
[1] 3713
>
まだ、詳しく使い方をわかっていないけど、上記でlocalhostのmongodbに接続し、 指定したドキュメントの指定したコレクションの件数を取得することができた。

2013/08/27

[three.js] Lightの使い方 - DirectionalLight編


前回、AmbientLight の使い方について書いた。今回は同じくライトの中で、DirectionalLight について纏めます。

DirectionalLight

DirectionalLightは、「指向性ライト」とでもいうのか。このライトに照らされるオブジェクトの素材(Material)によって、効果が変わる。ドキュメントには、

Affects objects using MeshLambertMaterial or MeshPhongMaterial.

とある。つまり、MeshLambertMeterialか、MeshPhongMaterialを使ったオブジェクトに作用する、と。
実際に、 をシーンに置いて、DirectionalLightで照らしてみたところ、ドキュメント通り動作した。
このライトによって、影が描画されるのかな、と思って、

  • shadowCameraNear
  • shadowCameraFar
  • shadowCameraLeft
  • shadowCameraRight
  • shadowCameraTop
  • shadowCameraBottom
を色々変えてみたが、影は描画できていない。その際に、もちろん、オブジェクト側のcastShadow属性や、 rendererのshadowMapEnabledはtrueで試した。
今のところの結論として、
  • オブジェクトはMeshLambertMaterialかMeshPhongMaterialであれば、光が当たっていることが表現される。
  • 影は描画できない。
を得た。 
Directional Light. - simalabsで実験版を動かしています。ご覧ください。


2013/08/26

[three.js] Lightの使い方 - AmbientLight編


Three.jsのライト

Three.js には、ライトを表現するオブジェクトとして、
がある。シーンに、ライトを適切に配置しないと、オブジェクトが見えない。
それぞれのライトがどのような性質があって、どう使えばいいのかが(3D初心者の僕には)わからないので、 一つずつ実験してみよう、ということで、AmbientLightを使ってみました。

Light

Lightは、上記の各ライトの基底となるオブジェクトで、属性として「color」を持っている。 それ以外に別段コレという属性も操作も持っていない。

AmbientLight

AmbientLightは、直訳すると「周辺光」という意味で、どうやら3D空間の描画において、自然に発生する普遍的な光を表現するための概念と思われた。
AmbientLightには、他のライトが持つような光源の座標や、影に関する属性がなく、
  • color
を属性に持っている。 それと、他のライトは、概ねintensityという光の強度を属性に持つが、AmbientLightはそれももっていない。
じゃあ、どうしたらライトのON/OFFができるのか、といえば、Lightの基底であるObject3Dから継承している、
  • visible
属性をfalseにすることで、AmbientLightをOFFにできた。
さらに、AmbientLightのドキュメントには、次のような記述がある。
This light's color gets applied to all the objects in the scene globally.

なので、このライトに照らされた全てのオブジェクトは、このライトが持つcolorの影響を受ける、ということだ。
一方で、3Dオブジェクトを表現するThree.jsのオブジェクト MeshLambertMaterialは、ambientという属性を持っていて、これは、
Ambient color of the material, multiplied by the color of the AmbientLight. Default is white.

なので、この値を変えれば、AmbientLightに照らされた時の色が表現できる、ということになる。

an experiment.

ということで、実際に試してみたのが、こちらになります。

2013/08/15

node(express.js)なアプリをcapistranoでdeployする。

Railsアプリをサーバーにデプロイする際に、Capistranoを使ってきたけど、これをNode.js+express.jsなアプリでも使えればなぁ、と思っていて、@d_akatsukaさんの、
Node.js アプリをデプロイして Upstart で起動させる Capistrano レシピを書いた
を大いに参考にさせて頂いて、やっと自分の環境でも動かすことができたので、まとめてみる。

Capistrano

Capistranoは、rubygemsとしてインストールする。

  $ gem install capistrano
  $ cap --version
  Capistrano v2.15.4
ちなみに、僕の環境のrubyはrbenv+ruby_buildでインストールしたruby2.0.0p0。

Capfileとdeploy.rb

Capistranoでデプロするには、一般的に、Capfileとdeploy.rbという2つのRubyスクリプトが必要になる。 今回は、express.jsアプリケーションの標準的なディレクトリ構成にこの2つのファイルを追加した。

project_root
├── Capfile
├── app.js
├── config
│   └── deploy.rb
├── node_modules
├── package.json
├── public
├── routes
└── views

それぞれ、次のような内容を書く。
#
# Capfile
#
load 'deploy'
# Uncomment if you are using Rails' asset pipeline
    # load 'deploy/assets'
load 'config/deploy' # remove this line to skip loading any of the default tasks
#
# deploy.rb
#
set :application,        'application_name'
set :host,               'your.host.com' # or ip address.
set :user,               'username'
set :password,           'password'
set :deploy_to,          "/var/www/apps/#{application}"
set :shared_children,    %w(log node_modules)

set :node_file,          'app.js'
set :node_version,       "v0.10.12"
set :application_binary, "/usr/local/nvm/#{node_version}/bin/node"
set :npm_binary,         "/usr/local/nvm/#{node_version}/bin/npm"

set :scm,          :git
set :repository,   'git://git.host/your/repository.git'
set :branch,       'master'
set :deploy_via,   :remote_cache

role :app,           host
set  :use_sudo,      false
set  :default_run_options, :pty => true

namespace :deploy do

  task :default do
    update
    start
  end

  task :cold do
    update
    start
  end

  task :setup, :expect => { :no_release => true } do
    dirs = [deploy_to, release_path, shared_path]
    dirs += shared_children.map { |d| File.join(shared_path, d) }
    run "mkdir -p #{dirs.join(' ')}"
    run "chmod g+w #{dirs.join(' ')}" if fetch(:group_writable, true)
  end

  task :finalize_update, :expect => { :no_release => true } do
    run "chmod -R g+x #{latest_release}" if fetch(:group_writable, true)
    run <<-CMD
      rm -rf #{latest_release}/log #{latest_release}/node_modules &&
      ln -s #{shared_path}/log #{latest_release}/log &&
      ln -s #{shared_path}/node_modules #{latest_release}/node_modules
    CMD
  end

  task :start, :roles => :app do
    run "#{sudo} restart #{application} || #{sudo} start #{application}"
  end

  task :stop, :roles => :app do
    run "#{sudo} stop #{application}"
  end

  task :restart, :roles => :app do
    start
  end

  task :npm, :roles => :app do
    run "cd #{latest_release} && #{npm_binary} install"
  end

  desc "writes the upstart script for running the daemon."
  task :write_upstart_script, :roles => :app do
    upstart_script = <<-UPSTART
description "#{application} upstart script"

start on (local-filesystem and net-device-up)
stop  on shutdown

respawn
respawn limit 5 60

script
  chdir #{current_path}
  exec sudo -u #{user} NODE_ENV="production" #{npm_binary} start >> log/production.log 2>&1
end script
    UPSTART

    put upstart_script, "/tmp/#{application}.conf"
    run "#{sudo} mv /tmp/#{application}.conf /etc/init"
  end

end

after 'deploy:setup',           'deploy:write_upstart_script'
after 'deploy:finalize_update', 'deploy:npm'
ほぼ、前述の@d_akatsukaさんの記事のdeploy.rbとかわらないけど、サーバーサイドでnvmをシステムワイドに適用していることで、 nvm経由のnodeやnpmの起動で、パスの指定がこのようになった。

デプロイする

初めてサーバーにデプロイする場合は、

 $ cap deploy:setup
を実行する。コレが成功すると、:deploy_toで指定したディレクトリがサーバーサイドで生成され、 さらに/etc/init配下にupstartのスクリプトが生成される。
通常は、
 $ cap deploy
を実行すると、リポジトリから最新モジュールを取得し、転送、配置、upstartでnodeの再起動をやってくれる。
上述のdeploy.rbで、
 $ cap deploy:start
 $ cap deploy:stop
 $ cap deploy:restart
 $ cap deploy:rollback
を試したけど、うまく動いた。

2013/08/10

モックhtmlはJade+LESS+CoffeeScript+Grunt.jsで。

WebサイトやWebアプリケーションの画面仕様やデザインの検討や確認のために、 モックhtmlを書くことが度々あった。 そのたびに、テキストエディタで、生のhtml、css、Javascriptをガシガシ書いていた。 が、ページ数が多くなるに連れて、DRYじゃないことに憤りを感じ、メンテナンスが面倒になり、 もっと効率良く、メンテナンスが楽にできないものなのか、と考えていた。

node.jsの勉強をしていて、express.jsに出会い、テンプレートエンジンJadeと メタCSS言語LESSに出会った。Railsを使った開発では、CoffeeScriptを使っていた。 そこで、これらを使って静的なページを作るとかなり効率がいいのでは?と思った。


モックをはやく作るための道具

JadeとLESS、CoffeeScriptで静的なHTMLを作れないか。
Jadeは単体で使える。
LESSも単体でコンパイルできる。
もちろんCoffeeSriptも。
で、全部Node.jsの上で動く。
全部一発でビルドできれば、そりゃあ楽ちんだわぁ。
そういえば、Grunt.jsっていうのがあったな、たしか。
Javaのapache antみたいなやつ。

ということで、使うのは、

node.jsとGrunt.jsのインストール

node.jsは予めインストールしておく必要がある。Grunt.jsは、grunt-cliというGrunt.jsのCLIパッケージをnpmでインストールする。

  $ npm install -g grunt-cli

ディレクトリとファイル

おそらく、こうしなければよい、という構造はない。 とりあえず、次のようなディレクトリ階層を作成し、2つのファイル、package.jsonとGruntfile.jsを作った。

├── Gruntfile.js
├── package.json
└── src
    ├── coffee
    │   └── jade-de-mock.coffee
    ├── jade
    │   ├── includes
    │   │   └── javascripts.jade
    │   ├── index.jade
    │   └── layout.jade
    └── less
        ├── jade-de-mock.less
        └── reset.less

Grunt.jsのプラグインとタスク

jadeのコンパイルや、lessのコンパイル、coffeeのコンパイルは、Grunt.jsのプラグインを利用する。 そのため、まず、Grunt.jsが動作する環境を整備しないと。

package.jsonを書く

  {
    "name": "jade-de-mock",
    "version": "0.1.0"
  }

gruntとgruntプラグインをnpmでインストールする。

jade、less、coffeeのgruntプラグインは、grunt.jsが提供してくれている。

それと、前回のビルド結果を相違するcleanタスクも欲しいので、これもインストール。

というわけで、上記4つのgruntプラグインを、npmコマンドでインストール。
  $ npm install grunt --save-dev
  $ npm install grunt-contrib-jade grunt-contrib-less grunt-contrib-coffee grunt-contrib-clean --save-dev
これを実行すると、上述のpackage.jsonにプラグインが追記され、結果、
  {
    "name": "jade-de-mock",
    "version": "0.1.0",
    "devDependencies": {
      "grunt": "~0.4.1",
      "grunt-contrib-coffee": "~0.7.0",
      "grunt-contrib-clean": "~0.5.0",
      "grunt-contrib-jade": "~0.8.0",
      "grunt-contrib-less": "~0.7.0"
    }
  }
となる。

Gruntfile.jsを書く

Gruntfile.jsは、apache-antでいうところのbuild.xmlのようなもの。gruntに実行させるタスクをJavascriptで書く(CoffeeScriptでも良い)。

module.exports = function(grunt) {

  // project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    jade: {
      compile: {
        options: {
          pretty: true
        },
        files: {
          "dst/index.html": ["src/jade/index.jade"]
        }
      }
    },
    less: {
      compile: {
        options: {
          compress: true,
          syncimport: true
        },
        files: {
          "dst/stylesheets/<%= pkg.name %>.min.css": "src/less/jade-de-mock.less"
        }
      }
    },
    coffee: {
      compile: {
        files: {
          "dst/javascripts/<%= pkg.name %>.js": "src/coffee/*.coffee"
        }
      }
    },
    clean: {
      build: ["dst"]
    }
  });

  // load npm tasks.
  grunt.loadNpmTasks('grunt-contrib-jade');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-coffee');
  grunt.loadNpmTasks('grunt-contrib-clean');

  // define default tasks.
  grunt.registerTask('default', ['clean', 'jade', 'less', 'coffee']);

};

これで準備完了。

モックを書く。

ひたすらモックを書く。Jadeを書く。LESSを書く。CoffeeScriptを書く。

ビルドする。

ビルドはGrundコマンドで実行。先ほどのGruntfile.jsにしたがって、タスクが実行される。

  $ grunt
これで、dstディレクトリが生成され、次のようなファイルが出力される。
  dst/
  ├── index.html
  ├── javascripts
  │   └── jade-de-mock.js
  └── stylesheets
       └── jade-de-mock.min.css

モックを作るたびに使えばいい

と思ってgithubに、

を作っちゃった。

2013/08/02

[three.js] PerspectiveCameraのレンズ

Three.jsのCameraには、レンズを設定するためのメソッド、

  THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) {
    if ( frameHeight === undefined ) frameHeight = 24;
      this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) );
      this.updateProjectionMatrix();
  }
があります。

このメソッドの引数は、

focalLength
焦点距離(mm)
frameHeight
フレーム高(mm)
となっていて、デフォルトだと、foculLength = 35, frameHeight = 24として動作します。

通常のカメラと同様に、foculLength(焦点距離)を大きくすると画角(fov)が小さくなるため、 描画対象が大きくなります(望遠レンズ)。
一方で、foculLengthを小さくすれば画角が大きくなるため、描画対象が小さくなります(広角レンズ)。

この振る舞いを確認するためのサンプルが、
let's play with cameras!
にあります。
WebGLに対応したブラウザで見ていただければ、と思います。

2013/07/30

[three.js] PerspectiveCameraの属性をイジる。

Three.jsには、Cameraがあります。
そこから派生した2つのカメラオブジェクト、
それぞれ、「正射影カメラ」、「透視投影カメラ」と呼ばれているようです。
今回は、後者のPerspectiveCamera、すなわち、「透視投影カメラ」のパラメータを弄ってみました。

Perspective Camera

人間の目で見えるように描画する。
つまり、同じ大きさの物体であれば、カメラから近いものほど大きく、遠いものほど小さく見える。

Perspective Cameraのパラメータには、

fov
field of view. y軸(縦)方向の画角(視野角)。
コレが大きいと、いわゆる広角になり、小さいと望遠になる。
aspect ratio
描画空間(xy面)のアスペクト比、つまり横/縦。
near
描画空間(手前側の面)の視点からの距離
far
描画空間(奥側側の面)の視点からの距離

があります。
これらの組み合わせが、描画する空間にどう作用するのかを確認するため、右のようなパラメータをイジる画面を表示するコードを書いてみました。

結果は、 let's play with cameras!にあります。
WebGLに対応したブラウザで見ていただければ、と思います。

2013/07/19

[three.js] Three.jsを使った最初のサンプル

一度は断念した Three.js を再び触り始めました。
上記サイトの documentation にある

というページにある超簡単なコードを書いてみました。結果は、 で確認できます。
WebGLに対応したブラウザで見ていただければ、と思います。

2013/07/16

[emacs] LESSのためのless-modeを導入!

など、CSSメタ言語(というのか)を利用する機会が増えています。
twitter-bootstrapは、LESSで書かれているし、 ExpressではLESSやStylusが使えます。
ということで、僕のemacsにもLESSを扱いやすくするlispを追加してみました。
ちなみに、SassとStylusに関しては、
[emacs] scss-mode
[emacs] jade-mode, stylus-mode
を見ていただければ、と思います。

LESSのlispは、

があります。 前者は、css-modeに依存しており、僕のemacsでは適切なcss-modeがインストールできず使えなかったため、 (次のような警告が出ました。 Wrong css-mode.el: please use the version by Stefan Monnier, bundled with Emacs >= 23.) 後者をインストールしました。

less-modeをダウンロードして、~/.emacsに、

(add-to-list 'load-path "/path/to/less-mode.el")
(require 'less-mode)
とすることで、*.lessのメジャーモードがLessになりました。 インデントも問題無さそうです。

2013/07/13

[fluentd] nginxのアクセスログをfluentdからmongodbに!

前々から気になっていたfluentdをようやく試しました。 fluentdは、rubyで書かれたオープンソースのログ収集デーモンです。

今回試したのは、nginxのアクセスログ(ltsv)をfluentdを使ってmongodbに集める、ということです。 (ここでは、mongodbのインストール方法などは書きません。)

fluentdのインストール

fluentdにはyumパッケージ、debianパッケージ、ruby gemなどいくつかあって、 僕はgemをインストールしました。

 $ ruby --version
 ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-linux]
 $ gem --version
 2.0.3
 $ sudo gem install fluentd

fluentdの設定

ディレクトリ /etc/fluent を作って、初期化コマンドを実行します。

 $ sudo mkdir /etc/fluent
 $ sudo fluentd --setup /etc/fluent

ltsv用プラグイン(input)

nginxのアクセスログは、ltsv形式で出力しています。
(nginxのアクセスログをltsv形式にする方法は、[nginx]アクセスログフォーマットにLTSVを適用する。にあります。)
stanaka/fluent-plugin-tail-labeled-tsvを使用させて頂いて、簡単にltsvなアクセスログをfluentdのinputとして扱うことができました。
in_tail_labeled_tsv.rbというRubyファイルを/etc/fluent/pluginsに配置します。

mongodb用プラグイン(output)

fluentdの出力を、mongodbへ格納するためのプラグインをインストールします。
fluent/fluent-plugin-mongoです。

 $ fluent-gem install fluent-plugin-mongo

fluent.conf

inputとoutputの定義をfluent.conf(/etc/fluent/fluent.conf)に書きます。
今回は、nginxとfluentd、mongodbを同じホスト上で動かしています。
そのため、↓のようなファイルになりました。

/etc/fluent/fluent.conf


  <source>
    type tail_labeled_tsv
    path /usr/local/nginx/logs/access.log
    tag nginx.access
    pos_file /var/log/fluent/access.log.pos
  </source>

  <match nginx.access>
    type       mongo
    database   fluent
    collection nginx
  </match>

fluentdの起動

fluentdのupstart用スクリプトを書いて起動します。

/etc/fluentd.conf


description "fluentd upstart script"

start on (local-filesystem and net-device-up)
stop  on shutdown

respawn
respawn limit 5 60

script
  exec sudo -u somebody /usr/local/rbenv/shims/fluentd -c /etc/fluent/fluent.conf
end script

 $ sudo start fluentd

これでmongodbにアクセスログがmongodbに蓄積されました。

参考にさせて頂いたサイト。

2013/07/10

[nginx]アクセスログフォーマットにLTSVを適用する。

以前、nginxのアクセスログフォーマットについて書きました。 ログ収集のためのツールであるfluentdが広まっており、サーバーログなどの扱い方も変わってきているように思います。

そういった中で、LTSVという形式でログを出力させることで、ログをアプリケーションで扱いやすくするという方法が広まっているようです。
LTSVに関する説明として、LTSV FAQ - LTSV って何? どういうところが良いの?がとても参考になります。

LTSV形式でnginxのログを出力させる場合、nginxの設定ファイル(一般的には、nginx.conf)に次のように記述します。
(http ディレクティブに書きました。)


    log_format ltsv "time:$time_local"
                    "\thost:$remote_addr"
                    "\tforwardedfor:$http_x_forwarded_for"
                    "\tuser:$remote_user"
                    "\treq:$request"
                    "\tmethod:$request_method"
                    "\turi:$request_uri"
                    "\tstatus:$status"
                    "\tsize:$body_bytes_sent"
                    "\treferer:$http_referer"
                    "\tua:$http_user_agent"
                    "\treqtime:$request_time"
                    "\tcache:$upstream_http_x_cache"
                    "\truntime:$upstream_http_x_runtime"
                    "\tapptime:$upstream_response_time"
                    "\tvhost:$host";



各項目のラベルは、上述のLTSVのサイトで推奨されているラベルを使っています。
そして、このログフォーマットを適用したいserverディレクティブ内で、
  server {
    listen 80;
    # 略
    access_log logs/access.log ltsv;
    # 略
  }
のように指定し、nginxを再起動することで、LTSV形式のログが出力されます。

2013/07/03

[nginx] worker_processesとworker_cpu_affinityについて

nginxにはworker_processesというパラメータがあります。 NginxのWikiCoreモジュールのページには、次のような説明があります。


A worker process is a single-threaded process.
If Nginx is doing CPU-intensive work such as SSL or gzipping and you have 2 or more CPUs/cores, then you may set worker_processes to be equal to the number of CPUs or cores.
If you are serving a lot of static files and the total size of the files is bigger than the available memory, then you may increase worker_processes to fully utilize disk bandwidth.
Your OS may schedule all workers on single CPU/core this can be avoided using worker_cpu_affinity.
Nginx has the ability to use more than one worker process for several reasons:

  1. to use SMP
  2. to decrease latency when workers blockend on disk I/O
  3. to limit number of connections per process when select()/poll() is used
The worker_processes and worker_connections from the event sections allows you to calculate maxclients value:
max_clients = worker_processes * worker_connections


何が書いてあるかといえば、

worker prcessは、シングルスレッドなプロセスだよ。
nginxがSSLやgzip圧縮みたいにCPUを専有するような処理をするって場合に、2つ以上のCPUコアがあるなら、worker_processesにはCPUコア数と同じを設定したらいいよ。
大量の静的ファイルをホスティングしていて、ファイルサイズが空きメモリサイズよりも大きくなっちゃうような場合も、worker_processesの値を増やして、ディスク帯域を十分に使えるようにしたらいいよ。
君のOSだと全部のworker_processを1つのCPUコアに割りつけてしまうかもしれないけど、そんな時はworker_cpu_affinityを設定すれば回避できるよ。
nginxは、

  1. SMPを使うため。
  2. ディスクI/Oによる応答遅延を減らすため。
  3. select()/poll()環境下でプロセスごとの接続数を制限するため。
といったいくつかの理由から複数のworker processが使えるようになっているよ。

worker_processesとeventセクションに設定するworker_connectionsから、最大クライアント数を計算できるよ。つまり、
最大クライアント数 = worker_processes * worker_connections
になるよ。

といった内容でしょうか。
つまり、worker_processes を CPUコア数にして、worker_cpu_affinityをきちんと設定しなさいよ、ということで、
僕のサーバは2コアなので、

  worker_processes 2;
  worker_cpu_affinity 0101 1010;
を設定しました。

2013/07/01

[node] nvmをシステムワイドに適用する。

rbenvをシステムワイドに適用する方法について、 rbenv + ruby-build を system-wide にインストールするを参考にさせていただき、無事に適用することができました。

まったく同じ要領で、nvmをシステムワイドに適用させてみました。

nvmのインストール
$ cd /usr/local
$ sudo git clone git://github.com/creationix/nvm.git nvm
$ sudo chown -R root:[グループ名] nvm
$ sudo chmod -R g+rwxX nvm
グループ名は、nvmを使用させるグループ名を指定します。
/etc/profile.d/nvm.sh
source /usr/local/nvm/nvm.sh
ユーザがログインすると、自動的にnvmが利用可能になります。

2013/05/25

[R]パッケージのミラーサイトの設定

ついに僕もRをいじり始めました。
Rubyにgemを追加するみたいに、Rもパッケージを追加することで、より便利にできます。

Rのパッケージは主にCRANで公開されています。
http://cran.r-project.org/

CRANのミラーサイトは日本国内にもいつくかあるので、 パッケージのダウンロードは、ミラーサイトから行います。 国内のミラーサイトには、

などがあります。

パッケージのダウンロード&インストールは、install.packages('パッケージ名')で行いますが、 ~/.Rprofile に下記のようにミラーサイトを記述しておくと、そのミラーサイトからダウンロードします。


  options(repos="ミラーサイトのURL")

例えば、筑波大学のミラーサイトを利用する場合は、


  options(repos="http://cran.md.tsukuba.ac.jp/")

のようになります。

2013/04/13

[node][express][mongoose] モデルのファイル分割

node,expressなWebアプリケーション開発の話です。
mongooseを使ったモデルをうまくファイル分割して配置したい、と思ってやってみました。
(うまいかどうか、正直自信はありません。)

expressで作ったアプリケーションディレクトリは、
  • app.js
  • package.json
  • node_modules
  • public
  • routes
  • views
のように、2つのファイルと、4つのディレクトリで構成されます。
この構成に対して、
db.js
mongodbへのコネクション処理を実装
models
mongodbのcollectionに対応したスキーマ定義ファイルを配置するディレクトリ
を追加しました。

実装は次のようにしました。

db.js

var mongoose = require('mongoose');
mongoose.connect('mongodb://hostname:port/dbname');

models/somemodel.js
var mongoose = require('mongoose');
var Schema   = mongoose.Schema;

var SomeModel = new Schema({
  attr1: SomeType,
  attr2: SomeType,
  :
});

// 以下、モデルのロジックの実装。
これで、モデルごとにファイルを分割し、models配下に格納していくことができます。
最後に、app.jsでdb.jsををrequireします。
// :
require('./db');
// :
また、モデル単位のファイルは、必要な場所でそれぞれrequireします。

2013/01/30

[rails] sassなtwitter-bootstrapをrailsで使う

いまさらですが、twitter-bootstrapが便利なことを知りました。
これをRails3に適用するにあたり、せっかくsassでCSSも無駄なく書けているので、sassを使いつつ、twitter-bootstrapも使いたい、 という欲求が出てきました。

そんな時は、 bootsrap-sassを使います。
以下、導入手順です。

Gemfile

  gem 'bootstrap-sass'

bundle install

  $ bundle install

app/assets/javascripts/application.js

  //= require jquery
  //= require jquery_ujs
  //= require bootstrap
  //= require_tree .

app/assets/stylesheets/bootstrap_and_overrides.css.scss

  @import "bootstrap";
  @import "bootstrap-responsive";

これだけで、bootstrapがsassで使えるようになりました。
bootstrap_and_overrides.css.scssでは、bootstrap自身がカスタマイズを許容しているスタイル変数、
具体的にはCustomize - Bootstrapにある 変数に対して、
  $bodyBackground: #ddd;
  $textColor:      #333;
のように、オーバライドします。
殊、bootstrapのレイアウト機構は、CSSがスパゲッティになりがちな僕にとっては強力な助けになっています。
参考サイト

2013/01/08

[rails] RSpecを使う際のポイント

現在、rails3アプリを開発中です。
テストにはRSpecを使用しています。
RSpecを使うにあたって、僕が注意している2点を書いておきます。
(別にRSpecだから、ということでもないですね・・・)

カバレッジ100%をキープする。

Rubyはコンパイルによる単純ミスの発見ができないため、
くだらないタイポなどが残ってしまう可能性があります。
RSpecとrcovやsimplecovなどのカバレッジ計測ツールを組み合わせて、
一度も通っていないルートをなくしています。

fixturesは必要最小限に抑える。

fixturesによるテストデータはとても便利です。
これに頼りすぎて、なんでもかんでもfixturesとして定義してしまうと、
テストケース間の結合度が密になり、テストのメンテナンス性が低くなります。
僕のチームでは、fixturesは、もっとも単純な正常系ケースを実行するのに必要な量のレコードのみを 定義するに留めて、他のケースに必要なデータはbeforeで作るか、スタブオブジェクトを使って テストするようにしています。

2013/01/06

[nginx]Rails3アプリの静的ファイルをnginxに処理させる。

Rails3アプリをnginx+unicornでホストする場合、Rails3内部に持つ静的ファイル(assetsなど)は、 nginxに応答させる方がパフォーマンスが出ます。

それを実現するには、nginxのコンフィグレーションで、次のように記述します。


  upstream rails_app {
      server  unix:/tmp/unicorn_rails_app.sock;
  }

  server {
      listen  80; 
      server_name rails_app.somedomain.com;
      location ~* \.(html|css|js|ico|gif|jpe?g|png)(\?[0-9]+)?$ {
          root /path/to/rails_app/current/public;
          break;
      }
      location / { 
          if (-f $request_filename) { break; }
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_pass  http://rails_app;
      }
  }