Module: Ecfr::Extensible
- Included in:
- AdminService::EcfrCorrection::CfrReference, AdminService::EditorialNote::Hierarchy, AdminService::IbrCfrRange::Address, AdminService::IbrCfrRange::Organization, AdminService::Issue::Change, Base, Common::Hierarchy, SearchService::ContentVersion::HierarchicalCount, SearchService::ContentVersion::HierarchicalCountNode, VersionerService::Ancestors::NodeSummary, VersionerService::IssuePackage::IssueVolume
- Defined in:
- lib/ecfr/extensible.rb
Overview
Users of this gem may want to subclass our API client classes to add app-specific functionality; for example, adding to functionality of the ‘Ancestor` or `NodeSummary` classes.
Because our the gem’s client classes instantiate other objects (eg Ancestors creates NodeSummary objects), we need to make it possible for the user to get instances of their own NodeSummary subclass created when they use their Ancestor subclass
To support upstream modification of these classes we record when inheritance happens and use that to instantiate the expected class at run time.
This means that these subclasses can only be inherited from / modified by a single upstream class (and will always be instantiated as that class). We skip this bookkeeping when the inheritance is from one of the classes that directly inherits from a service Base class as it is reasonable to expect that inheritance in that scenario works as all other Ruby inheritance.
Defined Under Namespace
Classes: AlreadyExtendedError
Instance Method Summary collapse
Instance Method Details
#inherited(subclass) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/ecfr/extensible.rb', line 24 def inherited(subclass) # Skip for class inheritance within the gem. return if subclass.to_s.starts_with?("Ecfr::") # Skip for inheritance tracking of top level gem classes return if superclass.to_s.ends_with?("Service::Base") # Only set if not already defined (constants can't be redefined) if const_defined?(:KLASS) # during autoreloading in dev type environments subclassing will appear # to happen twice - we can safely ignore that - if the class differs # from that already defined then we want to notify the user if self::KLASS.to_s != subclass.to_s raise AlreadyExtendedError, "#{name} has already been extended by '#{self::KLASS}'. Subclasses can not be extended by inheritance multiple times. #{subclass}" end else const_set(:KLASS, subclass) end end |