lib/lazydoc.rb in lazydoc-0.2.0 vs lib/lazydoc.rb in lazydoc-0.3.0
- old
+ new
@@ -1,202 +1,95 @@
require 'lazydoc/document'
module Lazydoc
- autoload(:Attributes, 'lazydoc/attributes')
-
- # A regexp matching an attribute start or end. After a match:
- #
- # $1:: const_name
- # $3:: key
- # $4:: end flag
- #
- ATTRIBUTE_REGEXP = /([A-Z][A-z]*(::[A-Z][A-z]*)*)?::([a-z_]+)(-?)/
-
- # A regexp matching constants from the ATTRIBUTE_REGEXP leader
- CONSTANT_REGEXP = /#.*?([A-Z][A-z]*(::[A-Z][A-z]*)*)?$/
-
- # A regexp matching a caller line, to extract the calling file
- # and line number. After a match:
- #
- # $1:: file
- # $3:: line number (as a string, obviously)
- #
- # Note that line numbers in caller start at 1, not 0.
- CALLER_REGEXP = /^(([A-z]:)?[^:]+):(\d+)/
-
module_function
- # A hash of (source_file, lazydoc) pairs tracking the
- # Lazydoc instance for the given source file.
+ # An array of documents registered with Lazydoc.
def registry
@registry ||= []
end
- # Returns the lazydoc in registry for the specified source file.
- # If no such lazydoc exists, one will be created for it.
+ # Returns the Document in registry for the specified source file.
+ # If no such Document exists, one will be created for it.
def [](source_file)
source_file = File.expand_path(source_file.to_s)
+ registry.find {|doc| doc.source_file == source_file } || register_file(source_file)
+ end
+
+ # Generates a Document the source_file and default_const_name and adds it to
+ # registry, or returns the document already registered to source_file. An
+ # error is raised if you try to re-register a source_file with an inconsistent
+ # default_const_name.
+ def register_file(source_file, default_const_name=nil)
+ source_file = File.expand_path(source_file.to_s)
lazydoc = registry.find {|doc| doc.source_file == source_file }
- if lazydoc == nil
- lazydoc = Document.new(source_file)
+
+ unless lazydoc
+ lazydoc = Document.new(source_file, default_const_name)
registry << lazydoc
end
+
+ if lazydoc.default_const_name != default_const_name
+ raise ArgumentError, "inconsistent default_const_name specified for #{source_file}: #{lazydoc.default_const_name.inspect} != #{default_const_name.inspect}"
+ end
+
lazydoc
end
- # Register the specified line numbers to the lazydoc for source_file.
- # Returns a comment_class instance corresponding to the line.
+ # Registers the line number to the document for source_file and
+ # returns the corresponding comment.
def register(source_file, line_number, comment_class=Comment)
Lazydoc[source_file].register(line_number, comment_class)
end
- # Registers the method at the specified index in the call stack, to
+ # Registers the method at the specified index in the call stack to
# the file where the method was called. Using the default index of
# 1, register_caller registers the caller of the method where
- # register_caller is called. For instance:
+ # register_caller is called (whew!). For instance:
#
# module Sample
# module_function
# def method
# Lazydoc.register_caller
# end
# end
#
# # this is the line that gets registered
- # Sample.method
+ # c = Sample.method
#
+ # c.resolve
+ # c.subject # => "c = Sample.method"
+ # c.comment # => "this is the line that gets registered"
+ #
def register_caller(comment_class=Comment, caller_index=1)
caller[caller_index] =~ CALLER_REGEXP
Lazydoc[$1].register($3.to_i - 1, comment_class)
end
- # Resolves all lazydocs which include the specified code comments.
- def resolve_comments(comments)
- registry.each do |doc|
- next if (comments & doc.comments).empty?
- doc.resolve
- end
- end
-
- # Scans the specified file for attributes keyed by key and stores
- # the resulting comments in the source_file lazydoc. Returns the
- # lazydoc.
- def scan_doc(source_file, key)
- lazydoc = nil
- scan(File.read(source_file), key) do |const_name, attr_key, comment|
- lazydoc = self[source_file] unless lazydoc
- lazydoc[const_name][attr_key] = comment
- end
- lazydoc
- end
-
- # Scans the string or StringScanner for attributes matching the key
- # (keys may be patterns, they are incorporated into a regexp). Yields
- # each (const_name, key, value) triplet to the mandatory block and
- # skips regions delimited by the stop and start keys <tt>:-</tt>
- # and <tt>:+</tt>.
+ # Parses the usage for a file (ie the first comment in the file
+ # following an optional bang line), wrapped to n cols. For
+ # example, with this:
#
- # str = %Q{
- # # Const::Name::key value
- # # ::alt alt_value
+ # [hello_world.rb]
+ # #!/usr/bin/env ruby
+ # # This is your basic hello world
+ # # script:
# #
- # # Ignored::Attribute::not_matched value
- # # :::-
- # # Also::Ignored::key value
- # # :::+
- # # Another::key another value
+ # # % ruby hello_world.rb
#
- # Ignored::key value
- # }
+ # puts 'hello world'
#
- # results = []
- # Lazydoc.scan(str, 'key|alt') do |const_name, key, value|
- # results << [const_name, key, value]
- # end
+ # You get this:
#
- # results
- # # => [
- # # ['Const::Name', 'key', 'value'],
- # # ['', 'alt', 'alt_value'],
- # # ['Another', 'key', 'another value']]
+ # "\n" + Lazydoc.usage('hello_world.rb')
+ # # => %Q{
+ # # This is your basic hello world script:
+ # #
+ # # % ruby hello_world.rb}
#
- # Returns the StringScanner used during scanning.
- def scan(str, key) # :yields: const_name, key, value
- scanner = case str
- when StringScanner then str
- when String then StringScanner.new(str)
- else raise TypeError, "can't convert #{str.class} into StringScanner or String"
- end
-
- regexp = /^(.*?)::(:-|#{key})/
- while !scanner.eos?
- break if scanner.skip_until(regexp) == nil
-
- if scanner[2] == ":-"
- scanner.skip_until(/:::\+/)
- else
- next unless scanner[1] =~ CONSTANT_REGEXP
- key = scanner[2]
- yield($1.to_s, key, scanner.matched.strip) if scanner.scan(/[ \r\t].*$|$/)
- end
- end
-
- scanner
- end
-
- # Parses constant attributes from the string or StringScanner. Yields
- # each (const_name, key, comment) triplet to the mandatory block
- # and skips regions delimited by the stop and start keys <tt>:-</tt>
- # and <tt>:+</tt>.
- #
- # str = %Q{
- # # Const::Name::key subject for key
- # # comment for key
- #
- # # :::-
- # # Ignored::key value
- # # :::+
- #
- # # Ignored text before attribute ::another subject for another
- # # comment for another
- # }
- #
- # results = []
- # Lazydoc.parse(str) do |const_name, key, comment|
- # results << [const_name, key, comment.subject, comment.to_s]
- # end
- #
- # results
- # # => [
- # # ['Const::Name', 'key', 'subject for key', 'comment for key'],
- # # ['', 'another', 'subject for another', 'comment for another']]
- #
- # Returns the StringScanner used during scanning.
- def parse(str) # :yields: const_name, key, comment
- scanner = case str
- when StringScanner then str
- when String then StringScanner.new(str)
- else raise TypeError, "can't convert #{str.class} into StringScanner or String"
- end
-
- scan(scanner, '[a-z_]+') do |const_name, key, value|
- comment = Comment.parse(scanner, false) do |line|
- if line =~ ATTRIBUTE_REGEXP
- # rewind to capture the next attribute unless an end is specified.
- scanner.unscan unless $4 == '-' && $3 == key && $1.to_s == const_name
- true
- else false
- end
- end
- comment.subject = value
- yield(const_name, key, comment)
- end
- end
-
- # Parses the usage for a file, ie the first comment in the file
- # following an optional bang line.
def usage(path, cols=80)
scanner = StringScanner.new(File.read(path))
- scanner.scan(/^#!.*?$/)
- Comment.parse(scanner, false).wrap(cols, 2).strip
+ scanner.scan(/#!.*?\r?\n/)
+ scanner.scan(/\s*#/m)
+ Comment.new.parse_down(scanner, nil, false).wrap(cols, 2).strip
end
end
\ No newline at end of file