10の練習問題をやってみよう(五日目)

新しくプログラミング言語を覚えたいときに行うべき10の練習問題
実際にやってみよう。

第四問

簡易電卓。0で割ったときの処理を自分なりに作りこむ。


こういう電卓クラスを作ろぞー

メソッドを定義するメソッドというものを作りたい。

  def_push_nums 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

ってやったら

  def push_0
    @disp = @disp * 10 + 0
  end
  
  def push_1
    @disp = @disp * 10 + 1
  end

  ...

こんなメソッドが定義されるようにしたい

define_method

Googleさんに聞いたところ「define_method」っていうメソッドを使うと実現できるらしい。

    define_method("push_0") { @disp = @disp * 10 + 0 }

って書くと

    def push_0
      @disp = @disp * 10 + 0
    end

↑のようなメソッドが定義されるみたいだ。

やってみよう

上の例を応用して、「push_0」〜「push_9」までのメソッドを一気に定義してしまおう。

class Calc
  
  def_push_nums 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  
  def def_push_nums(*nums)
    nums.each{ |num| define_method("push_#{num}") { @disp = @disp * 10 + num } }
  end

end

これでいいはずだ。いけー!

calc.rb:3: undefined method `def_push_nums' for Calc:Class (NoMethodError)
( ゚д゚) ・・・

ダメだった

「def_push_nums」が定義されていませんって言われてしまった。クラスを定義する時点で「def_push_nums」が定義されていないからダメということなんだろうなあ。
じゃあなんで「attr_accessor」はダメじゃないんだろう。不公平だー!
調べてみたところ、「attr_accessor」はModuleクラスのメソッドでした。そしてClassクラスはModuleクラスを継承しているらしい。しかる故にClassクラスのインスタンスである全てのクラスは、最初から「attr_accessor」を使うことができるのでありました。

わからん!

あまりにも分からなすぎて泣きたくなってきた。

やり直し

深入りしすぎたようだ。簡単に実装できる方法に切り替えよう。

class Calc
  
  def initialize
    @disp = 0;
  end
  
  def push(num)
    @disp = @disp * 10 + num
  end
  
  def display
    @disp
  end
  
end

テストケースも書き直し

$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..' , 'lib')

require 'test/unit'
require 'calc'

# 電卓クラスのテストケース
class TestCalc < Test::Unit::TestCase
  
  # 初期化メソッド。各テストメソッドの前に実行される。
  def setup
    @calc = Calc.new
  end
  
  # 数字ボタンのテスト [0] [1] [0] の順に押す
  def test_push_0
    assert_equal(0, @calc.push(0))
    assert_equal(0, @calc.display)
    
    assert_equal(1, @calc.push(1))
    assert_equal(1, @calc.display)
    
    assert_equal(10, @calc.push(0))
    assert_equal(10, @calc.display)
  end
  
end

よっしゃ。テスト通ったー。今日はココまで

思ったこと

電卓クラスはいつになったら完成するんだ(トホホ・・・)