第 20 回 Ruby 勉強会@関西 初級者レッスン演習課題解答例(RSpec版)
Test::Unit版 と同じことを RSpec でやってみた。
第 20 回 Ruby 勉強会@関西 に解答例(answer.pdf)がアップされていますがそれの捕捉説明的なものです。前回と同様、配布資料(print.pdf)が手元にある前提で進めます。
Test::Unit 版とは書いた時期が違うので微妙に実装が違っていたりします。
ちなみに RSpec を使って書くのは初めてです。RSpec についてはるびまの記事を参照してください。
なお、stack_spec.rb は、そのとき注目している機能に関係のある部分のみ掲載します。
実装するメソッド
- empty?
- スタックが空なら true、そうでなければ false を返す。
- size
- スタックのサイズを返す。
- push(val)
- 引数の値をスタックの一番上に積む。
- pop
- スタックの一番上の値を取り除いて返す。スタックが空の場合は Stack::EmptyStackErrorが発生する。
Step1
- Stack#empty? のテスト
- 「新しいスタックの empty? は真」
stack_spec.rb
require 'stack'
describe Stack, "when empty" do
before do
@empty_stack = Stack.new
end
it "should be empty" do
@empty_stack.should be_empty
end
after do
@empty_stack = nil
end
end
Stack が空のときの動作を記述。
- spec -c で実行すると色つきで結果が表示される
stack.rb
class Stack
def empty?
true
end
end
- とりあえず Test::Unit 版と同じように Fake it してみた
Step2
- Stack#push と Stack#pop のテスト
- 「新しいスタックに 3 を push して pop すると 3 が返る」
stack_spec.rb
describe Stack, "when push 3" do
before do
@stack = Stack.new
@stack.push(3)
end
it "should pop 3" do
@stack.pop.should == 3
end
after do
@stack = nil
end
end
- describe の引数に書いた内容を before のブロックに記述する
- it 〜 end に実際にチェックしたい内容を記述する
- after のブロックに後始末の処理を記述する
- before と after は省略可能
stack.rb
class Stack
def empty?
true
end
def push(val)
end
def pop
3
end
end
- Test::Unit 版と同じように Fake it
Step3
- Stack#size のテスト
- 「新しいスタックに 3 を push すると size は 1」
stack_spec.rb
describe Stack, "when push 3" do
before do
@stack = Stack.new
@stack.push(3)
end
it "should pop 3" do
@stack.pop.should == 3
end
it "should size 1" do
@stack.size.should == 1
end
after do
@stack = nil
end
end
- Step2 と事前準備の内容は同じなので同じ describe ブロック内に it 〜 end を追加する
stack.rb
class Stack
def empty?
true
end
def push(val)
end
def pop
3
end
def size
1
end
end
- 実装はひたすら Fake it
Step4
- Stack#size のテスト (2)
- 「新しいスタックに 3 を push すると size は 1」
- 「さらに 5 を push すると size は 2」
stack_spec.rb
describe Stack, "when push 3 and 5" do
before do
@stack = Stack.new
@stack.push(3)
@stack.push(5)
end
it "should size 2" do
@stack.size.should == 2
end
end
- 前のステップとは状況が違うので新しい describe ブロックを用意した
stack.rb
class Stack
def initialize
@size = 0
end
def empty?
true
end
def push(val)
@size += 1
end
def pop
3
end
def size
@size
end
end
- Fake it のままでは通らないので、ちょっとまじめに実装。
Step5
- Stack#empty? のテスト (2)
- 「新しいスタックに 3 を push すると empty? は偽」
stack_spec.rb
describe Stack, "when push 3" do
before do
@stack = Stack.new
@stack.push(3)
end
it "should pop 3" do
@stack.pop.should == 3
end
it "should size 1" do
@stack.size.should == 1
end
it "should not be empty" do
@stack.should_not be_empty
end
after do
@stack = nil
end
end
- 事前準備の状況が Step2, Step3 と同じなので同じ describe に振舞を追加
stack.rb
class Stack
def initialize
@size = 0
end
def empty?
size == 0
end
def push(val)
@size += 1
end
def pop
3
end
def size
@size
end
end
Step6
- Stack#pop のテスト (2)
- 「新しいスタックを pop すると Stack::EmptyStackError が発生する」
stack_spec.rb
describe Stack, "when empty" do
before do
@empty_stack = Stack.new
end
it "should be empty" do
@empty_stack.should be_empty
end
it "should raise Stack::EmptyStackError" do
lambda{
@empty_stack.pop
}.should raise_error Stack::EmptyStackError
end
after do
@empty_stack = nil
end
end
stack.rb
class Stack
class EmptyStackError < StandardError
end
def initialize
@size = 0
end
def empty?
size == 0
end
def push(val)
@size += 1
end
def pop
raise EmptyStackError if empty?
3
end
def size
@size
end
end
Step7
- Stack#pop のテスト (3)
- 「新しいスタックに 3 を push して 5 を push して pop すると size は 1」
stack_spec.rb
describe Stack, "when push 3 and 5, then pop" do
before do
@stack = Stack.new
@stack.push(3)
@stack.push(5)
@stack.pop
end
it "should size 1" do
@stack.size.should == 1
end
after do
@stack = nil
end
end
stack.rb
class Stack
class EmptyStackError < StandardError
end
def initialize
@size = 0
end
def empty?
size == 0
end
def push(val)
@size += 1
end
def pop
raise EmptyStackError if empty?
@size -= 1
3
end
def size
@size
end
end
Step8
- Stack#pop のテスト (4)
- 「新しいスタックに 3 を push して 5 を pushして pop すると 5 が返る」
stack_spec.rb
describe Stack, "when push 3 and 5" do
before do
@stack = Stack.new
@stack.push(3)
@stack.push(5)
end
it "should size 2" do
@stack.size.should == 2
end
it "should pop 5" do
@stack.pop.should == 5
end
after do
@stack = nil
end
end
stack.rb
class Stack
class EmptyStackError < StandardError
end
def initialize
@size = 0
@stack = []
end
def empty?
size == 0
end
def push(val)
@size += 1
@stack.push(val)
end
def pop
raise EmptyStackError if empty?
@size -= 1
@stack.pop
end
def size
@size
end
end
Step9
最後にリファクタリングします。
stack_spec.rb
require 'stack'
describe Stack, "when empty" do
before do
@empty_stack = Stack.new
end
it "should be empty" do
@empty_stack.should be_empty
end
it "should raise Stack::EmptyStackError" do
lambda{
@empty_stack.pop
}.should raise_error Stack::EmptyStackError
end
after do
@empty_stack = nil
end
end
describe Stack, "when push 3" do
before do
@stack = Stack.new
@stack.push(3)
end
it "should pop 3" do
@stack.pop.should == 3
end
it "should size 1" do
@stack.size.should == 1
end
it "should not be enpty" do
@stack.should_not be_empty
end
after do
@stack = nil
end
end
describe Stack, "when push 3 and 5" do
before do
@stack = Stack.new
@stack.push(3)
@stack.push(5)
end
it "should size 2" do
@stack.size.should == 2
end
it "should pop 5" do
@stack.pop.should == 5
end
after do
@stack = nil
end
end
describe Stack, "when push 3 and 5, then pop" do
before do
@stack = Stack.new
@stack.push(3)
@stack.push(5)
@stack.pop
end
it "should size 1" do
@stack.size.should == 1
end
after do
@stack = nil
end
end
- 上記の仕様を満たすように実装コードを書き換えます。
- 本来はちょっとずつ書き換えるべきですが、最終結果のみ書いておきます
stack.rb
require 'forwardable'
class Stack
extend Forwardable
def_delegators(:@stack, :empty?, :push, :size)
def initialize
@stack = []
end
def pop
raise EmptyStackError if empty?
@stack.pop
end
class EmptyStackError < StandardError
end
end
- forwardable ライブラリを使用するとメソッドを指定して特定のオブジェクトに委譲できる
- 使用方法はリファレンスマニュアルを確認してください
Posted in Ruby | コメントはありません | atom
Trackbacks
Use the following link to trackback from your own site:
http://typo.okkez.net/trackbacks?article_id=ruby-kansaiworkshop-20th-2&day=04&month=11&year=2007