予算ジェネレーターのソースコードを公開

GitHub に予算ジェネレーターのソースコードを公開しました。

GitHub と Google Code のどちらで公開するか迷いましたが、自分のプロジェクトが dashboard に一覧表示される点と、Git を採用している点、この2点で GitHub に決定。

Source のページからブラウザ上でソースコードを閲覧できます。また、download ボタンを押すとソースコードをアーカイブしてダウンロードできます。これは便利。Google Code にも欲しい機能ですね。

2011-03-28 追記

GitHub から Bitbucket に移行するため、ソースコードはこの記事に貼り付けておきます。

index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="jp" lang="jp">
    <head>
        <meta http-equiv="content=type" content="text/html;charset=UTF-8" />
        <title>予算ジェネレーター</title>
        <style type="text/css">
            body {
                font-family: Verdana, Helvetica, sans-serif;
                text-align: center;
            }

            #footer {
                margin-top: 15px;
            }
        </style>
    </head>
    <body>
        <div id="header">
            <img src="http://img.f.hatena.ne.jp/images/fotolife/g/griefworker/20090723/20090723204936.png" alt="20090723204936">
        </div>

        <div id="inner">
            <p>
            「収入に占める適性割合」をもとに、あなたに適した1ヶ月の予算を算出します。
            </p>
            <p>
            月収を入力して下さい。
            </p>

            <form method="post" action="/">
                <input type="text" name="money"/><input type="submit" value="予算作成"/>
            </form>

            {% if error_message %}
            <div style="color:#F00">{{ error_message }}</div>
            {% endif %}

            {% if budget %}
            <p>
            あなたの月収 {{ input }} 円に適した、1ヶ月の予算は次の表の通りです。
            </p>
            <table align="center" border="1">
                <tr>
                    <th>費目</th>
                    <th>金額(円)</th>
                </tr>
                <tr>
                    <td>食費</td>
                    <td>{{ budget.food }}</td>
                </tr>
                <tr>
                    <td>住居費</td>
                    <td>{{ budget.housing }}</td>
                </tr>
                <tr>
                    <td>水道光熱費</td>
                    <td>{{ budget.utilities }}</td>
                </tr>
                <tr>
                    <td>通信費</td>
                    <td>{{ budget.communication }}</td>
                </tr>
                <tr>
                    <td>こづかい</td>
                    <td>{{ budget.allowance }}</td>
                </tr>
                <tr>
                    <td>保険料</td>
                    <td>{{ budget.insurance }}</td>
                </tr>
                <tr>
                    <td>趣味・娯楽費</td>
                    <td>{{ budget.entertainment }}</td>
                </tr>
                <tr>
                    <td>被服費</td>
                    <td>{{ budget.clothing }}</td>
                </tr>
                <tr>
                    <td>交際費</td>
                    <td>{{ budget.business }}</td>
                </tr>
                <tr>
                    <td>日用雑費</td>
                    <td>{{ budget.incidental }}</td>
                </tr>
                <tr>
                    <td>その他</td>
                    <td>{{ budget.other }}</td>
                </tr>
                <tr>
                    <td>貯蓄</td>
                    <td>{{ budget.savings }}</td>
                </tr>
            </table>

            {% endif %}
        </div>

        <div id="footer">
            <address>
                &copy; 2009 <a href="http://d.hatena.ne.jp/griefworker">griefworker</a> 
            </address>
        </div>
    </body>
</html>
main.py
# -*- coding: utf-8 -*-

import os

from decimal import *
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app

def round_down(value):
    return Decimal(value).quantize(Decimal("1."), rounding=ROUND_DOWN)

# 予算
class Budget:
    def __init__(self, money):
        # 食費
        self.food = round_down(money * Decimal("0.17"))
        # 住居費
        self.housing = round_down(money * Decimal("0.27"))
        # 水道光熱費
        self.utilities = round_down(money * Decimal("0.06"))
        # 通信費
        self.communication = round_down(money * Decimal("0.05"))
        # こづかい
        self.allowance = round_down(money * Decimal("0.07"))
        # 保険料
        self.insurance = round_down(money * Decimal("0.06"))
        # 趣味・娯楽費
        self.entertainment = round_down(money * Decimal("0.03"))
        # 被服費
        self.clothing = round_down(money * Decimal("0.03"))
        # 交際費
        self.business = round_down(money * Decimal("0.03"))
        # 日用雑費
        self.incidental = round_down(money * Decimal("0.02"))
        # その他
        self.other = round_down(money * Decimal("0.06"))
        # 貯蓄
        self.savings = round_down(money * Decimal("0.15"))

class MainPage(webapp.RequestHandler):
    def render(self, template_name, template_values={}):
        path = os.path.join(os.path.dirname(__file__), template_name)
        self.response.out.write(template.render(path, template_values))

    def render_error(self, error_message):
        input = self.request.get("money")
        template_values = {
                "error_message": error_message,
                "input": input,
                }
        self.render("index.html", {"error_message": error_message})

    def get(self):
        self.render("index.html")

    def post(self):
        # 月収が入力されていない場合はトップページへ移動
        input = self.request.get("money")
        if not input:
            self.render_error("月収が入力されていません。")
            return

        # 正しい金額が入力されていない場合はトップページへ移動
        try:
            value = Decimal(input)
        except InvalidOperation:
            self.render_error("正しい金額が入力されていません。")
            return

        # 入力された金額がマイナスの場合はトップページへ移動
        if value < 0:
            self.render_error("金額をマイナスにはできません。")
            return

        budget = Budget(value)
        template_values = {
                "input": input,
                "budget": budget,
                }
        self.render("index.html", template_values)

application = webapp.WSGIApplication(
        [
            ('/', MainPage),
            ],
        debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()