module Factorial

  def Factorial.iterative ( x )
    if x.to_i != x then raise ArgumentError , 'Parameter must be an integer.' end
    if x < 0 then raise ArgumentError , 'Parameter must be a non-negative integer.' end
    total = 1
    ( 2..x ).each { | i | total *= i }
    total
  end

  def Factorial.recursive ( x )
    if x.to_i != x then raise ArgumentError , 'Parameter must be an integer.' end
    if x < 0 then raise ArgumentError , 'Parameter must be a non-negative integer.' end
    x <= 1 ? 1 : x * recursive( x - 1 )
  end

  def Factorial.tailRecursive ( x )
    if x.to_i != x then raise ArgumentError , 'Parameter must be an integer.' end
    if x < 0 then raise ArgumentError , 'Parameter must be a non-negative integer.' end
    iterate = lambda { | i , result |  i <= 1 ? result : iterate.call( i - 1 , result * i ) }
    iterate.call( x , 1 )
  end

end

