Programming分類文章 顯示方式:簡文 | 列表

March 24,2008

程式語言 學海無崖

今天我可能會很高興的說,我又多學了一種程式語言了,不過這代表甚麼呢?除了把我的工作完成,以及我可以在 resume 中多增加一項「技能」外,其他代表甚麼?

其實我今天多學的語言沒甚麼,相信很多人都會了,那就是 python ,學習它的動力來自於工作,平時我是個專打嘴砲的 project lead,寫 code 的機會較少了,但是今天老闆怕專案 schedule 趕不上來找我幫忙,我為了在一台只有 python 的機器上快速的開發一隻程式,所以只好倉促的學了 python。因為倉促,所以我也不敢說我學「會」了,頂多是會亂拼亂湊了。

不過以前我很逃避學 python,主要的原因是已經會了那麼多程式語言了,實在想不到任何讓我多學一種程式語言的理由。在今天了之後,除了得到一種成就感,也多得到一個困惑,那就是「Why are there so many programming languages?!」,有了 perl,還有 ruby、python 等等強大的 script 語言,這些語言的性質不都很相似嗎?為甚麼要創建出這麼多程式語言?! 而且這些語言就是因為相似,常常會讓自己搞不清楚究竟在寫哪一套,邊寫還要查一堆文件,讓我腦袋越來越頭大的而已。

這個問題是我在公車上胡思亂想想的,那時候我決定要回來問 Google 大神同樣的問題,Google 大神告訴我說,這個人有同樣的困惑:Eric Gunnerson,不過他的答案我也想得到,還有另外一篇文章在以演算法的角度看這問題Why so many languages? Programming languages, Computation, and Math.,喔,太難懂了; Joel on Software 也有篇文章提到了 Language Wars; 不過我最喜歡這篇的說法:Programming Languages are Like Women,這篇是以各種程式語言來借喻各種不一樣的女人,這種比喻蠻有趣的,我想程式語言跟女人一樣都是來困惑工程師的。







Posted by syshen at 樂多Roodo!20:38回應(1)

December 29,2007

Google Chart API 與我寫的 Rails plugin

Google 前不久有推出個圖表的 API,這個 API 的概念很簡單,只要按照說明文件上所寫的規範來指定 URL 後面的參數,Google 便會回傳一個 PNG 檔的圖表回來,這個 API 的好處是:

  • 解省伺服器端的 CPU 資源,繪製圖表的苦工就交給 Google 吧。
  • 解省伺服器端的頻寬,吃的是 Google 的頻寬。
  • 使用方式簡單且便利。

缺點是:

  • 僅能繪製簡單的圖表,太過複雜或者是資料龐大的圖表並不適合用此 API。
  • 客製化程度不高。
  • 不適合用在具私密性或者敏感性的資料上,因為所有的資料都是暴露在 URL 裡頭,容易留存在 cache 中,或者被竊聽。
  • 無法使用中文。

不過如果你只是想藉由 Google Chart API 開發簡單的網頁,我有寫個 Rails 的 plugin 包裝了一下這個 API,希望對你有幫助,但前提是你是利用 Rails 來開發網站。

[安裝]

於你的 Rails 目錄下執行:

script/plugin install svn://rubyforge.org/var/svn/googlechartapi

然後重新啟動你的 Rails 程式。所有成示碼都位於你 Rails 目錄下的 vendor/plugins/googlechartapi 中。

...繼續閱讀

Posted by syshen at 樂多Roodo!19:40回應(3)

November 22,2006

[Rails 筆記] tinyint ?

MySQL table 中欄位屬性如果為 tinyint(1) , Rails 會自動視其為 boolean 值,這個問題害我傷了很久的腦筋,今天找到答案了:

By default, the MysqlAdapter will consider all columns of type tinyint(1) as boolean. If you wish to disable this emulation (which was the default behavior in versions 0.13.1 and earlier) you can add the following line to your environment.rb file:

ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false


Posted by syshen at 樂多Roodo!12:02回應(0)引用(0)

November 6,2006

ruby plugin for vim

一直都是用 vim 寫 Ruby ,一直也都是黑與白,直到今天才熊熊想到,啊,沒有 syntax highlight。雖然 syntax highlight 對我來說沒什麼太大的用途,可是多點色彩,看起來好像會比較專業點,問了一下估狗大神,找到下面這個網址。

Vim/Ruby Configuration Files

抓 gem 檔回來安裝,設定好 vimrc ,人生又回復色彩了。



Posted by syshen at 樂多Roodo!22:35回應(0)引用(0)

November 1,2006

網頁自動化測試

要作網頁的 Unit test 有幾個工具可以用,例如 Ruby on Rails 本身就有提供 Unit test framework 了,而 PHP 也有幾套可以用,例如 PHPUnit、SimpleTest 以及 Spike PHPCoverage 測 code coverage,除了 RoR 我有用過外,PHP 的那些工具我都沒用過,不過這並不是我這篇想講的重點,我這裡主要是想介紹一個最近在玩的玩具,Web Service 的自動測試工具 - Watir

Watir 全名是 Web Application Testing in Ruby ,沒錯!你看到 Ruby 了,他就是用 Ruby 開發的測試架構。Watir 有什麼好處呢?第一,他是用 Ruby 開發,寫 Test Case 也是用 Ruby,感覺就親切許多,第二,他是直接 launch IE,並透過操控 IE 來測試你的 Web Application,所以可以測出一些可能在瀏覽器上才會遇到的問題,第三,寫好 Test Case 後,一切都可以自動化執行,第四,不管你的 Web Application 是用什麼語言寫的,Watir 都可以支援,因為他是啟動 IE 來瀏覽。不過它也有些缺點,第一,目前只支援 Windows 平台,第二,目前只支援 IE 瀏覽器,第三,因為是靠 IE 操作,所以測試時間會較其他測試方法長,不過總是比人工測快許多。
...繼續閱讀

Posted by syshen at 樂多Roodo!17:48回應(0)引用(0)

October 24,2006

innerHTML 與 createElement 的差異

查了一下網路上有關於 innerHTML 與 createElement() performance 的比較,都是顯示 innerHTML 有較好的 performance ,這跟我以前的印象有蠻大的差距,我一直都以為 innerHTML 會較差,直接 createElement() 以及 appendChild() 會有比較好的 performance,不過既然測試出來的數據都是這樣,看來也應該如此。

innerHTML 的優點是容易實做,程式碼容易維護,再加上 performance 較好,那麼我真的不知道使用 createElement() 跟 appendChild() 的理由為何了。

感謝 midoli 糾正我上一篇文章,我一時不查,以原本的想法觀念,寫了一篇錯誤的文章出來,看來作學問還是要秉持著嚴謹的態度。

Posted by syshen at 樂多Roodo!10:24回應(2)引用(0)

October 16,2006

[AJAX Pattern] Amazon A9 Search

上次在 Amazon 的 A9 Search 看到一個很有趣的 AJAX 應用,看了就很想自己實作看看,實際上也不困難,如果瞭解 AJAX 的原理,Javascript event 處理等就能寫出來了,所以在這裡介紹給大家看看。

[Amazon A9 Search]
傳統的搜尋引擎如 Google 或 Yahoo 等,在將搜尋結果丟出來後,會以分頁來顯示這些結果,使用者想要找的結果如果不是在第一頁的話,就會一頁接著一頁向後找尋。這種作法也沒什麼不對,很直覺,但是我看了 A9 的用法後,我反而覺得 A9 的作法更為實際,更加直覺。A9 怎麼操作的? Scrollbar !

ss
A9 會先丟出前幾筆的結果於網頁上,例如排名前 20 筆,但是當妳使用 Scrollbar 往下拉動時,更多資料就會源源不絕的顯示出來,同時妳也會發現左邊的 Scrollbar 越來越小,代表資料量越來越多。用寫的來描述這行為實在很難,妳可以上 http://www.a9.com ,透過實際操作便可瞭解。為什麼說他更直覺呢?因為如果第一次沒看到你想要的資料時,同時妳又看到 scrollbar 在旁邊,直覺上的操作就是會去拉動 scrollbar ,如同妳在 google 的搜尋結果中,也會拉動瀏覽器視窗的 scrollbar 來看底下的資料,如果沒有再點下一頁,所以既然都在拉動 scrollbar 了,何不在同時也去抓新的資料,所以我說他的操作方式更加直覺。

[怎麼做?]

假設我們想讓內容顯示在一 DIV 區塊中,藉由使用者拖拉 scrollbar 來動態增加顯示內容的話:

第一步、於 DIV 區塊上顯示 scrollbar
這很簡單,只需要透過簡單的 style 屬性設定即可,前提就是妳必須先設定 DIV 區塊高度,並設定屬性 overflow:auto ,例如:
<div id="content" style="width:490px;height:490px; overflow: auto">
....  妳想要顯示的內容。
</div>
當妳於 DIV 區塊中的內容超過 DIV 高度時,瀏覽器便會於右邊出現 scrollbar。

第二步、攔截使用者 scrolling 動作
檢而言之,攔截該 DIV 區塊的 onscroll 事件,例如:
// 注意:以下程式碼使用 prototype.js 語法
$('content').onscroll = checkScroll;
checkScoll 函式便是我們想要處理 scrolling event 的函式。

第三步、呼叫 AJAX,向伺服器要新資料,例如:
// 注意:以下程式碼使用 prototype.js 物件
var opts = new Object;
opts.parameters = 'page=' + page_num;
opts.onComplete = showResponse;
var ajax = new Ajax.Request (url, opts);
page_num ++;

第四步、取得 AJAX 回傳結果,也就是上述程式碼中的 showResponse 函式:
function showResponse(origReq) {
    $('content').innerHTML += origReq.responseText;
}
看,這樣就完成了!超簡單!所以來 re-factoring 一下。

[Refactoring]
我們將這樣的概念稍微把他物件化,讓它可以重複被使用,而且增加一些保護措施。
function showResponse(origReq) {
        var nav = $(this.nav.contentID);
        var last = nav.lastChild;
        while (last.nodeName != 'DIV') {
                last = last.previousSibling;
        }
        nav.removeChild (last);
        nav.innerHTML += origReq.responseText;
        nav.innerHTML += '<div style="background: #AAAAAA;">Fetching ... </div>';
        this.fetching = false;
}

function ScrollNav(contentID, url) {
        this.contentID = contentID;
        this.contentObj = $(contentID);
        this.contentObj.nav = this;  // 記錄目前物件,給 checkScroll 函式使用
        this.fetching = false;
        this.scrollTop = this.contentObj.scrollTop; // 記錄一開始 scrollTop
        this.scrollHeight = this.contentObj.scrollHeight; // 記錄一開始 scrollHeight
        this.url = url;

        this.idx = 0; // page number

        this.checkScroll = function() {
                if(this.nav.scrollTop == this.scrollTop)
                        return;
                if (this.fetching)
                        return;

                this.nav.scrollTop = this.scrollTop;
                if (this.scrollHeight == parseInt(this.style.height) + this.scrollTop) {
                        var opts = new Object;
                        opts.parameters = 'page=' + this.nav.idx;
                        opts.onComplete = showResponse.bind(this);

                        var ajax = new Ajax.Request(this.nav.url, opts);
                        this.fetching = true;
                        this.nav.idx ++;
                }
        }

        // 攔截 onscroll event
        this.contentObj.onscroll = this.checkScroll;
}

function init() {
        var nav = new ScrollNav('content', 'scroll_test.php');
        var nav = new ScrollNav('content2', 'scroll_test2.php');
}

這裡頭有個 ScrollNav 物件,就是將這些東西都包進去了,此外,於 checkScroll 函式中會檢查 event 是否被重複攔截,以及檢查目前 scrollbar 是否被拉動至最下方,唯有 scrollbar 被拉到最下面時,我們才向伺服器要求更多的資料,避免頻寬資源的浪費。scrollTop 跟 scrollHeight 都是內建的屬性,scrollTop 代表目前顯示的 view 距離最上方多少有 pixel,而 scrollHeight 則代表內容 view 的總長,同樣是 pixel,當妳資料越塞越多時,scrollTop 跟 scrollHeight 都會跟著增加,如果要判斷 scrollbar 是否為拉到最下方,最簡單的方法便是計算 scrollTop 和 DIV 區塊的高度總長是否等於 scrollHeight 即可。

至於在 showResponse() 函式中,我們會在每次抓到的新資料中都塞進個「Fetching ...」的字眼,代表目前正在抓取更多資料,這是一種小技巧,就像在大部分的 AJAX Pattern 中都可以看到的 Loading 字眼,妳也可以用個 gif 動畫來取代,只不過每次取得新資料時,必須將上一個「Fetching ...」移除。

想看結果嗎?請看 Demo 。裡頭有兩個 DIV 區塊,左邊的 DIV 區塊所 request 的 PHP 檔執行較快,而右邊的每次都會 sleep 5 秒鐘,所以感覺起來比較慢,拉動兩個 scrollbar 妳便可以發覺兩者間的不同。

[其他問題?]
目前這個範例還有些存在性的問題:
  1. 別吃光 browser 的記憶體了。塞資料時要設立停止點,別一直狂塞,吃光妳瀏覽器的記憶體了。
  2. 不一定要拉動到最下方才開始抓取資料,可以在使用者的 scrollbar 接近最下方時,便向伺服器要求新資料,可以達到更順暢的操作。


[這可以應用在哪?]< br/> 我想這些概念,實作都是很簡單,重要的是妳有沒有創意,有沒有想到這些 idea,以及怎麼應用在妳的網頁中,這我想應該讓妳自己去想想看,不過我覺得可以應用在某些功能上,例如 blog 留言版,留言版並不是每個人都想看,如果留言眾多時,每次都將留言塞到使用者的瀏覽器上也不甚合理,如果透過類似的方法,先讓使用者看到最新的留言,如果想繼續看下去,只需要拉動 scrollbar 即可。應該還可以想出更多有趣的應用,不過還是大家自己想想看吧。





Posted by syshen at 樂多Roodo!21:22回應(3)引用(0)

October 2,2006

[Rails 筆記] Boolean pitfall

Ruby 沒有明確的 boolean 型別定義,不過通常以 nil 或 false 來代表 false,其他通通都是 true ,所以有個陷阱了,C 語言同樣也沒有 boolean 型別,但可以用 0 代表 false,非 0 代表 true,我們也都習以為常,不過在 Ruby 中,0 代表 true,例如:

a = 0
if (a)
puts ("true")
else
puts ("false")
end

會印什麼,true 啊。

Posted by syshen at 樂多Roodo!10:47回應(2)引用(0)

September 28,2006

[Rails 筆記] 在 session 中儲存物件

答案是利用 Ruby 的 Marshal 物件,如下例:

class AdminController < ApplicationController
def do_login
if request.post?
user = User.login(params[:uid], params[:pwd])
if (user)
session[:user] = Marshal.dump(user)
end
end
end
end

然後在 application.rb 中:

class ApplicationController < ActionController::Base
model :user
def setup_variables
if (session[:user])
@login_user=Marshal.load(session[:user])
end
end
end
這樣有什麼好處,好處是對於一些常用的物件,例如 Query DB 得到的 Model,我不用在每個 page 都再去 query database,將他記錄在 session 中即可,而且可以避免 db schema 更改後還要改 code 的窘境。



Posted by syshen at 樂多Roodo!0:27回應(3)引用(0)

September 25,2006

[Rails 筆記] ActiveRecord 轉換 JSON

酷耶,看到這都快興奮的跳到桌子上了,看看這個連結吧:Accessing ActiveRecord objects in javascript
雖然我看不太懂這段 code 的意思,不過測試的結果,可以 work 耶! 讚!
就只剩下 JSON 轉 ActiveRecord 了,改天再來研究看看。

(1) 安裝 json:
% gem install json

(2) Add a new file : /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/json.rb , 裡頭包含以下程式碼:

require 'json/lexer'
require 'json/objects'
module ActiveRecord
  module Json # :nodoc:
    DEFAULT_CONVERSIONS = { Time => [:to_s, :db] }
    def to_json(conversions = {})
      conversions = DEFAULT_CONVERSIONS.merge(conversions)
      self.attributes.keys.inject({}) do |hsh, key|
        value = self.send(key)
        hsh.merge(key => conversions[value.class] ? value.send(*conversions[value.class]) : value.to_s)
      end.to_json
    end
  end
end


(3) 在 environment.rb 中加上: [Update]: 似乎不用加以下這段,加了反讓 fastcgi 掛掉,不加也能 work 啦

require "#{RAILS_ROOT}/lib/active_record/json"
ActiveRecord::Base.class_eval { include ActiveRecord::Json }


(4) 使用時,呼叫 to_json() 函式即可。

user = User.new()
user.to_json()



Posted by syshen at 樂多Roodo!18:59回應(0)引用(0)
 [1]  [2]  [3]  [最終頁]