| 1 | # $Id$ |
|---|
| 2 | |
|---|
| 3 | package Class::Data::ConfigHash; |
|---|
| 4 | use strict; |
|---|
| 5 | use warnings; |
|---|
| 6 | use base qw(Class::Data::Inheritable); |
|---|
| 7 | our $VERSION = '0.00001'; |
|---|
| 8 | |
|---|
| 9 | __PACKAGE__->mk_classdata(_config => {}); |
|---|
| 10 | |
|---|
| 11 | sub config { |
|---|
| 12 | my $self = shift; |
|---|
| 13 | my $config_sub = $self->can('_config'); |
|---|
| 14 | my $config = $self->$config_sub() || {}; |
|---|
| 15 | if (@_) { |
|---|
| 16 | my $newconfig = { %{@_ > 1 ? {@_} : ($_[0] || {})} }; |
|---|
| 17 | $self->_config( |
|---|
| 18 | $self->merge_config_hashes( $config, $newconfig ) |
|---|
| 19 | ); |
|---|
| 20 | } else { |
|---|
| 21 | # this is a bit of a kludge, required to make |
|---|
| 22 | # __PACKAGE__->config->{foo} = 'bar'; |
|---|
| 23 | # work in a subclass. Calling the Class::Data::Inheritable setter |
|---|
| 24 | # will create a new _config method in the current class if it's |
|---|
| 25 | # currently inherited from the superclass. So, the can() call will |
|---|
| 26 | # return a different subref in that case and that means we know to |
|---|
| 27 | # copy and reset the value stored in the class data. |
|---|
| 28 | |
|---|
| 29 | $self->_config( $config ); |
|---|
| 30 | |
|---|
| 31 | if ((my $config_sub_now = $self->can('_config')) ne $config_sub) { |
|---|
| 32 | |
|---|
| 33 | $config = $self->merge_config_hashes( $config, {} ); |
|---|
| 34 | $self->$config_sub_now( $config ); |
|---|
| 35 | } |
|---|
| 36 | } |
|---|
| 37 | return $config; |
|---|
| 38 | } |
|---|
| 39 | |
|---|
| 40 | sub merge_config_hashes |
|---|
| 41 | { |
|---|
| 42 | my ($self, $lefthash, $righthash) = @_; |
|---|
| 43 | return __merge_hashes($lefthash, $righthash); |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | sub __merge_hashes |
|---|
| 47 | { |
|---|
| 48 | # XXX - If Catalyst is in effect, we might just as well use |
|---|
| 49 | # Catalyst::Utils::merge_hashes, I suppose. |
|---|
| 50 | my ( $lefthash, $righthash ) = @_; |
|---|
| 51 | |
|---|
| 52 | if ( !defined $righthash ) { |
|---|
| 53 | return $lefthash; |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | if ( !defined $lefthash ) { |
|---|
| 57 | return $righthash; |
|---|
| 58 | } |
|---|
| 59 | |
|---|
| 60 | my %merged = %{$lefthash}; |
|---|
| 61 | for my $key ( keys %{$righthash} ) { |
|---|
| 62 | my $right_ref = ( ref $righthash->{$key} || '' ) eq 'HASH'; |
|---|
| 63 | my $left_ref = |
|---|
| 64 | ( ( exists $lefthash->{$key} && ref $lefthash->{$key} ) || '' ) eq |
|---|
| 65 | 'HASH'; |
|---|
| 66 | if ( $right_ref and $left_ref ) { |
|---|
| 67 | $merged{$key} = |
|---|
| 68 | __merge_hashes( $lefthash->{$key}, $righthash->{$key} ); |
|---|
| 69 | } |
|---|
| 70 | else { |
|---|
| 71 | $merged{$key} = $righthash->{$key}; |
|---|
| 72 | } |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | return \%merged; |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | 1; |
|---|
| 79 | |
|---|
| 80 | __END__ |
|---|
| 81 | |
|---|
| 82 | =head1 NAME |
|---|
| 83 | |
|---|
| 84 | Class::Data::ConfigHash - Add Catalyst-Style Config To Your Class |
|---|
| 85 | |
|---|
| 86 | =head1 NAME |
|---|
| 87 | |
|---|
| 88 | package MyClass; |
|---|
| 89 | use base qw(Class::Data::ConfigHash); |
|---|
| 90 | |
|---|
| 91 | __PACKAGE__->config( |
|---|
| 92 | foo => 'bar' |
|---|
| 93 | ); |
|---|
| 94 | |
|---|
| 95 | =head1 DESCRIPTION |
|---|
| 96 | |
|---|
| 97 | I often times find myself wanting a per-class config that can be used to |
|---|
| 98 | provide sane class-level defaults, but with the ability to easily customize |
|---|
| 99 | the values at run time. |
|---|
| 100 | |
|---|
| 101 | package MyClass; |
|---|
| 102 | __PACKAGE__->config({ |
|---|
| 103 | foo => 1, |
|---|
| 104 | bar => 2 |
|---|
| 105 | }); |
|---|
| 106 | |
|---|
| 107 | # Later, in perhaps an initialize hook somewhere |
|---|
| 108 | my %config = read_config_from_file() ; # say, %config = ( foo => 3 ) |
|---|
| 109 | MyClass->config(\%config); |
|---|
| 110 | |
|---|
| 111 | MyClass->config->{foo}; # yields 3 |
|---|
| 112 | MyClass->config->{bar}; # yields 2 |
|---|
| 113 | |
|---|
| 114 | The idea is that you can hardcode the defaults in your class, but you can also |
|---|
| 115 | easily override them by merging the original hash with a newly given hash. |
|---|
| 116 | This feature is handled beautifully in Catalyst. |
|---|
| 117 | |
|---|
| 118 | So there, this module is basically that feature from Catalyst ripped out to a |
|---|
| 119 | separate module so it can be used elsewhere. |
|---|
| 120 | |
|---|
| 121 | To use, simply subclass it in your module: |
|---|
| 122 | |
|---|
| 123 | package MyClass; |
|---|
| 124 | use base qw(Class::Data::ConfigHash); |
|---|
| 125 | |
|---|
| 126 | Done! Now you can use ->config in MyClass. |
|---|
| 127 | |
|---|
| 128 | =head1 METHODS |
|---|
| 129 | |
|---|
| 130 | =head2 config([\%hash]) |
|---|
| 131 | |
|---|
| 132 | Accessor for the underlying config. |
|---|
| 133 | |
|---|
| 134 | # set |
|---|
| 135 | $class->config(\%hash); |
|---|
| 136 | $class->config->{whatever} = 'foo'; |
|---|
| 137 | |
|---|
| 138 | # get |
|---|
| 139 | $class->config->{whatever}; |
|---|
| 140 | |
|---|
| 141 | If given a hashref argument, the values in the hashref are merged with whatever |
|---|
| 142 | values that existed prior to that. This merge is performed recursively to the |
|---|
| 143 | entire hash. |
|---|
| 144 | |
|---|
| 145 | =head2 merge_config_hashes(\%lefthash, \%righthash) |
|---|
| 146 | |
|---|
| 147 | Merges the two config hashes. |
|---|
| 148 | |
|---|
| 149 | =head1 CREDITS |
|---|
| 150 | |
|---|
| 151 | Sebastian Riedel, Marcus Ramberg, Matt S Trout wrote the code. |
|---|
| 152 | |
|---|
| 153 | =head1 AUTHOR |
|---|
| 154 | |
|---|
| 155 | Daisuke Maki C<< <daisuke@endeworks.jp> >> - Stole the code from Catalyst and repackaged it |
|---|
| 156 | |
|---|
| 157 | =head1 LICENSE |
|---|
| 158 | |
|---|
| 159 | This program is free software; you can redistribute it and/or modify it |
|---|
| 160 | under the same terms as Perl itself. |
|---|
| 161 | |
|---|
| 162 | See http://www.perl.com/perl/misc/Artistic.html |
|---|
| 163 | |
|---|
| 164 | =cut |
|---|