2012/08/09


gist に置いておくのも勿体ないかなと思ったので、こちらにも。
職業PGにわかるFizzBuzz - 日々常々

なんかFizzBuzzが書けないPGがどーとか定期的に話題になってるけど、私に言わせれば説明の仕方が悪い。

http://d.hatena.ne.jp/irof/20120808/p1
この設計書を参考に業務プログラマっぽくコードを書いてみた。
業務プログラマがFizzBuzz書いたらどうなるか ( ref: http://d.hatena.ne.jp/irof/20120808/p1 ) — Gist
https://gist.github.com/3292173
結構、設計書通りに作ったつもり。ループじゃなく、標準入力から読み込み、標準出力する部分も仕様通りです。
ただこの標準入出力を使っている事が裏目に出て、試験では標準入出力を一時的に差し替える必要があった。
試験コードだけ載せておく。
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;

import net.kaoriya.mattn.joke.FizzBuzz;

/**
 * FizzBuzzテストクラス.
 */
public class FizzBuzzTest {
    /** 標準入力退避用. */
    private InputStream in;

    /** 標準出力退避用. */
    private PrintStream out;

    /**
     * テスト開始前処理.
     *
     * <p>標準入力および標準出力を退避する</p>
     */
    @Before
    public void setUp() {
        in = System.in;
        out = System.out;
    }

    /**
     * テスト開始後処理.
     *
     * <p>標準入力および標準出力を復帰する</p>
     */
    @After
    public void tearDown() {
        System.setIn(in);
        System.setOut(out);
    }

    /**
     * テスト実行.
     *
     * <ul>
     * <li>標準出力を差し替える</li>
     * <li>標準入力を引数nを数値化した入力に差し替える</li>
     * <li>FizzBuzzクラスを生成する</li>
     * <li>FizzBuzz変換処理を実行する</li>
     * <li>標準出力された文字列と引数sで検証する</li>
     * </ul>
     *
     * @param n FizzBuzz変換処理に与える数値
     * @param s 期待する結果
     * @throws IOException 標準入出力処理に失敗した場合に発生
     */
    private void doFizzBuzz(int n, String s) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(baos);
        System.setOut(new PrintStream(bos));
        byte[] input = ("" + n + "\n").getBytes();
        System.setIn(new ByteArrayInputStream(input));

        FizzBuzz fb = new FizzBuzz();
        fb.runFizzBuzzConvert();

        System.out.flush();
        StringReader sr = new StringReader(baos.toString());
        String result = new BufferedReader(sr).readLine();
        assertEquals(s, result);
    }

    /**
     * FizzBuzz変換処理テスト.
     *
     * @throws IOException 標準入出力処理に失敗した場合に発生
     */
    @Test
    @SuppressWarnings
    public void testFizzBuzz() throws IOException {
        // CHECKSTYLE:OFF
        doFizzBuzz(1"1");
        doFizzBuzz(2"2");
        doFizzBuzz(3"Fizz");
        doFizzBuzz(4"4");
        doFizzBuzz(5"Buzz");
        doFizzBuzz(6"Fizz");
        doFizzBuzz(7"7");
        doFizzBuzz(8"8");
        doFizzBuzz(9"Fizz");
        doFizzBuzz(10"Buzz");
        doFizzBuzz(11"11");
        doFizzBuzz(12"Fizz");
        doFizzBuzz(13"13");
        doFizzBuzz(14"14");
        doFizzBuzz(15"FizzBuzz");
        doFizzBuzz(16"16");
        // CHECKSTYLE:ON
    }
}
一応、プロジェクトフォルダになっているので # git clone git://gist.github.com/3292173.git として貰ったら開発出来る様にしてある。gradle を使っているので # gradle build でビルド # gradle test でテスト。javadoc は # gradle javadoc でどうぞ。
ネタなのでツッコミなしでお願いします。ましてやバグチケット切るなど問題外です。
Posted at by




某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/08/01


togetterをvimからダラダラと見たいという衝動に駆られ作ってみました。
mattn/togetter-vim - GitHub

interface to togetter for vim

https://github.com/mattn/togetter-vim


:TogetterHot で注目一覧 :TogetterRecent で新着一覧が出ます。画面はこんな感じ
TogetterRecent
一覧でエンター押すと
Togetter
閲覧出来る。なにげに便利。
webapi-vim の最新版が必要。

追記
コメントなどは閲覧出来ない。やるかどうかは不明。
Posted at by