File Coverage

blib/lib/App/VOJournal.pm
Criterion Covered Total %
statement 23 89 25.8
branch 0 30 0.0
condition 0 9 0.0
subroutine 8 16 50.0
pod 1 1 100.0
total 32 145 22.0


line stmt bran cond sub pod time code
1             package App::VOJournal;
2              
3             # vim: set sw=4 ts=4 tw=76 et ai si:
4              
5 1     1   97356 use 5.006;
  1         4  
6 1     1   7 use strict;
  1         2  
  1         28  
7 1     1   6 use warnings FATAL => 'all';
  1         2  
  1         46  
8              
9 1     1   506 use App::VOJournal::VOTL;
  1         3  
  1         45  
10 1     1   13 use File::Find;
  1         3  
  1         94  
11 1     1   7 use File::Path qw(make_path);
  1         10  
  1         63  
12 1     1   995 use Getopt::Long qw(GetOptionsFromArray);
  1         13710  
  1         7  
13              
14             =head1 NAME
15              
16             App::VOJournal - call Vimoutline on a journal file.
17              
18             =head1 VERSION
19              
20             Version v0.4.6
21              
22             =cut
23              
24 1     1   228 use version; our $VERSION = qv('v0.4.6');
  1         2  
  1         9  
25              
26             =head1 SYNOPSIS
27              
28             Open a file in vimoutliner to write a journal
29              
30             use App::VOJournal;
31              
32             App::VOJournal->run;
33              
34             or, on the command line
35              
36             perl -MApp::VOJournal -e App::VOJournal->run
37              
38             =head1 SUBROUTINES/METHODS
39              
40             =head2 run
41              
42             This is the only function you need to use this Module. It parses the command
43             line and determines the date for which you want to write a journal entry.
44             Then it makes sure all necessary directories are created and starts
45             vimoutliner with the journal file for that date.
46              
47             use App::VOJournal;
48              
49             App::VOJournal->run;
50              
51             =cut
52              
53             sub run {
54 0     0 1   my $opt = _initialize(@ARGV);
55              
56 0 0         if ($opt->{version}) {
57 0           print "App::VOJournal version $VERSION\n";
58 0           return 0;
59             }
60              
61 0           my $basedir = $opt->{basedir};
62 0           my $editor = $opt->{editor};
63              
64 0           my ($day,$month,$year) = _determine_date($opt);
65              
66 0           my $dir = sprintf("%s/%4.4d/%2.2d",
67             $basedir, $year, $month);
68 0           my $path = sprintf("%s/%4.4d/%2.2d/%4.4d%2.2d%2.2d.otl",
69             $basedir, $year, $month, $year, $month, $day);
70 0           my $header = sprintf('; %4.4d-%2.2d-%2.2d',$year,$month,$day);
71              
72 0           my $last_file = _find_last_file($basedir,$path);
73              
74 0           make_path($dir);
75              
76 0 0         if ($last_file) {
77 0 0         if ($last_file cmp $path) {
78 0 0         if ($opt->{resume}) {
79 0           _use_last_file($path,$last_file,$opt,$header);
80             }
81             else {
82 0           _create_new_file($path,$opt,$header);
83             }
84             }
85             }
86             else {
87 0           _create_new_file($path,$opt,$header);
88             }
89 0 0         if ($opt->{resume}) {
90 0 0 0       if ($last_file
91             && $last_file cmp $path) {
92             }
93             }
94 0           system($editor, $path);
95 0           return $?;
96             } # run()
97              
98             # _create_new_file($path,$opt,$header)
99             #
100             # Creates a new vimoutliner file at $path optionally containing a header
101             # line.
102             sub _create_new_file {
103 0     0     my ($path,$opt,$header) = @_;
104 0           my $votl = App::VOJournal::VOTL->new();
105 0 0         if ($opt->{header}) {
106 0           $votl->insert_line(0,$header);
107             }
108 0           $votl->write_file($path);
109             } # _create_new_file()
110              
111             # _determine_date($opt)
112             #
113             # Determines the date respecting the given options.
114             #
115             sub _determine_date {
116 0     0     my ($opt) = @_;
117 0           my ($day,$month,$year) = (localtime)[3,4,5];
118 0           $year += 1900;
119 0           $month += 1;
120              
121 0 0         if (my $od = $opt->{date}) {
122 0 0         if ($od =~ /^\d{1,2}$/) {
    0          
    0          
123 0           $day = $od;
124             }
125             elsif ($od =~ /^(\d{1,2})(\d{2})$/) {
126 0           $month = $1;
127 0           $day = $2;
128             }
129             elsif ($od =~ /^(\d{4})(\d{2})(\d{2})$/) {
130 0           $year = $1;
131 0           $month = $2;
132 0           $day = $3;
133             }
134             }
135              
136 0           return ($day,$month,$year);
137             } # _determine_date()
138              
139             sub _find_files_with_pattern {
140 0     0     my ($dirname,$pattern) = @_;
141 0           my @files = ();
142              
143 0 0         if (opendir(my $DIR,$dirname)) {
144 0           while (defined(my $file = readdir($DIR))) {
145 0 0         push(@files,$file) if ($file =~ /$pattern/);
146             }
147 0           closedir($DIR);
148             }
149 0           return @files;
150             } # _find_files_with_pattern
151              
152             sub _find_last_file {
153 0     0     my ($basedir,$next_file) = @_;
154 0           my $last_file = '';
155             my $wanted = sub {
156 0     0     my $this_file = $File::Find::name;
157 0 0 0       if ($this_file =~ qr|^$basedir/\d{4}/\d{2}/\d{8}[.]otl$|
      0        
158             && 0 < ($this_file cmp $last_file)
159             && 0 >= ($this_file cmp $next_file)) {
160 0           $last_file = $this_file;
161             }
162 0           };
163 0           find($wanted,$basedir);
164 0           return $last_file;
165             } # _find_last_file()
166              
167             sub _use_last_file {
168 0     0     my ($path,$last_file,$opt,$header) = @_;
169 0           my $votl = App::VOJournal::VOTL->new();
170 0           $votl->read_file_unchecked_boxes($last_file);
171 0 0         if ($opt->{header}) {
172 0           $votl->insert_line(0,$header);
173             }
174 0           $votl->write_file($path);
175             } # _use_old_file
176              
177             =head1 COMMANDLINE OPTIONS
178              
179             =head2 --basedir $dir
180              
181             Use C<< $dir >> instead of C<< $ENV{HOME}/journal >> as base directory for
182             the journal files.
183              
184             =head2 --date [YYYY[MM]]DD
185              
186             Use a different date than today.
187              
188             One or two digits change the day in the current month.
189              
190             Three or four digits change the day and month in the current year.
191              
192             Eight digits change day, month and year.
193              
194             The program will not test for a valid date. That means, if you specify
195             '--date 0230' on the command line, the file for February 30th this year
196             would be opened.
197              
198             =head2 --editor $path_to_editor
199              
200             Use this option to specify an editor other than C to edit
201             the journal file.
202              
203             =head2 --[no]header
204              
205             Normally every journal file starts with some header lines, indicating the
206             day the journal is written.
207              
208             If the option C<--noheader> is given on the command line, this header lines
209             will be omitted.
210              
211             =head2 --[no]resume
212              
213             Look for open checkboxes in the last journal file and carry them forward
214             to this days journal file before opening it.
215              
216             This only works if there is no journal file for this day.
217              
218             The default is C<< --resume >>
219              
220             =head2 --version
221              
222             Print the version number and exit.
223              
224             =cut
225              
226             # _initialize(@ARGV)
227             #
228             # Parse the command line and initialize the program
229             #
230             sub _initialize {
231 0     0     my @argv = @_;
232 0           my $opt = {
233             'basedir' => qq($ENV{HOME}/journal),
234             'editor' => 'vim',
235             'header' => 1,
236             'resume' => 1,
237             };
238 0           my @optdesc = (
239             'basedir=s',
240             'date=i',
241             'editor=s',
242             'header!',
243             'resume!',
244             'version',
245             );
246 0           GetOptionsFromArray(\@argv,$opt,@optdesc);
247 0           return $opt;
248             } # _initialize()
249              
250             =head1 AUTHOR
251              
252             Mathias Weidner, C<< >>
253              
254             =head1 BUGS
255              
256             Please report any bugs or feature requests to C, or through
257             the web interface at L. I will be notified, and then you'll
258             automatically be notified of progress on your bug as I make changes.
259              
260             =head1 SUPPORT
261              
262             You can find documentation for this module with the perldoc command.
263              
264             perldoc App::VOJournal
265              
266              
267             You can also look for information at:
268              
269             =over 4
270              
271             =item * RT: CPAN's request tracker (report bugs here)
272              
273             L
274              
275             =item * AnnoCPAN: Annotated CPAN documentation
276              
277             L
278              
279             =item * CPAN Ratings
280              
281             L
282              
283             =item * Search CPAN
284              
285             L
286              
287             =back
288              
289              
290             =head1 ACKNOWLEDGEMENTS
291              
292              
293             =head1 LICENSE AND COPYRIGHT
294              
295             Copyright 2015 Mathias Weidner.
296              
297             This program is free software; you can redistribute it and/or modify it
298             under the terms of the the Artistic License (2.0). You may obtain a
299             copy of the full license at:
300              
301             L
302              
303             Any use, modification, and distribution of the Standard or Modified
304             Versions is governed by this Artistic License. By using, modifying or
305             distributing the Package, you accept this license. Do not use, modify,
306             or distribute the Package, if you do not accept this license.
307              
308             If your Modified Version has been derived from a Modified Version made
309             by someone other than you, you are nevertheless required to ensure that
310             your Modified Version complies with the requirements of this license.
311              
312             This license does not grant you the right to use any trademark, service
313             mark, tradename, or logo of the Copyright Holder.
314              
315             This license includes the non-exclusive, worldwide, free-of-charge
316             patent license to make, have made, use, offer to sell, sell, import and
317             otherwise transfer the Package with respect to any patent claims
318             licensable by the Copyright Holder that are necessarily infringed by the
319             Package. If you institute patent litigation (including a cross-claim or
320             counterclaim) against any party alleging that the Package constitutes
321             direct or contributory patent infringement, then this Artistic License
322             to you shall terminate on the date that such litigation is filed.
323              
324             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
325             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
326             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
327             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
328             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
329             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
330             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
331             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
332              
333              
334             =cut
335              
336             1; # End of App::VOJournal