File Coverage

lib/Spoon/Registry.pm
Criterion Covered Total %
statement 53 95 55.7
branch 6 18 33.3
condition 2 12 16.6
subroutine 12 16 75.0
pod 0 12 0.0
total 73 153 47.7


line stmt bran cond sub pod time code
1             package Spoon::Registry;
2 2     2   1464 use Spoon::Base -Base;
  2         5  
  2         20  
3 2     2   2702  
  2     2   5  
  2         68  
  2         11  
  2         6  
  2         3088  
4             const class_id => 'registry';
5             const registry_file => 'registry.dd';
6             const registry_directory => '.';
7             const lookup_class => 'Spoon::Lookup';
8              
9             field lookup =>
10             -init => '$self->load';
11             field 'temp_lookup';
12             field 'current_class_id';
13              
14 2     2 0 4 sub registry_path {
15 2         18 join '/', $self->registry_directory, $self->registry_file;
16             }
17              
18 2     2 0 17 sub load {
19 2         9 my $path = $self->registry_path;
20 2         15 my $lookup;
21 2 50       39 if (-e $path) {
22 0         0 $lookup = eval io($path)->all;
23 0 0       0 die "$path seems to be corrupt:\n$@" if $@;
24             }
25             else {
26 2         8 $lookup = $self->update->lookup;
27             }
28 2         110 $self->lookup(bless $lookup, $self->lookup_class);
29 2         102 return $self->lookup;
30             }
31              
32 2     2 0 4 sub update {
33 2         5 my $lookup = {};
34 2         54 $self->temp_lookup($lookup);
35 2         17 $self->set_core_classes;
36 2         33 for my $class_name (@{$self->hub->config->plugin_classes}) {
  2         14  
37 0         0 my $object = $self->load_class($class_name);
38 0 0       0 $self->not_a_plugin($class_name)
39             unless $object->can('register');
40 0         0 my $class_id = $self->$set_class_info($object);
41 0         0 $self->current_class_id($class_id);
42 0         0 $object->register($self);
43             }
44 2         70 $self->transform;
45 2         44 $self->lookup($self->temp_lookup);
46 2         107 return $self;
47             }
48              
49 0     0 0 0 sub not_a_plugin {
50 0         0 my $class_name = shift;
51 0         0 die "$class_name is not a plugin\n";
52             }
53              
54 10     10 0 163 sub load_class {
55 10         23 my $class_name = shift;
56 10 50       394 eval "require $class_name"; die $@ if $@;
  10         59  
57 10         76 $class_name->new;
58             }
59              
60 2     2 0 4 sub set_core_classes {
61 2         14 my %all = $self->hub->config->all;
62 2         10 my $hub = $self->hub;
63 2         10 for my $key (keys %all) {
64 22 100       349 next unless $key =~ /(.*)_class$/;
65 20         43 my $class_id = $1;
66 20         36 my $class_name = $all{$key};
67 20         489 $self->temp_lookup->{classes}{$class_id} = $class_name;
68 20   66     176 my $object = $hub->can($class_id) && $hub->$class_id ||
69             $self->load_class($class_name);
70 20         486 $self->add_classes($object);
71             }
72             }
73              
74             my sub set_class_info {
75             my $object = shift;
76             my $lookup = $self->temp_lookup;
77             my $class_name = ref $object;
78             my $class_id = $object->class_id
79             or die "No class_id for $class_name\n";
80             if (my $prev_name = $lookup->{classes}{$class_id}) {
81             $self->plugin_redefined($class_id, $class_name, $prev_name);
82             }
83             $lookup->{classes}{$class_id} = $class_name;
84             $self->add_classes($object);
85             push @{$lookup->{plugins}}, {
86             id => $class_id,
87             title => $object->class_title,
88             };
89             return $class_id;
90             }
91              
92 20     20 0 30 sub add_classes {
93 20         24 my $object = shift;
94             return unless
95 20 50       111 $object->can('inline_classes');
96 0         0 my $classes = $self->temp_lookup->{classes};
97 0         0 for my $class_name (@{$object->inline_classes}) {
  0         0  
98 0         0 my $object = $class_name->new;
99 0         0 $classes->{$object->class_id} = $class_name;
100             }
101             }
102              
103 0     0 0 0 sub plugin_redefined {}
104              
105 0     0 0 0 sub add {
106 0         0 my $class_id = $self->current_class_id;
107 0         0 my $key = shift;
108 0 0       0 if ($key eq 'hook') {
109 0         0 push @{$self->temp_lookup->{$key}}, [$class_id, @_];
  0         0  
110             }
111             else {
112 0         0 my $value = shift;
113 0         0 $self->temp_lookup->{$key}{$value} = [ $class_id, @_ ];
114 0         0 push @{$self->temp_lookup->{add_order}{$class_id}{$key}}, $value;
  0         0  
115             }
116             }
117              
118 0     0 0 0 sub write {
119 0         0 $self->dumper_to_file($self->registry_path, $self->lookup);
120             }
121              
122 2     2 0 5 sub transform {
123 2         6 $self->transform_hook;
124             }
125              
126 2     2 0 3 sub transform_hook {
127 2         46 my $lookup = $self->temp_lookup;
128 2 50       23 return unless defined $lookup->{hook};
129 0           my @hooks = @{$lookup->{hook}};
  0            
130 0           my $new_hooks = {};
131 0           for my $hook (@hooks) {
132 0           my ($class_id, $target, %args) = @$hook;
133 0           my $class_name = $lookup->{classes}{$class_id};
134 0           my ($target_class_id, $target_method) =
135             $target =~ /^(\w+):(\w+)$/;
136 0           my $target_class_name = $lookup->{classes}{$target_class_id};
137 0 0 0       die "Invalid hook '$target' in class '$class_id'\n"
      0        
      0        
138             unless $target_class_id and
139             $target_class_name and
140             ($args{pre} or $args{post});
141 0           push @{$new_hooks->{$target_class_name}}, [
  0            
142             $target_class_name . '::' .$target_method,
143             map {
144 0           my $method = $args{$_};
145 0           ($_, $class_name . '::' . $method);
146             } (keys %args),
147             ];
148             }
149 0           $self->temp_lookup->{hook} = $new_hooks;
150             }
151              
152             package Spoon::Lookup;
153 2     2   19 use Spiffy -base;
  2         6  
  2         19  
154              
155             # XXX consider an AUTOLOAD here.
156             field action => {};
157             field add_order => {};
158             field classes => {};
159             field plugins => [];
160             field preference => {};
161             field preload => {};
162             field wafl => {};
163              
164             __END__