File Coverage

blib/lib/Data/Edit.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package Data::Edit;
2              
3 1     1   29245 use 5.010001;
  1         3  
  1         42  
4 1     1   6 use strict;
  1         2  
  1         35  
5 1     1   5 use warnings;
  1         6  
  1         53  
6              
7             require Exporter;
8 1     1   5 use File::Spec;
  1         1  
  1         28  
9 1     1   1133 use YAML::Any;
  1         1275  
  1         6  
10 1     1   21823 use File::Temp qw/ tempfile /;
  1         76074  
  1         2009  
11 1     1   4479 use Data::Edit::vimdiff;
  0            
  0            
12             use Data::Edit::editor;
13             use Cwd;
14             use Try::Tiny;
15              
16             our @ISA = qw(Exporter);
17              
18             # Items to export into callers namespace by default. Note: do not export
19             # names by default without a very good reason. Use EXPORT_OK instead.
20             # Do not simply export all your public functions/methods/constants.
21              
22             # This allows declaration use Data::Edit ':all';
23             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
24             # will save memory.
25             our %EXPORT_TAGS = ( 'all' => [ qw(
26             edit_structure
27             ) ] );
28              
29             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
30              
31             our @EXPORT = qw();
32              
33             our $VERSION = '0.01';
34              
35             sub edit_structure {
36             my ($structure, $name) = @_;
37              
38             my $last_error;
39             my $out;
40              
41             my $header_lines=5;
42              
43             my @offer_to_edit = map { "$_\n" } split(/\n/, Dump($structure));
44              
45             do {
46             my @header_block = map { "## $_\n" } split(/\n/, $name || "");
47             if ($last_error) {
48             push @header_block, "## The previous error was:\n";
49             push @header_block, map { "## $_\n" } split(/\n/, $last_error);
50             }
51              
52             push @header_block, "##\n" while scalar(@header_block)<$header_lines;
53              
54             if (scalar(@header_block)>$header_lines) {
55             # Which cunningly extends the next header block by one line.
56             push @header_block, "## Error too long, line numbers will be wrong.\n";
57             }
58              
59             my ($orig_fh, $orig_fn) = tempfile( SUFFIX => ".yml" );
60             print $orig_fh map { "##\n" } @header_block;
61             print $orig_fh Dump($structure);
62             close $orig_fh;
63              
64             chmod 0400, $orig_fn;
65              
66             my ($edit_fh, $edit_fn) = tempfile( SUFFIX => ".yml" );
67             print $edit_fh @header_block;
68              
69             # XXX assumes only header lines at start
70             print $edit_fh grep { $_!~ /^##/ } @offer_to_edit;
71             close $edit_fh;
72              
73             my $ed = find_editor();
74             $ed->edit($edit_fn, $orig_fn);
75              
76             open(my $fh, "<", $edit_fn) or die $!;
77             @offer_to_edit = <$fh>;
78              
79             # XXX assumes only header lines at start
80             $header_lines = scalar(grep { /^##/ } @offer_to_edit);
81              
82             $last_error = undef;
83             try {
84             $out = Load(join("", @offer_to_edit));
85             }
86             catch {
87             $last_error = $_;
88             };
89              
90             close $fh;
91             unlink($orig_fn) or warn "Could not delete '$orig_fn': $!";
92             unlink($edit_fn) or warn "Could not delete '$edit_fn': $!";
93              
94              
95             } while ($last_error);
96              
97             return $out;
98             }
99              
100             sub find_editor {
101             my $ed = $ENV{VISUAL} || $ENV{EDITOR};
102              
103             # Debian / Ubuntu magic
104             unless ($ed) {
105             $ed = "/usr/bin/editor";
106             if (-l $ed) {
107             $ed = Cwd::realpath($ed);
108             }
109             }
110              
111             my ($vol, $dir, $file) = File::Spec->splitpath($ed);
112              
113             if ($file eq 'vim') {
114             if (-x (my $vimdiff = File::Spec->catpath($vol, $dir, 'vimdiff'))) {
115             return Data::Edit::vimdiff->new( path => $vimdiff );
116             }
117             }
118             return Data::Edit::editor->new( path => $ed );
119             }
120              
121             # Preloaded methods go here.
122              
123             # Autoload methods go after =cut, and are processed by the autosplit program.
124              
125             1;
126             __END__
127             # Below is stub documentation for your module. You'd better edit it!
128              
129             =head1 NAME
130              
131             Data::Edit - Perl wrapper around your text editor
132              
133             =head1 SYNOPSIS
134              
135             use Data::Edit;
136             my $structure = { ... };
137             Data::Edit::edit_structure($structure, "my structure");
138              
139             =head1 DESCRIPTION
140              
141             The module is a wrapper around a YAML parser and your text editor, for the
142             purpose of editing a data structure in memory. Special magic is added for vim
143             users to allow them to see the changes they are making in C<vimdiff>.
144              
145             =head2 EXPORT
146              
147             =over
148              
149             =item edit_structure
150              
151             May be exported
152              
153             =back
154              
155             =head1 ENVIRONMENT
156              
157             C<VISUAL> and C<EDITOR> are looked at to determine the text editor to use. If
158             these aren't defined, it checks for a symlink at /usr/bin/editor.
159              
160             =head1 SEE ALSO
161              
162             =over
163              
164             =item *
165              
166             L<YAML>
167              
168             =item *
169              
170             L<vimdiff>
171              
172             =back
173              
174             =head1 AUTHOR
175              
176             Dave Lambley, E<lt>davel@state51.co.ukE<gt>
177              
178             =head1 COPYRIGHT AND LICENSE
179              
180             Copyright (C) 2011 by Dave Lambley
181              
182             This library is free software; you can redistribute it and/or modify
183             it under the same terms as Perl itself, either Perl version 5.10.1 or,
184             at your option, any later version of Perl 5 you may have available.
185              
186              
187             =cut