ReST(ReStructuredText)を使おう

もちろん,この日記を見ている方々はオフラインドキュメントはTexかHTMLかなにかのマークアップ言語で書かれている事でしょう.

自分もそうです.

(Texが嫌いとか言う人はいないよね.世の中に...???)

TexもHTMLも悪くないんですが,いかんせんヘヴィ.

Texはさすがにさくさく書きたいのにコンパイルに失敗した日にはキーボード破壊したくなりますよね.HTMLはいいんですが,ササッと書くのには不向き.

というわけで,もっと限定的な機能をもったドキュメント作成言語がないかと思っていたのですが,

先日id:moqadaにReST(ReStructuredText)を教えてもらったので,ちょっと書いておきましょう.

ReST(ReStructuredText)

ReSTはwiki記法やはてな記法に似た記述で汎用性のあるドキュメントの作成を行えるマークアップ言語.

Pythonで書かれたDocutilsのコンポーネントの一つで,Docutilsのツールを使えば,tex, HTML, XML, S5などのドキュメントに吐き出しができる.

こんなかんじ.

========
Title
========


Section

              • -

- asdf
- asdf
- qwer

HTMLへの吐き出しにはテンプレートを使う事もできる.便利.

環境構築

環境を作る.emacsで全てが完了する環境を作る.またrst2pdf(ReSTからPDFを直接吐くプログラム)はDodutilsに入っていいので別途いれる.

対象の環境はMacOSX10.5 / Python2.6

インストールするパッケージと設定の指針を先に書いておく.

  • Docutils
  • rst2pdf
    • VLFont
    • ~/.rst2pdf/config
    • rst.el
    • rst.elショートカットキー

Docutils

インストールしましょう.まずは.

Docutils本家にソースがあるので落として解凍してインストール.

$ cd src
$ tar xvf docuitls-0.5.tar
$ cd docutils-0.5
$ sudo python setup.py install

標準のインストール先はPythonの実行バイナリ先のようなので

(Python2.6 on MacOSXなら'/Library/Frameworks/Python.framework/Versions/2.6/bin/')
(MacOSX標準のPython2.5なら'/System/Library/Frameworks/Python.framework/Versions/2.5/bin/')

必要ならパスを通す.

rst2pdf

Docutilsにはpdfに直に出力するrst2pdfが入っていない.

というわけで別途コンパイルする.

まず,rst2pdfの本家サイトを読むとReportLabとPIL(PythonImageLibrary)が必要なのだが,

ReportLabとPILは僕の場合既に入っているので割愛.おいいいいい

#PILとReportLabを正常にインストールしてから.
$ cd src
$ sudo python setup.py install

TTF日本語フォント

rst2pdfでpdf吐き出しをするとき,日本語の場合は日本語フォントが必要.

MacOSXは標準だとotfフォントなのでVLフォントあたりをもってくる.

$ cd src
$ curl -O https://sourceforge.jp/projects/vlgothic/downloads/41233/VLGothic-20090710.tar.bz2
$ tar xvf VLGothic-20090710.tar.bz2
$ sudo mv ./VLGothic/VL-* /Library/Fonts/ #homeのLibrary下でもおk

~/.rst2pdf/default-style.json

rst2pdfはスタイルシートを使える.スタイルは本来細かなスタイルを指定する.

日本語の場合は使うフォントを指定できるので,日本語を含むテキストの場合はスタイルを指定しましょう.

{"embeddedFonts" :
 [["VL-PGothic-Regular.ttf",
   "VL-PGothic-Regular.ttf",
   "VL-PGothic-Regular.ttf",
   "VL-PGothic-Regular.ttf"]],
 "fontsAlias" : {
     "stdFont": "VL-PGothic-Regular",
     "stdBold": "VL-PGothic-Regular",
     "stdItalic": "VL-PGothic-Regular",
     "stdMono": "VL-PGothic-Regular"
 },
 "styles" : [["base" , {"wordWrap": "CJK"}],
             ["literal" , {"wordWrap": "None"}]]
}

~/.rst2pdf/config

で,~/.rst2pdf/configにディフォルト動作の設定を書いておく.こうすると,実行時の引数を省略できる.

(~/.rst2pdf/configは個人用で,これとは別に/etc/rst2pdf.confgでも設定できる)

今回は最低限日本語が表示できればいいので,フォント格納先とディフォルトのスタイルシートを指定しておく.

(かならずフルパスで指定する事)

[general]
font_path="/Library/Fonts/"
stylesheets="/Users/yourUserName/.rst2pdf/default-style.json"

Emacs環境

EmacsenEmacsで全てを完結したい.というわけでEmacsでの作業環境も.

rst.el

emacsenは新しい言語を使う前にまず環境を整える.そこでReST環境一式が詰まったrst.elを導入する.

ここからrst.elをダウンロードする.

$ cd site/lisp/directory
$ curl -O http://docutils.sourceforge.net/tools/editors/emacs/rst.el
$ emacs -batch -f batch-byte-compile rst.el

で,さらにrst.elにはいってるrst2pdf呼び出し関数が変なので.emacs設定ついでにフックで直す.

;; rst-mode                                                                                                                                                                        
(setq frame-background-mode 'dark)
(setq auto-mode-alist
      (append '(("\\.rst$" . rst-mode)
                ("\\.rest$" . rst-mode)) auto-mode-alist))


(defun my-rst-compile-pdf-preview (&optional compile-option)
  "Convert the document to a PDF file and launch a preview program."
  (interactive)
  (let* ((pdf-compile-program "rst2pdf")
         (command (format "%s -o - %s %s | %s"
                          pdf-compile-program
                          (or compile-option "")
                          buffer-file-name
                          rst-pdf-program)))
    (message command)
    (start-process-shell-command "rst-pdf-preview" nil command)))

(add-hook 'rst-mode-hook
              (lambda ()
                (setq rst-slides-program "open -a Safari")
                (setq rst-pdf-program "open -a Preview -f")
                (defun rst-compile-pdf-preview (&optional compile-option)
                  (interactive)
                  (my-rst-compile-pdf-preview (or compile-option nil)))))

これで準備おk!

(上のelispMacOSXでしか動かないと思うけど)

rst-modeショートカットキー

  • C-c 1 htmlでファイルに出力
  • C-c 2 texでファイルに出力
  • C-c 3 psuedexmlでバッファに出力
  • C-c 5 ブラウザでS5スライドを開く


参考文献

Emacsからリモートファイルをいじくる

今までリモートのファイルを開くときはいったんローカルのemacsを閉じて

sshでリモートにログインしてからまたemacsを立ち上げていた.

eshellからsshで接続しても,emacsがeshell上で動かないので何も操作ができないから...

さすがにクリティカルなファイルの編集以外はできればemacsから行いたいと思ってたんだけど,

実はこんな方法があった.

TRAMP

TRAMP(TransparentRemoteAccessMultipleProtocol)はemacsからリモートファイルを操作する機能を提供するパッケージ.

emacs21.4から標準でパッケージで入っているようです.

使うのには

;; 標準パッケージなら
(require 'tramp)
;; 自分でインストールしたなら
(add-to-list 'load-path "~/to/site/lisp/tramp/lisp/")
(require 'tramp)

でおk.

ローカルファイルを編集する

ローカルファイルを一時root権限で開くなら,

C-x C-f /sudo::/etc/rc.common

でいける.らくちん.

リモートファイルを開く

#1
C-x C-f /ssh:username@hostname:.emacs
#2
C-x C-f /ssh:username@hostname:/home/username/.emacs
#3
C-x C-f /ssh:username@hostname:/var/sys/log/

と.簡単.

#1はログインしたユーザのホームの".bashrc"ファイルを開く.つまりホームからの相対パスをコロン以降に書くことができる.

#2はフルパスをコロン以降に書く方法.

#3はフォルダを開く.dired(フォルダビューア)が立ち上がる.便利.

リモートファイルをroot権限で開く

当たり前だけど,リモートにrootで入る事ができない.いや,しちゃいけない.

というわけで,いったん一般ユーザで入ってから,sudoしてファイルを開く事が好ましい.

こんな場合はマルチホップというものを使う.

C-x C-f /multi:ssh:username@hostname:sudo:root@hostname:/etc/apt/sources.list

というかんじ.この'multi'という最初のメソッドは複数のメソッドを直列化するという意味.

まず,usernameでリモートhostnameにsshログインして,次に'/etc/apt/sources.list'をrootにsudoして開くというもの.

なんと単純.

これでかなりの作業がemacsからできる.

ちなみに,このマルチホップを使うと,複数のsshサーバを経由してサーバを編集するとか複雑な事も可能になる.

注意点

当たり前だけど,emacsはそこらかしこにバッファファイルを作る.最後にチルダのついたアレです.

普通に作業している分には問題ないんだけど,root権限だとへんなところにバッファを作るとアレゲな場合が十二分にあります.

(setq make-backup-files nil)

.emacsに入れておくと,そもそもバックアップファイルは作りません.

(add-to-list 'backup-directory-alist
                  (cons tramp-file-name-regexp nil))

だと,trampで開いたファイルに関してはバックアップファイルを作りません.

自分は後者にしてます.

あと,最後に

C-x C-f /multi:ssh:username@hostname:sudo:root@hostname:/etc/crontab

とかしちゃいけません.

まとめ

強力すぎる.上の例だとsshしかつかってないけど,いろんなプロトコルが使えるっぽい.

これでかなりの仕事がさくさくemacs上から行える.

参考文献

進歩しよう...

表をなぞるようなPythonの使い方しかしてなかったのでちょっと調べてみる.

リスト内包

リスト内包(list comprehensions)を使うと変なリストを馬鹿みたいに簡単に作れる.

lst1 = range (10) # これは普通に [0,1,2,...,9]
lst2 = [a for a in range (10)] # 上に同じ結果.
lst3 = [(a, b) for a in range (3) for b in range (3)] # タプルのリスト[(0,0), (0,1), (0,2), (1,0), .... (2,2)]
lst4 = [list ( (a, b) ) for a in range (3) for b in range (3)] # 上のタプルをリスト化

"エクセレント!"

mapやfilterの(場合によるが)便利な代替品も書ける.

lst5 = [a for a in lst2 if a % 2 == 0] # lst2の中から奇数のものを消す.filter的使い方
lst6 = [str (a) for a in lst5] # lst5の各値を数値型から文字列型にキャスト.map的使い方

"エクセレント!!"

イテレータ

イテレータとは数え上げることのできるオブジェクト.

pythonイテレータイテレータとして振る舞うオブジェクトを返す__iter__()メソッドをコンテナオブジェクト(list型とか)に実装することと,

そのイテレータオブジェクトはnextメソッドで次の呼び出しとStopItereationのraiseによるイテレーションの停止を定義としている.*1

意味不明なのでコードで表現.

lst = [3, 4, 5]
isinstance (a, list) # True

lst.__iter__ () # イテレータを作ってみる.ああ,これはlistiterator型なのね.listじゃないよ.
<listiterator object at 0x00000>
it = lst.__iter__ () # イテレータを変数に束縛してみる.
it.next () # 3
it.next () # 4
it.next () # 5
it.next () # except StopIteration

となっている.この仕組みがなんの役に立つのか.それはfor-in文で役に立つ.

for-in文ではinの次ぎにくる値がイテレータとして振る舞うこと,つまりイテレータを返す__iter__メソッドをも実装していることを期待する.

だから,基本的な型であるlist型以外でもイテレータとしての実装が施されていれば同じように動作する訳だ.

class myiter ():
    def __init__ (self):
        self.lst = [3, 4, 5]
        self.index = 0
    def __iter__ (self):
        return self
    def next (self):
        if (self.index < len (self.lst)):
            self.index = self.index + 1
            return self.lst[self.index -1]
        else:
            raise StopIteration

it = myiter ()
iti = it.__iter__()
print iti.next () # 3
print iti.next () # 4
print iti.next () # 5
print iti.next () # except StopIteration

for a in myiter ():
    print a # 0, 1, 2と表示

と,なる.上の例だとmyiterクラス自体をイテレータとして振る舞うようにして,__iter__で自分自身を返すようにしている.



ひとつ,自分の最初勘違いしていた点として,nextメソッドを持つコンテナとイテレータを混同していたこと,

イテレータの定義にはnextメソッドだけではなく,__iter__メソッドも持つことが重要.

コンテナはnextメソッドをもっていようが持っていまいが__iter__が有ればどっちでもいいわけだ.

このような仕組みをプロトコル,言語仕様からくる束縛の様なものとしてpythonは持っているらしい.

あれ,意味不明ですね.このへんはコードを書きまくって理解してください.

ジェネレータ

ジェネレータ(generetor)はイテレータ(iterator)を生成する機構.便利すぎる.

上のmyiterの例はかなり書くのがめんどくさい.

ジェネレータを使えばもっと簡単に書ける.

def genmyiter ():
    lst	= [3, 4, 5]
    index = 0
    while True:
        if (index != len (lst)):
            index = index + 1
            yield lst [index - 1]
        else:
            return

it = genmyiter () # コンテナ風味な何かを生成.このオブジェクトもイテーラブルである.
ito = it.__iter__() # 明示的にイテレータを生成.
print ito.next ()
print ito.next ()
print ito.next ()
print ito.next ()

"エクセレント!!!"

上のgenmyiterは上のmyiterと全く同じ機能を持つが,

ジェネレータはlisp語族でいうところの継続のcall/ccの一般化の様なものである.

継続とは実行時のスナップショットを残したまま処理を一時停止すること.自分的には.

明示的にlambda式でコンテキストの続きを呼び出さないところが違う.

まーそういうことは置いといて,yieldは単純に処理の一旦停止と値の返却を意味する.そしてreturnはイテレーションの終了を意味する.



さらにジェネレータには面白いことがある.ジェネレータは遅延評価:実行時に逐次評価を行うことで計算量を最低限に押さえることができる.

応用としてコルーチン(co-routine)を使った疑似スレッドを書いてみる.

コルーチンを使った処理ではスレッドと違いロック機構がいらない,スレッド切り替えが存在しないなど,小規模な並列処理をくみ上げる場合はこっちの方が早い場合もある.らしいw

class coroutine ():
    def __init__ (self):
        self.__lst = []

    def __genlooplist (self, lst):
        while True:
            iterlst = iter (lst)
            while True:
                try:
                    yield iterlst.next ()
                except StopIteration:
                    break

    def addroutine (self, genobj):
        self.__lst.append (genobj)

    def run (self):
        looplist = self.__genlooplist (self.__lst)
        for obj in looplist:
            try:
                obj.next ()
            except StopIteration:
                return

def generator (name):
    while True:
        print name + ' said fuck'
        yield
        print name + ' said you'
        yield

cor = coroutine ()
cor.addroutine (generator ('hoge'))
cor.addroutine (generator ('fuga'))
cor.addroutine (generator ('pyo'))
cor.run ()
# 結果
hoge said fuck
fuga said fuck
pyo said fuck
hoge said you
fuga said you
pyo said you
hoge said fuck
...

という感じとなる.キューリストとなっているlooplistも循環参照する(ようにみせかけた)イテレータとなっており,

その参照先もイテレータのようになっている.

処理の進み方として,yieldでストップを書けることで複数のタスクが同時進行しているように見えるのが結果よりわかる.

この例だとどれか一つのworker(つめたジェネレータ)がStopIterationを投げると自動停止するけど,

循環リストからworkerを自動で取り除く構造をいれれば,こんなんでも使えるものができそうだ.

ジェネレータ式

さらにジェネレータを進化させたものにジェネレータ式(generator expression)というものがある.

先ほどのリスト内包と同じようにジェネレータを書けるというものだ.

# exp1 generator expression
for i in (ge for ge in range (1000) if ge % 2 == 0):
    print i

# exp2 list comprehensions
for i in [lc for lc in range (1000) if ic % 2 == 0]:
    print i

"エクセレント!!!!"

丸括弧が四角括弧になっただけだけど,これはジェネレータとして動く.

exp1のジェネレータ式はfor-in文によってnextメソッドを呼び出されるたびに必要な計算(if文による偶数判定)を行う.

それに対して,exp2のリスト内包は先に偶数のリストを全部作ってから計算を行う.

exp1とexp2の実行速度を比較すると,逐次イテレーションを行うジェネレータ式の方が遅い.

しかし,場合にもよるが途中で処理が終了することが予期される場合は,実行速度とメモリ節約の両観点からジェネレータ式の方が良さそうだ.

まとめ

うーん,pythonLisp並にパワフルながら可読性が良い.といっても,今回示したものは関数型言語に親しんでいないとなんとも意味不明で読みずらい構文に見えるかもしれないが.

今週のヘビロテ

Burningn'n Tree

Burningn'n Tree

高速打ち込みドラムと絡み合うトム・ジェンキンソンのベースが絶妙!

コマンドラインで自分のグローバルIPアドレスを確認する

dyndnsのAPIを使うので永続的かはわかりません.

仕様がかわるとこれまた困ります.

Ubuntuとか多分Linux全般で動作します.

$ wget -q -O - http://checkip.dyndns.org | sed 's/.*Address\:\s\(.*\)<\/body>.*/\1/g'