Skip to content

Instantly share code, notes, and snippets.

@mattwynne
Created November 21, 2012 00:27
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save mattwynne/4122250 to your computer and use it in GitHub Desktop.
Save mattwynne/4122250 to your computer and use it in GitHub Desktop.
Integrated documentation for Ruby
# 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!"
@mattwynne
Copy link
Author

Note that I did try patching the doc method onto the individual methods, but it seems that method returns new instances of Method every time for the same method name.

@tjsingleton
Copy link

This made my night. :)

@avdi
Copy link

avdi commented Nov 21, 2012

Methinks for something like this, monkeypatching core classes (like Method) might be permissible...

@avdi
Copy link

avdi commented Nov 21, 2012

And by monkeypatching, I of course mean adding a module to them :-)

@NateBarnes
Copy link

Love it, the simple elegance of it reminds me of the first time I read the minitest source :)

@mattwynne
Copy link
Author

So does anyone want to take this further? @avid could you fork and show me what you mean about monkey-patching Module?

@chrismdp
Copy link

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.

@lazyatom
Copy link

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...

@mattwynne
Copy link
Author

@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)

@ParkinT
Copy link

ParkinT commented Nov 22, 2012

This is an OUTSTANDING start! And I think the entire Ruby/Rails community would jump behind an initiative like this.

@mattwynne
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment