2012/02/01


こんにちわ。昨今、ウェブ開発の進化はすざましいですね。PythonやPerlやJava、色んな言語で書かれていると思います。
もちろん編集にはVimを使っているかと思います。
でも編集だけ?

違うよね!
Vim scriptはウェブアプリケーション記述言語なんだよ!

Plack::App::Vim
package Plack::App::Vim;
use strict;
use warnings;
use parent qw/Plack::Component/;
use Plack::Request;
use Encode;
use JSON::PP;

sub prepare_app {
    my $self = shift;
    $self->{vim} ||= 'vim';
    if (!$self->{server}) {
        open(my $f"vim --serverlist|");
        my $server = <$f>;
        close($f);
        chomp $server;
        $self->{server} = $server;
    }
    if (!$self->{encoding}) {
        open(my $fsprintf("%s --servername %s --remote-expr \"&encoding\"|",
            $self->{vim}$self->{server}));
        my $encoding = <$f>;
        close($f);
        chomp $encoding;
        $self->{encoding} = $encoding;
    }
    $self;
}

sub call {
    my ($self$env) = @_;
    my $req = Plack::Request->new($env);
    my $json = JSON::PP->new->ascii
        ->allow_singlequote->allow_blessed->allow_nonref;
    my $str = $json->encode({
        uri => $env->{PATH_INFO}||'',
        method => $req->method,
        headers => [split/\n/$req->headers->as_string)],
        content => $req->content,
    });
    $str =~ s!"!\\x22!g;

    my $command;
    if ($^O eq 'MSWin32') {
        $command = sprintf(
            '%s --servername %s --remote-expr "vimplack#handle("""%s""")"',
            $self->{vim}$self->{server},
            encode($self->{encoding} || 'utf8'$str));
    } else {
        $command = sprintf(
            "%s --servername %s --remote-expr 'vimplack#handle(\"%s\")'",
            $self->{vim}$self->{server},
            encode($self->{encoding} || 'utf8'$str));
    }
    open(my $f"$command|");
    binmode $f':utf8';
    my $out = <$f>;
    close $f;
    my $res = $json->decode($out);
    $res->[2][0] = encode_utf8 $res->[2][0] if $res;
    $res || [500, ['Content-Type' => 'text/plain'], ['Internal Server Error']];
}

1;

__END__

=head1 NAME

Plack::App::Vim - The Vim App in Plack

=head1 SYNOPSIS

  use Plack::Builder;
  use Plack::App::Vim;

  builder {
    mount "/" => Plack::App::Vim->new(server => 'VIM');
  };

=head1 DESCRIPTION

Plack::App::Vim allows you to write web application with Vim script.

=head1 AUTHOR

Yasuhiro Matsumoto

=head1 SEE ALSO

L<Plack>

=cut
Plack::Appのアプリケーションハンドラを書いたよ。これを起動するpsgiファイルを用意するよ!

app.psgi
#!perl
use lib qw/lib/;
use Plack::Builder;
use Plack::App::Vim;

builder {
    mount "/" => Plack::App::Vim->new(server => 'VIM');
};
引数のserverにはclientserver機能が使えるVimを立ち上げ、そのサーバIDを指定しておく必要があるよ!
そしてVim側にハンドラを書くよ!

autoload/vimplack.vim
scriptencoding utf-8

function! vimplack#handle(req)
  let req = json#decode(a:req)
  let res = [200, {}, ["hello world"]]
  return json#encode(res)
endfunction
PSGIプロトコルそのままですね!便利!

起動しよう!
# plackup app.psgi
HTTP::Server::PSGI: Accepting connections at http://0:5000/
ブラウザでhttp://localhost:5000を開こう!
Vim on PSGI
やたー!
あとはアプリケーション書き放題ですね!
試しに掲示板書いてみるよ!

autoload/vimplack.vim
scriptencoding utf-8

let s:comments = get(s:, 'comments', [])

function! vimplack#handle(req)
  let req = json#decode(a:req)
  if req.uri == "/"
    let res = [200{"Content-Type""text/html; charset=utf-8"}, [""
\."<html>"
\."<link rel='shortcut icon' href='/static/favicon.ico'>"
\."<title>comment board</title>"
\."<body>"
\."<form action='/regist' method='post'>"
\."コメント:<input type='text' name='comment' value='' /><br />"
\."<input type='submit' value='登録' />"
\."</form>"
\.join(map(copy(s:comments)'html#encodeEntityReference(v:val)')'<br />')
\."</body>"
\."</html>"
\]]
  elseif req.uri == '/regist' && req.method == 'POST'
    let params = {}
    for _ in map(split(req.content, '&')'split(v:val,"=")')
      let params[_[0]] = iconv(http#decodeURI(_[1])'utf-8', &encoding)
    endfor
    if has_key(params, 'comment')
      call add(s:comments, params['comment'])
    endif
    let res = [302{"Location""/"}, [""]]
  else
    let res = [404{}, ["404 Dan Not Found"]]
  endif
  return json#encode(res)
endfunction
アプリケーションの更新はVimを再起動するかautoload/vimplack.vimを開いている常態なら :so %
で行けるよ!
Vim on PSGI

知らんかったー
Vim scriptはウェブアプリケーション記述言語やったんやー
mattn/p5-Plack-App-Vim - GitHub

Vim Application Handler for PSGI

https://github.com/mattn/p5-Plack-App-Vim
Posted at by



2012/01/25


やっぱり最初はhello worldって事で...

Rust

RustRust a safe, concurrent, practical language Rust is a curly-brace, block-structured expression langu...
Rust is a curly-brace, block-structured expression language. It visually resembles the C language family, but differs significantly in syntactic and semantic details. Its design is oriented toward concerns of “programming in the large”, that is, of creating and maintaining boundaries – both abstract and operational – that preserve large-system integrity, availability and concurrency.

http://www.rust-lang.org/
windowsのインストーラがダウンロード出来なかったのでgithubからダウンロードしてビルドした。
mozilla/rust - GitHub

a safe, concurrent, practical language

https://github.com/mozilla/rust
ビルドはmingw/msysで./configure && make install
LLVM上のコンパイラなのでビルドは結構リソースを食う。かなり食う。

ただ単にfizzbuzz出してもdanさんの真似になって面白く無かったのでメッセージボックス出してみた。
use std;
import std::io;

#[abi = "stdcall"]
native mod user32 {
  fn MessageBoxA(h: ctypes::c_uint,
      message: str::sbuf, title: str::sbuf, flag: ctypes::c_uint)
        -> ctypes::c_uint;
}

fn main() {
  str::as_buf("hello", { |message|
    str::as_buf("world", { |title|
      user32::MessageBoxA(0u, message, title, 0u);
    })
  })
}
abiとしてcdeclやstdcallが指定出切る。rustcコマンドはuser32に対してちゃんと-luser32というリンクオプションを足してくれるので、コマンドラインでガチャガチャやるイメージはあまりない。
なお、CARGO_ROOTという環境変数にc:/rust/binc:/rust/libでいう所のc:/rustを指定しておくと、ちゃんとリンカが判断してファイルを探してくれる。
vim編集中に簡単に実行出切る様に、quickrunにもプルリクエストを送っておいた。(マージされた)
#22: support mozilla rust. by mattn for thinca/vim-quickrun - Pull Request - GitHub
https://github.com/thinca/vim-quickrun/pull/22

環境が揃うユーザならば、vimでファイル開いて<leader>rとタイプすればメッセージボックスが出る様になります。
rust-win32
所感としては、str::as_bufがブロック式なので、rubyっぽく思えると同時に引数2つの場合めんどくさ過ぎる!と思った。言語というか、仕組み的にはGo言語が近いなーとか思ってたら、Dubheadさんから教えてもらったリンクに既に書いてあった。
Doc language FAQ - GitHub

Have you seen this Google language, Go? How does Rust compare?

面白そうなのでしばらく触ってみる。
Posted at by



2012/01/17


trieなんたらが話題になってたのでなんとなく書いてみた。
ベンチとかはやってない。
404 Blog Not Found:Algorithm - 連想配列の実装としてのハッシュはオワコン?

そのデータ構造は、君の魂を差し出すに足るものかい? 連想配列( Associative array )がコレクション( Collection )、すなわち数多のデータ構造をまとめるデータ構造としての覇...

http://blog.livedoor.jp/dankogai/archives/51765855.html
#include <stdio.h>
#include <stdlib.h>

typedef struct _trie {
  char c;
  unsigned int n;
  struct _trie** next;
  void* value;
} trie;

trie*
trie_new() {
  trie* p = (trie*) malloc(sizeof(trie));
  p->c = 0;
  p->n = 0;
  p->next = NULL;
  return p;
}

void
trie_free(trie* p) {
  unsigned int i;
  for (i = 0; i < p->n; i++)
    trie_free(p->next[i]);
  if (p->n)
    free(p->next);
  free(p);
}

trie*
trie_put(trie* p, const char* key, const void* value) {
  if (*key == 0) {
    p->value = (void*) value;
    return p;
  }
  trie* next = NULL;
  int i;
  for (i = 0; i < p->n; i++)
    if (p->next[i]->c == *key) {
      next = p;
      break;
    }
  if (!next) {
    if (!(next = trie_new())) return NULL;
    trie** children = (trie**) realloc(p->next, p->n * sizeof(trie*));
    if (!children) return NULL;
    p->next = children;

    next->c = *key;
    p->next[p->n] = next;
    p->n++;
  }
  return trie_put(next, key+1, value);
}

trie*
trie_get(trie* p, const char* key) {
  if (p->c) {
    if (p->c != *key)
      return NULL;
    if (p->c == *key && *(key+1) == 0)
      return p;
    key++;
  }
  int i;
  trie* value = NULL;
  for (i = 0; i < p->n; i++) {
    if ((value = trie_get(p->next[i], key)))
      return value;
  }
  return NULL;
}

void
safe_puts(const char* key, const trie* p) {
  if (!p)
    printf("%s not found\n", key);
  else if (!p->value)
    printf("%s: null\n", key);
  else
    printf("%s%s\n", key, (char*) p->value);
}

int
main(int argc, char* argv[]) {
  trie* p = trie_new();
  trie* v;

  trie_put(p, "foo""bar");
  trie_put(p, "bar""baz");

  v = trie_get(p, "baz");
  safe_puts("baz", v);

  v = trie_get(p, "foo");
  safe_puts("foo", v);

  v = trie_get(p, "bar");
  safe_puts("bar", v);

  trie_put(p, "うんこ""うんこっこー");
  v = trie_get(p, "うんこ");
  safe_puts("うんこ", v);

  v = trie_get(p, "404 blog");
  safe_puts("404 blog", v);

  trie_free(p);
  return 0;
}
baz not found
foo: bar
bar: baz
うんこ: うんこっこー
404 blog not found
Posted at by