Module: Ecfr::Extensible

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