Ok so I'm trying to set up my own subclassing structure in ruby to allow functionality that matches the protocol pattern in Swift. My current approach is to create two base classes, one called Protocol which allows the declaration of protocols with x number of required methods, the other is called SwiftClass, which allows subclasses to 'inherit' protocols.
Protocol Class
class Protocol
@@required_methods = []
def self.required_method(method_name)
@@required_methods << method_name
end
def self.required_methods
return @@required_methods
end
end
Swift Class
class SwiftClass
@@protocols = []
def self.inherit_protocol(protocol_name)
protocol = Object.const_get(protocol_name)
@@protocols << protocol
end
def self.inherit_protocols(*protocol_names)
protocol_names.each do |protocol_name|
inherit_protocol(protocol_name)
end
end
def self.verify_conforms_to_protocols
@@protocols.each do |protocol|
if protocol.superclass != Protocol
raise "ERROR: #{protocol} must be a subclass of Protocol"
end
if (missing_methods = self.missing_methods_for protocol).length > 0
raise "\nERROR: #{self} does not conform to protocol #{protocol}. \nMISSING METHODS: #{missing_methods.join(", ")}"
end
end
end
def self.missing_methods_for(protocol)
protocol.required_methods.select do |required_method|
!self.method_defined? required_method
end
end
end
I can then create a protocol with required methods as such
class SampleProtocol < Protocol
required_method :number_of_sections_in
required_method :number_of_rows_in_section
end
And set a class to inherit this protocol
class SampleClass < SwiftClass
inherit_protocols :SampleProtocol
verify_conforms_to_protocols
end
So far everything works the way it should. if I run the code it raises the error I set in SwiftClass as expected
ERROR: SampleClass does not conform to protocol SampleProtocol.
MISSING METHODS: number_of_sections_in, number_of_rows_in_section
And then if I add the methods to SampleClass and run it it no longer raises any errors:
class SampleClass < SwiftClass
inherit_protocols :SampleProtocol
def number_of_sections_in; end
def number_of_rows_in_section; end
verify_conforms_to_protocols
end
Most of you guys who know anything about ruby can probably already see the glaring issue with this code; the class variables @@required_methods and @@protocols are both defined on the superclass level, so every time I add to them in a subclass it spreads to every other subclass. For example, if I were to add a separate protocol before the declaration of SampleClass
class SomeOtherProtocol < Protocol
required_method :cell_for_row_at
end
and then run the code I get the error
ERROR: SampleClass does not conform to protocol SampleProtocol.
MISSING METHODS: cell_for_row_at
Because the @@required_methods collects every required method from every Protocol subclass. The same is true for @@protocols for every subclass of SwiftClass.
So my question is, Can I use a superclass to set class variables for each of it's subclasses? I want the @@required_methods variable to hold different values for each subclass of Protocol and the @@protocols variable to hold different values for each subclass of SwiftClass, but I still want to hold the logic for this in the superclasses so that I don't have to repeat it in each subclass.
If possible, I'd like to keep the exact same structure for inheriting protocols in a SwiftClass, so that all I have to do to inherit a protocol is set "inherit_protocols :SomeProtocol." Same thing goes for adding methods to a new protocol with just the "method: some_method" calls.