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 still just a functional lanaguage in this respect, and not a full 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 announce => Tool
puts "This is my new project!"
end
announce.help = "Announces your project to the world!"
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.