fibonacci
rubocop にかかれば以下のコードも
require './assert_equal'
def fib(n)
if n==0
return 0
end
end
puts assert_equal(0, fib(0))
良い感じに整形してくれます :)
# frozen_string_literal: true
require './assert_equal'
def fib(n)
0 if n.zero?
end
puts assert_equal(0, fib(0))
return の挙動
fibonacci に n==1の場合を追加する。
# frozen_string_literal: true
require './assert_equal'
def fib(n)
0 if n.zero?
1 if n == 1
end
puts assert_equal(0, fib(0))
puts assert_equal(1, fib(1))
しかし、これだとテストに失敗する
expected: 0
result:
failed in assert_equal.
expected: 1
result: 1
succeeded in assert_equal.
最後の行のみ return が暗黙に付加される仕様なのかな?n に 0 が渡されたときは、最初の行がreturn されることなく、次の行で nil が返されてるっぽい。というわけで、素朴に以下のように書いてみる
# frozen_string_literal: true
require './assert_equal'
def fib(n)
if n==0
return 0
end
if n==1
return 1
end
end
puts assert_equal(0, fib(0))
puts assert_equal(1, fib(1))
rubocop を通すと、
# frozen_string_literal: true
require './assert_equal'
def fib(n)
return 0 if n.zero?
1 if n == 1
end
puts assert_equal(0, fib(0))
puts assert_equal(1, fib(1))
うーん、なんか汚くね?というわけでcase文つかってみる。
# frozen_string_literal: true
require './assert_equal'
def fib(n)
case n
when 0
0
when 1
1
end
end
puts assert_equal(0, fib(0))
puts assert_equal(1, fib(1))
expected: 0
result: 0
succeeded in assert_equal.
expected: 1
result: 1
succeeded in assert_equal.
OK.こういうとき、テストのありがたさを実感する。
n<=2
case 文は値を評価するのであって、n <= 2 みたいな式には対応できない。ので以下のように書くとテストに失敗する。(bool 値を評価しているから、のはず)
# frozen_string_literal: true
require './assert_equal'
def fib(n)
case n
when 0
0
when n <= 2
1
end
end
[[0, 0], [1, 1], [2, 1]].each do |pair|
puts assert_equal(pair[0], fib(pair[1]))
end
というわけで以下に直す。
# frozen_string_literal: true
require './assert_equal'
def fib(n)
return 0 if n.zero?
return 1 if n <= 2
end
[[0, 0], [1, 1], [2, 1]].each do |pair|
puts assert_equal(pair[1], fib(pair[0]))
end
これ、最初の行の if が false なら return そのものが実行されないってなかなか直感に反するなぁ。if が false なら returnがなかったことになるってことか…?
完成
以下が完成形。
# frozen_string_literal: true
require './assert_equal'
def fib(n)
return 0 if n.zero?
return 1 if n == 1
return fib(n - 1) + fib(n - 2)
end
[[0, 0], [1, 1], [2, 1], [3, 2], [4, 3], [5, 5], [6, 8], [7, 13], [8, 21]].each do |index, expected|
puts assert_equal(expected, fib(index))
end
でもrubocopに通すと fib の最後の return をなくされる。
# frozen_string_literal: true
require './assert_equal'
def fib(n)
return 0 if n.zero?
return 1 if n == 1
fib(n - 1) + fib(n - 2)
end
[[0, 0], [1, 1], [2, 1], [3, 2], [4, 3], [5, 5], [6, 8], [7, 13], [8, 21]].each do |index, expected|
puts assert_equal(expected, fib(index))
end
規則性が乱れるような感じで、やや気持ち悪いのだが、rubocop が言うならしゃーない…か
assert_equal の class化
# frozen_string_literal: true
require 'colorize'
class String
def assert_equal(n)
to_i == n
end
def assert_not_equal(n)
to_i != n
end
end
class Integer
def assert_equal(n)
self == n
end
def assert_not_equal(n)
self != n
end
end
if $PROGRAM_NAME == __FILE__
p '3'.assert_equal(3)
p 4.assert_equal(4)
end
% ruby assert_equal_class.rb
true
true
- source ~/ghq/github.com/TeamNishitani/grad_members_20f/members/syasin-5d/10th.org