lib/surrogate/api_comparer.rb in surrogate-0.5.5 vs lib/surrogate/api_comparer.rb in surrogate-0.6.0

- old
+ new

@@ -1,6 +1,8 @@ require 'set' +require 'surrogate/surrogate_class_reflector' +require 'surrogate/porc_reflector' class Surrogate # compares a surrogate to an object class ApiComparer @@ -9,26 +11,28 @@ def initialize(surrogate, actual) self.surrogate, self.actual = surrogate, actual end def surrogate_methods - @surrogate_methods ||= SurrogateMethods.new(surrogate).methods + @surrogate_methods ||= SurrogateClassReflector.new(surrogate).methods end def actual_methods - @actual_methods ||= ActualMethods.new(actual).methods + @actual_methods ||= PorcReflector.new(actual).methods end def compare @compare ||= { instance: { not_on_surrogate: instance_not_on_surrogate, not_on_actual: instance_not_on_actual, + types: instance_types, }, class: { not_on_surrogate: class_not_on_surrogate, not_on_actual: class_not_on_actual, + types: class_types, }, } end def instance_not_on_surrogate @@ -47,80 +51,74 @@ def class_not_on_actual surrogate_methods[:class][:api] - actual_methods[:class][:inherited] - actual_methods[:class][:other] end - # methods from the actual class (as opposed to "these are actually methods" - class ActualMethods < Struct.new(:actual) - def methods - { instance: { - inherited: instance_inherited_methods, - other: instance_other_methods, - }, - class: { - inherited: class_inherited_methods, - other: class_other_methods, - }, - } + # types are only shown for methods on both objects + def class_types + surrogate_class_methods = surrogate_methods[:class][:api] + surrogate_methods[:class][:inherited] + actual_class_methods = actual_methods[:class][:inherited] + actual_methods[:class][:other] + class_methods_that_should_match = (surrogate_class_methods & actual_class_methods) - surrogate_methods[:class][:without_bodies] - actual_methods[:class][:without_bodies] + class_methods_that_should_match.each_with_object Hash.new do |name, hash| + surrogate_type, actual_type = class_types_for name + next if surrogate_type == actual_type + hash[name] = { surrogate: surrogate_type, actual: actual_type } end + end - def instance_inherited_methods - Set.new actual.instance_methods - actual.instance_methods(false) + # types are only shown for methods on both objects + def instance_types + surrogate_instance_methods = surrogate_methods[:instance][:api] + surrogate_methods[:instance][:inherited] + actual_instance_methods = actual_methods[:instance][:inherited] + actual_methods[:instance][:other] + instance_methods_that_should_match = (surrogate_instance_methods & actual_instance_methods) - surrogate_methods[:instance][:without_bodies] - actual_methods[:instance][:without_bodies] + instance_methods_that_should_match.each_with_object Hash.new do |name, hash| + surrogate_type, actual_type = instance_types_for name + next if surrogate_type == actual_type + hash[name] = { surrogate: surrogate_type, actual: actual_type } end + end - def instance_other_methods - Set.new(actual.instance_methods) - instance_inherited_methods - end + private - def class_inherited_methods - Set.new actual.singleton_class.instance_methods - actual.singleton_class.instance_methods(false) - end + def class_types_for(name) + surrogate_method = class_api_method_for name + surrogate_method &&= to_lambda surrogate_method + surrogate_method ||= surrogate.method name + actual_method = actual.method name + return type_for(surrogate_method), type_for(actual_method) + end - def class_other_methods - Set.new(actual.singleton_class.instance_methods) - class_inherited_methods - end + def instance_types_for(name) + surrogate_method = instance_api_method_for name + surrogate_method &&= to_lambda surrogate_method + surrogate_method ||= surrogate.instance_method name + actual_method = actual.instance_method name + return type_for(surrogate_method), type_for(actual_method) end + def type_for(method) + method.parameters.map(&:first) + end - class SurrogateMethods < Struct.new(:surrogate) - def methods - { instance: { - api: instance_api_methods, - inherited: instance_inherited_methods, - other: instance_other_methods, - }, - class: { - api: class_api_methods, - inherited: class_inherited_methods, - other: class_other_methods, - }, - } - end + def to_lambda(proc) + obj = Object.new + obj.singleton_class.send :define_method, :abc123, &proc + obj.method :abc123 + end - def instance_api_methods - Set.new surrogate.api_method_names - end + def instance_api_method_for(name) + class_hatchery.api_method_for name + end - def instance_inherited_methods - Set.new surrogate.instance_methods - surrogate.instance_methods(false) - end + def class_api_method_for(name) + singleton_class_hatchery.api_method_for name + end - def instance_other_methods - Set.new(surrogate.instance_methods false) - instance_api_methods - end + def class_hatchery + @class_hatchery ||= surrogate.instance_variable_get :@hatchery + end - def class_api_methods - Set.new surrogate.singleton_class.api_method_names - end - - # should have new and clone (don't screw up substitutability because of how we implement these) - def class_inherited_methods - Set.new surrogate.singleton_class.instance_methods - surrogate.singleton_class.instance_methods(false) - end - - # should not have new - def class_other_methods - Set.new(surrogate.singleton_class.instance_methods false) - class_api_methods - class_inherited_methods - end + def singleton_class_hatchery + @singleton_class_hatchery ||= surrogate.singleton_class.instance_variable_get :@hatchery end end end