Lazydoc

Lazydoc lazily pulls documentation out of source files and makes it available in code through lazy attributes. Lazydoc is used by the Tap framework.

Description

Lazydoc allows you to define lazy attributes that act as markers for documentation in a source file. When you call the lazy attribute, Lazydoc pulls out the documentation:

# Sample::key <value>
# This is the comment content.  A content
# string can span multiple lines...
class Sample
  extend Lazydoc::Attributes
  lazy_attr :key
end

comment = Sample::key
comment.value      # => "<value>"
comment.comment    # => "This is the comment content.  A content string can span multiple lines..."

Comments support wrapping, allowing for easy presentation:

thirtydots = "\n#{'.' * 30}\n"

"#{thirtydots}#{comment.wrap(30)}#{thirtydots}"
# => %q{
# ..............................
# This is the comment content.
# A content string can span
# multiple lines...
# ..............................
# }

In addition, Lazydoc provides helpers to register individual lines of code, particularly method definitions:

class Helpers
  extend Lazydoc::Attributes

  lazy_register(:method_one)

  # method_one is registered whenever it 
  # gets defined
  def method_one(a, b='str', &c)
  end

  # register_caller will register the line
  # that *calls* method_two
  def method_two
    Lazydoc.register_caller
  end
end

# *THIS* is the line that gets
# registered by method_two
Helpers.const_attrs[:method_two] = Helpers.new.method_two

doc = Helpers.lazydoc
doc.resolve

one = Helpers.const_attrs[:method_one]
one.method_name            # => "method_one"
one.arguments              # => ["a", "b='str'", "&c"]
one.to_s                   # => "method_one is registered whenever it gets defined"

two = Helpers.const_attrs[:method_two]
two.subject                # => "Helpers.const_attrs[:method_two] = Helpers.new.method_two"
two.to_s                   # => "*THIS* is the line that gets registered by method_two"

Lazy accessors may be defined to map the registered lines as well:

class Helpers
  lazy_attr(:one, :method_one)
  lazy_attr(:two, :method_two)
end

Helpers.one.method_name    # => "method_one"
Helpers.two.subject        # => "Helpers.const_attrs[:method_two] = Helpers.new.method_two"

Check out these links for development, and bug tracking.

Usage

Lazydoc can find two types of documentation, constant attributes and code comments. The distinction is primarily how they are found and parsed; both are represented by Comment objects.

Constant Attributes

Constant attributes are like constants in Ruby, but with an extra ‘key’ that must consist of only lowercase letters and/or underscores. For example, these are constant attributes:

# Const::Name::key
# Const::Name::key_with_underscores
# ::key

While these are not:

# Const::Name::Key
# Const::Name::key2
# Const::Name::k@y

Lazydoc parses a Lazydoc::Comment for each constant attribute by using the remainder of the line as a value (ie subject) and parsing down for content. Parsing continues until a non-comment line, an end key, or a new attribute is reached; the comment is then stored by constant name and key.

str = %Q{
# Const::Name::key value for key
# comment for key
# parsed until a 
# non-comment line

# Const::Name::another value for another
# comment for another
# parsed to an end key
# Const::Name::another-
#
# ignored comment
}

doc = Lazydoc::Document.new
doc.resolve(str)

doc.summarize {|c| [c.value, c.comment] } 
# => {
# 'Const::Name' => {
#   'key' =>     ['value for key', 'comment for key parsed until a non-comment line'],
#   'another' => ['value for another', 'comment for another parsed to an end key']}
# }

Constant attributes are only parsed from commented lines. To turn off attribute parsing for a section of documentation, use start/stop keys:

str = %Q{
Const::Name::not_parsed

# :::-
# Const::Name::not_parsed
# :::+
# Const::Name::parsed value
}

doc = Lazydoc::Document.new
doc.resolve(str)
doc.summarize {|comment| comment.value }   # => {'Const::Name' => {'parsed' => 'value'}}

To hide attributes from RDoc, make use of the RDoc :startdoc: document modifier like this (note that spaces are added to prevent RDoc from hiding the example):

# :start doc::Const::Name::one hidden in RDoc
# * This line is visible in RDoc.
# :start doc::Const::Name::one-
# 
#-- 
# Const::Name::two
# You can hide attribute comments like this.
# Const::Name::two-
#++
#
# * This line is also visible in RDoc.

As a side note, ‘Const::Name::key’ is not a reference to the ‘key’ constant (that would be invalid). In very idiomatic ruby ‘Const::Name::key’ is equivalent to the method call ‘Const::Name.key’.

Code Comments

Code comments are lines registered for parsing if and when a Lazydoc gets resolved. Unlike constant attributes, the registered line is the comment subject (ie value) and contents are parsed up from it (basically mimicking the behavior of RDoc).

str = %Q{
# comment lines for
# the method
def method
end

# as in RDoc, the comment can be
# separated from the method

def another_method
end
}

doc = Lazydoc::Document.new
doc.register(3)
doc.register(9)
doc.resolve(str)

doc.comments.collect {|c| [c.subject, c.comment] } 
# => [
# ['def method', 'comment lines for the method'],
# ['def another_method', 'as in RDoc, the comment can be separated from the method']]

Comments may be registered to specific line numbers, or with a Proc or Regexp that will determine the line number during resolution. In the case of a Regexp, the first matching line is used; Procs receive an array of lines and should return the line number that should be used. See Comment#parse_up for more details.

Installation

Lazydoc is available as a gem on RubyForge. Use:

% gem install lazydoc

Info

Copyright © 2008-2009, Regents of the University of Colorado.

Developer

Simon Chiang, Biomolecular Structure Program, Hansen Lab

Support

CU Denver School of Medicine Deans Academic Enrichment Fund

Licence

MIT-Style