I am trying to serve a template contained in the __DATA__ section of a controller class, but it doesn't seem to work.
In my main app.pl file I have
#!/usr/bin/env perl
use Mojolicious::Lite -signatures;
use FindBin qw($Bin);
use lib "$Bin/lib";
push #{app->renderer->classes}, 'Zairyo::Controller::Data';
push #{app->preload_namespaces}, 'Zairyo::Controller::Data';
get '/:uid' => [uid => qr/[a-z0-9]{32,32}/i ] => { controller => 'Data', action => 'serve_iframe' };
app->start;
and in Zairyo::Controller::Data:
package Zairyo::Controller::Data;
use Mojo::Base 'Mojolicious::Controller', -signatures;
sub serve_iframe ($c) {
$c->render(template => 'foo');
}
__DATA___
## foo.html.ep
what is this
which I'd expect to work as per the documentation but instead throws an error Could not render a response... on the browser and Template "foo.html.ep" not found on the log.
I've solved this by doing
$c->render(inline => data_section(__PACKAGE__, 'foo.html.ep') );
but it seems a bit of a hack.
What am I doing wrong here?
First, there are a few things a bit off in your Data.pm:
There are three underscores after __DATA when there should be two and a newline
The module does not return a true value
Here's what I ended up with:
package Zairyo::Controller::Data;
use Mojo::Base 'Mojolicious::Controller', -signatures;
sub serve_iframe ($c) {
$c->render(template => 'foo' );
}
1;
__DATA__
## foo.html.ep
what is this
In the main script, I load the class before I call start. Note that the docs say:
Note that for templates to be detected, these classes need to have already been loaded and added before warmup is called
And, warmup is called immediately by start, and it's warmup that cares about preload_namespaces. You need to get there even sooner, so preload_namespaces does nothing for this particular problem. If you haven't already loaded the module, its __DATA__ templates will not be detected.
#!/usr/bin/env perl
use Mojolicious::Lite -signatures;
use FindBin qw($Bin);
use lib "$Bin/lib";
push #{app->renderer->classes}, map { Mojo::Loader::load_class($_); $_ } 'Zairyo::Controller::Data';
get '/:uid' => [uid => qr/[a-z0-9]{32,32}/i ] => {
namespace => 'Zairyo::Controller',
controller => 'Data',
action => 'serve_iframe'
};
app->start;
I'm not suggesting this particular code, but now I know why you weren't getting what you wanted.
Related
Reading Mojolicious minions documentation I found the following code:
use v5.28;
use Mojolicious::Lite;
use experimental qw( signatures );
use Time::HiRes qw( time );
plugin Minion => {
SQLite => 'sqlite:' . app->home->child('minion.db'),
};
# ...
app->start;
How did they create a new syntax plugin Minion => {...}? I've never seen it in classic Perl books. Is it a function call with a hash parameter: "Minion" being a key and a hashref {...} is a value?
Also they call app->start - app is a function returning a blessed hashref? But if it was a hash why "start" is not enclosed into braces? This syntax looks strange to me.
app is a function which returns $app which is an instance of Mojolicious::Lite=HASH
app->start is same as app()->start
https://github.com/mojolicious/mojo/blob/24d1d1987dbfbe27eaaa37dd5db692d2deb8d07f/lib/Mojolicious/Plugin/Config.pm#L12-L14
"sub app; local *app = sub { \$app }; use Mojo::Base -strict; $content";
|
^ not a reference but escape
due to eval() of double quoted string
Reproduction
perl -MMojolicious::Lite -E 'no warnings; sub foo; local *foo = sub { app }; say for foo, app'
output
Mojolicious::Lite=HASH(0xe72080)
Mojolicious::Lite=HASH(0xe72080)
plugin is a regular function
perl -MData::Dumper -wE 'sub plugin { print Dumper \#_ } plugin Minion => { SQLite => "sqlite:" }'
$VAR1 = [
'Minion',
{
'SQLite' => 'sqlite:'
}
];
You can add parens, and drop fat comma to look like the usual function call,
plugin("Minion", { SQLite => "sqlite:" });
I am attempting to build a Restful service with CGI::Application::Plugin::REST, but I am not sure how to actually structure the script. Is it the same as using CGI::Application so the below will be the Instance Script referencing modules withing the Perl library path?
use CGI::Application::Plugin::REST qw( :all );
$self->rest_route(
'/Stage/:id' => {
'GET' => 'Stage',
},
'/Status/:id' => {
'GET' => 'Status',
},
'/Metadate/:id' => {
'GET' => 'Metadata',
},
$self->run();
I will admit I am probably learning CGI::Application backwards, and am looking for an easy way out as once the framework is done the rest is very achievable. Also I did not want to use MVC frameworks as I wanted to build it from scratch. Thanks for the help in advance.
Since you said you want to use this as a structure to build off of, I'd recommend putting your CGI::App logic in its own module. This will make it easier to test later when you start writing tests. Your App.pm will look like a normal CGI::App controller:
package App;
use strict;
use parent 'CGI::Application';
use CGI::Application::Plugin::REST ':all';
sub setup {
my $self = shift;
$self->rest_route(
'/some/route' => {
'GET' => 'read_widget',
'POST' => 'save_widget',
},
);
}
sub read_widget { ... }
sub save_widget { ... }
1;
And then in your instance script that the web server will call, you can simply use App; App->new->run;
You can find a fully functioning example in the C::A::P::REST test lib.
I want to use Perl module and wrap it into a standalone socket which would publish the subroutines from the module to other programmes. However, I probably cannot overcome namespace issues, since in the client script, I am still getting an error message:
RPC::Serialized::X::Application\',\'MESSAGE\' => \'No handler for 'predejPOS' .
My server script:
use RPC::Serialized::Server::NetServer::Single;
use RPC::Serialized::Handler::HashTree;
my $s = RPC::Serialized::Server::NetServer::Single->new({
net_server => {log_file => '', port => 20203 },
rpc_serialized => {handler_namespaces => ''},
});
$s->run;
My client script:
use RPC::Serialized::Client::INET;
my $client = RPC::Serialized::Client::INET->new({
io_socket_inet => {PeerAddr => '127.0.0.1', PeerPort => 20203,}
});
my $result = $client->predejPOS('flu-like');
My module (HastTree.pm):
package RPC::Serialized::Handler::HashTree;
require Exporter;
#ISA = qw(Exporter);
#EXPORT = qw(predejPOS);
use base 'RPC::Serialized::Handler';
our $VERSION = '0.01';
sub predejPOS {
my %POS;
$POS{'flu-like'}='<JJ>';
return $POS{$_[0]};
};
1;
I am using Windows 7, Strawberry Perl 5.12.3, and the module sits on the correct address
(C:\PROGS\Strawberry\perl\site\lib\RPC\Serialized\Handler). The function predejPOS is recognised inside the server script (ie. I can print its result from it), but I cannot access it through the client-server communication. I assume that it has something to do with the subtle difference between calling the function and calling the method. I am afraid that it is probably something simple, but even after a substantial effort and googling I was not able to make it work.
Thanks in advance!
Well I eventually solved it by myself:
First, I got completely wrong the concept of calling functions - over the network you can only call so called RPC Handlers. Moreover for each handler there must be a module in RPC::Serialized::Handler directory with the same name and a specific structure with only one subroutine inside called invoke(). Thus I changed my module (named now 'PredejPOS.pm') to:
package RPC::Serialized::Handler::PredejPOS;
{
$RPC::Serialized::Handler::PredejPOS::VERSION = '0.01';
}
use strict;
use warnings FATAL => 'all';
use base 'RPC::Serialized::Handler';
sub invoke {
my $self = shift;
my $key = shift;
my %POS;
$POS{'flu-like'}='<JJ>';
return scalar $POS{$key};
}
1;
But it was still not working.
Finally secondly I found that under Windows environment, the Perl Data::Serialize module does not work properly.
In the package Serialized.pm, subroutine recv (row 115), the chomp does not remove the damned Windows line ending '\cM'. When I corrected it, it started working as envisaged. Actually there is a lenghty discussion of this behaviour here ( http://www.perlmonks.org/?node_id=549385 )
Thanks for the suggestions.
For object method the first argument is always the current object instance itself. Sorry, if I am not clear enough, try to figure out the difference from this example:
Try this:
sub predejPOS {
my $self = shift;
my $key = shift;
my %POS;
$POS{'flu-like'}='<JJ>';
return $POS{$key};
};
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.
Let's say I have a Perl file in which there are parts I need to run only when I'm called as a script. I remember reading sometime back about including those parts in a main() method and doing a
main() unless(<some condition which tests if I'm being used as a module>);
But I forgot what the condition was. Searching Google hasn't turned out anything fruitful. Can someone point out the right place to look for this?
If the file is invoked as a script, there will be no caller so you can use:
main() unless caller;
See brian d foy's explanation.
#!/usr/bin/perl
use strict;
use warnings;
main() unless caller;
sub main {
my $obj = MyClass->new;
$obj->hello;
}
package MyClass;
use strict;
use warnings;
sub new { bless {} => shift };
sub hello { print "Hello World\n" }
no warnings 'void';
"MyClass"
Output:
C:\Temp> perl MyClass.pm
Hello World
Using from another script:
C:\Temp\> cat mytest.pl
#!/usr/bin/perl
use strict;
use warnings;
use MyClass;
my $obj = MyClass->new;
$obj->hello;
Output:
C:\Temp> mytest.pl
Hello World
I call these things "modulinos" originally in my Scripts as Modules article for The Perl Journal (now Dr. Dobbs). Google that term and you get the right resources. Sinan already linked to my development sources for one of my books where I talk about it. You might also like How a Script Becomes a Module.
Better to not do this, and instead take a structured approach like MooseX::Runnable.
Your class will look like:
class Get::Me::Data with (MooseX::Runnable, MooseX::Getopt) {
has 'dsn' => (
is => 'ro',
isa => 'Str',
documentation => 'Database to connect to',
);
has 'database' => (
is => 'ro',
traits => ['NoGetopt'],
lazy_build => 1,
);
method _build_database {
Database->connect($self->dsn);
}
method get_data(Str $for_person){
return $database->search({ person => $for_person });
}
method run(Str $for_person?) {
if(!$defined $for_person){
print "Type the person you are looking for: ";
$for_person = <>;
chomp $for_person;
}
my #data = $self->get_data($for_person);
if(!#data){
say "No data found for $for_person";
return 1;
}
for my $data (#data){
say $data->format;
}
return 0;
}
}
Now you have a class that can be used inside your program easily:
my $finder = Get::Me::Data->new( database => $dbh );
$finder->get_data('jrockway');
Inside an interactive script that is bigger than just the "run" method above:
...
my $finder = Get::Me::Data->new( dsn => 'person_database' );
$finder->run('jrockway') and die 'Failure'; # and because "0" is success
say "All done with Get::Me::Data.";
...
If you just want to do this standalone, you can say:
$ mx-run Get::Me::Data --help
Usage: mx-run ... [arguments]
--dsn Database to connect to
$ mx-run Get::Me::Data --dsn person_database
Type the person you are looking for: jrockway
<data>
$ mx-run Get::Me::Data --dsn person_database jrockway
<data>
Notice how little code you wrote, and how flexible the resulting class is. "main if !caller" is nice, but why bother when you can do better?
(BTW, MX::Runnable has plugins; so you can easily increase the amount of debugging output you see, restart your app when the code changes, make the app persistent, run it in the profiler, etc.)