summaryrefslogtreecommitdiff
path: root/content/post/2009-05-18-a-simple-feed-aggregator-with-modern-perl-part-4.1.md
blob: 5486ec37827530a687fcf36755d7262b33a597ed (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
---
date: 2009-05-18T00:00:00Z
summary: In which we had one more article on how to write a feed aggregator.
title: A simple feed aggregator with modern Perl - part 4.1
---

You can thanks [bobtfish](http://github.com/bobtfish) for being such a pedantic guy, 'cause now you will have a better chained examples. He forked my repository from GitHub and fix some code that I'll explain here.

### lib/MyFeedReader.pm

```perl
 package MyFeedReader;
+use Moose;
+use namespace::autoclean;

-use strict;
-use warnings;
-
-use Catalyst::Runtime '5.70';
+use Catalyst::Runtime '5.80';

-use parent qw/Catalyst/;
+extends 'Catalyst';
```

You can see that he use [Moose](http://search.cpan.org/perldoc?Moose), so we can remove

```perl
use strict;
use warnings;
```

and have a more elegant way to inherit from [Catalyst](http://search.cpan.org/perldoc?Catalyst) with

```perl
extends 'Catalyst';
```

instead of

```perl
use parent qw/Catalyst/;
```

He also have updated the **Catalyst::Runtime** version, and added **namespace::autoclean**. The purpose of this module is to keep imported methods out of you namespace. Take a look at the "documentation":http://search.cpan.org/perldoc?namespace::autoclean, it's easy to understand how and why it's usefull.

### lib/MyFeedReader/Controller/Root.pm

```perl
-use strict;
-use warnings;
-use parent 'Catalyst::Controller';
+use Moose;
+use namespace::autoclean;
+BEGIN { extends 'Catalyst::Controller' }

-sub index :Path :Args(0) {
+sub root : Chained('/') PathPart() CaptureArgs(0) {}
+
+sub index : Chained('root') PathPart('') Args(0) {
        my ( $self, $c ) = @_;

        # Hello World
        $c->response->body( $c->welcome_message );
    }

-sub default :Path {
+sub default : Private {
        my ( $self, $c ) = @_;
        $c->response->body( 'Page not found' );
        $c->response->status(404);
```

A new method, `root`, that will be the root path for our application. All our methods will be chained from this action. If start you catalyst server and go to **http://localhost:3000/** you will be served with the Catalyst's welcome message as before.

### lib/MyFeedReader/Controller/Entry.pm

```perl
-use warnings;
+use Moose;
 use MyAggregator::Entry;
-use parent 'Catalyst::Controller';
-
-__PACKAGE__->config->{namespace} = 'entry';
+use namespace::autoclean;
+BEGIN { extends 'Catalyst::Controller'; }

-sub view : Chained('/') : PathPart('entry') : Args(1) {
+sub view : Chained('/root') : PathPart('entry') : Args(1) {
     my ( $self, $c, $id ) = @_;

     $c->stash->{entry} = $c->model('KiokuDB')->lookup($id);
 }

-1;
-
+__PACKAGE__->meta->make_immutable;
```

We extends the **Catalyst::Controller** in a Moose way, and the `make_immutable` instruction is a Moose recommanded best practice (you can alsa add `no Moose` after the make_immutable).

### lib/MyFeedreader/Controller/Feed.pm

```perl
+use Moose;
+use namespace::autoclean;
+BEGIN { extends 'Catalyst::Controller' }

-use strict;
-use warnings;
-use parent 'Catalyst::Controller';
+sub feed : Chained('/root') PathPart('feed') CaptureArgs(0) {}

-__PACKAGE__->config->{namespace} = 'feed';
-
-sub index : Path : Args(0) {
+sub index : Chained('feed') PathPart('') Args(0) {
     my ( $self, $c ) = @_;

     $c->stash->{feeds}
         = [ $c->model('MyModel')->resultset('Feed')->search() ];
 }

-sub view : Chained('/') : PathPart('feed/view') : Args(1) {
+sub view : Chained('feed') : PathPart('view') : Args(1) {
     my ( $self, $c, $id ) = @_;

     $c->stash->{feed}
         = $c->model('MyModel')->resultset('Feed')->find($id);
 }

-1;
+__PACKAGE__->meta->make_immutable;
```

We got `feed` which is chained to root. `index` is chained to feed, and take no arguments. This method display the list of our feeds. And we got the `view` method, chained to feed too, but with one argument, that display the content of an entry.

If you start the application, you will see the following routes:


    .-------------------------------------+--------------------------------------.
    | Path Spec                           | Private                              |
    +-------------------------------------+--------------------------------------+
    | /root/entry/*                       | /root (0)                            |
    |                                     | => /entry/view                       |
    | /root/feed                          | /root (0)                            |
    |                                     | -> /feed/feed (0)                    |
    |                                     | => /feed/index                       |
    | /root/feed/view/*                   | /root (0)                            |
    |                                     | -> /feed/feed (0)                    |
    |                                     | => /feed/view                        |
    | /root                               | /root (0)                            |
    |                                     | => /index                            |
    '-------------------------------------+--------------------------------------'

I hope you got a better idea about chained action in catalyst now. And again, thanks to bobtfish for the code.