Last active
December 20, 2015 17:49
-
-
Save hashmal/6171583 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Class inheriting from this are be able to declare abstract methods that | |
# must be implemented by some other classes. Example: | |
# | |
# class A < Interface | |
# abstract :foo | |
# end | |
# | |
# class B | |
# implement A | |
# end | |
# | |
# B.new # Exception raised because B does not have a method named `foo'. | |
# | |
# class C; end | |
# | |
# A[C] # Exception raised because C does not implement A | |
# | |
# Obviously this requires a bit of magic and it is not as robust as say, Java | |
# interfaces, but I think it's still a nice tool to have. | |
class Interface | |
# Exception raised when a class does not fully implement an interface. | |
class AbstractMethodNotImplemented < Exception; end | |
def self.[] object | |
klass = object.class | |
if klass.send(:instance_variable_get, "@interfaces").include? self | |
return object | |
else | |
raise TypeError.new("`#{klass.name}' does not implement #{self.name}") | |
end | |
end | |
def self.abstract name | |
(@abstracts ||= Array.new) << name | |
end | |
end | |
# Meta magic. | |
class Object | |
attr_reader :interfaces | |
def self.new( *args, &blk ) | |
instance = allocate | |
instance.send :initialize, *args, &blk | |
instance.send :check_interfaces | |
return instance | |
end | |
def implement name | |
(@interfaces ||= []) << name | |
end | |
private | |
def check_interfaces | |
(self.class.interfaces || []).each do |interface| | |
check_interface(interface) | |
end | |
end | |
def check_interface(interface) | |
interface.instance_variable_get("@abstracts").each do |name| | |
check_method_implementation name | |
end | |
end | |
def check_method_implementation name | |
return if self.class.method_defined? name | |
raise Interface::AbstractMethodNotImplemented.new( | |
"`#{self.class.name}##{name}' not implemented.") | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment