File Coverage

blib/lib/News/Active.pm
Criterion Covered Total %
statement 15 96 15.6
branch 0 56 0.0
condition 0 21 0.0
subroutine 5 20 25.0
pod 15 15 100.0
total 35 208 16.8


line stmt bran cond sub pod time code
1             $VERSION = "0.13";
2             package News::Active;
3             our $VERSION = "0.13";
4              
5             # -*- Perl -*- Tue May 25 14:35:18 CDT 2004
6             ###############################################################################
7             # Written by Tim Skirvin . Copyright 2003-2004,
8             # Tim Skirvin. Redistribution terms are below.
9             ###############################################################################
10              
11             =head1 NAME
12              
13             News::Active - keep track of news active file information
14              
15             =head1 SYNOPSIS
16              
17             use News::Active;
18             my $active = News::Active->new( '/home/tskirvin/kiboze/active' );
19             $active->subscribe("humanities.philosophy.objectivism");
20             $active->add_article("humanities.philosophy.objectivism");
21             $active->write;
22              
23             See below for more information.
24              
25             =head1 DESCRIPTION
26              
27             News::Active is used to keep track of active newsgroup information in an
28             external file. It contains many C objects, one for
29             each newsgroup we are subscribed to. It should be a fairly simple module
30             to use and understand, as it is only a subsection of C.
31              
32             =head1 USAGE
33              
34             =head2 Variables
35              
36             =over 4
37              
38             =item $News::Active::DEBUG - default value for C in new objects.
39              
40             =item $News::Active::READONLY - default value for C in new objects.
41              
42             =back
43              
44             =cut
45              
46             ###############################################################################
47             ### main() ####################################################################
48             ###############################################################################
49              
50 1     1   5 use strict;
  1         2  
  1         33  
51 1     1   5 use warnings;
  1         3  
  1         28  
52 1     1   566 use News::Active::Entry;
  1         2  
  1         23  
53 1     1   5 use Net::NNTP::Functions;
  1         3  
  1         70  
54 1     1   5 use vars qw( $DEBUG $READONLY );
  1         2  
  1         1265  
55              
56             $DEBUG = 0;
57             $READONLY = 0;
58              
59             =head2 Basic Functions
60              
61             The following functions give us access to the object class
62              
63             =over 4
64              
65             =item new ( FILE [, HASH] )
66              
67             Creates and returns a new News::Active object. C is the filename
68             (later accessed with C) that we will load old information from
69             and save to when we close the object. It will be created if it doesn't
70             already exist, and read (with C) from if it does.
71              
72             If C is offered, its possible values:
73              
74             debug Print debugging information when using this
75             object. Defaults to $DEBUG.
76             readonly Don't write anything back out with this object
77             when we're done with it. Defaults to $READONLY.
78              
79             Returns undef on failure, or the object on success.
80              
81             =cut
82              
83             sub new {
84 0     0 1   my ($proto, $file, %hash) = @_;
85 0 0         return undef unless $file;
86 0   0       my $class = ref($proto) || $proto;
87 0   0       my $self = {
      0        
88             Groups => { },
89             FileName => $file,
90             Debug => $hash{'debug'} || $DEBUG || 0,
91             ReadOnly => $hash{'readonly'} || $READONLY || 0,
92             Changed => 0,
93             };
94 0           bless $self, $class;
95 0           $self->read($file);
96 0           $self;
97             }
98              
99             =item groups ()
100              
101             Returns a hash reference containing all subscribed newsgroups; the keys
102             are the group names, and the values are B objects.
103              
104             =item filename ()
105              
106             Returns the filename used for loading and saving our News::Active
107             information.
108              
109             =item debug ()
110              
111             Returns true if we want to print debugging information, false otherwise.
112              
113             =item readonly ()
114              
115             Returns true if we shouldn't write out the information later, false
116             otherwise.
117              
118             =cut
119              
120 0 0   0 1   sub groups { shift->{Groups} || {} }
121 0 0   0 1   sub filename { shift->{FileName} || undef }
122 0 0   0 1   sub debug { shift->{Debug} || 0 }
123 0 0   0 1   sub readonly { shift->{ReadOnly} || 0 }
124              
125             =item entry ( GROUP )
126              
127             Returns the News::Active::Entry object for C, or undef if none exists.
128              
129             =cut
130              
131             sub entry {
132 0     0 1   my ($self, $group) = @_;
133 0 0         $self->groups->{$group} || undef
134             }
135              
136             =item entries ( PATTERN )
137              
138             Returns an array of News::Active::Entry objects whose newsgroup names
139             match the given pattern C (using C.
140              
141             =cut
142              
143             sub entries {
144 0     0 1   my ($self, $pattern) = @_;
145 0           my @return;
146 0           foreach (sort keys %{$self->groups}) {
  0            
147 0 0 0       next unless wildmat($pattern || "*", $_);
148 0           push @return, $self->entry($_);
149             }
150 0           @return;
151             }
152              
153             =back
154              
155             =head2 Newsgroup Functions
156              
157             The following functions implement the functions that we actually want to
158             use this module for, ie adding groups and articles to the active file.
159              
160             =over 4
161              
162             =item subscribe ( GROUP )
163              
164             Adds a News::Active::Entry entry for the given C, thus adding it to
165             our subscription list. Returns 1 on success, undef otherwise.
166              
167             =cut
168              
169             sub subscribe {
170 0     0 1   my ($self, $group) = @_;
171 0 0         return undef unless $group;
172 0 0         return 1 if $self->subscribed($group);
173 0 0         print "Subscribing to $group\n" if $self->debug;
174 0           $self->{Changed}++;
175 0           $self->groups->{$group} = new News::Active::Entry($group);
176             # warn "G2: $group ", $self->groups->{$group}, "\n";
177             # foreach (keys %{$self->groups}) { warn "G3: $_\n"; }
178 0           1;
179             }
180              
181             =item unsubscribe ( GROUP )
182              
183             Unsubscribe from C by making sure there is no News::Active::Entry
184             entry for that groupname. Returns 1 on success or if we were already
185             unsubscribed, undef otherwise.
186              
187             =cut
188              
189             sub unsubscribe {
190 0     0 1   my ($self, $group) = @_;
191 0 0         return undef unless $group;
192 0 0         return 1 unless $self->groups->{$group};
193 0 0         print "Unsubscribing from $group\n" if $self->debug;
194 0           delete $self->groups->{$group};
195 0           $self->{Changed}++;
196 0           1;
197             }
198              
199             =item subscribed ( GROUP )
200              
201             Returns 1 if we are subscribed to C, 0 otherwise.
202              
203             =cut
204              
205             sub subscribed {
206 0     0 1   my ($self, $group) = @_;
207 0 0         return 0 unless $group;
208 0 0         $self->groups->{$group} ? 1 : 0;
209             }
210              
211             =item add_article ( GROUP [, ARGS] )
212              
213             Invokes C on the entry for C.
214              
215             =cut
216              
217             sub add_article {
218 0     0 1   my ($self, $group, @args) = @_;
219 0   0       my $entry = $self->entry($group) || return undef;
220 0           $self->{Changed}++;
221 0           $entry->add_article(@args);
222             }
223              
224             =back
225              
226             =head2 Input/Output Functions
227              
228             The following functions are used for reading, displaying, and saving
229             information from News::Active and News::Active::Entry.
230              
231             =over 4
232              
233             =item read ( [FILE] )
234              
235             Reads News::Active::Entry information from C (or the value of
236             C), populating the News::Active object. This file contains lines
237             that each contain the output from a single C
238             call. Returns 1 on success, undef otherwise.
239              
240             =cut
241              
242             sub read {
243 0     0 1   my ($self, $file) = @_;
244 0   0       $file ||= $self->filename;
245 0 0         return undef unless $file;
246 0           $$self{Groups} = {};
247 0 0         print "Reading from $file\n" if $self->debug;
248 0 0 0       open(FILE, $file) or (warn "Couldn't read from $file: $!\n" && return undef);
249 0           foreach () {
250 0           chomp;
251 0 0         my $entry = new News::Active::Entry($_) or next;
252 0           $self->groups->{$entry->name} = $entry;
253             }
254 0           close FILE;
255 0           $self->{Changed}++;
256 0           1;
257             }
258              
259             =item printable ()
260              
261             Returns an array (or arrayref, depending on invocation) containing the
262             value of C on each entry within the
263             News::Active object. These are then suitable for printing.
264              
265             =cut
266              
267             sub printable {
268 0     0 1   my ($self) = @_;
269 0           my @return;
270 0           foreach (sort keys %{$self->groups}) {
  0            
271 0           push @return, $self->entry($_)->print;
272             }
273 0 0         wantarray ? @return : join("\n", @return);
274             }
275              
276             =item output ()
277              
278             Returns an array (or arrayref, depending on invocation) containing the
279             value of C on each entry within the
280             News::Active object. These are then suitable for saving to a database and
281             later reloading.
282              
283             =cut
284              
285             sub output {
286 0     0 1   my ($self) = @_;
287 0           my @return;
288 0           foreach (sort keys %{$self->groups}) {
  0            
289 0           push @return, $self->entry($_)->output;
290             }
291 0 0         wantarray ? @return : join("\n", @return);
292             }
293              
294             =item write ( [FILE] )
295              
296             Using the information from output(), writes out to C (or the value
297             of C). Returns 1 on success, undef otherwise. If the readonly
298             flag is set, we don't actually write anything back out.
299              
300             Note that this function is called when the object is destroyed as well.
301              
302             =cut
303              
304             sub write {
305 0     0 1   my ($self, $file) = @_;
306 0 0         if ( !$self->{Changed} ) {
307 0 0         warn "Nothing changed, not writing\n" if $self->debug;
308 0           return 1;
309             }
310 0 0         if ( $self->readonly ) {
311 0 0         warn "Not writing output, readonly!\n" if $self->debug;
312 0           return 1;
313             }
314 0   0       $file ||= $self->filename;
315 0 0         return undef unless $file;
316 0 0         print "Writing to $file\n" if $self->debug;
317 0 0 0       open(FILE, ">$file")
318             or (warn "Couldn't write to $file: $!\n" && return undef);
319 0           print FILE join("\n", $self->output);
320 0           close FILE;
321 0           $self->{Changed} = 0;
322 0           1;
323             }
324              
325             =back
326              
327             =cut
328              
329             ###############################################################################
330             ### Internal Functions ########################################################
331             ###############################################################################
332              
333             ### DESTROY
334             # Item destructor. Make sure the file is written back out.
335             # sub DESTROY { shift->write }
336              
337             1;
338              
339             =head1 NOTES
340              
341             This and C are fairly similar, but are meant to take care of
342             different types of information. The News::Active file is meant to be
343             modified regularly, every time a new article is added; in INN terms this
344             is the equivalent of the active file. The information in News::GroupInfo
345             is meant to only be modified occasionally, when something major changes;
346             in INN terms this is the equivalent of the newsgroups and active.times
347             files.
348              
349             =head1 TODO
350              
351             File locking would be nice.
352              
353             =head1 REQUIREMENTS
354              
355             C
356              
357             =head1 SEE ALSO
358              
359             B, B
360              
361             =head1 AUTHOR
362              
363             Tim Skirvin
364              
365             =head1 HOMEPAGE
366              
367             B
368              
369             =head1 LICENSE
370              
371             This code may be redistributed under the same terms as Perl itself.
372              
373             =head1 COPYRIGHT
374              
375             Copyright 2003-2004, Tim Skirvin.
376              
377             =cut
378              
379             ###############################################################################
380             ### Version History ###########################################################
381             ###############################################################################
382             # v0.10 Wed Apr 28 10:12:40 CDT 2004
383             ### First documented version; it's been working since last year, though.
384             # v0.11 Wed Apr 28 11:06:26 CDT 2004
385             ### Added the matching stuff from Net::NNTP::Functions.
386             # v0.12 Tue May 25 11:21:03 CDT 2004
387             ### Added read-only stuff.
388             # v0.13 Tue May 25 14:34:25 CDT 2004
389             ### Doesn't automatically write on close anymore.