File Coverage

blib/lib/Data/RuledCluster.pm
Criterion Covered Total %
statement 72 81 88.8
branch 27 38 71.0
condition 2 4 50.0
subroutine 17 17 100.0
pod 8 9 88.8
total 126 149 84.5


line stmt bran cond sub pod time code
1             package Data::RuledCluster;
2 7     7   397207 use 5.008_001;
  7         66  
3 7     7   31 use strict;
  7         12  
  7         128  
4 7     7   25 use warnings;
  7         12  
  7         142  
5 7     7   28 use Carp ();
  7         12  
  7         94  
6 7     7   2850 use Class::Load ();
  7         119323  
  7         181  
7 7     7   2612 use Data::Util qw(is_array_ref is_hash_ref);
  7         4029  
  7         6280  
8              
9             our $VERSION = '0.07';
10              
11             sub new {
12 6     6 1 442 my $class = shift;
13 6 50       39 my %args = @_ == 1 ? %{$_[0]} : @_;
  0         0  
14 6         21 bless \%args, $class;
15             }
16              
17             sub resolver {
18 59     59 0 106 my ($self, $strategy) = @_;
19              
20 59         75 my $pkg = $strategy;
21 59 50       236 $pkg = $pkg =~ s/^\+// ? $pkg : "Data::RuledCluster::Strategy::$pkg";
22 59         180 Class::Load::load_class($pkg);
23 59         3865 $pkg;
24             }
25              
26             sub config {
27 9     9 1 12276 my ($self, $config) = @_;
28 9 100       64 $self->{config} = $config if $config;
29 9         29 $self->{config};
30             }
31              
32             sub resolve {
33 65     65 1 44381 my ($self, $cluster_or_node, $args, $options) = @_;
34              
35 65 50       155 Carp::croak("missing mandatory config.") unless $self->{config};
36              
37 65 100       128 if ($self->is_cluster($cluster_or_node)) {
    50          
38 36         85 my ($resolved_node, @keys) = $self->_delegate(resolve => $cluster_or_node, $args, $options);
39 34         354 return $self->resolve($resolved_node, \@keys);
40             }
41             elsif ($self->is_node($cluster_or_node)) {
42 29         62 return $self->_make_node_hashref($cluster_or_node);
43             }
44              
45 0         0 Carp::croak("$cluster_or_node is not defined.");
46             }
47              
48             sub resolve_node_keys {
49 23     23 1 1567 my ($self, $cluster_or_node, $keys, $args, $options) = @_;
50 23         35 my $orig_args = $args;
51              
52 23 50       63 if ( is_hash_ref $args ) {
53 0         0 $args = {%$args}; # shallow copy
54 0   0     0 $args->{strategy} ||= 'Key';
55 0         0 $args->{key} = $keys;
56             }
57             else {
58 23         33 $args = $keys;
59             }
60              
61 23         50 my %node_keys = $self->_delegate(resolve_node_keys => $cluster_or_node, $args, $options);
62 23         57 for my $cluster_or_node (keys %node_keys) {
63 32 100       63 next if $self->is_node($cluster_or_node);
64 7 50       16 if ($self->is_cluster($cluster_or_node)) {
65 7         12 my $cluster = $cluster_or_node;
66 7         11 my @key_info = @{ delete $node_keys{$cluster_or_node} };
  7         19  
67 7         14 for my $key_info (@key_info) {
68 16         43 my %child_node_keys = $self->resolve_node_keys($cluster, $key_info->{next}, $orig_args, $options);
69 16         30 for my $node (keys %child_node_keys) {
70 16   100     24 push @{ $node_keys{$node} ||= [] } => $key_info->{root};
  16         67  
71             }
72             }
73 7         22 next;
74             }
75              
76 0         0 Carp::croak("$cluster_or_node is not defined.");
77             }
78 23 100       75 return wantarray ? %node_keys : \%node_keys;
79             }
80              
81             sub _delegate {
82 59     59   124 my ($self, $method, $cluster, $args, $options) = @_;
83              
84 59 50       131 Carp::croak("missing mandatory config.") unless $self->{config};
85              
86 59 50       150 if ( is_hash_ref($args) ) {
87 0 0       0 Carp::croak("args has not 'strategy' field") unless $args->{strategy};
88 0         0 return $self->resolver($args->{strategy})->$method(
89             $self,
90             $cluster,
91             $args,
92             $options,
93             );
94             }
95              
96 59         112 my $cluster_info = $self->cluster_info($cluster);
97 59 100       177 if (is_array_ref($cluster_info)) {
    50          
98 18         41 return $self->resolver('Key')->$method(
99             $self,
100             $cluster,
101             +{ key => $args, },
102             $options,
103             );
104             }
105             elsif (is_hash_ref($cluster_info)) {
106 41         90 return $self->resolver($cluster_info->{strategy})->$method(
107             $self,
108             $cluster,
109             +{ %$cluster_info, key => $args, },
110             $options,
111             );
112             }
113              
114 0         0 Carp::croak('$cluster_info is invalid.');
115             }
116              
117             sub _make_node_hashref {
118 29     29   54 my ($self, $node) = @_;
119             return {
120             node => $node,
121 29         219 node_info => $self->{config}->{node}->{$node},
122             };
123             }
124              
125             sub cluster_info {
126 88     88 1 165 my ($self, $cluster) = @_;
127 88         197 $self->{config}->{clusters}->{$cluster};
128             }
129              
130             sub clusters {
131 29     29 1 6806 my ($self, $cluster) = @_;
132 29         53 my $cluster_info = $self->cluster_info($cluster);
133 29 100       114 my @nodes = is_array_ref($cluster_info) ? @$cluster_info : @{ $cluster_info->{nodes} };
  7         14  
134 29 100       92 wantarray ? @nodes : \@nodes;
135             }
136              
137             sub is_cluster {
138 123     123 1 204 my ($self, $cluster) = @_;
139 123 100       369 exists $self->{config}->{clusters}->{$cluster} ? 1 : 0;
140             }
141              
142             sub is_node {
143 65     65 1 106 my ($self, $node) = @_;
144 65 100       201 exists $self->{config}->{node}->{$node} ? 1 : 0;
145             }
146              
147             1;
148             __END__