顯示具有 gem 標籤的文章。 顯示所有文章
顯示具有 gem 標籤的文章。 顯示所有文章

1/07/2008

ludy 0.0.9 released

其實後來的更新幾乎都是亂寫了,這次的更新也差不了太多。大抵上就是增加個 C++ TR1 style 的 bind... 用起來的味道大概是這樣:(如果熟 C++ TR1/boost bind 的話,一眼就知道了)

assert_equal [9,8,7], ([1,2,3].map &(lambda{|lhs, rhs| lhs-rhs}.bind 10, :_1))
assert_equal [3,2,1], (lambda{|a,b,c| [a,b,c]}.bind :_3, :_2, :_1)[1,2,3]
assert_equal [1,9,3], (lambda{|a,b,c| [a,b,c]}.bind :_1, 9, :_3)[1,2,3]
assert_equal [9,2,3], (lambda{|a,b,c| [a,b,c]}.bind 9)[2,3]
assert_equal [9,4,2], (lambda{|a,b,c| [a,b,c]}.bind 9, :_3)[2,3,4]

不過我總覺得 ludy 應該可以繼續走下去才對。所以我想在下次做一次 major update, 版本號大概就是 0.1.0 吧。會做的改變大概如下:

1. 整理 project directory structure, 現在根本就是亂七八糟。我想大概會用 gem bones 去做吧。其實我是比較 prefer hoe, 但是 bones 的 rake task 有 namespace 比較漂亮... 如果 hoe 會更新到使用 namespace 的話,我再 switch 過去。現階段,我想 bones 是個不錯的選擇。

使用這種東西的好處,當然就是不用去設計 directory structure... 而且自己寫 gemspec 老實說也真的是滿麻煩的,bones 和 hoe 都有 rake task 幫我 build gem 檔,甚至還有 publish, 多方便。

2. 思索 puzzle_generator 的未來。其實他跟 ludy 一點關係都沒有,只是我為了使用 svn server 所以才把他加到 ludy 上的。到底 puzzle_generator 應該分出來,還是在 ludy 中找到一個位子?分出來的話,又該分去哪裡?

3. ruby 1.9 compatibility, 我剛剛稍微測試了一下,有幾個比較髒的東西在 ruby 1.9 是跑不起來的。這個應該要想辦法修掉,ruby 1.9 很棒的。除了效能好很多以外,多了很多我想要很久的功能,能早點轉過去就早點。可惜的是 1.9 問題還很多,而且很多 gem 沒辦法在上面跑,所以 1.8 還是必備的。現階段會讓 1.8 和 1.9 都相容,等 1.9 夠穩了,就不會考慮支援 1.8 了。

4. require path 的麻煩問題。去看看 facets, 他們對於 require path 大概也很頭痛吧。從 2.0.0 就整個把 require path 翻修過,結果還有大 bug, 害我完全沒辦法用。果然很快就推出 2.0.1 了...。還是 2.0.1 ~ 2.0.2 的階段,我忘了。反正就是很可笑的狀況,名稱衝突之類的。bug 期間我是暫時 monkey patch.

再看看 rubygems, 一開始有個 require_gem. 而我,卻也弄了個 require_ludy. 沒辦法,因為很難寫一個在任何情況下都有效的 require, 所以才搞出那種東西。但是現在我覺得,還是應該多為 user 想想,畢竟連 rubygems 都捨棄 require_gem, 我也不該繼續使用 require_ludy 才對。

無奈這真的是個很大的問題,可能勢必得做得不要那麼 general 吧?大致問題如下:
a. 使用 gem install 時可以正常 require.
b. 把東西全部 copy 到 project path 時, 讓 -I 可以 work.

其實簡單地說,就是希望不要 gem install 也可以輕鬆放到專案中使用。不過也許得放棄這個要求吧?因為實際在寫時,就會發現很多問題都跟這有關。如果能「假設」gem 一定有安裝起來的話,很多考量就可以不用做了。

事實上,不需要安裝 gem 也能 work, 對於開發也很有用。因為我可以改改程式就測試最新的結果,而不必自己裝一份。所以,還是再看看吧。還是希望能有好方法。

5. unit testing. 既然是 unit testing, 當然就要有能夠分開 test 的動作。我希望可以 ruby test/tc_bind.rb, 也可以 rake test 測試所有的 unit test. 之前因為沒在用 rake, 我自己寫了個 ts_ludy.rb, 大概就是做這件事。所以 ruby test/ts_ludy.rb 就可以跑所有的測試。

而我發現,如果照 unit test 原先的設計,把所有東西都 require 起來再跑,執行效能會變得很爛很爛。原因我不是很清楚... 所以後來我改變作法,變成一個個去跑每個 unit test, 然後把輸出結果蒐集起來,再報告出去。這樣的好處就是跑得速度真的快太多了,好幾倍的差別。缺點當然就是,這樣做挺詭異的...

所以關於 testing 的部份,也還需要再整理一下。大致就是希望能單獨跑也能一起跑。另一方面,我要求 testing 所使用的 lib 應該要是相對路徑下的,而不是 gem 上的。理由同 require path 上面的描述。

其實對於 require path 和 unit testing 的部份,我花了不少功夫,不過成果其實還滿差的。當時看是沒什麼感覺,現在看覺得實在很醜。

6. 去掉 shebang, 那很蠢。(那時候對 shell 太不熟了)

7. ludy_ext.rb
這東西,本來是想放各個沒在 Ludy module 下的東西,不過這樣成長太噁心了。應該學學 facets, 一個 method 一個檔才對。所以這部份也要切開,整理一下。

8. 整合之前為了 shooting-cubes 做的一些 rake task, 還有 erb meta-programming 的一些相關 method. 這個,和 puzzle_generator 一樣好像有點尷尬,不太屬於 ludy 的範疇。
不過在整個 ludy 東西還很少的狀況下,我希望盡量整合一些 lib.

9. 儘快整合 multi, 那個 multi-method 的 lib. 我在想,我可能自己實作一份,就不要直接把他吃進來。multi 是 MIT license, 我想我直接吃進來應該沒問題,只是整個感覺就很怪,而且他的程式有些部份我不太滿意,所以也許我自己做一份還是比較好,這樣也不用想怎麼合併。

如果確實做出來了,那大概就只留一份 NOTICE 或感謝之類的,就不保留原本的 require path 了。不然,我真的覺得那樣很醜,像是分裂的個體似的。

10. 修改一些文字說明,包含 README, CHANGES, description 之類的。現在的格式已經有點接近亂寫了。另一方面,也希望稍微修改一下 rubyforge 上的 release 結構。

11. 撰寫 rdoc, 完全沒 doc 其實也有點奇怪...

*

所有的 source code 都採用 Apache License 2.0, 希望下次的更新可以涵蓋以上幾點。

btw, bind 實作只有 13 行(含註解)

安裝:
gem install ludy

取得所有程式:
svn checkout http://ludy.rubyforge.org/svn/
or
svk mirror http://ludy.rubyforge.org/svn/ //mirror/ludy

7/08/2007

ruby facets

老實講,ruby 有一個地方真討厭,那就是每次都把我想做的東西做完了。有了 ruby, 我不覺得還有需要再自己弄一個程式語言,做得比我想像中的還好。唯一的缺點大概只有 lib 還不夠多,但有了 facets 的話,那也真的是差不多了。
http://facets.rubyforge.org/
該有的幾乎都有了,差的只剩下一些小東西。如果早點發現這東西,大概就不會想弄 ludy 了吧。

不過想用 facets 有點麻煩,例如我想用 Array#shuffle, 就必須
require 'rubygems'
require 'facets'
require 'array/shuffle'
這麻煩到爆炸了吧!!不過有個好東西:

require 'rubygems'
require 'facets/automatic'

接下來,就放心使用 Array#shuffle 吧!因為 automatic 會自動幫你 require... 我沒去看他的實做,但我猜是建 table 吧。有一個小缺點,例如你想這樣做:

[1,2,3].shuffle.map &:to_s

很不幸,這樣會失敗。shuffle 可以正常自動 require, 但是 Symbol#to_proc 不能藉由這個方法自動 require. 如果你寫:

[1,2,3].shuffle.map &:to_s.to_proc

這樣是 ok 的,automatic 可以自動 require 該 require 的東西。問題大概出在,&:to_s 是 implicit call, automatic 偵測不到。所以第一次使用,還是必須明確說明需要用到 Symbol#to_proc, 接下來就可以快樂地使用

[1,2,3].shuffle.map &:to_s

了。或是前面自己手動 require:

require 'rubygems'
require 'facets'
require 'facets/automatic'

第二行的 require 可以讓你使用 Symbol#to_proc, 所以就可以直接寫:

[1,2,3].shuffle.map &:to_s

快去安裝 facets 吧!!
gem install facets
另一個 ruby web framework nitro 0.41.0 也有用到 facets !! 雖然是用 1.4.5 版的,而現在最新的 facets 是 1.8.54(以 2007.07.08 為準的最新版本)有機會也可以試試 nitro
gem install nitro
官方網站是:
http://www.nitroproject.org/
缺點非常明確!幾乎沒有文件 XD 我很少看到一個東西的文件可以少到這樣。

不多說了,我現在頭痛就算了,眼睛也很痛。

5/03/2007

簡單的建立自己的 Gem Package

一不小心就跟 Godfat 寫的議題衝突,不過沒關係,我是走輕鬆簡單取向的。這次要講的就是如何將自己寫的程式包成 Ruby GEM,本文的參考自 JavaEye 上面的创建自己的ruby Gems,程式也是來自計算民國跟學年度的 Plugin的範例。



結構

要建立一個 GEM Package,首先要先搞清楚結構。因為我們是走極簡路線的,所以現在一開始連 unit-test 都不要 test。將你的 GEM Package 設定為下面的結構。

-----gem.spec
|
--README
|
--lib/

裡面 lib 就是放所有程式的所在。

結構檔

根目錄下面有 gem.spec,跟 README 兩個檔案。其中 gem.spec 是描述 GEM Package 的結構檔,也是最重要的檔案,裡面記載了這個 GEM Package 絕大多數的資訊。可以說學會了寫這個檔案,就學會了打包 GEM Package。這裡要講的是其實 gem.spec 檔名是我隨便取的,檔名不限定,而且他的格式可以使用 ruby 或是 YAML 語法的,這裡先使用 Ruby 語法。

require 'rubygems'
SPEC=Gem::Specification.new do |s|
s.name="Taiwan_Year"
s.version='0.01'
s.author='thegiive'
s.email="thegiive at gmail dot com"
s.homepage="http://lightyror.thegiive.net/"
s.platform=Gem::Platform::RUBY
s.summary="為台灣學年度跟民國所寫的Plugin"
condidates =Dir.glob("{bin,lib,docs,test}/**/*")
s.files=condidates.delete_if do |item|
item.include?("CVS")|| item.include?("rdoc")
end
s.require_path="lib"
s.has_rdoc=false
s.extra_rdoc_files=["README"]
end
裡面
  1. s.name 就是這個 gem 的名稱,也是他打包出來的檔名,也就是說這個 gem package 會叫做 Taiwan_Year-0.01.gem。
  2. s.version 部分 godfat 有解釋過,盡量從 0.0.1 而不是從 0.0.0 開始寫起。
  3. s.summary 就是當你打入 gem list 出現的簡單文字,安裝了本 gem ,按下 gem list 這裡會出現
    sources (0.0.1)
    This package provides download sources for remote gem installation

    Taiwan_Year (0.01)
    為台灣的學年度跟民國寫的 Plugin

    vim-ruby (2006.07.11)
    Ruby configuration files for Vim. Run 'vim-ruby-install.rb' to
    complete installation.
    這樣的情況。

再來就是 README ,就是打入一些information進去摟。

放入程式

最後把程式放入到 lib 底下,這裡是使用計算民國跟學年度的 Plugin的範例,把他放入 lib/year.rb 檔案裡面
class Time

def roc_year
self.year -
1911
end

def student_year
if self.month
< 7
self.roc_year -
1
else
self.roc_year
end
end

end
打包 gem

當程式都放好後,開始打包 gem 了。我們這裡使用 gem build 指令來打包
gem build gem.spec
這裡面的 gem.spec 就是你剛剛寫的結構檔的檔名。成功了之後,你就會發現我們已經產生了一個 Taiwan_Year-0.01.gem。

安裝 gem

要安裝這個剛打包好的 gem 就是直接打
gem i TaiwanYear-0.01.gem
即可。

使用 gem

要使用剛剛安裝好的 gem package ,首先要 require 'rubygems' ,告訴程式這個是使用 gem 的程式。

其次要搞清楚程式檔名,像我雖然 GEM Package 叫做 TaiwanYear ,但是我的程式其實是放在 lib/year.rb 底下的,所以使用上還是得必須 require 'year' 。

解決方式很簡單,當我們放入程式到 lib 裡面的時候,請將程式名稱取的跟 GEM Package 名字相同即可。像是當初在打包時,我們就將程式放在 lib/TaiwanYear.rb 底下,以後使用上就可以這樣使用。

require 'rubygems'
require 'TaiwanYear'
puts Time.now.roc_year
如此,我們已經學會如何打包 gem 了。

5/02/2007

require 'rubygems'

寫到一半因為有其他事所以先放著,結果回來就是八小時後了…。
有夠累。

==

大致調查(survey?)了一下要怎麼樣把程式 package 成 rubygem, 主要參考書籍當然是 Programming Ruby 2nd, 這本我看好久還是沒看完的書。(還不都是因為他太厚了…)在 Creating Your Own Gems 這一節中,相當詳細地描述了如何打包(在 MtG 中,不知為何把 entwine 翻譯成打包,瞬間從 spell 的意味變成像外帶一樣)。這邊將簡單示範一次我如何發佈 ludy 的。

首先呢,rubygems 有建議的檔案配置(layout),可以不依照這個規則來做,但一般來說建議使用跟別人相同的方式。所有雜七雜八的東西放在根目錄下,例如 ludy-0.0.1 裡面放的有:ludy.gemspec, LICENSE, NOTICE, README. 其他目錄則是很常見的:bin, doc, lib, test. 我沒有 bin 也沒有 doc, 所以只有放 lib 和 test 兩個目錄。

顧名思義,lib 裡面放的就是 ludy 本身的 source code, 專門拿來給人 require 用。而 test 底下則是所有的 test program, 以 tc_ 開頭的是 TestCase, 可以單獨執行,但主要是由 ts_ 開頭的 TestSuite 去 require 起來,然後 ts_ 會自動執行這些 tc_.

所以我的 ts_ludy.rb 裡面只有兩行:

require(File.join(File.dirname(__FILE__), '..', 'lib', 'ludy'))
require_all_in_dir __FILE__

第一行是把 lib/ludy.rb require 進來,這是使用 ludy 部份元件的必要手續。這樣做的理由是有些 path 問題很煩,所以我把處理 path 的 func 寫在 ludy.rb 中,如此一來需要確保路徑的只有 ludy.rb 這一個檔案。至於為何這裡要使用相對路徑去 require 呢?因為我堅持兩種使用 ludy 的方式,一個是安裝成 gem, 另一個是直接丟到 project 目錄下,使用路徑去 require. 前者不用說,可以有一個很標準的方式使用,但後者就不一定了。

為了處理這個問題,ludy 內部需要某些其他 ludy tool 時,就改用 require_ludy, 集中處理 require 問題,避免重複把相同路徑加入 load path. 使用者當然也可以使用 require_ludy, 或是依然習慣使用 require, 那麼只要確定自己 require 的 path 是正確的就好了,ludy 內部不會有路徑問題。至於 gem version, require 的方式就很單純用 require 'ludy/tool_name' 或是 require_ludy 'tool_name' 就好了。

第二行,則是把所有 tc_ 開頭的 TestCase require 進 TestSuite 裡面,(其實是同個目錄下所有的 .rb 檔,只是現在 test/ 下只有 tc_ 和正在執行的 ts_ 而已)unit test 就會自動執行了。不過這個 require_all_in_dir 的第一個參數卻是檔案名稱,名字好像取得不太好的樣子。

ok, 也就是說我要打包的東西是 ludy.gemspec, LICENSE, NOTICE, README, lib/*.rb, test/*.rb. 其中 lib/ 底下還有其他資料夾,也要一併打包。那麼寫好的 gemspec 就是


require 'rubygems'

spec = Gem::Specification.new{|s|
s.name = 'ludy'
s.version = '0.0.1'
s.author = 'Lin Jen-Shin(a.k.a. godfat)'
s.email = 'strip number: 135godfat7911@246gmail.890com'
s.homepage = 'http://ludy.rubyforge.org/'
s.platform = Gem::Platform::RUBY
s.summary = 'Aims to extend Ruby standard library, providing some useful
tools that\'s not existed in the standard library.'
candidates = Dir.glob '{bin,doc,lib,test}/**/*'
candidates+= Dir.glob '*'
s.files = candidates.delete_if{|item|
item.include?('CVS') || item.include?('rdoc') ||
File.extname(item) == '.gem'
}

s.require_path = 'lib'
s.autorequire = 'ludy'
s.test_file = 'test/ts_ludy.rb'
s.has_rdoc = false
# s.extra_rdoc_files = []
# s.add_dependency 'multi', '>=0.1'
}

if $0 == __FILE__
Gem::manage_gems
Gem::Builder.new(spec).build
end


其中 Dir.glob 的部份我還沒研究,所以寫得很爛,居然用補正的方式。反正就是全部抄自 Programming Ruby 2nd, 再做一點修修改改。其中最下面的 if $0 == __FILE__ 可以判斷這個程式是不是直接被 ruby interpreter 執行?如果是的話,就呼叫建立 rubygem 的 method. 不是的話,就只要定義 spec 就好了。

前者就是:
ruby ludy.gemspec
或是如果有加 #! 的話:
./ludy.gemspec
如果 ludy.gemspec 在現在目錄下的話。

後者就是:
gem build ludy.gemspec

這兩種方式都可以產生 ludy-0.0.1.gem. 接著再下:
gem install ludy
就可以正確安裝 ludy gem 了。至於 remote 的部份呢?只要上傳到 rubyforge 的 file release system 上,rubyforge 每日會有數次掃描裡面的 *.gem, 自動放到 rubygems 的 repository. 這件事我已經做完了,所以現在可以直接:

gem install ludy

就能看到我寫的一點程式了 :)
不過其實我只是在測試功能而已,本來是想標版本號 0.0.0, 可惜這樣用:

gem uninstall ludy

時會出一點問題。所以就還是標成 0.0.1, 但未來的更新暫時都不改版本號。正式釋出時大概會是 0.0.2 吧 :p 還是歡迎大家抓回去試試,使用方法全在 unit test 裡面,文件懶得寫了。

homepage:
http://ludy.rubyforge.org/
有空時會弄個應有的版面出來。

2007.05.02 godfat 真常

1/07/2007

newgem:方便打包 gem 的東西

當我看到KDr2這篇简单漂亮的打包GEM的時候,心裡想到的是「這真的解決了我許多問題」。有些程式碼其實我想打包成 gem code 來方便再利用,卻不知道該怎麼包 gem(其實是自己懶)。現在可好了,有 newgem 這個神兵利器,以後可沒藉口不包 gem 了。以下是參考KDr2简单漂亮的打包GEM。


使用方式:

1. 安裝 newgem

gem i newgem

2. 產生 gem package 的資料夾結構
假設我們要包的 gem 名字叫做 abc
newgem abc
3. 我們的 code 放置點
假設我們要包的 gem 名字叫做 abc ,那麼我們的 code 就放在 這裡裡面
lib/abc.rb
依照 module 方式來撰寫

4. 打包 gem file
rake package
這時已經打包好了,放在 pkg/abc-0.0.1.gem

5. 修改版本號碼
預設是 0.0.1 ,如果你想修改 gem version number ,請修改
lib/abc/version.rb
  1. module MapByMethod #:nodoc:
  2. module VERSION #:nodoc:
  3. MAJOR = 0
  4. MINOR = 0
  5. TINY = 1

  6. STRING = [MAJOR, MINOR, TINY].join(’.')
  7. end
  8. end
修改裡面的數字即可

延伸閱讀



11/17/2006

為什麼 Debian 跟 Ubuntu 上面沒有 ruby-gems?

Ruby Gems 是一個相當重要的 Ruby 套件管理系統,有太多 Ruby and Rails 的 Plugin 在 Gems 上面可以方便的下載。但是,FreeBSD ,MAC OS X,Gentoo 都可以直接用預設的套件系統安裝 gems ,卻只有標榜安裝快速方便的 Debian 跟 Ubuntu 沒有提供 APT 安裝。這到底是為什麼呢?

我看了一些討論串,這裡網頁解釋了許多 Debian 上面為何不加入 Ruby Gems 的原因。
  • Rubygems packages are not compatible with the FHS. Rubygems follows the “one directory per package and version” rule.
  • It is not possible to do “normal” (FHS-compatible) installations of rubygems, and some ruby software developers have started to distribute their software as gems only.
  • Rubygems is source-intrusive. The require instruction is replaced by a require_gem instruction to allow for versioned dependencies. Debian and most other systems think that dealing with versioned dependencies outside of the source is a better idea.
  • There are currently no plans to improve RubyGems to ease the work of Debian and RPM packagers.
當然啦,每個套件系統都有自己的 concern,不過我不太能接受這個理由,難道 Ruby Gems 必須為了特定系統開發一個新的方式嗎?

到底是系統應該配合開發者的習性,還是開發者得自己去適應系統的規則?

但是看到這個網頁,我覺得這個講的比較實在點
Pure ruby gems are converted fine. However, ones including C extensions are not.
大意是如果這個 GEMS 是純 Ruby 當然歡迎,但是有些 Ruby Gems 是有 C extenstions 的(一些 Ruby Lib 像是 ruby-mysql ),那就很容易出現安裝錯誤,所以相當不建議使用 Ruby Gems 摟。 為此,Debian-Ruby 的 Daigo Moriwaki 也寫了自動轉換 GEM 成為 DEB 的程式,希望能方便大家打包 Ruby Gems 的 DEB Package。但是話說回來, Ruby Gems 那麼多,你怎麼可能全部包成 DEB ?Ruby GEMS上有些東西有安全性顧慮時,要緊急下載 patch ,這時通常官方會建議使用 Gem 去更新,難道 DEB 也可以立刻做到即時更新?還是要使用者自己苦哈哈下載 source 自己裝?

到底是系統應該配合開發者的習性,還是開發者得自己去適應系統的規則?

如果答案是後者的話,Ruby GEMS 要怎麼做到跨平台?所以 Daigo Moriwaki 也深知這個道理,也提供了 Unofficial 的 deb source XD
deb http://www.sgtpepper.net/hyspro/deb unstable/
deb-src http://www.sgtpepper.net/hyspro/deb unstable/
Update 完 DEB index 之後,apt-get install rubygems 即可。