File Coverage

blib/lib/Class/Scaffold/Storable.pm
Criterion Covered Total %
statement 41 48 85.4
branch 6 12 50.0
condition n/a
subroutine 10 11 90.9
pod 3 3 100.0
total 60 74 81.0


line stmt bran cond sub pod time code
1 2     2   1211 use 5.008;
  2         7  
  2         119  
2 2     2   11 use warnings;
  2         4  
  2         49  
3 2     2   10 use strict;
  2         4  
  2         135  
4              
5             package Class::Scaffold::Storable;
6             BEGIN {
7 2     2   46 $Class::Scaffold::Storable::VERSION = '1.102280';
8             }
9              
10             # ABSTRACT: Base class for all framework classes that support a storage.
11 2     2   11 use parent 'Class::Scaffold::Base';
  2         4  
  2         11  
12             __PACKAGE__->mk_scalar_accessors(qw(storage_type))
13             ->mk_hash_accessors(qw(storage_info));
14              
15             # Don't store the storage object itself, store the method we need to call on
16             # the delegate to get the storage object. This is just a little overhead, but
17             # saves us from a lot of headache when serializing and deserializing objects
18             # with Storable's freeze() and thaw(), because storage objects can't be
19             # deserialized properly.
20             #
21             # Impose a certain order on how the constructor args are processed. We want
22             # the storage to be set first, because other properties could be defined using
23             # mk_framework_object_accessors(). Now if the args were set in an arbitrary
24             # order, the framework_object-properties could be processed before the storage
25             # is set, which would cause an error, because the storage wouldn't be set yet,
26             # so it can't be asked to make an object.
27             #
28             # We can't have storage_type as a key within the storage_info hash, because we
29             # want to be able to set it directly if passed as an argument to the
30             # constructor; we also need to be able to prefer it in
31             # Class::Scaffold::Storable::FIRST_CONSTRUCTOR_ARGS().
32             #
33             # We use the storage's signature as the id key, i.e. to find the id of the
34             # object within the storage. It would not be sufficient to use the storage's
35             # package name as the hash key because we can think of a multiplex storage
36             # that multiplexes onto two file system paths. In that case each of the
37             # multiplexed storages would have the same package name. And we can't use the
38             # storage's memory address (0x012345678) because different stages can be run
39             # within different processes and on different machines.
40             #
41             # For example, the attributes of an object of this class might look like:
42             # storage_type: core_storage
43             # storage_info:
44             # id:
45             # 'Registry::NICAT::Storage::DBI::Oracle::NICAT,dbname=db.test,dbuser=nic': id12345
46             # 'Some::File::Storage,fspath=/path/to/storage/root': id45678
47             # This example assumes that the core storage is multiplexing on a DBI storage
48             # and a file system storage.
49 2     2   256 use constant FIRST_CONSTRUCTOR_ARGS => ('storage_type');
  2         3  
  2         148  
50 2     2   11 use constant SKIP_COMPARABLE_KEYS => (qw/storage_type storage_info/);
  2         3  
  2         134  
51 2     2   10 use constant HYGIENIC => (qw/storage storage_type/);
  2         4  
  2         830  
52              
53             sub MUNGE_CONSTRUCTOR_ARGS {
54 6     6 1 581 my ($self, @args) = @_;
55              
56             # needed in order to mix object creation of a given class with and without
57             # explicitly setting the storage object for it (Erik P. Ostlyngen, NORID):
58 6 50       34 if (@args % 2 == 0) {
59 6         16 my %args = @args;
60 6 50       29 return %args if $args{storage_type};
61             }
62              
63             # The superclass does nothing, so we'll skip this for performance reasons
64             # - this method is called very often.
65             # @args = $self->SUPER::MUNGE_CONSTRUCTOR_ARGS(@args);
66 6         11 our %cache;
67 6         11 my $extra_args;
68 6 50       26 unless ($extra_args = $cache{ ref $self }) {
69 6         134 my $object_type = $self->get_my_factory_type;
70 6 100       207 if (defined $object_type) {
71 2         33 my $storage_type =
72             $self->delegate->get_storage_type_for($object_type);
73 2         12 $self->delegate->$storage_type->lazy_connect;
74              
75             # storage will be disconnected in Class::Scaffold::App->app_finish
76 2         3158 $extra_args = $cache{ ref $self } =
77             [ storage_type => $storage_type ];
78             } else {
79 4         16 $extra_args = $cache{ ref $self } = [];
80             }
81             }
82 6         36 (@args, @$extra_args);
83             }
84              
85             sub storage {
86 1     1 1 12 my $self = shift;
87 1         5 my $method = $self->storage_type;
88 1 50       8 if ($method) {
89 0         0 $self->delegate->$method;
90             } else {
91 1         3 local $Error::Depth = $Error::Depth + 1;
92 1         15 throw Error::Hierarchy::Internal::CustomMessage(custom_message =>
93             "can't find method to get storage object from delegate");
94             }
95             }
96              
97             sub id {
98 0     0 1   my $self = shift;
99 0           my $storage = shift;
100 0 0         if (@_) {
101 0           my $id = shift;
102 0           $self->storage_info->{id}{ $storage->signature } = $id;
103             } else {
104 0           $self->storage_info->{id}{ $storage->signature };
105             }
106             }
107             1;
108              
109              
110             __END__