lib/abstract_type.rb
# encoding: utf-8
# Module to allow class and methods to be abstract
module AbstractType
# Hook called when module is included
#
# @param [Module] descendant
# the module or class including AbstractType
#
# @return [undefined]
#
# @api private
def self.included(descendant)
super
create_new_method(descendant)
descendant.extend(AbstractMethodDeclarations)
end
private_class_method :included
# Define the new method on the abstract type
#
# Ensures that the instance cannot be of the abstract type
# and must be a descendant.
#
# @param [Class] abstract_class
#
# @return [undefined]
#
# @api private
def self.create_new_method(abstract_class)
abstract_class.define_singleton_method(:new) do |*args, &block|
if equal?(abstract_class)
fail NotImplementedError, "#{inspect} is an abstract type"
else
super(*args, &block)
end
end
end
private_class_method :create_new_method
module AbstractMethodDeclarations
# Create abstract instance methods
#
# @example
# class Foo
# include AbstractType
#
# # Create an abstract instance method
# abstract_method :some_method
# end
#
# @param [Array<#to_s>] names
#
# @return [self]
#
# @api public
def abstract_method(*names)
names.each(&method(:create_abstract_instance_method))
self
end
# Create abstract singleton methods
#
# @example
# class Foo
# include AbstractType
#
# # Create an abstract instance method
# abstract_singleton_method :some_method
# end
#
# @param [Array<#to_s>] names
#
# @return [self]
#
# @api private
def abstract_singleton_method(*names)
names.each(&method(:create_abstract_singleton_method))
self
end
private
# Create abstract singleton method
#
# @param [#to_s] name
# the name of the method to create
#
# @return [undefined]
#
# @api private
def create_abstract_singleton_method(name)
define_singleton_method(name) do |*|
fail NotImplementedError, "#{inspect}.#{name} is not implemented"
end
end
# Create abstract instance method
#
# @param [#to_s] name
# the name of the method to create
#
# @return [undefined]
#
# @api private
def create_abstract_instance_method(name)
define_method(name) do |*|
fail NotImplementedError, "#{self.class}##{name} is not implemented"
end
end
end # module AbstractMethodDeclarations
end # module AbstractType
require 'abstract_type/version'