File Coverage

blib/lib/Games/SGF/Util.pm
Criterion Covered Total %
statement 69 72 95.8
branch 23 24 95.8
condition 4 6 66.6
subroutine 10 10 100.0
pod 5 5 100.0
total 111 117 94.8


line stmt bran cond sub pod time code
1             package Games::SGF::Util;
2              
3 2     2   7553 use warnings;
  2         5  
  2         76  
4 2     2   13 use strict;
  2         4  
  2         73  
5 2     2   12 use Games::SGF;
  2         6  
  2         50  
6 2     2   10 no warnings 'redefine';
  2         4  
  2         1432  
7              
8             =head1 NAME
9              
10             Games::SGF::Util - Utility pack for Games::SGF objects
11              
12             =head1 VERSION
13              
14             Version 0.993
15              
16             =cut
17              
18             our $VERSION = 0.993;
19              
20              
21             =head1 SYNOPSIS
22              
23             Quick summary of what the module does.
24              
25             Perhaps a little code snippet.
26              
27             use Games::SGF::Util;
28              
29             my $util = new Games::SGF::Util($sgf);
30            
31             $util->filter( "C", undef ); # removes all comments from SGF
32              
33             =head1 DISCRIPTION
34              
35             This is a collection of useful methods for manipulating a Games::SGF object.
36              
37             All Util methods in this module will not call any game movement methods. This
38             means in order to work with files with multiple games you must move to the
39             game of choice then pass it into a util object.
40              
41             =head1 METHODS
42              
43             =head2 new
44              
45             $util = new Games::SGF::Util($sgf);
46              
47             This initializes a new Games::SGF::Util object. Will return C if C<$sgf>
48             is no supplied.
49              
50             =cut
51              
52             sub new {
53 3     3 1 3032 my $inv = shift;
54 3   33     18 my $class = ref $inv || $inv;
55 3         5 my $sgf = shift;
56 3 100       8 if($sgf) {
57             # $sgf = $sgf->clone(); # So we are not working with the actual sgf file
58             } else {
59 1         4 return undef;
60             }
61 2         8 return bless \$sgf, $class;
62             }
63              
64             =head2 touch
65              
66             $util->touch(\&sub);
67              
68             This will call C<&sub> for every node in $sgf. C<&sub> will be passed the
69             C<$sgf> object. any subroutines which manipulate the C<$sgf> tree will lead
70             to undefined behavior. The safe methods to use are:
71              
72             =over
73              
74             =item L
75              
76             =item L
77              
78             =item L
79              
80             =item L
81              
82             =item L
83              
84             =item L
85              
86             =item L
87              
88             =item L
89              
90             =item L
91              
92             =item L
93              
94             =item L
95              
96             =item L
97              
98             =back
99              
100             =cut
101              
102             sub touch {
103 3     3 1 5 my $self = shift;
104 3         10 my $callback = shift;
105 3         4 my $sgf = $$self;
106 3         8 my( @branches ) = (-1); # Stores the branch stack
107 3         9 $sgf->gotoRoot;
108             {
109 3         5 my $last = pop @branches;
  21         25  
110 21 100       41 &$callback($sgf) if $last == -1; # callback on current node
111              
112 21 100 100     50 if( $last < $sgf->branches and $sgf->gotoBranch(++$last)) {
    100          
113 12         17 push @branches, $last,-1;
114             } elsif(@branches > 0 ) {
115 6         15 $sgf->prev;
116 6         8 pop @branches;
117             } else {
118 3         8 last;
119             }
120 18         23 redo;
121             }
122             }
123              
124             =head2 filter
125              
126             $util->fiter( $tag, \&sub);
127              
128             Will call C<&sub> for every $tag which is in C<$sgf>. C<&sub> will be passed
129             the tag value. The value then be reset to the return of C<&sub>. If the return
130             is "" the tag will be unset.
131              
132             If the tag has a value list each value will be sent to $callback.
133              
134             If the $callback returns undef it will not be set.
135              
136             Example:
137              
138             # removes all comments that don't match m/Keep/
139             $util->filter( "C", sub { return $_[0] =~ m/Keep/ ? $_[0] : ""; );
140              
141             =cut
142              
143             sub filter {
144 3     3 1 352 my $self = shift;
145 3         4 my $tag = shift;
146 3         3 my $callback = shift;
147              
148             return $self->touch(
149             sub {
150 15     15   16 my $sgf = shift;
151 15         38 my $values = $sgf->property($tag);
152 15         22 my @set;
153 15 100       77 if( $values ) {
154 11 100       21 if( $callback ) {
155 8         17 foreach( @$values ) {
156 8         17 my $ret = &$callback($_);
157 8 100       49 if( defined $ret ) {
158 7         17 push @set, $ret
159             }
160             }
161             } # else unset tag
162 11         34 $sgf->setProperty($tag,@set);
163             }
164             }
165 3         19 );
166             }
167              
168             =head2 gameInfo
169              
170             my(@games) = $util->gameInfo;
171             foreach my $game (@games) {
172             print "New Game\n";
173             foreach my $tag (keys %$game) {
174             print "\t$tag -> $game->{$tag}\n";
175             }
176             }
177              
178             Will return the game-info tags for all games represented in the current
179             game tree. The return order is the closest to the root, and then the closest
180             to the main line branch.
181              
182             UNWRITTEN
183              
184             =cut
185              
186             sub gameInfo {
187 1     1 1 4 my $self = shift;
188 1         2 my $isRec = shift; # set if a recursive call
189 1         5 my $sgf = $$self;
190 1         1 my( @games );
191             # if this is first run
192 1 50       31 $sgf->gotoRoot unless $isRec;
193            
194             # touch all nodes in this branch
195             {
196             # check for games and add to @games
197 1         1 my(@tags) = $sgf->property;
  3         48  
198 3         6 my $game = {};
199 3         4 foreach my $t (@tags) {
200 7 100       25 if( $sgf->getTagType($t) & $sgf->T_GAME_INFO ) {
201 1         4 $game->{$t} = $sgf->getProperty($t);
202             }
203             }
204 3 100       9 if( keys %$game ) {
205 1         2 $games[@games] = $game;
206             }
207 3 100       8 redo if $sgf->next;
208             }
209              
210             # touch all variations
211 1         4 for( my $i = 0; $i < $sgf->branches; $i++ ) {
212             #add game info of branch onto our list
213 0         0 $sgf->gotoBranch($i);
214 0         0 push @games, $self->gameInfo( 1 );
215 0         0 $sgf->gotoParent;
216             }
217 1         4 return @games;
218             }
219              
220             =head2 sgf
221              
222             $sgf = $util->sgf;
223             $sgf = $util->sgf($sgf)
224              
225             This returns a clone of the C<$sgf> object associated with C<$util>, or sets the
226             C<$sgf> object to a clone of object supplied.
227              
228             =cut
229              
230             sub sgf {
231 5     5 1 16 my $self = shift;
232 5         7 my $sgf = shift;
233 5 100       133 if($sgf) {
234 1         3 $$self = $sgf;#->clone();
235 1         4 return $sgf;
236             }
237 4         7 $sgf = $$self;
238 4         25 return $sgf;#->clone();
239             }
240             1;
241             __END__