検索
連載

Rubyで逆ポーランド変換機を作りgem作成&コマンドの使い方若手エンジニア/初心者のためのRuby 2.1入門(13)(4/4 ページ)

オープンソースのオブジェクト指向プログラミング言語「Ruby」の文法を一から学ぶための入門連載。最新版の2.1に対応しています。連載最終回の今回は、小規模なgemの作成にチャレンジしてみましょう。gem作成の一連の流れを体験するために、逆ポーランド記法による計算機アプリケーションを作ってみましょう。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
前のページへ |       

RSpecで簡単なユニットテストを書いてみる

 たいていのgemにはユニットテストが用意されていて、ソースコードに変更を加えた後のテストを自動化しています。Rubyで使えるテストフレームワークにはさまざまなものがありますが、姉妹連載の「開発現場でちゃんと使えるRails 4入門」にならい、「RSpec」を使うこととします。RSpecの基本的な概念や使い方は、記事「RailsテストフレームワークRSpecのインストールと基本的な使い方、基礎文法」を参照してください。

StackCalculatorのテストコード

 テストコードは「/spec」ディレクトリ以下に配置します。「/lib/rpn_calculator/stack_calculator.rb」に対するテストコードは、「/spec/rpn_calculator/stack_calculator_spec.rb」として配置します。

require "spec_helper"
 
RSpec.describe RpnCalculator::StackCalculator do
  describe "#calc" do
    # simple patterns
    context "-2 3 +" do
      subject { RpnCalculator::StackCalculator.new(["-2", "3", "+"]).calc }
      it { expect(subject).to eq 1.0 }
    end
 
    context "-2 3 -" do
      subject { RpnCalculator::StackCalculator.new(["-2", "3", "-"]).calc }
      it { expect(subject).to eq -5.0 }
    end
 
    context "-2 3 *" do
      subject { RpnCalculator::StackCalculator.new(["-2", "3", "*"]).calc }
      it { expect(subject).to eq -6.0 }
    end
 
    context "-2 3 /" do
      subject { RpnCalculator::StackCalculator.new(["-2", "3", "/"]).calc }
      it { expect(subject).to eq (-2.to_f / 3.to_f) }
    end
 
    # complex pattern
    context "2.7 1.1 - -5.2 0.9 + *" do
      subject { RpnCalculator::StackCalculator.new(["2.7", "1.1", "-", "-5.2", "0.9", "+", "*"]).calc }
      it { expect(subject).to eq -6.88 }
    end
  end
 
  describe "#numeric?" do
    context "the argument can be converted to float" do
      subject { RpnCalculator::StackCalculator.new([]).send(:numeric?, "3.14") }
      it { expect(subject).to be true }
    end
 
    context "the argument can not be converted to float" do
      subject { RpnCalculator::StackCalculator.new([]).send(:numeric?, "+") }
      it { expect(subject).to be false }
    end
  end
end
/spec/rpn_calculator/stack_calculator_spec.rb

 6行目から31行目にかけて、calcメソッドのテストが記述されています。基本的な四則演算と、少し複雑な例をテストケースとして用いています。

 加えて、33行目から43にかけてnumeric?メソッドのテストが記述されています。numeric?メソッドはprivateになっているので、そのままでは呼び出すことができません。そこで、35行目と40行目では、sendメソッドを用いることでnumeric?メソッドを呼び出し、テストしています。

RnpCalculatorモジュールのテストコード

 せっかくなので、RnpCalculatorクラスのクラスメソッド「run」のテストも書いておきましょう。

 標準出力の内容をテストしたいので、「/rnp_calculator.gemspec」の「spec.add_development_dependency "rspec"」の下に、以下の1行を加えてください。

spec.add_development_dependency "ariete"

 「Ariete」は、筆者が開発しているgemで、RSpecを拡張して標準出力や標準エラー出力をキャプチャしてテストできるようになります。

 「/rnp_calculator.gemspec」に上述の1行を書き加えたら、あらためて以下のコマンドで依存ライブラリをインストールしてください。

$ bundle install --path vendor/bundle

 次に、RSpecでArieteを有効にするために、「/spec/spec_helper.rb」を編集します。最終行の「require 'ariete'」がポイントです。

$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
require 'rpn_calculator'
require 'ariete'
/spec/spec_helper.rb

 RnpCalculatorモジュールのテストコードは以下のようになります。

require "spec_helper"
 
RSpec.describe RpnCalculator do
  describe ".run" do
    subject { -> { RpnCalculator.run(["2.7", "1.1", "-", "-5.2", "0.9", "+", "*"]) } }
    it { expect(subject).to be_output "-6.88\n" }
  end
end
/spec/rnp_calculator_spec.rb

 ArieteのRSpec拡張によって、be_outputというRSpecの述語が使えるようになります。be_outputを使うことで、6行目のように、標準出力に出力された内容と期待値を比較し、一致するか異なっているかを調べることができます。

テストの実行

 では、RSpecによるテストを実行してみましょう。以下のコマンドを実行してみてください。

$ bundle exec rspec

 全てのテストにパスし、以下のような出力が得られたら成功です!

RpnCalculator::StackCalculator
  #calc
    -2 3 +
      should eq 1.0
    -2 3 -
      should eq -5.0
    -2 3 *
      should eq -6.0
    -2 3 /
      should eq -0.6666666666666666
    2.7 1.1 - -5.2 0.9 + *
      should eq -6.88
  #numeric?
    the argument can be converted to float
      should equal true
    the argument can not be converted to float
      should equal false
 
RpnCalculator
  .run
    should be output "-6.88\n"
 
Finished in 0.00499 seconds (files took 0.11788 seconds to load)
8 examples, 0 failures

 もしテストに失敗した場合は、失敗したテストケースのエラーメッセージを読んで、適宜修正してください。

gemのパッケージを生成する

 以上でアプリケーションそのものはひと通り完成です。最後に、作成したアプリケーションをパッケージ化して、.gemファイルを生成してみましょう。以下のコマンドを実行してみてください。

$ bundle exec rake build

 ビルドに成功すると、「/pkg/rpn_calculator-0.0.1.gem」というファイルが生成されます。

 生成したgemを他の環境にインストールしたい場合は、以下のようにgemコマンドでインストールできます。

$ gem install rpn_calculator-0.0.1.gem

 インストールが完了すると、以下のようにして逆ポーランド記法計算機を使えるようになります。

$ rpn_calculator 2 3 +
5.0

さらに使いやすく改良してみよう

 ここまでの作業で、それっぽい逆ポーランド記法による計算機を作ることができました。しかしながら、改良すべき点はたくさんあります。

 改良点の一つの例として、以下のようなコマンドを実行してみましょう。

$ bundle exec bin/rpn_calculator 5 3 $

 すると、以下のような出力が得られるでしょう。

/Users/flost/var/repo/diy/ruby/rpn_calculator/lib/rpn_calculator/stack_calculator.rb:15:in `block in calc': undefined method `$' for 5.0:Float (NoMethodError)
        from /Users/flost/var/repo/diy/ruby/rpn_calculator/lib/rpn_calculator/stack_calculator.rb:9:in `each'
        from /Users/flost/var/repo/diy/ruby/rpn_calculator/lib/rpn_calculator/stack_calculator.rb:9:in `calc'
        from /Users/flost/var/repo/diy/ruby/rpn_calculator/lib/rpn_calculator.rb:8:in `run'
        from bin/rpn_calculator:5:in `<main>'

 エラーメッセージを見てみると、例外NoMethodErrorが出ています。これは、数式の最初の5.0に対して、「$」という存在しないメソッドを実行しようとしたことが原因です。

 使えない演算子を使おうとしたユーザーの責任だとも言えますが、使い勝手を上げるためにも、この例外をキャッチして適切なエラーメッセージを出力すべきでしょう。

 rpn_calculatorは筆者のGitHubリポジトリに置いてあります。GitHubでのソーシャルコーディングの練習がてら、素敵な改良やバグ修正をしたら、ぜひプルリクエストを送ってください。一緒にrpn_calculatorを育てていきましょう!

連載の終わりに

 連載最終回となる今回は、これまでの総まとめとして簡単な逆ポーランド記法による計算機を作り、gemとしてパッケージ化しました。本連載の知識を総動員すれば、素敵なアプリケーションやライブラリを作って公開できるでしょう!

 今回を持ちまして、本連載は終了となります。私の不慣れなつたない草稿に温かい指摘をくださった関係者の皆さま、そしてこれを今まさに読んでくださっている読者の皆さまに感謝いたします。ここまで連載を続けてこられたのも、皆さまの支えがあったからこそです。

 本連載を通じて、変幻自在なRubyの面白さと、日々のエンジニアライフに生かすことのできるRubyの技術が少しでも伝われば幸いです。

監修者より

 本連載と「開発現場でちゃんと使えるRails 4入門」連載の監修者の山根です。今回を持ちまして、Ruby連載とRails連載はともには終了になります。今回初めての経験の監修業ということで、執筆者の麻田さん、林さんはじめ、記事を読んでくださった読者の皆さま方には本当に感謝をしています。本連載が、皆さま方のプログラミングライフの質と幸福度を向上する一助となれば、執筆関係者一同、これ以上の幸せはありません。ありがとうございました。

著者プロフィール

麻田 優真(Rails技術者認定シルバー試験問題作成者)

イタリア、ローマ生まれ。中学生のころHSPに初めて触れ、プログラミングの楽しさを知る。オープンソースやハッカーカルチャーを好む。C#からRubyに転向したときに、動的型付け言語の柔軟性やメタプログラミングの魅力に感動し、Rubyとともにプログラマーとしての人生を歩む決意を固める。

現在は奈良先端科学技術大学院大学で学生として所属するかたわら、株式会社アジャイルウェアでプログラマーとして従事。Ruby on Railsによるコンシューマー向けのWebサービスの開発などに尽力している。

好きなメソッドは、define_method。

Twitter:@Mozamimy、ブログ:http://blog.quellencode.org/


監修者プロフィール

山根 剛司(Ruby業務開発歴7年)

兵庫県生まれ。1997年からベンチャー系のパッケージベンダーで10年間勤務。当時、使用していた言語はJavaとサーバーサイドJavaScript。

2007年よりITコンサル会社に転職し、Rubyと出会って衝撃を受ける。基幹システムをRuby on Railsで置き換えるプロジェクトに従事。それ以来Ruby一筋で、Ruby on Railsのプラグインやgemも開発。

2013年より、株式会社アジャイルウェアに所属。アジャイルな手法で、Ruby on Railsを使って企業向けシステムを構築する業務に従事。

Ruby関西所属。

Twitter:@spring_kuma、Facebook:山根 剛司


Copyright © ITmedia, Inc. All Rights Reserved.

前のページへ |       
ページトップに戻る