# HG changeset patch # User Michael Granger # Date 1210355496 0 # Node ID 8c4ae0797d5fe5a29b92be65452adf76db95a306 # Parent 9b9e85ccf4f979744971e23441441f4746b9b043 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 diff -r 9b9e85ccf4f9 -r 8c4ae0797d5f lib/ezmlm/list.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 diff -r 9b9e85ccf4f9 -r 8c4ae0797d5f spec/ezmlm/list_spec.rb --- 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