File Coverage

blib/lib/Rose/DB/Registry.pm
Criterion Covered Total %
statement 68 79 86.0
branch 31 48 64.5
condition 4 12 33.3
subroutine 13 16 81.2
pod 9 11 81.8
total 125 166 75.3


line stmt bran cond sub pod time code
1             package Rose::DB::Registry;
2              
3 16     16   116 use strict;
  16         33  
  16         485  
4              
5 16     16   108 use Carp();
  16         34  
  16         259  
6              
7 16     16   8251 use Rose::DB::Registry::Entry;
  16         46  
  16         462  
8              
9 16     16   120 use Rose::Object;
  16         38  
  16         1082  
10             our @ISA = qw(Rose::Object);
11              
12             our $VERSION = '0.728';
13              
14             our $Debug = 0;
15              
16             #
17             # Object data
18             #
19              
20             use Rose::Object::MakeMethods::Generic
21             (
22 16         126 'scalar' =>
23             [
24             qw(error)
25             ],
26              
27             'scalar --get_set_init' =>
28             [
29             'hash',
30             'parent',
31             ],
32 16     16   105 );
  16         33  
33              
34             #
35             # Object methods
36             #
37              
38 34     34 0 462 sub init_hash { {} }
39 0     0 0 0 sub init_parent { 'Rose::DB' }
40              
41             sub add_entries
42             {
43 226     226 1 421 my($self) = shift;
44              
45             # Smuggle parent in with an otherwise nonsensical arrayref arg
46 226 100       690 my $parent = shift->[0] if(ref $_[0] eq 'ARRAY');
47 226   66     517 $parent ||= $self->parent;
48              
49 226         654 my $entries = $self->hash;
50              
51 226         1310 my @added;
52              
53 226         462 foreach my $item (@_)
54             {
55 226         426 my($domain, $type, $entry);
56              
57 226 50 0     564 if(ref $item eq 'HASH')
    0          
58             {
59 226 100       557 if($entry = delete $item->{'entry'})
60             {
61 2         11 $domain = delete $item->{'domain'};
62 2         7 $type = delete $item->{'type'};
63              
64 2 50       9 if(keys(%$item))
65             {
66 0         0 Carp::croak "If an 'entry' parameter is passed, no other ",
67             "parameters (other than 'domain' and 'type') ",
68             "may be passed";
69             }
70             }
71             else
72             {
73 224         1553 $entry = Rose::DB::Registry::Entry->new(%$item);
74             }
75             }
76             elsif(ref $item && $item->isa('Rose::DB::Registry::Entry'))
77             {
78 0         0 $entry = $item;
79             }
80 0         0 else { Carp::croak "Don't know how to add registry entry '$item'" }
81              
82 226 100       4469 $domain = $entry->domain unless(defined $domain);
83 226 100       603 $type = $entry->type unless(defined $type);
84              
85 226 100       499 unless(defined $domain)
86             {
87 4         12 $domain = $parent->default_domain;
88 4         38 $entry->domain($domain);
89             }
90              
91 226 100       434 unless(defined $type)
92             {
93 4         10 $type = $parent->default_type;
94 4         35 $entry->type($type);
95             }
96              
97 226 50       505 Carp::confess "$parent - Missing domain for registry entry: domain '$domain', type '$type'"
98             unless(defined $domain);
99              
100 226 50       431 Carp::confess "$parent - Missing type for registry entry: domain '$domain', type '$type'"
101             unless(defined $type);
102              
103 226 50       524 Carp::confess "$parent - Missing driver for registry entry: domain '$domain', type '$type'"
104             unless(defined $entry->driver);
105              
106 226         846 $entries->{$domain}{$type} = $entry;
107 226         546 push(@added, $entry);
108             }
109              
110 226 50       830 return wantarray ? @added : \@added;
111             }
112              
113             sub add_entry
114             {
115 226     226 1 2530 my($self) = shift;
116              
117             # Smuggle parent in with an otherwise nonsensical arrayref arg
118 226 100       765 my $parent = shift if(ref $_[0] eq 'ARRAY');
119              
120 226 50 33     1009 if(@_ == 1 || (ref $_[0] && $_[0]->isa('Rose::DB::Registry::Entry')))
      33        
121             {
122 0 0       0 return ($self->add_entries(($parent ? $parent : ()), @_))[0];
123             }
124              
125 226 100       2177 return ($self->add_entries(($parent ? $parent : ()), { @_ }))[0];
126             }
127              
128             sub entry_exists
129             {
130 22     22 1 283 my($self, %args) = @_;
131              
132             Carp::croak "Missing required 'type' argument"
133 22 50       62 unless(defined $args{'type'});
134              
135             Carp::croak "Missing required 'domain' argument"
136 22 50       48 unless(defined $args{'domain'});
137              
138 22         90 return exists $self->hash->{$args{'domain'}}{$args{'type'}};
139             }
140              
141             sub delete_entry
142             {
143 0     0 1 0 my($self, %args) = @_;
144 0 0       0 return undef unless($self->entry_exists(%args));
145 0         0 return delete $self->hash->{$args{'domain'}}{$args{'type'}};
146             }
147              
148             sub entry
149             {
150 8     8 1 905 my($self, %args) = @_;
151 8 50       33 return undef unless($self->entry_exists(%args));
152 8         95 return $self->hash->{$args{'domain'}}{$args{'type'}};
153             }
154              
155             sub delete_domain
156             {
157 0     0 1 0 my($self, $domain) = @_;
158 0         0 my $entries = $self->hash;
159 0         0 delete $entries->{$domain};
160             }
161              
162             sub registered_types
163             {
164 10     10 1 61 my($self, $domain) = @_;
165 10 50       20 my @types = sort keys %{ $self->hash->{$domain} || {} };
  10         25  
166 10 100       164 return wantarray ? @types : \@types;
167             }
168              
169             sub registered_domains
170             {
171 4     4 1 87 my @domains = sort keys %{ shift->hash };
  4         13  
172 4 100       63 return wantarray ? @domains : \@domains;
173             }
174              
175             sub dump
176             {
177 2     2 1 1535 my($self) = shift;
178              
179 2         9 my $entries = $self->hash;
180 2         14 my %reg;
181              
182 2         6 foreach my $domain ($self->registered_domains)
183             {
184 8         20 foreach my $type ($self->registered_types($domain))
185             {
186 34         115 $reg{$domain}{$type} = $entries->{$domain}{$type}->dump;
187             }
188             }
189              
190 2         10 return \%reg;
191             }
192              
193             1;
194              
195             __END__
196              
197             =head1 NAME
198              
199             Rose::DB::Registry - Data source registry.
200              
201             =head1 SYNOPSIS
202              
203             use Rose::DB::Registry;
204              
205             $registry = Rose::DB::Registry->new;
206              
207             $registry->add_entry(
208             domain => 'development',
209             type => 'main',
210             driver => 'Pg',
211             database => 'dev_db',
212             host => 'localhost',
213             username => 'devuser',
214             password => 'mysecret',
215             server_time_zone => 'UTC');
216              
217             $entry = Rose::DB::Registry::Entry->new(
218             domain => 'production',
219             type => 'main',
220             driver => 'Pg',
221             database => 'big_db',
222             host => 'dbserver.acme.com',
223             username => 'dbadmin',
224             password => 'prodsecret',
225             server_time_zone => 'UTC');
226              
227             $registry->add_entry($entry);
228              
229             $entry = $registry->entry(domain => 'development', type => 'main');
230              
231             $registry->entry_exists(domain => 'foo', type => 'bar'); # false
232              
233             $registry->delete_entry(domain => 'development', type => 'main');
234              
235             ...
236              
237             =head1 DESCRIPTION
238              
239             L<Rose::DB::Registry> objects manage information about L<Rose::DB> data sources. Each data source has a corresponding L<Rose::DB::Registry::Entry> object that contains its information. The registry entries are organized in a two-level namespace based on a "domain" and a "type." See the L<Rose::DB> documentation for more information on data source domains and types.
240              
241             L<Rose::DB::Registry> inherits from, and follows the conventions of, L<Rose::Object>. See the L<Rose::Object> documentation for more information.
242              
243             =head1 CONSTRUCTOR
244              
245             =over 4
246              
247             =item B<new PARAMS>
248              
249             Constructs a L<Rose::DB::Registry> object based on PARAMS, where PARAMS are
250             name/value pairs. Any object method is a valid parameter name.
251              
252             =back
253              
254             =head1 OBJECT METHODS
255              
256             =over 4
257              
258             =item B<add_entries ENTRY1 [, ENTRY2, ...]>
259              
260             Add registry entries. Each ENTRY must be either a L<Rose::DB::Registry::Entry>-derived object or reference to a hash of name/value pairs. The name/value pairs must be valid arguments for L<Rose::DB::Registry::Entry>'s constructor.
261              
262             Each ENTRY must have a defined domain and type, either in the L<Rose::DB::Registry::Entry>-derived object or in the name/value pairs. A fatal error will occur if these values are not defined.
263              
264             If a registry entry for the specified domain and type already exists, then the new entry will overwrite it. If you want to know beforehand whether or not an entry exists under a specific domain and type, use the L<entry_exists|/entry_exists> method.
265              
266             Returns a list (in list context) or reference to an array (in scalar context) of L<Rose::DB::Registry::Entry> objects added.
267              
268             =item B<add_entry ENTRY>
269              
270             Add a registry entry. ENTRY must be either a L<Rose::DB::Registry::Entry>-derived object or a list of name/value pairs. The name/value pairs must be valid arguments for L<Rose::DB::Registry::Entry>'s constructor.
271              
272             The ENTRY must have a defined domain and type, either in the L<Rose::DB::Registry::Entry>-derived object or in the name/value pairs. A fatal error will occur if these values are not defined.
273              
274             If a registry entry for the specified domain and type already exists, then the new entry will overwrite it. If you want to know beforehand whether or not an entry exists under a specific domain and type, use the L<entry_exists|/entry_exists> method.
275              
276             Returns the L<Rose::DB::Registry::Entry> object added.
277              
278             =item B<dump>
279              
280             Returns a reference to a hash containing information about all registered data sources. The hash is structured like this:
281              
282             {
283             domain1 =>
284             {
285             type1 =>
286             {
287             # Rose::DB::Registry::Entry attributes
288             # generated by its dump() method
289             driver => ...,
290             database => ...,
291             host => ...,
292             ...
293             },
294              
295             type2 =>
296             {
297             ...
298             },
299             ...
300             },
301              
302             domain2 =>
303             {
304             ...
305             },
306              
307             ...
308             }
309              
310             All the registry entry attribute values are copies, not the actual values.
311              
312             =item B<delete_domain DOMAIN>
313              
314             Delete an entire domain, including all the registry entries under that domain.
315              
316             =item B<delete_entry PARAMS>
317              
318             Delete the registry entry specified by PARAMS, where PARAMS must be name/value pairs with defined values for C<domain> and C<type>. A fatal error will occur if either one is missing or undefined.
319              
320             If the specified entry does not exist, undef is returned. Otherwise, the deleted entry is returned.
321              
322             =item B<entry PARAMS>
323              
324             Get the registry entry specified by PARAMS, where PARAMS must be name/value pairs with defined values for C<domain> and C<type>. A fatal error will occur if either one is missing or undefined. If the specified entry does not exist, undef is returned.
325              
326             =item B<entry_exists PARAMS>
327              
328             Returns true if the registry entry specified by PARAMS exists, false otherwise. PARAMS must be name/value pairs with defined values for C<domain> and C<type>. A fatal error will occur if either one is missing or undefined.
329              
330             =item B<registered_types DOMAIN>
331              
332             Returns a list (in list context) or reference to an array (in scalar context) of the names of all registered types under the domain named DOMAIN.
333              
334             =item B<registered_domains>
335              
336             Returns a list (in list context) or reference to an array (in scalar context) of the names of all registered domains.
337              
338             =back
339              
340             =head1 AUTHOR
341              
342             John C. Siracusa (siracusa@gmail.com)
343              
344             =head1 LICENSE
345              
346             Copyright (c) 2010 by John C. Siracusa. All rights reserved. This program is
347             free software; you can redistribute it and/or modify it under the same terms
348             as Perl itself.