用Sinatra編寫博客應用

來源: InfoQ  發布時間: 2011-01-27 10:21  閱讀: 2084 次  推薦: 0   原文鏈接   [收藏]  
摘要:關于作者:吳江,Ruby和Javascript程序員。從09年開始,在國內社區中積極宣傳和推廣Sinatra。10年8月底,以演講者的身份參加了在日本舉行的RubKaigi。現在上海一家Ruby行業的咨詢公司工作。

  Sinatra是Blake Mizerany在2007年9月開發的Ruby語言的Web框架。它最突出的特點就是輕量、快速。更難能可貴的是,Sinatra的源代碼只有一千多行。

  在第一次接觸到Sinatra的時候,我便被它深深地吸引住了。隨后,我在09年3月的Shanghai on Rails活動向大家介紹了這個框架。10年8月份我有幸可以在RubyKaigi這樣的全球級Ruby社區會議上作為演講者和聽眾交流Sinatra。本文則是對10年10月份在上海Linux用戶組介紹Sinatra的講座的一些整理和總結。希望讀者能夠通過本例子能體會到Sinatra的精妙之處。

  最新版本: 1.1

  截止到本文成文為止,Sinatra最新的版本是10年10月24日發布的1.1版本。很幸運的是,我對于README的翻譯正好在發布的前一天被合并進入了主分支。于是在1.1的正式版本中,中文的讀者可以直接閱讀到中文的README,從而更好的了解Sinatra的用法。官網上也有此文檔的鏈接,http://www.sinatrarb.com/intro-zh.html。本文的代碼全部以1.1版本為準。

  Sinatra的基本結構

  讓我們從Sinatra最常見的Hello world程序開始:

 
get '/' { "Hello, world!" }

  這段簡單的Hello world程序包含了Sinatra程序的三個基本組成部分:

  • 路由(route):

    '/' 就是路由。路由可以是單一的路徑,或者帶有參數的路徑(比如 /:name),甚至是正則表達式。對于Sinatra不知道的路由,Sinatra會返回404錯誤(作為App運行的時候),或者傳遞給下面的中間件(作為中間件運行的時候)。

  • 方法(method):

    get是方法。在Sinatra中,HTTP的四個方法GET/POST/PUT/DELETE都有相應的方法get/post/put/delete

  • 處理器(handler):

    處理器就是最后的代碼塊,處理器的返回值就是Sinatra返回給客戶端(主要是瀏覽器)的內容。返回值主要以字符串為主,也可以是包含狀態碼,消息頭,消息體的數組。

  渲染模版

  Sinatra支持的模版類型也在逐漸增加中。Haml是筆者常用的格式,因為它使用了CSS選擇符構造HTML標簽,從而節省編寫時間。另一種常見的格式是Ruby自帶的ERB,本例子將使用Haml作為博客的模版。

  渲染模版在Sinatra中是很容易的事:

 
get '/' do
haml :index
end

  在這里haml :index,就表示使用Haml渲染'views/index.haml'這個模版。

  傳遞參數也是很容易的事,可以使用實例變量:

 
# in app.rb
get
'/' do
@now = Time.now
haml :index
end
# in views
/index.haml
Hello, now is #{@now}

  或者用locals傳遞參數(如例子中的哈希):

 
# in app.rb
get
'/' do
now = Time.now
haml :index, :locals
= { :now = now }
end
# in views
/index.haml
Hello, now is #{now}

  熟悉了路由和模版,就可以開始構建Web應用程序了,Sinatra也提供了一些簡單的輔助方法,比如過濾器、helpersconfigurehaltpass等等,這些就不再這里一一敘述了,更多的內容請仔細參考官方文檔。

  開始博客應用

  文件格式

  本博客應用將使用dorothy格式的文件存儲,不會使用數據庫。

  例子如下:

 
# 文件名: 2010-10-10-a-lucky-day.txt
title:
"A Lucky Day"
date: 2010-10-10
author: "吳江"

# 今天是我的幸運日

早上在地鐵門將要關上的那一刻,我沖進了車廂,于是約會沒有遲到...

中午提前了一點去港麗,居然只排了42分鐘...

晚上又趕上了末班車...

到家數了數,錢包里面正好有42塊錢...

  該文件的結構是:以第一個連續換行符("\n\n")為界線,前一半是YAML格式的配置信息,后一半則是markdown格式的文本。YAML格式是一種表示數據的標記語言。這里只使用到它的鍵值對結構。markdown則是很方便的用純文本編寫HTML的格式。比如"# header1"會生成"h1header1/h1""*emphasis*"會生成"ememphasis/em"等等。

  安裝環境

  本博客應用使用Ruby 1.8.7版本。安裝好后,首先安裝Bundler(gem install bundler),然后編寫Gemfile(見下),運行bundle install即可一次性安裝好所需的gems。

 
# Gemfile
source
"http://rubygems.org"
gem 'haml' # Haml模版
gem
'rdiscount' # 渲染Markdown
gem
'sinatra' # Sinatra
gem
'thin' # 應用服務器
gem
'shotgun' # 重啟服務器
group :test
do
gem 'rspec' # 單元測試
gem
'nokogiri' # 解析HTML輸出
end

  測試驅動開發

  使用測試驅動開發并非為了趕時髦,只是為了能夠幫助我們寫出更好的代碼。

  在本例子中,我們的測試需要能夠達到以下目標:

  1. 訪問"/"的時候能夠正確返回文章列表(雖然只有一篇文章)

  2. 訪問"/:year/:month/:date/:title"的時候能夠正確地展示文章內容

  正式編寫

  在本例子中,將只接受兩個路由請求,'/''/:year/:month/:date/:title'

  首先編寫如下的測試:

 
# in app_spec.rb
describe
'blog' do
before do
@req = MockRequest.new(Sinatra::Application)
end

it
"should show index correctly" do
resp = @req.get '/'
resp.status.should == 200
end
end

  運行rspec app_spec.rb可以看到失敗結果。先編寫簡單的代碼讓測試通過。

 
# in app.rb
get
'/' do
""
end

  然后繼續增加測試,我們想讓返回的頁面中有鏈接到/2010/10/10/a-lucky-day這個日志的鏈接

 
# in app_spec.rb
...
it
"should show index correctly" do
resp = @req.get '/'
resp.status.should == 200

doc = Nokogiri.new(resp)
(doc
/'a[href="/2010/10/10/a-lucky-day"]').text.should == "A Lucky Day"
end

  為了通過這個測試則要寫一些長一點的代碼,為了省略篇幅,Article類的代碼在這里忽略:

 
# in app.rb
get
'/' do
@articles = []
Dir.glob(
"articles/*.txt").each do |article_file|
@articles Article.new(article_file)
end
haml :index
end

  在上文的代碼中,首先讀取了articles目錄下的所有txt后綴的文件,就是全部的日志。 并把這些日志裝到@articles這個數組類型的實例變量。

  在視圖中,則簡單的把日期和日志名稱羅列出來。

 
# in views/index.haml
...

- @articles.each do |article|
%header
%h2
= article.date.strftime("%Y年%m月%d日")
%a{ :href = article.path }= article.title

  接下來使用同樣的方式來編寫顯示日志具體內容的代碼:

 
it "should show article correctly" do
resp = @req.get '/2010/10/10/a-lucky-day'
resp.status.should == 200
doc = Nokogiri(resp.body)
(doc
/'title').text.should == "A Lucky Day"
(doc/'article h1').text.should == "今天是我的幸運日"
resp.body.should match "錢包里面正好有42塊錢"
end

  實現所用的代碼相對會少一些:

 
# in app.rb
get
'/:year/:month/:day/:title' do |year, month, day, title|
article_file = "articles/#{year}-#{month}-#{day}-#{title}.txt"
@article = Article.new(article_file)
haml :show
end

# in views
/show.haml
!!!
%html
%head
%title= @article.title
%body
%header
%h1
= @article.title
%article= @article.body

  測試通過以后,也可以使用shotgun app.rb -s thin開啟服務器, 訪問http://localhost:9393就可以看到在瀏覽器中的效果。

  部署

  Heroku是目前為止最好用的Ruby應用部署服務之一。在Heroku的幫助下,我們可以快速地把這個應用發布給全世界使用。

  首先編寫config.ru

 
# in config.ru
run Sinatra::Application

  然后運行如下代碼:

 
# git初始化
git init .
git commit
-a -m "Initial Commit"

# heroku 部署
heroku create
git push heroku master

  當看到"Launching ... done"的字樣的時候,就說明我們的程序部署成功了,趕快點擊下面的鏈接看看結果吧!

  評論

  Disqus是目前我知道的最好用的評論管理系統。更要命的是,它能夠很簡單的把一個評論系統加到我們的博客中:

 
section class="comments"
script type="text/javascript" src="http://disqus.com/forums/#{username}/embed.js"
/section

  只要把上面這段html代碼加入到我們的系統中,一個完善的評論系統就出現在用戶的眼前。本地調試的時候則要額外加上一句:

 
script type="text/javascript"var disqus_developer = 1;/script

  借助了Disqus,我們的評論系統就不會遜色于任何的博客應用。

  思考

  如果讀者能夠在整個過程中感受到快樂或者驚奇,那么我編寫本文章的目的就算達到了。 詳細的代碼請參考本文的項目地址:https://github.com/nouse/text-blog

  以下則為筆者在制作這個應用過程之中的一些思考。

  5年前,Rails的創造者David Heinemeier Hansson向全世界介紹了15分鐘編寫 blog應用。在5年后,我們又用Sinatra重復造輪子,如果讀者對比兩者的差別, 就能深刻感覺到這5年里Ruby世界的一些變化。

  基本工具(RVM和Bundler)

  這5年間,Ruby基本工具有了很大的發展。這其中最大的亮點就是RVM(Ruby Version Manager)。 除了如它的名字所述,可以幫助開發人員安裝不同版本的Ruby以外。它的gemset功能也非常 好用。不同的gemset之間是一個個獨立的環境,從而避免同一個gem的不同版本之間的干擾。

  如果在項目目錄下添加.rvmrc(rvm use version@gemset),就可以讓項目處于一個獨立的環境之中。 再編寫好Gemfile,將項目中需要的Ruby庫全部交給Bundler管理, 就不會出現部署的時候缺乏相應的庫導致失敗的情況了。

  方便的部署

  Git的普及和Heroku的崛起,大大簡化了部署的過程。如果5年前有Heroku的話, DHH的博客應用可以有更大的反響。編寫完成--git push--上線!。 一個博客應用就一瞬間仿佛活了一樣,從一個本地的演示項目變成了一個真正的線上應用。

  Disqus等第三方應用的興起

  5年前,Web 2.0剛剛興起,只要編寫一個使用Ajax增強交互功能的應用, 就可以吸引用戶的眼球。但是隨著Web 2.0的概念深入人心,做一個blog顯然不再能吸引用戶的眼球了。

  如果Disqus這樣的第三方應用能夠逐漸增多,那么我們就能夠把更多的時間放在我們真正想實現的功能上。 就像這里,我們只要把博客的內容展示做好就夠了,其他的則交給成熟的服務來處理。 Rails的成功就在于簡化了開發Web 2.0應用的時間。借用一下jQuery的口號write less, do more, 寫的更少,做的更多是軟件開發永遠的主題。

  Sinatra和Rails的關系

  DHH在推出Rails的時候,讓深陷于Java世界的開發人員看到了希望,Rails也借助Web 2.0的熱潮迅速走紅。 其實,筆者所做的演示的功能模仿的是一個Rack應用程序,toto。 所以讀者們也不必迷信,用Sinatra經過15分鐘能做出更好的博客應用,就說明Sinatra會取代Rails。

  當前最流行的方式是融合,比如gemcutter.org,也就是現在的rubygems.org。 他們整個站點使用的是Rails 3,而客戶下載gem的請求則是被Sinatra處理。 這樣就可以保證網站在升級的時候不會影響下載gem的請求,而且Sinatra處理請求的速度也優于Rails 3, 用來處理每天超過訪問網站數倍的下載請求也十分合適。

  不管怎樣,只有更多的了解一個框架的優缺點,才能在真正使用的時候做出正確的選擇。而Sinatra的源代碼只有一千行,要了解它并做出選擇,相信不是件難事。

0
0
 
 
 

文章列表

全站熱搜
創作者介紹
創作者 大師兄 的頭像
大師兄

IT工程師數位筆記本

大師兄 發表在 痞客邦 留言(0) 人氣()