How to implement an abstract class in ruby?
Just to chime in late here, I think that there's no reason to stop somebody from instantiating the abstract class, especially because they can add methods to it on the fly.
Duck-typing languages, like Ruby, use the presence/absence or behavior of methods at runtime to determine whether they should be called or not. Therefore your question, as it applies to an abstract method, makes sense
def get_db_name
raise 'this method should be overriden and return the db name'
end
and that should be about the end of the story. The only reason to use abstract classes in Java is to insist that certain methods get "filled-in" while others have their behavior in the abstract class. In a duck-typing language, the focus is on methods, not on classes/types, so you should move your worries to that level.
In your question, you're basically trying to recreate the abstract
keyword from Java, which is a code-smell for doing Java in Ruby.
I don't like using abstract classes in Ruby (there's almost always a better way). If you really think it's the best technique for the situation though, you can use the following snippet to be more declarative about which methods are abstract:
module Abstract
def abstract_methods(*args)
args.each do |name|
class_eval(<<-END, __FILE__, __LINE__)
def #{name}(*args)
raise NotImplementedError.new("You must implement #{name}.")
end
END
# important that this END is capitalized, since it marks the end of <<-END
end
end
end
require 'rubygems'
require 'rspec'
describe "abstract methods" do
before(:each) do
@klass = Class.new do
extend Abstract
abstract_methods :foo, :bar
end
end
it "raises NoMethodError" do
proc {
@klass.new.foo
}.should raise_error(NoMethodError)
end
it "can be overridden" do
subclass = Class.new(@klass) do
def foo
:overridden
end
end
subclass.new.foo.should == :overridden
end
end
Basically, you just call abstract_methods
with the list of methods that are abstract, and when they get called by an instance of the abstract class, a NotImplementedError
exception will be raised.