3/30/2007

Aptana 跟 RadRails 整合時間表

自從 RadRails 跟 Aptana 整合之後,新的主控者 Aptana 出了一點小錯誤,DNS 指定好像出了點錯誤,一直連不上 RadRails 官方網站,要上 RadRails 請先用 http://www.aptana.com/radrails 這個 Link。言歸正傳,Aptana已經提出了整合的時間表,他們希望四月就出 Boundle Download,五月就會做出 RHTML 整合到 Aptana ,真是令人興奮。



April

Bundled download. Users will be able to easily download a combined Aptana + RadRails, or the seperate plugins.


May

RHTML Integration. The Aptana HTML editor will support adding inline Ruby script with code assist. Other bug fixes and updates.


3/28/2007

Fragment Cache Part 2

上次介紹了如何使用最基本的 Fragment Cache,現在來加上一些小小的小 trick。上次介紹在 View 裡面要這樣使用Fragment Cache


<% cache do %>
我們要 cache 的 content
<% end %>
Cache 會出現在 RailsRoot/tmp/cache/你的host/你的controller/你的action.cache 這個檔案裡面。假設上面的 action 是在 lala controller 的 haha action ,那們上面的寫法跟 下面的寫法效果是一樣的
<% cache(:controller => 'lala' , :action => 'haha' ) do %>
我們要 cache 的 content
<% end %>
簡單講,就是最上面的 cache do 寫法算是預設值,寫不寫好像沒差,當這個頁面只有這裡需要 cache 時,這樣寫就很方便。不過如果這個 haha action 會依照後面接的 id 的不同顯示不同的內容時,你可以很直覺的加上 :id 這個選項
<% cache(:controller => 'lala' , :action => 'haha' , :id => params[:id] ) do %>
我們要 cache 的 content
<% end %>
Cache 會出現在 RailsRoot/tmp/cache/你的host/你的controller/你的action/這個頁面的id.cache 這個檔案裡面。簡單講,又多了一層以 action 為名的目錄,目錄裡面每個 id 都有自己的 cache file。這樣的作法可以簡單依照變數的不同區分 cache file 。

不過?

但是老實說,到目前為止,這個 fragment cache 用途還是不大。我們一個 Action 只能使用一個 Partial Cache,那如果同一個頁面有兩個以上的地方要 cache 呢?Partial Cache 的概念就是一個網站有很多個 block 可以被許多頁面共用。假設某個頁面有兩個部份要 cache ,一個是 RSS ,另外一個是 Info 這個地方。那我們依照 Rails 聖經本的方法,使用 part 變數供我們使用
<% cache(:controller => 'lala' , :action => 'haha' , :id => params[:id] , :part => 'rss' ) do %>
我們要 cache 的 rss content
<% end %>
<% cache(:controller => 'lala' , :action => 'haha' , :id => params[:id] , :part => 'info' ) do %>
我們要 cache 的 info content
<% end %>
如此,相關的 Cache 會產生在 RailsRoot/tmp/cache/你的host/你的controller/你的action/這個頁面的id.part=rss.cache 還有 RailsRoot/tmp/cache/你的host/你的controller/你的action/這個頁面的id.part=info.cache 這兩個 file 裡面。仔細看就知道,他的命名機制就是 id. part=part_name.cache 這樣的寫法。很簡單吧。

到現在 Partial Cache 才從還好變成好用的階段。read_fragment 或是 exprie_fragment 都是使用
:controller => 'lala' , :action => 'haha' , :id => params[:id] , :part => 'info' 
這樣的命名機制來操作,不難吧。

還有嗎?

到現在為止,我還沒看過 :part 還不夠的情況,不過如果真的覺得用 controller , action , id , part 都不夠區分你的 cache ,還有最後一招
<% cache(:controller => 'lala' , :action => 'haha' , :id => params[:id] , :part => 'rss' , :part2 => 'rss'
, :part3 => 'rss' .... ) do %>
我們要 cache 的 rss content
<% end %>
簡單講,其實 :part 只是聖經本這樣寫,所以在 Rails Fragment Cache 機制裡,id 以後的 fragment 命名方式不限制,而且數量不限制,只要你不嫌打字太累,你大可以用幾百層去命名你的 cache 。出來的 cache file 命名規則是這樣 ailsRoot/tmp/cache/你的host/你的controller/你的action/這個頁面的id.part=rss&part2=rss&part3=rss.cache。總之隨便你怎麼命名 :p

3/27/2007

class 與 instance

不知道為何,最近不管是私事或公事似乎都很多。造成的結果就是很多事不知道該從何處著手比較好。也許短時間內沒辦法寫什麼新東西也說不定,所以我又拿舊文章出來改了。這次講的是 Ruby 的物件系統。不過呢,由於這篇原本是回答別人的問題,因此有些地方講得不是很齊全,有些也講得比較偏。找到時間後,會再重新整理一次,現在就先這樣吧

編輯筆記:後面一段無關的刪去了,並補充了一小段。

==

在看 Ruby 的 class 與 instance 之前,先來看所謂 prototype-based language 是怎麼樣的東西,當然是舉大家最耳熟能詳的例子,ECMAScript(即 Javascript)

所謂 prototype-based 的意思是,沒有 class 的概念,所有的一切都是 instance, 產生東西一律使用 clone 的手法,從 prototype clone 出來。

在 ECMAScript 裡,要這樣操作 prototype:

=begin 例子

// 產生一個 function object, 會輸出「我是 ooo」
function say(){ print('I am ' + this) }

// 產生一個 function object, 拿這當 Duck 的 prototype
function Duck(){}

// 讓 Duck prototype 產生一個成員,也就是讓 say 變成他的 method
Duck.prototype.say = say;

// 定義 toString 讓 say 使用
Duck.prototype.toString = function(){ return 'Duck' }

// 假設現在有一個讓某東西說話的 function
function say_hello(who){ who.say() }

// 於是我們可以這樣呼叫 say_hello
say_hello(new Duck)

=end 例子

new Duck 會去尋找 Duck 的 prototype, 然後 clone 一份該 prototype 後傳回。所以 say_hello 的 who 會是一份 Duck 的複製,執行 say 則會輸出:

I am Duck



ok, 回到 Ruby. 雖然說 Ruby 被分類成 class-based, 但事實上,everything(ok, almost) is an object in Ruby, 就算是 class, 他其實本質上也是某個 instance, 是 Class 的 instance.

class A; end
a = A.new

a 是 A 的 instance, 所以 a 的 class 是 A.

a.class # A

A 是 Class 的 instance, 所以 A 的 class 是 Class

A.class # Class

其實,我覺得可以把這個 Class 視為某種 meta-class, 即 class 的 class, 如果我們要把 A 當嚴格 class 的話。但如果我們依然把 class 當 instance 看的話,當然,Class 本身其實也是一個 instance, 他是他自己的 instance.

Class.class # Class

有趣的是,這樣寫的話:

Class.object_id == Class.class.object_id

答案是:true.
Class.class 傳回來的,其實就是 Class, 也就是,他是他自己的 instance. 換句話說,其實 Class 是所有的 class 的 class.

A.kind_of? Class # true
Class.kind_of? Class # true
A.class # Class
Class.class # Class
A.class.object_id == Class.object_id # true



(btw, 其實更妙的是:

Module.kind_of? Class # true # Module 是 Class 的 instance
Class.kind_of? Module # true # Module 是 Class 的 superclass
Module.new.kind_of? Class # false # Module 的 instance 不是 Class



再加上 Object 會更複雜,可以試著畫畫看物件結構)

但是回想一下,一般我們是怎麼定義 class 的?

class A; end

其實,我個人會說這是一種 syntax sugar, 因為更合於 Ruby object system 的定義方式,應該是這樣:

A = Class.new
A.send(:define_method,
:say_hello,
lambda{ puts "Hello from A's instance." })

a = A.new
a.say_hello # Hello from A's instance.



由於 define_method 是 private 的,所以要用 send 去呼叫。其第一參數是你所要回應的 message symbol, 第二參數是 Proc/Method/Block 都可,將會成為該 method 的 body.

也就是說,其實你寫

class A
def say_hello
puts "Hello from A's instance."
end
end



對於 A 來說,他是先從 Class 產生一個實體(instance),然後將 A 這個「常數」指向那個實體,再對 A 呼叫 define_method, 把 say_hello 變成 symbol, 將 Block 變成該 method 的 body.

哪一個比較容易寫?當然是後者,畢竟那是大家都很習慣的模式,簡潔易懂。所以我會說那種寫法其實在某種程度上來說,是 syntax sugar... 而 Ruby 其實也是用 prototype 建出其 class 體系,這樣應該算是 prototype-based 還是 class-based, 看倌認為哩?

2007.02.08

補充:

有在寫 Ruby 的人,應該都知道 class 的名稱一定要大寫開頭。事實上,這只是一種延伸規則,並不是基本的規則。依照:

a = Class.new

仍然是可以得到一個不是大寫開頭的 class. 大寫開頭的 identifier 在 Ruby 是一個更簡單的概念:「常數」(constant)。也就是說,其實每一個 class name 都是一個常數,一個 constant variable refer to a Class's instance, 一個指向 Class 實體的常數,就跟一般的變數沒兩樣。所以我們可以寫:

def make klass
klass.new
end

這個 functiona 接受一個參數,這個參數的 type 的必要條件是實作 new method, 而任何一個 Class instance 都符合這個條件。

make(Array).push(123)

把 Array 這個 instance 丟給 make 這個 function, 回傳就是一個 Array instance.(global function 也值得探討,不過還是留待下次吧 :p)

那麼為什麼要讓 Class instance 成為一個常數?其實這是很顯而易見的,如果你把原本定義好的 class 整個變成其他人了,例如:

Array = String

這樣意義在哪裡?以後寫 Array.new 產生的就不是原本的 array, 而是 string 了。所以讓 class 成為一個 constant, 並要求其開頭字母是大寫,並非單純只是為了命名習慣的問題,背後是還有牽扯到其他因素的。

我覺得 Ruby 有趣且厲害並迷人的地方就在於,他不單單只是有強大的威力在內,還額外提供了許許多多方便使用的 syntax sugar, 使任何人都能快速上手,也能快速做到任何他想做到的事情。而當你需要更強大的表達能力時,也能立刻拋棄 syntax sugar, 從最原始的 Ruby 道理開始寫起程式。也就是說,Ruby 提供了各種不同的寫程式角度,大家都可以去找他喜愛的角度去使用。個人認為,Lisp 會不及 Ruby 方便,最主要的差別就在這裡了。(當然,我並不熟 Lisp, 所以這句話恐怕是大有問題在…。)

2007.03.27 godfat 真常

延伸閱讀

Fragment Cache Part 1

之前介紹過 Page Cache,那是一個將所有動態內容都變成靜態頁面,藉由不經過 CGI ,來達到最大覆載度的技巧。但是他的應用性不夠廣泛,僅限於下面的用途


  1. 流量超級大的頁面
    通常是 index page,一個網站可能有幾百個頁面,但是通常 index page 一個頁面就佔了三到五成的流量,而且 index page 通常每個網站都是一個小時,了不起 15 分鐘更新一次,這個時候用 index page 可以大幅度增加網站覆載度。
  2. 頁面修改的頻率遠遠小於讀取的頻率
    例如 Blog 系統,我可能一天寫一篇文章,但是一天讀取我的 Blog 的人可能有幾千個,這個時候為什麼每次讀取頁面的時候都得去 DB 撈資料,組合,Render 出來呢?還不如用靜態頁面儲存,然後每次修改頁面時都重新產生新的 HTML 即可
但是,如果要利用 Page Cache 做到某些部份的功能實在有點麻煩。像是在同一個頁面裡面,有些地方是很少機會修改,希望能夠 Cache 起來,但是有些地方修改頻率超頻繁,不能夠用 Page Cache 來做。這個時候,我們就可以使用 Partial Cache 的方式來加快速度,在Rails 裡面 Partial Cache 叫做 Fragment Cache。

使用方式如下

在 View 裡面

選定要 Cache 的部份,將他用 cache block 包起來
<% cache do %>
我們要 cache 的 content
<% end %>
如此,當我們用 production mode 的時候,你就會發現會出現 tmp/cache/你的controller/你的action.cache 這個檔案,也就是 cache 的內容。並且 reload 的時候,那個 block 的 content 都是不變的。

理論上 cache 是 work 的,但是如果你去翻 log 時,你會發現 db 一樣會去做相關的 operation。原因是因為我們並沒有告訴 Rails ,Controller 裡面某段 code 是已經 cache 好的東西,不需要去執行。我們都知道 db 通常是最大的 bottleneck ,如果 cache 沒辦法避免 db operation,那這樣的 cache 也僅僅省去了 render 的時間,並沒有太多幫助。

在 Controller 裡面

為了避免這樣,我們要在 controller 裡面指明,當 Fragment Cache work 時,某些 operation 是可以不用執行的。
unless read_fragment :action => '這個action的名字'
跟 cache 有關的 operation
只要有 cache ,就不需要去執行的 code.....

end
如此如果已經 cache 過了, Rails 就會避開這段 code 的執行。

要如何 Expire Cache

Expire Cache 也是相當的方便,在 controller 裡面使用 expire_fragment 即可。
expire_fragment :action => '這個action的名字'
以上都是最最最基本的 Fragment Cache 的機制,但是如果只知道這些東西,根本做不了太多事情,我們下次來談談比較實用的 Fragment Cache 機制。

Ajax auto-update

Ajax 跟 Ruby on Rails 的整合已經眾所皆知,今天心血來潮,想來實做 digg-spy 形式的資料更新。但是我的需求是每隔一段固定的時間更新,而不是一直 append 新的訊息。在參考了幾個網站後,驚訝的發現,這種 auto-update 的 Ajax 怎麼可以這麼簡單(請用 thegiive 的口氣自行想像)。

*** 斜體字為你尚未命名或已經命名好的名稱 ***

[summary] 我們得準備:
  • 一個 controller 裡面的新的 action,假設該 action 名稱為 action-name,該 controller 名稱為 controller-name
  • 一份 RJS template,置放在 /app/views/controller-name/action-name.rjs。
  • 一份 partial template,假設置放在 /app/views/controller-name/_show_topics.rhtml。
  • 在適當的地方加入 javascript。


step 0:
首先在預設的 layout 中掛入 prototype 等 JavaScript。寫法如下:

<%= javascript_include_tag :defaults %>

其中 :defaults 會將 /public/javascripts/ 中預設的 JavaScript 都掛載上來。如果不想全部掛上來的話,可以改寫成 :script-name

step 1:
接著在你的 controller 裡面寫入一個新的 action。假設我們想要每分鐘更新文章列表:

def update_topics
# 取出最新的 forum 文章,get_all_topics 請自己在 model / controller 撰寫
@all_topics = get_all_topics(10) # hard code 是不好的,小朋友不要學。也可以順便做錯誤處理。
end

step 2:
接著是你必須建立一個檔案 /app/views/controller-name/action-name.rjs,在這個 RJS template 裡面使用 prototype helper 裡面的 methods 來與瀏覽器溝通。內容如下:

page.replace_html 'update-topics-div', :partial => 'show_topics', :object => @all_topics
page.visual_effect :highlight, "update-topics-div"

我們用了 replace.html 來幫我們做取代的動作,如果是 digg-spy-style 的話,通常我們會用 insert.html,有空再來寫。值得注意的是,在這個檔案裡面無須使用 <%%> 來內嵌,直接撰寫即可。update-topics-div 這邊代表的是欲取代的 html element id,show_topics 則是欲取代的 partial template(注意 template 的命名有 prefix _,render 時無須 prefix _,也無須副檔名),再利用 :object 將變數 binding 到 template。visual_effect 效果我就不介紹了。

step 3:
當然你要有輸出的 view,我們假設是 /app/views/controller-name/another-action-name.rhtml。部份的片段應該有:

...
<%= render :partial => 'show_topics' %>
...

而我們的 template _show_topics.rhtml 假設長成這個樣子:

<div id='update-topics-div'>
<ul>
<% @all_topics.each{ |topic| %>
<li><%= topic.title %></li>
<% } %>
</ul>
</div>

step 4:
最後我們挑選一個適當的地方加入 JavaScript,什麼叫適當的地方呢?因為有些 template 會共用的關係,如果把 JavaScript 加入到共用的 template,會出現 RJS 找不到 html element id 的錯誤,所以說得擺在適當的地方,當然跟瀏覽器的支援程度也有關係。假設找到了適當的地方,則我們加入 JavaScript 如下所示:

var updateInterval = 60 * 1000; // 每分鐘 update 一次
var timer;

function goUpdateTopics() {
timer = setInterval('updateTopics()', updateTopicsInterval);
}

function updateTopics() {
// url 記得寫對!
url = "/controller-name/action-name";
new Ajax.Request(url, {
asynchronous: true,
method: "get",
});
}
goUpdateTopics();


Well, 經過這四步驟,你應該已經可以快樂地使用 Ajax 整合在 Rails 裡所提供的功能與樂趣。:)

延伸閱讀

3/24/2007

一個接近夢想的境界

A:我們該如何跑 Ruby on Rails 呢?
B:簡單,將你的 Rails App JAR 起來,然後 upload 到 tomcat ,就大功告成了。

這句話在Stockholm Rails/Ruby Group meeting 的時候爆出來,就顯得真的很夢想無限呀。
You JAR up your rails app, upload it to TomCat and your Rails app is deployed. It just works.
當然目前 JRuby Team 還沒 release 1.0(1.0 的目標就是 JVM 上跑 Rails),還得花點時間等這一天,不過,或許這一天真的快了也說不定。

3/21/2007

Gentoo 上面跑 DRB 可能出現的問題

有時候在 Gentoo 上面使用一些有關 DRB 的東西,像是 Breakpoint Server ,或是 gem_server。通常會遇到兩種很奇怪的 Error


  1. Exception `SocketError’ at /usr/lib/ruby/1.8/drb/drb.rb:840 - getnameinfo: ai_family not supported
  2. /usr/lib/ruby/1.8/drb/drb.rb:840:in `getaddrinfo’: getnameinfo: ai_family not supported (SocketError)
這問題的解法我一直到看到這個網頁才瞭解,是因為在 Gentoo 上面編 Ruby 時需要啟動 ipv6。不要問我為啥,事情就是這樣 。So, 解決方式很簡單,/etc/portage/package.use 裡面加一行 dev-lang/ruby ipv6。然後重新安裝 Ruby 即可。

3/20/2007

Rails 的 Rake Task List

今天有人問到怎麼清 log ,結果我一直記得 Rails 的 Rakefile 可以幫你 log,不過還是忘記怎麼打了,查了一下發現只要 rake log:clear 即可。

在 Rails 裡面,預設了很多 rake 指令可以幫你輕鬆達成許多任務。這裡列出所有的 Rails Rake Task List。基本上,要叫出 Task List 只要在 Rails 資料夾下面打 rake --task ,或是 rake -T ,他就會自動幫我們叫出 Rails 下面所有的 Rake Task List。

DB 處理方面的 Task
  1. rake db:fixtures:load
    # Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y
  2. rake db:migrate
    使用 Database 的 migrate 功能,他會把 db/migrate 裡面寫的 script 寫入到 DB 裡面。
  3. rake db:schema:dump
    將 DB 的 Schema Dump 到 schema.rb 這個檔案裡面
  4. rake db:schema:load
    將 schema.rb Load 進入 DB 裡面
  5. rake db:sessions:clear
    假設你的 Session 是利用 CGI::Session::ActiveRecordStore 存在 DB 裡面的時候,這個指令可以清理裡面Session 的 Table
  6. rake db:sessions:create
    當你要使用 ActiveRecordStore 來存放 Session 時,你可以用這個指令來 create Session DB
  7. rake db:structure:dump
    將 DB 的 Schema Dump 到 SQL format 的檔案
  8. rake db:test:clone
    # Recreate the test database from the current environment's database schema
  9. rake db:test:clone_structure
    # Recreate the test databases from the development structure
  10. rake db:test:prepare
    # Prepare the test database and load the schema
  11. rake db:test:purge
    # Empty the test database
自動建立 RDoc
  1. rake doc:app # Build the app HTML Files
  2. rake doc:clobber_app # Remove rdoc products
  3. rake doc:clobber_plugins # Remove plugin documentation
  4. rake doc:clobber_rails # Remove rdoc products
  5. rake doc:plugins # Generate documation for all installed plugins
  6. rake doc:rails # Build the rails HTML Files
  7. rake doc:reapp # Force a rebuild of the RDOC files
  8. rake doc:rerails # Force a rebuild of the RDOC files

清理 log file
  1. rake log:clear
    清除 log file
Rails 版本 Freeze 跟 Update
  1. rake rails:freeze:edge
    把這個 Rails Package 的 version lock 到最新的 version,也就是會 copy 一份Rails包到 vernder/rails/ 資料夾底下,以後跑這個 Rails Package 就不使用系統內部的 Rails Version,而是使用 vender/rails/ 底下的 version。
    # Lock to latest Edge Rails or a specific revision with REVISION=X (ex: REVISION=4021) or a tag with TAG=Y (ex: TAG=rel_1-1-0)
  2. rake rails:freeze:gems # Lock this application to the current gems (by unpacking them into vendor/rails)
  3. rake rails:unfreeze
    如果之前使用過 rake rails:freeze:edge ,但是如果你後悔了,想要重新啟用系統裡面的 Rails Version,那就用這個指令將 vender/rails 裡面的東西清掉。
    # Unlock this application from freeze of gems or edge and return to a fluid use of system gems
  4. rake rails:update # Update both configs, scripts and public/javascripts from Rails
  5. rake rails:update:configs # Update boot/config.rb from your current rails install
  6. rake rails:update:javascripts # Update your javascripts from your current rails install
  7. rake rails:update:scripts # Add new scripts to the application script/ directory
code state
  1. rake stats
    Show 出目前 App Code 的狀況
Unit Testing 方面
  1. rake test # Test all units and functionals
  2. rake test:functionals # Run tests for functionalsdb:test:prepare
  3. rake test:integration # Run tests for integrationdb:test:prepare
  4. rake test:plugins # Run tests for pluginsenvironment
  5. rake test:recent # Run tests for recentdb:test:prepare
  6. rake test:uncommitted # Run tests for uncommitteddb:test:prepare
  7. rake test:units # Run tests for unitsdb:test:prepare
清理 tmp/ 底下的暫存檔
  1. rake tmp:cache:clear
    將所有 tmp/cache/ 裡面的東西都清理掉
  2. rake tmp:clear
    將所有 tmp/ 裡面的東西都清理掉
  3. rake tmp:create
    建立 tmp/ 資料夾,順便建立 tmp/sessions/,tmp/cache/,tmp/sockets/
  4. rake tmp:sessions:clear
    將所有 tmp/sessions/ 裡面的東西都清理掉
  5. rake tmp:sockets:clear
    將所有 tmp/sockets/ 裡面的東西都清理掉

3/19/2007

ActiveRDF - putting semantic web on rails (1)

由諸多的現象我們可以推測,在 Social Web 的時代中 Ruby on Rails 這個 web development framework 不但嶄露頭角,甚至形成了大量的助力。我們能透過 Ruby on Rails 輕鬆地建置 tagging system,我們能透過 Ruby on Rails 建立社群的交流平台,我們能透過 Ruby on Rails 建立人事時地物的複雜關係,甚至透過 Ruby on Rails 來建置 Web Service 的環境與應用。我們甚至可以說,在 Web 2.0 的時代與 Ruby 社群蓬勃發展的現在,Ruby on Rails 幾乎不留遺憾。

我們並不清楚 Semantic Web 是不是 Social Web 的下一世代,不過 Semantic Web 確實有較多數人認同是 web 3.0。Semantic Web 是什麼呢?簡單的說,在 web 上的資源隱藏有語意的註記,透過這些語意的註記,將可以被機器處理。譬如一個簡單不過的例子,在 web 上有兩筆資料,『A 與 B 的結婚紀念照片』、『C 在 blog 中揭露了他的父親是 A』,則機器透過這兩筆資料上面隱藏語意的註記,再加上人們加諸給它的家庭的定義(或稱 ontology),則機器將可以運算出『C 的母親為 B』這樣的推論來。

我很難想像現存的 WWW 這麼龐大的資料如何被加入語意的註記,於是我非常能夠認同 Semantic Web 必須也得依靠眾人的智慧來成就,因為那些語意的註記絕對不是幾個團體能夠負擔,當然也很難達到自動的語意註記。

扯得有點遠了,回到這篇的主題來。我們知道 W3C 制定出了 RDF 與 OWL 等來描述 ontology 的框架 / 語言來。前陣子 DERI 裡面幾個研究人員幫 Ruby on Rails 寫了 ActiveRDF 來方便 Ruby on Rails 加入一些語意的支援。我們知道 ActiveRecord 扮演著 Object-Relational Mapping 的橋樑,將 Relational Database 裡面平面的表格透過 code generation 建構為具有階層關係的物件。而 ActiveRDF 則是可以將 RDF(S) 裡面的 Triple 關係建構為具有階層關係的物件。顯然地,作者群的開發時,野心並沒有大到連 reasoning、validation 或 constraint 這些機制都支援,正如同 Ruby on Rails 的精神之一;只扮演好自己該扮演的角色就足夠了。


延伸閱讀


3/18/2007

SWIG/Ruby

以下文章最早發表於 2006.08.06, ptt Ruby 板。由於這裡的版面跟 BBS 有極大的差異,所以稍微調整了一下排版。不過程式碼的部份可能很難調整到方便閱讀,這點也就請見諒了。

http://www.swig.org/

SWIG is an interface compiler that connects programs written in C and C++ with scripting languages such as Perl, Python, Ruby, and Tcl.

也就是,讓 C/C++ 與 scripting language 溝通的介面產生器。目前支援 13 種程式語言(含非 scripting language):

* Allegro Common Lisp
* C#
* Chicken
* Guile
* Java
* Modula-3
* Mzscheme
* OCAML
* Perl
* PHP
* Python
* Ruby
* Tcl

之前我測了一些 Ruby 與 C++ 的溝通方式,以下將簡單介紹一下測試的方法。首先先看到使用方式,我想這個應該是最重要的部份,畢竟如果使用不便,那其他的也不用再多說什麼了…。




以下這個程式是一個簡單的 type wrapper,(傳值版)由 template parameter 指定型別,data() 當 getter, data(type) 當 setter. 另外在 c'tor 和 d'tor 中插入 IO 來追蹤物件的生成與摧毀:
// in Wrapper.h

#include <iostream>

template <class Data>
class Wrapper{
public:
Wrapper(Data new_data): data_(new_data){
std::cout << "C++: Wrapper is created, which is '"
<< data_ << "' .\n";
}
~Wrapper(){
std::cout << "C++: Wrapper is decayed, which is '"
<< data_ << "' .\n";
}
Data data() const{ return data_; }
void data(Data new_data){ data_ = new_data; }
private:
Data data_;
};

有了這個 .h 檔的介面後(這裡同時也包含實作),接下來我們需要的是一個由 swig 產生的膠水,將 C++ 介面與 Ruby 介面混合,暫時命名為:Wrapper.i, 詳細做法等一下我們再來看。總之最終我們將產生一個動態連結檔,也就是一個 Ruby 的 module, 叫 Wrapper. 不過需要一提的是,由於 Ruby 本身不支援 template, 所以我們在 Wrapper.i 中必須明確指出我們需要什麼型別,否則 Ruby 會無法使用。(更明確來講,純 template 根本無法 compile)

所以在 Wrapper.i 中,裡面有一行是這個:

%template(Integer) Wrapper<int>;

這句話的意思是,將 Wrapper<int> 這個型別取作 Integer. 於是 Ruby module 做好後,可以使用 Integer 這個型別。




雖然我中間還有很多測試,不過直接看目前的最後結果吧。寫一個 Ruby 程式,內容如下:
#!/usr/bin/ruby
# in test.rb

require 'Wrapper' # 讀入剛剛做好的 Wrapper module

class Test < Wrapper::Integer # 繼承 C++ 寫好的 Wrapper<int>

def initialize(new_data) # c'tor 其實可以省略,因為可以使用
super(new_data) # C++ 中寫好的 Wrapper
end # 這裡只是展示 super 是可以用的

def plus(num)
data(data + num)
data
end

end

# 正式測試開始

fat = Test.new(123) # 建構出 Test 物件,傳入 123 當引數
puts fat.plus(7) # output: 130

fat.data(456) # 設值為 456
puts fat.plus(4) # output: 460

ok, 可是原本插入 C++ 的 c'tor 中的 IO 呢?整個程式的輸出結果是這樣:

C++: Wrapper is created, which is '123' .
130
460
C++: Wrapper is decayed, which is '460' .

也就是說,C++ 的 c'tor 與 d'tor 有被確實喚起。這樣說不定可以替 Ruby 實作出 d'tor...不過這是題外話。

另外,剛剛程式中的 fat.data 與 fat.data(456) 確實是喚起正確的 getter 與 setter, 可是 Ruby 沒有 overload? 我沒有實際去看,但我猜他內部大概是這樣實作的:
def data(*args)
case args.size
when 0 then return self.data_a
when 1 then return self.data_b(args[0])
end
end

所以如果你想要重新定義其中一個 overloaded method, 做不到…可能必須找到他實際的名字才有辦法。




那麼我們再來看到由 C++ 呼喚 Ruby... 否則不就太寂寞了嗎?基本上 Ruby 本身就提供了良好與 C 溝通的機制,照用不就好了?是這樣說沒錯,可是說真的我很討厭 C 的介面…囧rz
常常會要你記下一堆有的沒的,感覺很討厭。所以我覺得需要一個 C++ 的 wrapper, 一個可以輕鬆呼叫 Ruby 的方式。後來我找到這個:

http://www.sourcepole.com/sources/software/c++ruby/

不過這個東西實在是寫得不好,沒有處理 finalize 的部份。不知道還有沒有其他類似的 wrapper 可以用,所以我就暫時用這個來改。改寫他 singleton 的實作,還有記得在 d'tor 中呼叫 ruby_finalize();

最後的結果是,我可以這樣寫:
#include "rubyeval.h" // 就是上面抓來的那個
#include <ruby.h> // embedded ruby 必要的東西,去 ruby-lang 就可以抓

int main(){

RubyEval& ruby = RubyEval::instance();
ruby.eval("require 'Wrapper'"); // 直接用字串執行 Ruby
// 這邊是含入剛剛做好的 C++ => Ruby mod
// 當然這東西要先 compile 好

ruby.eval("fat = Wrapper::Integer.new(123)"); // 直接建立物件
std::cout << NUM2INT(ruby.eval("fat.data")) << std::endl; // 輸出 123

ruby.eval("fat.data(456);"); // 設值 456
std::cout << NUM2INT(ruby.eval("fat.data")) << std::endl; // 輸出 456

ruby.run_file("test.rb"); // 直接執行 ruby 程式
}

那個 test.rb, 就是上面寫好拿來測試 Ruby 呼叫 C++ 的程式。於是整個輸出結果就是:

C++: Wrapper is created, which is '123' .
123
456
C++: Wrapper is created, which is '123' .
130
460
C++: Wrapper is decayed, which is '460' .
C++: Wrapper is decayed, which is '456' .

第一行是從 C++ 建構的 Integer; 123, 456 則是 cout 輸出的。第四行的 123 則是 test.rb 產生 class Test < Wrapper::Integer 那個。130, 460 則是 Ruby 的 puts 產生出來的。

最後兩個 decayed 則是 Ruby 的 gc 正確在程式結束時摧毀物件輸出的順序剛好跟 c'tor 反過來,一切正常。




最後就來看怎麼實現這個的。Wrapper.i 是這樣寫的:

%module Wrapper

%{
#include "Wrapper.h"
%}

%include "Wrapper.h"
%template(Integer) Wrapper<int>;

這些語法請參考 SWIG 的網站,那邊都有詳細說明。甚至是 C++ 的多重繼承,在 Ruby 中也能使用。當然多少可能會有點限制,但似乎可以實現一定的功能。

下指令:
swig -c++ -ruby Wrapper.i
這樣就可以以 Wrapper.i 這個介面檔實作出由 Ruby 溝通 C++ 的程式。那個程式會叫做 Wrapper_wrap.cxx, 也就是 YOUR_NAME_wrap.cxx

再來就是將所有的程式打包成一個動態連結檔了,所有的檔案是:Wrapper.h (包含實作), Wrapper_wrap.cxx (SWIG 的膠水)。方便的做法是使用 Ruby 的 lib, 叫 mkmf
寫一個 Ruby 程式叫 mkmf.rb, 內容是:

require 'mkmf'
$libs = append_library($libs, "stdc++")
create_makefile(ARGV[0])

這邊是由於我個人方便,所以這樣寫的。第一行含入 mkmf, 第二行是因為我用到 C++ 標準函數庫(cout),所以必須連結 stdc++ 才行(我的系統是 GCC, VC++ 的話我不清楚)接著由 create_makefile 產生出我要的 makefile, 名稱由 cmd line 輸入。這邊我是輸入 Wrapper.(btw, 有人知道 stdc++ 可否動態連結嗎?)

接著就可以由 make 將 Wrapper.h 和 Wrapper_wrap.cxx 合併做出 Wrapper.so(我想 VC++ 系統應該會做出 Wrapper.dll 之類的)




最後要提的是,整個程式的執行環境。由於我是在 cygwin 下作業的,所以獨立執行這些程式需要的是:

cygwin1.dll 1.78 MB
cygruby18.dll 703 KB
cygcrypt-0.dll 6.5 KB

我想如果在 windows 下由 VC++ compile 的話,應該就只會需要 Ruby interpreter 的 dll 檔(這裡是 cygruby18.dll)。不過我就沒有做這一步的測試了,留給讀者當作練習吧 XD

(忽然心血來潮所以整理了這些東西)

2006.08.06 godfat 真常

延伸閱讀

3/17/2007

[ 工商服務 ] 和多設計工作室


Handlino 和多設計工作室是我大學同學 HLB跟朋友合開的工作室,他們不只有好設計,更有一流的 Ruby on Rails 技術。成員也都是開放原始碼界有頭有臉的人物,gugodhlblukhnos

根據他們的網頁,和多提供以下服務:

  • 網頁標準設計
  • Frontend engineering
  • 網頁應用程式開發,使用 Ruby on Rails 或 Perl
  • 桌面應用程式開發
  • 訓練與顧問服務
如果大家有興趣可以去他們網頁看看 : )

歡迎 GotFat 進駐本 Blog

GotFat 是 PTT Ruby 版版主,除了豐富的學識外,我發現他還有那一份「熱忱」,所以我邀請他加入本 Blog 的寫作作家之一。以後我還會慢慢邀請不同方面專長的作者進駐本 Blog,方向依舊是限定在 Ruby ,Ruby on Rails,Lighttpd,Javascript相關的議題上面。

各個作者的筆鋒陳述方式都可能不同,大家可能會有點不習慣,但是我相信每位作者的「熱忱」是絕對相同的。

3/16/2007

why scripting?

why scripting?

簡單一句話就是:「為了增進生產力」。不過這樣回答的話,就會衍生出另外一個問題:
「為什麼要增進生產力?」當然不是這個問題,這種問題根本沒有回答的必要。
這個問題是:「如何增進生產力?」

我們知道有一些狀況下,必須不斷修改程式,不管是因為現階段不知道最好的解決方式
是什麼,或是現況真的是會不斷改變。總而言之,我們必須「嘗試」而後「修改」。
這種時候,我們可以用需要 compile 而後 link 的程式語言(或是工作環境)嗎?

這篇影片道出了一些 "why": Better Web App Development
可以不用看沒關係,這邊會稍微提一下大概內容。簡單地說,GUI 的部份是最明顯的。
因為我們不知道我們的 user 會比較想要哪一種操作模式,甚至,連他們自己也不清楚。
這種事說來很不可思議,但實際上就是如此。很多事情是很難預測的。或是該說,
要正確地預測事情的成本,遠遠高於直接試試看,再從中獲取經驗,進而修改以符合
我們的希望。所以我們需要的是「能夠快速修改、變化」的程式語言(或是工作環境)。

scripting 就是為此而誕生的。他們的立意和 system programming 有著根本上的不同,
所以無須拿此二者來比較。這一篇並不是想探討此二者間的異同,所以不會再對此著墨。
這裡直接假設兩者同等重要,以此討論兩者之間該如何取得平衡。

*

事實上,越是前端的程式,越是需要此種「變化」的特性。因為 system programming
是面對機器,而機器可不會跟你鬧脾氣。(如果不明原因的當機不算的話…)
但是 scripting 通常是面對人,而人可是可以陰晴不定,今天好好的明天就跟你翻臉,
或是嘴巴說不要,身體倒是挺誠實的,諸如此類的問題可多著。
為了「適應」人的這種「特性」,我們也需要一個擅長「變化」的東西,
以此銜接 system, application, 與人類。

除此之外,大家也都知道 scripting 的執行效率一定遠遠不如 binary program,
在大部份的情況下,這不是個問題。因為現在的電腦已經快到一種很恐怖的境界了,
真的非常需要執行效能的狀況,其實很少。更何況大家都知道 80-20(1) 法則,效能的
重要性只會隨著時間越來越減少,但永遠不會消失,因為人的慾望是無窮的…。

*

舉遊戲程式為例。一般比較大型的遊戲程式,大抵上都會切成三個部份。第一個是
廣為人知的 engine, 這邊的執行效能是非常 critical 的。第二部份是遊戲主程式,
這部份一般而言,效能也是非常重要的,所以還是會以 C++ 來完成。但是有些東西,
卻不得不引入 scripting, 儘管執行效能可能會是個問題,但還是不得不引入。
這就是第三個部份,掌控一些最細微的遊戲設定,也是跟「人」最有關係的部份。

為何這部份需要引入 scripting? 最簡單的例子就是平衡度設定。Dragon 是否太強?
Drawf 是否太弱?Golem 需不需要再多加個 Trample 的能力?Ranger 的 favored enemy
是否該換成 Goblin? 諸如此類,不是一開始就能確定,你一定得「玩一玩」才有可能
知道的麻煩事。甚至,必須讓成千成萬個玩家去玩過,才會知道的,很隱晦的事。
在複雜系統之下,這種碰過才知道的事,是非常多的。但是我們可不能稍微修改一下,
重新 compile, link, 泡杯咖啡。接著測試兩分鐘,啊,不行,這個數字應該再減少一個
單位。重複上面發生的事。這樣別說效率很差了,耐心都被磨光了。有些時候,士氣其實
是遠遠重要於產出的程式,像這種極度消磨耐心的事,再怎麼樣都是不能出現的。

引入 scripting 的好處就在這裡,我們可以輕易地修改程式,接著直接重新啟動遊戲
即可。更有甚者,直接叫你的遊戲重讀 script 檔即可,連重新啟動遊戲都不必。
不過就像我上面說的,基本上遊戲是個幾乎每一處都很 critical 的程式,所以
scripting 也要越快越好。最常被選用的就是 Lua, 因為他真的很快。不過啊,個人是
不太喜歡使用 Lua, 因為他和 C++ 間的連接不是那麼地良好,怎麼說,有點詭異…。

第二個最常被使用的,可能是 Python. 這是個相當不錯的程式語言,boost 也有一整份
Python 的 binding library. 不過我個人還是比較偏好 Ruby 一點,Ruby 是目前為止
我看過我覺得最好的 scripting language, 原因很多,但主要可能是因為他對物件導向
的支援非常完善,而物件導向在遊戲裡,是個幾乎可以說不能沒有的東西。光 GUI 就
非常仰賴物件導向了,更何況 GUI 只是遊戲的一部分。這部份可以很複雜,也可以很
單純。但不管怎麼樣,物件導向都太重要了。

*

所以事實上,我是很希望遊戲程式可以引入 Ruby, 雖然 Ruby 的執行效能比較差,
但應該好用的東西就應該好用到底,應該跑得快的東西就應該快到底,我是這樣認為的。
Python 被用很多,但我相信 Ruby 也會越來越重要。最近也確實如雨後春筍一般,
四處都出現其應用,不是嗎? :p

boost 沒有提供 Ruby binding 是有點可惜,我想這是因為 Ruby 的熱門是最近幾年的
事。不過呢,SWIG 還是有提供 Ruby 的 binding! 而且也是相當完整的支援。
何不就來試試 C++ 透過 SWIG 與 Ruby 溝通的方式呢? :p
欲知詳情,請待下回分曉。

2007.03.16 godfat 真常

p.s. 為何遊戲一定要用 C++? 這…不在本篇討論範圍裡 :o

(1) 一個程式只有 20% 的部份會佔去 80% 的執行效率。或是各種類似說法。

為啥我得升級 Ruby 1.8.6

為什麼我得升級 Ruby 1.8.6?會跟 Rails 衝突,還得一定要升到 Rails 1.2.3 才能夠跑 Rails。那麼麻煩的 Ruby 版本,為啥我一定要升級?我給你一個原因
Ruby 1.8.6 已經將 FastThread包進去了
也就是說灌 Mongrel 應該不用加裝 FastThread 了。我們可以合理推測 Ruby Native 支援總比 Gem 支援來的好不是嗎 :p

還有一點,隨著 Ruby 1.8.6 的推出,看來下一版的 Mongrel 除了 fastThread,也不用裝 cgi_multipart_eof_fix 了。 Ruby 的整合度越高,狗皮膏藥越來越少總是一件好事。

樂天將採用 Ruby on Rails


日本樂天公司在 3/15 宣佈採用 Ruby on Rails ,他們將在大規模交易處理及安全性處理相關服務使用 Ruby on Rails。


說到日本樂天,來頭也真的不小,Alexa 可是排行 76名的很角色。樂天一向是 Linux,PHP,MySQL 支持者,他們已經使用超過一百台 PHP Application Server,超過一億筆 MySQL 資料。而這次轉向 Ruby on Rails,也是得到 Matz 所處的網路應用通信研究所的技術協助。報導中技術協助包括訓練課程, 以及使用他們所開發的 Rails Platform。Ruby on Rails 真的是越來越多公司開始漸漸採用了。

本篇圖片版權來自樂天市場,翻譯參考自 PTT 的 ericyu。







3/15/2007

守護樂生

右邊這張貼紙會放到這件事情有結果為止,謹此聊表心意。

在 Rails 之外使用 ActiveRecord

今天要寫一個 cron script 要用到資料庫,因為已經被 Active Record 慣壞了,懶得用 SQL。所以就花點時間 Survey 怎麼再 Rails 之外使用 Active Record。


簡單版

1. require 相關的 lib

require "rubygems"
require "active_record"

2. 建立 DB Connection

ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:username => "root",
:host => "localhost",
:password => "secret",
:database => "plants_db"
)

3. 宣告 ActiveRecord Class

class MyClass < ActiveRecord::Base
end


如此就可以開始使用啦。不過如果遇到你必須一次操作多個 DB 的情況時,你可以用比較 Rails 一點的 Config 來寫作

加入 Config 的用法

1. require 相關的 lib

require "rubygems"
require  "active_record"



2. 撰寫 DB 設定檔 ,我們仿 Rails 寫一個 database.yml

development:
__adapter: mysql
__host: localhost
__username: root
__password:
__database: lala



3. 將設定檔讀進來,讀到一個 $config 變數

$config = YAML.load_file(File.join(File.dirname(__FILE__), 'database.yml'))



4. 宣告 ActiveRecord 物件,記得加上 establish_connection

class MyClass < ActiveRecord::Base
establish_connection $config[''development"]
end


5. 開始快快樂樂使用 ActiveRecord 吧

3/13/2007

Ruby 1.8.6 Release:要升級請三思

Ruby 1.8.6 Release了,想看詳細情形,或是下載 Source 請看這裡。根據 fixneo 先生的提醒,我花了時間去找了一下 Bug Report ,發現到這篇文章。裡面寫到 Time.to_date 跟 MD5.new 會出現問題。不過這些 Bug 會在 Rails 1.2.3 做修正,也就是應該是 Rails 的問題?

隔天早上,Rails Team 也立刻發表了 Rails 1.2.3,所以要升級 Ruby 1.8.6也請順便升級 Rails 1.2.3。

3/11/2007

Rails 當中使用 Google Map:YM4R


最近發現 Google Map 很好玩,想要玩玩 Ruby on Rails 上面的 Google Map,就找上了 YM4R 這個 Rails Plugin,發現 YM4R 使用 Google Map真是方便呀,彈指之間搞定。YM4R 這個 Plugin 就是讓Ruby on Rails 上面使用 Yahoo Map 跟 Google Map 的 Rails Plugin。以下介紹一下這個 YM4R 怎麼使用。


安裝:

ruby script/plugin install svn://rubyforge.org/var/svn/ym4r/Plugins/GM/trunk/ym4r_gm


這個動作會把相關的 file copy 到 config,vendor/plugins, public/javascripts 裡面去,如此就把這個 YM4Rplugin 裝完了。

使用:
要使用這個 plugin 一共分成 controller 跟 view 兩個部份。

Controller:

在 controller 裡面加入底下的 code ,底下的 code 是改自這個網頁,他會 initial 一個 Gmap Object,顯示我們指定的位址。我們這裡舉台北為例子,台北的經緯度根據 Wikipedia ,為東經121.6度,北緯24.9度,放大的程度為 7,並且有一個 info_windows。
latitude = '24.9'
longitude = '121.6'
@map = GMap.new("map_div_id")
@map.control_init(:large_map => true, :map_type => true)
@map.center_zoom_init([latitude,longitude], 7)

marker = GMarker.new([latitude, longitude],
:title => "台北", :info_window => "我在台北呦~")
@map.overlay_init(marker)

View :

Google Map 使用方式都是 Javascript。要在 Ruby on Rails View 裡面使用方式,分成兩個步驟,第一個是在 head 裡面加入相關的 Javascript
<%= GMap.header %>

第二個就是在 Body 裡面,顯示剛剛在 controller 裡面設定完成的 @map 變數,這裡寬跟高都設定 600
<%= @map.to_html %>
<%= @map.div(:width => 600, :height => 600) %>


啟動:

請打入 http://localhost:3000/controller_name/ 就可以看到台北的 Google Map 了

等等,我都沒看到 Google API Key ?

是的,我們上面的例子都不用設定 Google API Key 的原因,是因為我們使用的 Domain 是 http://localhost:3000/ ,而這個 Plugin 已經預設裝入 http://localhost:3000/ 的 Google API Key 。

如果你想設定你的 Domain ,請到 config/gmaps_api_key.yml 裡面設定,請將你申請的 Google API Key ,放入 production 設定底下。話說,我不知道為啥我明明跑的是 development mode,但是將申請好的 API Key 放在 development 底下他不 work,反正似乎只能放在 production mode 才可以 work。

延伸閱讀:
  1. Rails Google Maps Plugin 教學
  2. YM4R Project Hompage

2007 年你一定得了解的科技:Ruby on Rails

Computer World 發表了 2007年你一定得了解的五大科技,第一名就是 Ruby on Rails。原因是因為 Faster, easier Web development。其他入選者是這樣的



Five Hot Technologies for 2007


1. Ruby on Rails
Faster, easier Web development

2. NAND drives
Bye-bye, HDD?

3. Ultra-Wideband
200x personal-area networking

4. Hosted hardware
Supercomputing for the masses

5. Advanced CPU architectures
Penryn, Fusion and more

3/09/2007

RedMine:專案管理系統


Trac 真是一個好東西,但是雖然違反重新造輪子的守則,但是因為 Ruby 社群有一種詭異的執念,RedMine 出現了。RedMine 是一個 Open Source 的 Project Management System,是用 Ruby and Ruby on Rails 寫的,GPL License,Code 同步是用 Subversion。可說是相當不錯的 Project Management 系統。

主要賣點是一個字「多」,多 DB,多國語言,多人管理,可管理多個 project,還有漂亮的甘特圖。



就算扣除掉 Ruby on Rails 的情感優勢,依照目前所發表的功能,我還是覺得似乎可以一用。因為 Trac 對我最大的不便是,Trac 我還是不太會安裝呀。

不過也有缺點,缺乏 Time tracking,Per project wiki 實在是有點掃興,不過依舊很值得一用。

RadRails 即將納入 Aptana 的控制下


RadRails 這個最早出現的 Open Source Rails IDE ,最近宣佈他們即將把控制權交給 Aptana 這個 Project。



Aptana 是一個 Eclipse Based 的 HTML,CSS,Javscript IDE,加入了 RadRails 也代表著除了 Aptana 原本強項的 HTML/CSS/JS編輯外,也一定會納入 Ruby on Rails 整合。


RadRails 官方早在幾天前就發表他們需要更多人手支援,並且他們不能夠再 Full Time OpenSource 下去了。也該是想想 RadRails 的未來怎麼走更好的時候了。
The bottom line to all of this is that Matt and I can't provide the same kind of commitment that we once could. Like or not, RadRails is not a business. We've been working our asses off on a startup for the past few months and RadRails has suffered as a result. I wish things were different and we could sit back and work on open source all day but that is just not the reality anymore.
幾天後,他們選擇面對問題的存在,閃電的宣佈兩者合併
I chose to come out and face our problems head on rather than hide from the obvious.

RadRails 雖然讓出了控制權,但是 RadRails 帶給我們的,卻是一連串的 Free Solution,包含 NetBeans,IntelliJ。
We've set a trend for Rails specific tooling that can now be seen in other IDEs such as Netbeans and IntelliJ. In many ways we've accomplished what we initially set out to do and 18 months later there is not just one Rails IDE, but close to a dozen free solutions.

不管如何,RadRails,Aptana 都是 Eclipse Base 的 IDE,也都是 EPL License,相互整合可說是沒有太多問題。Aptana 官方也馬上宣佈很快的就會有 Boundle 出現,並且 Aptana Team 的目標就是將兩者最初更加緊密的整合。
Initially, you’ll see some immediate bundling of the products, and then we’ll work on making a tighter integration as time goes on.
我對這件事情是抱持著相當正面的態度,Aptana 的 View 端 IDE 加上 RadRails 對於 Ruby on Rails 能力,相信可以做出相當不錯的 IDE Solution。

學習 Ruby on Rails 要看的書

Robbin 提出了一篇 RoR学习书籍推荐,裡面介紹學習 Ruby on Rails 要看的書,一共有三本。令人意外的,沒有 Programming Ruby。但是,這個想法跟我不謀而合。所以我也寫一篇學習 Ruby on Rails 要看的書,並且講解一下我的理由。注意,此學習歷程僅供「沒學過 Ruby 還有 Ruby on Rails ,但是想學習 Ruby on Rails 快速開發」的人參考,如果你沒了解這個前提代表的意思,這篇對你沒有參考價值。



當你什麼都不懂的時候,但是又想要立刻上手


請看 Agile Web Development with Rails 第二版,這本書是學習 Ruby on Rails 的第一本書,程度由淺入深,當初我一開始把 Tutorial 看完就可以直接來寫專案了。但是當你越來越熟練的時候,你還是少不了他,裡面有很多網頁開發的正確觀念值得一看再看,相當值得收藏。這裡有我第一版的書評

當你已經稍微了解 Rails ,但是想花時間了解 Ruby

Agile Web Development with Rails 是一本很難得的好書,但是他是專門介紹 Rails 的書,而非 Ruby 的書。當你看完第一本書的時候,你會發現到一件事情
我對 Rails 已經算熟了,但是 Ruby 的一些語法我只會常用的,我對 Ruby 不算熟怎麼辦?
所以在此我推薦 Ruby For Rails,這本書講解的是 Ruby ,但是他只限定在跟 Rails 有關的 Ruby ,你在裡面可以學到所有 Rails 用的到的 Ruby 語法,並且解釋的相當清楚(好啦,有些人覺得太過繁瑣),有了這本書,你可以很清楚的學習 Rails 用的上的 Ruby 語法。

我在工作上,有一些 Rails 上面的小問題,像是如何讓 Active Record 使用多個 database ,如何在 Active Record 跟自己建立 self relationship,該怎麼辦

為您推薦 Rails Recipes,這裡有許許多多的 Rails Tips,當你在工作時遇到一些小問題,在聖經本找不到解答時,可以考慮翻翻這本書,很多時候你會發現你所遇到的問題,其實大家都有遇到,而且在這本書可以找到很好的解法。

等等,那 Programming Ruby 呢?

是的, Programming Ruby 是一本學習 Ruby 的聖經,讀完他幾乎等於你已經對於 Ruby 的全貌有了相當好的了解了,並且這本書的編排很好,很容易一讀再讀愛不釋手。但是你要注意到一件事情,「Ruby on Rails 只用了一半左右的 Ruby」,Rails 是 Ruby 的好夥伴,但並不代表 Rails == Ruby 。

我這篇的前提是「沒學過 Ruby 還有 Ruby on Rails ,但是想學習 Ruby on Rails 快速開發」,當你對於 Ruby 沒興趣,但是對於 Rails 很有興趣,如果你的目的是真的只學習 Ruby on Rails,那你真的可以跳過這本書。但是如果你覺得 Ruby 很有趣,你一定得看這本書才能知道 Ruby 的美麗。

如果你還是質疑我的講法,我問你,Thinking in Java 是學習 Java 的聖經,但是你把這本書翻爛了,對於學習 Hibernate 這個 Java Framework有沒有太多幫助?

結論

很多人都推薦 Agile Web Development with Rails 跟 Programming Ruby 是學習 Rails 的必讀的書。但是,我認為
Agile Web Development with Rails -> Ruby for Rails -> Rails Recipes
才是學會 Ruby on Rails 最快的捷徑。至於 Programming Ruby ,這是精通 Ruby 必經的道路。

你,了解這兩者的差別嗎?

3/07/2007

Ruby on Rails Security Blog:讓你的 Rails 更安全


Ruby on Rails Security Blog 是一個新成立的 Blog,講解 Ruby on Rails 跟 他的搭配套件的安全性的 Blog,這也是 Ruby on Rails 一直被大家所另外質疑的部份,希望能夠喚起更多的 Security 常識。不過現在為止,都是在講 MySQL 的 security 的部份呀。

TIOBE 3月排行:Ruby 略有小進,Javascript 大跳躍

這個月 TIOBE 出來了,上個月我說
附帶一題,我看好 Ruby 跟 Javascript 會有繼續維持成長的動力,Python 保持平盤,Perl 跟 PHP 會保持緩慢下滑的態勢。不過這幾者之間的排行應該短期內不會有大幅度的變動。
看來馬上打槍了,Ruby 小幅上升了 0.245,Javascript 就很了不起,直接幹掉 C#,上升了 0.503。本來想說 Ruby 會先幹掉 Javascript 往上爬,結果卻發現 Javascript 成長的動力越來越強,看來 Ruby 得先幹掉 C# 了。



Position
Mar 2007
Programming
Language
Ratings
Mar 2007
1 Java 18.044%
2 C 15.633%
3 C++ 11.109%
4 PHP 9.458%
5 (Visual) Basic 8.147%
6 Perl 6.420%
7 Python 3.897%
8 JavaScript 3.485%
9 C# 3.365%
10 Ruby 2.773%

Lighttpd 佔有率暴漲

Lighttpd 佔有率這個月突然暴漲,在Netcraft二月的時候佔有率是第六名,數量是 702712。這個月突然 Double 起來,數量是 1399786,佔有率是第五名。目前輸給 Apache,IIS,SUN-One-Web-Server ,當然還有一個 Unknown。以這個上漲聲勢來看,有機會成為 Apache,IIS 以下第三大 Web Server。


JRuby 0.9.8 發佈,支援Ruby on Rails

JRuby Team 已經宣佈了 0.9.8 的版本,這個版本最大的差別在於他們終於宣告了 JRuby  Ruby on Rails 的 Support。在這個版本裡面,將近 98% test case 都已經成功執行,預計在 1.0 版本時可以完全 Support Ruby on Rails。並且JRuby 0.9.8 也加強了一些 IO Bottleneck 的部份的速度,在某些 test case  IO 大概快了 6.5 倍的速度。



到目前為止,我想 Ruby 上面 VM 的最佳解已經快要確定是 JRuby 了,擁有 JVM 的可擴充性,Ruby on Rails Support,SUN 的金錢支援。現在雖然速度輸給了 YARV,但是這只是因為 JRuby Team 目前的目標是100%支援 Ruby on Rails 而已,如果他們已經支援完成,開始注意效率的問題,我想這點差距以 JRuby Team 的活躍度,跟加入 SUN 之後的神秘的醍醐灌頂,YARV 簡直是秒殺的份。

我時候我分不清到底開放原始碼的進步動力,到底是來自於社群的力量好一些呢?還是商業力量好一些?在 JRuby 這個案例裡面,似乎很明顯的看出自從商業力量加入 JRuby Team 之後,他的捷報頻傳,不管是在 Performance 或是 支援度上面明顯腳步快了很多。以前是用走的,加入了 SUN 之後是用飛的。果然熱血只能一時,金錢才是最大動力。

不過話又說回來,如果一開始沒有社群的力量去支撐 Ruby and Ruby on Rails,我想 SUN 不可能投入 Ruby 這條路吧。社群的力量當作開始,而商業力量協助壯大,這才是開放原始碼的成功道路。



3/05/2007

Windows 上面 IDE 的選擇

Robbin 又有新的力作了,這次是 Windows平台的ruby IDE 点评。這文章裡面對於 Windows 上面所有 IDE 做了一個評選,可惜少了 Ruby in Steel。對於不用 IDE 的我來說,這是我寫不出來的文章。

本文我會列出 Windows 上面各個流派 IDE 的 Ruby 選擇,並且會列出 Robbin 對於 IDE 的觀點給大家當個參考。

流派列表:
在 Robbin 的選擇

目前最推薦的 IDE 還是 RadRails,這個改自 Eclipse 的 IDE 贏在 Bug 少,功能齊全。缺點在於 RDT 過於差勁。不過最近 RDT 會出 0.9 ,希望能夠改進這方面的缺失。

NetBeans 是最受期待的 IDE ,最大的原因在於 SUN 對於 jRuby 的大力支援。Netbeans 6.0 提供了 Generic Language Support Framework,對於 Ruby and Ruby on Rails 支援不錯。雖然有些小問題,不過 2007年年底 Netbeans 會出 6.0 正式版,相信會對 Ruby 支援大大加強。

最受期待的輕量級 IDE 是 E 。這是一個 Windows 上面的 textmate 的 clone。喜歡 textmate 卻又不希望買 MAC 的人可以試試看這個。