From: Sam Roberts Date: 2003-03-10T03:02:12+09:00 Subject: Re: rdoc - how to exclude internal APIs, and use :title: and :main:? --X1bOJ3K7DJ5YkBrT Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Quoteing dave@pragprog.com, on Sun, Mar 09, 2003 at 12:11:22PM +0900: > On Saturday, Mar 8, 2003, at 19:59 US/Central, Sam Roberts wrote: > >++ Q1 > Your best bet is probably to use :nodoc: on the internal module and the > internal private methods. Perfect, sorry I missed that in the docs. > Strange - both worked for me when I tried them here. Perhaps you are > not running the latest RDoc? I suggest getting the CVS version from > SourceForge and trying again. OK, things are much better from CVS. I have a title, and I think :main: is respected. But I have a new message now, what does Found symbol "line" mean? Attached is the src, in case that helps. Notice that I have: # Author:: Sam Roberts # Copyright:: Copyright (C) 2003 Sam Roberts # License:: May be distributed under the same terms as Ruby # # An implementation of the MIME Content-Type for Directory # Information (RFC 2425), and profiles of this format. module Rfc2425 ... Basically copied from your example, but in the html, those lines all begin with a '#' character. And the text description starts with two hashes! Is this intended? > Also, the 'main' directive sets the main page to the file that contains > the given symbol, which might not be the effect you're expecting. Is it possible that this may have been interacting badly with the --one-file option? Btw, I seem to have much more than one file, so I'm not to sure what --one-file is for. I was hoping to get all the docs in one file... :-) though I guess that's not possible with html frames. Thanks, Sam --X1bOJ3K7DJ5YkBrT Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="vcard.rb" =begin vcard - a library to manipulate vCard 2.1, vCard 3.0, and RFC 2425 objects. Copyright (C) 2003 Sam Roberts This library is free software; you can redistribute it and/or modify it under the same terms as the ruby language itself, see the file COPYING for details. =end =begin TODO: + VcardCollection class + allow passing a file to DirectoryInfo.new? + Put Field inside DirectoryInfo? + I think it's not good to return an Array OR a singular value + implement encoding + Allow the default capitalization of groups, names, and params to be specied by providing blocks, or something? + :title:, :main: not working? + reimplement: http://raa.ruby-lang.org/list.rhtml?name=csv2vcard Q: writing... how to dirty? # Q: URI, does it encode, or just decode? # Q: how to look for particular names/params # Q: how to map particular field names to classes? Use the "value" param. Types are: uri/text/date/time/date-time/integer/boolean/float/ + ucs-2 <-> utf-8 encoding + mutt vcard address-book hook + decoding sequences/structures of dirinfo objects =end # :title:vcard - a library to manipulate vCard and RFC 2425 objects # :main:Rfc2425::Vcard # # Author:: Sam Roberts # Copyright:: Copyright (C) 2003 Sam Roberts # License:: May be distributed under the same terms as Ruby # # An implementation of the MIME Content-Type for Directory # Information (RFC 2425), and profiles of this format. module Rfc2425 # Contains regular expression strings for the EBNF of RFC 2425. module Bnf #:nodoc: # 1*(ALPHA / DIGIT / "=") NAME = '[-a-z0-9]+' # <"> <"> QSTR = '"[^"]*"' # * PTEXT = '[^";:,]*' # param-value = ptext / quoted-string PVALUE = "#{PTEXT}|#{QSTR}" # V3.0: contentline = [group "."] name *(";" param) ":" value # V2.1: contentline = *( group "." ) name *(";" param) ":" value # # We accept the V2.1 syntax for backwards compatibility. LINE = "((?:#{NAME}\\.)*)?(#{NAME})([^:]*)\:(.*)" # param = name "=" param-value *("," param-value) PARAM = ";(#{NAME})=((?:#{PVALUE})(?:,#{PVALUE})*)" end # Split on \r\n or \n to get the lines, unfold continued lines (they # start with ' ' or \t), and return the array of unfolded lines. def Rfc2425.unfold(card) #:nodoc: unfolded = [] card.split(/\r?\n/).each do |line| # If it's a continuation line, add it to the last. if( line =~ /^[ \t]/ ) unfolded << unfolded.pop + line[1, line.size-1] else unfolded << line end end unfolded end # A utility function to unwrap a base-64 encoded string. def Rfc2425.decode_b64(str) #:nodoc: str.unpack('m*')[0] end # A utility function to unwrap a quoted-printable encoded string. def Rfc2425.decode_qp(str) #:nodoc: str.unpack('M*')[0] end # Unfold the lines in +card+, then return an array of one Field object per # line. def Rfc2425.decode(card) #:nodoc: content = Rfc2425.unfold(card).collect { |line| Field.new(line) } end # Errors raised by the API. module Errors # The input is not validly encoded. class InvalidFormatError < StandardError; end # The encoding parameter value is not valid/recognized. class InvalidEncodingError < StandardError; end end class Field def initialize(line) unless line.kind_of? String raise ArgumentError end @line = line # This seems to pass for things that are not validly encoded, need to test # more... unless line =~ %r{#{Bnf::LINE}}i raise InvalidFormatError.new(line) end # Need to check that we at least got name... otherwise the content line isn't # valid. @group = $1 @name = $2 @params = $3 @value = $4 @params_hash = {} # Collect the params, if any. if @params.size > 1 @params.gsub( %r{#{Bnf::PARAM}}i ) do # param names are case-insenstive, and multi-valued name = $1.downcase if ! @params_hash.key? name @params_hash[name] = [] end # Q: I could have the param value be a single string, if it's the only value, # or an array if there are more than one values. $2.gsub( %r{(#{Bnf::PVALUE})} ) do if $1.size > 0 @params_hash[name] << $1.downcase end end end end end def to_s "#{@group}#{@name}#{@params}:#{@value}\n" end def inspect "<#{@group}><#{@name}><#{@params}><#{@value}>" end def name?(name) name.upcase == @name.upcase end def group?(group) group.upcase == @group.chop.upcase end def type?(type) types = param('type') if types types = types.include?(type.to_str.downcase) end end def group @group.size > 0 ? @group.chop : nil end def each_param(&block) if @params_hash @params_hash.each(&block) end end def param(name) v = @params_hash[name.downcase] if v v = v.collect { |p| p.downcase } end v end # return the value of the encoding parameter, if present, or nil if not # present def encoding e = param "encoding" if e.kind_of? Array raise "multi-valued encoding parameter found #{e}" end e end =begin # type # value_type =end # The decoded value, that is, the value after the encoding specified in # the encoding parameter, if any, has been stripped. Both the RFC 2425 # encoding parameter ("b", base-64) and the vCard 2.1 encoding parameters # ("base64", "quoted-printable", "8bit", and "7bit") are supported. def value case encoding when nil, "8bit", "7bit" then @value when "b", "base64" then @value.unpack('m*')[0] when "quoted-printable" then @value.unpack('M*')[0] else raise InvalidEncodingError(encoding) end end def raw_value @value end attr_reader :line, :name, :params_hash # Legacy method name. alias param_value_of param end # An RFC 2425 directory info object. # # A vCard, for example, is a specialization of a directory info object. class DirectoryInfo # Initialize a new DirectoryInfo object from a string. The string may be delimited using # IETF (CRLF) or Unix (LF) conventions. def initialize(string) # Should check that it implements to_str, not that it IS a string. unless string.kind_of? String raise ArgumentError.new("Vcard.new requires a String") end @string = string if ! @string.nil? @fields = Rfc2425.decode @string end end # Return the value of the first Field named +name+. def value_of(name) all = fields_by_name(name) v = nil if all v = all[0].value end all ? all[0].value : nil end # Return an array of all the groups, or nil if there are none. def all_groups all = @fields.collect{ |field| field.group } all.compact! all.uniq! if all.size < 1 all = nil end all end # Calls block once for each Field. def each(&block) # :yields: field @fields.each(&block) end # Calls block once for each Field for which +cond+ is true. def each_by(cond, &block) # :yields: field @fields.each { |field| if cond.call(field); block.call(field); end } end # Calls block once for each Field named +name+. def each_by_name(name, &block) # :yields: field each_by(Proc.new { |field| field.name?(name) }, &block) end # Calls block once for each Field in the group +group+. def each_by_group(group, &block) # :yields: field each_by(Proc.new { |field| field.group?(group) }, &block) end # Return an array of all fields, or nil if there are none. def fields @fields end # Return an array of all fields for which +cond+ is true, or nil if there are none. def fields_by(&cond) # :yields: field all = @fields.find_all { |field| cond.call(field) } all.size > 0 ? all : nil end # Return an array of all fields named +name+, or nil if there are none. def fields_by_name(name) fields_by { |field| field.name?(name) } end # Return an array of all fields in the group +group+, or nil if there are none. def fields_by_group(group) fields_by { |field| field.group?(group) } end # Return the first Field named +name+, or nil if there are none. def field_by_name(name) f = fields_by_name(name) f = f[0] if f f; end #-- # For encoding... #def card #@fields.collect { |line| line.to_s } . join "" #end #++ # Returns the source string. def to_s @string end # Checks that the DirectoryInfo object is correctly delmited by a BEGIN # and END, that their profile values match, and if the profile is specified, that # they are the specified profile. def check_begin_end(profile=nil) unless @fields[0].name? "begin" raise "No BEGIN" end unless @fields[-1].name? "end" raise "No END" end b = @fields[0].value.capitalize e = @fields[-1].value.capitalize unless b == e raise "BEGIN/END value mismatch" end if profile if profile.capitalize != b raise "Mismatched profile" end end b end end # A vCard, a specialization of a DirectoryInfo object. # # The vCard format is specified by: # [vCard 2.1] see http://imc.org # [RFC2425] a directory information framework (ftp://ftp.ietf.org/rfc/rfc2425.txt) # [RFC2426] vCard 3.0 is a specific profile of the RFC2425 framework (ftp://ftp.ietf.org/rfc/rfc2426.txt) # # This implements vCard 3.0, but is backwards compatible with vCard 2.1. class Vcard < DirectoryInfo # Initialize a new vCard from a string. The string may be delimited using # IETF (CRLF) or Unix (LF) conventions. def initialize(string) super(string) check_begin_end "vCard" end # Returns the vCard version multiplied by 10 as an Integer. # If no VERSION line is present (which is non-conformant) nil is returned. # I.e., a version 2.1 vCard would have a version of 21, a version 3.0 # vCard would have a version of 30. def version v = value_of "version" if v v = v.to_f * 10 v = v.to_i end end # Base methods... end end --X1bOJ3K7DJ5YkBrT--