Emacsが好きだからS式のパーサー書いた

今思うとちょっとどうかしていたと思うけど、
S式しか返さないHTTPサーバーを作って、Emacsからしか読めないWebサービスを作ろうという計画が僕の胸の内にあったため、
その計画の第一歩として、S式のパーサーを書いてみたのだった。
これはサーバーをnode.jsで作ろうとしていたので、jsで書いた。

https://github.com/f-kubotar/sexpression

S式をjsのどんなデータ構造に割り当てていくかは、色々な形が考えられると思うけど、結果的に以下のようにした。

  • リスト -> Array
  • シンボル -> nameというプロパティを持つオブジェクト
  • コンスセル -> car,cdr という2つのプロパティを持つオブジェクト
  • キーワードリスト (:key val :key val)みたいな。 -> Object (連想配列)

一応、S式 <-> js の相互変換ができるようにはなってる。(はず)

リスト

リストをArrayに変換するのは当たり前じゃん。と直感的には思っちゃうけど、
S式のリストというのは、配列ではなくて、ネストしたコンスセルなので、
たとえば、コンスセルをjsで

{ car: 1, cdr: 2}

と表現するとすると、
(1 2 3) というリストは、S式の実装としては、

{ car: 1, cdr: { car: 2, cdr: { car: 3, cdr: null } } }

と表現するのが正しいとおもう。
でもこんなことすると、数字添字とかループとか自前で実装しないといけないからちょっと不便だし、
効率が悪そうだから、一回実装してみたものの、やめてしまった。

連想配列

S式では連想配列っぽいものの表現が複数ある。

alist (コンスセルのリスト)
((a . 1) (b . 2))
ハッシュ

make-hashとかで作ったりするやつ。

klist キーワードリスト

:ではじまるシンボル(キーワードシンボル)と値が対になったふつうのリスト

(:a 1 :b 2)

ハッシュはちょっとリストとして表現するのがめんどくさかったので存在を無視した。
Elisp上だと、alistの方が、操作する関数が多くて扱いやすかったりするけど、
データとして扱うのはklistがお手軽だったので、klistにした。
(alistをObjectに変換するのも一応実装してみた)
キーワードリスト以外の目的でキーワードシンボルを使うことが皆無だとおもうので、
壊れた連想配列を作ってしまったりする可能性は、alistもklistも対してかわんないかなとおもって

cの#includeについてよくわかんなかったことメモ

cのヘッダファイルというものについて理解が浅くて、よくコンパイルエラーやリンクエラーをお見舞いされるので整理してみる。

スクリプト言語だと、どのソースファイルを使うか、プログラマがrequire等々で指定する仕組みが普通だと思うけど、
cの場合は少し違っていて、基本的にはソースファイルはすべてコンパイル時にコンパイラに引数として渡して知らせる。そしてプログラマがソースを参照するコード書かなくても、コンパイラがリンクをしてくっつけてくれる。ということのようだ。
ではなぜ#includeが必要かというと、コンパイル中に別のファイルで定義している名前に出くわしたとき、それが何か知る必要があるから。だから#includeは、最低限の宣言だけを含んだヘッダファイルを対象にするのが普通。ということのようだ。
#includeというのも、その名のとおりで、ただ指定したファイルを展開しているだけなのだった。

kawaii.h

#ifndef __kawaii__
#define __kawaii__

void kawaii();

#endif /* defined(__kawaii__) */

sample_include.c

#include "kawaii.h"

int main(int argc, char **argv) {
    return 0;
}

sample_include2.c

#include "kawaii.h"

これらのソースの#includeを展開してみる。

$ gcc -E sample_include.c sample_include2.c
# 1 "sample_include.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "sample_include.c"
# 1 "kawaii.h" 1



void kawaii();
# 2 "sample_include.c" 2

int main(int argc, char **argv) {
    return 0;
}
# 1 "sample_include2.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "sample_include2.c"
# 1 "kawaii.h" 1



void kawaii();
# 2 "sample_include2.c" 2

void hoge(); が書いてあるファイルをインクルードすることで、sample_include.c、sample_include2.c 両方で、void hoge();
という宣言をするのと同じ意味になる。

ということは、void hoge();みたいな宣言は、別々のファイルにそれぞれ同じ記述があったとしても、リンク時にエラーにならないようになってるということになる。
そこで、実験してみたところ、別々のファイルどころか、同じソースに複数あってもエラーにならなかった。

// コンパイル通った
void hoge();
void hoge();
void hoge();
void hoge();
void hoge();
void hoge();
void hoge();


int main(int argc, char **argv) {
    return 0;
}

ところが関数の実装は、複数あるとエラーになる

// エラーになる
void hoge() {}
void hoge() {}

int main(int args, char **argv) {
    return 0;
}

さらに、実装は、別々のファイルに同じ関数が存在することができない。リンク時にエラーになる。

sample_include.c

void hoge() {}

int main() {
    return 0;
}

sample_include2.c

void hoge() {}
$ gcc sample_include.c sample_include2.c
ld: duplicate symbol _hoge in /var/folders/c1/rg29l13n7mbgsvdj9z8mzcs00000gn/T//ccH7WdQJ.o and /var/folders/c1/rg29l13n7mbgsvdj9z8mzcs00000gn/T//ccrb3ou7.o for architecture x86_64
collect2: ld returned 1 exit status

以上がエラーになるということは、ヘッダファイルに関数の実装が書いてある場合、問題になることがあるということになる。
複数のソースから、実装を含むファイルを#includeするとリンク時にエラーになる。

kawaii.h

#ifndef __dame__
#define __dame__

static void dame() {
}

#endif /* defined(__dame__) */

sample_include.c

#include "dame.h"

int main(int argc, char **argv) {
    return 0;
}

sample_include2.c

#include "dame.h"

エラーになる。

$ gcc sample_include.c sample_include2.c
duplicate symbol _dame in:
    /var/folders/q2/v5jmn6hn6715x8n3v0kh9z6c0000gn/T//ccht1ehW.o
    /var/folders/q2/v5jmn6hn6715x8n3v0kh9z6c0000gn/T//ccqzLElm.o
ld: 1 duplicate symbol for architecture x86_64
collect2: ld returned 1 exit status

これを回避するにはstaticを使う。
static宣言した関数は、そのファイル内でしか公開されなくなる。
このstatic宣言した関数を#includeすると、#includeはファイルを展開するだけのマクロなため、
#include先のファイルでローカルな関数になる。

#ifndef __dame__
#define __dame__

static void dame() {
}

#endif /* defined(__dame__) */

上のように修正すると、さっきの例でコンパイル通るようになる。

$ gcc sample_include.c sample_include2.c

これをやると、#include先のファイル全てに同じ関数が存在することになって、プログラムのサイズが増えるから、inlineと併用するのが良いのかも。

日本語テキストを指定したフォントで描いてpng画像にするというimagemagickのコマンド覚えられないよ

imagemagickのオプションをどうしても覚えていられない。
よく使うコマンドをメモっておいても探すのに時間がかかったり、似てる機能しかメモってなかったりする。
これはもはや人間が使うよりコンピュータに使わせた方が扱いやすい道具っぽいと思い、
自分が良く使う機能のみに絞り、使い方に迷わないラッパーを書いてリポジトリに入れておくことにした。

ちょうどゲームを作っていて、日本語テキストの画像が大量に必要になったので、
設定ファイルを食わせると、imagemagickを叩きまくって、日本語テキスト画像を作りまくる。というスクリプトを作ってみた。

ソースこれ
GitHub - hadashiA/text2png: very simple imagemagick wrapper. configuration file to be rendered in png.

設定ファイルはこんな感じ。

dir '~/out/of/dir'

font 'ヒラギノ明朝 Pro W3.otf', :size => 10.pt do 
  'appearance.png'        << "おれたちの闘争本能に火が点いた!"
  'attack_sequence_0.png' << "今だ!みんなで袋叩きだ!"
  'attack_sequence_1.png' << "練習どおりに攻撃だ!"
  'attack_sequence_2.png' << "世界進出だ!"
  'tanuki_deshi.png'      << "野生のタヌキが弟子になった!"
end

font 'ヒラギノ角ゴ Pro W6.otf', :size => 12.pt do 
  'score.png'        << "SCORE:"
  'karate_count.png' << "おしりプリンプリン空手:"
  'enemy_count.png'  << "野菜ドロボウ:"
end

font 'ヒラギノ丸ゴ ProN W4.otf', :size => 40.pt do 
  'gameover.png' << "ゲームオーバー"
end

これしきの構造を記述するならjsonでも良いのだけど、rubyファイルの方がこれから機能追加するとき良い気がした。

そういえば、imagemagickの全機能をエミュレートしたRubyのライブラリとかがあったけど、コマンドラインと同じことができて全く別のインターフェイスが存在するのは覚えること増え過ぎな気がした。

iPhoneをリモコンにしてブラウザの絵を操作

node.jsのデモとしておもしろいのでメモ。
iPhoneの傾きをsocket.ioでサーバーに送って、socket.ioの全てのコネクションと同期させる。
iPhoneの加速度センサーは、Safari上のjavascriptからも利用できるので、javascriptだけでできる。

サーバー

  io.on('connection', function(socket) {
    socket.on('accelerate', function(accel) {
      socket.broadcast.volatile.json.emit('move', accel);
    });
  });

クライアント

回転のアニメーションは、jquery rotate を使いました。

  $(function() {
    var tyome = $('#tyome'),
        defaultLeft = parseInt(tyome.offset().left),
        socket = io.connect(socketIOUrl + '/tyomecon');


    socket.on('move', function(pos) {
      var angle = (parseInt(pos.left) - defaultLeft);
      tyome.css(pos).rotate(angle);
    });

    //tyome.draggable({
    //  drag: function(event, ui) {
    //    var pos  = ui.position,
    //        left = pos.left,
    //        angle = (left - defaultLeft);
    //        
    //    tyome.rotate(angle);
    //    socket.json.emit('accelerate', ui.position);
    //  }
    //});

    // iPhone
    window.addEventListener("devicemotion", function(event) {
      var gravity = event.accelerationIncludingGravity,
          left    = parseInt(tyome.css('left')) || 0,
          top     = parseInt(tyome.css('top')) || 0,
          angle = (left - defaultLeft);

      left += gravity.x;

      cssPos = {
        left: left + 'px',
        top:  top  + 'px'
      };

      tyome.css(cssPos).rotate(angle);
      socket.json.emit('accelerate', cssPos);
    });
  });

redisのハイレベルラッパー、redbackはけっこう良い。CappedList使ってみた

visionmediaさんが推しているからなのか? node.jsとredisの相性が良い理由は全く把握していないけど、node.jsでライブラリ、ドキュメントが充実しているKVSはredisだった。

redisは、リスト、ハッシュ、集合のデータ構造を保存できるから、そういうデータ構造使おうとすると、ハイレベルなラッパーがあった方がやっぱり使いやすい。
redbackの良いところは、redisの基本データ構造をサポートするだけでなく、それらに色々な機能を追加したデータ構造も実装してくれているところ。あと自分で定義できるところ。

ドキュメントは、この自動生成されたやつしか見当たらず。この形式検索できないしあんまり見易くないと思うんだけど、どうですか? (RubyのRDocのが良いなあ。)
http://redbackjs.com/api.html

// redis-nodeパッケージに依存しているけど、redbackだけrequireして使える
var redback = require('redback').createClient();
// redis-nodeを明示的にrequireしておいて、色々設定しておいてから
// redbackに渡すこともできる
var redis = require('redis'),
    redback = require('redback');

// redisの設定
redis.debug_mode = true;

redis = redis.createClient();
redback = redback.createClient(redis);

// redback.client で、redis-nodeのクライアントが返る
// redis == redback.client
redback.client.on('error', function(err) {
  console.log(err);
});

CappedList
保存するデータの数を制限するリスト。
データの数が制限に達していた場合、自動的にあふれたデータを削除してくれる。

var list = redback.createCappedList('unko', 3); // キーが'unko'、データ数の制限が3のリスト

list.push('year!');
list.push('oh-year!');
list.push('hey-year!');
list.values(function(err, values) { console.log(values) });
// ['year!', 'oh-year!', 'hey-year!']

list.push('so-i-year!');
list.values(function(err, values) { console.log(values) });
// ['oh-year!', 'hey-year!', 'so-i-year!']

list.unshift('ha-i-year!');
list.values(function(err, values) { console.log(values) });
// ['ha-i-year!', 'oh-year!', 'hey-year!']

list.get(1, 2, function(err, values) { console.log(values) });
// ['oh-year!', 'hey-year!']
// さっき保存したCappedListをただのリストとして取ることもできる。
var list = redback.createList('unko');

expressで、railsのcontent_for を実装する

expressのdynamicHelperは、スコープを維持したfunctionオブジェクトを返せるようなので、dynamicHelperを使うとでける。

ここを見たらわかりましたよ
http://stackoverflow.com/questions/3601080/how-do-i-pass-content-from-a-template-to-a-layout-in-express

  app.dynamicHelpers({
    pageTitle: function() {
      var _pageTitle = '';

      return  {
        get: function() {
          return _pageTitle;
        },

        set: function(val) {
          _pageTitle = val;
          return _pageTitle;
        }
      };
    }
  });


layout.jade

title
  良いサイト #{pageTitle.get() ? ' - ' + pageTitle.get() : ''}

index.jade

h1= pageTitle.set('ていやー!')

<title>良いサイト - ていやー!</title>
<h1>ていやー!</h1>

こんな感じ。

nginx_tcp_proxy_module を入れてnode.jsのsocket.ioを動かすnginxの設定

設定をメモ

node.js の、listenするあたりはこうしてみた。

// node.js(express)はunixソケットをlistenさせてみる。
var app = module.exports = express.createServer();
var sockPath = './tmp/sockets/express.sock';
app.listen(sockPath, function() {
  fs.chmodSync(sockPath, '777');
});

// socket.io はポート3001をlistenさせる。
var io = require('socket.io').listen(3001),

クライアントサイドで、socket.ioにつなぐコード

// 実際にはポート3001で動かしてるけど、
// 別のポート(3000)でふつうにnginxにリクエストして、
// tcp_poxy_moduleがsocket.ioの3001へプロキシする。
// こうしないと動かなかった
var socket = io.connect('http://example.com:3000');
socket.on('hey hey hey hey', function(data) {
  console.log(data);
});


nginxの設定

http {
  # 本当はhttpディレクティブのなかは他の設定もいろいろあるけど省略

  upstream node-js-myapp {
    server unix:/var/apps/myapp/current/tmp/sockets/express.sock;
  }

  server {
    listen 80;
    server_name example.com;
    root /var/www/myapp;

    location / {
      try_files $uri @node-js-myapp;
    }

    location ^~ /socket.io/ {
      try_files $uri @node-js-myapp;
    }

    location /websockets_status {
      check_status;
    }

    location @node-js-myapp { 
      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://node-js-myapp;
    }
  }
}


tcp {
  upstream websocket-myapp {
    server 127.0.0.1:3001;
    check interval=3000 rise=2 fall=5 timeout=1000;
  }

  server {
    listen 3000;
    server_name example.com;

    proxy_read_timeout 200000;
    proxy_send_timeout 200000;
    proxy_pass websocket-myapp;
  }
}