Abstractable is Library for define abstract method.
Can know unimplemented abstract methods by fail fast as possible.
This mechanism is very useful for prevent the implementation leakage.
require "abstractable"
class AbstractDriver
extend Abstractable
abstract :open, :close
end
class AbstractIODriver < AbstractDriver
abstract :read, :write
end
class NotImplIODriver < AbstractIODriver; end
NotImplIODriver.new
# => following abstract methods are not implemented. (NotImplementedError)
# [:open, :close] defined in AbstractDriver
# [:read, :write] defined in AbstractIODriver
See sample above. error occurred at call new method.
Info of unimplemented abstract method have been included in the error message.
gem install abstractable
First, call require "abstractable".
Then, extend Abstractable.
require "abstractable"
class AbstractClass
extend Abstractable
end
Note: This document omit the require "abstractable" from now on.
- Specify Symbol (can specify multiple)
If want to express the arguments then can write be as follows.
class AbstractList extend Abstractable abstract :add, :insert, :empty? end
class AbstractList extend Abstractable def add(value); end def insert(index, value); end def empty?; end abstract :add, :insert, :empty? end
- In block
Defined methods in block is all treated as an abstract method.Can also be written as follows.class AbstractList extend Abstractable abstract do def add(value); end def insert(index, value); end def empty?; end end end
class AbstractList extend Abstractable abstract { def add(value); end } abstract { def insert(index, value); end } abstract { def empty?; end } end
abstract_methods returns an array containing the names of abstract methods in the receiver.
if set true to args include ancestors abstract methods (default true).
class AbstractDriver
extend Abstractable
abstract :open, :close
end
class AbstractIODriver < AbstractDriver
abstract :read, :write
end
AbstractIODriver.abstract_methods # => [:read, :write, :open, :close]
If specify false for the argument, only abstract methods defined in the receiver is returned.
AbstractIODriver.abstract_methods(false) # => [:read, :write]
Can undefine and if you call Module#undef_method.
However, the receiver must be a class that defines an abstract method.
(Can't be undefine of the abstract methods of the parent class from a subclass.)
class Parent
extend Abstractable
abstract :greet
end
class Child < Parent
undef_method :greet
end
begin
Child.new # => NotImplementedError
rescue NotImplementedError
end
class Parent
undef_method :greet
end
Child.new # => OK
Once you have confirmed that the unimplemented methods do not exist, validation does not take place.
if defined abstract method later, then perform validation once more.
required_validate? returns true if required unimplemented abstract methods validation.
class AbstractParent
extend Abstractable
abstract :greet
end
class Child < AbstractParent
def greet; end
end
Child.required_validate? # => true
Child.new
Child.required_validate? # => false
# define abstract method
AbstractParent.abstract :execute
Child.required_validate? # => true
This case is required_validate? returns true always.
ABSTRACTABLE_IGNORE_VALIDATE value allow any value.
# Linux
export ABSTRACTABLE_IGNORE_VALIDATE=true
# windows
set ABSTRACTABLE_IGNORE_VALIDATE=true
Abstract method of singleton class can't validation at new.
Therefore throw error at abstract method call.
But can find unimplemented abstract methods.
class AbstractParent
extend Abstractable
class << self
extend Abstractable
abstract :greet
end
end
class AbstractChild < AbstractParent
class << self
abstract :say
end
end
class Child < AbstractChild; end
Child.greet # => greet is abstract method defined in
# #<Class:AbstractParent>, and must implement.
# (NotImplementedError)
abstract_singleton_methods Returns an array containing the names of abstract methods
in the receivers singleton class.
if set true to args include ancestor singleton classes abstract methods (default true).
Child.abstract_singleton_methods # => [:say, :greet]
Child.abstract_singleton_methods(false) # => []
AbstractChild.abstract_singleton_methods # => [:say, :greet]
AbstractChild.abstract_singleton_methods(false) # => [:say]
if call validate_not_implemented_abstract_methods then can do explicitly validation.
class AbstractParent
extend Abstractable
abstract :greet
end
class Child < AbstractParent; end
# explicitly validation
Child.validate_not_implemented_abstract_methods
# => following abstract methods are not implemented. (NotImplementedError)
# [:greet] defined in AbstractParent
abstractable#find_not_implemented_info returns a following format Hash
{abstract_class => array of unimplemented abstract methods, ...}
class AbstractParent
extend Abstractable
abstract :greet
end
class Child < AbstractParent; end
Abstractable.find_not_implemented_info(Child) # => {AbstractParent=>[:greet]}
If call find_not_implemented_info_from_singleton,
Then can find unimplemented abstract methods of singleton class.
class AbstractParent
class << self
extend Abstractable
abstract :greet
end
end
class Child < AbstractParent; end
Abstractable.find_not_implemented_info_from_singleton(Child)
# => {#<Class:AbstractParent>=>[:greet]}