File Coverage

blib/lib/LaTeXML/Common/Object.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             # /=====================================================================\ #
2             # | LaTeXML::Common::Object | #
3             # | Abstract base class for LaTeXML objects | #
4             # |=====================================================================| #
5             # | Part of LaTeXML: | #
6             # | Public domain software, produced as part of work done by the | #
7             # | United States Government & not subject to copyright in the US. | #
8             # |---------------------------------------------------------------------| #
9             # | Bruce Miller #_# | #
10             # | http://dlmf.nist.gov/LaTeXML/ (o o) | #
11             # \=========================================================ooo==U==ooo=/ #
12             package LaTeXML::Common::Object;
13 22     22   73 use strict;
  22         17  
  22         462  
14 22     22   56 use warnings;
  22         21  
  22         342  
15 22     22   339 use LaTeXML::Global;
  22         21  
  22         1225  
16 22     22   4832 use XML::LibXML; # Need XML_xxx constants!
  0            
  0            
17             use base qw(Exporter);
18             our @EXPORT = (
19             qw(&Stringify &ToString &Revert &Equals),
20             );
21              
22             #======================================================================
23             # Exported generic functions for dealing with LaTeXML's objects
24             #======================================================================
25              
26             my %NOBLESS = map { ($_ => 1) } qw( SCALAR HASH ARRAY CODE REF GLOB LVALUE); # [CONSTANT]
27              
28             # Since the next two are used in debugging and error messages,
29             # be careful to avoid recursive errors
30             sub Stringify {
31             my ($object) = @_;
32             my $string = eval {
33             local $LaTeXML::IGNORE_ERRORS = 1;
34             if (!defined $object) { return 'undef'; }
35             elsif (!ref $object) { return $object; }
36             elsif ($NOBLESS{ ref $object }) { return "$object"; }
37             elsif ($object->can('stringify')) { return $object->stringify; }
38             # Have to handle LibXML stuff explicitly (unless we want to add methods...?)
39             elsif ($object->isa('XML::LibXML::Node')) {
40             if ($object->nodeType == XML_ELEMENT_NODE) {
41             my $model = $STATE && $STATE->getModel;
42             my $tag = ($model ? $model->getNodeQName($object)
43             : $object->nodeName);
44             my $attributes = '';
45             foreach my $attr ($object->attributes) {
46             my $name = $attr->nodeName;
47             my $val = $attr->getData;
48             $val = substr($val, 0, 30) . "..." if length($val) > 35;
49             $attributes .= ' ' . $name . "=\"" . $val . "\""; }
50             return "<" . $tag . $attributes . ($object->hasChildNodes ? ">..." : "/>");
51             }
52             elsif ($object->nodeType == XML_TEXT_NODE) {
53             return "XMLText[" . $object->data . "]"; }
54             elsif ($object->nodeType == XML_DOCUMENT_NODE) {
55             return "XMLDocument[" . $$object . "]"; }
56             elsif ($object->nodeType == XML_DOCUMENT_FRAG_NODE) {
57             return "XMLFragment[" . join('', map { Stringify($_) } $object->childNodes) . "]"; }
58             else { return "$object"; } }
59             else { return "$object"; } };
60             return (defined $string ? $string : overload::StrVal($object)); } # Fallback, if errors
61              
62             sub ToString {
63             my ($object) = @_;
64             return '' unless defined $object;
65             my $string = eval {
66             local $LaTeXML::IGNORE_ERRORS = 1;
67             my $r;
68             return (($r = ref $object) && !$NOBLESS{$r} ? $object->toString : "$object"); };
69             return (defined $string ? $string : overload::StrVal($object)); } # Fallback, if errors
70              
71             # Just how deep of an equality test should this be?
72             sub Equals {
73             my ($a, $b) = @_;
74             return 1 if !(defined $a) && !(defined $b); # both undefined, equal, I guess
75             return 0 unless (defined $a) && (defined $b); # else both must be defined
76             my $refa = (ref $a) || '_notype_';
77             my $refb = (ref $b) || '_notype_';
78             return 0 if $refa ne $refb; # same type?
79             return $a eq $b if ($refa eq '_notype_') || $NOBLESS{$refa}; # Deep comparison of builtins?
80             # Special cases? (should be methods, but that embeds State knowledge too low)
81              
82             if ($refa eq 'LaTeXML::Core::Token') { # Check if they've been \let to the same defn.
83             my $defa = $STATE->lookupMeaning($a) || $a;
84             my $defb = $STATE->lookupMeaning($b) || $b;
85             return $defa->equals($defb); }
86             return $a->equals($b); } # semi-shallow comparison?
87              
88             # Reverts an object into TeX code, as a Tokens list, that would create it.
89             # Note that this is not necessarily the original TeX.
90             sub Revert {
91             my ($thing) = @_;
92             no warnings 'recursion';
93             return (defined $thing
94             ? (ref $thing ? map { $_->unlist } $thing->revert
95             : LaTeXML::Core::Token::Explode($thing)) # Ugh!!
96             : ()); }
97              
98             #======================================================================
99             # LaTeXML Object
100             # Base object for all LaTeXML Objects;
101             # Defines basic default methods for comparison, printing
102             # Tried to use overloading, but the Magic methods lead to hard-to-find
103             # (and occasionally quite serious) performance issues -- at least, if you
104             # try to have stringify do too much.
105             #======================================================================
106              
107             sub stringify {
108             my ($object) = @_;
109             my $string = "$object"; overload::StrVal($object);
110             $string =~ s/^LaTeXML:://;
111             $string =~ s/=(SCALAR|HASH|ARRAY|CODE|REF|GLOB|LVALUE|)\(/\[@/;
112             $string =~ s/\)$/\]/;
113             return $string; }
114              
115             sub toString {
116             my ($self) = @_;
117             return $self->stringify; }
118              
119             sub toAttribute {
120             my ($self) = @_;
121             return $self->toString; }
122              
123             sub equals {
124             my ($a, $b) = @_;
125             return "$a" eq "$b"; } # overload::StrVal($a) eq overload::StrVal($b); }
126              
127             sub notequals {
128             my ($a, $b) = @_;
129             return !($a->equals($b)); }
130              
131             sub isaToken { return 0; }
132             sub isaBox { return 0; }
133             sub isaDefinition { return 0; }
134              
135             # These should really only make sense for Data objects within the
136             # processing stream.
137             # Defaults (probably poor)
138             sub beDigested {
139             my ($self) = @_;
140             return $self; }
141              
142             sub beAbsorbed {
143             my ($self, $document) = @_;
144             return $document->openText($self->toString, $document->getNodeFont($document->getElement)); }
145              
146             sub unlist {
147             my ($self) = @_;
148             return $self; }
149              
150             #**********************************************************************
151             1;
152              
153             __END__