Skip to content

Instantly share code, notes, and snippets.

@k-tsj
Last active August 29, 2015 14:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save k-tsj/deec45fc17883bf6be7c to your computer and use it in GitHub Desktop.
Save k-tsj/deec45fc17883bf6be7c to your computer and use it in GitHub Desktop.
# power_assert.rb
#
# Copyright (C) 2014 Kazuki Tsujimoto, All rights reserved.
# License: BSDL
#
# $ ruby power_assert.rb
# "0".class == "3".to_i.times.map {|i| i + 1 }.class
# | | | | |
# | | | | Array
# | | | [1, 2, 3]
# | | #<Enumerator: 3:times>
# | 3
# String
def main
power_assert do
"0".class == "3".to_i.times.map {|i| i + 1 }.class
end
end
RetValue = Struct.new(:method_id, :value, :colno)
TARGET_CALLER_DIFF = {c_return: 6, return: 7}
TARGET_CALLER_INDEX = {c_return: 2, return: 3}
def power_assert
base_caller_lengh = caller_locations.length
path = nil
lineno = nil
values = []
trace = TracePoint.new(:return, :c_return) do |tp|
locs = tp.binding.eval('caller_locations')
if locs.length - base_caller_lengh == TARGET_CALLER_DIFF[tp.event]
idx = TARGET_CALLER_INDEX[tp.event]
path ||= locs[idx].path
lineno ||= locs[idx].lineno
if path == locs[idx].path and lineno == locs[idx].lineno
values << RetValue[tp.method_id, tp.return_value, nil]
end
end
end
unless trace.enable { yield }
raise unless path
line = open(path).each_line.drop(lineno - 1).first
print_assersion_message(line, values)
end
end
def print_assersion_message(line, values)
set_colno(line, values)
vals = values.find_all(&:colno).sort_by(&:colno).reverse
if vals.empty?
return
end
fmt = (vals[0].colno + 1).times.map {|i| vals.find {|v| v.colno == i } ? "%<#{i}>s" : ' ' }.join + "\n"
puts line
printf(fmt, vals.each_with_object({}) {|v, h| h[v.colno.to_s.to_sym] = '|' })
vals.each do |i|
printf(fmt, vals.each_with_object({}) do |j, h|
h[j.colno.to_s.to_sym] = [i.value.inspect, '|', ' '][i.colno <=> j.colno]
end)
end
end
def set_colno(line, values)
rev_values = values.reverse
values.each do |val|
v = rev_values.find {|i| i.method_id == val.method_id and i.colno }
val.colno = line.index(/\b#{Regexp.escape(val.method_id)}\b/, v ? v.colno + 1 : 0)
end
end
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment