Runtime assertions for Ruby literal.fun
ruby
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

Improve interface type compaisons (#308)

When compared against a module, `_Interface` will inspect the instance
methods defined on that module.

authored by

Joel Drapper and committed by
GitHub
21c577b3 fb285952

+25 -12
+17 -12
lib/literal/types/interface_type.rb
··· 2 2 3 3 # @api private 4 4 class Literal::Types::InterfaceType 5 - # TODO: We can generate this and make it much more extensive. 6 - METHOD_TYPE_MAPPINGS = { 7 - :call => Set[Proc, Method], 8 - :to_proc => Set[Proc, Method, Symbol], 9 - :to_s => Set[String], 10 - }.freeze 5 + include Literal::Type 11 6 12 - include Literal::Type 7 + # List of `===` method owners where the comparison will only match for objects with the same class 8 + OwnClassTypeMethodOwners = Set[String, Integer, Kernel, Float, NilClass, TrueClass, FalseClass].freeze 13 9 14 10 def initialize(*methods) 15 11 raise Literal::ArgumentError.new("_Interface type must have at least one method.") if methods.size < 1 16 - @methods = methods 12 + @methods = methods.to_set.freeze 17 13 freeze 18 14 end 19 15 ··· 24 20 end 25 21 26 22 def ===(value) 27 - @methods.all? { |m| value.respond_to?(m) } 23 + @methods.each do |method| 24 + return false unless value.respond_to?(method) 25 + end 26 + 27 + true 28 28 end 29 29 30 30 def >=(other) 31 31 case other 32 32 when Literal::Types::InterfaceType 33 - @methods.all? { |m| other.methods.include?(m) } 33 + @methods.subset?(other.methods) 34 34 when Module 35 - @methods.map { |m| METHOD_TYPE_MAPPINGS[m] }.all? { |types| types&.include?(other) } 35 + public_methods = other.public_instance_methods.to_set 36 + @methods.subset?(public_methods) 36 37 when Literal::Types::IntersectionType 37 38 other.types.any? { |type| Literal.subtype?(type, self) } 38 39 when Literal::Types::ConstraintType 39 40 other.object_constraints.any? { |type| Literal.subtype?(type, self) } 40 41 else 41 - false 42 + if OwnClassTypeMethodOwners.include?(other.method(:===).owner) 43 + self === other 44 + else 45 + false 46 + end 42 47 end 43 48 end 44 49
+8
test/types/_interface.test.rb
··· 23 23 refute_subtype _Interface(:b), _Interface(:a) 24 24 refute_subtype _Interface(:a), _Interface(:a, :b) 25 25 refute_subtype Proc, _Interface(:to_proc, :random_method) 26 + 27 + assert_subtype "Hello", _Interface(:to_s) 28 + assert_subtype 1, _Interface(:+, :-) 29 + assert_subtype Object.new, _Interface(:inspect) 30 + assert_subtype 1.234, _Interface(:to_i) 31 + assert_subtype nil, _Interface(:nil?) 32 + assert_subtype true, _Interface(:to_s) 33 + assert_subtype false, _Interface(:to_s) 26 34 end 27 35 28 36 test "error message" do