2010年5月29日 星期六

Django 內建的 template

Django 內建的 template 定了一套完整的使用規範:
  • template 內不能 call function, a.b 會視情況解讀成  a.b, a[b], a.b()。所以不管 a 是 dictionary, list 還是其它物件, 「照理說」都能順利地拿到 b 的值。但若 b 是變數的話, 拿不到 a[b]。
  • filter 可以接受一個參數。比方說 my_list|join:', ' 相當於 ', '.join(my_list), 不過這裡的 join 是 Django 定的 template filter。透過 filter 能做到如同 Python function call 傳兩個參數。另外 filter 如預期般可以串起來, 像是 my_list|join:', '|safe。我常用的兩個例子是顯示 verbose_name 和用變數當 key 取出 dictionary 的值。
  • template tag 可以接受多個參數, 想用函式做的事, 它都能做。唯一不同之處, 在於 template tag 定了一套 parse -> new node -> node.render 的流程。不像平時的習慣: 傳參數到函式, 函式直接回傳字串。詳情可以參考官網的說明。
若有照 template 的規範寫, 應該能將 model、view (Django 的 controller)、template 切得很乾淨, template 的 helper function 一致放在 templatetags 目錄, 裡面有自制的 filter 和 template tag。但是 template tag 寫起來實在太冗了, 幾行可以搞定的事, 得拆成三個步驟做。另外我懷疑這樣是否會有效能的隱憂。

若沒照 template 的規範寫, 程式碼會變得比沒規範的情況更難懂。傳 class A 的物件 a 給 template 時, 就塞些 template 要用的東西到 a.x, a.y 裡, 而 x, y 不是 a 原始的 member field。或是在 A 裡寫和 A 不是很相關, 不接參數的函式, 目的只是要讓 template 可以取用值。

難怪 Django FAQ 裡有這麼一項: "I can't stand your template language. Do I have to use it?"。看到有人推 Jinja2 和 Mako。初步掃了一下語法, Jinja2 看起來滿漂亮的, Mako 看起來有點亂, 很像 Python 但又不是 Python。Jinja2 的 filter 可接受多個參數, 又有 macro 的語法, 應該可以輕鬆滿足常用需求。

不過稍微研究一下換 template 的事後, 發現有些 plugin 和內建 template 綁在一起, 如內建的 Django auth 和 django pagination。換用別的 template 就不能直接使用, 得自己用新的 template 改寫。想想還挺麻煩的。各家 template 也會有點小問題, 像 Jinja2 用到 ctypes 加速, Google App Engine 上沒有 ctypes, 造成 Jinja2 無法提供正確的錯誤訊息。還是先繼續用內建的 template 吧。

2010年5月27日 星期四

JAVA_HOME, ANT_HOME, Eclipse 和 Ubuntu

JAVA_HOME 和 ANT_HOME 是環境變數, 用來表示 Java 和 Ant 的相關檔存在那裡。Tomcat 和一些 Java App 會用 JAVA_HOME 來找 bin/java 或其它檔案。Ubuntu 上 JAVA_HOME 要設成 /usr/lib/jvm/java-6-sun。這篇有些相關說明。

Ubuntu 上 ANT_HOME 是 /usr/share/ant, ant 的執行檔放在 ANT_HOME/bin/ant, ANT_HOME/lib 下有些 ant 可能會用到的 jar 檔, 如 ANT_HOME/lib/ant-junit.jar。

這篇提到 Eclipse 有另外設 ANT_HOME, 會蓋掉 bash 的環境變數, 要從 window-> preferences ->ant -> rumtime 重設需要的東西。所以若在 Eclipse 裡執行 Ant 且有用到 ANT_HOME 的話, 要在 Eclipse 裡加入相關的 jar 檔到 Eclipse 內的 ant runtime, 比方加入 junit.jar 到 Eclipse 的 ant runtime。還有要記得在 runtime 裡設 ANT_HOME 為 /usr/share/ant。

2010年5月26日 星期三

JavaScript Closure 的運用: Memoization

JavaScript: The Good Parts ch4 後半提到 Closure 後, 一堆例子都滿有趣的, 4.15 提到 Memoization 的實作技巧。用遞迴的好處是寫起來直覺, 缺點是有可能重覆算算過的值而跑得過慢。像費氏數列就是很好的例子。Memorization 指用個 table 記住之前遞迴算過的值, 藉此減少不必要的遞迴。

上回練習寫 Memorization 已是高中的事了, 那時用 C 練程式競賽, 不過 C 沒有恰當的 scope 維護方式, Memorization 寫起來較醜一些, 表格得存在全域變數或函式內的靜態變數。JavaScript 配合 Closure 很漂亮地解決表格的 scope 問題, 以下是參考書上的範例練習寫的碼, 幾乎長得一樣啦。
var memorizer = function(memo, fundamental) {
    var shell = function (n) {
        if (memo[n] === undefined) {
            memo[n] = fundamental(shell, n);
        }
        return memo[n];
    };
    return shell;
};

var fib = memorizer([0, 1], function(shell, n) {
    return shell(n - 1) + shell(n - 2);
});

var factorial = memorizer([1], function(shell, n) {
    return n * shell(n - 1);
});

fib(5); // 5
fib(10); // 55
factorial(10); // 3628800

memorizer 的第二個參數的函式得多加一個 "shell" 欄位, 讓 memorizer 產生暫時的函式 shell, 再將它傳進目標函式, 這樣 fib /  factorial 裡用的 shell 就是有 memorization 效果的函式了。

初看的時候腦筋會打結吧, 看懂後覺得很有意思。

2010年5月25日 星期二

JavaScript 雜項心得

之後大概沒機會繼續玩 JavaScript, 整理一下之前看過的東西。

主要是看 Douglas Crockford 寫的文件。過去一直排斥學 JavaScript, 這回終於開始學了。沒想到意外地有趣, 感謝 Douglas Crockford 賣力地為它澄清, 讓我有機會重新認識它。

JavaScript

必讀文件:
  • coding convention
  • Google Tech Talk: JavaScript, the good parts。半小時而已, 看完立即明白 JavaScript 的問題, 避開它們後 JavaScript 其實是很美很強大的語言。
  • 讀 JsLint 的說明並試一試。可以協助記得 coding convention, 後來到是沒什麼在用。若有需長期維護的程式, 再拿來用吧。JsLint 可以幫忙列出函式內變數的可視範圍, 像是 global / closure / local, 頗方便的。
Douglas Crockford 寫了一些好文件, 下面是我看過覺得頗受用的幾篇:
另外就是讀他寫的書: JavaScript, the good parts。可惜我空閒時間花完了, 沒翻幾頁。之後有機會再來好好讀一讀。

jQuery

其實大部份時間都在寫 jQuery, 不過懂 JavaScript 語法的話, 寫起來比較順手, 不會被 JavaScript 的語法卡住。jQuery 真是我用過最容易上手功能又強大的函式庫。
  • jQuery 教學 - 基礎篇: 附許多例子, 大概掃一遍就能上工啦。
  • ericsk 寫的 tutorial: 有完整的例子可以跟著做。
  • 官網的 CSS Selector 文件: 要能活用 jQuery, 第一步就要能熟用 CSS Selector 選出目標物件。
  • jQuery 參考手冊: 官網文件寫得很清楚, 也有附範例碼。若要找函式名稱, visualjquery 也很方便, 可以快速濾出可能的函式。
  • jQuery UI 和 jQuery Tools 將 CSS, HTML 和 JavaScript 包好, 方便使用。像是附月曆輸入日期的 input tag, 或是 progress bar 等。
再來就是掃一遍 jQuery API, 或是視需求查一下相關的文件, 比方用 even / odd 可以一行搞定 table 奇偶列不同 css class。用 eq / index 可以找到列表中特定的元件。

QUnit

QUnit 是 jQuery 為了 unit test 而寫的函式庫。用法就是寫個 html 載入 QUnit 的 js、css, 就可以藉由瀏覽器讀網頁來執行 unit test 並將結果輸出在網頁裡。
  • 簡單易懂的例子。
  • 官網有不少例子可以參考, 像 fx.js 的寫法挺漂亮的, 用 jQuery 建出 test fixture 而不用綁在 html 上測。
若寫了不少 QUnit 想在 terminal 上執行, 可以透過 js-test-driver 執行。它只是一個 test runner, 有提供 QUnit 的 adaptor, 這樣就能用 terminal 跑 Java 程式, 透過一個執行中的瀏覽器自動跑 unit test。我是看 Miško Hevery 推薦才試用的, 只是我的 JavaScript 沒多到需要這麼測, 寫了一些 QUnit 測完較複雜的核心後, 就沒在用了。大多情況還是在 Firebug console 裡試成就就貼到 JavaScript 程式裡。待下次寫 JavaScript 時, 再來多挑戰用 TDD 開發。

Firebug

我一開始用 Chrome Developer Tools, 不過和 Firebug 交替用一陣子後, 感覺還是 Firebug 比較好用。像 DOM navigation 和調整 CSS 的部份 Firebug 好用多了。除之前在 CSS 心得提到的影片外, 再看《3 分鐘學會用 firebug 除錯》, 用 console.log() 輸出物件, 在 Firebug DOM 裡觀看細部資訊, 相當方便。

備忘

2010年5月21日 星期五

Sikuli 試用心得

由於 KMPlayer 設 Num+ 為加速播放的快速鍵, 而我用 Filco Tenkeyless, 沒有右側九宮格的小鍵盤。每次要加速播放就很麻煩, 要用滑鼠點點點的。從 100% 調到 130% 就要做六次「右鍵、移滑鼠點左鍵、移滑鼠點左鍵」, 做起來頗煩的。想說就來試試最近頗紅的 Sikuli。

成果如下, 原始碼在這裡, 以後可省下不少力氣。


簡記試用的過程
  1. 裝好後無法執行 exe, 出現 "JNI Exception: failed to create the Java VMReason: not enough memory."。google 一下發現 Windows XP 下不少人遇到一樣的問題, 執行 bat 檔即可。但這樣匯出 exe 檔後也不能執行, 只能用在 IDE 裡執行。
  2. 執行簡單的操作一直遇到問題, 預設 IDE 留很少的空間給 console, 沒看到上面的錯誤訊息。找到 console 後看到錯誤訊息說找不到圖檔, 才發現不能存在中文目錄下。
  3. IDE 抓 screenshot 的功能滿方便的, 但不知要怎麼和右鍵搭配。先用右鍵顯示某個選單, 再回 IDE 內寫 code 抓 screenshot, 右鍵叫出的選單就沒了。後來的解法是先亂抓圖, 之後再自己用抓圖軟體 (如 PicPick ) 抓右鍵選單上的圖, 抓好後再存檔覆蓋剛亂抓圖的檔名。
  4. 執行速度頗慢的, 慢到我想自己按。不過設 region 為螢幕右下角 1/4 大小後快了不少, 就夠用了。
  5. Sikuli 用 Python 的語法, 不需學習, 大概摸索一下就會用了。所以我才能順利完成自動化工作, 省下的時間拿來愉快地寫 blog。
若執行速度能更快的話, 也許可以拿來衡接產品上一些測試工作。有機會再來試。

2010年5月18日 星期二

CSS 雜項心得

再過一陣子大概會大幅減少寫 web 的事, 趁最近有空檔陸續來記錄最近的心得, 方便日後回憶。

學 CSS 的幾個重點:
一些雜項心得:
  • 先載入 undohtml 去除所有 tag 原本的功能, 方便之後設定。google 一下 "undohtml" 或 "reset css" 可以找到一些範例來用。
  • 置中的方式是將 margin 的左右設成 auto。
  • 用 colgroup 和 col 管理 table 的欄寬。
  • 用 jQuery 的 even / odd 可輕易將表格的奇偶欄設上 odd / even 的 class, 方便配色。
  • CSS 裡的 url 屬性是用相對於 CSS 檔的位置找檔案。
  • Give Up and Use Tables: 在找用 div 取代 table 的作法時發現這個站, 我聽從上面的建議, 很愉快地用 table 完成我該做的事。
日後有機會再來研究:
  • 如何模組化 CSS。網頁一多就很亂, 不好維護。和寫程式一樣, 要理出共用和各自延伸的 CSS code。
  • 適當的情況用 div / span 取代 table。讓資料可簡單地在表格和清單之間轉換呈現方式。

2010年5月10日 星期一

在 Django 內建 template 中存取 dict[key]

參考這篇的作法, 終於解掉心頭大恨。詳細問題見該篇文章最後的例子, 當 key 是變數時, 無法在 template 中用 dict.key 取值。解法是用 filter:
@register.filter(name='dict_get')
def dict_get(value, key):
    return value.get(key, '')  # 注意 filter 不能丟出 Exception

filter 的相關說明可參考之前的文章。

實在是不知該說什麼。之前為了這問題, 我笨笨地用 AJAX 分多次取回我想要的值, 實在太蠢了。

除非又遇到解不掉的功能, 或是 template 太慢, 暫時不會想換 template, 有太多東西要學啦。

在 Fedora 下裝 id-utils

Fedora 似乎因為執行檔撞名,而沒有提供 id-utils 的套件 ,但這是使用 gj 的必要套件,只好自己編。從官網抓好 tarball ,解開來編譯 (./configure && make)就是了。 但編譯後會遇到錯誤: ./stdio.h:10...