Perl and Catalyst: accessing maketext from a model - perl

Edited to clarify / reflect what I've been trying:
I'm using CatalystX::I18N::* in order to be able to internationalise my site. I have that working nicely, and my site text is coming from $c->maketext().
However, I've been trying to access these codes from my database model (in order to generate, e.g., success or failure messages when checking input before creating / updating) and am struggling.
According to the CatalystX::I18N docs, CatalystX::I18N::Maketext is a 'Helpful wrapper around Locale::Maketext. Can also be used outside of Catalyst'.
I have MyApp::Maketext setup as directed:
package MyApp::Maketext;
use strict;
use warnings;
use parent qw(CatalystX::I18N::Maketext);
1;
I have a little test script running, the setup for which is this:
#!/usr/bin/perl
use strict;
use warnings;
use FindBin qw( $Bin );
use lib "$Bin/../lib";
use TopTable::Maketext;
use Path::Class::Dir;
my $dir = Path::Class::Dir->new( "$Bin/..", "root", "locale" );
TopTable::Maketext->load_lexicon(
locales => ["en_GB"], # Required
directories => [$dir], # Required
gettext_style => 0, # Optional, Default 1
);
I am then trying two different ways to get a handle to the maketext() method:
my $lang = TopTable::Maketext->get_handle;
printf "%s\n", $lang->maketext( "menu.title.news" );
Gives the following result:
Can't call method "maketext" on an undefined value at bin\maketext-demo.pl line 23.
If I swap ->get_handle to ->new:
my $lang = TopTable::Maketext->new;
printf "%s\n", $lang->maketext( "menu.title.news" );
I get the following:
maketext doesn't know how to say:
menu.title.news
as needed at bin\maketext-demo.pl line 23.
I'm at a bit of a loss as to what to try next! Thank you so much in advance for any pointers anyone can give.
Chris

I have finally got my head around this - this is the code that eventually worked:
#!/usr/bin/perl
use strict;
use warnings;
use FindBin qw( $Bin );
use lib "$Bin/../lib";
use Data::Dumper::Concise;
use TopTable::Maketext;
use Config::ZOMG;
use Path::Class::Dir;
my $tt_config = Config::ZOMG->new( name => 'TopTable' );
my $config_hash = $tt_config->load;
my (#locales, %inhertiance, $config);
$config = $config_hash->{I18N}{locales};
foreach my $locale (keys %$config) {
push(#locales, $locale);
$inhertiance{$locale} = $config->{$locale}{inherits} if defined $con
+fig->{$locale}{inherits};
}
my $dir = Path::Class::Dir->new( "$Bin/..", "root", "locale" );
TopTable::Maketext->load_lexicon(
locales => \#locales,
directories => [$dir],
gettext_style => 1,
inheritance => \%inhertiance,
);
my $lang = TopTable::Maketext->get_handle( "en_GB" );
printf "%s\n", $lang->maketext( "menu.title.league-tables", "Division Three" );
1;
This gives the correct value of:
League Tables for Division Three
Thanks for putting up with my spam!

Related

Error in Perl Rose::DB : Can't use string ... as a HASH ref while "strict"

I am getting an error when using Rose::DB.
#MyApp/DB.pm
package MyIMDB::DB;
use strict; use warnings;
use base qw(Rose::DB);
__PACKAGE__->use_private_registry;
__PACKAGE__->register_db (
driver => 'SQLite',
....
);
1;
# MyApp/DB/Object.pm
package MyApp::DB::Object;
use strict; use warnings;
use MyApp::DB;
use base qw(Rose::DB::Object);
sub init_db { MyIMDB::DB->new }
1;
#
package MyApp::Users; #controller
use strict; use warnings;
use base 'Mojolicious::Controller';
use Mojo::ByteStream 'b';
use MyApp::Models::User;
use Data::Dumper;
sub my_action {
my $uc = shift;
my $err = MyApp::Models::User::->validate(...); #extra ::
# http://perldoc.perl.org/perlobj.html#Invoking-Class-Methods
}
# MyApp/Models/User.pm # 2 packages in this file
package MyApp::Models::User::Manager;
use base qw(Rose::DB::Object::Manager);
use MyApp::Models::User;
sub object_class { 'MyApp::Models::User'}
__PACKAGE__->make_manager_methods('users');
# class methods get_x, get_x_iterator, get_x_count, delete_x, update_x
1;
MyApp::Models::User
use strict; use warnings;
use base qw(MyApp::DB::Object);
__PACKAGE__->meta->setup(
#setup tables, columns....
);
sub validate {
my $u = shift;
my $n = MyApp::Models::User::Manager::->get_users_count(query => [user_name => $user]);
}
1;
The error I get is:
"Can't use string ("MyApp::Models::User") as a HASH ref while "strict refs"
in use at /usr/local/share/perl/5.18.2/Rose/DB/Object.pm line 91, <DATA> line 2231."
The entry point is my_action() method of MyApp:Users class.
I tried alternative setups of creating class MyApp::Models::User::Manager : separate .pm file, make_manager_class(), but to no avail.
(I found this discussion from 2007 with the same error message, but it does not help me out http://comments.gmane.org/gmane.comp.lang.perl.modules.dbi.rose-db-object/1537).
This may indicate I am trying to call an object method as if it were a class method. I tried the tricks listed here http://perldoc.perl.org/perlobj.html#Invoking-Class-Methods, but no success.
I now I can examine the contents of variables with Data::Dumper, but I have no clue what to dump as there are very little data structures used.
While use strict is a good idea when writing Perl code, you may want to relax the strict-ness by adding
no strict `refs`;
to get past the current error. As #ikegami pointed out another way to fix this is to get rid of the bad reference, but if you don't want to rewrite the module working around it with relaxing strict-ness is your best bet.

WWW:Facebook::API used in perl

I am getting www:Facebook:api in perl and CPAN
error while using the Use of uninitialized value within %field in hash element at /usr/share/perl5/WWW/Facebook/API/Auth.pm line 62.
i defined all keys
#!/usr/bin/perl -w
use strict;
use warnings;
use CGI;
use WWW::Facebook::API;
use WWW::Facebook::API::Auth;
use HTTP::Request;
use LWP;
my $TMP = $ENV{HOME}.'/tmp';
my $facebook_api = '--------';
my $facebook_secret = '-------';
my $facebook_clientid = '--------';
my $gmail_user = '-------';
my $gmail_password = '--------';
my $client = WWW::Facebook::API->new(
desktop => 1,
api_version => '1.0',
api_key => $facebook_api,
secret => $facebook_secret,
throw_errors => 1,
);
$client->app_id($facebook_clientid);
local $SIG{INT} = sub {
print "Logging out of Facebookn";
my $r = $client->auth->logout;
exit(1);
};
my $token = $client->auth->create_token;
print "$token \n";
$client->auth->get_session($token);
print "$client \n";
WWW::Facebook::API doesn't look like it's been updated for a while. Line 62 of that file is:
$self->base->{ $field{$key} } = $resp->{$key};
The undefined value is the $field{$key} part. The %fieldhash is a hard-coded mapping between the names of Facebook API's known fields (i.e. the fields in the data Facebook returns to you) and the names which the module wants them to be called. It seems that Facebook has added some additional fields to its data, and the module has not been updated to deal with them.
Ultimately, this is just a warning; you can just ignore it if you like. If you want your script's output to be a bit tidier, you could change that line to:
$self->base->{ $field{$key} } = $resp->{$key} if defined $field{$key};

Retrieve a value from object in perl

I am getting
$VAR1 = bless( \*{'Fh::fh00001Screenshot.png'}, 'Fh' );
in a variable. But I need to retrieve fh00001Screenshot.png from it. How can I get it?
The Fh package is used internally by the CGI module to handle temporary files used for building multipart data. You shouldn't be using it directly.
Check carefully to make sure there is no better way before using this code which comes from the CGI code for Fh::asString
(my $name = $$VAR1) =~ s/^\*(\w+::fh\d{5})+//;
print $name;
output
Screenshot.png
Update
Rather than picking bits out of the CGI code, it looks like this package - which should really be a private one - is accessible from calling code. Use just $var->asString instead, like this
use strict;
use warnings;
use CGI;
my $var = do {
no strict 'refs';
my $var = bless( \*{'Fh::fh00001Screenshot.png'}, 'Fh' );
};
print $var->asString;

Is it possible to read __DATA__ with Config::General in Perl?

I'd like to setup Config::General to read from the __DATA__ section of a script instead of an external file. (I realize that's not normally how it works, but I'd like to see if I can get it going. A specific use case is so I can send a script example to another developer without having to send a separate config file.)
According to the perldoc perldata, $main::DATA should act as a valid filehandle. I think Config::General should then be able to use -ConfigFile => \$FileHandle to read it, but it's not working for me. For example, this script will execute without crashing, but the __DATA__ isn't read in.
#!/usr/bin/perl -w
use strict;
use Config::General;
use YAML::XS;
my $configObj = new Config::General(-ConfigFile => $main::DATA);
my %config_hash = $configObj->getall;
print Dump \%config_hash;
__DATA__
testKey = testValue
I also tried:
my $configObj = new Config::General(-ConfigFile => \$main::DATA);
and
my $configObj = new Config::General(-ConfigFile => *main::DATA);
and a few other variations, but couldn't get anything to work.
Is it possible to use Config::General to read config key/values from __DATA__?
-ConfigFile requires a reference to a handle. This works:
my $configObj = Config::General->new(
-ConfigFile => \*main::DATA
);
The DATA handle is a glob, not a scalar.
Try *main::DATA instead of $main::DATA.
(and maybe try \*main::DATA. From the Config::General docs it looks like you are supposed to pass a filehandle argument as a reference.)
If the -ConfigGeneral => filehandle argument to the constructor doesn't do what you mean, an alternative is
new Config::General( -String => join ("", <main::DATA>) );
This works for me:
#!/usr/bin/perl
use strict;
use warnings;
use Config::General;
use YAML::XS;
my $string;
{
local $/;
$string = <main::DATA>;
};
my $configObj = new Config::General(-String => $string);
my %config_hash = $configObj->getall;
use Data::Dumper;
warn Dumper(\%config_hash);
__DATA__
testKey = testValue

How can I make these tests more DRY?

I currently have the following at the beginning of several test files, but it's very not DRY. But I'm not really sure what the best way to move this into its own file is. Any suggestions?
#!/usr/bin/perl
use strict;
use warnings;
BEGIN {
use Test::More;
use namespace::clean qw( pass );
}
use FindBin;
use Cwd qw( realpath );
use Dancer qw( :syntax );
use Test::WWW::Mechanize::PSGI;
set apphandler => 'PSGI';
my $appdir = realpath( "$FindBin::Bin/.." );
my $t = Test::WWW::Mechanize::PSGI->new(
app => sub {
my $env = shift;
setting(
appname => 'MyApp',
appdir => $appdir,
);
load_app 'MyApp';
config->{environment} = 'test';
Dancer::Config->load;
my $request = Dancer::Request->new( env => $env );
Dancer->dance( $request );
}
);
$t->agent('test');
$t->get_ok('/login') or diag $t->content;
$t->submit_form_ok({
form_name =>'loginform',
fields => {
username => 'myuser',
password => 'foo',
},
}, 'login ok' );
### END BOILERPLATE ###
update
unfortunately part of my problem with moving this off into a library is that as soon as I've done that the code stops working. I tried encapsulating it into a subroutine and returning $t but that doesn't appear to work. I'm trying to figure out what exactly needs to go into the library and what exactly needs to go into the test.
Make it a module (say t::MyApp), change my $t to our $t, and have the module export $t. (You could also write a custom import method to turn on strict & warnings in your test script.)
You could create a .pm module that includes these lines, with some object-oriented code to obtain the $t and other information from the boilerplate code, and then use it from your tests.