File Coverage

blib/lib/Biblio/Thesaurus.pm
Criterion Covered Total %
statement 338 784 43.1
branch 118 334 35.3
condition 16 92 17.3
subroutine 40 80 50.0
pod 45 45 100.0
total 557 1335 41.7


line stmt bran cond sub pod time code
1             # -*- Mode: Perl; tab-width: 2; -*-
2             package Biblio::Thesaurus;
3 7     7   262572 use 5.010;
  7         30  
  7         326  
4 7     7   46 use strict;
  7         14  
  7         277  
5 7     7   37 use warnings;
  7         17  
  7         328  
6             require Exporter;
7 7     7   23729 use Storable;
  7         45615  
  7         702  
8 7     7   58670 use CGI qw/:standard/;
  7         154339  
  7         58  
9              
10 7     7   29574 use Data::Dumper;
  7         18037  
  7         105568  
11              
12             # Version
13             our $VERSION = '0.43';
14              
15             # Module Stuff
16             our @ISA = qw(Exporter);
17             our %EXPORT_TAGS = ( 'all' => [ qw() ] );
18             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
19              
20             # We are working with an object oriented interface. This means, we only
21             # need to export constructors.
22             #
23             # The last three variables are used to down-translation sub (downtr)
24             our @EXPORT = qw(
25             &thesaurusLoad
26             &thesaurusLoadM
27             &thesaurusNew
28             &thesaurusRetrieve
29             &thesaurusMultiLoad
30             @terms $term $rel);
31              
32             our ($casesen,$rel,@terms,$term);
33              
34              
35             ##
36             #
37             #
38 0     0 1 0 sub top_name { topName(@_) }
39              
40             sub topName {
41 1     1 1 2 my ($self, $name) = @_;
42 1 50       3 if($name){ $self->{name} = $name;}
  0         0  
43 1         4 else { return $self->{name};}
44             }
45              
46             sub order {
47 0     0 1 0 my ($self,@names) = @_;
48 0 0       0 if(@names){ $self->{order} = [@names] ; }
  0         0  
49 0 0       0 else { defined $self->{order} ? (@{$self->{order}}) : () }
  0         0  
50             }
51              
52             sub isLanguage{
53 0     0 1 0 my ($self,$l) = @_;
54 0         0 return defined $self->{languages}{$l}
55             }
56              
57             sub languages{
58 0     0 1 0 my ($self,@names) = @_;
59 0 0       0 if(@names){ for (@names) { $self->{languages}{$_} = 1; }}
  0         0  
  0         0  
60 0         0 else { keys (%{$self->{languages}}) }
  0         0  
61             }
62              
63             sub baselang {
64 0     0 1 0 my ($self,$name) = @_;
65 0 0       0 if($name){ $self->{$name} = $self->{$self->{baselang}};
  0         0  
  0         0  
66 0         0 delete $self->{$self->{baselang}};
67 0         0 $self->{baselang} = $name;}
68             else {return $self->{baselang};}
69             }
70              
71             ##
72             #
73             #
74             sub terms {
75 28     28 1 337 my ($self, $term, @rels) = @_;
76 28         55 my $base = $self->{baselang};
77 28 50       63 return () unless $self->isDefined($term);
78 28         76 $term = $self->_definition($term);
79              
80 28         58 @rels = map { uc $_ } @rels;
  29         89  
81              
82             return (map {
83 28 100       56 if (defined($self->{$base}{$term}{$_})) {
  29         92  
84 11 50       45 if (ref($self->{$base}{$term}{$_}) eq "ARRAY") {
85 11         15 @{$self->{$base}{$term}{$_}}
  11         73  
86             } else {
87 0         0 ($self->{$base}{$term}{$_})
88             }
89             } else {
90             ()
91 18         44 }
92             } @rels);
93             }
94              
95             ##
96             # Parece-me que não está a ser usada.
97             #
98             # sub external {
99             # my ($self,$term,$external) = @_;
100             # $external = uc($external);
101             # $term = $self->definition($term);
102             # return $self->{$self->{baselang}}{$term}{$external};
103             # }
104              
105             ###
106             #
107             #
108 0     0 1 0 sub all_terms { allTerms(@_) }
109              
110             sub allTerms {
111 5     5 1 826 my $self = shift;
112 5         7 return sort keys %{$self->{$self->{baselang}}};
  5         46  
113             }
114              
115             ###
116             #
117             #
118             sub depth_first {
119 43     43 1 985 my ($self,$term,$niveis,@relat) = @_;
120 43         56 my %st=();
121              
122 43 100       93 if ($niveis>=1) {
  29 50       100  
123 14         35 for ($self->terms($term,@relat)) {
124 38         86 $st{$_}=depth_first($self,$_,$niveis-1,@relat);
125             }
126 14         51 \%st; }
127 0         0 elsif($niveis == 0) {1}
128             else {1}
129             }
130              
131             ###
132             #
133             #
134             sub _default_norelations {
135             return {
136 12     12   89 'URL'=> 1,
137             'SN' => 1
138             };
139             }
140              
141             ###
142             #
143             #
144             sub _default_inversions {
145 12     12   115 +{ NT => 'BT', BT => 'NT', RT => 'RT', USE => 'UF', UF => 'USE' };
146             }
147              
148             ###
149             #
150             #
151             sub _translateTerm {
152 0     0   0 my ($self,$term,$lang,$dic) = @_;
153 0 0       0 $dic = {} unless $dic;
154              
155 0         0 $lang = uc($lang);
156             # Se foi $lang definido como linguagem
157 0 0       0 if (defined($self->{languages}{$lang})) {
158 0         0 my $trad;
159             # Se existe a tradução
160 0 0       0 if (defined($trad = $self->{$self->{baselang}}{$term}{$lang})) {
161 0         0 return $trad;
162             }
163             }
164              
165 0 0       0 if(defined $dic->{$term}) {return $dic->{ $term}}
  0         0  
166 0 0       0 if(defined $dic->{lcfirst($term)}) {return ucfirst($dic->{lcfirst($term)})}
  0         0  
167 0 0       0 if(defined $dic->{lc($term)}) {return uc($dic->{ lc($term)})}
  0         0  
168              
169 0         0 return "[$self->{baselang}-$lang:".$self->getdefinition($term)."]";
170             }
171              
172              
173             ###
174             #
175             #
176             sub appendThesaurus {
177 2     2 1 7 my ($self,$other) = @_;
178              
179             # This way we handle full thesaurus objects or simple filename
180 2 50       9 unless (ref($other)) {
181 2         6 $other = thesaurusLoad($other);
182             }
183              
184 2         4 my $new;
185              
186             # Check if baselang is the same, or if some of them is undefined
187 2 100       13 if ($self->{baselang} eq $other->{baselang}) {
    50          
    50          
188 1         4 $new->{baselang} = $self->{baselang}
189              
190             } elsif ($self->{baselang} eq "_") {
191 0         0 $new->{baselang} = $other->{baselang}
192              
193             } elsif ($other->{baselang} eq "_") {
194 1         3 $new->{baselang} = $self->{baselang}
195              
196             } else {
197 0         0 return undef;
198             }
199              
200             # If some of the top is _top_, the other is choosed. If
201             # there are two different tops, use the first ($self) one
202 2 100       12 if ($other->{name} eq $self->{name}) {
    50          
    50          
203 1         2 $new->{name} = $self->{name}
204              
205             } elsif ($other->{name} eq "_top_") {
206 0         0 $new->{name} = $self->{name}
207              
208             } elsif ($self->{name} eq "_top_") {
209 1         3 $new->{name} = $other->{name}
210              
211             } else {
212 0         0 $new->{name} = $self->{name}
213             }
214              
215             # VERSION: current module version
216 2         6 $new->{version} = $VERSION;
217              
218             sub _ffjoin {
219             # key, hash1ref, hash2ref
220 8     8   18 my ($c,$a,$b) = @_;
221 8 50 33     44 if (exists($a->{$c}) && exists($b->{$c})) {
    0          
    0          
222 8         11 return {%{$a->{$c}},%{$b->{$c}}};
  8         33  
  8         56  
223             } elsif (exists($a->{$c})) {
224 0         0 return {%{$a->{$c}}}
  0         0  
225             } elsif (exists($b->{$c})) {
226 0         0 return {%{$b->{$c}}}
  0         0  
227             } else {
228             return {}
229 0         0 }
230             }
231              
232             # Inverses: join hash tables... in conflict, $self is used
233 2         7 $new->{inverses} = _ffjoin("inverses",$other,$self);
234              
235             # Descriptions: in conflict, $self is used
236 2         11 $new->{descriptions} = _ffjoin("descriptions",$other,$self);
237              
238             # Externals: union
239 2         9 $new->{externals} = _ffjoin("externals",$self,$other);
240              
241             # Languages: union
242 2         15 $new->{languages} = _ffjoin("languages",$self,$other);
243             # delete($new->{languages}{"_"}) if ($new->{baselang} ne "_");
244              
245             # Get terms for the new thesaurus
246 2         10 my @terms = _set_of(keys %{$self ->{$self ->{baselang}}},
  2         12  
247 2         13 keys %{$other->{$other->{baselang}}});
248              
249             # Para cada termo do thesaurus...
250 2         8 for my $term (@terms) {
251              
252             # existe em ambos...
253 20 100 100     44 if ($self->isDefined($term) && $other->isDefined($term)) {
    100          
254 6         17 my ($a_def,$b_def) = ($self->_definition($term),
255             $other->_definition($term));
256 6         12 my $def = $a_def;
257              
258 6         19 $new->{defined}{lc($def)} = $def;
259              
260 6         18 my @class = _set_of(keys %{$self ->{$self ->{baselang}}{$a_def}},
  6         23  
261 6         9 keys %{$other->{$other->{baselang}}{$b_def}});
262            
263             # para cada uma das suas relações...
264 6         13 for my $class (@class) {
265 16 100       56 if ($class eq "_NAME_") {
    100          
    50          
266              
267             # print STDERR Dumper($new->{$new->{baselang}}{$def});
268             # optar pela forma do thesaurus A
269 6         24 $new->{$new->{baselang}}{$def}{_NAME_} = $def;
270              
271             } elsif ($new->{externals}{$class}) {
272 1 50       5 if (exists($self->{$self->{baselang}}{$a_def}{$class})) {
273 1         9 push @{$new->{$new->{baselang}}{$def}{$class}},
  1         4  
274 1         2 @{$self->{$self->{baselang}}{$a_def}{$class}};
275             }
276 1 50       4 if (exists($other->{$other->{baselang}}{$b_def}{$class})) {
277 0         0 push @{$new->{$new->{baselang}}{$def}{$class}},
  0         0  
278 0         0 @{$other->{$other->{baselang}}{$b_def}{$class}};
279             }
280              
281             } elsif ($new->{languages}{$class}) {
282 0         0 $new->{$new->{baselang}}{$def}{$class} = "_";
283              
284             } else {
285 9 100 100     61 if (exists($self ->{$self ->{baselang}}{$a_def}{$class}) &&
    100          
286             exists($other->{$other->{baselang}}{$b_def}{$class})) {
287              
288             # Join lists
289 6         10 my %there;
290 6         19 @there{@{$self->{$self->{baselang}}{$a_def}{$class}}} =
  6         19  
291 6         8 1 x @{$self->{$self->{baselang}}{$a_def}{$class}};
292              
293 6         8 push @{$new->{$new->{baselang}}{$def}{$class}}, keys %there;
  6         23  
294              
295 6         11 for (@{$other->{$other->{baselang}}{$b_def}{$class}}) {
  6         17  
296 7 100       56 unless ($there{$_}) {
297 5         8 push @{$new->{$new->{baselang}}{$def}{$class}}, $_;
  5         13  
298             }
299 7         24 $there{$_} = 1;
300             }
301              
302             } elsif (exists($self->{$self->{baselang}}{$a_def}{$class})) {
303 2         13 $new->{$new->{baselang}}{$def}{$class} =
304             $self->{$self->{baselang}}{$a_def}{$class};
305             } else { ## other->b_def->class
306 1         12 $new->{$new->{baselang}}{$def}{$class} =
307             $other->{$other->{baselang}}{$b_def}{$class};
308             }
309             }
310             }
311              
312             } elsif ($self->isDefined($term)) {
313 9         17 $new->{defined}{lc($term)} = $self->_definition($term);
314 9         41 $new->{$new->{baselang}}{$term} = $self->{$self->{baselang}}{$term};
315             } else { ### $other->isDefined($term)
316 5         12 $new->{defined}{lc($term)} = $other->_definition($term);
317 5         72 $new->{$new->{baselang}}{$term} = $other->{$other->{baselang}}{$term};
318             }
319             }
320              
321 2         57 return bless($new);
322             }
323              
324              
325             ###
326             #
327             #
328             sub thesaurusMultiLoad {
329 1     1 1 813 my @files = @_;
330              
331 1         6 my $self = thesaurusLoad(shift @files);
332 1         4 while(@files) {
333 1         5 $self->appendThesaurus(shift @files);
334             }
335              
336 1         5 return $self;
337             }
338              
339             ###
340             #
341             #
342             sub top {
343 0     0 1 0 my $self = shift;
344 0         0 my $script = shift;
345 0         0 return "
    ".join("\n",
346 0         0 map {"
  • $_
  • "}
    347 0         0 @{$self->{$self->{baselang}}->{$self->{name}}->{NT}}). "";
    348             }
    349              
    350             ###
    351             #
    352             #
    353             sub _default_descriptions {
    354             return {
    355 12     12   99 'RT' => q/Related term/,
    356             'TT' => q/Top term/,
    357             'NT' => q/Narrower term/,
    358             'BT' => q/Broader term/,
    359             'USE' => q/Synonym/,
    360             'UF' => q/Quasi synonym/,
    361             'SN' => q/Scope note/,
    362             };
    363             }
    364              
    365             sub setExternal {
    366 0     0 1 0 my ($self,@rels) = @_;
    367 0         0 for (@rels) {
    368 0         0 $self->{externals}{uc($_)} = 1;
    369             }
    370 0         0 return $self;
    371             }
    372              
    373             sub isExternal {
    374 0     0 1 0 my ($self,$ext) = @_;
    375 0   0     0 return (defined($self->{externals}{uc($ext)}) &&
    376             defined($self->{externals}{uc($ext)}) == 1);
    377             }
    378              
    379             ###
    380             #
    381             #
    382             sub thesaurusNew {
    383 2     2 1 456 my $obj = {
    384             # thesaurus => {},
    385             inverses => _default_inversions(),
    386             descriptions => _default_descriptions(),
    387             externals => _default_norelations(),
    388             name => '_top_',
    389             baselang => '?',
    390             languages => {},
    391             version => $VERSION,
    392             prefix => "",
    393             };
    394              
    395             # bless and return it! Amen!
    396 2         9 return bless($obj);
    397             }
    398              
    399             ###
    400             #
    401             #
    402             sub storeOn {
    403 1     1 1 31 store(@_);
    404             }
    405              
    406             ###
    407             #
    408             #
    409             sub thesaurusRetrieve {
    410 1     1 1 783899 my $file = shift;
    411 1         11 my $obj = retrieve($file);
    412 1 50       378053 if (defined($obj->{version})) {
    413 1         12 return $obj;
    414             } else {
    415 0         0 die("Rebuild your thesaurus with a recent Biblio::Thesaurus version");
    416             }
    417             }
    418              
    419             ###
    420             #
    421             #
    422             sub _trurl {
    423 0     0   0 my $t = shift;
    424 0         0 $t =~ s/\s/+/g;
    425 0         0 return $t;
    426             }
    427              
    428             ###
    429             #
    430             #
    431             sub getHTMLTop {
    432 0     0 1 0 my $self = shift;
    433 0   0     0 my $script = shift || $ENV{SCRIPT_NAME};
    434 0         0 my $t = "
      ";
    435 0         0 $t.=join("\n",
    436 0         0 map { "
  • $_
  • " }
    437 0         0 @{$self->{$self->{baselang}}->{$self->{name}}->{NT}});
    438 0         0 $t .= "";
    439 0         0 return $t;
    440             }
    441              
    442             ###
    443             #
    444             #
    445             sub thesaurusLoad {
    446              
    447 10     10 1 2182 my %opt =();
    448             # completed => 1
    449 10 50       48 if(ref($_[0]) eq "HASH") {%opt = (%opt , %{shift(@_)}) } ;
      0         0  
      0         0  
    450              
    451 10         22 my ($file,$self) = @_;
    452 10         18 my %thesaurus;
    453              
    454 10 50       37 unless($self){
    455 10         37 $self->{inverses} = _default_inversions();
    456 10         34 $self->{descriptions} = _default_descriptions();
    457 10         34 $self->{externals} = _default_norelations();
    458 10         26 $self->{name} = "_top_";
    459 10         25 $self->{baselang} = "_";
    460 10         30 $self->{languages} = {};
    461 10         21 $self->{defined} = {};
    462 10         39 $self->{version} = $VERSION; }
    463             else {
    464 0         0 $self->{defined} = {};
    465             }
    466              
    467             # Open the thesaurus file to load
    468 10 50       531 open ISO, $file or die (q/Can't open thesaurus file/);
    469             ### binmode(ISO,"$opt{encoding}:") if($opt{encoding});
    470              
    471             # While we have commands or comments or empty lines, continue...
    472 10         368 while(($_ = )=~/(^(%|#))|(^\s*$)/) {
    473 104         14851 chomp;
    474              
    475 104 100       1078 if (/^%\s*inv(?:erse)?\s+(\S+)\s+(\S+)/) {
        100          
        50          
        50          
        100          
        100          
        100          
        100          
        100          
        100          
        50          
    476              
    477             # Treat the inv*erse command
    478 17         55 $self->{inverses}{uc($1)} = uc($2);
    479 17         99 $self->{inverses}{uc($2)} = uc($1);
    480              
    481             } elsif (/^%\s*enc(oding)?\s+(\S+)/) {
    482              
    483 1         6 $self->{encoding} = lc $2;
    484 1         5 $self->{encoding} =~ s/_/-/g;
    485 1     1   9 binmode ISO, ":encoding($self->{encoding})";
      1         2  
      1         10  
      1         38  
    486              
    487             } elsif (/^%\s*tit(le)?\s+(.+)/) {
    488 0         0 $self->{title} = $2;
    489              
    490             } elsif (/^%\s*aut(hor)?\s+(.+)/) {
    491 0         0 $self->{author} = $2;
    492              
    493             } elsif (/^%\s*desc(ription)?\[(\S+)\]\s+(\S+)\s+(.*)$/) {
    494              
    495             # Treat the desc*cription [lang] command.... 'RT EN'
    496 2         22 $self->{descriptions}{uc($3)." ".uc($2)} = $3;
    497              
    498             } elsif (/^%\s*desc(ription)?\s+(\S+)\s+(.*)$/) {
    499              
    500             # Treat the desc*cription command
    501 30         237 $self->{descriptions}{uc($2)} = $3;
    502              
    503             } elsif (/^%\s*ext(ernals?)?\s+(.*)$/) {
    504              
    505             # Treat the ext*ernals command
    506 4         15 chomp(my $classes = uc($2));
    507 4         18 for (split /\s+/, $classes) {
    508 8         46 $self->{externals}{$_} = 1;
    509             }
    510              
    511             } elsif (/^%\s*lang(uages?)?\s+(.*)$/) {
    512              
    513             # Treat the lang*uages command
    514 4         12 chomp(my $classes = uc($2));
    515 4         15 for (split /\s+/, $classes) {
    516 4         32 $self->{languages}{$_} = 1;
    517             }
    518              
    519             } elsif (/^%\s*top\s+(.*)$/) {
    520              
    521 5         36 $self->{name} = $1;
    522              
    523             } elsif (/^%\s*baselang(uage)?\s+(\S+)/) {
    524              
    525 8         116 $self->{baselang} = uc($2);
    526              
    527             } elsif (/^%/) {
    528              
    529 0         0 print STDERR "Unknown command: '$_'\n\n";
    530              
    531             } else {
    532             # It's a comment or an empty line: do nothing
    533             }
    534             }
    535              
    536             # Redefine the record separator
    537 10         27 my $old_sep = $/;
    538 10         26 $/ = "";
    539              
    540             # The last line wasn't a comment, a command or an empty line, so use it!
    541 10         37 $_ .= ;
    542              
    543 10         55 my $ncommands = $.-1;
    544              
    545             # While there are definitions...
    546 10         16 do {
    547             # define local variables
    548 148         160 my ($class,$term,$relations);
    549              
    550             ## Concat lines that continue back in one
    551 148         474 s/\n[ \t]+/ /g; # Can't use \s because "\n" =~ m!\s!
    552              
    553             # The first line contains the term to be defined
    554 148         773 /(.+)(?:\n((.|\n)+)|\n?$)/;
    555 148         281 $term = $1;
    556 148   100     417 $relations = $2 || "";
    557              
    558             # If the term is all spaces, go back...
    559 148 50       458 if ($term =~ /^\s+$/) {
    560 0         0 print STDERR "Term with only spaces ignored at block term ",$.-$ncommands,"\n\n";
    561 0         0 $term = '#zbr'; # This makes the next loop think this is a comment and ignore it
    562             }
    563              
    564             # Let's see if the term is commented...
    565 148 50       299 unless ($term =~ /^#/) {
    566 148         240 $term = _term_normalize($term);
    567              
    568 148 50       448 $term = $self->{defined}{lc($term)} if ($self->{defined}{lc($term)});
    569 148         557 $thesaurus{$term}{_NAME_} = $term;
    570 148         320 $self->{defined}{lc($term)} = $term;
    571              
    572             # The remaining are relations
    573 148         250 $_ = $relations;
    574              
    575             # OK! The term is *not* commented...
    576             # For each definition line...
    577 148 100       471 $_.="\n" unless /\n$/;
    578 148         639 while (/((([^#\s]+)|#)[ \t]*(.*)\n)/g) {
    579 253 100       618 next unless $4;
    580             # Is it commented?
    581 250 50       636 unless ($2 eq "#") {
    582             # it seems not... set the relation class
    583 250         368 $class = uc($2); # || $class;... now multiline are handled before this
    584              
    585 250 50       423 print STDERR "** WARNING **: '$1'\n" unless $class;
    586              
    587             # See if $class has a description
    588 250 100       593 $self->{descriptions}{$class} = ucfirst(lc($class)) unless defined $self->{descriptions}{$class};
    589             ## $descs->{$class}= ucfirst(lc($class)) unless(defined($descs->{$class}));
    590              
    591             # divide the relation terms by comma unless it is a language or extern relation
    592 250 100 66     1137 if ( exists($self->{externals}{$class}) && defined($self->{externals}{$class}) ) {
        100 66        
    593             ## $thesaurus{$term}{$class}.= ($2?"$4":" $4");
    594             ## $thesaurus{$term}{$class}.= ($thesaurus{$term}{$class}?" $4":"$4");
    595 22         23 push @{$thesaurus{$term}{$class}}, $4;
      22         202  
    596             } elsif (exists($self->{languages}{$class}) && defined($self->{languages}{$class})) {
    597             # $translations->{$class}->{_term_normalize($4)}.=$term;
    598 5         21 $self->{$class}{$4}.=$term;
    599 5         16 $self->{defined}{_term_normalize(lc($4))} = $term;
    600 5         31 $thesaurus{$term}{$class} = $4;
    601             } else {
    602 223         1310 push(@{$thesaurus{$term}{$class}}, map {
      481         712  
    603 223         218 _term_normalize($_)
    604             } split(/\s*,\s*/, $4));
    605             }
    606             }
    607             }
    608             }
    609             } while();
    610              
    611             # Close the ISO thesaurus file
    612 10         137 close ISO;
    613              
    614             # revert to the old record separator. Not needed, but beautifer.
    615 10         28 $/ = $old_sep;
    616              
    617 10         37 $self->{$self->{baselang}} = \%thesaurus;
    618 10         32 $self->{languages}{$self->{baselang}} = 1;
    619              
    620             # bless and return the thesaurus! Amen!
    621 10 50 33     54 if (exists($opt{completed}) && $opt{completed}) {
    622 0         0 return bless($self);
    623             } else {
    624 10         42 return complete(bless($self));
    625             }
    626             }
    627              
    628             sub _lc{
    629 0 0   0   0 if($casesen){$_[0]}
      0         0  
      0         0  
    630             else {lc($_[0])}
    631             }
    632              
    633             sub thesaurusLoadM {
    634 0     0 1 0 my $file = shift;
    635 0         0 my ($t,$rs)= _treatMetas1(thesaurusLoad($file));
    636 0 0       0 if(@$rs){
      0         0  
    637 0         0 undef $t->{$t->{baselang}};
    638 0         0 undef $t->{defined};
    639 0         0 _treatMetas2(thesaurusLoad($file,$t),$rs);}
    640             else{$t}
    641             }
    642              
    643             sub _treatMetas1 {
    644 0     0   0 my $t = shift;
    645 0         0 my @ts=();
    646 0         0 my %r=();
    647              
    648 0 0       0 if(@ts=$t->terms("_order_","NT")) { $t->order(@ts);
      0         0  
    649 0         0 @r{@ts,"_order_"}=(@ts,1) }
    650 0 0       0 if(@ts=$t->terms("_external_","NT")){ $t->setExternal(@ts);
      0         0  
    651 0         0 @r{@ts,"_external_"}=(@ts,1) }
    652 0 0       0 if(@ts=$t->terms("_top_","NT")) { $t->topName($ts[0]);
      0         0  
    653 0         0 $r{"_top_"}=1 }
    654 0 0       0 if(@ts=$t->terms("baselang_","NT")){ $t->baselang($ts[0]);
      0         0  
    655 0         0 @r{@ts,"baselang_"}=(@ts,1) }
    656 0 0       0 if(@ts=$t->terms("_language_","NT")){ $t->languages(@ts);
      0         0  
    657 0         0 @r{@ts,"_language_"}=(@ts,1) }
    658 0 0       0 if(@ts=$t->terms("_symmetric_","NT")){ for(@ts){ $t->addInverse($_,$_);}
      0         0  
      0         0  
    659 0         0 @r{@ts,"_symmetric_"}=(@ts,1) }
    660              
    661             # for each new relation describe it, add Invers and remove it as Term
    662 0 0       0 if(@ts=$t->terms("_relation_","NT")){
    663 0         0 $r{"_relation_"}=1 ;
    664             $t->downtr(
    665 0     0   0 { SN => sub{ $t->describe({rel => $term, desc=>$terms[0]}) }, ## FALTA A LINGUA
    666 0     0   0 INV => sub{ $t->addInverse($term,$terms[0])},
    667 0     0   0 RANG => sub{ $t->setExternal($term)},
    668             -order => ["SN","INV"],
    669 0     0   0 -eachTerm => sub{ $r{$term}=$term },
    670 0         0 }, @ts);
    671             }
    672 0         0 ($t,[(keys %r)]);
    673             }
    674              
    675             sub _treatMetas2{
    676 0     0   0 my ($t,$rs)= @_;
    677 0         0 for (@$rs){ $t->deleteTerm($_)}
      0         0  
    678 0         0 $t;
    679             }
    680              
    681             ###
    682             #
    683             #
    684             sub getDescription {
    685 0     0 1 0 my ($obj, $rel, $lang) = @_;
    686 0 0       0 if (defined($lang)) {
    687 0         0 my $x = uc($rel)." ".uc($lang);
    688 0 0       0 return exists($obj->{descriptions}->{$x})?$obj->{descriptions}->{$x}:"...";
    689             } else {
    690 0         0 my $x = uc($rel)." ".uc($obj->{baselang});
    691 0 0       0 if (exists($obj->{descriptions}->{$x})) {
        0          
    692 0         0 return $obj->{descriptions}->{$x};
    693             } elsif (exists($obj->{descriptions}->{$rel})) {
    694 0         0 return $obj->{descriptions}->{$rel};
    695             } else {
    696 0         0 return "...";
    697             }
    698             }
    699             }
    700              
    701             ###
    702             #
    703             #
    704             sub describe {
    705 0     0 1 0 my ($obj, $conf) = @_;
    706 0         0 my ($class, $desc, $lang);
    707 0 0       0 return unless ($class = uc($conf->{rel}));
    708 0 0       0 return unless ($desc = $conf->{desc});
    709 0 0       0 if ($conf->{lang}) {
    710 0         0 $lang = " ".uc($conf->{lang});
    711             } else {
    712 0         0 $lang = "";
    713             }
    714              
    715 0         0 $obj->{descriptions}->{$class.$lang}=$desc;
    716             }
    717              
    718             ###
    719             #
    720             #
    721             sub addInverse {
    722 0     0 1 0 my ($obj,$a,$b) = @_;
    723 0         0 $a = uc($a);
    724 0         0 $b = uc($b);
    725 0 0       0 $obj->{descriptions}{$a}="..." unless(defined($obj->{descriptions}{$a}));
    726 0 0       0 $obj->{descriptions}{$b}="..." unless(defined($obj->{descriptions}{$b}));
    727              
    728 0         0 for (keys %{$obj->{inverses}}) {
      0         0  
    729 0 0 0     0 delete($obj->{inverses}{$_}) if (($obj->{inverses}{$_} eq $a) ||
    730             ($obj->{inverses}{$_} eq $b));
    731             }
    732 0         0 $obj->{inverses}{$a}=$b;
    733 0         0 $obj->{inverses}{$b}=$a;
    734             }
    735              
    736             ###
    737             #
    738             #
    739             sub meta2str {
    740 0     0 1 0 my $obj = shift;
    741 0         0 my $term;
    742 0         0 my %inverses = %{$obj->{inverses}};
      0         0  
    743 0         0 my %descs = %{$obj->{descriptions}};
      0         0  
    744              
    745 0         0 my $t = "";
    746              
    747             # Save the 'encoding' command
    748             #
    749 0 0       0 $t.="\%encoding $obj->{encoding}\n\n" if defined $obj->{encoding} ;
    750              
    751             # Save the 'title' command
    752             #
    753 0 0       0 $t.="\%title $obj->{title}\n\n" if defined $obj->{title};
    754              
    755             # Save the 'author' command
    756             #
    757 0 0       0 $t.="\%author $obj->{author}\n\n" if defined $obj->{author};
    758              
    759             # Save the externals commands
    760             #
    761 0         0 $t.= "\%externals " . join(" ",keys %{$obj->{externals}});
      0         0  
    762 0         0 $t.="\n\n";
    763              
    764             # Save the languages commands
    765             #
    766 0         0 $t.= "\%languages " . join(" ",keys %{$obj->{languages}});
      0         0  
    767 0         0 $t.="\n\n";
    768              
    769             # Save the 'top' command
    770             #
    771 0 0       0 $t.="\%top $obj->{name}\n\n" if $obj->{name} ne "_top_";
    772              
    773             # Save the 'baselanguage' command
    774             #
    775 0 0       0 $t.="\%baselanguage $obj->{baselang}\n\n" if $obj->{baselang} ne "_";
    776              
    777             # Save the inverses commands
    778             #
    779 0         0 for $term (keys %inverses) {
    780 0         0 $t.= "\%inverse $term $inverses{$term}\n";
    781             }
    782 0         0 $t.="\n\n";
    783              
    784             # Save the descriptions commands
    785             #
    786 0         0 for $term (keys %descs) {
    787 0 0       0 if ( $term =~ /^(\w+)\s+(\w+)$/ ) {
    788 0         0 $t.= "\%description[$2] $1 $descs{$term}\n";
    789             } else {
    790 0         0 $t.= "\%description $term $descs{$term}\n";
    791             }
    792             }
    793 0         0 $t.="\n\n";
    794 0         0 $t;
    795             }
    796              
    797             ##
    798             #
    799             #
    800             sub save {
    801 0     0 1 0 my $obj = shift;
    802 0         0 my $file = shift;
    803 0         0 my ($term,$class);
    804 0         0 my %thesaurus = %{$obj->{$obj->{baselang}}};
      0         0  
    805 0         0 my $t = meta2str($obj); #save the metadata
    806              
    807             # Save the thesaurus
    808             #
    809 0         0 for $term (keys %thesaurus) {
    810 0         0 $t.= "\n$thesaurus{$term}{_NAME_}\n";
    811 0         0 for $class ( keys %{$thesaurus{$term}} ) {
      0         0  
    812 0 0       0 next if $class eq "_NAME_";
    813 0 0       0 if(defined $obj->{languages}{$class}) {
    814 0         0 $t.= "$class\t$thesaurus{$term}->{$class}\n";
    815             } else {
    816             # if save_compact, juntar por ',' as relacoes nao external
    817 0         0 $t.= "$class\t$_\n" for (@{$thesaurus{$term}{$class}});
      0         0  
    818             }
    819             }
    820             }
    821              
    822 0 0       0 open F, ">$file" or return 0;
    823 0 0       0 if (defined $obj->{encoding}) {
    824 0         0 $obj->{encoding} = lc($obj->{encoding});
    825 0         0 $obj->{encoding} =~ s/_/-/g;
    826 0         0 binmode(F,":encoding($obj->{encoding})") ;
    827             }
    828 0         0 print F $t;
    829 0         0 close F;
    830 0         0 return 1;
    831             }
    832              
    833             ###
    834             #
    835             #
    836             sub navigate {
    837             # The first element is the object reference
    838 0     0 1 0 my $obj = shift;
    839             # This is the script name
    840 0   0     0 my $script = $ENV{SCRIPT_NAME} || "";
    841              
    842             # Get the configuration hash
    843 0         0 my $conf = {};
    844 0 0       0 if (ref($_[0])) { $conf = shift }
      0         0  
    845              
    846 0   0     0 my $expander = $conf->{expand} || [];
    847 0         0 my @tmp = map {$obj->{inverses}{$_}} @$expander;
      0         0  
    848 0   0     0 my $language = $conf->{lang} || undef;
    849 0   0     0 my $second_level_limit = $conf->{level2size} || 0;
    850 0   0     0 my $hide_on_first_level = $conf->{level1hide} || [];
    851 0   0     0 my $hide_on_second_level = $conf->{level2hide} || \@tmp;
    852 0   0     0 my $capitalize = $conf->{capitalize} || 0;
    853 0   0     0 my $topic = $conf->{topic_name} || "t";
    854              
    855 0         0 my %hide;
    856 0         0 @hide{@$hide_on_first_level} = @$hide_on_first_level;
    857              
    858 0 0       0 $script = $conf->{scriptname} if (exists($conf->{scriptname}));
    859 0         0 my %param = @_;
    860              
    861 0         0 my $term;
    862 0         0 my $show_title = 1;
    863 0 0       0 if (exists($param{$topic})) {
    864 0         0 $param{$topic} =~ s/\+/ /g;
    865 0         0 $term = $obj->getdefinition($param{$topic});
    866             } else {
    867 0 0 0     0 $show_title = 0 if exists($conf->{title}) && $conf->{title} eq "no";
    868 0 0       0 if ($obj->isDefined($obj->{name})) {
    869 0         0 $term = $obj->{defined}{lc($obj->{name})};
    870             } else {
    871 0         0 $term = '_top_';
    872             }
    873             }
    874              
    875 0         0 my (@terms,$html);
    876              
    877             # If we don't have the term, return only the title
    878 0 0       0 return h2($term) unless ($obj->isDefined($term));
    879              
    880             # Make the page title
    881 0 0       0 $html = h2(capitalize($capitalize, $obj->_translateTerm($term,$language))) if $show_title;
    882              
    883             # Get the external relations
    884 0         0 my %norel = %{$obj->{externals}};
      0         0  
    885              
    886             # Now print the relations
    887 0         0 my $rel;
    888 0         0 for $rel (keys %{$obj->{$obj->{baselang}}{$term}}) {
      0         0  
    889             # next iteraction if the relation is the _NAME_
    890 0 0       0 next if ($rel eq "_NAME_");
    891              
    892             # Next if we want to hide it
    893 0 0       0 next if exists $hide{$rel};
    894              
    895             # This block jumps if it is an expansion relation
    896 0 0       0 next if grep {$_ eq uc($rel)} @{$expander};
      0         0  
      0         0  
    897              
    898             # The externs exceptions...
    899 0 0       0 if (exists($norel{$rel})) {
        0          
    900             # It's an external, so...
    901             #
    902             # Its description is "..."?
    903 0         0 my $desc = $obj->getDescription($rel, $language);
    904              
    905 0         0 $html .= join("
    \n", map { b($desc)." $_" } @{$obj->{$obj->{baselang}}{$term}{$rel}});
      0         0  
      0         0  
    906 0         0 $html .= " ".br;
    907             } elsif (exists($obj->{languages}{$rel})) {
    908             ## This empty block is used for languages translations
    909              
    910             } else {
    911             ## OK! It's a simple relation
    912              
    913             # There is a translation for the *relation* description?
    914 0         0 my $desc = $obj->getDescription($rel, $language);
    915 0 0       0 if ($desc eq "...") {
    916 0         0 $html .= b($rel)." ";
    917             } else {
    918 0         0 $html.= b($desc)." ";
    919             }
    920              
    921             # Now, write each term with a thesaurus link
    922 0         0 $html.= join(", ", map {
    923 0         0 my $term = $_;
    924 0         0 my $link = $term;
    925 0         0 $link =~ s/\s/+/g;
    926 0         0 $term = $obj->_translateTerm($term, $language);
    927 0         0 a({ href=>"$script?$topic=$link"},$term)
    928 0         0 } sort {lc($a)cmp lc($b)} @{$obj->{$obj->{baselang}}{$term}{$rel}});
      0         0  
    929              
    930 0         0 $html.= br;
    931             }
    932             }
    933              
    934             # Now, treat the expansion relations
    935 0         0 for $rel (@{$expander}) {
      0         0  
    936 0         0 $rel = uc($rel);
    937 0 0       0 if (exists($obj->{$obj->{baselang}}{$term}{$rel})) {
    938 0         0 @terms = sort {lc($a)cmp lc($b)} @{$obj->{$obj->{baselang}}{$term}{$rel}};
      0         0  
      0         0  
    939 0         0 $html.= ul(li([map {
    940 0 0       0 _thesaurusGetHTMLTerm($_, $obj, $script, $language,
    941             $second_level_limit, $hide_on_second_level);
    942             } @terms])) if (@terms);
    943             }
    944             }
    945 0         0 return $html;
    946             }
    947              
    948             ###
    949             #
    950             #
    951             sub toTex{
    952 0     0 1 0 my $self = shift;
    953 0   0     0 my $_corres = shift || {};
    954 0   0     0 my $mydt = shift || {};
    955             # my $a;
    956              
    957 0         0 my %descs = %{$self->{descriptions}};
      0         0  
    958              
    959             my $procgr= sub {
    960 0     0   0 my $r="";# my $a;
    961 0   0     0 my $auxrel = $descs{$rel} || $rel;
    962 0         0 $auxrel =~ s/_/ /g;
    963 0         0 $auxrel = ucfirst(lc($auxrel));
    964 0   0     0 my $ki = $_corres->{$rel}->[0] || "\\\\\\emph{$auxrel} -- " ;
    965 0   0     0 my $kf = $_corres->{$rel}->[1] || "\n";
    966 0         0 $r = "\\item[$ki]" .
    967 0 0       0 join(' $\diamondsuit$ ',(sort {lc($a) cmp lc($b)} @terms)) if @terms;
    968 0         0 };
    969              
    970 0     0   0 $self->downtr(
    971             { '-default' => $procgr,
    972             '-end' => sub{s/_/\\_/g;
    973 0         0 "\\begin{description}\n$_\\end{description}\n"},
    974 0     0   0 '-eachTerm' =>
    975             sub{"\n\\item[$term]~\\begin{description}\n$_\\end{description}\n"},
    976 0 0       0 (defined $self->{order}?(-order => $self->{order}):()),
    977             (%$mydt) }
    978             );
    979             }
    980              
    981             sub toXml{
    982 0     0 1 0 my $self = shift;
    983 0   0     0 my $_corres = shift || {};
    984 0   0     0 my $mydt = shift || {};
    985 0         0 my $a;
    986              
    987             my $proc= sub {
    988 0     0   0 my $r=""; my $a;
      0         0  
    989 0   0     0 my $ki = $_corres->{$rel}->[0] || "$rel" ;
    990 0   0     0 my $kf = $_corres->{$rel}->[1] || "/$rel";
    991 0         0 for $a (@terms){ $r .= " <$ki>$a<$kf>\n";};
      0         0  
    992 0         0 $r;
    993 0         0 };
    994              
    995 0     0   0 $self->downtr({
    996             '-default' => $proc,
    997             '-eachTerm' =>
    998             sub{" \n <$self->{baselang}>$term{baselang}>\n$_ \n"},
    999 0     0   0 '-end' => sub{"\n$_\n"},
    1000 0         0 (%$mydt)
    1001             });
    1002             }
    1003              
    1004             ###
    1005             #
    1006             #
    1007             sub dumpHTML {
    1008 0     0 1 0 my $obj = shift;
    1009 0         0 my %thesaurus = %{$obj->{$obj->{baselang}}};
      0         0  
    1010 0         0 my $t = "";
    1011 0         0 for (keys %thesaurus) {
    1012 0         0 $t.=_thesaurusGetHTMLTerm($_,$obj,"",$obj->{baselang});
    1013             }
    1014 0         0 return $t;
    1015             }
    1016              
    1017             ###
    1018             #
    1019             #
    1020             sub relations {
    1021 1     1 1 3 my ($self,$term) = @_;
    1022              
    1023 1         2 return sort grep { $_ !~ /^_/ } keys %{$self->{$self->{baselang}}->{$term}}
      2         10  
      1         6  
    1024             }
    1025              
    1026              
    1027             ###
    1028             #
    1029             # Given a term, return it's information (second level for navigate)
    1030             sub _thesaurusGetHTMLTerm {
    1031 0     0   0 my ($term,$obj,$script,$language,$limit,$hide) = @_;
    1032              
    1033 0 0       0 my @rels2hide = map {uc} (defined($hide))?@$hide:();
      0         0  
    1034 0         0 my %rels2hide;
    1035 0         0 @rels2hide{@rels2hide}=1;
    1036              
    1037             # Put thesaurus and descriptions on handy variables
    1038 0         0 my %thesaurus = %{$obj->{$obj->{baselang}}};
      0         0  
    1039 0         0 my %descs = %{$obj->{descriptions}};
      0         0  
    1040              
    1041             # Check if the term exists in the thesaurus
    1042 0 0       0 if ($obj->isDefined($term)) {
    1043 0         0 $term = $obj->{defined}{lc($term)};
    1044 0         0 my ($c,$t,$tterm);
    1045 0         0 my $link = $term;
    1046              
    1047 0         0 $link =~ s/\s/+/g;
    1048 0         0 $tterm = $obj->_translateTerm($term,$language);
    1049 0         0 $t = b(a({href=>"$script?t=$link"},$tterm)). br . "
    \n";
    1050              
    1051 0         0 for $c (sort keys %{$thesaurus{$term}}) {
      0         0  
    1052 0         0 $c = uc($c);
    1053 0 0       0 next if exists($rels2hide{$c});
    1054             # jump if it is the name relation :)
    1055 0 0       0 next if ($c eq "_NAME_");
    1056              
    1057 0 0       0 if (exists($obj->{externals}{$c})) {
        0          
    1058             # put an external relation
    1059 0         0 my $desc = $obj->getDescription($c,$language);
    1060 0 0       0 if ($desc eq "...") {
    1061 0         0 $t .= join("
    \n", map { div($_) } @{$thesaurus{$term}{$c}});
      0         0  
      0         0  
    1062             } else {
    1063 0         0 $t .= join("
    \n", map { b($desc)." $_" } @{$thesaurus{$term}{$c}});
      0         0  
      0         0  
    1064             }
    1065             } elsif (exists($obj->{languages}{$c})) {
    1066             # Jump the language relations
    1067             } else {
    1068 0         0 my $desc = $obj->getDescription($c,$language);
    1069 0 0       0 if ($desc eq "...") {
    1070 0         0 $t.= b($c)." ";
    1071             } else {
    1072 0         0 $t.= b($desc)." ";
    1073             }
    1074 0         0 my @termos = sort {lc($a)cmp lc($b)} ( @{$thesaurus{$term}{$c}} );
      0         0  
      0         0  
    1075 0 0 0     0 if (defined($limit) && $limit!=0 && @termos > $limit) {
          0        
    1076 0         0 while(@termos > $limit) { pop @termos; }
      0         0  
    1077 0         0 push @termos, "...";
    1078             }
    1079 0 0       0 if (defined($script)) {
    1080 0         0 @termos = map {my $link = $_;
      0         0  
    1081 0 0       0 if ($link eq "...") {
    1082 0         0 $link
    1083             } else {
    1084 0   0     0 $_ = $obj->_translateTerm($_,$language) || $_;
    1085 0         0 $link =~s/\s/+/g;
    1086 0         0 a({href=>"$script?t=$link"},$_)
    1087             }
    1088             } @termos;
    1089             }
    1090 0         0 $t.= join(", ", @termos) . br."\n";
    1091             }
    1092             }
    1093 0         0 $t.= "\n";
    1094 0         0 return $t;
    1095             } else {
    1096 0         0 print STDERR "Can't find term '$term'\n";
    1097 0         0 return qq/Term $term is not defined\n/;
    1098             }
    1099             }
    1100              
    1101 11     11 1 1096 sub getdefinition { getDefinition(@_) }
    1102             sub getDefinition {
    1103 11     11 1 12 my $self = shift;
    1104 11         25 my $term = _term_normalize(lc(shift));
    1105 11 50       23 if ($self->isDefined($term)) {
    1106 11         37 return $self->{defined}{$term};
    1107             } else {
    1108 0         0 return $term;
    1109             }
    1110             }
    1111              
    1112             ###
    1113             #
    1114             #
    1115             sub isDefined {
    1116 101063     101063 1 675616 my $obj = shift;
    1117 101063         208592 my $term = _term_normalize(lc(shift));
    1118 101063         386861 return defined($obj->{defined}{$term});
    1119             }
    1120              
    1121             ###
    1122             #
    1123             #
    1124             sub _definition {
    1125 267     267   362 my ($self,$term) = @_;
    1126 267         643 return $self->{defined}{_term_normalize(lc($term))};
    1127             }
    1128              
    1129             ###
    1130             #
    1131             #
    1132             sub complete {
    1133 12     12 1 21 my $obj = shift;
    1134 12         83 my $thesaurus = $obj->{$obj->{baselang}};
    1135 12         25 my %inverses = %{$obj->{inverses}};
      12         106  
    1136 12         30 my ($termo,$classe);
    1137              
    1138             # para cada termo
    1139 12         58 for $termo (keys %$thesaurus) {
    1140             # $obj->{defined}{lc($termo)} = $termo;
    1141             # e para cada classe,
    1142 164         172 for $classe (keys %{$thesaurus->{$termo}}) {
      164         560  
    1143             # verificar se existem duplicados...
    1144 429 100       1210 if (ref($thesaurus->{$termo}{$classe}) eq "ARRAY") {
    1145 260         258 my %h;
    1146 260         267 @h{@{$thesaurus->{$termo}{$classe}}} = @{$thesaurus->{$termo}{$classe}};
      260         1236  
      260         450  
    1147 260         838 $thesaurus->{$termo}{$classe} = [ keys %h ];
    1148              
    1149             # se tiver inverso,
    1150 260 100       785 if (defined($inverses{$classe})) {
    1151             # completar cada um dos termos relacionados
    1152 233         238 for (@{$thesaurus->{$termo}{$classe}}) {
      233         560  
    1153             # %thesaurus = _completa($obj,$_,$inverses{$classe},$termo,%thesaurus);
    1154 556         1108 _completa($obj,$_,$inverses{$classe},$termo,$thesaurus);
    1155             }
    1156             }
    1157             }
    1158             }
    1159             }
    1160              
    1161 12         44 $obj -> {$obj->{baselang}} = $thesaurus;
    1162              
    1163 12         75 return $obj;
    1164             }
    1165              
    1166             ###
    1167             #
    1168             #
    1169             sub _completa {
    1170             ## Yeah, obj and thesaurus can be redundanct, but it's better this way...
    1171 556     556   927 my ($obj,$palavra,$classe,$termo,$thesaurus) = @_;
    1172 556         519 my $t;
    1173              
    1174             # Ver se existe a palavra e a classe no thesaurus
    1175 556 100       1015 if ($obj->isDefined($palavra)) {
    1176 286         675 $t = $obj->{defined}{lc($palavra)};
    1177 286 100       684 if (defined($thesaurus->{$t}{$classe})) {
    1178             # se existe, o array palavras fica com os termos (para ver se ja' existe)
    1179 121         173 my @palavras = @{$thesaurus->{$t}{$classe}};
      121         363  
    1180             # ver se ja' existe
    1181 121         196 for (@palavras) {
    1182 288 100       1000 return $thesaurus if (lc eq lc($termo));
    1183             }
    1184             }
    1185             # nao existe: aumentar
    1186 192         207 push @{$thesaurus->{$t}{$classe}}, $obj->{defined}{lc($termo)};
      192         783  
    1187             } else {
    1188             # nao existe: aumentar
    1189 270 50 33     1095 $thesaurus->{$palavra}{_NAME_} = $palavra unless
    1190             defined($thesaurus->{$palavra}) && defined($thesaurus->{$palavra}{_NAME_});
    1191 270         586 $obj->{defined}{lc($palavra)} = $palavra;
    1192 270         293 push @{$thesaurus->{$palavra}{$classe}}, $obj->{defined}{lc($termo)};
      270         876  
    1193             }
    1194 462         1402 return $thesaurus;
    1195             }
    1196              
    1197             ###
    1198             #
    1199             #
    1200             sub addTerm {
    1201 100011     100011 1 660883 my $obj = shift;
    1202 100011         194317 my $term = _term_normalize(shift);
    1203              
    1204 100011         653927 $obj->{$obj->{baselang}}{$term}{_NAME_} = $term;
    1205 100011         419556 $obj->{defined}{lc($term)} = $term;
    1206             }
    1207              
    1208             sub hasRelation {
    1209 15     15 1 784 my ($obj, $term, $rel, $rterm) = @_;
    1210 15         27 $rel = uc($rel);
    1211              
    1212 15 50       30 return 0 unless $obj->isDefined($term); # Check if term exists
    1213 15         36 $term = $obj->_definition($term);
    1214              
    1215 15         22 my $has = 0;
    1216 15 100       29 if ($rterm) {
    1217 13 50       33 if (exists($obj->{externals}{$rel})) {
    1218 0 0       0 $has = 1 if (grep { $_ eq $rterm } @{$obj->{$obj->{baselang}}{$term}{$rel}});
      0         0  
      0         0  
    1219             } else {
    1220 13         20 $rterm = _term_normalize($rterm);
    1221 13 100       15 $has = 1 if (grep { $_ eq $rterm} @{$obj->{$obj->{baselang}}{$term}{$rel}});
      22         51  
      13         50  
    1222             }
    1223             } else {
    1224 2 100       9 $has = 1 if exists($obj->{$obj->{baselang}}{$term}{$rel});
    1225             }
    1226 15         70 return $has;
    1227             }
    1228              
    1229             ###
    1230             #
    1231             #
    1232             sub addRelation {
    1233 4     4 1 1355 my ($obj, $term, $rel, @terms) = @_;
    1234 4         7 $rel = uc($rel);
    1235              
    1236 4 50       19 $obj->{descriptions}{$rel} = "..."
    1237             unless defined($obj->{descriptions}{$rel});
    1238              
    1239 4 50       9 unless ($obj->isDefined($term)) {
    1240 0         0 $obj->{defined}{lc(_term_normalize($term))} = _term_normalize($term);
    1241             }
    1242              
    1243 4         11 $term = $obj->_definition($term);
    1244              
    1245 4 100       15 if (exists($obj->{externals}{$rel})) {
    1246 1         4 push @{$obj->{$obj->{baselang}}{$term}{$rel}}, @terms;
      1         6  
    1247              
    1248             } else {
    1249 3         12 push @{$obj->{$obj->{baselang}}{$term}{$rel}},
      7         10  
    1250 3         3 map {_term_normalize($_)} @terms;
    1251 3         6 for (@terms) {
    1252 7 50       22 $obj->addTerm($_) unless $obj->isDefined($_);
    1253             }
    1254             }
    1255              
    1256             }
    1257              
    1258             ###
    1259             #
    1260             #
    1261             sub deleteRelation {
    1262 6     6 1 835 my ($self, $term, $rel, @terms) = @_;
    1263 6         13 $rel = uc($rel);
    1264              
    1265 6 100       15 if (@terms) {
    1266 3         6 for my $oterm (@terms) {
    1267 4         13 $self->_deleteRelation($term, $rel, $oterm);
    1268             ## Se existe inversa, do the same shit
    1269 4 50       16 if (exists $self->{inverses}{$rel}) {
    1270 4         11 $self->_deleteRelation($oterm, $self->{inverses}{$rel}, $term);
    1271             }
    1272             }
    1273             } else {
    1274 3 100       12 if (exists($self->{externals}{$rel})) {
    1275 1         4 $self->_deleteRelation($term, $rel);
    1276             } else {
    1277 2         20 @terms = $self->terms($term,$rel);
    1278 2 100       7 return unless @terms;
    1279 1         6 $self->deleteRelation($term, $rel, @terms);
    1280             }
    1281             }
    1282             }
    1283              
    1284             ###
    1285             #
    1286             #
    1287             sub _deleteRelation {
    1288 9     9   20 my ($obj, $term, $rel, $oterm) = @_;
    1289              
    1290             # return if the term is not defined
    1291 9 50       19 return unless $obj->isDefined($term);
    1292              
    1293 9         22 $term = $obj->_definition($term);
    1294 9 100       23 if ($oterm) {
    1295             # if we have a full relation (term,rel,term), then it is not an external relation
    1296 8 50       26 return if exists($obj->{externals}{$rel});
    1297            
    1298 8         24 $oterm = _term_normalize($oterm);
    1299 8         11 $obj->{$obj->{baselang}}{$term}{$rel} = [ grep { $_ ne $oterm } @{$obj->{$obj->{baselang}}{$term}{$rel}}];
      11         43  
      8         33  
    1300             } else {
    1301 1         6 delete($obj->{$obj->{baselang}}{$term}{$rel});
    1302             }
    1303             }
    1304              
    1305             ###
    1306             #
    1307             #
    1308             sub deleteTerm {
    1309 1     1 1 2 my $obj = shift;
    1310 1         5 my $term = _term_normalize(shift);
    1311 1         2 my $t2=$term;
    1312 1         4 $term = $obj->_definition($term);
    1313 1         2 my ($t,$c);
    1314              
    1315 1 50 0     28 warn("'$t2' => '$term'\n") && return unless defined($term);
    1316              
    1317 1 50       5 if (defined($obj->{$obj->{baselang}}{$term})){
      0         0  
    1318 1         4 delete($obj->{$obj->{baselang}}{$term});
    1319 1         4 delete($obj->{defined}{lc($term)});
    1320             }
    1321             else {warn ("'$term' not found...\n");}
    1322              
    1323 1         1 foreach $t (keys %{$obj->{$obj->{baselang}}}) {
      1         5  
    1324 1         1 foreach $c (keys %{$obj->{$obj->{baselang}}{$t}}) {
      1         4  
    1325 1         3 my @a = ();
    1326 1 50       8 if ( ref($obj->{$obj->{baselang}}{$t}{$c}) eq "ARRAY") {
    1327 0         0 foreach (@{$obj->{$obj->{baselang}}{$t}{$c}}) {
      0         0  
    1328 0 0       0 push(@a,$_) unless($_ eq $term);
    1329             }
    1330 0         0 $obj->{$obj->{baselang}}{$t}{$c}=\@a;
    1331             }
    1332             }
    1333             }
    1334             }
    1335              
    1336             ###
    1337             #
    1338             #
    1339             sub downtr {
    1340 0     0 1 0 my $self = shift;
    1341 0         0 my $handler = shift;
    1342 0 0       0 die("bad use of downtr method; args should be: hashRef, termlist")
    1343             unless(ref($handler) eq "HASH");
    1344 0         0 my @tl = @_ ; #lc(shift);
    1345 0         0 @tl = (sort
    1346 0         0 {lc($a) cmp lc($b)}
    1347 0 0       0 keys %{$self->{$self->{baselang}}}) unless (@tl);
    1348 0         0 my $r2 = ""; #final result
    1349 0         0 my $c;
    1350 0         0 for my $t (@tl){
    1351 0         0 my $r = "";
    1352 0         0 $term = $t;
    1353 0 0       0 if (defined( $handler->{"_NAME_"})){
    1354 0         0 $r .= &{$handler->{"_NAME_"}};
      0         0  
    1355             }
    1356              
    1357 0         0 my @rels = (keys %{$self->{$self->{baselang}}->{$t}});
      0         0  
    1358 0         0 my %rels = ();
    1359 0         0 @rels{@rels} = @rels;
    1360 0 0       0 my $order = defined $handler->{-order} ? $handler->{-order} :
        0          
    1361             ( defined $self->{order} ? $self->{order} : []);
    1362 0         0 delete(@rels{@$order});
    1363 0         0 @rels = ( @{$order}, (sort keys(%rels) ));
      0         0  
    1364              
    1365 0         0 for $c (@rels) {
    1366 0 0       0 next unless $self->{$self->{baselang}}{$t}{$c};
    1367 0 0       0 next if ($c eq "_NAME_");
    1368              
    1369             # Set environment variables to downtr function
    1370             #
    1371             # rel...
    1372             #
    1373 0         0 $rel = $c;
    1374             #
    1375             # List of terms...
    1376             #
    1377 0 0       0 if ($self->{languages}->{$rel}) {
    1378 0         0 @terms = ( $self->{$self->{baselang}}{$t}{$rel} );
    1379             } else {
    1380 0         0 @terms = @{$self->{$self->{baselang}}{$t}{$rel}};
      0         0  
    1381             }
    1382              
    1383             #
    1384             # Current term...
    1385             #
    1386 0         0 $term = $t;
    1387              
    1388 0 0       0 if (exists($handler->{$rel})) {
        0          
    1389 0   0     0 $r .= &{$handler->{$rel}} // "";
      0         0  
    1390             } elsif (exists($handler->{-default})) {
    1391 0   0     0 $r .= &{$handler->{-default}} // "";
      0         0  
    1392             } else {
    1393 0         0 $r .= "\n$rel\t".join(", ",@terms);
    1394             }
    1395             }
    1396 0         0 for($r){
    1397 0 0       0 if (exists($handler->{'-eachTerm'})) {
    1398 0         0 my $ans = &{$handler->{'-eachTerm'}};
      0         0  
    1399 0 0       0 $r2 .= ($ans)?$ans:"";
    1400             } else {
    1401 0         0 $r2 .= $_;
    1402             }
    1403             }
    1404             }
    1405 0 0       0 if (defined($handler->{-end})) {
    1406 0         0 for($r2){
    1407 0         0 $_ = &{$handler->{'-end'}}
      0         0  
    1408             }
    1409             }
    1410 0         0 $r2;
    1411             }
    1412              
    1413             ###
    1414             #
    1415             #
    1416             sub tc{
    1417 1     1 1 11 my ($self,$term,@relations) = @_;
    1418 1         6 my %x = _tc_aux($self, $term, {}, @relations);
    1419 1         11 return (keys %x);
    1420             }
    1421              
    1422              
    1423             ###
    1424             #
    1425             #
    1426             sub toHash {
    1427 1     1 1 16 my ($self, $rel) = @_;
    1428 1   50     3 $rel //= "NT";
    1429 1 50       12 $rel = [$rel] unless ref($rel);
    1430 1         6 my $top = $self->topName;
    1431 1         7 return +{ $top => $self->_toHash($top, $rel, [$top]) };
    1432             }
    1433              
    1434             sub _toHash {
    1435 4     4   7 my ($self, $term, $rel, $stack) = @_;
    1436 4         12 my $h = $self->depth_first($term, 1, @$rel);
    1437 4 100       12 if (keys %$h) {
    1438 1         3 for (keys %$h) {
    1439 3         13 $h->{$_} = $self->_toHash($_, $rel, [@$stack, $_]);
    1440             }
    1441             } else {
    1442 3         7 $h = join("::", @$stack);
    1443             }
    1444 4         17 return $h;
    1445             }
    1446              
    1447             ##
    1448             #
    1449             #
    1450             sub toJson {
    1451 0     0 1 0 my ($self, $rel) = @_;
    1452 0   0     0 $rel //= "NT";
    1453 0 0       0 $rel = [$rel] unless ref($rel);
    1454 0         0 my $top = $self->topName;
    1455 0         0 $self->_toJson($top, $rel);
    1456             }
    1457              
    1458             sub _toJson {
    1459 0     0   0 my ($self, $term, $rel) = @_;
    1460 0         0 my $h = $self->depth_first($term, 1, @$rel);
    1461 0         0 my $json = "{ \"data\": \"$term\", \"attr\":{id:\"$term\"}";
    1462 0 0       0 if (keys %$h) {
    1463 0         0 $json .= ", \"children\": [";
    1464 0         0 $json .= join(", ", map { $self->_toJson($_, $rel) } keys %$h);
      0         0  
    1465 0         0 $json .= "]"
    1466             }
    1467 0         0 $json .= "}";
    1468             }
    1469              
    1470             ###
    1471             #
    1472             #
    1473             sub _tc_aux {
    1474 10     10   16 my ($self,$term,$vis,@relat) = @_;
    1475 10         24 $term = $self->getdefinition($term);
    1476 10         21 my %r = ( $term => 1 );
    1477 10         24 for ($self->terms($term,@relat)) {
    1478 9 50       20 next if exists $vis->{$_};
    1479 9         14 $vis->{$_}++;
    1480 9 50       40 %r = (%r, $_ => 1, _tc_aux($self,$_,@relat)) unless $r{$_};
    1481             }
    1482 10         78 return %r;
    1483             }
    1484              
    1485             ###
    1486             #
    1487             #
    1488             sub _term_normalize {
    1489 202015     202015   238051 my $t = shift;
    1490 202015         1126942 $t =~ s/^\s*(.*?)\s*$/$1/;
    1491 202015         344821 $t =~ s/\s\s+/ /g;
    1492 202015         404054 return $t;
    1493             }
    1494              
    1495             sub capitalize {
    1496 0     0 1 0 my $op = shift;
    1497 0         0 my $text = shift;
    1498 0 0       0 if ($op) {
    1499 0         0 $text = join(" ",map {ucfirst} split /\s+/, $text);
      0         0  
    1500             }
    1501 0         0 return $text;
    1502             }
    1503              
    1504             # remove duplicados de uma lista
    1505             sub _set_of {
    1506 8     8   15 my %set = ();
    1507 8         51 $set{$_} = 1 for @_;
    1508 8         46 return keys %set;
    1509             }
    1510              
    1511             1;
    1512             __END__