ひよっこ。

I want to…

Wordで差分管理するのは現実的?

投稿者: hikaruworld : 2009 12月 19

@coelacanthが書いた記事が興味深かったのでトラックバック。

差分が取れないというのはもちろんですが、仕様書やチャートなどをバージョン管理することの効果は大きいですよね。
周りの人に聞くと、あんまり賛同してれる人もいない・・・。

あらま、自分は一応やっている派です。
WordではなくWikiですが。

wordを利用した場合の解決策

Wordで履歴管理しようとすると選択肢が限定されてくるように感じます。
思いつくのは、以下の方法(実際に全て検証しているわけではありません)。

  1. Word自身のdiff/履歴管理機能を使う(Diff:ツール→文書の比較と反映)
    • 履歴管理に関しては、Word内部で独自管理されるのでリビジョンの意味がなくなってしまうので、バージョン管理システムと相性が悪いように感じる。
  2. xdocdiffを利用する(Windows限定)
    • ローカルだけではなくTracやRedmineと連携させて、サーバにインストールする方法でも可能だが、Linuxで利用できないのが痛すぎる(Wineでいける?)。
    • メリットとしては、リポジトリの差分参照と同じインターフェイスで参照できるのは非常に便利。
      サーバがWinでTracなりを利用しているなら便利かも
  3. Eclipse3.5のWordの差分表示機能を利用する(ここの下の方で触れられている)。
    • xdocxに対応していないのが痛い。
    • リポジトリ履歴で参照できるかは試していないので知らない。誰か教えて。
  4. SharePointServerを利用する。
    • 出来るらしいが、あんなもの高くて個人レベルや小規模プロジェクトじゃ試せないので、知らない。
  5. Diffdocという有償ツールを利用する
    詳しくは知りません。ウン万円ですがこれを買うなら違うものを買います。
  6. 別のテキスト形式で管理して、必要に応じてExportする。
  7. Silverlight4のCOM連携とかに期待して星を見ながら待つ。

自分の環境の場合

冒頭にあるように、自分の場合は6になります。希望は7ですが。
昔、ちろっと書いたような気がしますが…
実体をWordで管理せずにTracで管理しているのは、自分が求めているドキュメント機能が、

  • ブラウザベースであること(いつでも読める、ハイパーリンクによる遷移、ViewとEditの分断)
  • 複数ページにより構成がしやすい(1つの機能単位で仕様まとめたい場合はsheetによる分割(Excel)や、見出しごとに分割(Word)よりも視認性があがると思います)。
  • ハイライトや強調、イタリック、画像添付などのサポート(tracはドラッグドロップ出来ないなど多少弱い部分もありますが)

といったことから、Wikiで必要十分かなと。
もう少し具体的に言うと、tracのwikiで管理して必要(納品とかですね)に応じてWordやPDFにエクスポートします。
※TracプラグインWikiExportPluginを参照のこと。日本語だとちょっち問題ありますが。

今の運用方法だと、ストーリー(要するに要件)をWiki上に書いて、UI設計のMock(HTMLなので)も

{{{
#!html
}}}

を利用して、Trac上に埋め込みます。
Mockを埋め込むと画面遷移をしながら仕様を詰めて、必要に応じてその場でWikiを修正できるのが非常に助かります。
※hoge.htmlの仕様は、wiki/hoge.htmlという【Wikiページ】に定義されているため、埋め込まれたHTML単位で画面遷移が可能です。

この運用で見えてきた問題点

但し、この運用すると以下のような問題があります。

  • Wiki文法ベースでのDiffになってしまうこと
  • 検索にいらないHTMLタグが無駄に引っかかること。
  • Tracベースの管理ため、仕様の履歴管理(要するにWikiのスナップショット)が出来ない。

まぁ、この辺りはおいおい解決していこうかなと。

以上です。

カテゴリー: program | タグ: , , | コメントする »

TDD読書会#3+北陸エンジニアグループ2009振り返り会に行ってきたよ

投稿者: hikaruworld : 2009 12月 14

と言うわけで、TDD読書会#3+北陸エンジニアグループ2009振り返り会に行ってきました。
って、あれ開発プロセス勉強会だったような気が…まぁいいか。

北陸エンジニアグループに関連する勉強会は今年はこれで最後になります。
なんだか色々あった気がしますが、そちらは年末に改めて振り返ってみます。

あと、最後に@yuuitiroさんに、毎度のことながらインフラ関係を感謝したく思います。
目立たないけど、一番大事な縁の下の力持ちだと思います。

さて本題。
今回はこじんまりした形式ではなく、講義形式でTDD読書会では初参加の方がたくさんいたので、
冒頭に15分ほどTDDの歴史byKanazawaProcessとして発表しました。
以下がスライドです。

で、以下は内容の一行感想
詳しくは、他のみなさんが書かれてるのでそちらに譲ります。

#1 @hikaruworld
自分なので、省略。
#2 @coelacanth
SSASなんて今日知ったっす。面白そうだなーと思ったけど、バージョンが古すぎる…
今後のバージョンアップに期待

#3 @kussy_y
やっぱりファシリテーションって面白いなーと思う。
こういうのを会社でやりたいよねと思いました。

#Ex 懇親会
第七安し!!。ひとり1500円程度で食べれるのは医大だ!!

おまけ。
最後に今回のTwitterのタイムラインを貼っておきます。

katzchang はじまた。 #hokueng でいいよね。 2009-12-12 12:17:14
mitukiii 始まってる。 #hokueng 2009-12-12 12:20:11
rch850 「テストファーストなひと」「……」 #hokueng [VtP] 2009-12-12 12:26:48
katzchang さて、くしださんをお迎えにいくので、12:40ころに一度でかけます。13:30ころには帰ってくると思います。進行とか、どなたかお願いします>< #hokueng 2009-12-12 12:27:22
shozzy 今日のタグはこれか #hokueng 2009-12-12 12:29:13
rch850 SSASで単体テスト。へんたいだー #hokueng [VtP] 2009-12-12 12:31:41
katzchang 最優先事項:他のメンバーが持つ全ての疑問を解決するよう、協力します。 #hokueng 2009-12-12 12:33:20
katzchang ということで、自分がわからないことは質問していく!他の人の質問にはみんな答えていく!で行きましょう! #hokueng 2009-12-12 12:34:02
hikaruworld お昼ごはん。 #hokueng 2009-12-12 12:36:35
shoito 時間が時間だからか、みんなメシ食ってる #hokueng 2009-12-12 12:37:40
rch850 SSASって言ってるけど、実際はECMAScriptのほうが近い? #hokueng [VtP] 2009-12-12 12:39:18
wtnabe 実は SSAS がなんだかよく分かってなかったり #hokueng 2009-12-12 12:40:31
katzchang ですね。ASとか。 RT @rch850: SSASって言ってるけど、実際はECMAScriptのほうが近い? #hokueng [VtP] 2009-12-12 12:41:20
shozzy おやつ持ってくればよかったな #hokueng 2009-12-12 12:41:37
rch850 ほー、FMSってSSAS使うんだ #hokueng [VtP] 2009-12-12 12:43:23
checkela Testの規約って、言語毎に微妙に違うよねえ… #hokueng 2009-12-12 12:44:51
wtnabe prototype.superclass ってどのバージョンから使えるのかな? #hokueng 2009-12-12 12:44:56
wtnabe ecmascript 的には smallCamelCase にするのがいいのかな? 好きじゃないけど。 #hokueng 2009-12-12 12:46:49
shozzy 開発を進めるための方法=TDD。品質保証のための方法ではない。 #hokueng 2009-12-12 12:47:34
wtnabe この辺は宗教戦争なので、使ってる言語で推奨されているデフォルトスタイルでいくのがいいはず。好きじゃないけど。 #hokueng 2009-12-12 12:47:55
shozzy 同じxUnitを使うので混同しがちだけどね。これがTDD勉強会での発見だったな。 #hokueng 2009-12-12 12:48:08
rch850 .@coelacanth の FMSUnit が力技過ぎるw #hokueng [VtP] 2009-12-12 12:48:56
rch850 SSAS での単体テストに JSUnit のコードがだいぶ流用できそうに見えるなー #hokueng [VtP] 2009-12-12 12:53:13
shozzy 「アジャイルソフトウェア開発の奥義」は6000円するそう #hokueng 2009-12-12 12:58:53
shozzy ドキュメントは最小限でいいよー っていうか、要件が明確なら、内部設計はいらない。発注側としては。 #hokueng 2009-12-12 13:03:37
rch850 「納品」って単語にそもそもなじみが無いんだよなー #hokueng [VtP] 2009-12-12 13:03:51
shozzy 詳細設計書にSQLまで書いてたことある。意味ないよねー #hokueng 2009-12-12 13:04:25
rch850 詳細設計書とかって、なんかおかしいことがあったとき用なのかしらね #hokueng [VtP] 2009-12-12 13:05:57
shoito wikiにストーリー書いて、レビュー、調整、テストコード書いて、開発やねぇ #hokueng 2009-12-12 13:10:48
itsuki_kosen アジェイルソフトウェア開発によるメリットと言うか,良いところは迅速かつ適応的ってのはわかるけど,実際に何か作ったり案件として請け負ったものを,アジェイルソフトウェア開発でやると,具体的にどう変わるのか.どう良くなったのかの実例が知りたいなぁ. #hokueng 2009-12-12 13:11:19
shozzy 「気持ちいい開発」 #hokueng 2009-12-12 13:11:24
shozzy 土曜出勤とかぶるとほんとへこむよねー #hokueng 2009-12-12 13:12:22
masayan_kazu ラダーのセクションにテストコード埋め込む作戦 #hokueng 2009-12-12 13:13:10
itsuki_kosen #hokueng 調べたら少しあった.ユーザにとってのアジャイル開発のメリット http://www.thinkit.co.jp/free/article/0608/3/2/ 2009-12-12 13:13:12
itsuki_kosen #hokueng 実践者インタビュー http://www.atmarkit.co.jp/farc/rensai2/prac01/prac01b.html 2009-12-12 13:13:43
shozzy ツールがテストコードを要求してくるわけか #hokueng 2009-12-12 13:23:21
rch850 cutagem でテンプレつくる。それで rake すると何もテストが無いという失敗になる #hokueng [VtP] 2009-12-12 13:24:47
shozzy 要求というより、自動でコケるテストコードを生成してくれるのか #hokueng 2009-12-12 13:25:04
hikaruworld 最近の #hokueng 2009-12-12 13:26:42
hikaruworld Eclipse+JUnitだと、自動生成したテストコードには、エラーfail()が実装されてたりする。 #hokueng 2009-12-12 13:27:27
shozzy よし、グリーンだ!きゅうけい! #hokueng 2009-12-12 13:30:57
kussy_y #hokueng のみなさんありがとうございました。ブログを書くまでがイベントですよ! 2009-12-12 16:57:36
wtnabe お届けタスク終了して帰宅なう #hokueng 2009-12-12 17:17:39
wtnabe えーとその後 tweet する機会がなかったんで補足しますと、今日使った道具は gem と rake と cutagem の http://github.com/genki/cutagem だけっすね。あとは Ruby 標準のものばかり。 #hokueng 2009-12-12 17:33:35
wtnabe コードの補完は Emacs でもやる人はすごいレベルでできるのですが、自分はそんなにヘビーには使い込んでないです。 #hokueng 2009-12-12 17:35:18
shoito 今年のコミュニティ活動をふりかえってきたよ – 北陸エンジニアグループ2009ふりかえり http://blog.air-life.net/2009/12/hokuriku-engineer-group-retrospective.html #hokueng 2009-12-12 23:27:26
katzchang ちなみに、今回の参加表明曲線です。 #hokueng http://f.hatena.ne.jp/katzchang/20091213030326 2009-12-13 03:04:36

#hokueng – ハッシュタグクラウドより。

カテゴリー: program | タグ: , , | コメントする »

Air2.0(ベータ版)でネイティブプロセスでjarファイルを実行する方法(泥臭い編)

投稿者: hikaruworld : 2009 12月 13

Air2.0(現時点ではβ1版)での新機能の一つとして、ネイティブプロセスを実行することができるようになっています。

詳細はこのあたりが参考になります。

  1. AIR 2.0 ではじめるコミュニケーションツール Comm On AIR 2.0

この新機能を用いてjarファイルを実行したかったのですが、
ちょっと面倒な実装になってしまったのでメモしておきます。

ちなみに環境はMacOSX(雪豹)です。
winだとjarファイルを直接渡しても実行してくれるのかなぁ(javaw -jar hoge.jar)。

結論としては、jarファイル単体実行が結局うまくいかずshのラッパーを用意しました。

  • bin/exec.jar
  • bin/wrapper.sh

という感じでアプリケーションに実行ファイルを含めておきます。

exec.jarはマニュフェストファイルが存在する実行可能jarファイルで固めてあります。
wrapper.shの中身はこんな感じです。

#!/bin/sh

# 単純にjava -jarで第一引数に実行対象のjarファイルを渡す。
# jarファイルにパスが通っている前提
$(java -jar $1)

java -jarコマンドを実行時に$1でwrapper.shに渡された
引数(これが実行対象のjarファイルになります)をそのまま指定しています。

Air2.0側では、以下のような実装を書きました。

var info:NativeProcessStartupInfo = new NativeProcessStartupInfo();
// 実行対象のファイル(ラッパー)を指定
var file:File = File.applicationDirectory.resolvePath("bin/wrapper.sh");
info.executable = file;

// wrapper.shに渡す引数を指定
var args:Vector.<String> = new Vector.<String>();
// 相対指定だとAirのランタイムからの指定になってしまうので、
// 実際にjava -jarコマンドに渡したいファイルの絶対パスを解決する。
var jarFile:File = File.applicationDirectory.resolvePath("bin/exec.jar");
args.push(jarFile.nativePath);
info.arguments = args;

// 実行
this.process = new NativeProcess();
process.start(info);

ソースコード上のコメントにもありますが、
ネイティブプロセスによって実行されたファイルのカレントディレクトリ(pwd)が、
AirのRuntimeになってしまうようで、アプリ内に存在するファイルの
絶対パスを解決して渡しているとう微妙な実装をしています。

以上。

めちゃめちゃ泥臭い実装なんですが、
よりより方法があれば誰か教えてください。

カテゴリー: program | タグ: , , , | コメントする »

agiloをインストールしたら有効化されなくてはまった

投稿者: hikaruworld : 2009 12月 9

結論はGenshiのバージョンが古かったこと。

自分の場合、easy_install を利用して全環境に適用可能にするのではなく、
任意の環境のpluginsフォルダにインストールするケースが多い。
理由はいくつかあるが、もっとも大きいのは属性やスコープの違うtracを複数運用しているため。
# 開発用だったり、あるいは運用用だったり、要件管理用だったり。

そんなわけでagilo

python setup.py bdist_egg

でインストール→コピー→プラグイン有効化したわけだが、なぜか画面に表示されない。

agiloのsetup.pyを確認してみたが、必須モジュールのGenshiもsimplejsonもインストールしている。

   install_requires=['trac >= 0.11',
                      'genshi >= 0.5.1, < 0.6dev', # see Genshi bug #254
                      'simplejson'
                      ],

変だなーと思いつつログを確認してみると、以下のようなエラーが出てる。

2009-12-09 14:38:36,916 Trac[loader] ERROR: Skipping “agilo 0.8.3-r1918-20090925″: (version conflict “(Genshi 0.5 (/usr/local/Python252/lib/python2.5/site-packages/Genshi-0.5-py2.5-linux-i686.egg), Requirement. parse(‘genshi>=0.5.1,<0.6dev'))")

なるほど、つまりGenshiのバージョンが古いと。

easy_installを使ってGenshiのバージョンをUpdateした

easy_install -U Genshi

するとGenshiのバージョン0.5.1がインストールされたのでapache再起動

…今度はInternalServerError….orz.

ExtractionError: Can’t extract file(s) to egg cache\n\nThe following error occurred while trying to extract file(s) to the Python egg\ncache:\n\n [Err no 13]

なんか、懐かしいバグにあったったみたい。
easy_install.pthからGenshiの行を削除してeggファイルを削除して再度Genshiをインストール。

easy_install --always-unzip Genshi

DBをupdate。
OK-。

無事確認できた。
なんかいらん事にはまってしまったorz…

カテゴリー: program | タグ: , | コメントする »

Air2.0β版のruntimeがぶっ壊れた

投稿者: hikaruworld : 2009 11月 20

Air2.0のβ版を触っていたんですが、とあるアプリケーションをインストールしようとしたらエラーに。

bfa表_The application could not be installed because the installer file is damaged. Try obtaining a new installer file from the application author.

なんだか、他のところでも発生している事を@shoitoに教えてもらいました。

回避策は、AdobeAirのruntimeの再インストールで発生しなくなりました。
…MacのUninstallerを探すのが大変でした。

ちなみに、FlashBuilderでデバッグしようとするとこんなエラーになります。

Error: Error #0
	at flash.filesystem::FileStream/close()
	at com.adobe.air.logging::FileTarget/write()[/Users/mesh/src/as3corelib/src/com/adobe/air/logging/FileTarget.as:86]
	at com.adobe.air.logging::FileTarget/http://www.adobe.com/2006/flex/mx/internal::internalLog()[/Users/mesh/src/as3corelib/src/com/adobe/air/logging/FileTarget.as:78]
	at mx.logging.targets::LineFormattedTarget/logEvent()[C:\autobuild\3.4.0\frameworks\projects\framework\src\mx\logging\targets\LineFormattedTarget.as:163]
	at mx.logging::AbstractTarget/logHandler()[C:\autobuild\3.4.0\frameworks\projects\framework\src\mx\logging\AbstractTarget.as:332]
	at flash.events::EventDispatcher/dispatchEventFunction()
	at flash.events::EventDispatcher/dispatchEvent()
	at mx.logging::LogLogger/info()[C:\autobuild\3.4.0\frameworks\projects\framework\src\mx\logging\LogLogger.as:182]
	at net.fxug.hokuriku.chocolat.helper::SORAAIHelper/checkForUpdate()[/Users/morizou/Documents/Adobe Flash Builder Beta 2/soraai/src/net/fxug/hokuriku/chocolat/helper/SORAAIHelper.as:70]
	at net.fxug.hokuriku.chocolat.helper::SORAAIHelper/creationCompleteHandler()[/Users/morizou/Documents/Adobe Flash Builder Beta 2/soraai/src/net/fxug/hokuriku/chocolat/helper/SORAAIHelper.as:65]
	at flash.events::EventDispatcher/dispatchEventFunction()
	at flash.events::EventDispatcher/dispatchEvent()
	at mx.core::UIComponent/dispatchEvent()[C:\autobuild\3.4.0\frameworks\projects\framework\src\mx\core\UIComponent.as:9408]
	at mx.core::UIComponent/set initialized()[C:\autobuild\3.4.0\frameworks\projects\framework\src\mx\core\UIComponent.as:1169]
	at mx.managers::LayoutManager/doPhasedInstantiation()[C:\autobuild\3.4.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:718]
	at Function/http://adobe.com/AS3/2006/builtin::apply()
	at mx.core::UIComponent/callLaterDispatcher2()[C:\autobuild\3.4.0\frameworks\projects\framework\src\mx\core\UIComponent.as:8733]
	at mx.core::UIComponent/callLaterDispatcher()[C:\autobuild\3.4.0\frameworks\projects\framework\src\mx\core\UIComponent.as:8673]

今回のAir2.0では、ネイティブアクセスが部分が強化されているので
何かしら影響が出てるのかもしませんね。

カテゴリー: program | タグ: , | コメントする »

GoogleMapAPI For Flash のバグがfixされたみたい。

投稿者: hikaruworld : 2009 11月 16

以前の記事で触れていた、GoogleMapAPIForFlashにおいて、ルート検索が出来ない障害がfixされているようです。

issues1553

externalInterface使わなきゃいけないかなぁと思っているうちにfixしてくれたみたいです。
…次のバージョンになりますけど。
…ソース公開されていないので確認できませんが。

カテゴリー: program | コメントする »

Flash制作に欠かせない3つのツール・FlexBuilderプラグイン編

投稿者: hikaruworld : 2009 10月 14

なんだか、そここらで標題をやっているので自分も乗ってみます。
ちなみに自分はちょっと視点を変えて、FlexBuilderPluginの観点から。

  1. TODO/FIXME プラグイン
    タスクはEclipseデフォルトビューの一つで、Javaなどの場合は問題なく表示されるのですが、Flexはそれを拾ってくれません。
    このプラグインはFlexのMXML及びAS上のTODOとFIXMEを認識してタスクタブ上に表示してくれます。
    FlexBuilder2用なのですが、FlexBuilder3でもFlashBuilder4 Beta2でも動きます。
    自分は「とりあえずTODO」が多いので非常に助かります。

  2. Blueprint プラグイン
    選択したクラスやメソッドのヘルプとサンプルソースコードを開いてくれます。
    大変便利なのですが、開かれるASDocが英語というのがタマに傷。
    日本語に出来るともっといいのですが。

    FlashBuilder4 Beta2では動かないのは私だけですかね。

  3. FlexFormatter プラグイン
    記述されたコードのフォーマットをしてくれるプラグイン。
    適当なインデントで書いたコードも、さっくりインデントなどの
    フォーマットをしてくれる優れものです。

個人的には、CheckStyle的なプラグインがのどから手が出るくらい欲しいのですが、
他人任せに祈っていたりします。

以上ー。

カテゴリー: program | タグ: , , | 2件のコメント »

trac上にFreeMindファイル(.mm)を表示させる。

投稿者: hikaruworld : 2009 9月 29

Trac上にFreeMindのデータを表示させたくなることがたまにあります。
(というか、Flash系のデータ。グラフ描画用にamChartとかも活用できるはず。)
今までは、毎回PNGに落として表示していたんですが、以下の事情から何とかならないかなと思っていました。

  • イチイチ書き出す必要があること
  • データの実体が異なること(実体が.mmでPNGを書き出すので)

で、適当に考えて試してみたらうまく行ったので、ここに方法を書いておきます。
実際にはFlashViewFreemindFlashBrowserの併せ技です。

まずは出力をflashで行うため、trac上にFlashを表示させるプラグインが必要になります。
自分は前回のエントリにもあるように、FlashViewを利用しています。

というわけで、任意のFlashを表示できるプラグインをインストールします。
ここで大切なのは、FlashVarsの変数を利用して参照するファイルを指定しますので、
FlashVarsとswfファイルをパラメタに渡して表示してくれるようなインターフェイスを持つプラグインを準備する必要があります。
# 一応前回の投稿でデフォルトのFlashViewプラグインにパッチをあてる手順を公開しておいたのでよかったらどうぞ。

以下は上記の準備が出来ているものとして手順を進めます。

FreeMindのFlash描画用ライブラリの適用

FreeMindのファイル(.mm)を読みこませて表示させるライブラリを作られた方がいますので、
作者さんに感謝しつつ、ここからダウンロードします。

ダウンロードしたファイルは参照可能な領域においておきます。

# 自分の環境では複数Trac環境が同一のhtdocsを共有する運用をしているので、その配下においておきます。
# リモートなどに配備した場合は、クロスドメインの制約がかかるので注意してください。

次は以下のようにwikiに設定を書きます。

[[FlashView(/htdocs/ffb/visorFreemind.swf,100%,300px,hogehoge.mm)]]

hogehoge.mmは対象のFreeMindファイルを指定してください。
個人的には対応するwikiページに添付する使い方をしています。

これで画面上に表示されます。

以上です。

カテゴリー: program | コメントする »

FlashViewプラグインに引数を追加してみた

投稿者: hikaruworld : 2009 9月 28

tracでFlashを表示するためのプラグインとしてFlashViewPluginというプラグインがあります。
これは大変便利なのですが、引数として、対象となるswfファイル、幅、高さしか渡せないため、
FlashVarsで引数やquorityを設定できないのでちょっと困るときがあります。ありますよね?

というわけで、このマクロを少し拡張してみました。
やりたいことは以下のとおりです。

  • FlashVarsを渡したい
  • quorityを指定したい(デフォルトはlow)

できるだけ、元ソースに編集を加えない方向で修正してみました。
修正結果のdiffを張っておきます。

diffを適用すれば以下のような感じで利用できるようになります。

[[FlashView(hoge.swf, 400,300,vars="hoge=piyo", quality=hight)]]
変数 内容 補足
第1引数 対象のswfファイル 必須
第2引数 必須?
第3引数 高さ 必須?
keyがvars FlashVarsに渡される引数(ペア値を渡す場合は括弧でくくること) 任意
keyがquality 解像度。デフォルトはlow 任意
*** flashview.py.r2457	2009-09-28 14:27:54.000000000 +0900
--- flashview.py	2009-09-28 14:30:04.000000000 +0900
***************
*** 5,11 ****
  from cgi import escape as escapeHTML
  import os
  from trac.core import *
! from trac.wiki.api import IWikiMacroProvider

  def swfsize(f):
	  magic, version, datasz = unpack("<3s1B1L", f.read(8))
--- 5,11 ----
  from cgi import escape as escapeHTML
  import os
  from trac.core import *
! from trac.wiki.api import IWikiMacroProvider, parse_args

  def swfsize(f):
	  magic, version, datasz = unpack("<3s1B1L", f.read(8))
***************
*** 63,69 ****
		  # args will be null if the macro is called without parenthesis.
		  if not content:
			  return ''
!         args = content.split(',')
		  filespec = args[0]

		  # parse filespec argument to get module and id if contained.
--- 63,70 ----
		  # args will be null if the macro is called without parenthesis.
		  if not content:
			  return ''
!         args, kw = parse_args(content);
!         #args = content.split(',')
		  filespec = args[0]

		  # parse filespec argument to get module and id if contained.
***************
*** 142,151 ****
				  width = args[1]
				  height = args[2]

		  vars = {
			  'width': width,
			  'height': height,
!             'raw_url': raw_url
			  }

		  return """
--- 143,165 ----
				  width = args[1]
				  height = args[2]

+         # Custom Options..
+         if "vars" in kw:
+             vars_val = kw['vars'].strip("\"")
+         else:
+             vars_val = ''
+         if 'quality' in kw:
+             qlt = kw['quality'].strip("\"")
+         else:
+             # default parameter
+             qlt = "low"
+
		  vars = {
			  'width': width,
			  'height': height,
!             'raw_url': raw_url,
!             'vars_val': vars_val,
!             'qlt': qlt
			  }

		  return """
***************
*** 153,161 ****
		  codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"
		  width="%(width)s" height="%(height)s">
	<param name="movie" value="%(raw_url)s">
!   <param name="quality" value="low">
	<param name="play" value="true">
!   <embed src="%(raw_url)s" quality="low" width="%(width)s" height="%(height)s"
		   type="application/x-shockwave-flash"
		   pluginspage="http://www.macromedia.com/go/getflashplayer">
	</embed>
--- 167,176 ----
		  codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"
		  width="%(width)s" height="%(height)s">
	<param name="movie" value="%(raw_url)s">
!   <param name="quality" value="%(qlt)s">
	<param name="play" value="true">
!   <param name="FlashVars" value="%(vars_val)s" />
!   <embed src="%(raw_url)s" quality="%(qlt)s" width="%(width)s" height="%(height)s" FlashVars="%(vars_val)s"
		   type="application/x-shockwave-flash"
		   pluginspage="http://www.macromedia.com/go/getflashplayer">
	</embed>

面白かったのは、trac.wiki.api. parse_argsという関数がめちゃ便利でした。
この関数は、引数に渡されたマクロのパラメータを分解してくれるんですが、
例えば[[Hoge(http://hoge/, 400, piyo=hogepiyo)]]という値の場合

http://hoge/, 400, piyo=hogepiyo

という文字列が渡されてくるのですがparse_argsを使って以下のようにします。

[/sourcecode]

args, kw = parse_args(content);
[/sourceocde]
すると、argsには

list: [u'http://hoge/', u'400']

kwには

dict: {‘piyo’: u’hogepiyo’}

が渡されます。

つまり、argsにはキーを持たない値の一覧、kwにはキーと値のペアを辞書型で渡してくれるという優れものです。
これは面白いので、是非ソースを…と言いたいところですが
これはまた後日tracのソースを読みながら見てみたいと思います(使い方はhelp()で)。

ということをやった後に実は既に対応されている方がいました(SWFObjectの対応に併せて、Flashvarsも渡せるようにしてくれています)。

何が悲しいかといえば、既に自分のプロジェクトでもパッチを適用していたことに後で気がついたことです。
amlineというグラフチャートを利用していたので、SwfObjectも設定されているし。
悲しい…

まぁ、SWFObjectをいちいちヘッダーに埋め込みたくないようなかたがいれば使ってください。

カテゴリー: program | タグ: , , | コメントする »

tracのソースを読む(その1) – Standalone.py -

投稿者: hikaruworld : 2009 9月 26

前回のエントリにある通りとりあえず、デバッグ環境は構築出来たので、
どこから読むか迷ったんですが、起動スクリプトからソースを読んでいきたいと思います。
# 全体的なtracのアーキテクチャをまず理解するか、テストソースの方がいいのか迷って…

メモ代わりに書いていますので、間違っている部分など突っ込んでいただけると感謝です。

という訳で、まずはtracの内蔵サーバを利用して起動させる際に利用されるStandalone.pyから見ていこうと思います。
今回読んだソースはL296-L298のたった3行のみです(涙)
# のわりには、めちゃ長文なんですが(汗

ここで起動スクリプトがstandalone.pyであると知っているのは、公式のドキュメントにそう書いてあるからです。
あ、言い忘れましたがTracのバージョンは0.11.5になります。

さて、起動部分からです。
standalone.pyは基本的にはクラス(class)と関数(def)のみで、実際の実行は最後尾の以下のみになります。

if __name__ == '__main__':
	pkg_resources.require('Trac==%s' % VERSION)
	main()

速攻まずここで躓きました。
よくわからなかったのは以下の通り(ほとんどわかっていないんです)。

  1. __name__とは何か
  2. pkg_resourcesとは何か
  3. pkg_resources.requireとは何か

1. __name__とは何か

pythonはスクリプトとして実行した場合(コンソール上からpython standalone.pyとかやる)は__name____main__という文字列が
割り当てられるということは知っていましたが、実際に細かい挙動がわからなかったので復習しておくことにしました。
へたれプログラマの日々というサイトがわかりやすくて参考になりました。感謝。

といわけで上記サイトを参考に早速実験してみます。
カレントディレクトリにHoge.pyというファイルを作成します。中身は以下の通りです。

#!/usr/bin/python

print "hoge";
print __name__;

if __name__ == '__main__':
	print 'oooo....'

これをコンソール上から実行してみます。

python Hoge.py

hoge
__main__
oooooo…..

書いてある通り、__name__には__main__という文字列が格納されているようです。
__name__に設定されている文字列も正しかったためif文内部の実行も行われています。

では今度は、インタプリタ上で実行してみます

import Hoge

hoge
Hoge

ふむふむ。importした際のクラス名が__name__に格納されていますね。
そして当然if文内部は実行されていません。

では、今度はエイリアスをつけてみます。

import Hoge as piyo

こちらでもエイリアスが設定される訳ではなく、importの実体が設定されるため変わらないようです。

hoge
Hoge

やはり参考にしたサイトでも示されていた通りの挙動を示すようですね。

今回参照しているStandalone.pyはスクリプトとして実行された際に特別な挙動で動くように設定されていましたが、
その他の方法としては、これらの処理はdoctestを実行する際に便利に利用できるようです。

2. pkg_resourcesとは何か

次に気になったのは、以下です。

pkg_resources.require('Trac==%s' % VERSION)

2-1. ‘Trac==%s’ % VERSIONとは何か

とりあえず細かく分解して確認していきたいと思います。
%sをVERSIONで置換している事はわかりますが、VERSIONの取得がどうなっているか気になりました。
VERSION自体はimport時にエイリアスとして設定されており、実際はtracパッケージのパッケージ変数を参照しています(import文を参照)
Pythonはas演算子を使ってimportした関数やクラスを任意の文字列に置き換える事が出来るそうです。

from trac import __version__ as VERSION

from tracとfromにパッケージを指定することで、__init__.py上に設定されている変数が参照可能になります。

2-1-1. __init__.pyとは

__init__.pyはpythonのサブディレクトリを示す際に必要となるファイルです。
pythonランタイムによって対象のディレクトリがサブパッケージと認識させるためにはこのファイルを必ず置いておく必要があるそうです。
この名前のファイルが置いてあること」が重要で、ファイルの中身は空でもかまいません。

ただ、今回のように__init__.pyに変数が設定されているような場合、__init__.pyで定義されているファイルを読み込みたい場合は、
fromでパッケージを指定して、「package名.initに存在する変数」で参照することが可能になります。
というわけで、__init__.pyの中身を参照してみます。

__version__ = __import__('pkg_resources').get_distribution('Trac').version
2-1-1-1. __import__とは

__import__はPythonによって提供されている組み込み関数です。
余談ですが、Python上で「__」(アンダースコア2つ)によって定義される関数は特別な意味を持つそうです。

__import__はimportによって任意のオブジェクトをimportした際に呼び出される組み込み関数になります。
そのため、以下お処理は同じ物を表していいます。

# __import__とimportは同じ処理をしている
__import__('pkg_resources')
import pkg_resources
2-1-1-2. pkg_resources.get_distributionとは

get_distributionはsetuptoolsによって提供される関数で、get_distributionの引数で指定したモジュール名をキーとしてDistributionを返します。
これはTracがPythonモジュールの配布の方式で配布されているため、Distributionからバージョン情報が取得できるようになるためのようです。

ここでは単純にversion情報の取得のみ行っていますが、以下のような情報も参照可能なようです。
詳しくはDistributionのインスタンスを引数にhelp()を実行してみると色々と出てくると思います。

>>> __import__('pkg_resources').get_distribution('Trac').key
>>> __import__('pkg_resources').get_distribution('Trac').extras

なお、これらのDistributionとしての設定はインストール時のsetup.pyのsetup()に記述されています。
setup()で引数に取れるデフォルトのプロパティは、distutils.core — Distutils のコア機能を、setuptoolsによって拡張されるプロパティはNew and Changed setup() Keywords(邦訳)を参照してください。
どうせなのでpythonのsetup.pyを確認してみます(maintainerなどが書いてあるためtrac0.11.1-ja1を表示しています)。

from setuptools import setup, find_packages

setup(
	# パッケージの名前
	name = 'Trac',
	# パッケージのバージョン番号
	version = '0.11.1.ja1',
	# 1行で書いたパッケージ解説
	description = 'Integrated SCM, wiki, issue tracker and project environment',
	# パッケージの長い解説
	long_description = """
Trac is a minimalistic web-based software project management and bug/issue
tracking system. It provides an interface to the Subversion revision control
systems, an integrated wiki, flexible issue tracking and convenient report
facilities.

Japanese translated edition.
""",
	# パッケージ作者の名前
	author = 'Edgewall Software',
	# パッケージ作者のemailアドレス
	author_email = 'info@edgewall.com',
	# 現在のメンテナの名前(パッケージ作者と異なる場合)
	maintainer = 'InterAct',
	# 現在のメンテナのemailアドレス(パッケージ作者と異なる場合)
	maintainer_email = 'trac-ja@i-act.co.jp',
	# パッケージのライセンス
	license = 'BSD',
	# パッケージのURL(ホームページ)
	url = 'http://trac.edgewall.org/',
	# パッケージダウンロード用URL
	download_url = 'http://trac.edgewall.org/wiki/TracDownload',
	# パッケージのカテゴリのリスト
	# 詳細は右記 http://pypi.python.org/pypi?:action=list_classifiers
	classifiers = [
		'Environment :: Web Environment',
		'Framework :: Trac',
		'Intended Audience :: Developers',
		'License :: OSI Approved :: BSD License',
		'Operating System :: OS Independent',
		'Programming Language :: Python',
		'Topic :: Software Development :: Bug Tracking',
		'Topic :: Software Development :: Version Control',
	],
	# distutilsが操作するPythonパッケージのリスト
	packages = find_packages(exclude=['*.tests']),
	# パッケージ名と、ファイル名のパターンのリストの対応付け
	package_data = {
		'': ['templates/*'],
		'trac': ['htdocs/*.*', 'htdocs/README', 'htdocs/js/*', 'htdocs/css/*',
				 'htdocs/guide/*'],
		'trac.wiki': ['default-pages/*'],
		'trac.ticket': ['workflows/*.ini'],
	},
	# この引数を指定すると、例えばsetup.py testを使って、指定されたテストスイートをtestコマンドで実行することが可能
	test_suite = 'trac.test.suite',
	# プロジェクトがzipファイルから安全にインストールされ、実行されるか指定します???
	zip_safe = False,

	# この配布物がインストールされるときに、インストールされていなければならない他の配布物を指定
	install_requires = [
		'setuptools>=0.6b1',
		'Genshi>=0.5'
	],
	# 拡張機能を使うためにインストールされていなければならない他の配布物を示す文字列か文字列のリストを対応付ける辞書
	extras_require = {
		'Pygments': ['Pygments>=0.6'],
		'reST': ['docutils>=0.3'],
		'SilverCity': ['SilverCity>=0.9.4'],
		'Textile': ['textile>=2.0'],
	},
	# エントリーポイントのグループ名と、エントリーポイントを定義する文字列または文字列のリストを対応付ける辞書です。
	# エントリーポイントは、プロジェクトが提供するサービスまたはプラグインを動的に探す手助けをします。
	entry_points = """
		[console_scripts]
		trac-admin = trac.admin.console:run
		tracd = trac.web.standalone:main

		[trac.plugins]
		trac.about = trac.about
		trac.admin.console = trac.admin.console
		trac.admin.web_ui = trac.admin.web_ui
		trac.attachment = trac.attachment
		trac.db.mysql = trac.db.mysql_backend
		trac.db.postgres = trac.db.postgres_backend
		trac.db.sqlite = trac.db.sqlite_backend
		trac.mimeview.enscript = trac.mimeview.enscript
		trac.mimeview.patch = trac.mimeview.patch
		trac.mimeview.php = trac.mimeview.php
		trac.mimeview.pygments = trac.mimeview.pygments[Pygments]
		trac.mimeview.rst = trac.mimeview.rst[reST]
		trac.mimeview.silvercity = trac.mimeview.silvercity[SilverCity]
		trac.mimeview.txtl = trac.mimeview.txtl[Textile]
		trac.prefs = trac.prefs.web_ui
		trac.search = trac.search.web_ui
		trac.ticket.admin = trac.ticket.admin
		trac.ticket.query = trac.ticket.query
		trac.ticket.report = trac.ticket.report
		trac.ticket.roadmap = trac.ticket.roadmap
		trac.ticket.web_ui = trac.ticket.web_ui
		trac.timeline = trac.timeline.web_ui
		trac.versioncontrol.svn_fs = trac.versioncontrol.svn_fs
		trac.versioncontrol.web_ui = trac.versioncontrol.web_ui
		trac.web.auth = trac.web.auth
		trac.wiki.macros = trac.wiki.macros
		trac.wiki.web_ui = trac.wiki.web_ui
	""",
)

これらの設定はEgg化した際に、EGG-INFO内に格納されるようですが、
今はTracのソースを読んでいるのでsetuptoolsについては深追いしません。
出来れば、この辺りは一度きちんとドキュメントをしっかり読んでおきたいところです。

今回はget_distributionのメソッドの内部までは踏み入りませんので、ソースのコメントだけ見てみます。
引数で渡された情報を元に合致するDistributionオブジェクトを返しているようですね(ソースは変数は省略)。
DistributionObjectを探

"""Return a current distribution object for a Requirement or string"""

3. pkg_resources.requireとは何か

pkg_resourcesはファイルの冒頭で以下の様にimportされています。

import pkg_resources

pkg_resourcesはsetuptoolsで定義されたモジュールで、setuptoolsはPythonのdistutilsの多くの機能が拡張されたものだそうです。
distutilsとはPythonモジュールの配布の形式で、俗に言う

python setup.py insatll

でのインストールが可能になるための方法になります。

pkg_resourcesに関してはなんとなくわかったような気がするので(というか深追いするときりがない)
その関数であるrequireの実装がどうなっているかだけ覗いてみました。

	def require(self, *requirements):
		"""Ensure that distributions matching `requirements` are activated

		`requirements` must be a string or a (possibly-nested) sequence
		thereof, specifying the distributions and versions required.  The
		return value is a sequence of the distributions that needed to be
		activated to fulfill the requirements; all relevant distributions are
		included, even if they were already activated in this working set.
		"""

		needed = self.resolve(parse_requirements(requirements))

		for dist in needed:
			self.add(dist)

		return needed

コメントで丁寧に説明されていますが、引数で指定したrequirementsに関連するモジュールを取得しているようですね。
self.resolveで必要なDistributionの配列を返しています。

ちょっと面白かったのは、requireの引数にはバージョン番号の指定が必須になっているところです。
バージョン管理が意識されているなぁと感じます。

あと、ソースの内部を覗いているとresolve内部でリストに対して以下のような処理を行っている部分がありました。

hoge[::-1]

???だったんですが、つぶやいてみると以下のように教えてくれた方がいて納得しました(@miau_jp, @nishio に感謝!)

@hikaruworld pythonでlist[::1]とかlist[::-1]っていう書き方を見るんだけど、これはどう解釈するんだろう .
@miaumiau_jp @hikaruworld スライスの step 指定だとは思いますけど、1 なら省略可能なような・・・。
@nishio @hikaruworld 3番目はstepなので’abc’[::-1]==’cba’で’abcdefg’[::2]==’aceg’

つまり…

# [::x]のxは実行するステップ単位を表す
# [::]と[::1]は同じ。
>>> hoge = 'abcdefgh'
>>> hoge[::1]
'abcdefgh'
# 逆順
>>> hoge[::1]
'hgfedcab'
# 2つ単位で
>>> hoge[::2]
'aceg'

ということらしいです。この書き方は新鮮で面白いです。
テキストスライスに関してはこの辺りが面白かったです。

今回ははじめの一歩という事で。
これから起動部分のmain()関数に入っていきたいと思います。
その際にtracdからどうやってstandalone.pyが実行されるのかも確認していきたいと思います。

残件

以下は、今回調べきれなかった残件になります。

  • setuptoolsによる挙動の詳細(インストール周りなど)
  • doctestとdocstringの使い方

カテゴリー: program | タグ: , , | コメントする »