卒業論文
GitHub
を利用した
Ruby
初心者学習ソフトの開発
関西学院大学 理工学部 情報科学科
2549
浦田航貴
2017
年
3
月
指導教員 西谷 滋人 教授
目次
1
序論
3
2
方法
4
2.1
ruby novice
の設計仕様
. . . .
4
2.2
コードテスト環境
. . . .
6
3
開発ソフトの仕様と使用法
8
3.1
ruby novice
の振る舞いと意義
. . . .
8
3.2
ruby novice
の仕組み
. . . .
8
3.3
ruby novice
の現状
. . . .
12
3.4
ruby novice
の作業の流れ
. . . .
13
3.5
ruby novice
の使用法
. . . .
14
3.6
全章のテストの仕方
. . . .
18
3.7
各章ごとのテストの仕方
. . . .
18
4
考察
21
4.1
なぜ
aruba? (aruba vs test::unit) . . . .
21
5
結論
25
6
謝辞
26
7
参考文献
26
GitHub
を利用した
Ruby
初心者学習ソフトの開発
1
序論
Ruby
は本格的なオブジェクト指向プログラムが記述できる汎用性の高い日本発のオー
プンソースである.
Ruby
は初心者に分かり易く
,
プログラム教育にもスムーズに活用で
きるメリットがある
[1].
西谷研究室に在籍している学生は,
Ruby
プログラミングを修得
するために初心者向けの問題集を使って学習している.
ところが開発現場においては単に文法やプログラミングの書き方を知っているだけでは
未熟で,より多くのスキルが要求される.典型的なものがバックアップに対するスキルで
ある.バックアップをとるあるいはおいておくことはプログラミングの初心者に強調され
るが,実際にバックアップのスキルを具体的に指示する指導は行われていない.現在のプ
ログラミング環境においては
Github
がその標準となりつつある.
Github
はバックアッ
プだけでなく,進捗確認,バージョン管理やプルリクエストといった,チームによるプロ
グラミングを促進するサービスが提供されている.
一方で,プログラミング開発の最先端の技法として
Test
駆動開発
(Test Driven
Devel-opment:TDD)
が奨励されている.
TDD
では仕様を満たすテストを書く
(Red),
テスト
と通るコードを書く
(Green),
コードを読みやすく直す
(Refactoring)
というステップで
プログラミングを進めていくいくことを基本としている.それぞれの段階でなにに目標を
おいて集中するかが明確になり,コード開発の効率が上がるとされている.
「初学者がこれらのスキルを自然と身につけることはできないか?」という問いに対す
る一つの答えとして
ruby novice
を開発する.
Ruby novcie
が目指すものは,学習者自身
が出力チェックできるようにし
Ruby
プログラミングにおけるテスト実行に自然と慣れる
ような学習形態を目指している.さらに,進捗状況の管理や指導者からの添削をより容易
におこなえるように改善するため,バージョン管理ソフト
GitHub
を利用するシステム
(ruby novice)
を開発している.本研究は
Ruby
初心者が文法だけでなく,プログラミン
グにおける振舞いを身につけるための支援ソフトを開発することを目的としている.
本研究では,はじめに開発ソフトの仕様を2章で紹介する.さらに,開発したソフトの
使用法を3章で述べる
. 4
章では
,
なぜ
aruba
を使用したかの説明を述べている.
2
方法
2.1
ruby novice
の設計仕様
ruby novice
が想定している操作法について概略を記す.
2.1.1
Github
本研究では
Github
を使用し,進捗状況の管理や指導者からの添削をより容易できるよ
うにする
.Github
は,コンピュータープログラムの元となるソースコードをインターネッ
ト上で管理するためのサービスである
.
複数人が携わるソフトウェア開発において
,
ソー
スコードの共有や,バージョン管理といった作業は必要不可欠となる
[2].
本研究では,下
記の図のように
Github
を利用している.
図
1
Github
のしくみ
.
ここからは,図
1
を参考にしながら
Github
を利用した作業の流れを段階を踏んで示し
ます.
2.1.2
進捗状況の報告
まずは本研究での進捗状況の報告までの簡単な流れは以下の通りである.
(git init, fork
が済んでいると仮定
)
1.
ファイルを作成する.
2. git remote -v: origin
が自分のアドレスで
upstream
が先生のアドレスであるか確
かめる.
3. git add -A:
編集操作を
local
の
repository
に登録
.
4. git commit:
ファイルの追加や変更の履歴をリポジトリに保存.
5. git push origin master: Github
の
origin
へ
master
を
push.
6. pull request: Github
で自分のサイトに載せた変更を,先生のサイトに変更希望と
して出す.コメント欄で変更詳細を伝えることが可能.
基本的にローカルリポジトリで作業を行い,その作業内容をリモートポジトリ
(Github)
へプッシュする流れで行う.
2.1.3
添削後の作業の流れ
1.
先生がファイルを添削後
,
リモートリポジトリ
(Github)
に
git push
.
2. git pull upstream master:
自分の開発中のファイルに反映.
このサイクルを繰り返して,研究または,課題を進めていきます.
それぞれの用語の説明は以下の通りである.
•
リポジトリ
:
ファイルやディレクトリの状態を保存する場所
.
•
ローカルリポジトリ
:
自分のマシン内にあるリポジトリ
.
•
リモートリポジトリ
:
サーバなどネットワーク上にあるリポジトリ
.
•
コミット
(commit):
ファイルの追加や変更の履歴をリポジトリに保存すること
.
• origin:
リポジトリの場所
(URL)
の別名.
• master:
ブランチの名前.
•
プッシュ
(push):
ファイルの追加や変更の履歴をリモートリポジトリにアップロー
ドするための操作
.
2.2
コードテスト環境
ruby novice
では提出されたコードを開発現場で使用されている一般的なテスト環境で
テストする.本研究でモデルとしたテスト駆動開発ならびに比較検討したフレームワーク
を示す.
2.2.1
TDD (Test Driven Development)
2000
年代初期に開発手法として確立された「テスト駆動開発」(
Test Driven
Develop-ment
)は
,
その後
10
年もの間で普及が進み
,
今や珍しくない開発スタイルの
1
つとなって
いる
.
国内でも「アジャイルアカデミー」「
TDD Boot Camp
」などによる推進・普及活
動が各地で活発化し
,
認知が広がっている
[3].
テスト駆動開発は
,
簡単に言うとプログラムを書く前にテストコードを書くということ
です
.
プログラムが完成した後 にテストコードを書くのではなく
,
テストコードを先に書
くことに大きな意味があります
.
それは先に仕様を決め
,
テストコードを書くことによっ
て自分が次にやることが明確になるためです
.
これにより作業効率も上がります
.
最初に
いきなりプログラムを書くと
,
整理されていないプログラムが出来てしまいます
.
しかし
はじめにテストコードを書くことによって何をすべきか明確になるのでプログラムが書き
やすくなります
.
他に
TDD
の目的としては
,
軽快なフィードバックの確保
,
きれいで動く
コードの確保などによる開発の改善が挙げられます
.
テスト駆動開発は
,
テストファース
トによる追加・変更とリファクタリングによる設計改善という
2
つの活動で構成されま
す
.
継続的にユニットテストを使って設計検討やチェック
,
リファクタリングを行うこと
により
,
テスタビリティに優れバグの少ないソースコードを実現することができます
.
2.2.2
test::unit
とは
Ruby
用の
xUnit
系の単体テストフレームワークである
. Ruby1.8
までは
Ruby
本体
に標準添付されていたが
,Ruby1.9.1
からは
minitest
というフレームワークが標準添付さ
れている
. test-unit
が
Ruby1.8
に標準添付されていた頃はほとんど機能拡張などがされ
ず
,RSpec
など新しいテスティングフレームワークから見劣りするものとなっていた
.
し
かし
,Ruby
標準添付ではなく
,
1つのプロジェクトとして開発が進められるようになって
からは活発に開発が進められている
.Ruby
本体のバージョンアップに関係なく新しいバー
ジョンをリリースできるようになったことも開発が活発になった理由の一つである
[4].
2.2.3
aruba
とは
Aruba
は
Cucumber,RSpec,Minitest
のような人気のある
TDD/BDD
フレームワーク
でコマンドラインアプリケーションのテストを簡単で楽しいものにする拡張である.特徴
としては以下の通りである
[5]
.
•
どんな言語で実装されたコマンドラインツールでもテスト可能
.
–
テ ス ト 自 体 は
Ruby
で 書 く が
,
テ ス ト 対 象 は
,Python
の
CLI
ツ ー ル で も
Golang
の
CLI
ツールでもよい
.
•
ファイルシステムやプロセス環境をヘルパーによって操作できる
.
–
例えば
,read
でファイルを読み込みできる
.
–
例えば
,run
で外部コマンドを実行し
,
その結果を
have output matcher
など
で検証できる
.
•
ファイルシステムやプロセス環境はテストのたびにリセットされるので
,leaking
state
がない
.
–
例えばテスト中に作成されたファイルはテスト終了後には消えている
.
•
コミュ二ティーサポートが手厚い
.
•
ドキュメントにあるとおりに動作することが期待できる
[5].
3
開発ソフトの仕様と使用法
本研究で開発したソフト
ruby novice
は
1. ruby
の標準ライブラリ配布機構である
rubygems
に従っている
2. github
を使って生徒のレポート提出機構を提供している
3. aruba
によって生徒自身によるテスト機能を提供している
これらの使い方を理解していただくために,ここで少し詳しく紹介する.
3.1
ruby novice
の振る舞いと意義
ruby novice
は,情報環境である
GitHub
を利用し
Ruby
初心者が文法だけでなく,
Ruby
プログラミングにおける振舞いを身につけるための支援ソフトを開発する.また
Ruby
プログラミングで重要となるテスト駆動をおこなえる環境を提供している.これに
より,学習者自身が出力チェックできるようにし
Ruby
プログラミングにおけるテスト実
行に自然と慣れるような学習形態を目指している.
3.2
ruby novice
の仕組み
ruby novice
の構造は,図2のように3つに分かれています.
chap files.rb (chap1.rb, chap2.rb ...)
Text(
たのしい
Ruby)
のコードを書く部分
.
ruby novice.rb
chap files.rb
を呼び出している.
spec files.rb
run
で外部コマンドを入力して,出力結果
=
期待している値の検証.
テストコードが書いている
spec
ファイルを各章ごとに分け,
ruby novice.rb
で呼び出す
ことにより,章ごとにテストを実行することを可能にした.
以下が
ruby novice.rb
のコードの中身である
.
「たのしい
Ruby
」の1章に対応する
コードのみを抜粋している.
1 # r u b y _ n o v i c e . rb 2 3 $ L O A D _ P A T H . u n s h i f t F i l e . e x p a n d _ p a t h (" . . / . . / lib /#{ ENV [ ’ R U B Y N O V I C E _ N A M E ’]} ", _ _ F I L E _ _) 4 b e g i n 5 r e q u i r e " c h a p _ f i l e s " 6 r e s c u e L o a d E r r o r 7 p " L o a d ␣ E r r o r ␣ of ␣ e x _ f i l e s ␣ in ␣ r u b y n o v i c e . rb . "図
2
ruby novice
の構造.
8 p F i l e . e x p a n d _ p a t h (" . . / . . / lib /#{ ENV [ ’ R U B Y N O V I C E _ N A M E ’]} ", _ _ F I L E _ _) 9 e x i t 10 end 11 12 r e q u i r e " r u b y _ n o v i c e / v e r s i o n " 13 r e q u i r e ’ t h o r ’ 14 # r e q u i r e " c o d e " 15 16 m o d u l e R u b y N o v i c e 17 # Y o u r c o d e g o e s h e r e ... 18 19 c l a s s CLI < T h o r 20 # c l a s s _ o p t i o n : help , t y p e : : boolean , a l i a s e s : ’ - h ’ , d e s c : ’ h e l p . ’ 21 # c l a s s _ o p t i o n : debug , t y p e : : boolean , a l i a s e s : ’ - d ’ , d e s c : ’ d e b u g m o d e ’ 22 23 =b e g i n 24 d e s c ’ h e l l o ’, ’ p r i n t ␣ h e l l o ’ 25 def h e l l o 26 m y _ h e l l o 27 end28 =end 29 30 d e s c ’ m y _ h e l l o r u b y ’, ’ p r i n t ␣ h e l l o r u b y ’ 31 def m y _ h e l l o r u b y 32 h e l l o r u b y 33 end 34 35 d e s c ’ m y _ p u t s _ a n d _ p ’, ’ p r i n t ␣ p u t s _ a n d _ p ’ 36 def m y _ p u t s _ a n d _ p 37 p u t s _ a n d _ p 38 end 39 40 d e s c ’ m y _ k i r i t s u b o ’, ’ p r i n t ␣ k i r i t s u b o ’ 41 def m y _ k i r i t s u b o 42 k i r i t s u b o 43 end 44 45 d e s c ’ m y _ a r e a _ v o l u m e ’, ’ p r i n t ␣ a r e a _ v o l u m e ’ 46 def m y _ a r e a _ v o l u m e 47 a r e a _ v o l u m e 48 end 49 50 d e s c ’ m y _ c o m m e n t _ s a m p l e ’, ’ p r i n t ␣ c o m m e n t _ s a m p l e ’ 51 def m y _ c o m m e n t _ s a m p l e 52 c o m m e n t _ s a m p l e 53 end 54 55 d e s c ’ m y _ g r e a t e r _ s m a l l e r ’, ’ p r i n t ␣ g r e a t e r _ s m a l l e r ’ 56 def m y _ g r e a t e r _ s m a l l e r 57 g r e a t e r _ s m a l l e r 58 end 59 60 d e s c ’ m y _ g r e a t e r _ s m a l l e r _ e l s e ’, ’ p r i n t ␣ g r e a t e r _ s m a l l e r _ e l s e ’ 61 def m y _ g r e a t e r _ s m a l l e r _ e l s e 62 g r e a t e r _ s m a l l e r _ e l s e 63 end 64 65 d e s c ’ v e r s i o n ’, ’ v e r s i o n ’ 66 def v e r s i o n 67 p u t s R u b y N o v i c e :: V E R S I O N 68 end 69 70 p r i v a t e 71 72 def o u t p u t _ e r r o r _ i f _ d e b u g _ m o d e ( e ) 73 r e t u r n u n l e s s o p t i o n s [: d e b u g ] 74 S T D E R R . p u t s ( e . m e s s a g e ) 75 S T D E R R . p u t s ( e . b a c k t r a c e ) 76 end 77 end 78 end
code
を書き出している.
1 # s p e c _ c h a p 1 . rb 2 r e q u i r e ’ s p e c _ h e l p e r ’ 3 4 R S p e c . d e s c r i b e ’ r u b y _ n o v i e ␣ c o m m a n d ’, t y p e : : a r u b a do 5 c o n t e x t ’ v e r s i o n ␣ o p t i o n ’, t y p e : : v e r s i o n do 6 b e f o r e (: e a c h ) { run (’ r u b y _ n o v i c e ␣ v ’) } 7 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to b e _ s u c c e s s f u l l y _ e x e c u t e d } 8 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to h a v e _ o u t p u t (" 0 . 1 . 0 ") } 9 end 10 11 c o n t e x t ’ h e l p ␣ o p t i o n ’, t y p e : : h e l p do 12 e x p e c t e d = ‘ b u n d l e e x e c exe / r u b y _ n o v i c e help ‘ 13 b e f o r e (: e a c h ) { run (’ r u b y _ n o v i c e ␣ h e l p ’) } 14 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to b e _ s u c c e s s f u l l y _ e x e c u t e d } 15 # it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to h a v e _ o u t p u t ( e x p e c t e d ) } 16 end 17 18 =b e g i n 19 c o n t e x t ’ p r i n t ␣ h e l l o ’, t y p e : : h e l l o do 20 b e f o r e (: e a c h ) { run (’ r u b y _ n o v i c e ␣ h e l l o ’) } 21 e x p e c t e d = " H e l l o . " 22 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to b e _ s u c c e s s f u l l y _ e x e c u t e d } 23 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to h a v e _ o u t p u t ( e x p e c t e d ) } 24 end 25 =end 26 27 c o n t e x t ’ h e l l o r u b y ’, t y p e : : h e l l o r u b y do 28 b e f o r e (: e a c h ) { run (’ r u b y _ n o v i c e ␣ m y _ h e l l o r u b y ’) } 29 e x p e c t e d = " Hello , ␣ R u b y . " 30 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to b e _ s u c c e s s f u l l y _ e x e c u t e d } 31 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to h a v e _ o u t p u t ( e x p e c t e d ) } 32 end 33 34 c o n t e x t ’ p u t s _ a n d _ p ’, t y p e : : p u t s _ a n d _ p do 35 b e f o r e (: e a c h ) { run (’ r u b y _ n o v i c e ␣ m y _ p u t s _ a n d _ p ’) } 36 e x p e c t e d = " Hello ,\ n \ t R u b y .\ n \ "Hello ,\ n \ t R u b y .\" " 37 38 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to b e _ s u c c e s s f u l l y _ e x e c u t e d } 39 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to h a v e _ o u t p u t ( e x p e c t e d ) } 40 end 41 42 c o n t e x t ’ k i r i t s u b o ’, t y p e : : k i r i t s u b o do 43 b e f o r e (: e a c h ) { run (’ r u b y _ n o v i c e ␣ m y _ k i r i t s u b o ’) } 44 e x p e c t e d = "いづれの御時にか女御更衣あまたさぶらいたまいけるなかに\ nい と や\\ 45 ␣む ご と な き 際 に は あ ら ぬ が す ぐ れ て 時 め き た ま ふ あ り け り" 46 47 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to b e _ s u c c e s s f u l l y _ e x e c u t e d } 48 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to h a v e _ o u t p u t ( e x p e c t e d ) } 49 end 50 51 c o n t e x t ’ a r e a _ v o l u m e ’, t y p e : : a r e a _ v o l u m e do 52 b e f o r e (: e a c h ) { run (’ r u b y _ n o v i c e ␣ m y _ a r e a _ v o l u m e ’) } 53 e x p e c t e d = "表面積= 2 2 0 0 \ n体 積= 6 0 0 0 "54 55 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to b e _ s u c c e s s f u l l y _ e x e c u t e d } 56 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to h a v e _ o u t p u t ( e x p e c t e d ) } 57 end 58 59 c o n t e x t ’ g r e a t e r _ s m a l l e r ’, t y p e : : g r e a t e r _ s m a l l e r do 60 b e f o r e (: e a c h ) { run (’ r u b y _ n o v i c e ␣ m y _ g r e a t e r _ s m a l l e r ’) } 61 e x p e c t e d = " g r e a t e r " 62 63 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to b e _ s u c c e s s f u l l y _ e x e c u t e d } 64 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to h a v e _ o u t p u t ( e x p e c t e d ) } 65 end 66 67 68 c o n t e x t ’ g r e a t e r _ s m a l l e r _ e l s e ’, t y p e : : g r e a t e r _ s m a l l e r _ e l s e do 69 b e f o r e (: e a c h ) { run (’ r u b y _ n o v i c e ␣ m y _ g r e a t e r _ s m a l l e r _ e l s e ’) } 70 e x p e c t e d = " g r e a t e r " 71 72 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to b e _ s u c c e s s f u l l y _ e x e c u t e d } 73 it { e x p e c t ( l a s t _ c o m m a n d _ s t a r t e d ). to h a v e _ o u t p u t ( e x p e c t e d ) } 74 end 75 end
chap1 spec.rb
などが呼び出す
spec helper.rb
は以下の通りである.
$LOAD PATH
に
gem
の標準構造の場合に配置される
lib
を入れている.また,その後は
support directory
であるが,
RUBY
の
version
が古い場合にも対応するように設定している.
1 # s p e c _ h e l p e r . rb 2 $ L O A D _ P A T H . u n s h i f t F i l e . e x p a n d _ p a t h (’ . . / . . / lib ’, _ _ F I L E _ _) 3 r e q u i r e ’ r u b y _ n o v i c e ’ 4 # r e q u i r e ’ a r u b a / r s p e c ’ 5 $ L O A D _ P A T H . u n s h i f t F i l e . e x p a n d _ p a t h (’ . . / . . / lib ’, _ _ F I L E _ _) 6 7 if R U B Y _ V E R S I O N < ’ 1 . 9 . 3 ’ 8 :: Dir . g l o b (:: F i l e . e x p a n d _ p a t h (’ ../ s u p p o r t /*. rb ’, _ _ F I L E _ _)). e a c h { | f | r e q u i r e F i l e . j o i n ( F i l e . d i r n a m e ( f ) , F i l e . b a s e n a m e ( f , ’ . rb ’)) } 9 :: Dir . g l o b (:: F i l e . e x p a n d _ p a t h (’ ../ s u p p o r t / * * / * . rb ’, _ _ F I L E _ _)). e a c h { | f | r e q u i r e F i l e . j o i n ( F i l e . d i r n a m e ( f ) , F i l e . b a s e n a m e ( f , ’ . rb ’)) } 10 e l s e 11 :: Dir . g l o b (:: F i l e . e x p a n d _ p a t h (’ ../ s u p p o r t /*. rb ’, _ _ F I L E _ _)). e a c h { | f | r e q u i r e _ r e l a t i v e f } 12 :: Dir . g l o b (:: F i l e . e x p a n d _ p a t h (’ ../ s u p p o r t / * * / * . rb ’, _ _ F I L E _ _)). e a c h { | f | r e q u i r e _ r e l a t i v e f } 13 end3.3
ruby novice
の現状
現状は
,
「たのしい
Ruby
」の第
1
章 第
7
章までのテストコードを書き実装できる.各
章の概要は,以下の通りである.
•
第
1
章
(list1.1
1.7): puts
メソッドや
p
メソッド
•
第
3
章
(list3.1
3.11):
ファイルの読み込み
•
第
4
章
(list4.1):
ローカル変数とグローバル変数
•
第
5
章
(list5.1
5.5):
条件判断
(if, unless
など
)
•
第
6
章
(list6.1
6.13):
繰り返し
(for,times,while
など
)
•
第
7
章
(list7.1
7.4):
メソッド
3.3.1
注意
「たのしい
Ruby
」の課題では,通し番号以外に,コードに対応する適当なプログラム
名が付されている.しかし,
Rub
言語の予約語
(for,while
など
)
はコード中で使えないた
め,以下の問題は名前を変更して
”1”
をつけている.
• list5.3: unless.rb
→
unless1.rb
に変更.
• list5.4: case.rb
→
case1.rb
に変更.
• list6.4: for.rb
→
for1.rb
に変更.
• list6.6: while.rb
→
while11.rb
に変更
.
• list6.9: until.rb
→
until1.rb
に変更.
• list7.4: myloop.rb
→
myloop1.rb
に変更.
3.4
ruby novice
の作業の流れ
図
3
のように
Ruby
学習者は
Red, Green
という作業サイクルを繰り返してプログラミ
ングを進めていきます.
1.
作成したいプログラムの仕様を明確にする.
2. Red (
テストに失敗
)
3. Green(Red
の状態ならば,編集しテストを成功させるコードを書く
)
4. Green
になると次の問題に進む.
Red,Green
という言葉は
,TDD
で多用されるテスティングフレームワークの多くがテス
ト失敗を赤色表示で
,
テスト成功を緑色表示で通知することに由来している.図
4
がテス
トにパスした時の出力結果で,図
5
がテストに失敗した時の出力結果である.色を見るだ
けでテストをパスしているか失敗しているか一目瞭然である.
図
3
学習の流れ
.
3.5
ruby novice
の使用法
1.
自分の好きな名前
(koki)
をつけたディレクトリを作成する
.
2. ./lib/koki/chap files.rb
を準備する
.
3. chap files.rb
の中に
require ”chap1”
と書く
.
4. chap1.rb
というファイルを作り
,
そのファイルにたのしい
Ruby
1章の
list(1.1 1.7)
のコードを書いていく.
5. rspec
で,個人ごとの検査を実行する場合
,
環境変数
RUBYNOVICE NAME
にディ
レクトリ名
(koki)
を入れる
.
• (csh,tcsh)setenv RUBYNOVICE NAME koki
• (bash,zsh)export RUBYNOVICE NAME=koki
図
4
Green
の出力結果.
コード例
1 # / U s e r s / K o k i / r u b y _ n o v i c e % cat lib / k o k i / c h a p _ f i l e s . rb 2 3 r e q u i r e " c h a p 1 " 4 # r e q u i r e " c h a p 3 " 5 # r e q u i r e " c h a p 4 " 6 # r e q u i r e " c h a p 5 " 7 # r e q u i r e " c h a p 6 " 8 # r e q u i r e " c h a p 7 " 9 10 (注) # は コ メ ン ト ア ウ ト .コード例
(
たのしい
Ruby
第1章
)
1 # / U s e r s / K o k i / r u b y _ n o v i c e % cat lib / k o k i / c h a p 1 . rb 2 3 def h e l l o r u b y 4 p r i n t (" Hello , ␣ R u b y .\ n ") 5 end図
5
Red
の出力結果
.
6 7 def p u t s _ a n d _ p 8 p u t s " Hello ,\ n \ t R u b y . " 9 p " Hello ,\ n \ t R u b y . " 10 end 11 12 def k i r i t s u b o 13 p r i n t "いづれの御時にか女御更衣あまたさぶらいたまいけるなかに\ n " 14 p r i n t "いとやむごとなき際にはあらぬがすぐれて時めきたまふありけり\ n " 15 end 16 17 def a r e a _ v o l u m e 18 x = 10 19 y = 20 20 z = 30 21 a r e a = ( x * y + y * z + z * x ) * 2 22 v o l u m e = x * y * z 23 p r i n t "表面積= ", area , " \ n " 24 p r i n t "体積= ", volume , " \ n " 25 end26 27 def c o m m e n t _ s a m p l e 28 =b e g i n 29 「 た の し いR u b y 第 5 版 」 サ ン プ ル 30 コ メ ン ト の 使 い 方 の 例 31 2 0 0 6 / 0 6 / 1 6 作 成 32 2 0 0 6 / 0 7 / 0 1 一 部 コ メ ン ト を 追 加 33 2 0 1 5 / 1 0 / 0 1 第 5 版 用 に 更 新 34 =end 35 36 x = 10 # 縦 37 y = 20 # 縦 38 z = 30 # 高 さ 39 # 表 面 積 と 体 積 を 計 算 す る 40 a r e a = ( x * y + y * z + z * x ) * 2 41 v o l u m e = x * y * z 42 # 出 力 す る 43 p r i n t "表面積= ", area , " \ n " 44 p r i n t "体積= ", volume , " \ n " 45 end 46 47 def g r e a t e r _ s m a l l e r 48 a = 20 49 if a >= 10 t h e n 50 p r i n t " g r e a t e r \ n " 51 end 52 if a <= 9 t h e n 53 p r i n t " s m a l l e r \ n " 54 end 55 end 56 57 def g r e a t e r _ s m a l l e r _ e l s e 58 a = 20 59 if a >= 10 60 p r i n t " g r e a t e r \ n " 61 e l s e 62 p r i n t " s m a l l e r \ n " 63 end 64 end
3.5.1
tag
の表示の仕方
1. grep type spec/ruby novice spec.rb
で全ての
context
と
type
を表示
. type
は各章
の各問題名に相当する.各問題ごとにテストする時の便宜となる.
1 c o n t e x t ’ v e r s i o n ␣ o p t i o n ’, t y p e : : v e r s i o n do 2 c o n t e x t ’ h e l p ␣ o p t i o n ’, t y p e : : h e l p do 3 c o n t e x t ’ p r i n t ␣ h e l l o ’, t y p e : : h e l l o do 4 c o n t e x t ’ h e l l o r u b y ’, t y p e : : h e l l o r u b y do 5 c o n t e x t ’ p u t s _ a n d _ p ’, t y p e : : p u t s _ a n d _ p do 6 c o n t e x t ’ k i r i t s u b o ’, t y p e : : k i r i t s u b o do 7 c o n t e x t ’ a r e a _ v o l u m e ’, t y p e : : a r e a _ v o l u m e do8 c o n t e x t ’ c o m m e n t _ s a m p l e ’, t y p e : : c o m m e n t _ s a m p l e do 9 c o n t e x t ’ g r e a t e r _ s m a l l e r ’, t y p e : : g r e a t e r _ s m a l l e r do 10 c o n t e x t ’ g r e a t e r _ s m a l l e r _ e l s e ’, t y p e : : g r e a t e r _ s m a l l e r _ e l s e do 11 c o n t e x t ’ p r i n t _ a r g v ’, t y p e : : p r i n t _ a r g v do 12 c o n t e x t ’ h a p p y _ b i r t h ’, t y p e : : h a p p y _ b i r t h do 13 c o n t e x t ’ a r g _ a r i t h ’, t y p e : : a r g _ a r i t h do 14 c o n t e x t ’ r e a d _ t e x t ’, t y p e : : r e a d _ t e x t do 15 c o n t e x t ’ r e a d _ t e x t _ s i m p l e ’, t y p e : : r e a d _ t e x t _ s i m p l e do 16 c o n t e x t ’ r e a d _ t e x t _ o n e l i n e ’, t y p e : : r e a d _ t e x t _ o n e l i n e do 17 c o n t e x t ’ r e a d _ l i n e ’, t y p e : : r e a d _ l i n e do 18 c o n t e x t ’ s i m p l e _ g r e p ’, t y p e : : s i m p l e _ g r e p do 19 c o n t e x t ’ h e l l o _ r u b y 2 ’, t y p e : : h e l l o _ r u b y 2 do 20 c o n t e x t ’ u s e _ g r e p ’, t y p e : : u s e _ g r e p do 21 c o n t e x t ’ s c o p e t e s t ’, t y p e : : s c o p e t e s t do 22 c o n t e x t ’ a d 2 h e i s e i ’, t y p e : : a d 2 h e i s e i do 23 c o n t e x t ’ i f _ e l s i f ’, t y p e : : i f _ e l s i f do 24 c o n t e x t ’ u n l e s s 1 ’, t y p e : : u n l e s s 1 do 25 c o n t e x t ’ c a s e 1 ’, t y p e : : c a s e 1 do 26 c o n t e x t ’ c a s e _ c l a s s ’, t y p e : : c a s e _ c l a s s do 27 c o n t e x t ’ t i m e s ’, t y p e : : t i m e s do 28 c o n t e x t ’ t i m e s 2 ’, t y p e : : t i m e s 2 do 29 c o n t e x t ’ t i m e s 3 ’, t y p e : : t i m e s 3 do 30 c o n t e x t ’ f o r 1 ’, t y p e : : f o r 1 do 31 c o n t e x t ’ f o r _ n a m e s ’, t y p e : : f o r _ n a m e s do 32 c o n t e x t ’ w h i l e 1 ’, t y p e : : w h i l e 1 do 33 c o n t e x t ’ w h i l e 2 ’, t y p e : : w h i l e 2 do 34 c o n t e x t ’ w h i l e 3 ’, t y p e : : w h i l e 3 do 35 c o n t e x t ’ u n t i l 1 ’, t y p e : : u n t i l 1 do 36 c o n t e x t ’ w h i l e _ n o t ’, t y p e : : w h i l e _ n o t do 37 c o n t e x t ’ e a c h _ n a m e s ’, t y p e : : e a c h _ n a m e s do 38 c o n t e x t ’ e a c h ’, t y p e : : e a c h do 39 c o n t e x t ’ b r e a k _ n e x t ’, t y p e : : b r e a k _ n e x t do 40 c o n t e x t ’ t i m e s _ w i t h _ p a r a m ’, t y p e : : t i m e s _ w i t h _ p a r a m do 41 c o n t e x t ’ h e l l o _ w i t h _ n a m e ’, t y p e : : h e l l o _ w i t h _ n a m e do 42 c o n t e x t ’ h e l l o _ w i t h _ d e f a u l t ’, t y p e : : h e l l o _ w i t h _ d e f a u l t do 43 c o n t e x t ’ m y l o o p 1 ’, t y p e : : m y l o o p 1 do
3.6
全章のテストの仕方
1. bundle exec rspec
すべての章のテストを一括して実行できる.
3.7
各章ごとのテストの仕方
例
: 1
章
(chap1)
のテストをしたい時
.
2. bundle exec rake chap 1
実行例
1 / U s e r s / K o k i / r u b y _ n o v i c e % b u n d l e e x e c r a k e c h a p 1 2 3 r u b y _ n o v i e c o m m a n d 4 v e r s i o n o p t i o n 5 s h o u l d be s u c c e s s f u l l y e x e c u t e d 6 s h o u l d h a v e o u t p u t : " 0 . 1 . 0 " 7 h e l p o p t i o n 8 s h o u l d be s u c c e s s f u l l y e x e c u t e d 9 h e l l o r u b y 10 s h o u l d be s u c c e s s f u l l y e x e c u t e d 11 s h o u l d h a v e o u t p u t : " Hello , ␣ R u b y . " 12 p u t s _ a n d _ p 13 s h o u l d be s u c c e s s f u l l y e x e c u t e d 14 s h o u l d h a v e o u t p u t : " Hello ,\ n \ t R u b y .\ n \ "Hello ,\ n \ t R u b y .\" " 15 k i r i t s u b o 16 s h o u l d be s u c c e s s f u l l y e x e c u t e d 17 s h o u l d h a v e o u t p u t : "いづれの御時にか女御更衣あまたさぶらいたまいけるなか に\ nい と や む ご と な き 際 に は あ ら ぬ が す ぐ れ て 時 め き た ま ふ あ り け り" 18 a r e a _ v o l u m e 19 s h o u l d be s u c c e s s f u l l y e x e c u t e d 20 s h o u l d h a v e o u t p u t : "表面積= 2 2 0 0 \ n体 積= 6 0 0 0 " 21 c o m m e n t _ s a m p l e 22 s h o u l d be s u c c e s s f u l l y e x e c u t e d 23 s h o u l d h a v e o u t p u t : "表面積= 2 2 0 0 \ n体 積= 6 0 0 0 " 24 g r e a t e r _ s m a l l e r 25 s h o u l d be s u c c e s s f u l l y e x e c u t e d 26 s h o u l d h a v e o u t p u t : " g r e a t e r " 27 g r e a t e r _ s m a l l e r _ e l s e 28 s h o u l d be s u c c e s s f u l l y e x e c u t e d 29 s h o u l d h a v e o u t p u t : " g r e a t e r " 30 31 F i n i s h e d in 7 . 6 1 s e c o n d s ( f i l e s t o o k 1 . 0 3 s e c o n d s to l o a d ) 32 17 e x a m p l e s , 0 f a i l u r e s3.7.1
各問題ごとのテストの仕方
例
:
各問題
(helloruby)
ごとにテストをしたい時
.
1. bundle exec rspec –tag type:helloruby spec/ruby novice spec.rb (helloruby
は問
題名
)
2. bundle exec rake test name helloruby
実行例
1 / U s e r s / K o k i / r u b y _ n o v i c e % b u n d l e e x e c r a k e t e s t _ n a m e h e l l o r u b y 2 Run o p t i o n s : i n c l u d e {: t y p e = >" h e l l o r u b y "} 3 4 r u b y _ n o v i e c o m m a n d 5 h e l l o r u b y6 s h o u l d be s u c c e s s f u l l y e x e c u t e d 7 s h o u l d h a v e o u t p u t : " Hello , ␣ R u b y . "
8
9 F i n i s h e d in 0 . 8 7 1 2 8 s e c o n d s ( f i l e s t o o k 0 . 8 1 6 8 4 s e c o n d s to l o a d ) 10 2 e x a m p l e s , 0 f a i l u r e s
問題名は
,
上記の
grep type spec/ruby novice spec.rb
で調べることができる.
type
が各
問題の名前になる.また
text
の問題名
(
例えば
puts and p.rb)
が,そのまま使えるので
テストも簡単にでき,問題名で中身のコードの内容も把握できる.
3.7.2
各問題ごとの実行結果の出力
例
: helloruby
の実行結果の出力
1. bundle exec exe/ruby novice my helloruby
2. bundle exec rake/output helloruby
実行例
1 / U s e r s / K o k i / r u b y _ n o v i c e % b u n d l e e x e c r a k e o u t p u t h e l l o r u b y 2 Hello , R u b y .
4
考察
4.1
なぜ
aruba? (aruba vs test::unit)
Cucumber,RSpec,Minitest
のような人気のある
TDD/BDD
フレームワークの中でも
aruba
を使用した理由は以下の通りである.
test:unit
や
aruba
で書くとどうなるかを具
体的に書いたコードを比べて示していきます.
4.1.1
test::unit
で書いたテストコード
たのしい
Ruby
のテキストに記載されている問題で比較していきたいと思います.テキ
ストの最初の問題は,
Hello, Ruby
を出力するプログラムです.
print("Hello, Ruby.\n")
まず
,
出力される
Hello, Ruby
をテストする場合のコードです.
1 # h e l l o r u b y . rb 2 3 def h e l l o r u b y 4 r e t u r n " Hello , ␣ R u b y .\ n " 5 end• test::unit
で書いたテストコード
1 r e q u i r e ’ t e s t / u n i t ’ 2 r e q u i r e ’ ./ h e l l o r u b y ’ 3 4 c l a s s T e s t _ S a m p l e < T e s t :: U n i t :: T e s t C a s e 5 def t e s t _ h e l l o r u b y 6 a s s e r t _ e q u a l (" Hello , ␣ R u b y .\ n ", h e l l o r u b y ) 7 end 8 end 9 p r i n t (" Hello , ␣ r u b y .\ n ")テストコードの内容は以下の通りである.
Ruby
で代表的な
test/unit
という
gem
が提供
されています.このプログラムの始め(
require ’test/unit’
)で,
test/unit
を呼び出しま
す.
Test::Unit::TestCase
を継承したクラスを用意し、
test xxx
というメソッドを定義す
るとそのメソッドがテストの実行対象になり
,
ここではそれぞれ
Test Sample
クラスと
test helloruby
メソッドがそれに該当します。クラス名は大文字から始めるという規則が
せん.ここでは単純に
test helloruby
としています.実行してみると分かりますが,
test
がないとちゃんと動いてくれません.テストコードは,
assert equal(
期待値
),(
実際の値
)
で実行結果を検証します
.assert equal
は,ふたつの引数をとり,第1引数は期待している
結果で,第2引数はテストの対象です.両者が一致すればテストをパスし
,
一致しない場
合はテストが失敗する
.
補足ですが,
test xxx
というメソッドはクラス内に複数あっても
構いません
.
また、
1
つのテストメソッド内に
assert equal
を複数書くのも
OK
です
.
(と
はいえ、原則として
1
テストメソッドにつき
1
アサーションとするのが望ましい)
このテストを実行すると以下のような出力になります.
1 / U s e r s / K o k i / r u b y n o v i c e / s p e c / t e s t _ u n i t / l i s t 1 % r u b y t e s t _ h e l l o r u b y . rb 2 Hello , r u b y . 3 L o a d e d s u i t e t e s t _ h e l l o r u b y 4 S t a r t e d . 5 6 F i n i s h e d in 0 . 0 0 0 9 8 2 s e c o n d s . 7 8 1 tests , 1 a s s e r t i o n s , 0 f a i l u r e s , 0 errors , 0 p e n d i n g s , 0 o m i s s i o n s , 0 n o t i f i c a t i o n s 9 1 0 0 % p a s s e d 10 11 1 0 1 8 . 3 3 t e s t s / s , 1 0 1 8 . 3 3 a s s e r t i o n s / s4.1.2
test::unit
での問題点
この場合だと初心者である
Ruby
の学習者がスクリプトとテストコードを同時に書かな
ければならない.学習者は,テストコードの書き方も学ぶ必要があるので,学習コストや
間違えるリスクが大きくなる.一番の問題点は,テキストを見ながら,その問題通りに
書けないということです.先ほどの問題で説明すると,コードに
return
を付け加えなけ
ればならないことや,
メソッドは
return
できないので,テストするときは
return
”Hello, Ruby.
n”
と書き換えなければなりません.このように
test::unit
だとメソッドを書き換えないと
いけないことや,
メソッドを
return
で返すことができないというデメリットがあ
る.そこで
aruba
は
をそのまま出力できテストが可能である.学習者が
text
(たの
しい
Ruby
)を見ながら書いていけるというメリットがあるので学習コストや間違えるリ
スクを削減できます.実際に
aruba
で書いたコードを元にして具体的に示します.
4.1.3
aruba
で書いたテストコード
1 # c o d e . rb 2 3 def h e l l o r u b y 4 p r i n t (" Hello , ␣ R u b y .\ n ") 5 end 1 # r u b y _ n o v i c e . rb 2 3 r e q u i r e ’ t h o r ’ 4 r e q u i r e " c o d e . rb " 5 6 m o d u l e R u b y N o v i c e 7 c l a s s CLI < T h o r 8 d e s c ’ m y _ h e l l o r u b y ’, ’ p r i n t ␣ h e l l o r u b y ’ 9 def m y _ h e l l o r u b y 10 h e l l o r u b y 11 end 12 end