问题
I'm writing a base class for an interface.. I want all the inherited classes to implement a few methods, is there a way to make them?
I have a payment_method_base
class that I will be inheriting from.
I want all my payment_method
classes to implement the method kind()
that will return a string say 'credit_card'
or 'braintree'
or 'paypal'
or 'amazon_pay'
...
Is there a way to make sure that classes that inherit from payment_method_base
are forced to implement the method kind()
Keeping in mind that the creator of a new payment_method
class may not know about these requirements before they create the class.
In java these are called abstract methods. I'm wondering if ruby has something like that? https://github.com/shuber/defined/blob/master/lib/defined.rb
---- Evolution
I am wondering if there have been fixes to the language that allow for abstract methods.
---- partial answer This answer might be the clue to adding the hooks I need. Is there a hook similar to Class#inherited that's triggered only after a Ruby class definition?
This doesn't quite work the way I expected it would. The call doesn't seem to be done at the right time. Even so it is how many gems handle it. https://github.com/shuber/defined/blob/master/lib/defined.rb
SIMPLES ANSWER THAT I CAN'T SUBMIT BECAUSE THIS IS A REPEAT OF A QUESTION THAT HAD NO REAL ANSWER.
def self.abstract(*methods_array)
@@must_abstract ||= []
@@must_abstract = Array(methods_array)
end
def self.inherited(child)
trace = TracePoint.new(:end) do |tp|
if tp.self == child #modules also trace end we only care about the class end
trace.disable
missing = ( Array(@@must_abstract) - child.instance_methods(false) )
raise NotImplementedError, "#{child} must implement the following method(s) #{missing}" if missing.present?
end
end
trace.enable
end
abstract :foo
回答1:
Ruby doesn't really implement anything like interfaces as it's against it's philosophy but if you really want to simulate interfaces you can use some gem, for example https://github.com/djberg96/interface.
回答2:
There are no abstract methods in ruby.
I suppose you could implement a method like this, and I have seen it from time to time:
def some_method
raise "This method should be over-ridden by a sub-class"
end
If a sub-class neglects to implement that method -- it won't be caught at 'compile time', because that doesn't happen in ruby. But if someone tries to call that method, which hasn't been implemented, you'll get an exception raised.
Of course, if you hadn't put that method (that does nothign more than raise) in the "abstract" superclass, and it was called on a sub-class without the sub-class implementing it... you'd still get a NoMethodException raised anyway. So the "abstract" method implementation that does nothing more than raise doesn't add much. Maybe a documentation of intent.
I think the most ruby-like way to handle this would probably be to provide a test suite of some kind, that another developer implementing a sub-class can easily run against their sub-class. The test suite will complain if the sub-class hasn't implemented things it's supposed to -- and it can even go beyond method signatures, and make sure the semantics of the sub-class are as expected too (you can't do that with just method signatures in Java!). I haven't actually seen anyone do that though, but have often thought it would make sense.
来源:https://stackoverflow.com/questions/28754070/abstract-methods-in-ruby-2-2-0-do-they-exist