TDDBC福岡でRubyとRSpecを用いたTDDを見て、かなり興味が湧きまして、そして少し触ってみることにしました。元々、「次にWebアプリ系を触るときはRubyをやる!」という気持ちはあったので、これも何かの縁と思ってやりました。
1日触ったくらいですが、RSpecはユニットテストのフレームワークというより、BDD(Behavior Driven Development, 振る舞い駆動開発)のフレームワークと言った方がしっくりくる感じがしました。(単純にそのように感じたというだけです。テストというより振る舞いを決めている、という感じが強かったからでしょうか)。
今回の課題は某日経ソフトウェアという雑誌の課題から拝借しまして行いました。ちなみにその某雑誌の方ではC(かC++)で解答がついています。私は見てませんが(笑)
課題内容ですが、36進数を10進数にする、というもの。
base36_spec.rb
require 'base36' def trans_spec(name, actual, expected) context name do subject { Base36.new(actual).decimal } it { should == expected } end end describe Base36 do trans_spec("with z", "z", 35) trans_spec("with 10", "10", 36) trans_spec("with aaaa", "aaaa", 479890) trans_spec("with Z", "Z", 35) trans_spec("with _", "_", -1) end
base36.rb
class Base36 def initialize(str) @strData = str end def digitToDecimal(chr) if chr =~ /\d+/ then return chr.to_i elsif chr =~ /[a-z]/ then return chr.bytes.to_a[0] - "a".bytes.to_a[0] + 10 elsif chr =~ /[A-Z]/ then return chr.bytes.to_a[0] - "A".bytes.to_a[0] + 10 else return -1 end end def decimal() strArray = @strData.split(//) i, retnum = 1, 0 for str in strArray do if digitToDecimal(str) < 0 then return -1 else retnum += digitToDecimal(str) * (36**(strArray.length - i)) i += 1 end end return retnum end end
テストコード側はかなり重複除去を進めています。実装側のコードのリファクタリングが足りない気もします。パラメタライズドテストみたくなったのは気のせいだと思います。重複を除去しようと頑張った結果です。
仕様として記号などの文字が入っていた場合に-1を返すようにしているのがあまり好きではないです。また、ASCII文字以外の文字が入っていた場合は完全にエラーという処理になります。このあたりも対処法があるのであれば直したいところです。
Ruby自体にも慣れていないのでこのコードを書くだけで随分と時間をとってしまいました。実際にはRubyに標準で任意の基数への変換のメソッドが存在するので今回のコードは練習用でしかないです。
Rubyの書き方というものに慣れていないので、微妙なコードになっている気がしてなりません。いわゆる「動くけど…」という状態です。このあたりは他の人のよいコードを見ながら学んでいくしかなさそうです。
今回Rubyを始めて、Ruby自体の感想としては今回のコードでも用いましたが、Rubyの簡単に行える正規表現の判定はすごく便利でした。このあたりはWebアプリやスクリプトでは重宝しそうです。
ちなみに今回のコードを書くにあたり、Ruby入門、Rubyist Magazine、id:t-wadaさんのRSpec の入門とその一歩先へは大変参考になりました。とくにid:t-wadaさんのRSpecの解説は丁寧で初心者でもRubyist Magazineの記事を読んでいるだけでRSpecの初歩が分かるように書かれています。また私はまだRailsを全く触っていないので何とも言えませんが、Rubyist Magazineの記事にはRSpec on Railsも書かれています(というよりは基本的にそれが主)。Railsをやっている方も参考になると思います。ぜひ、RSpec初心者の方はこの2つの記事は参考にしてみてください。