AbstractaContracts exposes one supported entry point:
require "abstracta_contracts"The supported root API is intentionally small:
AbstractaContracts.with_methodsAbstractaContracts.interfaceAbstractaContracts::ErrorAbstractaContracts::VERSION- the class DSL installed by
include AbstractaContracts:abstract_class!,abstract_method,abstract_class_method, andimplements - the documented introspection methods installed by
include AbstractaContracts
Implementation modules, contract objects, guards, and specialized errors live behind AbstractaContracts::Internal and are not public API. No pre-release compatibility entry points are shipped.
Declarative abstract classes and interfaces for Ruby.
Gem:
abstracta-contracts
Namespace:AbstractaContracts
gem "abstracta-contracts", require: "abstracta_contracts"require "abstracta_contracts"The compact API is the recommended form:
class FeatureProvider
include AbstractaContracts.with_methods(:enabled?, :features)
endA class with an incomplete contract cannot be instantiated. A descendant becomes concrete when it implements every required method.
class RedisProvider < FeatureProvider
def enabled?(feature)
features.include?(feature)
end
def features
[:search, :reports]
end
endClass-method contracts use class_methods::
class Provider
include AbstractaContracts.with_methods(:call, class_methods: [:provider_name])
endFor dynamic or incremental declarations, use the explicit DSL:
class Provider
include AbstractaContracts
abstract_class!
abstract_method :enabled?
abstract_method :features
abstract_class_method :provider_name
endabstract_class! marks only the declaring class as explicitly abstract. The marker is not inherited. Method requirements are inherited and can be extended or redeclared by descendants.
with_methods returns a reusable module-like contract:
cache_contract = AbstractaContracts.with_methods(:read, :write, :delete)
RedisCache = Class.new do
include cache_contract
def read(key) = nil
def write(key, value) = value
def delete(key) = nil
endInterfaces are separate from abstract classes:
module Cacheable
include AbstractaContracts.interface(
:read,
:write,
:delete,
class_methods: [:adapter_name]
)
endClasses opt into AbstractaContracts and explicitly declare interfaces:
class RedisCache
include AbstractaContracts
implements Cacheable
def read(key) = nil
def write(key, value) = value
def delete(key) = nil
def self.adapter_name = :redis
endAbstractaContracts deliberately does not add implements to every Ruby class.
An interface may include another AbstractaContracts interface. Interface modules may also provide default instance methods; those methods satisfy their requirements.
module Readable
include AbstractaContracts.interface(:read)
end
module Cacheable
include Readable
include AbstractaContracts.interface(:write)
def read(key) = nil
endAbstract classes expose:
Provider.abstract?
Provider.concrete?
Provider.explicitly_abstract?
Provider.abstract_methods
Provider.abstract_class_methods
Provider.missing_abstract_methods
Provider.missing_abstract_class_methods
Provider.valid_implementation?
Provider.validate_implementation!Classes implementing interfaces also expose:
RedisCache.interfaces
RedisCache.direct_interfaces
RedisCache.implements?(Cacheable)
RedisCache.interface_methods
RedisCache.interface_class_methods
RedisCache.missing_interface_methods
RedisCache.missing_interface_class_methodsmissing_methods and missing_class_methods return the combined unresolved abstract-class and interface requirements.
- Abstract method contracts accumulate through inheritance.
- Redeclaring a method as abstract requires a fresh implementation below that declaration.
- Private and protected methods can satisfy contracts.
- Modules included below an abstract declaration can satisfy instance-method contracts.
- Interfaces remain distinct from abstract classes.
- Interface requirements can be satisfied by the class, inherited implementations, or interface defaults.
- AbstractaContracts has no runtime dependencies.
Run bundle exec rake yard and open doc/index.html for the public API.
The DSL entries on the AbstractaContracts page are methods installed on
consuming classes. Implementation details under Internal are unsupported.
Interface modules expose interface? (always true), interface_methods, and
interface_class_methods (frozen, deduplicated symbol arrays including parent
interfaces). Use implements to register an interface for validation; ordinary
Ruby inclusion alone does not register it as a class requirement.
Validation checks presence, not arity, argument types, or return values.
The constructor guard validates before forwarding arguments and blocks to
new; it does not prevent lower-level allocation or arbitrary Ruby overrides.
Rescue AbstractaContracts::Error for contract failures. Empty factory inputs
raise ArgumentError; including a factory result in the wrong kind of object
raises TypeError.
bundle install
bundle exec rake
bundle exec gem build abstracta-contracts.gemspecThe repository includes CI and a RubyGems Trusted Publishing workflow. Repository synchronization, branches, commits, tags, and other version-control operations are intentionally outside the gem's responsibilities.
MIT.