X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FXML%2FTags.pm;h=a9e0785f300fd7c86a426d53c475c381d11d41a2;hb=dea7a4fdc380caecb71dfa1bedd6e89fcd38398f;hp=60ab398b758ef377a1c53ffdd8a26b61a54607fd;hpb=43a70ddbfb592107d8c59e776e6d45fa5a9aebb2;p=catagits%2FWeb-Simple.git diff --git a/lib/XML/Tags.pm b/lib/XML/Tags.pm index 60ab398..a9e0785 100644 --- a/lib/XML/Tags.pm +++ b/lib/XML/Tags.pm @@ -5,6 +5,8 @@ use warnings FATAL => 'all'; use File::Glob (); +require overload; + my $IN_SCOPE = 0; sub import { @@ -14,24 +16,26 @@ sub import { my $opts = shift(@args) if ref($args[0]) eq 'HASH'; my $target = $class->_find_target(0, $opts); my @tags = $class->_find_tags(@args); - $class->_setup_glob_override; my $unex = $class->_export_tags_into($target => @tags); + if ($INC{"bareword/filehandles.pm"}) { bareword::filehandles->import } $class->_install_unexporter($unex); $IN_SCOPE = 1; } -sub sanitize { +sub to_xml_string { map { # string == text -> HTML, scalarref == raw HTML, other == passthrough ref($_) ? (ref $_ eq 'SCALAR' ? $$_ : $_) : do { local $_ = $_; # copy - s/&/&/g; s/"/"/g; s//>/g; $_; + if (defined) { + s/&/&/g; s/"/"/g; s//>/g; $_; + } else { + '' + } } } @_ } -sub _glob_glob { eval '\*CORE::GLOBAL::glob' } - sub _find_tags { shift; @_ } sub _find_target { @@ -41,12 +45,16 @@ sub _find_target { return (caller($level))[0]; } -sub _setup_glob_override { - no warnings 'redefine'; +sub _set_glob { + # stupid insanity. delete anything already there so we disassociated + # the *CORE::GLOBAL::glob typeglob. Then the string reference call + # revivifies it - i.e. creates us a new glob, which we get a reference + # to, which we can then assign to. + # doing it without the quotes doesn't - it binds to the version in scope + # at compile time, which means after a delete you get a nice warm segv. delete ${CORE::GLOBAL::}{glob}; - *{_glob_glob()} = sub { - return \('<'.$_[0].'>'); - }; + no strict 'refs'; + *{'CORE::GLOBAL::glob'} = $_[0]; } sub _export_tags_into { @@ -55,20 +63,25 @@ sub _export_tags_into { no strict 'refs'; tie *{"${into}::${tag}"}, 'XML::Tags::TIEHANDLE', \"<${tag}>"; } + _set_glob(sub { + local $XML::Tags::StringThing::IN_GLOBBERY = 1; + \('<'."$_[0]".'>'); + }); + overload::constant(q => sub { XML::Tags::StringThing->from_constant(@_) }); return sub { foreach my $tag (@tags) { no strict 'refs'; delete ${"${into}::"}{$tag} } - delete ${CORE::GLOBAL::}{glob}; - *{_glob_glob()} = \&File::Glob::glob; + _set_glob(\&File::Glob::glob); + overload::remove_constant('q'); $IN_SCOPE = 0; }; } sub _install_unexporter { my ($class, $unex) = @_; - $^H |= 0x120000; # localize %^H + $^H |= 0x20000; # localize %^H $^H{'XML::Tags::Unex'} = bless($unex, 'XML::Tags::Unex'); } @@ -81,4 +94,47 @@ package XML::Tags::Unex; sub DESTROY { local $@; eval { $_[0]->(); 1 } || warn "ARGH: $@" } +package XML::Tags::StringThing; + +use overload ( + '.' => 'concat', + '""' => 'stringify', + fallback => 1 +); + +sub stringify { + join( + '', + ((our $IN_GLOBBERY) + ? XML::Tags::to_xml_string(@{$_[0]}) + : (map +(ref $_ ? $$_ : $_), @{$_[0]}) + ) + ); +} + +sub from_constant { + my ($class, $initial, $parsed, $type) = @_; + return $parsed unless $type eq 'qq'; + return $class->new($parsed); +} + +sub new { + my ($class, $string) = @_; + bless([ \$string ], $class); +} + +sub concat { + my ($self, $other, $rev) = @_; + my @extra = do { + if (ref($other) && ($other =~ /[a-z]=[A-Z]/) && $other->isa(__PACKAGE__)) { + @{$other} + } else { + $other; + } + }; + my @new = @{$self}; + $rev ? unshift(@new, @extra) : push(@new, @extra); + bless(\@new, ref($self)); +} + 1;