Permalink
Browse files

Made TypeError messages even more useful

Telling the developers about what value failed to convert is even better
than just saying something went wrong: developers will know the exact
value that caused the failure.
  • Loading branch information...
francois committed May 20, 2015
1 parent 7966b06 commit fb1a9693a2c9a9f8bcf6fb32aaf7a6943963a035
Showing with 76 additions and 48 deletions.
  1. +49 −21 lib/lotus/utils/kernel.rb
  2. +27 −27 test/kernel_test.rb
View
@@ -140,7 +140,7 @@ def self.Set(arg)
Set.new(::Kernel.Array(arg))
end
rescue NoMethodError
raise TypeError.new("can't convert into Set")
raise TypeError.new("can't convert #{inspect_type_error(arg)}into Set")
end
# Coerces the argument to be a Hash.
@@ -205,7 +205,7 @@ def self.Hash(arg)
super(arg)
end
rescue NoMethodError
raise TypeError.new "can't convert into Hash"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Hash"
end
else
def self.Hash(arg)
@@ -217,7 +217,7 @@ def self.Hash(arg)
super(arg)
end
rescue ArgumentError, NoMethodError
raise TypeError.new "can't convert into Hash"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Hash"
end
end
@@ -336,13 +336,13 @@ def self.Integer(arg)
when NilClass, ->(a) { a.respond_to?(:to_i) && a.to_s.match(NUMERIC_MATCHER) }
arg.to_i
else
raise TypeError.new "can't convert into Integer"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Integer"
end
rescue NoMethodError
raise TypeError.new "can't convert into Integer"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Integer"
end
rescue RangeError
raise TypeError.new "can't convert into Integer"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Integer"
end
# Coerces the argument to be a BigDecimal.
@@ -426,10 +426,10 @@ def self.BigDecimal(arg)
when ->(a) { a.to_s.match(NUMERIC_MATCHER) }
BigDecimal.new(arg)
else
raise TypeError.new "can't convert into BigDecimal"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into BigDecimal"
end
rescue NoMethodError
raise TypeError.new "can't convert into BigDecimal"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into BigDecimal"
end
# Coerces the argument to be a Float.
@@ -552,13 +552,13 @@ def self.Float(arg)
when NilClass, ->(a) { a.respond_to?(:to_f) && a.to_s.match(NUMERIC_MATCHER) }
arg.to_f
else
raise TypeError.new "can't convert into Float"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Float"
end
rescue NoMethodError
raise TypeError.new "can't convert into Float"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Float"
end
rescue RangeError
raise TypeError.new "can't convert into Float"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Float"
end
# Coerces the argument to be a String.
@@ -659,14 +659,14 @@ def self.String(arg)
super(arg)
end
rescue NoMethodError
raise TypeError.new "can't convert into String"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into String"
end
else
def self.String(arg)
arg = arg.to_str if arg.respond_to?(:to_str)
super(arg)
rescue NoMethodError
raise TypeError.new "can't convert into String"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into String"
end
end
@@ -731,7 +731,7 @@ def self.Date(arg)
Date.parse(arg.to_s)
end
rescue ArgumentError, NoMethodError
raise TypeError.new "can't convert into Date"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Date"
end
# Coerces the argument to be a DateTime.
@@ -799,7 +799,7 @@ def self.DateTime(arg)
DateTime.parse(arg.to_s)
end
rescue ArgumentError, NoMethodError
raise TypeError.new "can't convert into DateTime"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into DateTime"
end
# Coerces the argument to be a Time.
@@ -864,7 +864,7 @@ def self.Time(arg)
Time.parse(arg.to_s)
end
rescue ArgumentError, NoMethodError
raise TypeError.new "can't convert into Time"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Time"
end
# Coerces the argument to be a Boolean.
@@ -917,7 +917,7 @@ def self.Boolean(arg)
!!arg
end
rescue NoMethodError
raise TypeError.new "can't convert into Boolean"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Boolean"
end
# Coerces the argument to be a Pathname.
@@ -975,7 +975,7 @@ def self.Pathname(arg)
super
end
rescue NoMethodError
raise TypeError.new "can't convert into Pathname"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Pathname"
end
# Coerces the argument to be a String.
@@ -1021,13 +1021,41 @@ def self.Pathname(arg)
# Lotus::Utils::Kernel.Symbol(input) # => TypeError
def self.Symbol(arg)
case arg
when '' then raise TypeError.new "can't convert into Symbol"
when '' then raise TypeError.new "can't convert #{inspect_type_error(arg)}into Symbol"
when ->(a) { a.respond_to?(:to_sym) } then arg.to_sym
else
raise TypeError.new "can't convert into Symbol"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Symbol"
end
rescue NoMethodError
raise TypeError.new "can't convert into Symbol"
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Symbol"
end
class << self
# Returns the most useful type error possible
#
# If the object does not respond_to?(:inspect), we return the class, else we
# return nil. In all cases, this method is tightly bound to callers, as this
# method appends the required space to make the error message look good.
#
# Used internally by Lotus::Utils::Kernel. This method is not part of the public
# API.
#
# @since x.x.x
#
# @api private
def inspect_type_error(arg)
(arg.respond_to?(:inspect) ? arg.inspect : arg.to_s) << " "
rescue NoMethodError => _
# missing the #respond_to? method, fall back to returning the class' name
begin
arg.class.name << " instance "
rescue NoMethodError => _
# missing the #class method, can't fall back to anything better than nothing
# Callers will have to guess from their code
nil
end
end
private :inspect_type_error
end
end
end
Oops, something went wrong.

0 comments on commit fb1a969

Please sign in to comment.