4 use warnings FATAL => 'all';
13 die "Can't import XML::Tags into a scope when already compiling one that uses it"
15 my ($class, @args) = @_;
16 my $opts = shift(@args) if ref($args[0]) eq 'HASH';
17 my $target = $class->_find_target(0, $opts);
18 my @tags = $class->_find_tags(@args);
19 my $unex = $class->_export_tags_into($target => @tags);
20 $class->_install_unexporter($unex);
25 map { # string == text -> HTML, scalarref == raw HTML, other == passthrough
27 ? (ref $_ eq 'SCALAR' ? $$_ : $_)
28 : do { local $_ = $_; # copy
30 s/&/&/g; s/"/"/g; s/</</g; s/>/>/g; $_;
40 while(my $raw = shift) {
41 my $normalized_raw = ref $raw ? (ref $raw eq 'SCALAR' ? $$raw: "$raw") : $raw;
46 ( / )? ( [^/!<>\s"'=]+ )
47 ( (?:"[^"]*"|'[^']*'|[^"'<>])+? )?
49 (!-- .*? -- | ![^\-] .*? )
61 $comment_or_directive,
65 if($comment_or_directive) {
66 if($events[-1] && $events[-1]->{type} eq 'SPECIAL') {
67 $events[-1]->{raw} .= $normalized_raw;
69 push @events, { type => 'SPECIAL', raw => $normalized_raw };
71 } elsif(!scalar(@info)) {
72 if($events[-1] && $events[-1]->{type} eq 'TEXT') {
73 $events[-1]->{raw} .= $normalized_raw;
74 } elsif(ref $raw && ref $raw eq 'SCALAR' && $events[-1] && $events[-1]->{type} eq 'SPECIAL') {
75 $events[-1]->{raw} .= $normalized_raw;
76 } elsif(ref $raw && ref $raw eq 'SCALAR') {
77 push @events, { type => 'SPECIAL', raw => $normalized_raw };
80 push @events, { type => 'TEXT', raw => $normalized_raw };
84 $tag_name =~ tr/A-Z/a-z/;
85 push @events, { type => 'CLOSE', name => $tag_name, raw => $normalized_raw};
87 $attrs = '' if !defined($attrs) or $attrs =~ /^ +$/;
91 is_in_place_close => $in_place_close,
92 HTML::Zoom::Parser::BuiltIn::_hacky_attribute_parser($attrs),
93 raw_attrs => $attrs||'',
101 is_in_place_close => 1,
110 sub _find_tags { shift; @_ }
113 my ($class, $extra_levels, $opts) = @_;
114 return $opts->{into} if defined($opts->{into});
115 my $level = ($opts->{into_level} || 1) + $extra_levels;
116 return (caller($level))[0];
120 # stupid insanity. delete anything already there so we disassociated
121 # the *CORE::GLOBAL::glob typeglob. Then the string reference call
122 # revivifies it - i.e. creates us a new glob, which we get a reference
123 # to, which we can then assign to.
124 # doing it without the quotes doesn't - it binds to the version in scope
125 # at compile time, which means after a delete you get a nice warm segv.
126 delete ${CORE::GLOBAL::}{glob};
128 *{'CORE::GLOBAL::glob'} = $_[0];
131 sub _export_tags_into {
132 my ($class, $into, @tags) = @_;
133 foreach my $tag (@tags) {
135 tie *{"${into}::${tag}"}, 'XML::Tags::TIEHANDLE', \"<${tag}>";
138 local $XML::Tags::StringThing::IN_GLOBBERY = 1;
141 overload::constant(q => sub { XML::Tags::StringThing->from_constant(@_) });
143 foreach my $tag (@tags) {
145 delete ${"${into}::"}{$tag}
147 _set_glob(\&File::Glob::glob);
148 overload::remove_constant('q');
153 sub _install_unexporter {
154 my ($class, $unex) = @_;
155 $^H |= 0x120000; # localize %^H
156 $^H{'XML::Tags::Unex'} = bless($unex, 'XML::Tags::Unex');
159 package XML::Tags::TIEHANDLE;
161 sub TIEHANDLE { my $str = $_[1]; bless \$str, $_[0] }
162 sub READLINE { ${$_[0]} }
164 package XML::Tags::Unex;
166 sub DESTROY { local $@; eval { $_[0]->(); 1 } || warn "ARGH: $@" }
168 package XML::Tags::StringThing;
180 ? XML::Tags::to_xml_string(@{$_[0]})
181 : (map +(ref $_ ? $$_ : $_), @{$_[0]})
187 my ($class, $initial, $parsed, $type) = @_;
188 return $parsed unless $type eq 'qq';
189 return $class->new($parsed);
193 my ($class, $string) = @_;
194 bless([ \$string ], $class);
198 my ($self, $other, $rev) = @_;
200 if (ref($other) && ($other =~ /[a-z]=[A-Z]/) && $other->isa(__PACKAGE__)) {
207 $rev ? unshift(@new, @extra) : push(@new, @extra);
208 bless(\@new, ref($self));