File Coverage

blib/lib/PickLE/Component.pm
Criterion Covered Total %
statement 61 62 98.3
branch 18 24 75.0
condition 3 3 100.0
subroutine 12 12 100.0
pod 6 6 100.0
total 100 107 93.4


line stmt bran cond sub pod time code
1             #!/usr/bin/env perl
2              
3             =head1 NAME
4              
5             C<PickLE::Component> - Representation of an electronic component in a pick list
6              
7             =cut
8              
9              
10             use strict;
11 3     3   171111 use warnings;
  3         24  
  3         76  
12 3     3   13 use Carp;
  3         5  
  3         59  
13 3     3   11 use Moo;
  3         4  
  3         132  
14 3     3   934  
  3         12050  
  3         13  
15             =head1 ATTRIBUTES
16              
17             =over 4
18              
19             =item I<picked>
20              
21             Has the component in the list already been picked?
22              
23             =cut
24              
25             has picked => (
26             is => 'rw',
27             default => 0
28             );
29              
30             =item I<name>
31              
32             Name or part number of the component. A way to uniquely identify this component
33             in the list without being too descriptive.
34              
35             =cut
36              
37             has name => (
38             is => 'rw',
39             default => ''
40             );
41              
42             =item I<value>
43              
44             Component value if it has one. Useful for things like passive components. This
45             attribute also has associated clearer (C<clear_value>) and predicate
46             (C<has_value>) methods.
47              
48             =cut
49              
50             has value => (
51             is => 'rw',
52             clearer => 1,
53             predicate => 1
54             );
55              
56             =item I<description>
57              
58             A brief description of the component to make it easier to understand what the
59             often times cryptic I<name> refers to. This attribute also has associated
60             clearer (C<clear_description>) and predicate (C<has_description>) methods.
61              
62             =cut
63              
64             has description => (
65             is => 'rw',
66             clearer => 1,
67             predicate => 1
68             );
69              
70             =item I<case>
71              
72             Since C<package> is kind of a reserved word, this defines the component package
73             as a simple string. This attribute also has associated clearer (C<clear_case>)
74             and predicate (C<has_case>) methods.
75              
76             =cut
77              
78             has case => (
79             is => 'rw',
80             clearer => 1,
81             predicate => 1
82             );
83              
84             =item I<refdes>
85              
86             A B<list reference> of reference designators for this component. This is
87             important since it'll be the only way this class can determine the quantity of
88             components to be picked.
89              
90             =cut
91              
92             has refdes => (
93             is => 'ro',
94             lazy => 1,
95             default => sub { [] },
96             writer => '_set_refdes'
97             );
98              
99             =back
100              
101             =head1 METHODS
102              
103             =over 4
104              
105             =item I<$comp> = C<PickLE::Component>->C<new>([I<picked>, I<name>, I<value>,
106             I<description>, I<case>, I<refdes>])
107              
108             Initializes a component object with a I<name>, the reference designator list
109             (I<refdes>), if the component has been I<picked>, a I<value> in cases where it
110             is applicable, a brief I<description> if you see fit, and an component package
111             (I<case>).
112              
113             =item I<$comp> = C<PickLE::Component>->C<from_line>(I<$line>)
114              
115             =item I<$comp> = I<$comp>->C<from_line>(I<$line>)
116              
117             This method can be called statically, in which it will initialize a brand new
118             component object, or in object context in which it'll override just the
119             attributes of the object and leave the instance intact.
120              
121             In both variants it'll parse a component descriptor I<$line> and populate the
122             component object. Will return C<undef> if we couldn't parse a component from the
123             given line.
124              
125             =cut
126              
127             my ($self, $line) = @_;
128             $self = $self->new() unless ref $self;
129 56     56 1 86  
130 56 50       825 # Try to parse the component descriptor line.
131             if ($line =~ /\[(?<picked>.)\]\s+(?<quantity>\d+)\s+(?<name>[^\s]+)\s*(\((?<value>[^\)]+)\)\s*)?("(?<description>[^"]+)"\s*)?(\[(?<case>[^\]]+)\]\s*)?/) {
132             # Populate the component with required parameters.
133 56 50       2356 $self->picked(($+{picked} ne ' ') ? 1 : 0);
134             $self->name($+{name});
135 2 50   2   3621  
  2         688  
  2         1016  
  56         302  
136 56         191 # Component value.
137             if (exists $+{value}) {
138             $self->value($+{value});
139 56 100       190 }
140 38         131  
141             # Component description.
142             if (exists $+{description}) {
143             $self->description($+{description});
144 56 50       185 }
145 56         174  
146             # Component package.
147             if (exists $+{case}) {
148             $self->case($+{case});
149 56 50       176 }
150 56         151  
151             return $self;
152             }
153 56         139  
154             # Looks like the component descriptor line couldn't be parsed.
155             return undef;
156             }
157 0         0  
158             =item I<$comp>->C<parse_refdes_line>(I<$line>)
159              
160             Parses the reference designator line in a document and populates the I<refdes>
161             list with them.
162              
163             =cut
164              
165             my ($self, $line) = @_;
166              
167             # Append the reference designators.
168 56     56 1 89 if (substr($line, 0, 1) ne '') {
169             $self->add_refdes(split /\s+/, $line);
170             }
171 56 50       128 }
172 56         179  
173             =item I<$comp>->C<add_refdes>(I<@refdes>)
174              
175             Adds any number of reference designators to the reference designator list.
176              
177             =cut
178              
179             my $self = shift;
180             push @{$self->refdes}, @_;
181             }
182              
183 58     58 1 78 =item I<$quantity> = I<$comp>->C<quantity>()
184 58         60  
  58         884  
185             Gets the quantity of the component to be picked.
186              
187             =cut
188              
189             my ($self) = @_;
190              
191             return scalar @{$self->refdes};
192             }
193              
194 14     14 1 1428 =item I<$str> = I<$comp>->C<refdes_string>()
195              
196 14         18 Gets the list of reference designators seoarated by spaces as a string.
  14         293  
197              
198             =cut
199              
200             my ($self) = @_;
201             my $str = '';
202              
203             # Go through reference designators building up a string.
204             foreach my $refdes (@{$self->refdes}) {
205             $str .= "$refdes ";
206 11     11 1 15 }
207 11         15  
208             # Remove any trailling whitespace and return.
209             $str =~ s/\s+$//;
210 11         11 return $str;
  11         151  
211 3         14 }
212              
213             =item I<$str> = I<$comp>->C<as_string>()
214              
215 11         63 Gets the string representation of this object.
216 11         18  
217             =cut
218              
219             my ($self) = @_;
220             my $str = '';
221              
222             # Make sure we have a name.
223             if (not $self->_attr_available($self->name)) {
224             carp "Component can't be represented because no name has been defined";
225             return '';
226 12     12 1 3821 }
227 12         20  
228             # First line.
229             $str .= '[' . (($self->picked) ? 'X' : ' ') . "]\t" . $self->quantity .
230 12 100       35 "\t" . $self->name;
231 1         187  
232 1         57 # Component value.
233             if ($self->_attr_available($self->value)) {
234             $str .= "\t(" . $self->value . ')';
235             }
236 11 100       41  
237             # Component description.
238             if ($self->_attr_available($self->description)) {
239             $str .= "\t\"" . $self->description . "\"";
240 11 100       97 }
241 8         17  
242             # Component package.
243             if ($self->_attr_available($self->case)) {
244             $str .= "\t[" . $self->case . ']';
245 11 100       24 }
246 6         14  
247             # Reference designators.
248             $str .= "\n";
249             $str .= $self->refdes_string;
250 11 100       23  
251 4         10 # Remove any trailling whitespace and return.
252             $str =~ s/\s+$//;
253             return $str;
254             }
255 11         17  
256 11         16 =back
257              
258             =head1 PRIVATE METHODS
259 11         49  
260 11         90 =over 4
261              
262             =item I<$available> = I<$self>->C<_attr_available>(I<$attribute>)
263              
264             Checks if an I<$attribute> is defined and isn't an empty string.
265              
266             =cut
267              
268             my ($self, $attribute) = @_;
269              
270             return ((defined $attribute) and ($attribute ne ''));
271             }
272              
273             1;
274              
275              
276 45     45   63 =back
277              
278 45   100     141 =head1 AUTHOR
279              
280             Nathan Campos <nathan@innoveworkshop.com>
281              
282             =head1 COPYRIGHT
283              
284             Copyright (c) 2022- Nathan Campos.
285              
286             =cut