File Coverage

blib/lib/Util/H2O/More.pm
Criterion Covered Total %
statement 98 108 90.7
branch 12 16 75.0
condition n/a
subroutine 20 21 95.2
pod 6 6 100.0
total 136 151 90.0


line stmt bran cond sub pod time code
1 6     6   669587 use strict;
  6         66  
  6         191  
2 6     6   49 use warnings;
  6         20  
  6         258  
3              
4             package Util::H2O::More;
5 6     6   2706 use parent q/Exporter/;
  6         1849  
  6         35  
6              
7             our $VERSION = q{0.1};
8              
9             our @EXPORT_OK = (qw/baptise opt2h2o h2o o2h h3o o3h/);
10              
11 6     6   3584 use Util::H2O ();
  6         39863  
  6         156  
12              
13 6     6   38 use feature 'state';
  6         13  
  6         3547  
14              
15             # quick hack to export h2o, uses proper
16             # Util::H2O::h2o called with full namespace
17             sub h2o {
18 43     43 1 2721 return Util::H2O::h2o @_;
19             }
20              
21             # maintains basically a count to create non-colliding
22             # unique $pkg names (basically what Util::H2O::h2o does
23             # if $pkg is not specified using -class
24             # monatomically increasing uuid
25             sub _uuid {
26 9     9   16 state $uuid = 0;
27 9         46 return ++$uuid;
28             }
29              
30             # non-recursive option
31             sub baptise ($$@) {
32 9     9 1 8615 my ( $ref, $pkg, @default_accessors );
33 9         20 my $pos0 = shift;
34              
35             # check pos0 for '-recurse'
36 9 100       33 if ( $pos0 eq q{-recurse} ) {
37 7         52 ( $ref, $pkg, @default_accessors ) = @_;
38             }
39             else {
40 2         4 $ref = $pos0;
41 2         5 ( $pkg, @default_accessors ) = @_;
42             }
43              
44 9         44 my $self;
45 9         25 my $real_pkg = sprintf qq{%s::_%s}, $pkg, _uuid;
46              
47             # uses -isa to inherit from $pkg; -class to bless with a package name
48             # derived from $pkg
49 9 100       32 if ( $pos0 eq q{-recurse} ) {
50 7         25 $self = h2o -recurse, -isa => $pkg, -class => $real_pkg, $ref, @default_accessors;
51             }
52             else {
53 2         10 $self = h2o -isa => $pkg, -class => $real_pkg, $ref, @default_accessors;
54             }
55              
56 9         2436 return $self;
57             }
58              
59             # preconditioner for use with Getopt::Long flags; returns just the flag name given
60             # a list of option descriptors, e.g., qw/option1=s option2=i option3/;
61              
62             # flags to keys
63             sub opt2h2o(@) {
64 1     1 1 174 my @getopt_def = @_;
65 1         4 my @flags_only = map { m/([^=|\s]+)/g; $1 } @getopt_def;
  4         15  
  4         14  
66 1         6 return @flags_only;
67             }
68              
69             # return a dereferences hash (non-recursive); reverse of `h2o'
70             sub o2h($) {
71              
72             # makes internal package name more generic for baptise created references
73 18     18 1 2656 $Util::H2O::_PACKAGE_REGEX = qr/::_[0-9A-Fa-f]+\z/;
74 18         55 my $ref = Util::H2O::o2h @_;
75 18 50       657 if ( ref $ref ne q{HASH} ) {
76 0         0 die qq{Could not fully remove top-level reference. Probably an issue with \$Util::H2O_PACKAGE_REGEX\n};
77             }
78 18         96 return $ref;
79             }
80              
81             # traverses a all ARRAY and HASH references in a data structure reference,
82             # looking for HASH references to bless using h2o; basically it's C
83             # on performance enhancing drugs
84              
85             ## Notes on implementation
86             # * Interface - should accept all things h2o does [what about default accessors?]
87             # * All hash refs should get accessors (what about default accessors?)
88             # * all arrays to get an vmethod that returns all elements in it
89             # * anything not ARRAY or HASH should be untouched
90              
91             sub h3o($); # forward declaration to get rid of "too early" warning
92              
93             sub h3o($) {
94 108     108 1 2170 my $thing = shift;
95 108         171 my $isa = ref $thing;
96 108 100       255 if ( $isa eq q{ARRAY} ) {
    100          
97              
98             # uses lexical scop of the 'if' to a bless $thing (an ARRAY ref)
99             # and assigns to it some virtual methods for making dealing with
100             # the "lists of C references easier, as a container
101 6     6   50 no strict 'refs';
  6         16  
  6         3470  
102 20         133 my $a2o_pkg = sprintf( qq{%s::_a2o_%d}, __PACKAGE__, int rand 100_000 ); # internal a2o
103 20         138 bless $thing, $a2o_pkg;
104              
105             # add vmethod to wrap around things
106 20     0   98 my $GET = sub { my ( $self, $i ) = @_; return $self->[$i]; };
  0         0  
  0         0  
107 20     2   52 my $ALL = sub { my $self = shift; return @$self; };
  2         2097  
  2         6  
108 20     14   47 my $SCALAR = sub { my $self = shift; return scalar @$self; };
  14         239  
  14         59  
109              
110             # 'push' will apply "h3o" to all elements pushed
111 20     6   67 my $PUSH = sub { my ( $self, @i ) = @_; h3o \@i; push @$self, @i; return \@i };
  6         3549  
  6         20  
  6         16  
  6         17  
112              
113             # 'pop' intentionally does NOT apply "o3h" to anything pop'd
114 20     4   64 my $POP = sub { my $self = shift; return pop @$self };
  4         10541  
  4         10  
115              
116             # 'unshift' will apply "h3o" to all elements unshifted
117 20     6   89 my $UNSHIFT = sub { my ( $self, @i ) = @_; h3o \@i; unshift @$self, @i; return \@i };
  6         3604  
  6         23  
  6         12  
  6         14  
118              
119             # 'shift' intentionally does NOT apply "o3h" to anything shift'd
120 20     8   49 my $SHIFT = sub { my $self = shift; return shift @$self };
  8         18484  
  8         20  
121 20         27 *{"${a2o_pkg}::get"} = $GET;
  20         106  
122 20         42 *{"${a2o_pkg}::all"} = $ALL;
  20         78  
123 20         28 *{"${a2o_pkg}::scalar"} = $SCALAR;
  20         74  
124 20         42 *{"${a2o_pkg}::push"} = $PUSH;
  20         57  
125 20         32 *{"${a2o_pkg}::pop"} = $POP;
  20         67  
126 20         30 *{"${a2o_pkg}::unshift"} = $UNSHIFT;
  20         70  
127 20         33 *{"${a2o_pkg}::shift"} = $SHIFT;
  20         65  
128              
129 20         137 foreach my $element (@$thing) {
130 54         108 h3o $element;
131             }
132             }
133             elsif ( $isa eq q{HASH} ) {
134 24         80 foreach my $keys ( keys %$thing ) {
135 38         80 h3o( $thing->{$keys} );
136             }
137              
138             # package level wrapper, so this can be monkey patched
139             # if so desired, per documentation
140 24         52 h2o $thing;
141             }
142 108         2745 return $thing;
143             }
144              
145             # includes internal dereferencing so to be compatible
146             # with the behavior of Util::H2O::o2h
147             sub o3h($); # forward declaration to get rid of "too early" warning
148              
149             sub o3h($) {
150 2     2 1 89 my $thing = shift;
151 6     6   52 no warnings 'prototype';
  6         14  
  6         1470  
152 2 50       8 return $thing if not $thing;
153 2         3 my $isa = ref $thing;
154 2 50       10 if ( $isa eq q{ARRAY} ) {
    50          
155 0         0 my @_thing = @$thing;
156 0         0 foreach my $element (@_thing) {
157 0         0 $element = o3h($element);
158             }
159             }
160             elsif ( $isa eq q{HASH} ) {
161 0         0 my %_thing = %$thing;
162 0         0 foreach my $key ( keys %_thing ) {
163 0         0 $_thing{$key} = o3h( $_thing{$key} );
164             }
165 0         0 $thing = Util::H2O::o2h \%_thing;
166             }
167 2         5 return Util::H2O::o2h $thing;
168             }
169              
170             1;
171              
172             __END__