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