The following feature refers to the Github version and is experimental: https://github.com/forwardever/Forward-Routes
Forward::Routes supports the nesting of routes, which can result in better performance and maintainability.
However, as your project grows, route stuctures can quickly become confusing.
The following routes:
my $r = Forward::Routes->new;
my $authors = $r->add_route('/authors');
$authors->add_route->to('Author#index');
my $author = $authors->add_route('/:author_name');
$author->add_route->to('Author#show');
my $articles = $author->add_route('articles');
$articles->add_route->to('Article#index');
my $article = $articles->add_route('/:article_id');
$article->add_route->to('Article#show');
my $comments = $article->add_route('comments');
$comments->add_route->to('Comment#index');
$comments->add_route('/:comment_id')->to('Comment#show');
match:
# tests
my $m = $r->match(get => '/authors');
is_deeply $m->[0]->params, {controller => 'Author', action => 'index'};
$m = $r->match(get => '/authors/steven');
is_deeply $m->[0]->params, {controller => 'Author', action => 'show',
author_name => 'steven'};
$m = $r->match(get => '/authors/steven/articles');
is_deeply $m->[0]->params, {controller => 'Article', action => 'index',
author_name => 'steven'};
$m = $r->match(get => '/authors/steven/articles/4');
is_deeply $m->[0]->params, {controller => 'Article', action => 'show',
author_name => 'steven', article_id => 4};
$m = $r->match(get => '/authors/steven/articles/4/comments');
is_deeply $m->[0]->params, {controller => 'Comment', action => 'index',
author_name => 'steven', article_id => 4};
$m = $r->match(get => '/authors/steven/articles/4/comments/3');
is_deeply $m->[0]->params, {controller => 'Comment', action => 'show',
author_name => 'steven', article_id => 4, comment_id => 3};
Therefore, with two additional lines of code:
sub new {
...
my $code_ref = pop @_ if @_ && ref $_[-1] eq 'CODE';
$code_ref->($self) if $code_ref;
...
}
I have added a block syntax to the module, so the code can now also be written like this:
my $b = Forward::Routes->new;
$b->add_route('/authors', sub {
my $authors = shift;
$authors->add_route->to('Author#index');
$authors->add_route('/:author_name', sub {
my $author = shift;
$author->add_route->to('Author#show');
$author->add_route('articles', sub {
my $articles = shift;
$articles->add_route->to('Article#index');
$articles->add_route('/:article_id', sub {
my $article = shift;
$article->add_route->to('Article#show');
$article->add_route('comments', sub {
my $comments = shift;
$comments->add_route->to('Comment#index');
$comments->add_route('/:comment_id')
->to('Comment#show');
});
});
});
});
});
And in order to make it more simple, use Method::Signatures::Simple
use Method::Signatures::Simple;
my $ms = Forward::Routes->new;
$ms->add_route('/authors', func($authors) {
$authors->add_route->to('Author#index');
$authors->add_route('/:author_name', func($author) {
$author->add_route->to('Author#show');
$author->add_route('articles', func($articles) {
$articles->add_route->to('Article#index');
$articles->add_route('/:article_id', func($article) {
$article->add_route->to('Article#show');
$article->add_route('comments', func($comments) {
$comments->add_route->to('Comment#index');
$comments->add_route('/:comment_id')
->to('Comment#show');
});
});
});
});
});
]]>
One of my classes just has to delegate method calls to another class, here my first draft:
## Delegation (using Method::Signatures::Simple)
method manager {Forward::ORM::Migrations::Manager->new}
method create_table (@params) {$self->manager->create_table(@params)}
method add_column (@params) {$self->manager->add_column(@params)}
method remove_column (@params) {$self->manager->remove_column(@params)}
with the Mouse handles command, it becomes:
has manager => (
default => sub {Forward::ORM::Migrations::Manager->new},
handles => [qw/add_column create_table remove_column/]
);
This is 46% less code. And the savings will become even bigger as I will add new commands :)
]]>In my first version, I used default Perl:
sub up {
my $self = shift;
$self->create_table('authors', sub {my $t = shift;
$t->add_column('id', 'integer', primary_key => 1);
$t->add_column('name', 'varchar', length => 40);
});
}
I then noticed that Method::Signatures::Simple also works with anonymous functions and methods, so my code now looks like this:
sub up {
my $self = shift;
$self->create_table('authors', func($t){
$t->add_column('id', 'integer', primary_key => 1);
$t->add_column('name', 'varchar', length => 40);
});
}
and later
$code_ref->($table);
While not as pretty as Ruby code blocks, as func has to be passed as a parameter and thus must be surrounded by braces, it is at least a small improvement.
]]>yes, I can still access any other site, including https://metacpan.org/
Turning off my router and then turning it on again actually helps!
Does that make any sense at all???
By the way, search.cpan.org is the only site showing this strange behaviour!
]]>INSERT INTO "authors" DEFAULT VALUES
In SQL::Abstract and SQL::Maker, it does not work:
INSERT INTO "authors" () VALUES () # syntax error
The only module that seems to get things right is vti's ObjectDB2, which is in a very early stage of development and not on CPAN so far.
]]>still get DBD::mysql::db prepare failed: Async support was not built into this version of DBD::mysql at async_mysql.pl line 17.
working on Strawberry Perl on Windows
]]>Have already given up, but finally decided to make a Github search for DBIx, which provided exactly what I needed. Just curious why it was so hard to find this module?
use DBI;
use DBIx::Inspector;
use 5.010000;
my $username = "";
my $password = "";
$dbh = DBI->connect('dbi:mysql:mydb', $username, $password)
or die $DBI::errstr;
my $inspector = DBIx::Inspector->new(dbh => $dbh);
my $table = $inspector->tables('users')->next;
say "Name";
say " ", $table->name;
say "Primary Keys";
for my $pk ($table->primary_key) {
say " ", $pk->name;
}
say "Columns";
for my $column ($table->columns) {
say " ", $column->name, " ", $column->type_name,
"(", $column->column_size ,")";
}
1;
]]>
not sure what your point is...!?
]]>https://github.com/ingydotnet/mo-pm/blob/master/lib/Mo/Features.pod
2.)
has 'first' => (chain => 1);
chaining must requested per accessor, as it cannot be the default (see my older post and the related comments)
3.) it might be possible to add a feature called e.g. chain_by_default, so you would only have to say chain => 0 if chaining is not desired, not sure whether there is any interest for that in the Mo community
]]>package ChainedAccessors;
use Mo qw/chain/;
has 'first' => (chain => 1);
has 'second' => (chain => 1);
package main;
$f = ChainedAccessors->new;
$f->first(1)->second(2);
$f->first; # 1
$f->second; # 2
thanks also for the feedback in response to my previous blog post
]]>