doctestの誕生についてを翻訳してみた

動機

1ヶ月ほど前にネットを徘徊していたらTim PetersがdoctestについてコメントをGoogleGroupsに書いていたので、興味半分で読んでいたらなんとそれがdoctestのプロトタイプコードだった。

Pythonの中で好きなモジュールを挙げよって言われたらおそらく真っ先にdoctestと答えるだろうってぐらい好きだし、このモジュールの強力なところはテストとしてもドキュメント中のサンプルコードとしても振舞いが可能であると言う点が非常にエレガント。
さらにこれが後にDDD(Docstring Driven Development, 巷でよく言われてるDomain Driven Developmentじゃないよ)となったという歴史的瞬間でもあったと考えたらモチベーション右肩上がりですw

翻訳文

翻訳は自分のbitbucketに公開してあるのでそちらを参照してください。
現状ではドラフト段階ですがそのうち正式版にします。

Bitbucket | The Git solution for professional teams

フィードバック

フィードバックについては大歓迎です。
コメントに残していってもらって結構です。


FlashBuilder4でのデータとサービスでハイフンが入ったタグ名を回避する方法

きっかけ

自宅サーバーにSubsonicというミュージックサーバーを動かしていて、こいつはAPIを使っていろいろクライアントを作れたりする。
実際にいくつかクライアントが公式ページで紹介されている。
そこでAIRを使って自分で遊んでみようと思いたって作る事にした。
FlashBuilder4から新しく使えるようになった「データとサービス」を使うとWebサービスなどのデータがものすごく簡単にアクセスできるようになった。
ところがいざSubsonicAPIを使って「戻り値の型を設定」のウィザードにある自動検出で操作を呼び出して設定しようすると下のようなエラーが出て先に進めず...


ActionScript命名規則の壁

SubsonicAPIXMLかMP3などのバイナリを返してきくるが、XMLのタグにハイフンが含まれているせいであるようだ。
実際にハイフンを除いてウィザードの「サンプルXML/JSON応答を入力」を選び、図の様に入力すると問題無く次に進む。
ググってみたらどうやらXMLパーサーが解析したタグの名前をプロパティ名に充てようとするために起こるらしい。

具体的に言うとXMLに"foo-tag"というタグ名があるとオブジェクトは次の様にマッピングしようとする(多分

HogeObj.foo-tag

ハイフンはマイナス演算子として扱われるためにエラーになるらしい。
回避方法としては[]を使ってインデックスに文字列を指定してアクセスすればいけるらしい。
でも今回はデータとサービスの機能を使いたいしということで却下w

Flaskでproxy的な使い方をする

まずFlaskを簡単に説明するとRubyでいうSinatraにあたるマイクロWebフレームワーク。
詳しく知りたい方はググってください。

で、具体的な方法はFlaskがSubsonicサーバーのフロントエンドになりFlaskのハンドラがurllib2でアクセスしにいってその中のXMLを書き換えるという強引な方法。
こうした理由はHTML5でも使う予定をしてるけどサーバーが返すレスポンスが少しマズいのでaudioタグで再生できないというのが有ったし、いろいろ書き換えて遊ぶためにFlaskを採用した。
まあ最もお前の趣味だろと言われれば否定しないけどw

コード

今回できたコードが以下。
とりあえうず動く確証が欲しかったのでベタ書き&ping.viewのAPIのみしか動きませんが...

#! python
# -*- coding:utf-8 -*-

from flask import Flask
import urllib2

BASEURL = 'http://<subsonic-url>/rest/'

app = Flask(__name__)


@app.route("/ping.view")
def do_ping():
    target_action = "ping.view?u=USERNAME&p=PASSWORD&v=VERSION&c=CLIENTNAME"
    result = urllib2.urlopen(BASEURL + target_action)
    result_body = result.read()
    return result_body.replace("subsonic-response", "subsonicResponse")
    

if __name__ == '__main__':
    app.run(debug=True)

ちなみにユーザー名とかパスワードとか(GETパラメータのu,pの部分)べた書きすればパスワード無しでAPI使えるだだ漏れミュージックサーバーができる。

今後の改良点

上のコードだとAPIの数だけルーティング書かないといけなくなりさすがに面倒臭いのでURLの部分からぶっこ抜いて横流しすれば関数1個で済む。
というコードが書けたらいいなあと思ってる。
あとはデータを弄る関数を分離することぐらいかな。

iPadでPDFをiBooksに保存する方法

あらまし

会社のiPadを使ってる上司からSafariでPDFを開いたらそれを保存していつでもオフラインで見たいんだけどなんかいい方法ないの?と言われて自分もちょっと気になったので調べてみた。

iBooksで開く

普段はiPhone使ってるのでPDFダウンロードするとiBooksで開くというボタンが開く事が出来るけどiPadSafariには無く、どうやらiOS4Safariの機能らしい。
ということでこの方法は秋まで待つしかない。

Goodreader経由で開く

幸い上司の持っているiPadにはGoodreaderが入っていて、最初はURLコピーしてGoodreaderでペーストしてダウンロードしてそれをiBooksで開いてくださいという提案をしたら、そんなめんどくせー事いちいちやってられるかとあっさり却下された。
で、今日しばらく調べたらhttpの前にgをつけて、ghttp:// 〜にすればGoodreaderで開けるらしい。
さすがにアドレスバーにコピペしてgつけてくださいって言っても二の舞になりかねないのでブックマークレットを作る事にした。

ブッマークレットのソース

スペースはURLエンコードしてやるのが正しいんだろうけど、しなくてもうまくいったのでとりあえず貼っとく。

javascript:var a=document.getElementsByTagName('a');for(var i=0;i<a.length;i++){if(a[i].href.search(/^http:\/\/.*\.pdf$/i)==0){a[i].href='g'+a[i].href;}}

解説するとhttp:// 〜.pdfのリンクのURLの先頭にgをつけて書き換えるということをしているだけです。
解説終わり。

バグや改善などあったら指摘いただければ幸いです。

SimpleHTTPServerのMIMEタイプ追加

HTML5GPSロガー作ろうと言う事でコーディング中。
んで山の中の僻地言った場合どうすんのよとかいちいちつなぐとお金掛かるし的な事を考えてOffline Web Applicationsを使おうとなり、習得の為に写経することにした。

とりあえずテスト用にHTTPサーバーが欲しいときにはPythonistaな人なら迷わず

python -m SimpleHTTPServer

とやってると思います。

Offline Web Applicationsを実現するにはキャッシュマニフェストというものを書かないといけないんだけど、それのMIMEタイプが"text/cache-manifest"にする必要がある。
そこでMIMEタイプを追加する方法を調べたらSimpleHTTPHandlerのextensions_mapにマッピングを追加すればいいらしい。
ちなみにextensions_mapはdict型です。

出来たコードは以下。
コード自体は9割公式マニュアルのパクリです。

#! python
# -*- coding:utf-8 -*-

import SimpleHTTPServer
import SocketServer

PORT = 8000

Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
Handler.extensions_map['.manifest'] = 'text/cache-manifest'

httpd = SocketServer.TCPServer(("",PORT), Handler)

print "serving at port", PORT
httpd.serve_forever()

取得結果もばっちり。

TDDBC名古屋に参加してきた

前回のTDDBC北陸は私事により1日しか参加できなかったので今回はフルでTDDBCに参加してきました。
企画していただいた @bleis さんをはじめスタッフの方々、講師をしていただいた @t_wada さんありがとうございました!

感想

まとめようと思ってブレストしてたらなんか普通にマインドマップ書いてたのでこっちをさらします。
検索性が劣るのが難点なので気が向いたらテキストに落とす作業します。


そういえば

Scalaチームがすごい熱かったですね。あのモチベーションはこちらも触発された。
あと名古屋アジャイル勉強会の型のおかげで大人数でのKPTスタンドアップミーティングを体験することができたのがすごくよかったです。

rst2pdfの日本語周り設定

日本語でrstファイルを書いてそのままrst2pdfに突っ込むと大変残念なPDFが生成される。
ググったところフォントとスタイルシートを設定すればいいらしい。
具体的な設定は以下を参照してください。
rst2pdfをWindowsで使ってみた - 偏った言語信者の垂れ流し

本題

で、このスタイルシートとフォントの指定をいちいちするのは非常に面倒。
たまにしか使わないからいいかと思ったけど、たまにしか使わないので毎回「オプションどうやって書いたっけ?」な状態。
調べたら公式マニュアルに設定ファイルを書けと載っていたので設定してみたところ無事できた。

設定ファイル

以下自分が使っている設定ファイル。
フォントやスタイルシートは先述の日本語の設定の記事を書いたid:nurupobugさんのものを基に自分の環境に合わせたもの使ってます。

# This is an example config file. Modify and place in ~/.rst2pdf/config
[general]
# A comma-separated list of custom stylesheets. Example:
# stylesheets="fruity.json,a4paper.json,verasans.json"
stylesheets="~/.rst2pdf/ja.json"
# Create a compressed PDF
# Use true/false (lower case) or 1/0
# Example: compressed=true
compressed=false
# A colon-separated list of folders to search for fonts. Example:
# font_path="/usr/share/fonts:/usr/share/texmf-dist/fonts/"
font_path="C:/Fonts"
# Language to be used for hyphenation support
language="ja_JP"
# Default page header and footer
header=""
footer=""
# What to do if a literal block is too large. Can be
# shrink/truncate/overflow
fit_mode="shrink"
# What is the maximum level of heading that starts in a new page.
# 0 means no level starts in a new page.
break_level=0

header, footerはNoneにしておくと何故かそのまま"None"と入ってしまうので空文字を設定した。

rst2pdf公式マニュアル和訳

3章の設定ファイルを抜粋で翻訳。
かなり適当なので、翻訳ミス等がありましたらご指摘ください。
自分で訳しておきながら自分の設定ファイルは英語というw

3 設定ファイル
バージョン0.8からrst2pdfは/etc/rst2pdf.confと~/.rst2pdf/configにある設定ファイルを読み込みます(設定ファイルがある場合)。
~/.rst2pdf/configの設定ファイルは/etc/rst2pdf.confにある設定ファイルより優先されます。
以下に現在使用できる設定とファイル内容の例を示します。

# これは設定ファイル例です。修正して~/rst2pdf/configに置いてください。
[general]
# カンマ区切りのカスタムスタイルシートのリスト。
# 例:"fruity.json,a4paper.json,verasans.json"
stylesheets=""
# 圧縮されたPDFを生成
# 使用する true/false (全て小文字) もしくは 1/0
# 例: compressed=true
compressed=false
# コロン区切りのフォントサーチパスのリスト
# 例: font_path="/usr/share/fonts:/usr/share/texmf-dist/fonts/"
font_path=""
# 言語のハイフネーションサポート
language="en_US"
# デフォルトのページヘッダとページフッタ
header=None
footer=None
# リテラルブロックが大きすぎる場合の処理
# shrink/truncate/overflow
fit_mode="shrink"
# 改ページ処理のヘッディング最大レベルを指定します。
# 0は改ページ処理のレベルを設定しないことを意味します。
break_level=0

rst2pdfにある設定例にはすべてのオプションが含まれています。

小数点の表し方とメソッド呼び出し

第2回Python-FITで

dir(3)で調べると、3はrealというメソッドを持っている。しかし3.realはできない。なぜ?

という質問が出た。

確認してみると

>>> 3.real
  File "<stdin>", line 1
    3.real
         ^
SyntaxError: invalid syntax

確かにエラーだ。
その時自分も咄嗟には答えられなかったけど、書籍版Pyチュー第1版かなんかに

整数に.をつけると小数点として扱われる。

的なものを思い出した。そこで確認したら、

>>> type(3)
<type 'int'>
>>> type(3.)
<type 'float'>

となった。んで、float型がraalメソッドは持っているかということを確認したら、

>>> dir(3.)
['__abs__', '__add__', '__class__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getformat__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__int__', '__le__', '__long__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__nonzero__', '__pos__', '__pow__', '__radd__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruediv__', '__setattr__', '__setformat__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', 'as_integer_ratio', 'conjugate', 'fromhex', 'hex', 'imag', 'is_integer', 'real']

問題なくある様子。ということで上記の結果から導き出される事実は、

浮動小数点の表記間違ってるぞゴルァ

ということで怒られているんだろう。正しくは、

>>> int(3).real
3
>>> (3).real
3

2つ目は何をしているかと言うと、ただし()内の演算は行おうとして、何もせず整数の3を返し、realメソッドを呼び出す。という動作(多分

余談

Pythonだとこんなキモい表記が許されるようです。

>>> 3..real
3.0