* Working on a new way of handling words files.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 8 years ago
parent 4ac37e239f
commit ec307bc019
  1. 72
      AN/Tools.pm
  2. 2
      AN/Tools/Storage.pm
  3. 186
      AN/Tools/Words.pm
  4. 37
      AN/an-tools.xml

@ -13,8 +13,6 @@ BEGIN
use strict; use strict;
use warnings; use warnings;
use IO::Handle;
use XML::Simple;
use Data::Dumper; use Data::Dumper;
my $THIS_FILE = "Tools.pm"; my $THIS_FILE = "Tools.pm";
@ -24,9 +22,10 @@ $ENV{'PERL_UNICODE'} = 1;
# I intentionally don't use EXPORT, @ISA and the like because I want my "subclass"es to be accessed in a # I intentionally don't use EXPORT, @ISA and the like because I want my "subclass"es to be accessed in a
# somewhat more OO style. I know some may wish to strike me down for this, but I like the idea of accessing # somewhat more OO style. I know some may wish to strike me down for this, but I like the idea of accessing
# methods via their containing module's name. (A La: $an->Module->method rather than $an->method). # methods via their containing module's name. (A La: C<< $an->Module->method >> rather than C<< $an->method >>).
use AN::Tools::Alert; use AN::Tools::Alert;
use AN::Tools::Storage; use AN::Tools::Storage;
use AN::Tools::Words;
=pod =pod
@ -93,14 +92,13 @@ sub new
HANDLE => { HANDLE => {
ALERT => AN::Tools::Alert->new(), ALERT => AN::Tools::Alert->new(),
STORAGE => AN::Tools::Storage->new(), STORAGE => AN::Tools::Storage->new(),
WORDS => AN::Tools::Words->new(),
}, },
DATA => {}, DATA => {},
ERROR_COUNT => 0, ERROR_COUNT => 0,
ERROR_LIMIT => 10000, ERROR_LIMIT => 10000,
DEFAULT => { DEFAULT => {
LANGUAGE => 'en_CA', LANGUAGE => 'en_CA',
LOG_FILE => '/var/log/an.log',
STRINGS => 'AN/strings.xml',
}, },
ENV_VALUES => { ENV_VALUES => {
ENVIRONMENT => 'cli', ENVIRONMENT => 'cli',
@ -116,6 +114,7 @@ sub new
# Get a handle on the various submodules # Get a handle on the various submodules
$an->Alert->parent($an); $an->Alert->parent($an);
$an->Storage->parent($an); $an->Storage->parent($an);
$an->Words->parent($an);
# Set some system paths and system default variables # Set some system paths and system default variables
$an->_add_environment_path_to_search_directories; $an->_add_environment_path_to_search_directories;
@ -129,8 +128,7 @@ sub new
$an->data($parameter->{data}) if $parameter->{data}; $an->data($parameter->{data}) if $parameter->{data};
# I need to read the initial words early. # I need to read the initial words early.
# $self->{DEFAULT}{STRINGS} = $an->Storage->find({file => $self->{DEFAULT}{STRINGS}, fatal => 1}); $an->Words->read({file => $an->data->{path}{words}{'an-tools.xml'}});
# $an->Storage->read_words({file => $self->{DEFAULT}{STRINGS}});
# Set passed parameters if needed. # Set passed parameters if needed.
if (ref($parameter) eq "HASH") if (ref($parameter) eq "HASH")
@ -283,17 +281,15 @@ sub environment
=head1 Submodule Access Methods =head1 Submodule Access Methods
The methods below are used to access methods of submodules using 'C<$an->Module->method()>'. The methods below are used to access methods of submodules using 'C<< $an->Module->method() >>'.
=cut =cut
=head2 Alert =head2 Alert
Access the C<Alert.pm> methods via 'C<$an->Alert->method>'. Access the C<Alert.pm> methods via 'C<< $an->Alert->method >>'.
=cut =cut
# Makes my handle to AN::Tools::Storage clearer when using this module to access its methods.
sub Alert sub Alert
{ {
my $self = shift; my $self = shift;
@ -303,11 +299,9 @@ sub Alert
=head2 Storage =head2 Storage
Access the C<Storage.pm> methods via 'C<$an->Storage->method>'. Access the C<Storage.pm> methods via 'C<< $an->Storage->method >>'.
=cut =cut
# Makes my handle to AN::Tools::Storage clearer when using this module to access its methods.
sub Storage sub Storage
{ {
my $self = shift; my $self = shift;
@ -315,6 +309,18 @@ sub Storage
return ($self->{HANDLE}{STORAGE}); return ($self->{HANDLE}{STORAGE});
} }
=head2 Words
Access the C<Words.pm> methods via 'C<< $an->Words->method >>'.
=cut
sub Words
{
my $self = shift;
return ($self->{HANDLE}{WORDS});
}
=head1 Private Functions; =head1 Private Functions;
@ -328,7 +334,7 @@ These methods generally should never be called from a program using AN::Tools. H
=head2 _add_environment_path_to_search_directories =head2 _add_environment_path_to_search_directories
This method merges @INC and $ENV{'PATH'} into a single array and uses the result to set C<$an->Storage->search_directories>. This method merges @INC and $ENV{'PATH'} into a single array and uses the result to set C<< $an->Storage->search_directories >>.
=cut =cut
sub _add_environment_path_to_search_directories sub _add_environment_path_to_search_directories
@ -369,20 +375,42 @@ sub _set_paths
my ($an) = shift; my ($an) = shift;
# Executables # Executables
$an->data->{path}{exe} = { $an->data->{path} = {
exe => {
gethostip => "/usr/bin/gethostip", gethostip => "/usr/bin/gethostip",
hostname => "/bin/hostname", hostname => "/bin/hostname",
},
logs => {
'an-tools.log' => "/var/log/an-tools.log",
},
words => {
'an-tools.xml' => "/usr/share/perl5/AN/an-tools.xml",
},
}; };
# Make sure we actually have each executable # Make sure we actually have the requested files.
foreach my $program (sort {$a cmp $b} keys %{$an->data->{path}{exe}}) foreach my $type (sort {$a cmp $b} keys %{$an->data->{path}})
{
# We don't look for logs because we'll create them if they don't exist.
next if $type eq "logs";
foreach my $file (sort {$a cmp $b} keys %{$an->data->{path}{$type}})
{ {
if (not -e $an->data->{path}{exe}{$program}) if (not -e $an->data->{path}{$type}{$file})
{ {
my $full_path = $an->Storage->find({file => $program}); my $fatal = 0;
if ($type eq "words")
{
# We have to die if we don't find a words file.
$fatal = 1;
}
my $full_path = $an->Storage->find({
file => $file,
fatal => $fatal,
});
if ($full_path) if ($full_path)
{ {
$an->data->{path}{exe}{$program} = $full_path; $an->data->{path}{$type}{$file} = $full_path;
}
} }
} }
} }
@ -398,7 +426,7 @@ AN::Tools->new() passed something other than a hash reference.
=head2 C<2> =head2 C<2>
Failed to find the requested file in C<AN::Tools::Storage->find> and 'fatal' was set. Failed to find the requested file in C<< AN::Tools::Storage->find >> and 'fatal' was set.
=head1 Requirements =head1 Requirements

@ -38,7 +38,7 @@ Provides all methods related to storage on a system.
=head1 METHODS =head1 METHODS
Methods in the core module; Methods in this module;
=cut =cut
sub new sub new

@ -0,0 +1,186 @@
package AN::Tools::Words;
#
# This module contains methods used to handle storage related tasks
#
use strict;
use warnings;
use Data::Dumper;
use XML::LibXML;
use Encode;
our $VERSION = "3.0.0";
my $THIS_FILE = "Words.pm";
# Setup for UTF-8 mode.
# use utf8;
# $ENV{'PERL_UNICODE'} = 1;
### Methods;
# read
=pod
=encoding utf8
=head1 NAME
AN::Tools::Words
Provides all methods related to generating translated strings for users.
=head1 SYNOPSIS
use AN::Tools::Words;
# Get a common object handle on all AN::Tools modules.
my $an = AN::Tools->new();
# Access to methods using '$an->Words->X'.
#
# Example using 'read()';
my $foo_path = $an->Words->read({file => $an->data->{path}{words}{'an-tools.xml'}});
=head1 METHODS
Methods in this module;
=cut
sub new
{
my $class = shift;
my $self = {};
bless $self, $class;
return ($self);
}
# Get a handle on the AN::Tools object. I know that technically that is a sibling module, but it makes more
# sense in this case to think of it as a parent.
sub parent
{
my $self = shift;
my $parent = shift;
$self->{HANDLE}{TOOLS} = $parent if $parent;
return ($self->{HANDLE}{TOOLS});
}
#############################################################################################################
# Public methods #
#############################################################################################################
=head2 read
This reads in a words file containing translated strings used to generated output for the user.
Example to read 'C<an-tools.xml>';
my $words_file = $an->data->{path}{words}{'an-words.xml'};
my $an->Words->read({file => $words_file}) or die "Failed to read: [$words_file]. Does the file exist?\n";
Successful read will return '0'. Non-0 is an error;
0 = OK
1 = Invalid file name or path
2 = File not found
3 = File not readable
4 = File found, but did not contain strings.
NOTE: Read works are stored in 'C<< $an->data->{words}{<file_name>}{language}{<language>}{string} >>'. Metadata, like what languages are provided, are stored under 'C<< $an->data->{words}{<file_name>}{meta}{...} >>'.
Parameters;
=head3 file
This is the file to read.
=cut
sub read
{
my $self = shift;
my $parameter = shift;
my $an = $self->parent;
# Setup default values
my $file = defined $parameter->{file} ? $parameter->{file} : 0;
my $return_code = 0;
if (not $file)
{
# TODO: Log the problem, do not translate.
print $THIS_FILE." ".__LINE__."; AN::Tools::Words->read()' called without a file name to read.\n";
$return_code = 1;
}
elsif (not -e $file)
{
# TODO: Log the problem, do not translate.
print $THIS_FILE." ".__LINE__."; AN::Tools::Words->read()' asked to read: [$file] which was not found.\n";
$return_code = 2;
}
elsif (not -r $file)
{
# TODO: Log the problem, do not translate.
print $THIS_FILE." ".__LINE__."; AN::Tools::Words->read()' asked to read: [$file] which was not readable by: [".getpwuid($<)."/".getpwuid($>)."] (uid/euid: [".$<."/".$>."]).\n";
$return_code = 3;
}
else
{
# Read the file with XML::LibXML
my $parser = XML::LibXML->new();
my $dom = XML::LibXML->load_xml({location => $file});
print "===========================================================\n";
print Dumper $dom;
print "===========================================================\n";
# my $data = "";
# eval { $data = $xml->XMLin($file, KeyAttr => {node => 'name'}, ForceArray => 1) };
# if ($@)
# {
# chomp $@;
# print $THIS_FILE." ".__LINE__."; [ Error ] - The was a problem reading: [$file]. The error was:\n";
# print "===========================================================\n";
# print $@."\n";
# print "===========================================================\n";
# $return_code = 4;
# }
# else
# {
# print "===========================================================\n";
# #print Dumper $data;
# print Dumper $data->{language};
# print "===========================================================\n";
#
# # Read the meta data
# my $meta_found = 0;
# my $version = $data->{meta}->[0]->{version}->[0];
# my $languages = $data->{meta}->[0]->{languages}->[0];
# #print $THIS_FILE." ".__LINE__."; [ Debug ] - Version: [$version], languages: [$languages]\n";
#
# my $this_language = "";
# foreach my $hash_ref (@{$data->{language}})
# {
# $this_language = $hash_ref->{name};
# my $long_name = $hash_ref->{long_name};
# print $THIS_FILE." ".__LINE__."; [ Debug ] - this_language: [$this_language], long_name: [$long_name]\n";
# }
# }
}
return($return_code);
}
# =head3
#
# Private Functions;
#
# =cut
#############################################################################################################
# Private functions #
#############################################################################################################
1;

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Company: Alteeve's Niche, Inc.
License: GPL v2+
Author: Madison Kelly <mkelly@alteeve.ca>
This is the AN::Tools master 'words' file.
-->
<words>
<meta>
<version>3.0.0</version>
<languages>en_CA,jp</languages>
</meta>
<!-- Canadian English -->
<language name="en_CA" long_name="Canadian English" description="Created by Madison Kelly (mkelly@alteeve.ca) for the AN::Tools suite of perl modules">
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key>
<key name="t_0001">Test replace: [#!variable!test!#].</key>
<key name="t_0002">Test Out of order: [#!variable!second!#] replace: [#!variable!first!#].</key>
<!-- Do not use 't_0003'. It is used to test failures caused by calling a non-existent key. -->
<key name="t_0004">#!FREE!#</key>
</language>
<!-- 日本語 -->
<language name="jp" long_name="日本語" description=">Created by Madison Kelly (mkelly@alteeve.ca) for the AN::Tools suite of perl modules.">
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">テスト</key>
<key name="t_0001">テスト いれかえる: [#!variable!test!#]。</key>
<key name="t_0002">テスト、 整理: [#!variable!second!#]/[#!variable!first!#]。</key>
<!-- Do not use 't_0003'. It is used to test failures caused by calling a non-existent key. -->
<key name="t_0004">#!FREE!#</key>
</language>
</words>
Loading…
Cancel
Save