メソッド名とシグニチャを統一して美しいAPI設計
スポンサーリンク
スポンサーリンク
ライフスタイル関連のコンテンツ
お金 | 仕事 | 勉強 | プライベート | 健康 | 心
プログラミング関連のコンテンツ
C言語/C++入門 | Ruby入門 | Python入門 | プログラミング全般
お金 | 仕事 | 勉強 | プライベート | 健康 | 心
プログラミング関連のコンテンツ
C言語/C++入門 | Ruby入門 | Python入門 | プログラミング全般
=追記(2010/07/23)
Rubyベストプラクティスのひとり読書。理解が難しかった部分を中心にまとめています。
書籍から引用しすぎと思われたページ、理解したページなどを削除して、当初より公開ページを減らしました。すいません。
読書のまとめ記事は難しいと感じたので、今後はブログで読書のまとめは書かないでおきます。差し障りがあれば現存するページも削除致しますので予めご了承下さい。
=追記ここまで
スポンサーリンク
P36からのRuportライブラリを使って、Tableオブジェクトを作成する例。
あらかじめ、以下を実行してRuportをインストールしておく。
gem install ruport gem install ruport-util
また、people.csv を使うのであらかじめ同じディレクトリに作成しとく。
メソッド名とシグニチャを統一して使いやすAPIにする
受け取るオブジェクトによって異なるメソッド名とシグニチャのAPI。
これだと使いにくAPI。
table1 = Ruport::Data::Table.new( :column_names => %w[first_name last_name], :data => [["Gregory", "Brown"], ["Deborah", "Orlando"]] ) table2 = Ruport::Data::Table.load("people.csv") csv = "first_name,last_name\nGregory,Brown\nDeborah\nOrlando\n" table3 = Ruport::Data::Table.parse(csv)
上のnew, load, parseメソッドをラップして、Tableメソッド1つのAPIにする。
こうすると使いやすい(覚えやすい)APIができる。
table1 = Table(%w[first_name last_name], :data => [["Gregory", "Brown"], ["Deborah", "Orlando"]] ) # CSVファイルを受け取る args[0] => .csvファイル table2 = Table("people.csv") # 文字列を受け取る args[0] => Hash (:string => hoge) csv = "first_name,last_name\nGregory,Brown\nDeborah\nOrlando\n" table3 = Table(:string => csv)
Tableメソッド(使いやすいAPI)の実装とサンプル実行
require "pp" require "rubygems" require "ruport" def Table(*args, &block) table = case args[0] when Array opts = args[1] || {} Ruport::Data::Table.new( {:column_names => args[0]}.merge(opts), &block) when /\.csv$/i Ruport::Data::Table.load(args[0], &block) when Hash if file = args[0].delete(:file) Ruport::Data::Table.load(file, args[0], &block) elsif string = args[0].delete(:string) Ruport::Data::Table.parse(string, args[0], &block) else Ruport::Data::Table.new(args[0], &block) end else Ruport::Data::Table.new(:data => [], :column_names => args, &block) end return table end # カラム名(配列)とデータ(ハッシュ)を受け取る args[0] => Array table1 = Table(%w[first_name last_name], :data => [["Gregory", "Brown"], ["Deborah", "Orlando"]] ) pp table1 # CSVファイルを受け取る args[0] => .csvファイル table2 = Table("people.csv") pp table2 # 文字列を受け取る args[0] => Hash (:string => hoge) csv = "first_name,last_name\nGregory,Brown\nDeborah,Orlando\n" table3 = Table(:string => csv) pp table3
実行結果
>ruby 36.rb #<Ruport::Data::Table:0x2c2ff68 @column_names=["first_name", "last_name"], @data= [#<Ruport::Data::Record:0x2c2f34c @attributes=["first_name", "last_name"], @data={"first_name"=>"Gregory", "last_name"=>"Brown"}>, #<Ruport::Data::Record:0x2c2e7e4 @attributes=["first_name", "last_name"], @data={"first_name"=>"Deborah", "last_name"=>"Orlando"}>], @record_class="Ruport::Data::Record"> #<Ruport::Data::Table:0x2d48170 @column_names=["first_name", "last_name"], @data= [#<Ruport::Data::Record:0x2d47590 @attributes=["first_name", "last_name"], @data={"first_name"=>"Gregory", "last_name"=>"Brown"}>, #<Ruport::Data::Record:0x2d4707c @attributes=["first_name", "last_name"], @data={"first_name"=>"Deborah", "last_name"=>"Orlando"}>], @record_class="Ruport::Data::Record"> #<Ruport::Data::Table:0x2d42b58 @column_names=["first_name", "last_name"], @data= [#<Ruport::Data::Record:0x2d41fdc @attributes=["first_name", "last_name"], @data={"first_name"=>"Gregory", "last_name"=>"Brown"}>, #<Ruport::Data::Record:0x2d41ac8 @attributes=["first_name", "last_name"], @data={"first_name"=>"Deborah", "last_name"=>"Orlando"}>], @record_class="Ruport::Data::Record">
統一したAPIであるTableメソッドで、違う種類のオブジェクトを受け取り、同一のTableオブジェクトが生成されていることを確認できました。
使われているテクニックのまとめ
デフォルト値付きの引数
ハッシュを用いた擬似キーワード引数
def hoge(*args); fuga; end と*argsで可変長引数
コードブロックの引数(詳細は次回)
スポンサーリンク
>> 次の記事 : コードブロックを用いたサーバーとクライアントの例
<< 前の記事 : mustメソッドで読みやすいテスト
- - 関連記事 -
- プロキシオブジェクトの例で関数型プログラミングを理解
- 無名クラスを継承するRubyの動的機能
- method_missing()とsend()でフック(処理を捕捉)
- obj.instance_eval(&block)とblock.call(obj)の違いを確認
- コードブロックを用いたサーバーとクライアントの例
- mustメソッドで読みやすいテスト
スポンサーリンク