今回は内部DSLの詳細,
内部DSLに適した言語 - Ruby
2005年12月にRuby on Railsの正式版のリリース以降,
そのことを端的に表しているのが,
なぜ,
私は,
Dave Thomas氏は,
Rubyで作られるDSLの多くは,
リスト1 内部DSLを使って実装されている代表的なもの
a. Ruby on Rails
class Library < ActiveRecord::Base
has_many :books
validates_associated :books
end
b.Rake
task :default => [:test]
task :test do
ruby "test/unittest.rb"
end
c.RSpec
describe Bowling do
it "should score 0 for gutter game" do
bowling = Bowling.new
20.times { bowling.hit(0) }
bowling.score.should == 0
end
end
d.Capistrano
role :libs, "www.gihyo.jp"
task :search_libs do
run "ls -x1 /usr/lib | grep -i xml"
end
また,
その一方で,
- ※1)
- 『達人プログラマー―システム開発の職人から名匠への道』
Andrew Hunt/
David Thomas著, 村上雅章訳, ISBN10:4894712741 - ※2)
『プログラミングRuby 第2版 言語編』/ 『プログラミングRuby 第2版 ライブラリ編』 Dave Thomas/ Chad Fowler/ Andy Hunt著, まつもとゆきひろ監訳, 田和勝訳, ISBN10:4274066428/ 4274066436 - ※3)
- 『エンタープライズ アプリケーションアーキテクチャパターン』
Martin Fowler著, 長瀬嘉秀監訳, 株式会社テクノロジックアート翻訳, ISBN104798105538 - ※4)
- 『ThoughtWorksアンソロジー ―アジャイルとオブジェクト指向によるソフトウェアイノベーション』
ThoughtWorks Inc.著, 株式会社オージス総研 オブジェクトの広場編集部翻訳, ISBN10:487311389X
Rubyによる, CSVファイル読み込みDSL
「第1回 - DSLとは?」
CSVファイルの仕様は,
一般的なプログラム
一般的なプログラムの方法は,
その2つの方法で共通する処理を抽出し,
表1 共通する処理
1 | CSVファイルのパスの指定 |
2 | CSVファイルの読み込み |
3 | CSVデータの解析 |
4 | 指定したデータの取得
|
(1) メンバ変数に値を保持する方法
CSVRecordクラスを継承し,
Contactクラスには,
クライアントがContactクラスにアクセスし,
表2 CSVファイルの列とContactクラスのメンバ変数との対応表
列番号 | 定数 | アクセッサメソッドの定義 |
---|---|---|
1 | COL_ | :id |
2 | COL_ | :first_ |
3 | COL_ | :last_ |
4 | COL_ |
class Contact < CSV::Base::CSVRecord
COL_ID = 0
COL_FIRST_NAME = 1
COL_LAST_NAME = 2
COL_EMAIL = 3
def set_values(row_num, values)
return if row_num == COLUMN_ROW_NUM
# contact value object - nameless class.
contact_class = Class.new{
attr_accessor :id, :first_name, :last_name, :email
def to_s
str = ""
str << "id:#{self.id}, "
str << "first_name:#{self.first_name}, "
str << "last_name:#{self.last_name}, "
str << "email:#{self.email}"
end
}
contact = contact_class.new
contact.id = values[COL_ID].to_i
contact.first_name = values[COL_FIRST_NAME]
contact.last_name = values[COL_LAST_NAME]
contact.email = values[COL_EMAIL]
@records << contact
end
end
この方法を採用することで生じる問題点は,
(2) ハッシュ (連想配列) に値を保持する方法
メンバ変数に値を保持する方法と同様に,
class CSVHash < CSV::Base::CSVRecord
def set_values(row_num, values)
# CSVファイルの1行目の列名は,ハッシュのキーとして利用する.
if (row_num == 1)
@columns = values
else
hash = {}
values.length.times do |i|
# ハッシュに値を設定
hash[@columns[i]] = values[i]
end
@records << hash
end
end
end
この方法を採用する事で生じる問題点は,