2012/08/09


某SNSでFizzBuzzが再燃しておりますが、面接時の足きり尺度としてFizzBuzzが使えるかどうかは別として、コードとしてFizzBuzzは有益でもなんでも無いので、FizzBuzzを題材としたコードを晒してみる。 Go言語には、元々Gobと呼ばれるエンコーダが同梱されていて、Goで扱える型をストリーム上に垂れ流しデコードする事が出来る。かつ、RPCも用意されているので小規模なクラサバならば簡単に書けてしまう。
巷のRPCは、エンティティからスタブを作ったり面倒だったりしますが、Go言語ではクライアントとサーバの意識さえ合っていればスタブも必要ない。
まずサーバ package main

import (
    "fmt"
    "net"
    "net/rpc"
)

type FizzBuzz int

func (fb *FizzBuzz) Serve(n int, r *stringerror {
    switch {
    case n % 15 == 0:
        *r = "FizzBuzz"
    case n % 3 == 0:
        *r = "Fizz"
    case n % 5 == 0:
        *r = "Buzz"
    default:
        *r = fmt.Sprintf("%d", n)
    }
    return nil
}

func main(){
    fb := new(FizzBuzz)
    rpc.Register(fb)

    server, _ := net.Listen("tcp"":8001")
    for {
        client, err := server.Accept()
        if err != nil {
            println(err.Error())
            continue
        }
        rpc.ServeConn(client)
    }
}
Register に渡される型のメソッドで、入力引数、戻り値のアドレス の二つを引数に持ち、戻り値に error を持つ物はエクスポートされる。なのでこの場合、n が FizzBuzz の入力、r が戻り値へのアドレスになる。
尚、このRPCは透過性があるので、別に TCP でなくても構わない。

次にクライアント。型がサーバと一致しているのなら、とても簡単に呼び出せる。 package main

import (
    "net/rpc"
)

func main() {
    client, _ := rpc.Dial("tcp""localhost:8001")
    var ret string
    for i := 1; i <= 100; i++ {
        client.Call("FizzBuzz.Serve", i, &ret)
        println(ret)
    }
}
GobというGo言語に特化したエンコーダなので、他の言語でも...という訳には行かないが、ちょっとした物を作る時にはかなり便利である。
尚、Go言語には net/rpc/jsonrpc も含まれていて、こちらを使えばポータビリティのある RPC が書ける様になっている。
Posted at by



2012/07/27


プログラム中に HTML とか埋め込むためのテンプレートエンジン picotemplate を作った件 - kazuhoのメモ置き場

たとえばドキュメント生成ツールなんかを作ってると、HTML をプログラムの中で生成したい!ってことは良くあると思います。でも、そのためにいちいちテンプレートエンジンを使うのは大げさな場合も多いですよね。たとえば、ちょっとリストを出力するとき。以下のような感じのコードを書いたことがある人は多いと思います。

http://d.hatena.ne.jp/kazuhooku/20120726/1343290960
例えばこんなのどうだろう
#include <string>
#include <list>
#include <iostream>

#define _(...) std::string(#__VA_ARGS__)

int
main() {
  std::list<std::string> list = {
    "foo""bar""baz"
  };

  std::string code = _( <ul class="mylist">\n );
  for (auto i = list.begin(); i != list.end(); ++i) {
    code += _( <li class="mylist-item"> ) + *i + _( </li>\n );
  }
  code += _( </ul> ); 

  std::cout << code << std::endl;
}
出力結果
<ul class="mylist">
<li class="mylist-item">foo</li>
<li class="mylist-item">bar</li>
<li class="mylist-item">baz</li>
</ul>
いや、エスケープとか全く考えてないけどね。

Posted at by



2012/07/26


キモトの関係で自分が発言したときに通知が欲しいですね


https://twitter.com/bulkneets/statuses/222928161023868929
作りましょう!
#!perl
use strict;
use warnings;
use utf8;
use Config::Pit;
use AnyEvent::Twitter::Stream;
use Growl::Any;
use YAML::Syck;

my $icon = 'https://api.twitter.com/1/users/profile_image?screen_name=bulkneets';
my $growl = Growl::Any->new(appname => "キモトwatcher"events => ["ヤバイ"]);

my $done = AnyEvent->condvar;

my $config = pit_get("api.twitter.com"require => {
    consumer_key        => 'consumer key on twitter',
    consumer_secret     => 'consumer secret on twitter',
    access_token        => 'access token on twitter',
    access_token_secret => 'access token secret on twitter',
});

binmode STDOUT":utf8";

my $streamer = AnyEvent::Twitter::Stream->new(
    consumer_key    => $config->{consumer_key},
    consumer_secret => $config->{consumer_secret},
    token           => $config->{access_token},
    token_secret    => $config->{access_token_secret},
    method          => 'filter',
    follow          => '3523861',
    on_tweet        => sub {
        my $tweet = shift;
        #warn Dump $tweet;
        #warn $tweet->{source};
        if ($tweet->{source} =~ 'キモト') {
            my $text = $tweet->{text};
            $growl->notify("ヤバイ""キモト"$text$icon);
            warn $text;
        }
    },
    on_error => sub {
        my $error = shift;
        warn "ERROR: $error";
        $done->send;
    },
    on_eof => sub {
        $done->send;
    },
);

$done->recv;
Windows の Growl For Windows でも動作します。
AnyEvent::Twitter::Stream の follow にスクリーンネームを渡していて少しハマったのは内緒。
token をどうやって取得するかは、プログラマなら知ってるはずなので頑張って下さい。
キモトwatcher
イベントで魚拓を取るも良し、メールするも良し、お役立て下さい。
Posted at by