Permalink
Browse files

Test builder_xml_output.t now uses IO::Scalar (in t/lib) so passes on…

… 5.6
  • Loading branch information...
1 parent 79d8500 commit 03589fe982632ea40e97412e4d2a08506a61b109 @draegtun committed Jan 13, 2009
Showing with 3,433 additions and 7 deletions.
  1. +5 −0 Changes
  2. +8 −0 MANIFEST
  3. +1 −0 MANIFEST.SKIP
  4. +15 −2 MANIFEST.bak
  5. +2 −2 META.yml
  6. +2 −2 lib/Builder.pm
  7. +10 −1 t/builder_xml_output.t
  8. +196 −0 t/lib/IO/AtomicFile.pm
  9. +282 −0 t/lib/IO/InnerFile.pm
  10. +184 −0 t/lib/IO/Lines.pm
  11. +778 −0 t/lib/IO/Scalar.pm
  12. +791 −0 t/lib/IO/ScalarArray.pm
  13. +446 −0 t/lib/IO/Stringy.pm
  14. +222 −0 t/lib/IO/Wrap.pm
  15. +491 −0 t/lib/IO/WrapTie.pm
View
@@ -1,5 +1,10 @@
Revision history for Builder
+0.03 Tues January 13, 2009
+ * Test builder_xml_output.t now uses IO::Scalar (in t/lib) so passes on 5.6.*
+ - IO::Stringy 2.110 used in t/lib
+
+
0.02 Thurs January 1, 2009
* Updated test suite & docs. Minor additions/fixes for new tests to work!
- CDATA now fixed
View
@@ -15,6 +15,14 @@ t/builder_xml_cdata.t
t/builder_xml_namespace.t
t/builder_xml_output.t
t/builder_xml_pretty.t
+t/lib/IO/AtomicFile.pm
+t/lib/IO/InnerFile.pm
+t/lib/IO/Lines.pm
+t/lib/IO/Scalar.pm
+t/lib/IO/ScalarArray.pm
+t/lib/IO/Stringy.pm
+t/lib/IO/Wrap.pm
+t/lib/IO/WrapTie.pm
t/pod-coverage.t
t/pod.t
TODO
View
@@ -9,3 +9,4 @@
\.old$
^MANIFEST\.SKIP$
CVS
+.DS_Store
View
@@ -4,15 +4,28 @@ lib/Builder.pm
lib/Builder/Utils.pm
lib/Builder/XML.pm
lib/Builder/XML/Utils.pm
+Makefile.PL
MANIFEST
+META.yml
README
+t/.DS_Store
t/00-load.t
t/boilerplate.t
t/builder_xml_basic.t
t/builder_xml_cdata.t
t/builder_xml_namespace.t
+t/builder_xml_output.t
+t/builder_xml_pretty.t
+t/lib/.DS_Store
+t/lib/IO/.DS_Store
+t/lib/IO/AtomicFile.pm
+t/lib/IO/InnerFile.pm
+t/lib/IO/Lines.pm
+t/lib/IO/Scalar.pm
+t/lib/IO/ScalarArray.pm
+t/lib/IO/Stringy.pm
+t/lib/IO/Wrap.pm
+t/lib/IO/WrapTie.pm
t/pod-coverage.t
t/pod.t
TODO
-Makefile.PL
-META.yml
View
@@ -1,6 +1,6 @@
---
name: Builder
-version: 0.02
+version: 0.03
author:
- 'Barry Walsh <draegtun@cpan.org>'
abstract: 'Build XML, HTML, CSS and other outputs in blocks'
@@ -13,7 +13,7 @@ build_requires:
provides:
Builder:
file: lib/Builder.pm
- version: 0.02
+ version: 0.03
Builder::Utils:
file: lib/Builder/Utils.pm
version: 0.02
View
@@ -2,7 +2,7 @@ package Builder;
use strict;
use warnings;
use Carp;
-our $VERSION = '0.02';
+our $VERSION = '0.03';
sub new {
@@ -77,7 +77,7 @@ Builder - Build XML, HTML, CSS and other outputs in blocks
=head1 VERSION
-Version 0.02
+Version 0.03
View
@@ -1,9 +1,18 @@
use Test::More tests => 2;
use Builder;
+# local test lib
+use lib 't/lib';
+use IO::Scalar;
+
my $got;
-open my $fh, '>', \$got or die $!;
+
+# below only works in 5.8.* and greater
+# open my $fh, '>', \$got or die $!;
+
+my $fh = IO::Scalar->new( \$got ); # so use IO::Scalar insteead
my $builder = Builder->new( output => $fh );
+
my $xm = $builder->block( 'Builder::XML', { indent => 4, newline => 1 } );
my $expected =
View
@@ -0,0 +1,196 @@
+package IO::AtomicFile;
+
+### DOCUMENTATION AT BOTTOM OF FILE
+
+# Be strict:
+use strict;
+
+# External modules:
+use IO::File;
+
+
+#------------------------------
+#
+# GLOBALS...
+#
+#------------------------------
+use vars qw($VERSION @ISA);
+
+# The package version, both in 1.23 style *and* usable by MakeMaker:
+$VERSION = "2.110";
+
+# Inheritance:
+@ISA = qw(IO::File);
+
+
+#------------------------------
+# new ARGS...
+#------------------------------
+# Class method, constructor.
+# Any arguments are sent to open().
+#
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new();
+ ${*$self}{'io_atomicfile_suffix'} = '';
+ $self->open(@_) if @_;
+ $self;
+}
+
+#------------------------------
+# DESTROY
+#------------------------------
+# Destructor.
+#
+sub DESTROY {
+ shift->close(1); ### like close, but raises fatal exception on failure
+}
+
+#------------------------------
+# open PATH, MODE
+#------------------------------
+# Class/instance method.
+#
+sub open {
+ my ($self, $path, $mode) = @_;
+ ref($self) or $self = $self->new; ### now we have an instance!
+
+ ### Create tmp path, and remember this info:
+ my $temp = "${path}..TMP" . ${*$self}{'io_atomicfile_suffix'};
+ ${*$self}{'io_atomicfile_temp'} = $temp;
+ ${*$self}{'io_atomicfile_path'} = $path;
+
+ ### Open the file! Returns filehandle on success, for use as a constructor:
+ $self->SUPER::open($temp, $mode) ? $self : undef;
+}
+
+#------------------------------
+# _closed [YESNO]
+#------------------------------
+# Instance method, private.
+# Are we already closed? Argument sets new value, returns previous one.
+#
+sub _closed {
+ my $self = shift;
+ my $oldval = ${*$self}{'io_atomicfile_closed'};
+ ${*$self}{'io_atomicfile_closed'} = shift if @_;
+ $oldval;
+}
+
+#------------------------------
+# close
+#------------------------------
+# Instance method.
+# Close the handle, and rename the temp file to its final name.
+#
+sub close {
+ my ($self, $die) = @_;
+ unless ($self->_closed(1)) { ### sentinel...
+ $self->SUPER::close();
+ rename(${*$self}{'io_atomicfile_temp'},
+ ${*$self}{'io_atomicfile_path'})
+ or ($die ? die "close atomic file: $!\n" : return undef);
+ }
+ 1;
+}
+
+#------------------------------
+# delete
+#------------------------------
+# Instance method.
+# Close the handle, and delete the temp file.
+#
+sub delete {
+ my $self = shift;
+ unless ($self->_closed(1)) { ### sentinel...
+ $self->SUPER::close();
+ return unlink(${*$self}{'io_atomicfile_temp'});
+ }
+ 1;
+}
+
+#------------------------------
+# detach
+#------------------------------
+# Instance method.
+# Close the handle, but DO NOT delete the temp file.
+#
+sub detach {
+ my $self = shift;
+ $self->SUPER::close() unless ($self->_closed(1));
+ 1;
+}
+
+#------------------------------
+1;
+__END__
+
+
+=head1 NAME
+
+IO::AtomicFile - write a file which is updated atomically
+
+
+=head1 SYNOPSIS
+
+ use IO::AtomicFile;
+
+ ### Write a temp file, and have it install itself when closed:
+ my $FH = IO::AtomicFile->open("bar.dat", "w");
+ print $FH "Hello!\n";
+ $FH->close || die "couldn't install atomic file: $!";
+
+ ### Write a temp file, but delete it before it gets installed:
+ my $FH = IO::AtomicFile->open("bar.dat", "w");
+ print $FH "Hello!\n";
+ $FH->delete;
+
+ ### Write a temp file, but neither install it nor delete it:
+ my $FH = IO::AtomicFile->open("bar.dat", "w");
+ print $FH "Hello!\n";
+ $FH->detach;
+
+
+=head1 DESCRIPTION
+
+This module is intended for people who need to update files
+reliably in the face of unexpected program termination.
+
+For example, you generally don't want to be halfway in the middle of
+writing I</etc/passwd> and have your program terminate! Even
+the act of writing a single scalar to a filehandle is I<not> atomic.
+
+But this module gives you true atomic updates, via rename().
+When you open a file I</foo/bar.dat> via this module, you are I<actually>
+opening a temporary file I</foo/bar.dat..TMP>, and writing your
+output there. The act of closing this file (either explicitly
+via close(), or implicitly via the destruction of the object)
+will cause rename() to be called... therefore, from the point
+of view of the outside world, the file's contents are updated
+in a single time quantum.
+
+To ensure that problems do not go undetected, the "close" method
+done by the destructor will raise a fatal exception if the rename()
+fails. The explicit close() just returns undef.
+
+You can also decide at any point to trash the file you've been
+building.
+
+
+=head1 AUTHOR
+
+=head2 Primary Maintainer
+
+David F. Skoll (F<dfs@roaringpenguin.com>).
+
+=head2 Original Author
+
+Eryq (F<eryq@zeegee.com>).
+President, ZeeGee Software Inc (F<http://www.zeegee.com>).
+
+
+=head1 REVISION
+
+$Revision: 1.2 $
+
+=cut
Oops, something went wrong.

0 comments on commit 03589fe

Please sign in to comment.