File Coverage

blib/lib/Data/Random/Structure.pm
Criterion Covered Total %
statement 59 74 79.7
branch 16 32 50.0
condition 2 4 50.0
subroutine 11 12 91.6
pod 7 7 100.0
total 95 129 73.6


line stmt bran cond sub pod time code
1             package Data::Random::Structure;
2             {
3             $Data::Random::Structure::VERSION = '0.01';
4             }
5              
6             #ABSTRACT: Generate random data structures
7              
8              
9 2     2   69407 use warnings;
  2         4  
  2         63  
10 2     2   12 use strict;
  2         4  
  2         70  
11              
12 2     2   2130 use Data::Random qw(rand_chars);
  2         8531  
  2         207  
13 2     2   18 use Carp qw(croak);
  2         4  
  2         2651  
14              
15             # Use grotty old style OO
16             # No validation, whee
17              
18             sub new {
19 1     1 1 15 my $class = shift;
20              
21 1 50       6 if ( scalar @_ % 2 != 0 ) {
22 0         0 croak "Constructor requires even number of arguments.\n";
23             }
24              
25 1         3 my $self = { @_ };
26 1         4 bless $self, $class;
27              
28 1   50     13 $self->{max_depth} ||= 3;
29 1   50     8 $self->{max_elements} ||= 6;
30              
31 1         5 $self->_init();
32              
33 1         3 return $self;
34             }
35              
36             sub _init {
37 1     1   2 my $self = shift;
38              
39 1         2 push @{$self->{_types}}, qw(HASH ARRAY);
  1         5  
40 1         2 push @{$self->{_scalar_types}}, qw(string integer float bool);
  1         5  
41             }
42              
43              
44             sub max_depth {
45 1     1 1 3 my $self = shift;
46 1         2 my $max_depth = shift;
47              
48 1 50       5 if ( defined $max_depth ) {
49 0         0 $self->{max_depth} = $max_depth;
50             }
51              
52 1         5 return $self->{max_depth};
53             }
54              
55              
56             sub max_elements {
57 1     1 1 1 my $self = shift;
58 1         2 my $max_elements = shift;
59              
60 1 50       3 if ( defined $max_elements ) {
61 0         0 $self->{max_elements} = $max_elements;
62             }
63              
64 1         4 return $self->{max_elements};
65             }
66              
67              
68             sub generate {
69 1     1 1 7 my ($self, $depth, $ref) = @_;
70              
71 1 50       5 $depth = 0 if not defined $depth;
72              
73 1 50       4 if ( $depth > $self->max_depth() ) {
74 0         0 return $ref;
75             }
76              
77             # decide what we're making
78 1         2 my $type_count = scalar @{$self->{_types}};
  1         3  
79 1         48 my $type = $self->{_types}[int(rand($type_count))];
80              
81 1         1 my $r; # this is the new thing we're going to make
82              
83 1 50       7 if ( $type eq 'HASH' ) {
    50          
84 0         0 $r = $self->generate_hash();
85             }
86             elsif ( $type eq 'ARRAY' ) {
87 1         4 $r = $self->generate_array();
88             }
89              
90             # connect $r to $ref
91 1 50       4 if ( not defined $ref ) {
    0          
    0          
92 1         17 $ref = $r;
93             }
94             elsif ( ref($ref) eq 'HASH' ) {
95             # $ref is a hash, generate a random key and assign $r
96 0         0 $ref->{$self->generate_scalar()} = $r;
97             }
98             elsif ( ref($ref) eq 'ARRAY' ) {
99 0         0 push @{$ref}, $r;
  0         0  
100             }
101              
102             # decide whether we should add a new level
103 1 50       4 if ( rand(1) < 0.5 ) {
104 0         0 $self->generate($depth+1, $ref);
105             }
106             else {
107 1         3 return $ref;
108             }
109             }
110              
111              
112             sub generate_scalar {
113 3     3 1 4 my $self = shift;
114              
115 3         3 my $type_count = scalar @{$self->{_scalar_types}};
  3         6  
116 3         7 my $type = $self->{_scalar_types}[int(rand($type_count))];
117              
118 3 100       14 if ( $type eq 'float' ) {
    50          
    100          
    50          
119 1         4 return rand(1);
120             }
121             elsif ( $type eq 'integer' ) {
122 0         0 return int(rand(1_000_000));
123             }
124             elsif ( $type eq 'string' ) {
125 1         6 return scalar(rand_chars( set => 'all', min => 6, max => 32 ));
126             }
127             elsif ( $type eq 'bool' ) {
128 1 50       6 return (rand(1) < 0.5) ? 1 : 0;
129             }
130             else {
131 0         0 croak "I don't know how to generate $type\n";
132             }
133             }
134              
135              
136             sub generate_array {
137 1     1 1 2 my $self = shift;
138              
139 1         2 my $ar = [];
140              
141 1         6 push @{$ar}, $self->generate_scalar() for 0 .. int(rand($self->max_elements()));
  3         297  
142              
143 1         3 $ar;
144             }
145              
146              
147             sub generate_hash {
148 0     0 1   my $self = shift;
149              
150 0           my $hr = {};
151              
152 0           $hr->{$self->generate_scalar()} = $self->generate_scalar() for 0 .. int(rand($self->max_elements()));
153              
154 0           $hr;
155             }
156              
157             1;
158              
159             __END__