Skip to content

Instantly share code, notes, and snippets.

@hashmal
Last active December 20, 2015 17:49
Show Gist options
  • Save hashmal/6171583 to your computer and use it in GitHub Desktop.
Save hashmal/6171583 to your computer and use it in GitHub Desktop.
# 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