| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Badger::Config::Item; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 7 |  |  | 7 |  | 41 | use Badger::Debug ':dump'; | 
|  | 7 |  |  |  |  | 9 |  | 
|  | 7 |  |  |  |  | 35 |  | 
| 4 |  |  |  |  |  |  | use Badger::Class | 
| 5 | 7 |  |  |  |  | 126 | version   => 0.01, | 
| 6 |  |  |  |  |  |  | debug     => 0, | 
| 7 |  |  |  |  |  |  | base      => 'Badger::Base', | 
| 8 |  |  |  |  |  |  | import    => 'class CLASS', | 
| 9 |  |  |  |  |  |  | utils     => 'blessed', | 
| 10 |  |  |  |  |  |  | accessors => 'name arity', | 
| 11 |  |  |  |  |  |  | constants => 'DELIMITER ARRAY HASH', | 
| 12 |  |  |  |  |  |  | constant  => { | 
| 13 |  |  |  |  |  |  | ARITY_ITEM => 1, | 
| 14 |  |  |  |  |  |  | ARITY_LIST => 2, | 
| 15 |  |  |  |  |  |  | ARITY_HASH => 3, | 
| 16 |  |  |  |  |  |  | }, | 
| 17 |  |  |  |  |  |  | alias     => { | 
| 18 |  |  |  |  |  |  | init  => \&init_item, | 
| 19 |  |  |  |  |  |  | }, | 
| 20 |  |  |  |  |  |  | messages  => { | 
| 21 |  |  |  |  |  |  | bad_type     => 'Invalid type prefix specified for %s: %s', | 
| 22 |  |  |  |  |  |  | bad_method   => 'Missing method for the %s %s configuration item: %s', | 
| 23 |  |  |  |  |  |  | dup_item     => 'Duplicate specification for scheme item: %s', | 
| 24 |  |  |  |  |  |  | bad_fallback => 'Invalid fallback item specified for %s: %s', | 
| 25 |  |  |  |  |  |  | no_value     => 'No value specified for the %s configuration item', | 
| 26 |  |  |  |  |  |  | no_key_value => 'No value specified for the <2> key of the <1> configuration item', | 
| 27 | 7 |  |  | 7 |  | 49 | }; | 
|  | 7 |  |  |  |  | 11 |  | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | our $ARITY = { | 
| 30 |  |  |  |  |  |  | '$' => ARITY_ITEM, | 
| 31 |  |  |  |  |  |  | '@' => ARITY_LIST, | 
| 32 |  |  |  |  |  |  | '%' => ARITY_HASH, | 
| 33 |  |  |  |  |  |  | }; | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | sub init_item { | 
| 36 | 59 |  |  | 59 | 0 | 91 | my ($self, $config) = @_; | 
| 37 | 59 |  |  |  |  | 63 | my ($name, @aka, $alias, $fallback, $test); | 
| 38 |  |  |  |  |  |  |  | 
| 39 | 59 |  | 33 |  |  | 102 | my $fall = delete $config->{ fallback_provider } || $self; | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 59 |  |  |  |  | 60 | $self->debug("Generating config item: ", $self->dump_data($config)) | 
| 42 |  |  |  |  |  |  | if DEBUG; | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | $name = $config->{ name } | 
| 45 | 59 |  | 50 |  |  | 107 | || return $self->error_msg( missing => 'name' ); | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | # A '!' at the end of the name indicates it's mandatory. | 
| 48 |  |  |  |  |  |  | # A '=value' at the end indicates a default value. | 
| 49 | 59 | 100 |  |  |  | 186 | $self->{ required } = ($name =~ s/!$//)        ?  1 : $config->{ required }; | 
| 50 | 59 | 100 |  |  |  | 175 | $self->{ default  } = ($name =~ s/=(\w\S*)$//) ? $1 : $config->{ default  }; | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  | # Alternately, '=$XXX', '=@XXX' or '=%XXX' can be used to indicate that | 
| 53 |  |  |  |  |  |  | # the options takes one 'XXX' argument, multiple 'XXX' arguments or key | 
| 54 |  |  |  |  |  |  | # values/pairs where the values are 'XXX' arguments | 
| 55 | 59 | 50 |  |  |  | 112 | if ($name =~ s/=([\$\@\%])(.+)$//) { | 
| 56 | 0 |  |  |  |  | 0 | $self->debug("config item: $name [$1] [$2]") if DEBUG; | 
| 57 | 0 |  |  |  |  | 0 | $config->{ arity } = $ARITY->{ $1 }; | 
| 58 | 0 |  |  |  |  | 0 | $config->{ args  } = $2; | 
| 59 |  |  |  |  |  |  | } | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | # name can be 'name|alias1|alias2|...' | 
| 63 | 59 |  |  |  |  | 153 | ($name, @aka) = split(/\|/, $name); | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | # alias can be specified as hash ref or string | 
| 66 | 59 |  | 50 |  |  | 160 | $alias = $config->{ alias } || { }; | 
| 67 | 59 | 50 |  |  |  | 93 | $alias = [ split(DELIMITER, $alias) ] | 
| 68 |  |  |  |  |  |  | unless ref $alias; | 
| 69 | 59 | 50 |  |  |  | 97 | $alias = { map { $_ => $name } @$alias } | 
|  | 0 |  |  |  |  | 0 |  | 
| 70 |  |  |  |  |  |  | if ref $alias eq ARRAY; | 
| 71 | 59 | 50 |  |  |  | 83 | return $self->error_msg( invalid => alias => $alias ) | 
| 72 |  |  |  |  |  |  | unless ref $alias eq HASH; | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | # aliases, and more generally, fallbacks, can be specified as a list ref | 
| 75 |  |  |  |  |  |  | # or string which we split | 
| 76 | 59 |  |  |  |  | 59 | $self->debug("fallback: ", $self->dump_data($config->{ fallback })) if DEBUG; | 
| 77 |  |  |  |  |  |  |  | 
| 78 | 59 |  | 100 |  |  | 149 | $fallback = $config->{ fallback } || [ ]; | 
| 79 | 59 | 100 |  |  |  | 102 | $fallback = [ split(DELIMITER, $fallback) ] | 
| 80 |  |  |  |  |  |  | unless ref $fallback eq ARRAY; | 
| 81 | 59 |  |  |  |  | 89 | push(@$fallback, @aka); | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 59 |  |  |  |  | 49 | $self->debug("fallbacks: ", $self->dump_data($fallback)) if DEBUG; | 
| 84 |  |  |  |  |  |  |  | 
| 85 | 59 |  |  |  |  | 77 | foreach my $item (@$fallback) { | 
| 86 | 62 | 100 |  |  |  | 158 | unless ($item =~ /:/) { | 
| 87 | 22 |  |  |  |  | 40 | $alias->{ $item } = $name; | 
| 88 | 22 |  |  |  |  | 31 | next; | 
| 89 |  |  |  |  |  |  | } | 
| 90 | 40 |  |  |  |  | 75 | my ($type, $data) = split(/:/, $item, 2); | 
| 91 | 40 |  | 50 |  |  | 82 | $item = $fall->fallback($name, $type, $data) | 
| 92 |  |  |  |  |  |  | || return $self->error_msg( bad_type => $name, $type ); | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | # add any aliases specified as part of the name and bind them | 
| 96 |  |  |  |  |  |  | # back into the field info hash | 
| 97 | 59 |  |  |  |  | 73 | $self->{ fallback } = $fallback; | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | # this is getting way too large... but I just want to get things working | 
| 100 |  |  |  |  |  |  | # before I start paring things down | 
| 101 | 59 |  |  |  |  | 70 | $self->{ name    } = $name; | 
| 102 | 59 |  |  |  |  | 71 | $self->{ alias   } = $alias; | 
| 103 | 59 |  | 33 |  |  | 145 | $self->{ message } = $config->{ message } || $config->{ error }; | 
| 104 | 59 |  |  |  |  | 70 | $self->{ action  } = $config->{ action  }; | 
| 105 | 59 |  |  |  |  | 122 | $self->{ method  } = $config->{ method  }; | 
| 106 | 59 |  |  |  |  | 62 | $self->{ about   } = $config->{ about   }; | 
| 107 | 59 |  |  |  |  | 114 | $self->{ args    } = $config->{ args    }; | 
| 108 | 59 |  | 50 |  |  | 143 | $self->{ arity   } = $config->{ arity   } || 0; | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 59 |  |  |  |  | 68 | $self->debug( | 
| 111 |  |  |  |  |  |  | "Configured configuration item: ", $self->dump | 
| 112 |  |  |  |  |  |  | ) if DEBUG; | 
| 113 |  |  |  |  |  |  |  | 
| 114 | 59 |  |  |  |  | 128 | return $self; | 
| 115 |  |  |  |  |  |  | } | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | sub fallback { | 
| 119 | 0 |  |  | 0 | 0 | 0 | shift->not_implemented; | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | sub names { | 
| 123 | 71 |  |  | 71 | 0 | 73 | my $self  = shift; | 
| 124 | 71 |  |  |  |  | 82 | my @names = ($self->{ name }, keys %{ $self->{ alias } }); | 
|  | 71 |  |  |  |  | 180 |  | 
| 125 |  |  |  |  |  |  | return wantarray | 
| 126 |  |  |  |  |  |  | ?  @names | 
| 127 | 71 | 50 |  |  |  | 186 | : \@names; | 
| 128 |  |  |  |  |  |  | } | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | sub configure { | 
| 132 | 267 |  |  | 267 | 0 | 361 | my ($self, $config, $target, $class) = @_; | 
| 133 | 267 |  |  |  |  | 258 | my ($name, $alias, $code, @args, $ok, $value); | 
| 134 |  |  |  |  |  |  |  | 
| 135 | 267 |  | 33 |  |  | 419 | $class ||= $target; | 
| 136 |  |  |  |  |  |  |  | 
| 137 | 267 |  |  |  |  | 212 | $self->debug("configure(", CLASS->dump_data_inline($config), ')') if DEBUG; | 
| 138 | 267 |  |  |  |  | 213 | $self->debug("item is ", $self->dump_data($self)) if DEBUG; | 
| 139 |  |  |  |  |  |  | #    $self->debug("items: ", CLASS->dump_data($items)) if DEBUG; | 
| 140 |  |  |  |  |  |  |  | 
| 141 | 267 |  |  |  |  | 448 | $name = $self->{ name }; | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | # TODO: abstract out action calls. | 
| 144 |  |  |  |  |  |  |  | 
| 145 | 267 | 50 |  |  |  | 257 | FALLBACK: foreach $alias ($name, @{ $self->{ fallback } || [ ] }) { | 
|  | 267 |  |  |  |  | 484 |  | 
| 146 | 495 | 50 |  |  |  | 626 | next unless defined $alias; | 
| 147 |  |  |  |  |  |  |  | 
| 148 | 495 | 100 |  |  |  | 762 | if (ref $alias eq ARRAY) { | 
|  |  | 100 |  |  |  |  |  | 
| 149 | 102 |  |  |  |  | 172 | ($code, @args) = @$alias; | 
| 150 |  |  |  |  |  |  | #$self->todo('calling code'); | 
| 151 | 102 |  |  |  |  | 193 | ($ok, $value) = $code->($class, $name, $config, $target, @args); | 
| 152 | 102 | 100 |  |  |  | 180 | if ($ok) { | 
| 153 | 92 |  |  |  |  | 166 | return $self->set($target, $name, $value, $class); | 
| 154 |  |  |  |  |  |  | } | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  | elsif (defined $config->{ $alias }) { | 
| 157 | 71 |  |  |  |  | 55 | $self->debug("Found value for $name ($alias): $config->{ $alias }\n") if DEBUG; | 
| 158 | 71 |  |  |  |  | 130 | return $self->set($target, $name, $config->{ $alias }, $class); | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  | else { | 
| 161 | 322 |  |  |  |  | 305 | $self->debug("Nothing found for $alias to set $name\n") if DEBUG; | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 | 104 | 100 |  |  |  | 165 | if (defined $self->{ default }) { | 
| 166 | 13 |  |  |  |  | 11 | $self->debug("setting to default value: $self->{ default }\n") if DEBUG; | 
| 167 | 13 |  |  |  |  | 28 | return $self->set($target, $name, $self->{ default }, $class); | 
| 168 |  |  |  |  |  |  | } | 
| 169 |  |  |  |  |  |  |  | 
| 170 | 91 | 100 |  |  |  | 111 | if ($self->{ required }) { | 
| 171 | 1 |  |  |  |  | 2 | $self->debug("$name is required, throwing error\n") if DEBUG; | 
| 172 | 1 |  | 50 |  |  | 18 | return $self->error_msg( $self->{ message } || missing => $name ); | 
| 173 |  |  |  |  |  |  | } | 
| 174 |  |  |  |  |  |  |  | 
| 175 | 90 |  |  |  |  | 167 | return $self; | 
| 176 |  |  |  |  |  |  | } | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | sub set { | 
| 180 | 176 |  |  | 176 | 0 | 452 | my ($self, $target, $name, $value, $object) = @_; | 
| 181 | 176 |  |  |  |  | 165 | my $method; | 
| 182 |  |  |  |  |  |  |  | 
| 183 | 176 |  | 33 |  |  | 226 | $object ||= $target; | 
| 184 |  |  |  |  |  |  |  | 
| 185 | 176 |  |  |  |  | 148 | $self->debug("set($target, $name, $value)") if DEBUG; | 
| 186 |  |  |  |  |  |  |  | 
| 187 | 176 | 50 |  |  |  | 314 | if ($self->{ arity } == ARITY_LIST) { | 
|  |  | 50 |  |  |  |  |  | 
| 188 | 0 |  | 0 |  |  | 0 | my $list = $target->{ $name } ||= [ ]; | 
| 189 | 0 |  |  |  |  | 0 | push(@$list, $value); | 
| 190 |  |  |  |  |  |  | } | 
| 191 |  |  |  |  |  |  | elsif ($self->{ arity } == ARITY_HASH) { | 
| 192 | 0 | 0 |  |  |  | 0 | return $self->error_msg( invalid => 'key/value pair' => $value) | 
| 193 |  |  |  |  |  |  | unless ref $value eq ARRAY; | 
| 194 |  |  |  |  |  |  |  | 
| 195 | 0 |  | 0 |  |  | 0 | my $hash = $target->{ $name } ||= { }; | 
| 196 | 0 |  |  |  |  | 0 | $hash->{ $value->[0] } = $value->[1]; | 
| 197 |  |  |  |  |  |  | } | 
| 198 |  |  |  |  |  |  | else { | 
| 199 | 176 |  |  |  |  | 282 | $target->{ $name } = $value; | 
| 200 |  |  |  |  |  |  | } | 
| 201 |  |  |  |  |  |  |  | 
| 202 | 176 | 50 |  |  |  | 267 | $self->{ action }->($self, $name, $value) if $self->{ action }; | 
| 203 |  |  |  |  |  |  |  | 
| 204 | 176 | 50 | 66 |  |  | 623 | if (blessed($object) && ($method = $self->{ method })) { | 
| 205 | 0 |  |  |  |  | 0 | $self->debug("calling method $method on object $object\n") if DEBUG; | 
| 206 | 0 |  |  |  |  | 0 | $object->$method($name, $value); | 
| 207 |  |  |  |  |  |  | } | 
| 208 |  |  |  |  |  |  |  | 
| 209 | 176 |  |  |  |  | 495 | return $self; | 
| 210 |  |  |  |  |  |  | } | 
| 211 |  |  |  |  |  |  |  | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | # this is being replaced by Badger::Config::Reader::Args | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  | sub args { | 
| 216 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 217 | 0 |  |  |  |  |  | my $args = shift; | 
| 218 | 0 |  |  |  |  |  | my $value; | 
| 219 |  |  |  |  |  |  |  | 
| 220 | 0 | 0 |  |  |  |  | if ($self->{ args }) { | 
| 221 | 0 |  |  |  |  |  | $self->debug("looking for $self->{ name } arg in ", $self->dump_data($args)) if DEBUG; | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | return $self->error_msg( no_value => $self->{ name } ) | 
| 224 | 0 | 0 | 0 |  |  |  | unless @$args && defined $args->[0] && $args->[0] !~ /^-/; | 
|  |  |  | 0 |  |  |  |  | 
| 225 |  |  |  |  |  |  |  | 
| 226 | 0 |  |  |  |  |  | $value = shift @$args; | 
| 227 |  |  |  |  |  |  |  | 
| 228 | 0 | 0 |  |  |  |  | if ($self->{ arity } == ARITY_HASH) { | 
| 229 | 0 |  |  |  |  |  | my $key = $value; | 
| 230 | 0 | 0 | 0 |  |  |  | return $self->error_msg( no_key_value => $self->{ name }, $key ) | 
|  |  |  | 0 |  |  |  |  | 
| 231 |  |  |  |  |  |  | unless @$args && defined $args->[0] && $args->[0] !~ /^-/; | 
| 232 | 0 |  |  |  |  |  | $value = shift @$args; | 
| 233 | 0 |  |  |  |  |  | $value = [ $key, $value ]; | 
| 234 |  |  |  |  |  |  | } | 
| 235 |  |  |  |  |  |  | } | 
| 236 |  |  |  |  |  |  | else { | 
| 237 | 0 |  |  |  |  |  | $value = 1; | 
| 238 |  |  |  |  |  |  | } | 
| 239 |  |  |  |  |  |  | # this is all the wrong way around - quick hack | 
| 240 | 0 |  |  |  |  |  | return $self->configure({ $self->{ name } => $value }, @_); | 
| 241 |  |  |  |  |  |  | } | 
| 242 |  |  |  |  |  |  |  | 
| 243 |  |  |  |  |  |  | # temporary method providing access to args value | 
| 244 |  |  |  |  |  |  | sub has_args { | 
| 245 | 0 |  |  | 0 | 0 |  | shift->{ args }; | 
| 246 |  |  |  |  |  |  | } | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | sub hash_arity { | 
| 249 | 0 |  |  | 0 | 0 |  | shift->{ arity } == ARITY_HASH; | 
| 250 |  |  |  |  |  |  | } | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | sub list_arity { | 
| 253 | 0 |  |  | 0 | 0 |  | shift->{ arity } == ARITY_LIST; | 
| 254 |  |  |  |  |  |  | } | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | sub summary { | 
| 257 | 0 |  |  | 0 | 0 |  | my ($self, $reporter) = @_; | 
| 258 | 0 |  |  |  |  |  | my $name  = $self->{ name }; | 
| 259 | 0 |  | 0 |  |  |  | my $args  = $self->{ args }  || ''; | 
| 260 | 0 |  | 0 |  |  |  | my $about = $self->{ about } || ''; | 
| 261 | 0 | 0 |  |  |  |  | if (length $args) { | 
| 262 | 0 |  |  |  |  |  | $args =~ s/\s+/> | 
| 263 | 0 |  |  |  |  |  | $args = " <$args>"; | 
| 264 |  |  |  |  |  |  | } | 
| 265 | 0 | 0 |  |  |  |  | return $reporter | 
| 266 |  |  |  |  |  |  | ? $reporter->option( $name.$args, $about ) | 
| 267 |  |  |  |  |  |  | : sprintf('--%-20s %s', $name.$args, $about); | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | 1; |