Date:  Wed, 24 Oct 2007 17:15:20 +0900
Subject:  【オブジェクト倶楽部: 2007-38号】
X-Mail-Count: 00213

       ┏━━━━━━━━━━━━━━━━━━━━━━━━━━■
       ┃                         ■┃
      ●┃● ● オ ブ ジ ェ ク ト 倶 楽 部   ■ ┃
       ┃                       ■  ┃
       ┗━━━━━━━━━━━━━━━━━━━━━━■━━━┛
                          No.207 2007/10/24

■ I N D E X
┃
┣【Topics】秋イベント「秋の宴」についてお知らせ
┣【プログラミング】Rubyで進むオブジェクトの道 [25]
┣【プログラミング】ゆるーいHaskell [14]
┗【アンケート】気になるシステム業界 ホントのところ

〇━━━━━━━━━━━━━━━━━━━━━━━━━━━T o p i c s━
 〇 秋イベント「秋の宴」についてお知らせ
  〇 〇━━━━━━━━━━━━━ ━━・ 

あっという間に満席となってしまった秋イベント。多数のお申し込みをいただ
き、とても嬉しいです。ありがとうございました。

「秋の宴」はPFP関東の皆さんのご協力のもと、懇親会を企画中です。
ご参加予定の皆様は、当日実費3000円をお支払いください。
ご連絡が事後になり申し訳ありません。よろしくお願いいたします。

●「秋の宴」
PFP(プロジェクトファシリテーションを推進する会)さんのご協力のもと、秋の
宴を開催いたします。
参加費 : 3,000円
【PFP関東】 http://projectfacilitationproject.go2.jp/wiki/
※「秋の宴」にご案内してございます。
 宴に関する情報は、今後も更新される可能性があります。開催直前までwiki
 をご確認ください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━1 s t ■━
■
┗【プログラミング】Rubyで進むオブジェクトの道 [25]

■はじめに
今日は、RSpecでスタブの書き方を勉強します。

早速、ソースから
時間が9時なら"hello!"、18時なら "good by!"、それ以外の時間なら"hey!"を
返すプログラムです。

■ geeting.rb

class Greeting
  def say
     return "hello!" if Time.now.hour == 9
     return "good bye!" if Time.now.hour == 18
     "hay!"
  end
end

ここで厄介なのがTime.nowです。実際のTime.nowのままでは、時間帯によって
返す値が異なり、sayメソッドのテストがやりにくくなっています。

■RSpecのスタブを使わなかった場合
テストし易い構造に変えてしまって対処する方法は、いくつか思いつきます。
 
方法1
 - 厄介な箇所(時間の問い合わせ)をインタフェースで切り出す
 - インターフェスに対して時間を問い合わせるように修正
 - テストの際は、決まった時間返すスタブを用意し、Greetingオブジェクトに
   インジェクトしてテストする。

方法2
 -厄介な時間の問い合わせの箇所をメソッド化する
 -テストの際は時間の問い合わせの箇所をオーバライドして決まった時間を返
  すようにする。

方法3
 -そもそもAPIが悪いと判断。sayメソッドの引数に時間を明示的に渡すように
  APIを変えてしまう。

■RSpecのスタブを使った場合
RSpecのstub!メソッドを使えば、上記のような対処は不要で、上記のソースの
ままでもスタブによるテストが可能です。下記にRSpecを使ったスタブによるテ
ストを例を示します。

-- geeting_spec.rb
describe Greeting, "at 9:00" do
  before(:each) do
    Time.stub!(:now).and_return(Time.gm(*"2007-10-01-09-00".split("-")))
    @greeting = Greeting.new
  end

  it "should say 'hello!'" do
    @greeting.say.should == "hello!"
  end
end

describe Greeting, "at 18:00" do
  before(:each) do
    Time.stub!(:now).and_return(Time.gm(*"2007-10-01-18-00".split("-")))
    @greeting = Greeting.new
  end

  it "should say 'good bye!'" do
    @greeting.say.should == "good bye!"
  end
end

describe Greeting, "not 9:00 or 18:00" do
  (0..23).reject { |hour| hour == 9 or hour == 18 }.each { |hour|
    it "should say 'hay!'" do
      Time.stub!(:now).and_return(Time.gm(*"2007-10-01-#{hour}-00".split("-")))
      @greeting = Greeting.new
      @greeting.say.should == "hay!"
    end
  }
end


■解説
Time.stub!(:now).and_return(Time.gm(*"2007-10-01-09-00".split("-")))
がポイントです。これだけで、実際の時間ではなくスタブによって指定された
時間(9時)を返すようになります。

■補足:スタブとモックの違い
xUnit Test Patterns[*1]によると、スタブとモックの定義を分けています。
簡単に違いを説明するとスタブは、単に決まった値をテスト対象の要素に返す
だけで(indirect input)、期待した振る舞いを行ったかのVerifyは、テスト対
象の要素に問い合わせます。

#上記の例では
テスト対象要素:@greeting
スタブ : Time.stub!(:now).and_return(Time.gm(*"2007-10-01-#{hour}-00".split("-")))
Verifyかの問い合わせ : @greeting.say.should == "hello!"
に相当します。

対して、モックは、テスト対象の要素とモックとの間でどんなメッセージのや
り取り行うかの期待をモックに明記し、テスト対象の要素を実行したのちに、
モックにVerifyかを問い合わせます。
次回は、RSpecを使ったモックについて勉強してみたいと思います。(IENAGA)

■参考
[1] : xUnit Test Patterns
      http://xunitpatterns.com/Test%20Double.html
      http://xunitpatterns.com/Test%20Stub.html
      http://xunitpatterns.com/Mock%20Object.html
 _______________________________________________________________________
この記事への評価にご協力をお願いします。
URLをクリックして、「ご協力ありがとうございました」のメッセージがご使用
のブラウザに表示されれば投票完了です。
良かった:
http://www.ObjectClub.jp/community/object_ml/estimate?vol=E006-24&choice=0
普通:
http://www.ObjectClub.jp/community/object_ml/estimate?vol=E006-24&choice=1
イマイチ:
http://www.ObjectClub.jp/community/object_ml/estimate?vol=E006-24&choice=2

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━2 n d ■━
■
┗【プログラミング】ゆるーいHaskell [14]

こんにちは。西川です。
今回はリストモナドについてお話しします。これまで普通に使ってきたあのリ
ストもHaskellではモナドの仲間です。リストの定義をよく見てみましょう。
ghciを起動します。

> > :i []
data [] a = [] | a : [a]        -- <wired into compiler>
instance (Eq a) => Eq [a] -- Defined in GHC.Base
instance Monad [] -- Defined in GHC.Base

(リストのinstance宣言がつづきます)
リストがモナドになっていることがお分かりになると思います。リストはモナ
ドクラスのインスタンスなのです。

# リストのモナドクラスのinstance宣言
instance  Monad []  where
    m >>= k             = foldr ((++) . k) [] m
    m >> k              = foldr ((++) . (\ _ -> k)) [] m
    return x            = [x]
    fail _    = []

リストのinstance宣言は上記のようになっています。
実際にリストをモナドとして操作してみましょう。

Prelude> [1,2,3] >>= return . (1+)
[2,3,4]

いきなりすぎてよく分かりませんね。上記のinstance宣言からこの操作は以下
の操作と等価です。

0> foldr ((++) . (return . (1+))) [] [1,2,3]

((++) . (return . (1+))の見通しが悪いので、ラムダ式を使って見やすい形に
変形してみましょう。return x
= [x]で、関数合成を無くしてみると、

1> foldr (\x -> ([1+x]++)) [] [1,2,3]
と変形することができます。これをfoldrの定義からこれを展開すると、

2> [1+1] ++ (foldr (\x -> ([1+x]++)) [] [2,3])
3> [1+1] ++ ([1+2] ++ (foldr (\x -> ([1+x]++)) [] [3]))
4> [1+1] ++ ([1+2] ++ ([1+3] ++ (foldr (\x -> ([1+x]++)) [] [])))
5> [1+1] ++ ([1+2] ++ ([1+3] ++ ([])))
6> [2,3,4]

となります。まあなんとなくリストはモナドなんだな、ということが分かって
いただければ大丈夫です。
最後にguard関数を紹介しましょう。guard関数を使って整数のリストから奇数
のみ抽出する関数を作ります。

> > let oddList xs = xs >>= \x -> guard (odd x) >> return x
# let oddList xs = do x <- xs; guard (odd x); return xとも書くことがで
きます。

> > oddList [1..10]
[1,3,5,7,9]

guard関数についてちょっと見てみましょう。

guard           :: (MonadPlus m) => Bool -> m ()
guard True      =  return ()
guard False     =  mzero

guard関数はControl.Monadモジュールで上記のように定義されている関数です。
guard関数の型に注目です。
「Control.Monad.guard :: (Control.Monad.MonadPlus m) => Bool -> m ()」の
「(Control.Monad.MonadPlusm) =>」の部分は『以降に出現する型変数mという
のはControl.Monad.MonadPlusのクラス(のインスタンス)でなければならない』
という注釈にあたります。

Control.Monad.MonadPlusを見てみましょう。

> > :i Control.Monad.MonadPlus
class (Monad m) => Control.Monad.MonadPlus m where
  Control.Monad.mzero :: m a
  Control.Monad.mplus :: m a -> m a -> m a
        -- Defined in Control.Monad
> > Control.Monad.mzero :: [a]
[]
> > Control.Monad.mplus [1,2,3] [4,5,6]
[1,2,3,4,5,6]

リストモナドでのmzero,mplusの定義をghciから確認してみました。
先程のoddList関数の「guard(odd x)」の「odd x」がFalseのときは空リストが
返ってきます。ちょうどこのような感じになります。

> > [] >> return 1
[]
「odd x」がTrueの場合はこのような感じです。
> > [()] >> return 1
[1]
今ひとつこのoddList関数の振舞いが分かりづらい、という方はリストの(>>=)
関数、(>>)関数、return関数の定義からoddList関数を変形すると見通しが良く
なるかもしれません。今回はリストモナドについてお話しました。(西川)
______________________________________________________________________
この記事への評価にご協力をお願いします。
URLをクリックして、「ご協力ありがとうございました」のメッセージがご使用
のブラウザに表示されれば投票完了です。
良かった:
http://www.ObjectClub.jp/community/object_ml/estimate?vol=E008-13&choice=0
普通:
http://www.ObjectClub.jp/community/object_ml/estimate?vol=E008-13&choice=1
イマイチ:
http://www.ObjectClub.jp/community/object_ml/estimate?vol=E008-13&choice=2

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━3 r d ■━
■
┗【アンケート】気になるシステム業界 ホントのところ

今週は「読者の皆さんの職場はどこですか?」のホントのところ。
オブラブメルマガ編集のひそやかな楽しみは、読者の皆さんからの感想メール。
お返事は遅いですが、それぞれに目を通しつつ、皆さんがどこからこの感想を
送ってくれているのか楽しみにしています。東京から近いところ。遠いところ。
「雪がふりました」「桜が咲きました」など、それぞれの土地の便りを載せて
届くメールは、普段お目にかかれない読者の皆さんとの距離をぐっと近づけて
くれますね。さて、皆さんの職場はどこでしょうか?

  北海道。
     http://www.ObjectClub.jp/special/kininaru/vote?vol=173&choice=0
  東北。
     http://www.ObjectClub.jp/special/kininaru/vote?vol=173&choice=1
  関東。
     http://www.ObjectClub.jp/special/kininaru/vote?vol=173&choice=2
  中部(北陸・甲信越・東海)。
     http://www.ObjectClub.jp/special/kininaru/vote?vol=173&choice=3
  近畿。
     http://www.ObjectClub.jp/special/kininaru/vote?vol=173&choice=4
  中国。
     http://www.ObjectClub.jp/special/kininaru/vote?vol=173&choice=5
  四国。
     http://www.ObjectClub.jp/special/kininaru/vote?vol=173&choice=6
  九州・沖縄。
     http://www.ObjectClub.jp/special/kininaru/vote?vol=173&choice=7
  国外。
     http://www.ObjectClub.jp/special/kininaru/vote?vol=173&choice=8
  それは秘密です。
     http://www.ObjectClub.jp/special/kininaru/vote?vol=173&choice=9
  ちょっと語らせて!
     詳細をこのメールに返信ください!!

アンケート結果はオブジェクト倶楽部サイト上にて公開します。お楽しみに。
なお、前号「プロジェクトファシリテーションを何で知りましたか?」の結果
は公開中。ぜひご覧下さい。
⇒http://www.ObjectClub.jp/special/kininaru/vol172/PlonePopoll_results2
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--■--●--■
■
┗編集後記

こんにちは、編集人です。席替えがありました。急に見通しが良くなっちゃって、
まだなんとなく気持ちが落ち着きません。皆さんの職場は、よく席替えがあり
ますか?席が替わって気がついたのは、オブラブスタッフ職場におけるメンバー
のPF浸透度。気がつけば可動式ホワイトボードがたくさん増えて、圧巻です!

今週の強引な一言
***酒は天の美禄(ことわざ)***
お酒は天から賜った手厚い封禄であるという意味。お酒を飲むときは愚痴は脇
において、天からのご褒美を存分に味わいたいものですね。ゆっくりと。
(上田雅美)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--■--●--■
● ご意見、ご感想は         ⇒このメールに返信ください
〇 配信中止、アドレス変更は ⇒http://www.ObjectClub.jp/community/object_ml/help/
〇 免責事項、過去の記事は   ⇒http://www.ObjectClub.jp/community/object_ml/
■ 発行:オブジェクト倶楽部 ⇒http://www.ObjectClub.jp/
■ 編集代表:平鍋  健児
Copyright (c)2003-2007 オブジェクト倶楽部. All Rights Reserved.
powered by Eiwa System Management, Inc.