Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

Twistedで作るローカルYoutubeサーバ その3

今度はテンプレート。
おさらい

web.py
from nevow import rend
from nevow import loaders
from nevow import accessors
from nevow import inevow
from twisted.python import util
from twisted.python.components import registerAdapter

items = []

class VideoItem(object):
    pass

class ListPage(rend.Page):

    docFactory=loaders.xmlfile(util.sibpath(__file__, 'list.html'))
    
    def childFactory(self, ctx, segments):
        return DetailPage(segments)

    def data_list(self, ctx, data):
        return items

class DetailPage(rend.Page):
    addSlash = True
    docFactory=loaders.xmlfile(util.sibpath(__file__, 'detail.html'))
    
    def __init__(self, id):
        self.id = id

    def data_id(self, ctx, data):
        return '/flvplayer.swf?file=/video/%s.flv' % self.id
        
registerAdapter(accessors.ObjectContainer, VideoItem, inevow.IContainer)

Pageクラスはこんな感じ。
docFactoryでファイルを読み込む。
docFactoryには引き数でいろいろ設定を渡す事ができるけど使としてもtemplateDirectoryぐらいなので省略。
テンプレートだけどnevowは幾つかのテンプレートを用意している。

  1. XML(XHTML)
  2. stan
  3. HTML(もういらないと思う)

簡単にXML部分を説明すると、
XML、HTMLを使う場合にはnevow用の名前空間を使用する。

<html xmlns:n="http://nevow.com/ns/nevow/0.1">

動的に変える部分はそのタグの属性に記述をするといったイメージ。
これらはNevow's Tag Attribute Languageと呼ばれている。TAL系に近いけどもう少しわかりやすくした感じ。
そのためdjangomakoなんかに比べてレイアウトが崩れにくい。

基本的には以下の属性がある。

  • nevow:render -- Pythonメソッドを実行し、ノードの値を置き換える
  • nevow:data -- Pythonメソッドを実行し、データをセットしノードを置き換える
  • nevow:pattern -- ノードに識別用に名前をつける
  • nevow:slot -- slotと同じ
  • nevow:attr -- 属性の値を置き換える

これらに合わせPageにメソッドを作って値を返すようにするとレンダリング時に属性の種類に合わせ呼ばれる。
よく使うのはnevow:renderだがどのようにrenderingするか設定する必要がある。
rendersには以下のものがある。

  • data -- ノードのdataをレンダリング
  • string -- ノードのdataをstringとしてレンダリング
  • sequence -- "item" という名前のpatternを繰り返し処理する
  • mapping -- ノードのdataのitemsメソッドを呼びだしkeyとvalueをペア作る。それを元にslotと同じ動作をする。(fillSlots)
  • xml -- xmlを直接insertする(よろしくない)

簡単な例:

<html><div nevow:render="foo" /></html>

renderでfooメソッドを呼ぶようになっているのでPageにはこのようなメソッドを作成しておく。

def render_foo(self, ctx, data):
    return "Hello"

結果

<html>Hello</html>

直接renderしているので値がそのまま出る。
(divタグが消えている点注意)
またrenderはdataと合わせてよく使う。

<html><div nevow:data="name" nevow:render="data" /></html>

この場合renderにdataを指定している。
dataはどこから取るかというとnameから取るようになっている。
dataはdata_から始まるメソッドで返す。

def data_name(self, ctx, data):
    return "Hello!"

結果

<html><div>Hello!</div></html>

dataを使うとタグは消えない。
で応用。
まずはListPageでレンダリングするlist.htmlから

list.html
<html xmlns:n="http://nevow.com/ns/nevow/0.1">
    <head>YouTube</head>
    <body>
        <ul n:render="sequence" n:data="list">
            <li n:pattern="item">
            <a><n:attr name="href">/<n:invisible n:data="id" n:render="data" />/</n:attr><n:invisible n:data="title" n:render="string" /></a>
            </li>
        </ul>
    </body>
</html>

ulタグをデータ分出力するのでsequenseを使用。
dataはlistを指定なので以下のメソッドが呼ばれる。

    def data_list(self, ctx, data):
        return items

繰り返し部分をグルーピングするのでliに対し、patternを設定(sequenceだとitem固定かな?)
itemの中はVideoItemなのだがこいつの中のdataを繰り返して出力する。
nevow:attrは直前のタグの属性を書き換えことができる。
この例だとhref部をVideoItem.idの値を使う。
nevow:invisibleはタグを出力したくない場合のダミーのタグ。
置き換えたい部分をわざわざspanタグで囲むとspanタグも出力されてしまう。
それを回避するためにはこのnevow:invisibleを使う。
また繰り返し部分などに複雑なObject(複数の値を持てるObjectなど)を突っ込む場合にはregisterAdapterで登録が必要になる。
(単純な文字列だけならpatternなどでもいける)
次にdetail.html

detail.html
<html xmlns:n="http://nevow.com/ns/nevow/0.1">
    <head>Detail</head>
    <body>
        <object type="application/x-shockwave-flash" data="/flvplayer.swf?file=/video/4-uxh1iQX0E.flv" width="560" height="380" wmode="transparent"><n:attr name="data" n:data="id" n:render="string" />
            <param name="movie"><n:attr name="value" n:data="id" n:render="string" /></param>
            <param name="wmode" value="transparent" />
        </object>
    </body>
</html>

こいつは単純に属性を書き換えてflvplayerに渡すファイルの部分を変えているだけ。

stanについてはまた書く機会があれば書く。
あと最後には再度全ソースを貼り直す予定。
次回はsshsshというかmanhole。
うくく。