* Added rdoc-generation to the cruise task and the artifacts that get saved
* Added Darkfish external and fixed up the RDoc generation task to use it
* Factored out the config-file reading from #owner into a generic config reader, and then added some
methods to access config values
* Fixed the message-file sort block
* Added a DRb service daemon: Ezmlm::ListDaemon
--- a/Rakefile Fri May 09 17:51:36 2008 +0000
+++ b/Rakefile Sat May 10 01:52:42 2008 +0000
@@ -132,7 +132,7 @@
### Cruisecontrol task
desc "Cruisecontrol build"
-task :cruise => [:clean, :coverage, :package] do |task|
+task :cruise => [:clean, :coverage, :rdoc, :package] do |task|
raise "Artifacts dir not set." if ARTIFACTS_DIR.to_s.empty?
artifact_dir = ARTIFACTS_DIR.cleanpath
artifact_dir.mkpath
@@ -140,6 +140,9 @@
$stderr.puts "Copying coverage stats..."
FileUtils.cp_r( 'coverage', artifact_dir )
+ $stderr.puts "Copying documentation..."
+ FileUtils.cp_r( 'docs/api', artifact_dir + 'rdoc' )
+
$stderr.puts "Copying packages..."
FileUtils.cp_r( FileList['pkg/*'].to_a, artifact_dir )
end
--- a/lib/ezmlm.rb Fri May 09 17:51:36 2008 +0000
+++ b/lib/ezmlm.rb Sat May 10 01:52:42 2008 +0000
@@ -35,7 +35,7 @@
require 'ezmlm/list'
-
+ require 'ezmlm/listdaemon'
###############
--- a/lib/ezmlm/list.rb Fri May 09 17:51:36 2008 +0000
+++ b/lib/ezmlm/list.rb Sat May 10 01:52:42 2008 +0000
@@ -31,6 +31,9 @@
def initialize( listdir )
listdir = Pathname.new( listdir ) if !listdir.is_a?( Pathname )
@listdir = listdir
+
+ # Cached lookups
+ @config = nil
end
@@ -42,6 +45,25 @@
attr_reader :listdir
+ ### Return the configured name of the list (without the host)
+ def name
+ return self.config[ 'L' ]
+ end
+
+
+ ### Return the configured host of the list
+ def host
+ return self.config[ 'H' ]
+ end
+
+
+ ### Return the configured address of the list (in list@host form)
+ def address
+ return "%s@%s" % [ self.name, self.host ]
+ end
+ alias_method :fullname, :address
+
+
### Return the number of messages in the list archive
def message_count
numfile = self.listdir + 'num'
@@ -62,16 +84,28 @@
mail = self.last_post or return nil
return mail.from
end
+
+
+ ### Return the list config as a Hash
+ def config
+ unless @config
+ configfile = self.listdir + 'config'
+ raise "List config file %p does not exist" % [ configfile ] unless configfile.exist?
+
+ @config = configfile.read.scan( /^(\S):([^\n]*)$/m ).inject({}) do |h,pair|
+ key,val = *pair
+ h[key] = val
+ h
+ end
+ end
+
+ return @config
+ end
### Return the email address of the list's owner.
def owner
- config = self.listdir + 'config'
- if config.read =~ /^5:([^\n]+)$/m
- return $1
- else
- return nil
- end
+ self.config['5']
end
@@ -148,7 +182,7 @@
# Find the last numbered file under the last numbered directory we found
# above.
last_post_path = Pathname.glob( last_archdir + '[0-9]*' ).
- sort_by {|pn| Integer(pn.basename.to_s) }.last
+ sort_by {|pn| pn.basename.to_s }.last
raise RuntimeError, "unexpectedly empty archive directory '%s'" % [ last_archdir ] \
unless last_post_path
--- a/rake/rdoc.rb Fri May 09 17:51:36 2008 +0000
+++ b/rake/rdoc.rb Sat May 10 01:52:42 2008 +0000
@@ -3,6 +3,14 @@
# $Id$
#
+BEGIN {
+ require 'pathname'
+ basedir = Pathname.new( __FILE__ ).dirname.parent
+ docsdir = basedir + 'docs'
+
+ $LOAD_PATH << docsdir.to_s
+}
+
require 'rake/rdoctask'
### Task: rdoc
--- a/spec/ezmlm/list_spec.rb Fri May 09 17:51:36 2008 +0000
+++ b/spec/ezmlm/list_spec.rb Sat May 10 01:52:42 2008 +0000
@@ -29,25 +29,42 @@
LISTDIR = Pathname.new( 'list' )
-
TEST_SUBSCRIBERS = %w[
pete.chaffee@toadsmackers.com
dolphinzombie@alahalohamorra.com
piratebanker@yahoo.com
]
-
TEST_MODERATORS = %w[
dolphinzombie@alahalohamorra.com
]
-
+ TEST_LIST_NAME = 'waffle-lovers'
+ TEST_LIST_HOST = 'lists.syrup.info'
TEST_OWNER = 'listowner@rumpus-the-whale.info'
-
TEST_CUSTOM_MODERATORS_DIR = '/foo/bar/clowns'
-
-
-
+ TEST_CONFIG = <<-"EOF".gsub( /^\t+/, '' )
+ F:-aBCDeFGHijKlMnOpQrStUVWXYZ
+ X:
+ D:/var/qmail/alias/lists/waffle-lovers/
+ T:/var/qmail/alias/.qmail-waffle-lovers
+ L:#{TEST_LIST_NAME}
+ H:#{TEST_LIST_HOST}
+ C:
+ 0:
+ 3:
+ 4:
+ 5:#{TEST_OWNER}
+ 6:
+ 7:
+ 8:
+ 9:
+ EOF
+
it "can create a new list"
+ it "can add a new subscriber"
+ it "can remove a current subscriber"
+ it "can edit the list's text files"
+
###
### List manager functions
@@ -60,6 +77,49 @@
end
+ it "can return the configured list name" do
+ @list.stub!( :config ).and_return({ 'L' => :the_list_name })
+ @list.name.should == :the_list_name
+ end
+
+
+ it "can return the configured list host" do
+ @list.stub!( :config ).and_return({ 'H' => :the_list_host })
+ @list.host.should == :the_list_host
+ end
+
+
+ it "can return the configured list address" do
+ @list.stub!( :config ).and_return({ 'L' => TEST_LIST_NAME, 'H' => TEST_LIST_HOST })
+ @list.address.should == "%s@%s" % [ TEST_LIST_NAME, TEST_LIST_HOST ]
+ end
+
+
+ CONFIG_KEYS = %w[ F X D T L H C 0 3 4 5 6 7 8 9 ]
+
+ it "can fetch the list config as a Hash" do
+ config_path = mock( "Mock config path" )
+ @listpath.should_receive( :+ ).with( 'config' ).and_return( config_path )
+ config_path.should_receive( :exist? ).and_return( true )
+ config_path.should_receive( :read ).and_return( TEST_CONFIG )
+
+ @list.config.should be_an_instance_of( Hash )
+ @list.config.should have( CONFIG_KEYS.length ).members
+ @list.config.keys.should include( *CONFIG_KEYS )
+ end
+
+
+ it "raises an error if the list config file doesn't exist" do
+ config_path = mock( "Mock config path" )
+ @listpath.should_receive( :+ ).with( 'config' ).and_return( config_path )
+ config_path.should_receive( :exist? ).and_return( false )
+
+ lambda {
+ @list.config
+ }.should raise_error( RuntimeError, /does not exist/ )
+ end
+
+
it "can return a list of subscribers' email addresses" do
subscribers_dir = LISTDIR + 'subscribers'
@@ -313,61 +373,20 @@
### List owner
- TEST_CONFIG_WITHOUT_OWNER = <<-"EOF".gsub( /^\t+/, '' )
- F:-aBCDeFGHijKlMnOpQrStUVWXYZ
- X:
- D:/var/qmail/alias/lists/waffle-lovers/
- T:/var/qmail/alias/.qmail-waffle-lovers
- L:waffle-lovers
- H:lists.syrup.info
- C:
- 0:
- 3:
- 4:
- 5:
- 6:
- 7:
- 8:
- 9:
- EOF
-
it "returns nil when the list doesn't have an owner in its config" do
- config_path_obj = mock( "Config path object" )
- @listpath.should_receive( :+ ).with( 'config' ).and_return( config_path_obj )
- config_path_obj.should_receive( :read ).and_return( TEST_CONFIG_WITHOUT_OWNER )
-
+ @list.stub!( :config ).and_return({ '5' => nil })
@list.owner.should == nil
end
- TEST_CONFIG_WITH_OWNER = <<-"EOF".gsub( /^\t+/, '' )
- F:-aBCDeFGHijKlMnOpQrStUVWXYZ
- X:
- D:/var/qmail/alias/lists/waffle-lovers/
- T:/var/qmail/alias/.qmail-waffle-lovers
- L:waffle-lovers
- H:lists.syrup.info
- C:
- 0:
- 3:
- 4:
- 5:#{TEST_OWNER}
- 6:
- 7:
- 8:
- 9:
- EOF
-
it "can return the email address of the list owner" do
- config_path_obj = mock( "Config path object" )
- @listpath.should_receive( :+ ).with( 'config' ).and_return( config_path_obj )
- config_path_obj.should_receive( :read ).and_return( TEST_CONFIG_WITH_OWNER )
-
+ @list.stub!( :config ).and_return({ '5' => TEST_OWNER })
@list.owner.should == TEST_OWNER
end
end
+
###
### Archive functions
###
@@ -402,12 +421,13 @@
TEST_ARCHIVE_DIR = LISTDIR + 'archive'
TEST_ARCHIVE_SUBDIRS = %w[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 ]
+ TEST_POST_FILES = %w[ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 ]
before( :each ) do
@archive_dir = TEST_ARCHIVE_DIR.dup
@archive_subdirs = TEST_ARCHIVE_SUBDIRS.dup
@archive_subdir_paths = TEST_ARCHIVE_SUBDIRS.collect {|pn| TEST_ARCHIVE_DIR + pn }
- @archive_post_paths = TEST_ARCHIVE_SUBDIRS.collect {|pn|
+ @archive_post_paths = TEST_POST_FILES.collect {|pn|
TEST_ARCHIVE_DIR + TEST_ARCHIVE_SUBDIRS.last + pn
}
end