summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Rinaldo <toddr@cpanel.net>2010-07-06 01:28:00 -0400
committerDavid Golden <dagolden@cpan.org>2010-07-06 01:30:30 -0400
commitace47d680c1383b41a705467fadb2c64e7f39c71 (patch)
tree2ab4754109d2da986b31f4a74142a027498088c3
parenta519c2cf8a56d92061e00b715b65a73dd66692c6 (diff)
downloadperl-ace47d680c1383b41a705467fadb2c64e7f39c71.tar.gz
Locale::Maketext external cache support
This patch with tests provides RO support for lexicon hashes in Locale::Maketext. This allows you to have GDBM language files owned by root which can be accessed by non-root, but not altered. If your lexicon is a tied hash the simple act of caching the compiled value can be fatal. For example a GDBM_File GDBM_READER tied hash will die with something like: gdbm store returned -1, errno 2, key "..." at ... All you need to do is turn on caching outside of the lexicon hash itself like so: sub init { my ($lh) = @_; ... $lh->{'use_external_lex_cache'} = 1; ... } And then instead of storing the compiled value in the lexicon hash it will store it in $lh->{'_external_lex_cache'} I've verified that blead is the authoritative location for Locale::Maketext source. Signed-off-by: David Golden <dagolden@cpan.org>
-rw-r--r--MANIFEST1
-rw-r--r--dist/Locale-Maketext/lib/Locale/Maketext.pm57
-rw-r--r--dist/Locale-Maketext/lib/Locale/Maketext.pod19
-rw-r--r--dist/Locale-Maketext/t/04_use_external_lex_cache.t40
4 files changed, 97 insertions, 20 deletions
diff --git a/MANIFEST b/MANIFEST
index b97e7de6df..a600a0a538 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -2730,6 +2730,7 @@ dist/Locale-Maketext/lib/Locale/Maketext.pod Locale::Maketext documentation
dist/Locale-Maketext/lib/Locale/Maketext/TPJ13.pod Locale::Maketext documentation article
dist/Locale-Maketext/README Locale::Maketext
dist/Locale-Maketext/t/01_about_verbose.t See if Locale::Maketext works
+dist/Locale-Maketext/t/04_use_external_lex_cache.t See if Locale::Maketext works
dist/Locale-Maketext/t/10_make.t See if Locale::Maketext works
dist/Locale-Maketext/t/20_get.t See if Locale::Maketext works
dist/Locale-Maketext/t/30_local.t See if Locale::Maketext works
diff --git a/dist/Locale-Maketext/lib/Locale/Maketext.pm b/dist/Locale-Maketext/lib/Locale/Maketext.pm
index 1bfbbc9bba..7a10ffb91e 100644
--- a/dist/Locale-Maketext/lib/Locale/Maketext.pm
+++ b/dist/Locale-Maketext/lib/Locale/Maketext.pm
@@ -10,7 +10,7 @@ use I18N::LangTags 0.30 ();
BEGIN { unless(defined &DEBUG) { *DEBUG = sub () {0} } }
# define the constant 'DEBUG' at compile-time
-$VERSION = '1.14';
+$VERSION = '1.15';
@ISA = ();
$MATCH_SUPERS = 1;
@@ -186,27 +186,44 @@ sub maketext {
# Look up the value:
my $value;
- foreach my $h_r (
- @{ $isa_scan{ref($handle) || $handle} || $handle->_lex_refs }
- ) {
- DEBUG and warn "* Looking up \"$phrase\" in $h_r\n";
- if(exists $h_r->{$phrase}) {
- DEBUG and warn " Found \"$phrase\" in $h_r\n";
- unless(ref($value = $h_r->{$phrase})) {
- # Nonref means it's not yet compiled. Compile and replace.
- $value = $h_r->{$phrase} = $handle->_compile($value);
+ if (exists $handle->{'_external_lex_cache'}{$phrase}) {
+ DEBUG and warn "* Using external lex cache version of \"$phrase\"\n";
+ $value = $handle->{'_external_lex_cache'}{$phrase};
+ }
+ else {
+ foreach my $h_r (
+ @{ $isa_scan{ref($handle) || $handle} || $handle->_lex_refs }
+ ) {
+ DEBUG and warn "* Looking up \"$phrase\" in $h_r\n";
+ if(exists $h_r->{$phrase}) {
+ DEBUG and warn " Found \"$phrase\" in $h_r\n";
+ unless(ref($value = $h_r->{$phrase})) {
+ # Nonref means it's not yet compiled. Compile and replace.
+ if ($handle->{'use_external_lex_cache'}) {
+ $value = $handle->{'_external_lex_cache'}{$phrase} = $handle->_compile($value);
+ }
+ else {
+ $value = $h_r->{$phrase} = $handle->_compile($value);
+ }
+ }
+ last;
}
- last;
- }
- elsif($phrase !~ m/^_/s and $h_r->{'_AUTO'}) {
- # it's an auto lex, and this is an autoable key!
- DEBUG and warn " Automaking \"$phrase\" into $h_r\n";
-
- $value = $h_r->{$phrase} = $handle->_compile($phrase);
- last;
+ # extending packages need to be able to localize _AUTO and if readonly can't "local $h_r->{'_AUTO'} = 1;"
+ # but they can "local $handle->{'_external_lex_cache'}{'_AUTO'} = 1;"
+ elsif($phrase !~ m/^_/s and ($handle->{'use_external_lex_cache'} ? ( exists $handle->{'_external_lex_cache'}{'_AUTO'} ? $handle->{'_external_lex_cache'}{'_AUTO'} : $h_r->{'_AUTO'} ) : $h_r->{'_AUTO'})) {
+ # it's an auto lex, and this is an autoable key!
+ DEBUG and warn " Automaking \"$phrase\" into $h_r\n";
+ if ($handle->{'use_external_lex_cache'}) {
+ $value = $handle->{'_external_lex_cache'}{$phrase} = $handle->_compile($phrase);
+ }
+ else {
+ $value = $h_r->{$phrase} = $handle->_compile($phrase);
+ }
+ last;
+ }
+ DEBUG>1 and print " Not found in $h_r, nor automakable\n";
+ # else keep looking
}
- DEBUG>1 and print " Not found in $h_r, nor automakable\n";
- # else keep looking
}
unless(defined($value)) {
diff --git a/dist/Locale-Maketext/lib/Locale/Maketext.pod b/dist/Locale-Maketext/lib/Locale/Maketext.pod
index 15533e4e87..14b47c884e 100644
--- a/dist/Locale-Maketext/lib/Locale/Maketext.pod
+++ b/dist/Locale-Maketext/lib/Locale/Maketext.pod
@@ -937,6 +937,25 @@ lexicon keys be autoable, except for possibly a few, and I
arbitrarily decided to use a leading underscore as a signal
to distinguish those few.
+=head1 READONLY LEXICONS
+
+If your lexicon is a tied hash the simple act of caching the compiled value can be fatal.
+
+For example a L<GDBM_File> GDBM_READER tied hash will die with something like:
+
+ gdbm store returned -1, errno 2, key "..." at ...
+
+All you need to do is turn on caching outside of the lexicon hash itself like so:
+
+ sub init {
+ my ($lh) = @_;
+ ...
+ $lh->{'use_external_lex_cache'} = 1;
+ ...
+ }
+
+And then instead of storing the compiled value in the lexicon hash it will store it in $lh->{'_external_lex_cache'}
+
=head1 CONTROLLING LOOKUP FAILURE
If you call $lh->maketext(I<key>, ...parameters...),
diff --git a/dist/Locale-Maketext/t/04_use_external_lex_cache.t b/dist/Locale-Maketext/t/04_use_external_lex_cache.t
new file mode 100644
index 0000000000..f290a5cfb3
--- /dev/null
+++ b/dist/Locale-Maketext/t/04_use_external_lex_cache.t
@@ -0,0 +1,40 @@
+use Test::More tests => 11;
+
+BEGIN {
+ chdir 't';
+ unshift @INC, qw(lib ../lib);
+ use_ok('Locale::Maketext');
+};
+
+package MyTestLocale;
+
+@MyTestLocale::ISA = qw(Locale::Maketext);
+%MyTestLocale::Lexicon = ();
+%MyTestLocale::Lexicon = (); # to avoid warnings
+
+package MyTestLocale::fr;
+
+@MyTestLocale::fr::ISA = qw(MyTestLocale);
+
+%MyTestLocale::fr::Lexicon = (
+ '_AUTO' => 1,
+ 'Hello World' => 'Bonjour Monde',
+);
+
+package main;
+
+my $lh = MyTestLocale->get_handle('fr');
+$lh->{'use_external_lex_cache'} = 1;
+ok(exists $MyTestLocale::fr::Lexicon{'Hello World'} && !ref $MyTestLocale::fr::Lexicon{'Hello World'}, 'lex value not a ref');
+
+is($lh->maketext('Hello World'), 'Bonjour Monde', 'renders correctly first time');
+ok(exists $lh->{'_external_lex_cache'}{'Hello World'} && ref $lh->{'_external_lex_cache'}{'Hello World'}, 'compiled into lex_cache');
+ok(exists $MyTestLocale::fr::Lexicon{'Hello World'} && !ref $MyTestLocale::fr::Lexicon{'Hello World'}, 'lex value still not a ref');
+
+is($lh->maketext('Hello World'), 'Bonjour Monde', 'renders correctly second time time');
+ok(exists $lh->{'_external_lex_cache'}{'Hello World'} && ref $lh->{'_external_lex_cache'}{'Hello World'}, 'still compiled into lex_cache');
+ok(exists $MyTestLocale::fr::Lexicon{'Hello World'} && !ref $MyTestLocale::fr::Lexicon{'Hello World'}, 'lex value still not a ref');
+
+is($lh->maketext('This is not a key'), 'This is not a key', '_AUTO renders correctly first time');
+ok(exists $lh->{'_external_lex_cache'}{'This is not a key'} && ref $lh->{'_external_lex_cache'}{'This is not a key'}, '_AUTO compiled into lex_cache');
+ok(!exists $MyTestLocale::fr::Lexicon{'This is not a key'}, '_AUTO lex value not added to lex');