File Coverage

blib/lib/Decl/Util.pm
Criterion Covered Total %
statement 53 57 92.9
branch 24 26 92.3
condition n/a
subroutine 13 14 92.8
pod 9 9 100.0
total 99 106 93.4


line stmt bran cond sub pod time code
1             package Decl::Util;
2            
3 12     12   72 use warnings;
  12         25  
  12         783  
4 12     12   66 use strict;
  12         24  
  12         582  
5 12     12   65 use base qw(Exporter);
  12         24  
  12         1020  
6 12     12   66 use vars qw(@EXPORT);
  12         26  
  12         10471  
7            
8             @EXPORT = qw(car cdr popcar splitcar lazyiter escapequote hh_set hh_get);
9            
10             =head1 NAME
11            
12             Decl::Util - some utility functions for the declarative framework - automatically included for generated code.
13            
14             =head1 VERSION
15            
16             Version 0.01
17            
18             =cut
19            
20             our $VERSION = '0.01';
21            
22            
23             =head1 SYNOPSIS
24            
25             This class is a lightweight set of utilities to make things easier throughout C. I'm not yet sure what will end up here, but my
26             rule of thumb is that it's extensions I'd like to be able to use in code generators as well.
27            
28             =head2 Lazy Lispy lists: car(), cdr(), popcar(), splitcar()
29            
30             I like Higher-Order Perl, really I do - but his head/tail streams are really just car and cdr, so I'm hereby defining car and cdr as lazy-evaluated streams
31             throughout the language. Nodes are arrayrefs. Clean and simple, no object orientation required.
32            
33             =cut
34            
35 23076 100   23076 1 83015 sub car ($) { return undef unless ref $_[0] eq 'ARRAY'; $_[0]->[0] }
  12157         43481  
36             sub cdr ($) {
37 7269     7269 1 22585 my ($s) = @_;
38 7269 100       16592 return undef unless ref $s eq 'ARRAY';
39 7262 100       19005 $s->[1] = $s->[1]->() if ref $s->[1] eq 'CODE';
40 7262         95679 $s->[1];
41             }
42             sub popcar ($) {
43 851     851 1 2141 my $p = car($_[0]);
44 851         2042 $_[0] = cdr($_[0]);
45 851         3791 return $p;
46             }
47 1231     1231 1 1628 sub splitcar ($) { @{$_[0]}; }
  1231         4802  
48            
49             =head2 lazyiter($iterator)
50            
51             Takes any coderef (but especially an L) and builds a stream out of it. Invokes the coderef once to get the
52             first value in the stream.
53            
54             =cut
55            
56             sub lazyiter {
57 5102     5102 1 6825 my $i = shift;
58 5102         18313 my $value = $i->();
59 5102 100       118017 return unless defined $value;
60 3029     3010   18886 [$value, sub { lazyiter ($i); }]
  3010         5210  
61             }
62            
63             =head2 escapequote($string, $quote)
64            
65             Returns a new string with C<$quote> escaped (by default, '"' is escaped) by means of a backslash.
66            
67             =cut
68            
69             sub escapequote {
70 0     0 1 0 my ($string, $quote) = @_;
71 0 0       0 $quote = '"' unless $quote;
72 0         0 $string =~ s/($quote)/\\$1/g;
73 0         0 $string
74             }
75            
76             =head2 Hierarchical values a la CSS: hh_set(hash, name, value), hh_get (hash, name), and prepare_hierarchical_value as a helper
77            
78             You know how CSS lets you specify something like C as well as something more like C? These functions give
79             you something similar using hierarchically nested hashrefs. They allow you to mix types of addressing:
80            
81             hh_set($h, 'border-left', 'my value');
82             hh_set($h, 'border', 'right: val1; top: val2');
83            
84             # { 'border' => {'left' => 'my value',
85             # 'right' => 'val1',
86             # 'top' => 'val2'
87             # }
88             # }
89            
90             Clear? Then you can use C to retrieve 'border' or 'border-left' by digging down into the hashref hierarchy.
91            
92             Separators for names can be anything in -./
93            
94             =cut
95            
96             sub prepare_hierarchical_value {
97 28     28 1 48 my ($hash, $name) = @_;
98 28 100       87 $hash->{$name} = {} unless defined $hash->{$name};
99 28 100       75 if (not ref $hash->{$name}) {
100 3         9 my $newhash = {'*' => $hash->{$name}};
101 3         8 $hash->{$name} = $newhash;
102             }
103 28         118 return $hash->{$name};
104             }
105            
106             sub hh_set {
107 43     43 1 75 my ($hash, $name, $value) = @_;
108            
109 43 100       101 unless (ref $name) {
110 27         95 my @s = split /[.\-\/]/, $name;
111 27         60 $name = \@s;
112             }
113            
114 43         97 my ($first, @rest) = @$name;
115 43 100       90 if (@rest) {
116 16         36 hh_set (prepare_hierarchical_value ($hash, $first), \@rest, $value);
117             } else {
118 27 100       89 if ($value =~ /:/) {
    100          
119 4         25 foreach (split / *; */, $value) {
120 12         25 hh_set (prepare_hierarchical_value ($hash, $first), split / *: */);
121             }
122             } elsif (ref $hash->{$first}) {
123 1         10 $hash->{$first}->{'*'} = $value;
124             } else {
125 22         142 $hash->{$first} = $value;
126             }
127             }
128             }
129            
130             sub hh_get {
131 13     13 1 25 my ($hash, $name) = @_;
132            
133 13 100       30 unless (ref $name) {
134 7         30 my @s = split /[.\-\/]/, $name;
135 7         15 $name = \@s;
136             }
137 13         30 my ($first, @rest) = @$name;
138 13 100       97 return $hash->{$first} unless @rest;
139 6         20 hh_get ($hash->{$first}, \@rest);
140             }
141            
142            
143             =head1 AUTHOR
144            
145             Michael Roberts, C<< >>
146            
147             =head1 BUGS
148            
149             Please report any bugs or feature requests to C, or through
150             the web interface at L. I will be notified, and then you'll
151             automatically be notified of progress on your bug as I make changes.
152            
153             =head1 LICENSE AND COPYRIGHT
154            
155             Copyright 2010 Michael Roberts.
156            
157             This program is free software; you can redistribute it and/or modify it
158             under the terms of either: the GNU General Public License as published
159             by the Free Software Foundation; or the Artistic License.
160            
161             See http://dev.perl.org/licenses/ for more information.
162            
163             =cut
164            
165             1; # End of Decl::Util