-
-
Save mattwynne/4122250 to your computer and use it in GitHub Desktop.
# For context, this was inspired by the RubyRogues podcast #79 where they talked about | |
# documentation in Ruby, and specifically grumbled quite a bit about the failings of RDoc. | |
# | |
# http://rubyrogues.com/079-rr-documenting-code/ | |
# | |
# As someone who's spent a lot of time using an IDE for programming C# and Java, I think | |
# Ruby could do a lot better at putting documentation at our fingertips as we program. | |
# | |
# Maybe making the documentation part of the structure of the code would facilitate this? | |
# | |
module Documentable | |
def self.included(type) | |
type.class_eval do | |
def method(name) | |
doc = self.class.docs[name] | |
super(name).tap do |method| | |
method.class.class_eval do | |
define_method(:doc) { doc } | |
end | |
end | |
end | |
def self.doc(*args) | |
@last_doc = args.first.strip # <= insert sophistication here | |
end | |
def self.docs | |
@docs ||= {} | |
end | |
def self.method_added(method_name) | |
return if method_name == :method | |
docs[method_name] = @last_doc | |
end | |
end | |
end | |
end | |
class Foo | |
include Documentable | |
doc %{ | |
Docs for bar | |
} | |
def bar | |
end | |
doc %{ | |
Docs for foo | |
} | |
def foo | |
end | |
end | |
require 'rspec/expectations' | |
foo = Foo.new | |
foo.method(:bar).doc.should == "Docs for bar" | |
foo.method(:foo).doc.should == "Docs for foo" | |
puts "We won!" |
This made my night. :)
Methinks for something like this, monkeypatching core classes (like Method) might be permissible...
And by monkeypatching, I of course mean adding a module to them :-)
Love it, the simple elegance of it reminds me of the first time I read the minitest source :)
So does anyone want to take this further? @avid could you fork and show me what you mean about monkey-patching Module?
Like the idea. Love that fact that we could add metadata rather than just strings to this. Worried that any DSL we design around this will make the source tricky to read, so will need careful thought.
Would it be significantly worse to have the API as foo.doc(:bar)
rather than foo.method(:bar).doc
, where the doc
method is only added to instances if doc
has been called in the class? I realise this is adding an extra non-behaviour method to an object that's potentially in the domain (foo
), rather than one which is about the language (method(:bar)
), but it might ultimately be simpler, rather than trying to wrangle Ruby's weird Method
objects...
@lazyatom it seems to me that should be optional - so we keep the data on method, but add a sugary shortcut method that you can use if you want to. Probably less chance of a clash if it's called something a bit more long-winded like foo.doc_for_method(:bar)
This is an OUTSTANDING start! And I think the entire Ruby/Rails community would jump behind an initiative like this.
Related, from @lsegal: https://gist.github.com/lsegal/357240
Note that I did try patching the doc method onto the individual methods, but it seems that
method
returns new instances ofMethod
every time for the same method name.