Yes, that's right. I no longer believe in methods. Why? Becuase this is OOP and if the methods aren't honest to goodness objects from the start, without exception, then they are not really methods. They're just glorified functions.
Let me show you what I mean. I have a Project class in which is defined a set of tools that can manipulate it. Clearly the proper implementation abstraction for these tools is the method.
Class Project
def announce
puts "This is my new project!"
end
end
But these tools must be distinguishable from other supporting methods. Moreover additional information may be associated with these tools, like help information or valid states of the Project for the tool to be useful. How do we encode this information with Ruby? Since methods aren't first class objects, we are forced to return to functional programming. In which case, it is best to define some sort of DSL.
module ProjectDSL
def help( name, text )
@help ||= {}
@help[name] = text
end
def valid( name, &test )
@valid ||= {}
@valid[name] = test
end
end
Class Project
extend ProjectDSL
def announce
puts "This is my new project!"
end
help :announce, "Announces your project to the world!"
valid :announce { @version > "0.0.0" }
end
Now this kind of thing has come up enough in large projects, such as
Nitro, that a general means of
annotation proved to be most effective.
require 'facet/annotation'
Class Project
def announce
puts "This is my new project!"
end
ann :announce, :help => "Announces your project to the world!",
:valid => lambda { @version > "0.0.0" }
end
Annotations works very well, and if you find yourself in need of this kind of "method metadata" it is an excellent approach.
But I've worked with all this long enough now to be able to have a wide perspective on it and it's become very clear to me that the whole "special needs" arises out of the fact that Ruby is, in this respect at least, still a functional lanaguage and not a true OOPL. (And please no objections that
method()
and
instance_method()
make it otherwise, these do not provide a persitant object, but return a new object every time they are invoked.) So what might the above look like if it were not so? There would of course be more than one way to go about it, but imagine this:
class Tool < Method
attr_accessor :help
def valid( &test )
@valid = test
end
end
Class Project
def:Tool announce
puts "This is my new project!"
end
Tool:announce.help = "Announces your project to the world!"
Tool:announce.valid { @version > "0.0.0" }
end
I'm taking some liberties with the syntax here for clarity. But in anycase it certainly paints a provocative idea. And I would argue that it paints the approprite OOP idea too.