File Coverage

blib/lib/Lego/Ldraw.pm
Criterion Covered Total %
statement 24 161 14.9
branch 0 34 0.0
condition 0 7 0.0
subroutine 8 30 26.6
pod 19 20 95.0
total 51 252 20.2


line stmt bran cond sub pod time code
1             package Lego::Ldraw;
2            
3 1     1   60440 use 5.008004;
  1         4  
  1         38  
4 1     1   5 use strict;
  1         1  
  1         31  
5 1     1   5 use warnings; no warnings qw/uninitialized/;
  1     1   7  
  1         38  
  1         6  
  1         1  
  1         43  
6            
7 1     1   4 use Carp;
  1         2  
  1         286  
8 1     1   2328 use Lego::Ldraw::Line;
  1         4  
  1         43  
9            
10 1     1   7 use File::Basename;
  1         2  
  1         104  
11            
12             use overload
13 1         11 '@{}' => \&lines,
14 1     1   7 '""' => \&stringify;
  1         2  
15            
16            
17            
18             our $VERSION = "0.5.8";
19            
20             sub new {
21 0     0 1   my $proto = shift;
22 0   0       my $class = ref($proto) || $proto;
23 0           my $self = {};
24            
25 0           $self->{lines} = [];
26 0           $self->{file} = undef;
27 0           $self->{name} = undef;
28 0           $self->{description} = undef;
29 0           $self->{dir} = undef;
30            
31 0           bless ($self, $class);
32 0           return $self;
33             }
34            
35             sub DESTROY {
36 0     0     my $self = shift;
37 0           $_->{model} = undef for @{$self->lines};
  0            
38 0           $self = undef;
39             }
40            
41             sub new_from_file {
42 0     0 1   my $self = shift->new;
43 0   0       my $file = shift || \*STDIN;
44            
45 0 0         unless (ref $file eq 'GLOB') {
46 0 0         croak "Error $? opening $file" unless -e $file;
47 0 0         open LDRAW, $file or croak "Error $? opening $file";
48 0           $self->{file} = $file;
49 0           $self->{name} = basename($file);
50 0           $self->{dir} = dirname($file);
51 0           $file = \*LDRAW;
52             }
53            
54 0           while (<$file>) {
55 0           chomp;
56 0 0         unless (/^\s*$/) {
57 0           my $line = Lego::Ldraw::Line->new_from_string($_);
58 0 0         $self->{description} = $line->command unless $.;
59 0           $self->add($line);
60             }
61             }
62 0 0         close $file unless ref $file;
63 0           return $self;
64             }
65            
66             sub copy {
67 0     0 1   my $self = shift;
68 0           my $copy = Lego::Ldraw->new;
69            
70 0           $copy->{file} = $self->{file};
71 0           $copy->{name} = $self->{name};
72 0           $copy->{dir} = $self->{dir};
73            
74 0           for (@$self) {
75 0           my $line = Lego::Ldraw::Line->new_from_string("$_");
76 0           $copy->add($line);
77             }
78 0           return $copy;
79             }
80            
81             sub add {
82 0     0 1   my $self = shift;
83 0           my $line = shift;
84 0           my $pos = shift;
85            
86 0 0         $pos = 0 unless @{$self->{lines}};
  0            
87            
88 0 0         if ($pos) {
89 0           splice @{$self->{lines}}, $pos, 0, $line;
  0            
90             } else {
91 0           push @{$self->{lines}}, $line;
  0            
92             }
93 0           $self->{tree}->{$line->part}->{$line->color}++;
94 0           $line->dir($self->dir);
95             }
96            
97             sub splice {
98 0     0 1   my $self = shift;
99 0           my ($what, $offset, $length) = @_;
100            
101 0           for (ref $what) {
102 0 0         /^Lego::Ldraw::Line$/ && do {
103 0           splice @{$self->{lines}}, $offset, $length, $what;
  0            
104 0           last;
105             };
106 0 0         /^Lego::Ldraw$/ && do {
107 0           splice @{$self->{lines}}, $offset, $length, @{$what->{lines}};
  0            
  0            
108 0           last;
109             };
110             }
111             }
112            
113             sub lines {
114 0     0 1   my $self = shift;
115 0 0         return wantarray ? @{$self->{lines}} : $self->{lines};
  0            
116             }
117            
118             sub stringify {
119 0     0 1   my $self = shift;
120 0           return join "\n", @{$self};
  0            
121             }
122            
123             sub length {
124 0     0 1   my $self = shift;
125 0           return scalar @{$self->{lines}};
  0            
126             }
127            
128             sub subparts {
129 0     0 1   my $self = shift;
130 0           return grep { $_->type == 1 } @{ $self };
  0            
  0            
131             }
132            
133             sub colors {
134 0     0 1   my $self = shift;
135 0           my %colors;
136 0           for ($self->lines) {
137 0 0         next unless my $c = $_->color;
138 0           $colors{$c}++;
139             }
140 0           return sort keys %colors;
141             }
142            
143             ###################################################
144             # quick fixes for file, name, tree
145             ###################################################
146            
147             sub file {
148 0     0 1   return shift->{file};
149             }
150            
151             sub name {
152 0     0 1   return shift->{name};
153             }
154            
155             sub tree {
156 0     0 1   return shift->{tree}
157             }
158            
159             sub parts {
160 0     0 1   return sort keys %{ shift->{tree} };
  0            
161             }
162            
163             sub dir {
164 0     0 1   return shift->{dir}
165             }
166            
167             sub description {
168 0     0 1   my $self = shift;
169 0 0         $self->{description} = shift if @_;
170 0           return $self->{description}
171             }
172            
173             sub partsdirs {
174 0     0 1   return Lego::Ldraw::Line->partsdirs;
175             }
176            
177             sub basedir {
178 0     0 1   return Lego::Ldraw::Line->basedir;
179             }
180            
181            
182             ##################################################
183             # experimental part: build tree with callback
184             ##################################################
185            
186             sub Lego::Ldraw::build_tree {
187 0     0 1   my $ldraw = shift;
188 0           my $callback = shift;
189 0           my $test = shift;
190            
191 0           my $b; # part tree: $d->{$part}->{$subpart} means $subpart is used in $part;
192             my $d; # reverse part tree: $d->{$subpart}->{$part} means $subpart is used in $part;
193 0           my $s; # recursed parts list. Value is 1 if list is ready to be built for subpart
194            
195 0           $ldraw->recurse_part_tree(\$b, \$d, \$s, $test);
196            
197             # while there are parts ready for list building
198 0           while (my @l = grep { $d->{$_} } keys %{$s}) {
  0            
  0            
199 0           for my $p (@l) {
200             # if part has no subparts
201 0 0         if ($s->{$p}) {
202             # build a list for the part
203 0           print STDERR "traversing tree for $p";
204             # Lego::Ldraw::Display->build_list($p);
205 0           &{$callback}($p);
  0            
206             # delete part from list of parts that need building lists
207             # delete $s->{$p}; # = 0;
208             # set parts that use it as ready for list building
209 0           my @r = keys %{$d->{$p}}; # all parts that use this subpart
  0            
210 0           for (@r) {
211 0           delete $b->{$_}->{$p}; # delete subpart from part tree
212 0 0         $s->{$_} = 1 unless keys %{$b->{$_}} # is there are no subparts list can be built
  0            
213             }
214             # delete part reverse tree
215 0           delete $d->{$p};
216             }
217             }
218             }
219 0           my $t;
220 0           $b = undef;
221 0           $d = undef;
222 0           $s = undef;
223             }
224            
225             sub Lego::Ldraw::recurse_part_tree {
226 0     0 0   my $tree = shift->copy;
227 0           my ($b, $d, $s, $test) = @_;
228 0   0 0     $test = $test || sub { shift->type == 1 };
  0            
229            
230 0           $$s->{$tree->name} = 1;
231 0           for (@$tree) {
232 0 0         if (&{$test}($_)) {
  0            
233 0           $$b->{$tree->name}->{$_->name}++;
234 0           $$d->{$_->name}->{$tree->name}++;
235 0           $$s->{$tree->name} = 0;
236 0 0         unless (defined $$s->{$_->name}) {
237 0           my $x = $_->explode;
238 0           $x->recurse_part_tree($b, $d, $s);
239             }
240             }
241             }
242 0           $b = undef;
243 0           $d = undef;
244 0           $s = undef;
245 0           $tree = undef;
246             }
247            
248             1;
249             __END__