From: Jacob Fugal Date: 2006-03-12T08:53:01+09:00 Subject: Re: [RCR] abstract method in Ruby On 3/11/06, kwatch wrote: > I think it is convenient if the Module#abstract_method is defined. I'm of a similar opinion with others that predeclaring an abstract method that raises NotImplementedError is of limited use when compared with the existing NoMethodError duck-typing approach. As such, I don't think it belongs in the core. *However*, this is a useful concept which could be used to extend the capabilities of the language for those who do still want it. I encourage you to build a library from this idea and publicize it. Just because it doesn't belong in the core doesn't mean it won't be useful to some. One place I can see this being used is if the NotImplementedError gave a more descriptive output, such as "#{self} requires that the host implement the method '#{method_name}'." E.g. "Enumerable requires that the host implement the method 'each'." > ---------- > class Module > def abstract_method(*method_names) > method_names.each do |name| > s = <<-END > def #{name} > mesg = "\#{self.class.name}##{name}() is not implemented." > raise NotImplementedError.new(mesg) > end > END > module_eval s > end > end > > class Foo > abstract_method :m1, :m2, :m3 # define abstract methods > end > > obj = Foo.new > obj.m1 #=> Foo#m1() is not implemented yet. (NotImplementedError) > ---------- > > But this solution doesn't allow us to define a method with arguments. One thing that you can do to make this approach (which seems cleaner and simpler than the backtrace manipulation approach you later proposed) more flexible by removing the arity restriction on the method using the splat operator: $ cat abstract.rb class Module def abstract_method(*method_names) mesg_template = "#{self} requires that the host implement the method '%s'." method_names.each do |name| mesg = mesg_template % [name] module_eval <<-END def #{name}(*args) raise NotImplementedError.new("#{mesg}") end END end end end module MyModule def foo bar("test") end abstract_method :bar end class MyClass include MyModule end a = MyClass.new b = MyClass.new class << a def bar( s ) puts s end end a.foo b.foo $ ruby abstract.rb test (eval):2:in `bar': MyModule requires that the host implement the method 'bar'. (NotImplementedError) from abstract.rb:17:in `foo' from abstract.rb:37 -- Jacob Fugal