Abstract method in Ruby

On Mon, 13 Mar 2006, kwatch wrote:

[email protected] wrote:

class Module
def abstract_method m
define_method(m){|*a| super rescue raise NotImplementedError}
end
end

It seems to be a good solution.
I’ll consider and examine this idea.
Thanks ara.

sure. this one’s a bit more robust since it doesn’t mask errors:

 harp:~ > cat a.rb
 class Module
   def abstract_method m
     define_method(m) do |*a|
       begin; super; rescue NoMethodError; raise 

NotImplementedError, m; end
end
end
end
module Interface
abstract_method :foo
def bar; foo end
end
class C
def foo; “C#foo” end
end
class D < C
include Interface
end
p D::new.foo

 harp:~ > ruby a.rb
 "C#foo"

regards.

-a

On Mon, 13 Mar 2006, kwatch wrote:

I separate ‘abstract method’ and ‘typing’. They are different thing, I
think. I have no intention to bring strong typing into Ruby. The merits of
abstract method is not only typing. Please take account of reading code, as
well as writing or executing code. Descriptive code help those who reading
the program code.

careful - ruby is strongly typed. what it is not is statically typed.

ruby typing => strong and dynamic

just wanted to point this out because the issue really seems to confuse
people.

i’m all for your RCR btw…

regards.

-a

Hi,

In message “Re: [RCR] abstract method in Ruby”
on Mon, 13 Mar 2006 12:33:45 +0900, “kwatch” [email protected]
writes:

|> class Base
|> def each
|> …
|> end
|> end
|>
|> class Derived < Base
|> include Enumerable
|> …
|> end
|>
|> The abstract “each” method defined in Enumerable overrides the “each”
|> in the Base class. I’m not against the idea of abstract (or deferred)
|> method, but sometimes it’s not that simple.
|
|Oh, I didn’t realized that.

It’s caused by mix-in, a kind of multiple inheritance. The above is
rather artificial case, so that it does not cause troubles on most of
the cases, but if we want to add abstract method in the core, I think
we need to care about such cases as well.

						matz.

On Mar 12, 2006, at 10:08 PM, kwatch wrote:

What you say is right. I agree with your opinion.
My point is that program code should be descriptive and
it should be prime documentation than comment or api doc.
Abstract method helps this.

I don’t believe it is any more descriptive than the current
situation. I think that whenever possible, you are right code should
be self-describing, but I don’t think abstract methods are self-
describing.

I think that in ruby this already is self describing:

module Enumerable

def map(&block)
results = []
each { |x| results << block.call(x) }
results
end
end

Looking at this a programmer using this api will say, ok I need to
provide an each method,
and it needs to take a block. That’s what the code tells him. If he
doesn’t read the code, and attempts to use Enumerable, he will get an
exception. This exception will tell him what method his object
doesn’t implement that enumerable relies upon. This exception may be
a NoMethodError, or a NotImplementedError. Either way though he has
to go back to the code or docs to see what is expected. Implementing
an each that doesn’t take a block or an each that takes more or less
arguments than its expected too is just as bad as or worse than no
each at all. I digress though, because what it really comes down to
is that your abstract_method should be a comment or an rdoc
directive. It really, really should. There is no reason to write code
that does effectively nothing. Your abstract method (irrespective of
abstract methods in other languages) is a documentation tool, and
that’s where it should be implemented. You say “consider
readability”, so do I. What is more readable, a comment telling me I
need to have an each method to include Enumerable, possibly even
explaining why, or a a call to a class method named abstract _method?
Now admittedly I can guess what that means, but I still have to find
out to be sure. Especially since it looks like its doing something. A
comment can be just as short as your method call, doesn’t introduce
any new code and it IS part of the code, unless you read your code
with all the comments stripped out. You keep saying code should be
descriptive, I don’t believe this adds to the descriptiveness. Which
is why I would not want this in the core ruby. It doesn’t add anything.

Hi,

At Mon, 13 Mar 2006 13:10:45 +0900,
[email protected] wrote in [ruby-talk:183841]:

 harp:~ > cat a.rb
 class Module
   def abstract_method m
     define_method(m) do |*a|
       begin; super; rescue NoMethodError; raise NotImplementedError, m; end

This hides NoMethodError within the super method too.

Instead:

  defined?(super) or raise NotImplementedError, m
  super

In Java, the presence of methods is checked at compiletime,
if they are defined “abstract”. Your solution only checks the
presence of these methods at runtime, which is already
checked by Ruby itself.

In this case (class definitions in Ruby), the closest to
“compile time” is probably “allocate time”. I mean, the first
time you use a class after you defined it, is the moment you
create an instance of that class. (Other ideas?)

If you want to check a class for specific methods, “allocate
time” might be the right time to do so. (Unless you’re willing
to wait until you run into the traditional NoMethodError.) I
came up with the following, using wrap_module_method (as
discussed before [1] and summarized here [2]) to wrap
Class#new.

This is probably not a good solution, unless you don’t care
about performance… It might be optimized by unwrapping the
Class#new once the class has been checked. Although that’s just
a theory, for now…

gegroet,
Erik V. - http://www.erikveen.dds.nl/

[1] http://tinyurl.com/ntbl4
[2] Ruby Monitor-Functions - Or Meta-Meta-Programming in Ruby


require “ev/metameta” # That’s where the code from [2] lives…

class Class
def abstract_method(*method_names)
wrap_module_method(:new) do |org_method, args, block, obj|
method_names.each do |method_name|
obj.instance_eval do
unless instance_methods.include?(method_name.to_s)
raise NotImplementedError, “Class #{self} doesn’t
implement method #{method_name}.”
end
end
end

   org_method.call(*args, &block)
 end

end
end


class Foo
abstract_method :baz
end

class Bar1 < Foo
end

class Bar2 < Foo
def baz
:ok
end
end

[Bar1, Bar2].each do |klass|
begin
klass.new
rescue NotImplementedError => e
$stderr.puts e.message
end
end

On Mon, 13 Mar 2006 [email protected] wrote:

This hides NoMethodError within the super method too.

Instead:

 defined?(super) or raise NotImplementedError, m
 super

hmmm - but that (both actually) fails here:

 harp:~ > cat a.rb
 class Module
   def abstract_method m
     define_method(m) do |*a|
       defined?(super) ? super : raise(NotImplementedError, m)
     end
   end
 end

 class A
   def foo; 42; end
 end
 class B < A
   abstract_method "foo"
 end

 p B::new.foo


 harp:~ > ruby a.rb
 42

what about this fix?

 harp:~ > cat a.rb
 class Module
   def abstract_method m
     already_respond_to_m = instance_method(m) rescue nil

     define_method(m) do |*a|
       if already_respond_to_m
         raise(NotImplementedError, m)
       else
         defined?(super) ? super : raise(NotImplementedError, m)
       end
     end

   end
 end

 class A
   def foo; 42; end
 end
 class B < A
   abstract_method "foo"
 end

 p B::new.foo


 harp:~ > ruby a.rb
 b.rb:7:in `foo': foo (NotImplementedError)
         from b.rb:23

thoughts?

-a

On Mon, 13 Mar 2006, Erik V. wrote:

In this case (class definitions in Ruby), the closest to “compile time” is
probably “allocate time”. I mean, the first time you use a class after you
defined it, is the moment you create an instance of that class. (Other
ideas?)

how interesting!

this is a very appropriate for some circumstances which i’d never
thought of -
i’m sure i’ll steal it in the near future. :wink:

regards.

-a

A good portion of the GoF patterns rely on abstract methods (visitor,
abstract factory, template method, etc… ) which IMO only shine in
statically typed languages. It would be a shame to port all patterns
(and their required prerequisite: abstract methods) simply because they
are recognized in the static world and therefore would make a good fit
in Ruby.

The additional code needed for the ruby “abstract method” approach
doesn’t make the code any more readable. The extra LoC actually slows
down the maintenance developer as she has to wade through more.

In both solutions, an exception is thrown at runtime. The abstract
method approach will not allow the developer to catch it any earlier
than the duck typed default.

The exception proposed although slightly more readable will not in
practice add any value as Ruby developers are used to seeing the
exception and can narrow in on it expediently.

We should simply rejoice in the power of the mixin and realize that the
abstract specifier was devised prior to (and probably due to the absence
of) this incredibly powerfull construct.

Lastly, the code becomes somewhat heavier which violates 2 key
principles of Ruby, one being the enjoyable to code principle, and the
other, least surprise principle.

ilan

The exception proposed although slightly more readable will
not in practice add any value as Ruby developers are used to
seeing the exception and can narrow in on it expediently.

I’m not advocating these abstract methods in Ruby. On the
contrary, I don’t like them either.

It’s just that, when I read this thread, I thought: Can I do
that with my meta-meta-programming library? Answer: yes. That’s
all what I wanted to know… :slight_smile:

It’s not about “yes or no”, but about “how if yes”…

gegroet,
Erik V. - http://www.erikveen.dds.nl/

On Tue, 14 Mar 2006, ilan berci wrote:

A good portion of the GoF patterns rely on abstract methods (visitor,
abstract factory, template method, etc… ) which IMO only shine in
statically typed languages. It would be a shame to port all patterns (and
their required prerequisite: abstract methods) simply because they are
recognized in the static world and therefore would make a good fit in Ruby.

The additional code needed for the ruby “abstract method” approach doesn’t
make the code any more readable. The extra LoC actually slows down the
maintenance developer as she has to wade through more.

i disagree strongly here. check out these two snippets that i am
working on
as we speak:

 def will_process_holding *a, &b
   raise NotImplementedError
 end
 def process_holding *a, &b
   raise NotImplementedError
 end
 def will_process_incoming(*a, &b)
   raise NotImplementedError
 end
 def process_incoming(*a, &b)
   raise NotImplementedError
 end

vs

 abstract_method "will_process_holding"
 abstract_method "process_holding"
 abstract_method "will_process_incoming"
 abstract_method "process_incoming"

it’s for precisely these kinds of simple repetetive defs that we have
‘attr’,
‘attr_accessor’, ‘attr_writer’, and ‘attr_reader’. think about how
simple all
these methods are to write - but people love the shorthand and the fact
that
rdoc can grok something meaningful from the metaprogramming is quite
beneficial.

sure - i could just go full on duck type - but good luck reading the
2000 line
satellite image processing library that requires these four methods (and
about
20 others) and trying to figure out which ones you need to implement. i
nice
compact listing like this surely helps out with that task doesn’t it?

here’s another example from the standard lib

 tsort.rb
 ...
   #
   # Should be implemented by a extended class.
   #
   # #tsort_each_node is used to iterate for all nodes over a graph.
   #
   def tsort_each_node # :yields: node
     raise NotImplementedError.new
   end

   #
   # Should be implemented by a extended class.
   #
   # #tsort_each_child is used to iterate for child nodes of _node_.
   #
   def tsort_each_child(node) # :yields: child
     raise NotImplementedError.new
   end
 ...

now, all this starts out at about line 230. this is a little deep is it
not?
i think it’d be great of rdoc understood and abstract_method hook just
like it
now supports the ‘attr_XXX’ hooks but, even without that, i’ll take any
hint i
can get in code like this.

ask yourself this: why did the author not just rely on duck-typing? why
put
these methods into the code at all?

In both solutions, an exception is thrown at runtime. The abstract method
approach will not allow the developer to catch it any earlier than the duck
typed default.

unless, using one approach it takes an hour to figure out which methods
to
impliment and the other way it does not. consider an abstract method

module Interface
def extra_debugging_info e

end
end

used like

module Interface
def foobar
begin


rescue ExceptionThatOccursOncePerMonth => e
logger.warn{ extra_debugging_info e}
end
end
end

how anoying! you really should have written that method because your
code now
fails once per month. having an ‘abstract_method’ hook makes it so,
even if
the developer didn’t comment their code, the code itself clearly showed
the
list of methods which should be implimented.

trust me - i realize this is really a small gain over pure duck typing -
but
for the kinds of systems i’m writing, with 10,000 lines of ruby code,
it’s
really quite helpful to have this sort of note to myself jump out in the
code. that’s why i’ve already written this:

class Subscription

def self::abstract_method m
module_eval <<-definition
def #{ m }(*a, &b)
raise NotImplementedError
end
definition
end

The exception proposed although slightly more readable will not in
practice add any value as Ruby developers are used to seeing the
exception and can narrow in on it expediently.

agreed. the point is to not get the exception in the first place
becausee the
code was easier to understand how to hook into.

We should simply rejoice in the power of the mixin and realize that the
abstract specifier was devised prior to (and probably due to the absence
of) this incredibly powerfull construct.

Lastly, the code becomes somewhat heavier which violates 2 key
principles of Ruby, one being the enjoyable to code principle, and the
other, least surprise principle.

i really don’t see why people would object to this idea. is it because
people
are only writing 100 line programs in ruby that might require one
abstract
method? i just don’t understand how someone could think that diving
into a
complex inheritence hierarchy of 30 classes/modules requiring 20 or so
abstract
methods would NOT be made easier to grok if one could grep for
/abstract_method/ in their editor to get a jump on things…

my 2cts.

kind regards.

-a

On 3/13/06, [email protected] [email protected] wrote:

slows down the maintenance developer as she has to wade through more.
raise NotImplementedError
abstract_method “process_incoming”
Okay, Ara. Why do these methods need to be abstract and specifically
have code around them? IMO, the same question should be asked of
tsort.rb. I think that, in both cases, the answer is the same: they
don’t.

Adding a definition for an “abstract_method” really doesn’t add
anything to the readability of the code that a well-written comment
(which is read by rdoc without modification) doesn’t provide.

[…]

sure - i could just go full on duck type - but good luck reading the
2000 line satellite image processing library that requires these four
methods (and about 20 others) and trying to figure out which ones you
need to implement. i nice compact listing like this surely helps out
with that task doesn’t it?

I’m not sure. As I said earlier, PDF::Writer doesn’t use them. In
development versions of PDF::Writer, things like that have appeared –
and promptly been removed because they add clutter, not clarity.

[…]

now, all this starts out at about line 230. this is a little deep is
it not? i think it’d be great of rdoc understood and abstract_method
hook just like it now supports the ‘attr_XXX’ hooks but, even without
that, i’ll take any hint i can get in code like this.

ask yourself this: why did the author not just rely on duck-typing?
why put these methods into the code at all?

I ask, instead, how old tsort.rb is – and that will generally indicate
why it has defined abstract methods.

In both solutions, an exception is thrown at runtime. The abstract
method approach will not allow the developer to catch it any earlier
than the duck typed default.
unless, using one approach it takes an hour to figure out which
methods to impliment and the other way it does not.

Ara, this ignores the examples I gave early on:

All clients of this module must implement #each with no parameters.

module Enum
def map
arr = []
each { |elem| arr << yield(elem) }
arr
end
end

I have just made #each an abstract method without adding any code at
all.

The exception proposed although slightly more readable will not in
practice add any value as Ruby developers are used to seeing the
exception and can narrow in on it expediently.
agreed. the point is to not get the exception in the first place
becausee the code was easier to understand how to hook into.

And I disagree that it makes it easier to read, Ara. I don’t write
10,000 line programs, but PDF::Writer is 5,000 lines. Certain items,
especially in current development versions, could easily have been
declared as “abstract” (and would have to had been in static languages)
but aren’t necessary to do such in Ruby.

i really don’t see why people would object to this idea. is it
because people are only writing 100 line programs in ruby that might
require one abstract method? i just don’t understand how someone
could think that diving into a complex inheritence hierarchy of 30
classes/modules requiring 20 or so abstract methods would NOT be made
easier to grok if one could grep for /abstract_method/ in their editor
to get a jump on things…

I really don’t think that there’s need for this in the core. I think
that the use of it is a crutch; with the programs you have to write,
Ara, that might be necessary. (I’ve used similar crutches in some
versions of PDF::Writer experiments.)

-austin

On 3/13/06, [email protected] [email protected] wrote:

   raise NotImplementedError
 abstract_method "process_incoming"

The question is, why use either of those methods? Why not just note
in your documentation that those four functions must be defined? The
user is going to have to read the documentation anyway, in order to
understand what those four abstract methods are for. A
“NoMethodError” conveys the same information as a
“NotImplementedError”, in this case.

And this is arguably an abuse of NotImplementedError. The usual
semantics of NotImplementedError are to indicate that the method is
either a) not yet implemented by a library; or b) is not supported on
the current platform. Whereas in the example above it is being used
to indicate that a precondition was not met.

I see that you’re trying to make your code more declarative and more
explicit about it’s semantics. But seeing ‘abstract_method
:will_process_holding’ doesn’t tell me anything more than getting a
“NoMethodError: will_process_holding”. Both of them just tell me I’m
going to have to go look at the documentation to learn what the heck
#will_process_holding is supposed to do.

If you really want to add useful semantic information, then put in
more specific error information where the “abstract” method is
called. E.g.:

def frobnicate(duck)
    duck.quack() rescue NoMethodError raise("Ducks must quack in

order to be frobnicated. See documentation.")
end

If you want to get fancy and declarative and proactive about it, you
could make a #precondition method:

def frobnicate(duck)
    precondition("Ducks must quack in order to be frobnicated"){

duck.respond_to? :quack}

end

I believe there are some libraries out there that assist in doing this
kind of “strict duck typing”.

As a bonus, you are keeping your preconditions close to the code that
actually depends on them, which reduces the chances that they will get
out of sync with your code, and give the user false information.

~Avdi

I still prefer the “full on type ducking” with a readable comment in the
file. As for the exception that occurs once a month, I get the same
thing in statically compiled language! Sure I am guaranteed that the
method exists due to my compiler bulking at the ommission of my method
definition but since it will only get exercized once a month, I probably
won’t see the error till the runtime hits it anyway. (and yes, I have
had yearly bugs pop up on new years day…) The answer is proper test
cases that detect these things early. A compiler making sure your
method exists is not a proper test of the monthly condition that may
occur.

As an aside, I should state that all my Ruby is on peripheral projects
assisting my main enterprise development project. The complexity of my
Ruby projects has not reached 10k LoC so I should make that caveat
clear. :slight_smile:

ilan

unknown wrote:

i disagree strongly here. check out these two snippets that i am
working on
as we speak:

 def will_process_holding *a, &b
   raise NotImplementedError
 end
 def process_holding *a, &b
   raise NotImplementedError
 end
 def will_process_incoming(*a, &b)
   raise NotImplementedError
 end
 def process_incoming(*a, &b)
   raise NotImplementedError
 end

vs

 abstract_method "will_process_holding"
 abstract_method "process_holding"
 abstract_method "will_process_incoming"
 abstract_method "process_incoming"

On Tue, 14 Mar 2006, Austin Z. wrote:

Okay, Ara. Why do these methods need to be abstract and specifically have
code around them? IMO, the same question should be asked of tsort.rb. I
think that, in both cases, the answer is the same: they don’t.

Adding a definition for an “abstract_method” really doesn’t add anything
to the readability of the code that a well-written comment (which is read
by rdoc without modification) doesn’t provide.

you are perfectly correct. however, i think we all know that there is a
lot
of code, especially in-house, where the docs are pretty thin. in my
case
keeping 30,000 lines of ruby documented makes no sense since

  • i’m the only developer

  • we do research and the code changes daily

  • it’s less work to use long variable names and abstract code at
    every
    possible opportunity into stand-alone libs than to write docs.

it just makes my life easier to do things like (all real examples)

native_int_attribute ‘samples’

xdr_long_attribute ‘grid_size’

$LOAD_PATH << “nrtlib” # vs $:

abort “#{ $PROGRAM_NAME } parse failure” # vs $0

hash_of_subscriber_to_prefixes = {}

abstract_method ‘foo’

required_argument ‘dirname’

option ‘–verbose’, ‘-v’

in otherwords, to make the code slightly more verbose, self describing,
editor
searchable (this is huge ihmho), and clear to someone new taking over
the
project because there aint’ any docs.

also, i’d maintain encoding sematics into docs is more difficult that it
sounds. if it weren’t the entire stdlib would have great docs - lord
knows
there has been enough time and man power available. but the truth is in
the
puddin - people (myself included) don’t do it (enough).

I’m not sure. As I said earlier, PDF::Writer doesn’t use them. In
development versions of PDF::Writer, things like that have appeared – and
promptly been removed because they add clutter, not clarity.

trust me - i with you. sometimes. most of my libs take that approach
too.
but sometimes it’s nice to be extra clear.

the thing is, having ‘abstract_method’ does not prevent one from using
your
approach - it’s simply another arrow in the quiver.

I ask, instead, how old tsort.rb is – and that will generally indicate why
it has defined abstract methods.

sure. but it’s in the stdlib as is alot of old code where often the
code is
the only correct/detailed documentation. i don’t even use ri or rdoc
anymore

  • i prefer to simply do something like

    vim -o webrick.rb webrick/*

and peek around. it would be great to then do

/abstract_method

just as i know often do

/attr

or

/def <<

etc.

I have just made #each an abstract method without adding any code at
all.

oh i know, and i’d never use ‘abstract_method’ here - but what if the
number
of ‘virtual abstract methods’ exceeded fifty?

And I disagree that it makes it easier to read, Ara. I don’t write
10,000 line programs,

(OT: me neither btw - but all the libs/progs together approach 30k in my
latest system - i think the largest file is only about 1000 lines.
fyi)

but PDF::Writer is 5,000 lines. Certain items, especially in current
development versions, could easily have been declared as “abstract” (and
would have to had been in static languages) but aren’t necessary to do such
in Ruby.

I really don’t think that there’s need for this in the core. I think
that the use of it is a crutch; with the programs you have to write,
Ara, that might be necessary. (I’ve used similar crutches in some
versions of PDF::Writer experiments.)

you may be right here - perhaps a lib only. still, one could make
almost
every argument against ‘attr’ and co. you’ve made against
‘abstract_method’.
both are unnecessary simple convenience solutions for simple problems.
still,
unless a more grandiose vision of abstract methods/interfaces is in the
plans

  • what would it hurt?

kind regards.

-a

On Mar 13, 2006, at 2:21 PM, [email protected] wrote:

  • it’s less work to use long variable names and abstract code at
    every
    possible opportunity into stand-alone libs than to write docs.

What’s the big difference between

abstract method foo

and

abstract_method :foo ?

This is what’s boggling my mind. It’s not writing some documentation,
its writing it in the same place you’d call your abstract_method
method anyway. And you can still search for it within vim or
whatever. I don’t know enough about your particular case for
“native_int_atrribute” but tyou’re probably talkign to some library
that expects an int and that method probably does some checking on
assignment, which is fine. That makes sense. What I’m suggesting is
that although a program should explode immediately when there’s a
problem, it also shouldn’t explode when there isn’t one. If I never
call map, each will never be called, so its ok if I don’t implement
it. Then on the day I do call it, and run it for the first time, it
expldoes right there, when I’m calling each. I know immediately what
change I just made caused it to explode. OTOH if I mixin Enumerable
w/o an each, and each is an “abstract_method” it breaks whether I use
it or not. But when everbody starts using abstract methods, all of a
sudden I’m back in the land of compile-fix, compile-fix. Cause that
error is gonna happen right away, so I have to deal with that
immediate error. Then I can run it again to make sure it works, but
now the error happens again, compile-fix ad infinitum.

On 3/13/06, Logan C. [email protected] wrote:

error is gonna happen right away, so I have to deal with that
immediate error. Then I can run it again to make sure it works, but
now the error happens again, compile-fix ad infinitum.

Umm, except, no. Maybe if we used Erik’s “allocation-time checking”
approach, but not with kwatch’s NotImplementedError approach. If you
mixin Enumerable, but then never call map/inject/collect/etc., you’ll
never get the NotImplementedError exception, just as you never got the
NoMethodError exception. As far as behavior, timing/severity of the
failure is exactly the same – you get an exception when the library
tries to use the method you should have defined.

The value of Erik’s approach (which, as Pit and Matz pointed out,
needs refining) is in self-documentation and explicit error messages.
Obviously, you and Ara don’t agree on how much that self-documentation
is worth. I’m not sure either; you both make good arguments. This is
the reason why I also vote against it being in the core.

However, I highly value the more descriptive exception. I’ll take an
exception that tells me “If you want to extend Enumerable, you need to
provide an ‘each’ method” over “NoMethodError: each” any day. Sure, I
have to go back to the documentation and see what that each method
should do, but I know more precisely why things are failing. You may
disagree, and that’s fine. I’m just staing my opinion as to why I
think it will be a valuable non-core library.

Jacob F.

[email protected] schrieb:

(… implementing Module#abstract_method …)

All those implementations which actually create dummy methods prohibit
implementing an abstract method using method_missing.

Regards,
Pit

[email protected] wrote:

i think it’d be great of rdoc understood and abstract_method hook
just like it now supports the ‘attr_XXX’ hooks but, even without
that, i’ll take any hint i can get in code like this.

Rdoc does! Just use the -A option:

rdoc -A abstract_method=ABSTRACT

or something like that. Change ABSTRACT to be something you like that
will tag the attr the the rdoc output.

rdoc -h | grep -A 5 “accessor”
–accessor, -A accessorname[,…]
comma separated list of additional class methods
that should be treated like ‘attr_reader’ and
friends. Option may be repeated. Each accessorname
may have ‘=text’ appended, in which case that text
appears where the r/w/rw appears for normal accessors.

Hi,

At Tue, 14 Mar 2006 01:01:31 +0900,
[email protected] wrote in [ruby-talk:183918]:

 harp:~ > ruby a.rb
 42

Simply separate Module#abstract_method and Class#abstract_method.

 class Class
   def abstract_method m
     define_method(m) do |*a|
       raise(NotImplementedError, m)
     end
   end
 end