Skip to content

Instantly share code, notes, and snippets.

@sleepingkingstudios
Created October 6, 2015 18:38
Show Gist options
  • Save sleepingkingstudios/26f7236ee5f646403f87 to your computer and use it in GitHub Desktop.
Save sleepingkingstudios/26f7236ee5f646403f87 to your computer and use it in GitHub Desktop.
class Comparator
def initialize(actual, expected)
@actual = actual
@expected = expected
@errors = Hash.new { |hsh, key| hsh[key] = [] }
end # constructor
attr_accessor :actual, :expected, :errors
def eql?
compare actual, expected, []
end # method eql?
alias_method :valid?, :eql?
private
def compare(first, v, keys)
if time?(first)
return compare_times(first, v, keys)
elsif time?(v)
return compare_times(v, first, keys)
end # if
unless first.is_a?(v.class)
@errors[format_keys keys] << "expected #{v.class}, got #{first.class}"
return false
end # unless
case first
when Array
unless first.count == v.count
@errors[format_keys keys] << "expected #{first.count} items, got #{v.count} items"
return false
end # unless
return false unless first.map.with_index do |item, index|
compare(item, v[index], keys + [index])
end.reduce(true) { |memo, bool| memo && bool }
when Hash
unless first.keys == v.keys
@errors[format_keys keys] << "expected keys #{first.keys}, got #{v.keys}"
return false
end # unless
return false unless first.keys.reduce(true) do |memo, key|
memo && compare(first[key], v[key], keys + [key])
end # reduce
else
unless first == v
byebug
@errors[format_keys keys] << "expected #{first.inspect}, got #{v.inspect}"
return false
end # unless
end # when
return true
end # method compare
def compare_times(time, value, keys)
if value.is_a?(ActiveSupport::TimeWithZone)
return true if time.to_i == value.to_i
elsif value.is_a?(Integer) || (value.is_a?(String) && value =~ /\A\d+\z/)
return true if time.to_i == value.to_i
elsif value.is_a?(String)
return true if time.to_i == Time.parse(value).to_i
end # if-elsif
@errors[format_keys keys] << "expected #{time.inspect}, got #{value.inspect}"
false
end # method compare_times
def format_keys(keys)
keys.empty? ? :root : :"#{[keys.first, keys[1..-1].map { |k| "[#{key}]" }].join}"
end
def time?(value)
case value
when Time, DateTime, ActiveSupport::TimeWithZone
true
else
false
end # case
end # method time?
end # class Comparator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment