Created
December 21, 2017 10:25
-
-
Save Bongs/d6a477dabf829dc8451d7df4f7c8b8f7 to your computer and use it in GitHub Desktop.
Ruby on Rails - Abstract class and STI. Make any class an Abstract class at any level of STI. Raise error when abstract class instantiated.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Abstractable | |
extend ActiveSupport::Concern | |
included do | |
class << self | |
attr_accessor :isabstract | |
end | |
@isabstract = true | |
end | |
def initialize(*args) | |
# Raise custom error | |
raise CustomError::AbstractClass.new(self.class) if self.class.isabstract | |
super | |
end | |
module ClassMethods | |
def inherited(subklass) | |
subklass.instance_variable_set('@isabstract', instance_variable_get('@isabstract')) | |
super | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module CustomError | |
class Error < StandardError; end | |
class AbstractClass < CustomError::Error | |
attr_reader :klass_object, :message | |
attr_writer :default_message | |
def initialize(klass_object = nil, message = nil) | |
@message = message | |
@klass_object = klass_object | |
@default_message = "Can not instantiate abstract class. Type has to be specified." | |
if klass_object.present? && Object.const_defined?(klass_object.to_s) | |
descendants_list = klass_object.try(:descendants).try(:reject, &:isabstract).try(:map, &:name).try(:map, &:demodulize).try(:join, ', ') | |
@default_message += " #{klass_object.to_s} can be one of type: #{descendants_list}." | |
end | |
end | |
def to_s | |
@message || @default_message | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module TopLevelModule | |
class SomeBaseClass < ApplicationRecord | |
# By default it will make this class and its child classes an Abstract class | |
# after including the Abstractable module | |
include Abstractable | |
end | |
module SomeNameSpace1 | |
class SomeChildClass1 < TopLevelModule::SomeBaseClass | |
# Makes the child class non-abstract | |
@isabstract = false | |
end | |
class SomeChildClass2 < TopLevelModule::SomeBaseClass | |
@isabstract = false | |
end | |
class SomeChildClass3 < TopLevelModule::SomeBaseClass | |
@isabstract = false | |
end | |
end | |
class AnotherChildClass < TopLevelModule::SomeBaseClass | |
# An abstract class. | |
end | |
module SomeNameSpace2 | |
class SomeOtherChild1 < TopLevelModule::AnotherChildClass | |
@isabstract = false | |
end | |
class SomeOtherChild2 < TopLevelModule::AnotherChildClass | |
@isabstract = false | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment