Skip to content

Commit

Permalink
add Util::TypeAnalysis
Browse files Browse the repository at this point in the history
  • Loading branch information
jbodah committed Aug 23, 2018
1 parent 5dd9aad commit 90a3100
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 0 deletions.
66 changes: 66 additions & 0 deletions lib/spy/util.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
require 'spy'
require 'set'

module Spy
module Util
class TypeAnalysis
attr_reader :type_info

def initialize(spy)
@spy = spy
@type_info = {}
end

def decorate
if @spy.is_a?(Spy::Multi)
spies = @spy.spies
else
spies = [@spy]
end

spies.each do |spy|
spy.wrap do |method_call, &block|
record_args(method_call)
block.call
record_rv(method_call)
end
end

self
end

def respond_to_missing?(sym, incl_private = false)
@spy.respond_to_missing?(sym, incl_private)
end

def method_missing(sym, *args, &block)
@spy.send(sym, *args, &block)
end

private

def record_args(method_call)
@type_info[method_call.name] ||= {}
@type_info[method_call.name][:args] ||= []
method_call.args.each.with_index do |arg, idx|
@type_info[method_call.name][:args][idx] ||= Set.new
@type_info[method_call.name][:args][idx] << type_of(arg)
end
end

def record_rv(method_call)
@type_info[method_call.name] ||= {}
@type_info[method_call.name][:return_value] ||= Set.new
@type_info[method_call.name][:return_value] << type_of(method_call.result)
end

def type_of(obj)
if obj.is_a?(Array) && obj.size > 0
[Array, obj[0].class]
else
obj.class
end
end
end
end
end
1 change: 1 addition & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Add lib to load path
$LOAD_PATH.push 'lib', __FILE__
require 'spy'
require 'spy/util'

require 'coveralls'
Coveralls.wear!
Expand Down
39 changes: 39 additions & 0 deletions test/util_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'test_helper'

class UtilTest < Minitest::Spec
describe 'type analysis' do
it 'does things' do
klass = Class.new(Object)
klass.class_eval do
def name
"josh"
end

def compliment(color)
case color
when "red" then ["blue", "yellow"]
when "black" then "white"
else nil
end
end
end

multi = Spy.on_class(klass)
multi = Spy::Util::TypeAnalysis.new(multi).decorate
obj = klass.new

obj.name
obj.compliment("red")
obj.compliment("black")
obj.compliment("green")

type_info = multi.type_info

assert_equal [], type_info[:name][:args]
assert_equal [String], type_info[:name][:return_value].to_a

assert_equal [String], type_info[:compliment][:args][0].to_a
assert_equal [[Array, String], String, NilClass], type_info[:compliment][:return_value].to_a
end
end
end

0 comments on commit 90a3100

Please sign in to comment.