Added more archive-related functions:
authorMichael Granger <mgranger@laika.com>
Fri, 09 May 2008 17:51:36 +0000
changeset 4 8c4ae0797d5f
parent 3 9b9e85ccf4f9
child 5 804e1c2b9a40
Added more archive-related functions: - Fetch the last post to the list - Fetch date/author/subject of the last post to the list - Fetch message count
lib/ezmlm/list.rb
spec/ezmlm/list_spec.rb
--- a/lib/ezmlm/list.rb	Thu May 08 21:32:18 2008 +0000
+++ b/lib/ezmlm/list.rb	Fri May 09 17:51:36 2008 +0000
@@ -20,6 +20,7 @@
 
 require 'pathname'
 require 'ezmlm'
+require 'tmail'
 
 
 ### A Ruby interface to an ezmlm-idx mailing list directory
@@ -41,6 +42,28 @@
 	attr_reader :listdir
 
 
+	### Return the number of messages in the list archive
+	def message_count
+		numfile = self.listdir + 'num'
+		return 0 unless numfile.exist?
+		return Integer( numfile.read[/^(\d+):/, 1] )
+	end
+
+
+	### Return the Date parsed from the last post to the list.
+	def last_message_date
+		mail = self.last_post or return nil
+		return mail.date
+	end
+
+
+	### Return the author of the last post to the list.
+	def last_message_author
+		mail = self.last_post or return nil
+		return mail.from
+	end
+	
+
 	### Return the email address of the list's owner.
 	def owner
 		config = self.listdir + 'config'
@@ -110,6 +133,30 @@
 	end
 	
 	
+	### Return a TMail::Mail object loaded from the last post to the list. Returns
+	### +nil+ if there are no archived posts.
+	def last_post
+		archivedir = self.listdir + 'archive'
+		return nil unless archivedir.exist?
+
+		# Find the last numbered directory under the archive dir
+		last_archdir = Pathname.glob( archivedir + '[0-9]*' ).
+			sort_by {|pn| Integer(pn.basename.to_s) }.last
+
+		return nil unless last_archdir
+
+		# 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
+
+		raise RuntimeError, "unexpectedly empty archive directory '%s'" % [ last_archdir ] \
+			unless last_post_path
+
+		last_post = TMail::Mail.load( last_post_path.to_s )
+	end
+	
+	
 
 	#########
 	protected
--- a/spec/ezmlm/list_spec.rb	Thu May 08 21:32:18 2008 +0000
+++ b/spec/ezmlm/list_spec.rb	Fri May 09 17:51:36 2008 +0000
@@ -9,7 +9,9 @@
 	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
 }
 
+
 begin
+	require 'tmail'
 	require 'spec/runner'
 	require 'spec/lib/helpers'
 	require 'ezmlm/list'
@@ -369,9 +371,170 @@
 	### 
 	### Archive functions
 	### 
-	it "can return the count of archived posts"
+	describe "archive functions" do
+	
+		before( :each ) do
+			@listpath = LISTDIR.dup
+			@list = Ezmlm::List.new( @listpath )
+		end
+		
+		
+		it "can return the count of archived posts" do
+			numpath_obj = mock( "num file path object" )
+			@listpath.should_receive( :+ ).with( 'num' ).and_return( numpath_obj )
+			
+			numpath_obj.should_receive( :exist? ).and_return( true )
+			numpath_obj.should_receive( :read ).and_return( "1723:123123123" )
+			
+			@list.message_count.should == 1723
+		end
+	
+		it "can return the count of archived posts to a list that hasn't been posted to" do
+			numpath_obj = mock( "num file path object" )
+			@listpath.should_receive( :+ ).with( 'num' ).and_return( numpath_obj )
+			
+			numpath_obj.should_receive( :exist? ).and_return( false )
+			
+			@list.message_count.should == 0
+		end
+		
+
+		
+		TEST_ARCHIVE_DIR = LISTDIR + 'archive'
+		TEST_ARCHIVE_SUBDIRS = %w[ 0 1 2 3 4 5 6 7 8 9 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|
+				TEST_ARCHIVE_DIR + TEST_ARCHIVE_SUBDIRS.last + pn
+			  }
+		end
+		
+
+		it "can return a TMail::Mail object parsed from the last archived post" do
+			# need to find the last message
+			archive_path_obj = mock( "archive path" )
+
+			@listpath.should_receive( :+ ).with( 'archive' ).and_return( archive_path_obj )
+			archive_path_obj.should_receive( :exist? ).and_return( true )
+
+			# Find the last numbered directory under the archive dir
+			archive_path_obj.should_receive( :+ ).with( '[0-9]*' ).
+				and_return( :archive_dir_globpath )
+			Pathname.should_receive( :glob ).with( :archive_dir_globpath ).
+				and_return( @archive_subdir_paths )
+
+			# Find the last numbered file under the last numbered directory we found
+			# above.
+			@archive_subdir_paths.last.should_receive( :+ ).with( '[0-9]*' ).
+				and_return( :archive_post_pathglob )
+			Pathname.should_receive( :glob ).with( :archive_post_pathglob ).
+				and_return( @archive_post_paths )
+
+			TMail::Mail.should_receive( :load ).with( @archive_post_paths.last.to_s ).
+				and_return( :mail_object )
+
+			@list.last_post.should == :mail_object
+		end
+		
+		
+		it "returns nil for the last post if there is no archive directory for the list" do
+			archive_path_obj = mock( "archive path" )
+
+			@listpath.should_receive( :+ ).with( 'archive' ).and_return( archive_path_obj )
+			archive_path_obj.should_receive( :exist? ).and_return( false )
+			@list.last_post.should == nil
+		end
+		
+		
+		it "returns nil for the last post if there haven't been any posts to the list" do
+			archive_path_obj = mock( "archive path" )
+			mail_object = mock( "Mock TMail object" )
 
-	it "can return a hash of the subjects of all archived posts to message ids"
+			@listpath.should_receive( :+ ).with( 'archive' ).and_return( archive_path_obj )
+			archive_path_obj.should_receive( :exist? ).and_return( true )
+
+			# Find the last numbered directory under the archive dir
+			archive_path_obj.should_receive( :+ ).with( '[0-9]*' ).
+				and_return( :archive_dir_globpath )
+			Pathname.should_receive( :glob ).with( :archive_dir_globpath ).and_return( [] )
+
+			@list.last_post.should == nil
+		end
+		
+		
+		it "raises a RuntimeError if the last archive directory doesn't have any messages in it" do
+			archive_path_obj = mock( "archive path" )
+			mail_object = mock( "Mock TMail object" )
+
+			@listpath.should_receive( :+ ).with( 'archive' ).and_return( archive_path_obj )
+			archive_path_obj.should_receive( :exist? ).and_return( true )
+
+			# Find the last numbered directory under the archive dir
+			archive_path_obj.should_receive( :+ ).with( '[0-9]*' ).
+				and_return( :archive_dir_globpath )
+			Pathname.should_receive( :glob ).with( :archive_dir_globpath ).
+				and_return( @archive_subdir_paths )
+
+			@archive_subdir_paths.last.should_receive( :+ ).with( '[0-9]*' ).
+				and_return( :archive_post_pathglob )
+			Pathname.should_receive( :glob ).with( :archive_post_pathglob ).
+				and_return( [] )
+
+			lambda {
+				@list.last_post
+			}.should raise_error( RuntimeError, /unexpectedly empty/i )
+		end
+		
+		
+		it "can fetch the date of the last archived post" do
+			mail_object = mock( "Mock TMail object" )
+
+			@list.should_receive( :last_post ).and_return( mail_object )
+			mail_object.should_receive( :date ).and_return( :the_message_date )
+
+			@list.last_message_date.should == :the_message_date
+		end
+
+		
+		it "can fetch the date of the last archived post" do
+			mail_object = mock( "Mock TMail object" )
+
+			@list.should_receive( :last_post ).and_return( mail_object )
+			mail_object.should_receive( :date ).and_return( :the_message_date )
+
+			@list.last_message_date.should == :the_message_date
+		end
+
+		
+		it "can fetch the author of the last archived post" do
+			mail_object = mock( "Mock TMail object" )
+
+			@list.should_receive( :last_post ).and_return( mail_object )
+			mail_object.should_receive( :from ).and_return( :the_message_author )
+
+			@list.last_message_author.should == :the_message_author
+		end
+
+		
+		it "can fetch the subject of the last archived post" do
+			mail_object = mock( "Mock TMail object" )
+
+			@list.should_receive( :last_post ).and_return( mail_object )
+			mail_object.should_receive( :from ).and_return( :the_message_author )
+
+			@list.last_message_author.should == :the_message_author
+		end
+
+	end
+
+
+	it "can fetch the body of an archived post by message id"
+	it "can fetch the header of an archived post by message id"
+	
+	it "can return a hash of the subjects of all archived posts to message ids" 
 	it "can return an Array of the subjects of all archived posts"
 
 	it "can return a hash of the threads of all archived posts to message ids"
@@ -380,14 +543,6 @@
 	it "can return a hash of the authors of all archived posts to message ids"
 	it "can return an Array of the authors of all archived posts"
 
-
-	it "can fetch the body of an archived post by message id"
-	it "can fetch the header of an archived post by message id"
-
-	it "can fetch the date of the last archived post"
-	it "can fetch the author of the last archived post"
-	it "can fetch the subject of the last archived post"
-
 end