What have you found for these years?

2009-02-07

rack middleware

我一直搞不懂他 middleware 到底是怎麼處理的,
use 和 run 之間又有什麼差別?再一次證明:



也許正是因為所有的奧秘都在 source 裡面,所以才沒有任何人
出來講解到底 use 和 run 之間究竟有什麼差異?每每查詢 rack,
又只能找到 how but why. how 還要你說嗎?隨便找個 config.ru 就知道了吧...

就如同誰說的忘記了,rack's interface is deadly simple.
重點應該還是 middleware 是怎麼串接起來的。
當然,其實這種事也是寥寥幾行就能述盡,或許並不值得拿出來大叔吧。

重點就在這,這是 use:

def use(middleware, *args, &block)
@ins << if block_given?
lambda { |app| middleware.new(app, *args, &block) }
else
lambda { |app| middleware.new(app, *args) }
end
end

把 middleware 用 lambda 包一層放進 @ins 裡。接著是 run:
def run(app)
@ins << app #lambda { |nothing| app }
end

這裡就可以看出,use 要丟 class 進去,而 run 要丟 instance 進去。
而且 use 所丟進去的 class 的 constructor 的第一個 argument,
必須接受某一個 middleware! 這樣也可以猜測出,middleware 必定是串接的。
最後就是 to_app, 也就是真正的重點:
def to_app
@ins[-1] = Rack::URLMap.new(@ins.last) if Hash === @ins.last
inner_app = @ins.last
@ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) }
end

先不要看那個 URLMap 是什麼鬼,重點只在那個 inject(fold),
他會把你所有的 middileware 做成一個遞迴結構(inductive type?),
大概像是:

(Mid (Mid (Mid (Mid (App args))))


那個 App 就是 use 的 App, 而 Mid 就是任何的 middleware.
事實上,App 和 Mid 是差不多的東西,只差在 App 不需要串 Mid,
所以他的 constructor 並沒有受到限制。記得嗎?我們是丟 instance 進去。

上面的 a 就是某個 App/Mid, 而 e 則是 Mid constructor(廣義的 c'tor)
以顛倒的順序串起,表示當我們寫:
use Rack::Deflater
use Rack::CommonLogger

run MyApp.new

時,request 會這樣跑:
request => MyApp => CommonLogger => Deflater => client
也就是說我們需要注意 middleware 串起來的順序,沒有 side-effect 的
middleware 如 CommonLogger 當然不用在意,但 Deflater 這種會修改
response body 與 http header 的東西就必須小心其串接順序。
(不過這邊有個 trick, 就是 body 不能當成 String, 要當 Enumerator...)
(這可能跟之前提到的 EventMachine 有關,必須分段傳送,這點千萬小心。)

也就是說,上面的 use/run 是可以改寫成一個 run:
run Rack::CommonLogger.new(Rack::Deflater.new(MyApp.new))

而轉換成這種模式,則是靠 Rack::Builder 來達成。這是一個 App,
其 call 只是這樣定義:
def call(env)
to_app.call(env)
end

建造出上述的遞迴結構,然後 call 起來。

我個人認為 rack 的程式沒有寫得很好,大概只比 rails 好一點吧?
不過設計倒是滿巧妙的,確實是個很不錯的解決辦法,只是實作可能要加強一下。
而且這個做法,在 middleware 很多的情況下,不知道會不會影響效能?
畢竟串成這種遞迴結構,變成你要呼叫 MyApp 必須先把前面的 middleware 展開。
這樣會使得 call stack 變得有點巨大。當然這只是我的推測而已,
沒有實際測過,也懶得測...

反正沒有用到二三十個 middleware 的話,這應該也不會是什麼問題?
只是覺得照這樣繼續發展下去,用到一堆 middleware 是還滿有可能的。

==
我個人覺得做網頁的話,rack 會是個一定要認識的東西。
先不要管效能問題,他的彈性真的是超級大。這介面設計得相當漂亮。
大抵上只有三個概念:Handler, Middleware, Application.
前者銜接 server, 中間就是上面在說的東西,app 則是 middleware 的簡化。

2009-02-06

浪費 (2)

http://www.andaudio.com/phpbb3/viewtopic.php?p=529346#p529346

[quote="herroyuihk"]
我覺得人生要花在有趣的地方
所以浪費時間聽堪用的Grado
比浪費錢買好像聽不出來差別的耳擴.....還要浪費很多 :D
[/quote]

2009-02-03

找到右手腕殺手了

我想頻繁地在滑鼠與鍵盤之間交換應該是元兇。
解決辦法是... 不要用滑鼠 orz
試著盡量完全用 cmd + tab 切換看看。
游標移動看看能不能用左手碰那殘廢的觸控板看看。

不然最近右手真的太不舒服了...

奇怪怎麼最近有這麼多頻繁切換?

不過老實講,我覺得 windows 對鍵盤使用者親切很多,
像是 windows 鍵和 alt 都可以用上下左右控制選單。
mac 好像沒看到類似的用法,都要死記一堆快鍵...

2009-02-02

trailing whitespace

非常好:

Stage this hunk [y/n/a/d/s/e/?]? y
:27: trailing whitespace.

warning: 1 line adds whitespace errors.

git 真的是越來越強大了,連這也有 warning!
大家要養成好習慣啊,不要弄一堆詭異的 trailing whitespace.
可以用 source-tools st:strip XD

http://github.com/godfat/source-tools

這東西會做以下幾件事:

1. strip trailing whitespace
2. 把所有的 CRLF 都轉成 LF(windows 滾)
3. 刪除 utf-8 BOM(windows 滾)
4. 如果檔案最後一行沒有 newline, 則補上(最後留一空行是好習慣)
5. 把所有的 tab 都轉成 space. 可以指定 tab 要轉幾個 space:

source-tools st:strip[4]

source-tools st:strip spaces=4

預設是 2.

會對所有事先定義好的檔案執行,包含 .txt, .rb, .cpp, ...等等。
寫好這個之後,我拿去跑之前別人寫的 project,
然後就會看到恐怖的 Stripping message XD

接著 commit 可以看到 +1xxx lines -1xxx lines 感覺很爽...

有了 source-tools st:strip, 別人丟亂七八糟的文字檔也沒關係了 @_@

曾經還想做自動 iconv -f big5-hkscs -t utf-8
不過這個比較麻煩,要判斷編碼,沒有 100% 的方法...
好在後來很少再看到 big5 了。至於 CRLF 和 utf-8 BOM,
還有 tab 的問題就常有,所以才順手一起寫上去。

汝は人狼なりや? review (0)

(對了,規則可以看這篇:
http://www.ptt.cc/bbs/C_Chat/M.1233226402.A.5D5.html


還是寫個 review 好了...
目前大概打過六場,兩場村民,一場埋毒,一場共生,一場狼人,一場靈能。
村民當然沒啥好講的,埋毒記得是活到最後,
共生是被咬死,狼人那個自認打得不錯,(以新手而言 orz)
不過就中規中矩,不算好打法就是了... 如果獵人沒防得那麼準,
而且一直沒猜到「真」獵人,應該可以贏才對。
只是只剩一條狼,要到贏變成要吃到只剩一個人也有點難 XD
所以那場也算敗得很合理就是了...

比較值得提的還是剛剛那場靈能的。我只能說,
狼人如果成功掌控局面,或是讓局面混亂,勝算真的很大啊...
只是畢竟不是每個人都那麼會玩,相較之下村民方的勝算就提昇了。
不過如果都是精英... XD 我是覺得狼人要贏就很容易了。
畢竟這遊戲根本就沒什麼 100% 的推斷,只有推測啊...
只能從機率比較高的那方下手,而單就運氣而言,狼在暗處就有很大的優勢。

當然這些是跳過妖狐來講的。加入妖狐那又不太一樣了。

我個人認為這場的關鍵還是在「真」占卜實在太可疑,
規則沒搞清楚就亂講話,而且又沒明確說明占卜結果...
雖然有不少人覺得沒必要那麼快吊死他,只是應該也不是信任他吧 XD

確實就算他是假的,留下來也沒什麼不好,反正就是多個線索。
只是他又有點聒噪,有點洗板,給人印象真的太差了 XD
所以就是情勢所逼啊...

剩下兩個因素一個是埋毒沒有留遺言,結果就被假占卜真狼人假裝成占死妖狐。
畢竟這也是合情合理的解釋.... 本來就是 50% 的機率。

最後一個就是身為靈能的我沒有跳出來質疑占卜是假的!
沒跳出來的原因也很簡單,他確實可能是假的,但是也可能是真的。
如果假設真占卜沒死,那他一定就會是真占卜,畢竟沒人跳出來質疑。
那如果真占卜死了呢?...可能這個情況太慘了,所以就不願意往那邊想吧 XD
尤其埋毒如果還活著,應該出來說話,證明占卜說占到妖狐是假的!

也就是說,到了後期,其實占卜是假的機率非常高!

而且就算最後失敗而我被吊死,至少也可以動搖讓下幾個回合他被吊死的機率提高。
我想這就是為什麼會有很多人說靈能應該跳出來的。
不過我們當然沒辦法假設每個人都有辦法依照最該做的事情來做...
畢竟這不是精英團啊,所以變數非常多...

而狼人最後還是敗給妖狐,又僅僅是運氣罷了,
一開始就被假占卜當成真人... 後來就動不了妖狐了 XD
就像假占卜在黑夜裡所說的,這時候他就只能被讓人戳破他是假占卜,
於是占卜結果不對,接下來就是暴民亂吊人... orz

只是來不及,所以還是妖狐贏了。

共生莫名其妙就被吊死了,沒啥好說的。
獵人搞不清楚狀況也是當然的,連我也搞不清楚。
狼人一個當假占卜,一個當假靈能,這招真的很難擋...
倒是狂人是誰我忘了,沒啥發揮空間,畢竟狼人已經掌控局面...
他也沒辦法知道妖狐是誰,也就只能閉上嘴巴當個村民了。

我是覺得這場狼人算是發揮得不錯,只是運氣不好所以才敗給妖狐。

技法真的不少,不過也要大家都是精英才玩得起來 XD
不然暴民亂吊人就真的是完全比運氣了...
這其實也滿令人玩味的,理智的行動真的可以增加勝算?
增加自己的贏面,其實也是增加敵人的贏面啊... XD

或許有時候必須裝暴民勝算反而比較高。
說到最後可能還是兩個字:

「運氣」

畢竟誰知道計中計中計中計,反反反反反反飛彈是什麼鬼東西? XD

2009-02-01

放假

雖然說剛開始因為老鼠,再加上後來沒有自制力,
導致整週都處於日夜顛倒的狀況...

起床前也總是翻來覆去,腦中盡是一些沒有必要的妄想;
起床後打電腦除了正事都沒做,歪事也都沒做,
只做了一堆浪費時間的事,例如回頭打失落的封印,
打初音甩蔥的 flash 遊戲,東翻西看,
到頭來我可想不起來究竟做過哪些事。

雖然工作早已是生活的一部份,週末在家就是醉生夢死,
作息不正常而導致身體不太舒服,眼前飛蚊不斷,
說來說去全部都是負面的事情。

雖然說有這麼多雖然說,還是得說,很感謝有這些浪費時間的日子。
或是說,也只是盡力在認為其實都無妨吧。

==
不過最後兩天,第一天不知道該說想像力太豐富,
還是病入膏肓,居然胡思亂想到睡不著...
第二天又不知道為什麼迷上「汝は人狼なりや?
變化規則大概很多吧,總之就變成一直在想這個而睡不著 =_=b

唉,也罷,反正也只是囈語罷了

All texts are licensed under CC Attribution 3.0