Rubyで逆ポーランド変換機を作りgem作成&コマンドの使い方:若手エンジニア/初心者のためのRuby 2.1入門(13)(4/4 ページ)
オープンソースのオブジェクト指向プログラミング言語「Ruby」の文法を一から学ぶための入門連載。最新版の2.1に対応しています。連載最終回の今回は、小規模なgemの作成にチャレンジしてみましょう。gem作成の一連の流れを体験するために、逆ポーランド記法による計算機アプリケーションを作ってみましょう。
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
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'
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
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連載はともには終了になります。今回初めての経験の監修業ということで、執筆者の麻田さん、林さんはじめ、記事を読んでくださった読者の皆さま方には本当に感謝をしています。本連載が、皆さま方のプログラミングライフの質と幸福度を向上する一助となれば、執筆関係者一同、これ以上の幸せはありません。ありがとうございました。
- Rubyで逆ポーランド変換機を作りgem作成&コマンドの使い方
- 難しいが強力! Rubyのメタプログラミング、self、特異クラス/メソッド、オープンクラスとモンキーパッチ
- RubyのThread、Fiber、Kernel、forkで並列処理やプロセスの深淵へ
- RubyのFile/IOクラスで入力と出力、ファイルの読み取りと書き込み、フィルター作成
- Rubyの例外とその捕捉――基本のbegin〜rescue〜endからensure、else、retry、後置rescueまで
- Rubyの面白さを理解するためのメソッド、ブロック、Proc、lambda、クロージャの基本
- Rubyのオブジェクト指向におけるクラスとモジュール、継承、Mixin、アクセス制御の使い方
- RubyのNumericとTimeで数値と時間をさまざまな操作・演算・判定
- RubyのString/Regexpクラスによる強力な文字列操作/正規表現
- RubyのRangeクラスと範囲オブジェクト、範囲演算子、イテレーターの使い方
- Rubyの配列、ハッシュテーブルを表現するArray、Hashクラスの使い方
- Ruby 2.1の基本構文/基本文法まとめ&Pryの使い方
- Rubyプログラミングを始めるための基礎知識とインストール
著者プロフィール
麻田 優真(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.
関連記事
- 数々の“スペル”で高度なプログラミング:Rubyの魔術
- 公用語に英語、「再起動」したRubyKaigi 2013が東京で開催
いったん終了していたRubyコミュニティ主催の年次イベントが再開。技術色、国際色を強め、盛況のうちに幕を閉じた - Web業界、今から行くならRubyエンジニアが狙い目?
不況で冷え込んでいたIT業界の転職市場に、回復の兆しが見え始めている。だが、業種や職種によって採用数や条件に大きな差異が生まれている。転職市場の動向を追い、自身のキャリア戦略立案に生かしてほしい。 - Ruby 2.0.0がリリース、大規模化対応の機能などを搭載
生誕20年となる節目を迎えて、プログラミング言語「Ruby」の最新版がリリースされた - 新バージョンで何が変わるのか、Rubyはどこへ向かうのか:まつもと×笹田、Ruby 1.9を語る
- いよいよ始まるRuby 1.9への移行:開発コアメンバが語るRubyの今とこれから(前編)
- Rubyの今後の進化の方向性とは?:開発コアメンバが語るRubyの今とこれから(後編)
- 互換性や脆弱性の問題にどう対応していくのか:Rubyが抱える課題、NaClの前田氏が講演
- Rails Hub情報局:「なんでRubyなんか作った!? 迷惑だ!」に対するMatzの答え
- Rails Hub情報局:Rubyはイノベーション言語として選ばれている
- Rails Hub情報局:Rubyのまつもと氏は、一発屋で終わるのか?
- Rails Hub情報局:Rubyに魔法は要らない
- 数々の“スペル”で高度なプログラミング:Rubyの魔術
- 晴読雨読@エンジニアライフ:『たのしい開発 スタートアップRuby』――なぜRubyistたちはあれほど楽しそうなのか
- 「JRuby 1.7.0」登場、1年半ぶりのメジャーアップデート
JavaVM上のRuby実装「JRuby」の最新版となる「JRuby 1.7.0」が、10月22日にリリースされた。