File Coverage

blib/lib/Lego/Ldraw.pm
Criterion Covered Total %
statement 23 160 14.3
branch 0 34 0.0
condition 0 7 0.0
subroutine 8 30 26.6
pod 19 20 95.0
total 50 251 19.9


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