File Coverage

blib/lib/Color/Palette.pm
Criterion Covered Total %
statement 55 57 96.4
branch 12 14 85.7
condition n/a
subroutine 11 12 91.6
pod 4 5 80.0
total 82 88 93.1


line stmt bran cond sub pod time code
1             package Color::Palette 0.100004;
2 1     1   1121 use Moose;
  1         472437  
  1         7  
3             # ABSTRACT: a set of named colors
4              
5 1     1   8306 use MooseX::Types::Moose qw(Str HashRef ArrayRef);
  1         64109  
  1         9  
6 1     1   5870 use Color::Palette::Types qw(RecursiveColorDict ColorDict Color);
  1         3  
  1         9  
7              
8             #pod =head1 DESCRIPTION
9             #pod
10             #pod The libraries in the Color-Palette distribution are meant to make it easy to
11             #pod build sets of named colors, and to write applications that can define and
12             #pod validate the color names they required.
13             #pod
14             #pod For example, a color palette might contain the following data:
15             #pod
16             #pod highlights => #f0f000
17             #pod background => #333
18             #pod sidebarBackground => #88d
19             #pod sidebarText => 'highlights'
20             #pod sidebarBoder => 'sidebarText'
21             #pod
22             #pod Colors can be defined by a color specifier (a L<Graphics::Color> object,
23             #pod a CSS-style hex triple, or an arrayref of RGB values) or by a name of another
24             #pod color that appears in the palette. If colors are defined in terms of another
25             #pod color that doesn't exist, an exception will be raised.
26             #pod
27             #pod Applications that wish to use color palettes can provide schemas that define
28             #pod the names they expect to be present in a palette. These schemas are
29             #pod L<Color::Palette::Schema> objects.
30             #pod
31             #pod A palette can be checked against a schema with the schema's C<check> method, or
32             #pod may be reduced to the minimal set of colors needed to satisfy the schema with
33             #pod the palette's C<optimized_for> method.
34             #pod
35             #pod =attr colors
36             #pod
37             #pod This attribute is a hashref. Keys are color names and values are either Color
38             #pod objects or names of other colors. To get at the color object for a name
39             #pod consult the C<L</color>> method.
40             #pod
41             #pod =cut
42              
43             has colors => (
44             is => 'bare',
45             isa => RecursiveColorDict,
46             coerce => 1,
47             required => 1,
48             reader => '_colors',
49             );
50              
51             #pod =begin :private
52             #pod
53             #pod =attr _resolved_colors
54             #pod
55             #pod This attribute is just like C<colors>, but all values are Color objects.
56             #pod
57             #pod =end :private
58             #pod
59             #pod =cut
60              
61             has _resolved_colors => (
62             is => 'ro',
63             isa => ColorDict,
64             lazy => 1,
65             traits => [ 'Hash' ],
66             coerce => 1,
67             required => 1,
68             builder => '_build_resolved_colors',
69             handles => {
70             has_color => 'exists',
71             _get_color => 'get',
72             color_names => 'keys',
73             },
74             );
75              
76             sub _build_resolved_colors {
77 3     3   7 my ($self) = @_;
78              
79 3         93 my $input = $self->_colors;
80              
81 3         7 my %output;
82              
83 3         15 for my $key (keys %$input) {
84 21         32 my $value = $input->{ $key };
85 21 100       40 next unless ref $value;
86              
87 16         35 $output{ $key } = $value;
88             }
89              
90 3         11 for my $key (keys %$input) {
91 21         26 my $value = $input->{ $key };
92 21 100       45 next if ref $value;
93              
94 5         7 my %seen;
95 5         9 my $curr = $key;
96 5         7 REDIR: while (1) {
97             Carp::confess "$key refers to missing color $curr"
98 10 50       21 unless exists $input->{$curr};
99              
100 10 100       19 if ($output{ $curr }) {
101 5         10 $output{ $key } = $output{ $curr };
102 5         11 last REDIR;
103             }
104              
105 5         9 $curr = $input->{ $curr };
106 5 50       13 Carp::confess "looping at $curr" if $seen{ $curr }++;
107             }
108             }
109              
110 3         104 return \%output;
111             }
112              
113             #pod =method color
114             #pod
115             #pod my $color_obj = $palette->color('extremeHighlight');
116             #pod
117             #pod This method will return the Color object to be used for the given name.
118             #pod
119             #pod =cut
120              
121             sub color {
122 20     20 1 1554 my ($self, $name) = @_;
123 20 100       671 confess("no color named $name") unless my $color = $self->_get_color($name);
124              
125 18         63 return $color;
126             }
127              
128             #pod =method color_names
129             #pod
130             #pod my @names = $palette->color_names;
131             #pod
132             #pod This method returns a list of all color names the object knows about.
133             #pod
134             #pod =method as_css_hash
135             #pod
136             #pod my $triple_for = $palette->as_css_hash
137             #pod
138             #pod This method returns a hashref. Every color name known to the palette has an
139             #pod entry, and the value is the CSS-safe hex string for the resolved color. For
140             #pod example, the output for the color scheme in the L</DESCRIPTION> section would
141             #pod be:
142             #pod
143             #pod {
144             #pod highlights => '#f0f000',
145             #pod background => '#333333',
146             #pod sidebarBackground => #8888dd',
147             #pod sidebarText => #f0f000',
148             #pod sidebarBoder => #f0f000',
149             #pod }
150             #pod
151             #pod =cut
152              
153             sub as_css_hash {
154 1     1 1 3 my ($self) = @_;
155 1         3 my $output = {};
156 1         45 $output->{$_} = $self->color($_)->as_css_hex for $self->color_names;
157 1         87 return $output;
158             }
159              
160             #pod =method as_strict_css_hash
161             #pod
162             #pod my $hashref = $palette->as_strict_css_hash;
163             #pod
164             #pod This method behaves just like C<L</as_css_hash>>, but the returned hashref is
165             #pod tied so that trying to read values for keys that do not exist is fatal. The
166             #pod hash may also become read-only in the future.
167             #pod
168             #pod =cut
169              
170             sub as_strict_css_hash {
171 1     1 1 707 my ($self) = @_;
172 1         6 my $hashref = $self->as_css_hash;
173 1         18 tie my %hash, 'Color::Palette::TiedStrictHash';
174 1         41 %hash = %$hashref;
175 1         41 return \%hash;
176             }
177              
178             #pod =method optimized_for
179             #pod
180             #pod my $optimized_palette = $palette->optimized_for($schema);
181             #pod
182             #pod This method returns a new palette containing only the colors needed to fulfill
183             #pod the requirements of the given schema. This is useful for reducing a large
184             #pod palette to the small set that must be embedded in a document.
185             #pod
186             #pod C<optimize_for> redispatches to this method for historical reasons.
187             #pod
188             #pod =cut
189              
190             sub optimize_for {
191 0     0 0 0 my $self = shift;
192             # warn deprecated
193 0         0 $self->optimized_for(@_);
194             }
195              
196             sub optimized_for {
197 1     1 1 401 my ($self, $checker) = @_;
198              
199 1         34 my $required_colors = $checker->required_colors;
200              
201 1         3 my %new_palette;
202 1         2 for my $name (@{ $checker->required_colors }) {
  1         28  
203 7         18 $new_palette{ $name } = $self->color($name);
204             }
205              
206 1         10 (ref $self)->new({
207             colors => \%new_palette,
208             });
209             }
210              
211             {
212             package
213             Color::Palette::TiedStrictHash;
214 1     1   4537 use Tie::Hash;
  1         1037  
  1         44  
215 1     1   118 BEGIN { our @ISA = qw(Tie::StdHash) }
216             sub FETCH {
217 2     2   611 my ($self, $key) = @_;
218 2 100       10 die "no entry in palette hash for key $key"
219             unless $self->EXISTS($key);
220 1         12 return $self->SUPER::FETCH($key);
221             }
222             }
223              
224             1;
225              
226             __END__
227              
228             =pod
229              
230             =encoding UTF-8
231              
232             =head1 NAME
233              
234             Color::Palette - a set of named colors
235              
236             =head1 VERSION
237              
238             version 0.100004
239              
240             =head1 DESCRIPTION
241              
242             The libraries in the Color-Palette distribution are meant to make it easy to
243             build sets of named colors, and to write applications that can define and
244             validate the color names they required.
245              
246             For example, a color palette might contain the following data:
247              
248             highlights => #f0f000
249             background => #333
250             sidebarBackground => #88d
251             sidebarText => 'highlights'
252             sidebarBoder => 'sidebarText'
253              
254             Colors can be defined by a color specifier (a L<Graphics::Color> object,
255             a CSS-style hex triple, or an arrayref of RGB values) or by a name of another
256             color that appears in the palette. If colors are defined in terms of another
257             color that doesn't exist, an exception will be raised.
258              
259             Applications that wish to use color palettes can provide schemas that define
260             the names they expect to be present in a palette. These schemas are
261             L<Color::Palette::Schema> objects.
262              
263             A palette can be checked against a schema with the schema's C<check> method, or
264             may be reduced to the minimal set of colors needed to satisfy the schema with
265             the palette's C<optimized_for> method.
266              
267             =head1 PERL VERSION
268              
269             This library should run on perls released even a long time ago. It should work
270             on any version of perl released in the last five years.
271              
272             Although it may work on older versions of perl, no guarantee is made that the
273             minimum required version will not be increased. The version may be increased
274             for any reason, and there is no promise that patches will be accepted to lower
275             the minimum required perl.
276              
277             =head1 ATTRIBUTES
278              
279             =head2 colors
280              
281             This attribute is a hashref. Keys are color names and values are either Color
282             objects or names of other colors. To get at the color object for a name
283             consult the C<L</color>> method.
284              
285             =head1 METHODS
286              
287             =head2 color
288              
289             my $color_obj = $palette->color('extremeHighlight');
290              
291             This method will return the Color object to be used for the given name.
292              
293             =head2 color_names
294              
295             my @names = $palette->color_names;
296              
297             This method returns a list of all color names the object knows about.
298              
299             =head2 as_css_hash
300              
301             my $triple_for = $palette->as_css_hash
302              
303             This method returns a hashref. Every color name known to the palette has an
304             entry, and the value is the CSS-safe hex string for the resolved color. For
305             example, the output for the color scheme in the L</DESCRIPTION> section would
306             be:
307              
308             {
309             highlights => '#f0f000',
310             background => '#333333',
311             sidebarBackground => #8888dd',
312             sidebarText => #f0f000',
313             sidebarBoder => #f0f000',
314             }
315              
316             =head2 as_strict_css_hash
317              
318             my $hashref = $palette->as_strict_css_hash;
319              
320             This method behaves just like C<L</as_css_hash>>, but the returned hashref is
321             tied so that trying to read values for keys that do not exist is fatal. The
322             hash may also become read-only in the future.
323              
324             =head2 optimized_for
325              
326             my $optimized_palette = $palette->optimized_for($schema);
327              
328             This method returns a new palette containing only the colors needed to fulfill
329             the requirements of the given schema. This is useful for reducing a large
330             palette to the small set that must be embedded in a document.
331              
332             C<optimize_for> redispatches to this method for historical reasons.
333              
334             =begin :private
335              
336             =attr _resolved_colors
337              
338             This attribute is just like C<colors>, but all values are Color objects.
339              
340             =end :private
341              
342             =head1 AUTHOR
343              
344             Ricardo SIGNES <cpan@semiotic.systems>
345              
346             =head1 CONTRIBUTORS
347              
348             =for stopwords Karen Etheridge Ricardo Signes
349              
350             =over 4
351              
352             =item *
353              
354             Karen Etheridge <ether@cpan.org>
355              
356             =item *
357              
358             Ricardo Signes <rjbs@semiotic.systems>
359              
360             =back
361              
362             =head1 COPYRIGHT AND LICENSE
363              
364             This software is copyright (c) 2022 by Ricardo SIGNES.
365              
366             This is free software; you can redistribute it and/or modify it under
367             the same terms as the Perl 5 programming language system itself.
368              
369             =cut