update Mojolicious and added Mojolicious::Plugin::INICo...
...nfig and display ssh URL
... | ... |
@@ -29,3 +29,4 @@ db/* |
29 | 29 |
!db/.gitignore |
30 | 30 |
extlib/* |
31 | 31 |
rep/* |
32 |
+gitprep.my.ini |
... | ... |
@@ -2,3 +2,6 @@ requires 'DBI', '== 1.621'; |
2 | 2 |
requires 'DBD::SQLite', '== 1.37'; |
3 | 3 |
requires 'Object::Simple', '== 3.08'; |
4 | 4 |
requires 'DBIx::Custom', '== 0.28'; |
5 |
+requires 'Mojolicious::Plugin::INIConfig', '== 0.02'; |
|
6 |
+requires 'Mojolicious', '== 3.91'; |
|
7 |
+requires 'Config::Tiny', '== 2.14'; |
... | ... |
@@ -0,0 +1,6 @@ |
1 |
+[basic] |
|
2 |
+;;; SSH port |
|
3 |
+;ssh_port=55555 |
|
4 |
+ |
|
5 |
+[hypnotoad] |
|
6 |
+listen=http://*:10020 |
... | ... |
@@ -0,0 +1,6 @@ |
1 |
+[basic] |
|
2 |
+;;; SSH port |
|
3 |
+ssh_port=55555 |
|
4 |
+ |
|
5 |
+[hypnotoad] |
|
6 |
+listen=http://*:10020 |
... | ... |
@@ -20,9 +20,12 @@ sub startup { |
20 | 20 |
my $self = shift; |
21 | 21 |
|
22 | 22 |
# Config |
23 |
- #my $conf_file = $ENV{GITPREP_CONFIG_FILE} |
|
24 |
- # || $self->home->rel_file('gitprep.conf'); |
|
25 |
- #$self->plugin('JSONConfigLoose', {file => $conf_file}) if -f $conf_file; |
|
23 |
+ $self->plugin('INIConfig', {ext => 'conf'}); |
|
24 |
+ |
|
25 |
+ # My Config(Development) |
|
26 |
+ my $my_conf_file = $self->home->rel_file('gitprep.my.conf'); |
|
27 |
+ $self->plugin('INIConfig', {file => $my_conf_file}) if -f $my_conf_file; |
|
28 |
+ |
|
26 | 29 |
my $conf = $self->config; |
27 | 30 |
$conf->{root} = $self->home->rel_file('rep'); |
28 | 31 |
$conf->{hypnotoad} ||= {listen => ["http://*:10020"]}; |
... | ... |
@@ -1,3 +0,0 @@ |
1 |
-This is Mojolicious v3.70 back porting to perl 5.8.7 |
|
2 |
- |
|
3 |
- https://github.com/jamadam/mojo-legacy |
... | ... |
@@ -15,10 +15,9 @@ has log => sub { Mojo::Log->new }; |
15 | 15 |
has ua => sub { |
16 | 16 |
my $self = shift; |
17 | 17 |
|
18 |
- # Fresh user agent |
|
19 | 18 |
my $ua = Mojo::UserAgent->new->app($self); |
20 | 19 |
weaken $self; |
21 |
- $ua->on(error => sub { $self->log->error(pop) }); |
|
20 |
+ $ua->on(error => sub { $self->log->error($_[1]) }); |
|
22 | 21 |
weaken $ua->{app}; |
23 | 22 |
|
24 | 23 |
return $ua; |
... | ... |
@@ -27,10 +26,8 @@ has ua => sub { |
27 | 26 |
sub new { |
28 | 27 |
my $self = shift->SUPER::new(@_); |
29 | 28 |
|
30 |
- # Detect home directory |
|
29 |
+ # Check if we have a log directory |
|
31 | 30 |
my $home = $self->home->detect(ref $self); |
32 |
- |
|
33 |
- # Log directory |
|
34 | 31 |
$self->log->path($home->rel_file('log/mojo.log')) |
35 | 32 |
if -w $home->rel_file('log'); |
36 | 33 |
|
... | ... |
@@ -101,7 +98,7 @@ See L<Mojolicious> for more! |
101 | 98 |
|
102 | 99 |
L<Mojo> implements the following attributes. |
103 | 100 |
|
104 |
-=head2 C<home> |
|
101 |
+=head2 home |
|
105 | 102 |
|
106 | 103 |
my $home = $app->home; |
107 | 104 |
$app = $app->home(Mojo::Home->new); |
... | ... |
@@ -112,7 +109,7 @@ which stringifies to the actual path. |
112 | 109 |
# Generate portable path relative to home directory |
113 | 110 |
my $path = $app->home->rel_file('data/important.txt'); |
114 | 111 |
|
115 |
-=head2 C<log> |
|
112 |
+=head2 log |
|
116 | 113 |
|
117 | 114 |
my $log = $app->log; |
118 | 115 |
$app = $app->log(Mojo::Log->new); |
... | ... |
@@ -122,7 +119,7 @@ The logging layer of your application, defaults to a L<Mojo::Log> object. |
122 | 119 |
# Log debug message |
123 | 120 |
$app->log->debug('It works!'); |
124 | 121 |
|
125 |
-=head2 C<ua> |
|
122 |
+=head2 ua |
|
126 | 123 |
|
127 | 124 |
my $ua = $app->ua; |
128 | 125 |
$app = $app->ua(Mojo::UserAgent->new); |
... | ... |
@@ -140,21 +137,21 @@ interfere with new blocking ones. |
140 | 137 |
L<Mojo> inherits all methods from L<Mojo::Base> and implements the following |
141 | 138 |
new ones. |
142 | 139 |
|
143 |
-=head2 C<new> |
|
140 |
+=head2 new |
|
144 | 141 |
|
145 | 142 |
my $app = Mojo->new; |
146 | 143 |
|
147 | 144 |
Construct a new L<Mojo> application. Will automatically detect your home |
148 | 145 |
directory and set up logging to C<log/mojo.log> if there's a C<log> directory. |
149 | 146 |
|
150 |
-=head2 C<build_tx> |
|
147 |
+=head2 build_tx |
|
151 | 148 |
|
152 | 149 |
my $tx = $app->build_tx; |
153 | 150 |
|
154 | 151 |
Transaction builder, defaults to building a L<Mojo::Transaction::HTTP> |
155 | 152 |
object. |
156 | 153 |
|
157 |
-=head2 C<config> |
|
154 |
+=head2 config |
|
158 | 155 |
|
159 | 156 |
my $config = $app->config; |
160 | 157 |
my $foo = $app->config('foo'); |
... | ... |
@@ -168,7 +165,7 @@ Application configuration. |
168 | 165 |
my $foo = $app->config->{foo}; |
169 | 166 |
delete $app->config->{foo}; |
170 | 167 |
|
171 |
-=head2 C<handler> |
|
168 |
+=head2 handler |
|
172 | 169 |
|
173 | 170 |
$app->handler(Mojo::Transaction::HTTP->new); |
174 | 171 |
|
... | ... |
@@ -40,18 +40,22 @@ Mojo::Asset - HTTP content storage base class |
40 | 40 |
|
41 | 41 |
L<Mojo::Asset> is an abstract base class for HTTP content storage. |
42 | 42 |
|
43 |
+=head1 EVENTS |
|
44 |
+ |
|
45 |
+L<Mojo::Asset> inherits all events from L<Mojo::EventEmitter>. |
|
46 |
+ |
|
43 | 47 |
=head1 ATTRIBUTES |
44 | 48 |
|
45 | 49 |
L<Mojo::Asset> implements the following attributes. |
46 | 50 |
|
47 |
-=head2 C<end_range> |
|
51 |
+=head2 end_range |
|
48 | 52 |
|
49 | 53 |
my $end = $asset->end_range; |
50 | 54 |
$asset = $asset->end_range(8); |
51 | 55 |
|
52 | 56 |
Pretend file ends earlier. |
53 | 57 |
|
54 |
-=head2 C<start_range> |
|
58 |
+=head2 start_range |
|
55 | 59 |
|
56 | 60 |
my $start = $asset->start_range; |
57 | 61 |
$asset = $asset->start_range(0); |
... | ... |
@@ -63,53 +67,53 @@ Pretend file starts later. |
63 | 67 |
L<Mojo::Asset> inherits all methods from L<Mojo::EventEmitter> and implements |
64 | 68 |
the following new ones. |
65 | 69 |
|
66 |
-=head2 C<add_chunk> |
|
70 |
+=head2 add_chunk |
|
67 | 71 |
|
68 | 72 |
$asset = $asset->add_chunk('foo bar baz'); |
69 | 73 |
|
70 | 74 |
Add chunk of data to asset. Meant to be overloaded in a subclass. |
71 | 75 |
|
72 |
-=head2 C<contains> |
|
76 |
+=head2 contains |
|
73 | 77 |
|
74 | 78 |
my $position = $asset->contains('bar'); |
75 | 79 |
|
76 | 80 |
Check if asset contains a specific string. Meant to be overloaded in a |
77 | 81 |
subclass. |
78 | 82 |
|
79 |
-=head2 C<get_chunk> |
|
83 |
+=head2 get_chunk |
|
80 | 84 |
|
81 |
- my $chunk = $asset->get_chunk($offset); |
|
85 |
+ my $bytes = $asset->get_chunk($offset); |
|
82 | 86 |
|
83 | 87 |
Get chunk of data starting from a specific position. Meant to be overloaded |
84 | 88 |
in a subclass. |
85 | 89 |
|
86 |
-=head2 C<is_file> |
|
90 |
+=head2 is_file |
|
87 | 91 |
|
88 | 92 |
my $false = $asset->is_file; |
89 | 93 |
|
90 | 94 |
False. |
91 | 95 |
|
92 |
-=head2 C<is_range> |
|
96 |
+=head2 is_range |
|
93 | 97 |
|
94 | 98 |
my $success = $asset->is_range; |
95 | 99 |
|
96 | 100 |
Check if asset has a C<start_range> or C<end_range>. |
97 | 101 |
|
98 |
-=head2 C<move_to> |
|
102 |
+=head2 move_to |
|
99 | 103 |
|
100 | 104 |
$asset = $asset->move_to('/home/sri/foo.txt'); |
101 | 105 |
|
102 | 106 |
Move asset data into a specific file. Meant to be overloaded in a subclass. |
103 | 107 |
|
104 |
-=head2 C<size> |
|
108 |
+=head2 size |
|
105 | 109 |
|
106 | 110 |
my $size = $asset->size; |
107 | 111 |
|
108 | 112 |
Size of asset data in bytes. Meant to be overloaded in a subclass. |
109 | 113 |
|
110 |
-=head2 C<slurp> |
|
114 |
+=head2 slurp |
|
111 | 115 |
|
112 |
- my $string = $asset->slurp; |
|
116 |
+ my $bytes = $asset->slurp; |
|
113 | 117 |
|
114 | 118 |
Read all asset data at once. Meant to be overloaded in a subclass. |
115 | 119 |
|
... | ... |
@@ -5,7 +5,7 @@ use Carp 'croak'; |
5 | 5 |
use Errno 'EEXIST'; |
6 | 6 |
use Fcntl qw(O_CREAT O_EXCL O_RDWR); |
7 | 7 |
use File::Copy 'move'; |
8 |
-use File::Spec; |
|
8 |
+use File::Spec::Functions 'catfile'; |
|
9 | 9 |
use IO::File; |
10 | 10 |
use Mojo::Util 'md5_sum'; |
11 | 11 |
|
... | ... |
@@ -17,12 +17,12 @@ has handle => sub { |
17 | 17 |
my $handle = IO::File->new; |
18 | 18 |
my $path = $self->path; |
19 | 19 |
if (defined $path && -f $path) { |
20 |
- $handle->open("< $path") or croak qq{Can't open file "$path": $!}; |
|
20 |
+ $handle->open($path, '<') or croak qq{Can't open file "$path": $!}; |
|
21 | 21 |
return $handle; |
22 | 22 |
} |
23 | 23 |
|
24 | 24 |
# Open new or temporary file |
25 |
- my $base = File::Spec->catfile($self->tmpdir, 'mojo.tmp'); |
|
25 |
+ my $base = catfile File::Spec::Functions::tmpdir, 'mojo.tmp'; |
|
26 | 26 |
my $name = defined $path ? $path : $base; |
27 | 27 |
until ($handle->open($name, O_CREAT | O_EXCL | O_RDWR)) { |
28 | 28 |
croak qq{Can't open file "$name": $!} if defined $path || $! != $!{EEXIST}; |
... | ... |
@@ -35,7 +35,7 @@ has handle => sub { |
35 | 35 |
|
36 | 36 |
return $handle; |
37 | 37 |
}; |
38 |
-has tmpdir => sub { $ENV{MOJO_TMPDIR} || File::Spec->tmpdir }; |
|
38 |
+has tmpdir => sub { $ENV{MOJO_TMPDIR} || File::Spec::Functions::tmpdir }; |
|
39 | 39 |
|
40 | 40 |
sub DESTROY { |
41 | 41 |
my $self = shift; |
... | ... |
@@ -59,7 +59,6 @@ sub add_chunk { |
59 | 59 |
sub contains { |
60 | 60 |
my ($self, $string) = @_; |
61 | 61 |
|
62 |
- # Seek to start |
|
63 | 62 |
my $handle = $self->handle; |
64 | 63 |
$handle->sysseek($self->start_range, SEEK_SET); |
65 | 64 |
|
... | ... |
@@ -95,12 +94,10 @@ sub contains { |
95 | 94 |
sub get_chunk { |
96 | 95 |
my ($self, $start) = @_; |
97 | 96 |
|
98 |
- # Seek to start |
|
99 | 97 |
$start += $self->start_range; |
100 | 98 |
my $handle = $self->handle; |
101 | 99 |
$handle->sysseek($start, SEEK_SET); |
102 | 100 |
|
103 |
- # Range support |
|
104 | 101 |
my $buffer; |
105 | 102 |
if (defined(my $end = $self->end_range)) { |
106 | 103 |
my $chunk = $end + 1 - $start; |
... | ... |
@@ -165,26 +162,30 @@ Mojo::Asset::File - File storage for HTTP content |
165 | 162 |
|
166 | 163 |
L<Mojo::Asset::File> is a file storage backend for HTTP content. |
167 | 164 |
|
165 |
+=head1 EVENTS |
|
166 |
+ |
|
167 |
+L<Mojo::Asset::File> inherits all events from L<Mojo::Asset>. |
|
168 |
+ |
|
168 | 169 |
=head1 ATTRIBUTES |
169 | 170 |
|
170 | 171 |
L<Mojo::Asset::File> inherits all attributes from L<Mojo::Asset> and |
171 | 172 |
implements the following new ones. |
172 | 173 |
|
173 |
-=head2 C<cleanup> |
|
174 |
+=head2 cleanup |
|
174 | 175 |
|
175 | 176 |
my $cleanup = $file->cleanup; |
176 | 177 |
$file = $file->cleanup(1); |
177 | 178 |
|
178 | 179 |
Delete file automatically once it's not used anymore. |
179 | 180 |
|
180 |
-=head2 C<handle> |
|
181 |
+=head2 handle |
|
181 | 182 |
|
182 | 183 |
my $handle = $file->handle; |
183 | 184 |
$file = $file->handle(IO::File->new); |
184 | 185 |
|
185 | 186 |
File handle, created on demand. |
186 | 187 |
|
187 |
-=head2 C<path> |
|
188 |
+=head2 path |
|
188 | 189 |
|
189 | 190 |
my $path = $file->path; |
190 | 191 |
$file = $file->path('/home/sri/foo.txt'); |
... | ... |
@@ -192,7 +193,7 @@ File handle, created on demand. |
192 | 193 |
File path used to create C<handle>, can also be automatically generated if |
193 | 194 |
necessary. |
194 | 195 |
|
195 |
-=head2 C<tmpdir> |
|
196 |
+=head2 tmpdir |
|
196 | 197 |
|
197 | 198 |
my $tmpdir = $file->tmpdir; |
198 | 199 |
$file = $file->tmpdir('/tmp'); |
... | ... |
@@ -205,45 +206,45 @@ C<MOJO_TMPDIR> environment variable or auto detection. |
205 | 206 |
L<Mojo::Asset::File> inherits all methods from L<Mojo::Asset> and implements |
206 | 207 |
the following new ones. |
207 | 208 |
|
208 |
-=head2 C<add_chunk> |
|
209 |
+=head2 add_chunk |
|
209 | 210 |
|
210 | 211 |
$file = $file->add_chunk('foo bar baz'); |
211 | 212 |
|
212 | 213 |
Add chunk of data. |
213 | 214 |
|
214 |
-=head2 C<contains> |
|
215 |
+=head2 contains |
|
215 | 216 |
|
216 | 217 |
my $position = $file->contains('bar'); |
217 | 218 |
|
218 | 219 |
Check if asset contains a specific string. |
219 | 220 |
|
220 |
-=head2 C<get_chunk> |
|
221 |
+=head2 get_chunk |
|
221 | 222 |
|
222 |
- my $chunk = $file->get_chunk($start); |
|
223 |
+ my $bytes = $file->get_chunk($start); |
|
223 | 224 |
|
224 | 225 |
Get chunk of data starting from a specific position. |
225 | 226 |
|
226 |
-=head2 C<is_file> |
|
227 |
+=head2 is_file |
|
227 | 228 |
|
228 | 229 |
my $true = $file->is_file; |
229 | 230 |
|
230 | 231 |
True. |
231 | 232 |
|
232 |
-=head2 C<move_to> |
|
233 |
+=head2 move_to |
|
233 | 234 |
|
234 | 235 |
$file = $file->move_to('/home/sri/bar.txt'); |
235 | 236 |
|
236 | 237 |
Move asset data into a specific file and disable C<cleanup>. |
237 | 238 |
|
238 |
-=head2 C<size> |
|
239 |
+=head2 size |
|
239 | 240 |
|
240 | 241 |
my $size = $file->size; |
241 | 242 |
|
242 | 243 |
Size of asset data in bytes. |
243 | 244 |
|
244 |
-=head2 C<slurp> |
|
245 |
+=head2 slurp |
|
245 | 246 |
|
246 |
- my $string = $file->slurp; |
|
247 |
+ my $bytes = $file->slurp; |
|
247 | 248 |
|
248 | 249 |
Read all asset data at once. |
249 | 250 |
|
... | ... |
@@ -73,9 +73,10 @@ L<Mojo::Asset::Memory> is an in-memory storage backend for HTTP content. |
73 | 73 |
|
74 | 74 |
=head1 EVENTS |
75 | 75 |
|
76 |
-L<Mojo::Asset::Memory> can emit the following events. |
|
76 |
+L<Mojo::Asset::Memory> inherits all events from L<Mojo::Asset> and can emit |
|
77 |
+the following new ones. |
|
77 | 78 |
|
78 |
-=head2 C<upgrade> |
|
79 |
+=head2 upgrade |
|
79 | 80 |
|
80 | 81 |
$mem->on(upgrade => sub { |
81 | 82 |
my ($mem, $file) = @_; |
... | ... |
@@ -94,7 +95,7 @@ Emitted when asset gets upgraded to a L<Mojo::Asset::File> object. |
94 | 95 |
L<Mojo::Asset::Memory> inherits all attributes from L<Mojo::Asset> and |
95 | 96 |
implements the following new ones. |
96 | 97 |
|
97 |
-=head2 C<auto_upgrade> |
|
98 |
+=head2 auto_upgrade |
|
98 | 99 |
|
99 | 100 |
my $upgrade = $mem->auto_upgrade; |
100 | 101 |
$mem = $mem->auto_upgrade(1); |
... | ... |
@@ -102,7 +103,7 @@ implements the following new ones. |
102 | 103 |
Try to detect if content size exceeds C<max_memory_size> limit and |
103 | 104 |
automatically upgrade to a L<Mojo::Asset::File> object. |
104 | 105 |
|
105 |
-=head2 C<max_memory_size> |
|
106 |
+=head2 max_memory_size |
|
106 | 107 |
|
107 | 108 |
my $size = $mem->max_memory_size; |
108 | 109 |
$mem = $mem->max_memory_size(1024); |
... | ... |
@@ -116,46 +117,46 @@ C<MOJO_MAX_MEMORY_SIZE> environment variable or C<262144>. |
116 | 117 |
L<Mojo::Asset::Memory> inherits all methods from L<Mojo::Asset> and implements |
117 | 118 |
the following new ones. |
118 | 119 |
|
119 |
-=head2 C<new> |
|
120 |
+=head2 new |
|
120 | 121 |
|
121 | 122 |
my $mem = Mojo::Asset::Memory->new; |
122 | 123 |
|
123 | 124 |
Construct a new L<Mojo::Asset::Memory> object. |
124 | 125 |
|
125 |
-=head2 C<add_chunk> |
|
126 |
+=head2 add_chunk |
|
126 | 127 |
|
127 | 128 |
$mem = $mem->add_chunk('foo bar baz'); |
128 | 129 |
my $file = $mem->add_chunk('abc' x 262144); |
129 | 130 |
|
130 | 131 |
Add chunk of data and upgrade to L<Mojo::Asset::File> object if necessary. |
131 | 132 |
|
132 |
-=head2 C<contains> |
|
133 |
+=head2 contains |
|
133 | 134 |
|
134 | 135 |
my $position = $mem->contains('bar'); |
135 | 136 |
|
136 | 137 |
Check if asset contains a specific string. |
137 | 138 |
|
138 |
-=head2 C<get_chunk> |
|
139 |
+=head2 get_chunk |
|
139 | 140 |
|
140 |
- my $chunk = $mem->get_chunk($offset); |
|
141 |
+ my $bytes = $mem->get_chunk($offset); |
|
141 | 142 |
|
142 | 143 |
Get chunk of data starting from a specific position. |
143 | 144 |
|
144 |
-=head2 C<move_to> |
|
145 |
+=head2 move_to |
|
145 | 146 |
|
146 | 147 |
$mem = $mem->move_to('/home/sri/foo.txt'); |
147 | 148 |
|
148 | 149 |
Move asset data into a specific file. |
149 | 150 |
|
150 |
-=head2 C<size> |
|
151 |
+=head2 size |
|
151 | 152 |
|
152 | 153 |
my $size = $mem->size; |
153 | 154 |
|
154 | 155 |
Size of asset data in bytes. |
155 | 156 |
|
156 |
-=head2 C<slurp> |
|
157 |
+=head2 slurp |
|
157 | 158 |
|
158 |
- my $string = mem->slurp; |
|
159 |
+ my $bytes = mem->slurp; |
|
159 | 160 |
|
160 | 161 |
Read all asset data at once. |
161 | 162 |
|
... | ... |
@@ -2,8 +2,6 @@ package Mojo::Base; |
2 | 2 |
|
3 | 3 |
use strict; |
4 | 4 |
use warnings; |
5 |
- |
|
6 |
-# Mojo modules are modern! |
|
7 | 5 |
use utf8; |
8 | 6 |
|
9 | 7 |
# No imports because we get subclassed, a lot! |
... | ... |
@@ -16,8 +14,6 @@ use IO::Handle (); |
16 | 14 |
sub import { |
17 | 15 |
my $class = shift; |
18 | 16 |
return unless my $flag = shift; |
19 |
- |
|
20 |
- # No limits! |
|
21 | 17 |
no strict 'refs'; |
22 | 18 |
|
23 | 19 |
# Base |
... | ... |
@@ -37,8 +33,6 @@ sub import { |
37 | 33 |
if ($flag) { |
38 | 34 |
my $caller = caller; |
39 | 35 |
push @{"${caller}::ISA"}, $flag; |
40 |
- |
|
41 |
- # Can haz? |
|
42 | 36 |
*{"${caller}::has"} = sub { attr($caller, @_) }; |
43 | 37 |
} |
44 | 38 |
|
... | ... |
@@ -64,14 +58,12 @@ sub attr { |
64 | 58 |
my ($class, $attrs, $default) = @_; |
65 | 59 |
return unless ($class = ref $class || $class) && $attrs; |
66 | 60 |
|
67 |
- # Check default |
|
68 |
- Carp::croak('Default has to be a code reference or constant value') |
|
61 |
+ Carp::croak 'Default has to be a code reference or constant value' |
|
69 | 62 |
if ref $default && ref $default ne 'CODE'; |
70 | 63 |
|
71 |
- # Create attributes |
|
64 |
+ # Compile attributes |
|
72 | 65 |
for my $attr (@{ref $attrs eq 'ARRAY' ? $attrs : [$attrs]}) { |
73 |
- Carp::croak(qq{Attribute "$attr" invalid}) |
|
74 |
- unless $attr =~ /^[a-zA-Z_]\w*$/; |
|
66 |
+ Carp::croak qq{Attribute "$attr" invalid} unless $attr =~ /^[a-zA-Z_]\w*$/; |
|
75 | 67 |
|
76 | 68 |
# Header (check arguments) |
77 | 69 |
my $code = "package $class;\nsub $attr {\n if (\@_ == 1) {\n"; |
... | ... |
@@ -100,7 +92,7 @@ sub attr { |
100 | 92 |
# We compile custom attribute code for speed |
101 | 93 |
no strict 'refs'; |
102 | 94 |
warn "-- Attribute $attr in $class\n$code\n\n" if $ENV{MOJO_BASE_DEBUG}; |
103 |
- Carp::croak("Mojo::Base error: $@") unless eval "$code;1"; |
|
95 |
+ Carp::croak "Mojo::Base error: $@" unless eval "$code;1"; |
|
104 | 96 |
} |
105 | 97 |
} |
106 | 98 |
|
... | ... |
@@ -184,7 +176,7 @@ All three forms save a lot of typing. |
184 | 176 |
L<Mojo::Base> exports the following functions if imported with the C<-base> |
185 | 177 |
flag or a base class. |
186 | 178 |
|
187 |
-=head2 C<has> |
|
179 |
+=head2 has |
|
188 | 180 |
|
189 | 181 |
has 'name'; |
190 | 182 |
has [qw(name1 name2 name3)]; |
... | ... |
@@ -199,7 +191,7 @@ Create attributes for hash-based objects, just like the C<attr> method. |
199 | 191 |
|
200 | 192 |
L<Mojo::Base> implements the following methods. |
201 | 193 |
|
202 |
-=head2 C<new> |
|
194 |
+=head2 new |
|
203 | 195 |
|
204 | 196 |
my $object = BaseSubClass->new; |
205 | 197 |
my $object = BaseSubClass->new(name => 'value'); |
... | ... |
@@ -208,7 +200,7 @@ L<Mojo::Base> implements the following methods. |
208 | 200 |
This base class provides a basic constructor for hash-based objects. You can |
209 | 201 |
pass it either a hash or a hash reference with attribute values. |
210 | 202 |
|
211 |
-=head2 C<attr> |
|
203 |
+=head2 attr |
|
212 | 204 |
|
213 | 205 |
$object->attr('name'); |
214 | 206 |
BaseSubClass->attr('name'); |
... | ... |
@@ -225,7 +217,7 @@ be excuted at accessor read time if there's no set value. Accessors can be |
225 | 217 |
chained, that means they return their invocant when they are called with an |
226 | 218 |
argument. |
227 | 219 |
|
228 |
-=head2 C<tap> |
|
220 |
+=head2 tap |
|
229 | 221 |
|
230 | 222 |
$object = $object->tap(sub {...}); |
231 | 223 |
|
... | ... |
@@ -11,10 +11,11 @@ our @EXPORT_OK = ('b'); |
11 | 11 |
# Turn most functions from Mojo::Util into methods |
12 | 12 |
my @UTILS = ( |
13 | 13 |
qw(b64_decode b64_encode camelize decamelize hmac_md5_sum hmac_sha1_sum), |
14 |
- qw(html_escape html_unescape md5_bytes md5_sum punycode_decode), |
|
15 |
- qw(punycode_encode quote sha1_bytes sha1_sum slurp spurt squish trim), |
|
16 |
- qw(unquote url_escape url_unescape xml_escape xor_encode) |
|
14 |
+ qw(html_unescape md5_bytes md5_sum punycode_decode punycode_encode quote), |
|
15 |
+ qw(sha1_bytes sha1_sum slurp spurt squish trim unquote url_escape), |
|
16 |
+ qw(url_unescape xml_escape xor_encode) |
|
17 | 17 |
); |
18 |
+push @UTILS, 'html_escape'; # DEPRECATED in Rainbow! |
|
18 | 19 |
for my $name (@UTILS) { |
19 | 20 |
my $sub = Mojo::Util->can($name); |
20 | 21 |
Mojo::Util::monkey_patch __PACKAGE__, $name, sub { |
... | ... |
@@ -85,7 +86,7 @@ Mojo::ByteStream - ByteStream |
85 | 86 |
|
86 | 87 |
# Use the alternative constructor |
87 | 88 |
use Mojo::ByteStream 'b'; |
88 |
- my $stream = b('foobarbaz')->html_escape; |
|
89 |
+ my $stream = b('foobarbaz')->b64_encode('')->say; |
|
89 | 90 |
|
90 | 91 |
=head1 DESCRIPTION |
91 | 92 |
|
... | ... |
@@ -96,7 +97,7 @@ manipulation functions in L<Mojo::Util>. |
96 | 97 |
|
97 | 98 |
L<Mojo::ByteStream> implements the following functions. |
98 | 99 |
|
99 |
-=head2 C<b> |
|
100 |
+=head2 b |
|
100 | 101 |
|
101 | 102 |
my $stream = b('test123'); |
102 | 103 |
|
... | ... |
@@ -107,19 +108,19 @@ Construct a new scalar-based L<Mojo::ByteStream> object. |
107 | 108 |
L<Mojo::ByteStream> inherits all methods from L<Mojo::Base> and implements the |
108 | 109 |
following new ones. |
109 | 110 |
|
110 |
-=head2 C<new> |
|
111 |
+=head2 new |
|
111 | 112 |
|
112 | 113 |
my $stream = Mojo::ByteStream->new('test123'); |
113 | 114 |
|
114 | 115 |
Construct a new scalar-based L<Mojo::ByteStream> object. |
115 | 116 |
|
116 |
-=head2 C<b64_decode> |
|
117 |
+=head2 b64_decode |
|
117 | 118 |
|
118 | 119 |
$stream = $stream->b64_decode; |
119 | 120 |
|
120 | 121 |
Base64 decode bytestream with L<Mojo::Util/"b64_decode">. |
121 | 122 |
|
122 |
-=head2 C<b64_encode> |
|
123 |
+=head2 b64_encode |
|
123 | 124 |
|
124 | 125 |
$stream = $stream->b64_encode; |
125 | 126 |
$stream = $stream->b64_encode("\n"); |
... | ... |
@@ -128,25 +129,25 @@ Base64 encode bytestream with L<Mojo::Util/"b64_encode">. |
128 | 129 |
|
129 | 130 |
b('foo bar baz')->b64_encode('')->say; |
130 | 131 |
|
131 |
-=head2 C<camelize> |
|
132 |
+=head2 camelize |
|
132 | 133 |
|
133 | 134 |
$stream = $stream->camelize; |
134 | 135 |
|
135 | 136 |
Camelize bytestream with L<Mojo::Util/"camelize">. |
136 | 137 |
|
137 |
-=head2 C<clone> |
|
138 |
+=head2 clone |
|
138 | 139 |
|
139 | 140 |
my $stream2 = $stream->clone; |
140 | 141 |
|
141 | 142 |
Clone bytestream. |
142 | 143 |
|
143 |
-=head2 C<decamelize> |
|
144 |
+=head2 decamelize |
|
144 | 145 |
|
145 | 146 |
$stream = $stream->decamelize; |
146 | 147 |
|
147 | 148 |
Decamelize bytestream with L<Mojo::Util/"decamelize">. |
148 | 149 |
|
149 |
-=head2 C<decode> |
|
150 |
+=head2 decode |
|
150 | 151 |
|
151 | 152 |
$stream = $stream->decode; |
152 | 153 |
$stream = $stream->decode('iso-8859-1'); |
... | ... |
@@ -155,7 +156,7 @@ Decode bytestream with L<Mojo::Util/"decode">, defaults to C<UTF-8>. |
155 | 156 |
|
156 | 157 |
$stream->decode('UTF-16LE')->unquote->trim->say; |
157 | 158 |
|
158 |
-=head2 C<encode> |
|
159 |
+=head2 encode |
|
159 | 160 |
|
160 | 161 |
$stream = $stream->encode; |
161 | 162 |
$stream = $stream->encode('iso-8859-1'); |
... | ... |
@@ -164,13 +165,13 @@ Encode bytestream with L<Mojo::Util/"encode">, defaults to C<UTF-8>. |
164 | 165 |
|
165 | 166 |
$stream->trim->quote->encode->say; |
166 | 167 |
|
167 |
-=head2 C<hmac_md5_sum> |
|
168 |
+=head2 hmac_md5_sum |
|
168 | 169 |
|
169 | 170 |
$stream = $stream->hmac_md5_sum('passw0rd'); |
170 | 171 |
|
171 | 172 |
Generate HMAC-MD5 checksum for bytestream with L<Mojo::Util/"hmac_md5_sum">. |
172 | 173 |
|
173 |
-=head2 C<hmac_sha1_sum> |
|
174 |
+=head2 hmac_sha1_sum |
|
174 | 175 |
|
175 | 176 |
$stream = $stream->hmac_sha1_sum('passw0rd'); |
176 | 177 |
|
... | ... |
@@ -178,16 +179,7 @@ Generate HMAC-SHA1 checksum for bytestream with L<Mojo::Util/"hmac_sha1_sum">. |
178 | 179 |
|
179 | 180 |
b('foo bar baz')->hmac_sha1_sum('secr3t')->quote->say; |
180 | 181 |
|
181 |
-=head2 C<html_escape> |
|
182 |
- |
|
183 |
- $stream = $stream->html_escape; |
|
184 |
- $stream = $stream->html_escape('^\n\r\t !#$%(-;=?-~'); |
|
185 |
- |
|
186 |
-Escape unsafe characters in bytestream with L<Mojo::Util/"html_escape">. |
|
187 |
- |
|
188 |
- b('<html>')->html_escape->say; |
|
189 |
- |
|
190 |
-=head2 C<html_unescape> |
|
182 |
+=head2 html_unescape |
|
191 | 183 |
|
192 | 184 |
$stream = $stream->html_unescape; |
193 | 185 |
|
... | ... |
@@ -195,44 +187,44 @@ Unescape all HTML entities in bytestream with L<Mojo::Util/"html_unescape">. |
195 | 187 |
|
196 | 188 |
b('<html>')->html_unescape->url_escape->say; |
197 | 189 |
|
198 |
-=head2 C<md5_bytes> |
|
190 |
+=head2 md5_bytes |
|
199 | 191 |
|
200 | 192 |
$stream = $stream->md5_bytes; |
201 | 193 |
|
202 | 194 |
Generate binary MD5 checksum for bytestream with L<Mojo::Util/"md5_bytes">. |
203 | 195 |
|
204 |
-=head2 C<md5_sum> |
|
196 |
+=head2 md5_sum |
|
205 | 197 |
|
206 | 198 |
$stream = $stream->md5_sum; |
207 | 199 |
|
208 | 200 |
Generate MD5 checksum for bytestream with L<Mojo::Util/"md5_sum">. |
209 | 201 |
|
210 |
-=head2 C<punycode_decode> |
|
202 |
+=head2 punycode_decode |
|
211 | 203 |
|
212 | 204 |
$stream = $stream->punycode_decode; |
213 | 205 |
|
214 | 206 |
Punycode decode bytestream with L<Mojo::Util/"punycode_decode">. |
215 | 207 |
|
216 |
-=head2 C<punycode_encode> |
|
208 |
+=head2 punycode_encode |
|
217 | 209 |
|
218 | 210 |
$stream = $stream->punycode_encode; |
219 | 211 |
|
220 | 212 |
Punycode encode bytestream with L<Mojo::Util/"punycode_encode">. |
221 | 213 |
|
222 |
-=head2 C<quote> |
|
214 |
+=head2 quote |
|
223 | 215 |
|
224 | 216 |
$stream = $stream->quote; |
225 | 217 |
|
226 | 218 |
Quote bytestream with L<Mojo::Util/"quote">. |
227 | 219 |
|
228 |
-=head2 C<say> |
|
220 |
+=head2 say |
|
229 | 221 |
|
230 | 222 |
$stream->say; |
231 | 223 |
$stream->say(*STDERR); |
232 | 224 |
|
233 | 225 |
Print bytestream to handle and append a newline, defaults to C<STDOUT>. |
234 | 226 |
|
235 |
-=head2 C<secure_compare> |
|
227 |
+=head2 secure_compare |
|
236 | 228 |
|
237 | 229 |
my $success = $stream->secure_compare($string); |
238 | 230 |
|
... | ... |
@@ -240,25 +232,25 @@ Compare bytestream with L<Mojo::Util/"secure_compare">. |
240 | 232 |
|
241 | 233 |
say 'Match!' if b('foo')->secure_compare('foo'); |
242 | 234 |
|
243 |
-=head2 C<sha1_bytes> |
|
235 |
+=head2 sha1_bytes |
|
244 | 236 |
|
245 | 237 |
$stream = $stream->sha1_bytes; |
246 | 238 |
|
247 | 239 |
Generate binary SHA1 checksum for bytestream with L<Mojo::Util/"sha1_bytes">. |
248 | 240 |
|
249 |
-=head2 C<sha1_sum> |
|
241 |
+=head2 sha1_sum |
|
250 | 242 |
|
251 | 243 |
$stream = $stream->sha1_sum; |
252 | 244 |
|
253 | 245 |
Generate SHA1 checksum for bytestream with L<Mojo::Util/"sha1_sum">. |
254 | 246 |
|
255 |
-=head2 C<size> |
|
247 |
+=head2 size |
|
256 | 248 |
|
257 | 249 |
my $size = $stream->size; |
258 | 250 |
|
259 | 251 |
Size of bytestream. |
260 | 252 |
|
261 |
-=head2 C<slurp> |
|
253 |
+=head2 slurp |
|
262 | 254 |
|
263 | 255 |
$stream = $stream->slurp; |
264 | 256 |
|
... | ... |
@@ -266,7 +258,7 @@ Read all data at once from file into bytestream with L<Mojo::Util/"slurp">. |
266 | 258 |
|
267 | 259 |
b('/home/sri/myapp.pl')->slurp->split("\n")->shuffle->join("\n")->say; |
268 | 260 |
|
269 |
-=head2 C<spurt> |
|
261 |
+=head2 spurt |
|
270 | 262 |
|
271 | 263 |
$stream = $stream->spurt('/home/sri/myapp.pl'); |
272 | 264 |
|
... | ... |
@@ -274,7 +266,7 @@ Write all data from bytestream at once to file with L<Mojo::Util/"spurt">. |
274 | 266 |
|
275 | 267 |
b('/home/sri/foo.txt')->slurp->squish->spurt('/home/sri/bar.txt'); |
276 | 268 |
|
277 |
-=head2 C<split> |
|
269 |
+=head2 split |
|
278 | 270 |
|
279 | 271 |
my $collection = $stream->split(','); |
280 | 272 |
|
... | ... |
@@ -282,7 +274,7 @@ Turn bytestream into L<Mojo::Collection>. |
282 | 274 |
|
283 | 275 |
b('a,b,c')->split(',')->pluck('quote')->join(',')->say; |
284 | 276 |
|
285 |
-=head2 C<squish> |
|
277 |
+=head2 squish |
|
286 | 278 |
|
287 | 279 |
$stream = $stream->squish; |
288 | 280 |
|
... | ... |
@@ -290,27 +282,27 @@ Trim whitespace characters from both ends of bytestream and then change all |
290 | 282 |
consecutive groups of whitespace into one space each with |
291 | 283 |
L<Mojo::Util/"squish">. |
292 | 284 |
|
293 |
-=head2 C<to_string> |
|
285 |
+=head2 to_string |
|
294 | 286 |
|
295 | 287 |
my $string = $stream->to_string; |
296 | 288 |
my $string = "$stream"; |
297 | 289 |
|
298 | 290 |
Stringify bytestream. |
299 | 291 |
|
300 |
-=head2 C<trim> |
|
292 |
+=head2 trim |
|
301 | 293 |
|
302 | 294 |
$stream = $stream->trim; |
303 | 295 |
|
304 | 296 |
Trim whitespace characters from both ends of bytestream with |
305 | 297 |
L<Mojo::Util/"trim">. |
306 | 298 |
|
307 |
-=head2 C<unquote> |
|
299 |
+=head2 unquote |
|
308 | 300 |
|
309 | 301 |
$stream = $stream->unquote; |
310 | 302 |
|
311 | 303 |
Unquote bytestream with L<Mojo::Util/"unquote">. |
312 | 304 |
|
313 |
-=head2 C<url_escape> |
|
305 |
+=head2 url_escape |
|
314 | 306 |
|
315 | 307 |
$stream = $stream->url_escape; |
316 | 308 |
$stream = $stream->url_escape('^A-Za-z0-9\-._~'); |
... | ... |
@@ -320,23 +312,23 @@ L<Mojo::Util/"url_escape">. |
320 | 312 |
|
321 | 313 |
b('foo bar baz')->url_escape->say; |
322 | 314 |
|
323 |
-=head2 C<url_unescape> |
|
315 |
+=head2 url_unescape |
|
324 | 316 |
|
325 | 317 |
$stream = $stream->url_unescape; |
326 | 318 |
|
327 | 319 |
Decode percent encoded characters in bytestream with |
328 | 320 |
L<Mojo::Util/"url_unescape">. |
329 | 321 |
|
330 |
- b('%3Chtml%3E')->url_unescape->html_escape->say; |
|
322 |
+ b('%3Chtml%3E')->url_unescape->xml_escape->say; |
|
331 | 323 |
|
332 |
-=head2 C<xml_escape> |
|
324 |
+=head2 xml_escape |
|
333 | 325 |
|
334 | 326 |
$stream = $stream->xml_escape; |
335 | 327 |
|
336 | 328 |
Escape only the characters C<&>, C<E<lt>>, C<E<gt>>, C<"> and C<'> in |
337 | 329 |
bytestream with L<Mojo::Util/"xml_escape">. |
338 | 330 |
|
339 |
-=head2 C<xor_encode> |
|
331 |
+=head2 xor_encode |
|
340 | 332 |
|
341 | 333 |
$stream = $stream->xor_encode($key); |
342 | 334 |
|
... | ... |
@@ -8,7 +8,6 @@ sub get { (shift->{cache} || {})->{shift()} } |
8 | 8 |
sub set { |
9 | 9 |
my ($self, $key, $value) = @_; |
10 | 10 |
|
11 |
- # Cache with size limit |
|
12 | 11 |
my $cache = $self->{cache} ||= {}; |
13 | 12 |
my $queue = $self->{queue} ||= []; |
14 | 13 |
delete $cache->{shift @$queue} if @$queue >= $self->max_keys; |
... | ... |
@@ -40,7 +39,7 @@ L<Mojo::Cache> is a naive in-memory cache with size limits. |
40 | 39 |
|
41 | 40 |
L<Mojo::Cache> implements the following attributes. |
42 | 41 |
|
43 |
-=head2 C<max_keys> |
|
42 |
+=head2 max_keys |
|
44 | 43 |
|
45 | 44 |
my $max = $cache->max_keys; |
46 | 45 |
$cache = $cache->max_keys(50); |
... | ... |
@@ -52,13 +51,13 @@ Maximum number of cache keys, defaults to C<100>. |
52 | 51 |
L<Mojo::Cache> inherits all methods from L<Mojo::Base> and implements the |
53 | 52 |
following new ones. |
54 | 53 |
|
55 |
-=head2 C<get> |
|
54 |
+=head2 get |
|
56 | 55 |
|
57 | 56 |
my $value = $cache->get('foo'); |
58 | 57 |
|
59 | 58 |
Get cached value. |
60 | 59 |
|
61 |
-=head2 C<set> |
|
60 |
+=head2 set |
|
62 | 61 |
|
63 | 62 |
$cache = $cache->set(foo => 'bar'); |
64 | 63 |
|
... | ... |
@@ -112,7 +112,7 @@ L<Mojo::Collection> is a container for collections. |
112 | 112 |
|
113 | 113 |
L<Mojo::Collection> implements the following functions. |
114 | 114 |
|
115 |
-=head2 C<c> |
|
115 |
+=head2 c |
|
116 | 116 |
|
117 | 117 |
my $collection = c(1, 2, 3); |
118 | 118 |
|
... | ... |
@@ -123,13 +123,13 @@ Construct a new array-based L<Mojo::Collection> object. |
123 | 123 |
L<Mojo::Collection> inherits all methods from L<Mojo::Base> and implements the |
124 | 124 |
following new ones. |
125 | 125 |
|
126 |
-=head2 C<new> |
|
126 |
+=head2 new |
|
127 | 127 |
|
128 | 128 |
my $collection = Mojo::Collection->new(1, 2, 3); |
129 | 129 |
|
130 | 130 |
Construct a new array-based L<Mojo::Collection> object. |
131 | 131 |
|
132 |
-=head2 C<each> |
|
132 |
+=head2 each |
|
133 | 133 |
|
134 | 134 |
my @elements = $collection->each; |
135 | 135 |
$collection = $collection->each(sub {...}); |
... | ... |
@@ -141,7 +141,7 @@ Evaluate callback for each element in collection. |
141 | 141 |
say "$count: $e"; |
142 | 142 |
}); |
143 | 143 |
|
144 |
-=head2 C<first> |
|
144 |
+=head2 first |
|
145 | 145 |
|
146 | 146 |
my $first = $collection->first; |
147 | 147 |
my $first = $collection->first(qr/foo/); |
... | ... |
@@ -153,7 +153,7 @@ callback returned true. |
153 | 153 |
|
154 | 154 |
my $five = $collection->first(sub { $_ == 5 }); |
155 | 155 |
|
156 |
-=head2 C<grep> |
|
156 |
+=head2 grep |
|
157 | 157 |
|
158 | 158 |
my $new = $collection->grep(qr/foo/); |
159 | 159 |
my $new = $collection->grep(sub {...}); |
... | ... |
@@ -164,7 +164,7 @@ or for which the callback returned true. |
164 | 164 |
|
165 | 165 |
my $interesting = $collection->grep(qr/mojo/i); |
166 | 166 |
|
167 |
-=head2 C<join> |
|
167 |
+=head2 join |
|
168 | 168 |
|
169 | 169 |
my $stream = $collection->join("\n"); |
170 | 170 |
|
... | ... |
@@ -172,7 +172,7 @@ Turn collection into L<Mojo::ByteStream>. |
172 | 172 |
|
173 | 173 |
$collection->join("\n")->say; |
174 | 174 |
|
175 |
-=head2 C<map> |
|
175 |
+=head2 map |
|
176 | 176 |
|
177 | 177 |
my $new = $collection->map(sub {...}); |
178 | 178 |
|
... | ... |
@@ -181,7 +181,7 @@ from the results. |
181 | 181 |
|
182 | 182 |
my $doubled = $collection->map(sub { $_ * 2 }); |
183 | 183 |
|
184 |
-=head2 C<pluck> |
|
184 |
+=head2 pluck |
|
185 | 185 |
|
186 | 186 |
my $new = $collection->pluck($method); |
187 | 187 |
my $new = $collection->pluck($method, @args); |
... | ... |
@@ -192,31 +192,31 @@ results. |
192 | 192 |
# Equal to but more convenient than |
193 | 193 |
my $new = $collection->map(sub { $_->$method(@args) }); |
194 | 194 |
|
195 |
-=head2 C<reverse> |
|
195 |
+=head2 reverse |
|
196 | 196 |
|
197 | 197 |
my $new = $collection->reverse; |
198 | 198 |
|
199 | 199 |
Create a new collection with all elements in reverse order. |
200 | 200 |
|
201 |
-=head2 C<slice> |
|
201 |
+=head2 slice |
|
202 | 202 |
|
203 | 203 |
my $new = $collection->slice(4 .. 7); |
204 | 204 |
|
205 | 205 |
Create a new collection with all selected elements. |
206 | 206 |
|
207 |
-=head2 C<shuffle> |
|
207 |
+=head2 shuffle |
|
208 | 208 |
|
209 | 209 |
my $new = $collection->shuffle; |
210 | 210 |
|
211 | 211 |
Create a new collection with all elements in random order. |
212 | 212 |
|
213 |
-=head2 C<size> |
|
213 |
+=head2 size |
|
214 | 214 |
|
215 | 215 |
my $size = $collection->size; |
216 | 216 |
|
217 | 217 |
Number of elements in collection. |
218 | 218 |
|
219 |
-=head2 C<sort> |
|
219 |
+=head2 sort |
|
220 | 220 |
|
221 | 221 |
my $new = $collection->sort; |
222 | 222 |
my $new = $collection->sort(sub {...}); |
... | ... |
@@ -226,7 +226,7 @@ from the results. |
226 | 226 |
|
227 | 227 |
my $insensitive = $collection->sort(sub { uc(shift) cmp uc(shift) }); |
228 | 228 |
|
229 |
-=head2 C<uniq> |
|
229 |
+=head2 uniq |
|
230 | 230 |
|
231 | 231 |
my $new = $collection->uniq; |
232 | 232 |
|
... | ... |
@@ -40,14 +40,9 @@ sub clone { |
40 | 40 |
sub generate_body_chunk { |
41 | 41 |
my ($self, $offset) = @_; |
42 | 42 |
|
43 |
- # Drain |
|
44 | 43 |
$self->emit(drain => $offset) |
45 | 44 |
if !delete $self->{delay} && !length(defined $self->{body_buffer} ? $self->{body_buffer} : ''); |
46 |
- |
|
47 |
- # Get chunk |
|
48 |
- my $chunk = do { my $tmp = (delete $self->{body_buffer}); defined $tmp ? $tmp : '' }; |
|
49 |
- |
|
50 |
- # EOF or delay |
|
45 |
+ my $chunk = do { my $tmp = delete $self->{body_buffer}; defined $tmp ? $tmp : '' }; |
|
51 | 46 |
return $self->{eof} ? '' : undef unless length $chunk; |
52 | 47 |
|
53 | 48 |
return $chunk; |
... | ... |
@@ -92,12 +87,12 @@ sub leftovers { shift->{buffer} } |
92 | 87 |
sub parse { |
93 | 88 |
my $self = shift; |
94 | 89 |
|
95 |
- # Parse headers |
|
90 |
+ # Headers |
|
96 | 91 |
$self->_parse_until_body(@_); |
97 | 92 |
return $self if $self->{state} eq 'headers'; |
98 | 93 |
$self->emit('body') unless $self->{body}++; |
99 | 94 |
|
100 |
- # Parse chunked content |
|
95 |
+ # Chunked content |
|
101 | 96 |
$self->{real_size} = defined $self->{real_size} ? $self->{real_size} : 0; |
102 | 97 |
if ($self->is_chunked && $self->{state} ne 'headers') { |
103 | 98 |
$self->_parse_chunked; |
... | ... |
@@ -130,7 +125,7 @@ sub parse { |
130 | 125 |
|
131 | 126 |
# Chunked or relaxed content |
132 | 127 |
if ($self->is_chunked || $self->relaxed) { |
133 |
- $self->{size} += length(defined $self->{buffer} ? $self->{buffer} : ''); |
|
128 |
+ $self->{size} += length($self->{buffer} = defined $self->{buffer} ? $self->{buffer} : ''); |
|
134 | 129 |
$self->_uncompress($self->{buffer}); |
135 | 130 |
$self->{buffer} = ''; |
136 | 131 |
} |
... | ... |
@@ -140,12 +135,11 @@ sub parse { |
140 | 135 |
my $len = $headers->content_length || 0; |
141 | 136 |
$self->{size} ||= 0; |
142 | 137 |
if ((my $need = $len - $self->{size}) > 0) { |
143 |
- my $chunk = substr $self->{buffer}, 0, $need, ''; |
|
138 |
+ my $len = length $self->{buffer}; |
|
139 |
+ my $chunk = substr $self->{buffer}, 0, $need > $len ? $len : $need, ''; |
|
144 | 140 |
$self->_uncompress($chunk); |
145 | 141 |
$self->{size} += length $chunk; |
146 | 142 |
} |
147 |
- |
|
148 |
- # Finished |
|
149 | 143 |
$self->{state} = 'finished' if $len <= $self->progress; |
150 | 144 |
} |
151 | 145 |
|
... | ... |
@@ -168,19 +162,10 @@ sub progress { |
168 | 162 |
sub write { |
169 | 163 |
my ($self, $chunk, $cb) = @_; |
170 | 164 |
|
171 |
- # Dynamic content |
|
172 | 165 |
$self->{dynamic} = 1; |
173 |
- |
|
174 |
- # Add chunk |
|
175 | 166 |
if (defined $chunk) { $self->{body_buffer} .= $chunk } |
176 |
- |
|
177 |
- # Delay |
|
178 |
- else { $self->{delay} = 1 } |
|
179 |
- |
|
180 |
- # Drain |
|
167 |
+ else { $self->{delay} = 1 } |
|
181 | 168 |
$self->once(drain => $cb) if $cb; |
182 |
- |
|
183 |
- # Finish |
|
184 | 169 |
$self->{eof} = 1 if defined $chunk && $chunk eq ''; |
185 | 170 |
|
186 | 171 |
return $self; |
... | ... |
@@ -188,23 +173,15 @@ sub write { |
188 | 173 |
|
189 | 174 |
sub write_chunk { |
190 | 175 |
my ($self, $chunk, $cb) = @_; |
191 |
- |
|
192 |
- # Chunked transfer encoding |
|
193 | 176 |
$self->headers->transfer_encoding('chunked') unless $self->is_chunked; |
194 |
- |
|
195 |
- # Write |
|
196 | 177 |
$self->write(defined $chunk ? $self->_build_chunk($chunk) : $chunk, $cb); |
197 |
- |
|
198 |
- # Finish |
|
199 | 178 |
$self->{eof} = 1 if defined $chunk && $chunk eq ''; |
200 |
- |
|
201 | 179 |
return $self; |
202 | 180 |
} |
203 | 181 |
|
204 | 182 |
sub _build { |
205 | 183 |
my ($self, $method) = @_; |
206 | 184 |
|
207 |
- # Build part from chunks |
|
208 | 185 |
my $buffer = ''; |
209 | 186 |
my $offset = 0; |
210 | 187 |
while (1) { |
... | ... |
@@ -215,7 +192,6 @@ sub _build { |
215 | 192 |
# End of part |
216 | 193 |
last unless my $len = length $chunk; |
217 | 194 |
|
218 |
- # Part |
|
219 | 195 |
$offset += $len; |
220 | 196 |
$buffer .= $chunk; |
221 | 197 |
} |
... | ... |
@@ -241,7 +217,6 @@ sub _parse_chunked { |
241 | 217 |
return $self->_parse_chunked_trailing_headers |
242 | 218 |
if (defined $self->{chunk_state} ? $self->{chunk_state} : '') eq 'trailing_headers'; |
243 | 219 |
|
244 |
- # Parse chunks |
|
245 | 220 |
while (my $len = length $self->{pre_buffer}) { |
246 | 221 |
|
247 | 222 |
# Start new chunk (ignore the chunk extension) |
... | ... |
@@ -274,7 +249,6 @@ sub _parse_chunked { |
274 | 249 |
sub _parse_chunked_trailing_headers { |
275 | 250 |
my $self = shift; |
276 | 251 |
|
277 |
- # Parse |
|
278 | 252 |
my $headers = $self->headers->parse(delete $self->{pre_buffer}); |
279 | 253 |
return unless $headers->is_finished; |
280 | 254 |
$self->{chunk_state} = 'finished'; |
... | ... |
@@ -287,7 +261,6 @@ sub _parse_chunked_trailing_headers { |
287 | 261 |
sub _parse_headers { |
288 | 262 |
my $self = shift; |
289 | 263 |
|
290 |
- # Parse |
|
291 | 264 |
my $headers = $self->headers->parse(delete $self->{pre_buffer}); |
292 | 265 |
return unless $headers->is_finished; |
293 | 266 |
$self->{state} = 'body'; |
... | ... |
@@ -301,21 +274,13 @@ sub _parse_headers { |
301 | 274 |
sub _parse_until_body { |
302 | 275 |
my ($self, $chunk) = @_; |
303 | 276 |
|
304 |
- # Add chunk |
|
305 | 277 |
$self->{raw_size} += length($chunk = defined $chunk ? $chunk : ''); |
306 | 278 |
$self->{pre_buffer} .= $chunk; |
307 | 279 |
|
308 |
- # Parser started |
|
309 | 280 |
unless ($self->{state}) { |
310 |
- |
|
311 |
- # Update size |
|
312 | 281 |
$self->{header_size} = $self->{raw_size} - length $self->{pre_buffer}; |
313 |
- |
|
314 |
- # Headers |
|
315 |
- $self->{state} = 'headers'; |
|
282 |
+ $self->{state} = 'headers'; |
|
316 | 283 |
} |
317 |
- |
|
318 |
- # Parse headers |
|
319 | 284 |
$self->_parse_headers if (defined $self->{state} ? $self->{state} : '') eq 'headers'; |
320 | 285 |
} |
321 | 286 |
|
... | ... |
@@ -363,9 +328,10 @@ RFC 2616. |
363 | 328 |
|
364 | 329 |
=head1 EVENTS |
365 | 330 |
|
366 |
-L<Mojo::Content> can emit the following events. |
|
331 |
+L<Mojo::Content> inherits all events from L<Mojo::EventEmitter> and can emit |
|
332 |
+the following new ones. |
|
367 | 333 |
|
368 |
-=head2 C<body> |
|
334 |
+=head2 body |
|
369 | 335 |
|
370 | 336 |
$content->on(body => sub { |
371 | 337 |
my $content = shift; |
... | ... |
@@ -379,7 +345,7 @@ Emitted once all headers have been parsed and the body starts. |
379 | 345 |
$content->auto_upgrade(0) if $content->headers->header('X-No-MultiPart'); |
380 | 346 |
}); |
381 | 347 |
|
382 |
-=head2 C<drain> |
|
348 |
+=head2 drain |
|
383 | 349 |
|
384 | 350 |
$content->on(drain => sub { |
385 | 351 |
my ($content, $offset) = @_; |
... | ... |
@@ -393,10 +359,10 @@ Emitted once all data has been written. |
393 | 359 |
$content->write_chunk(time); |
394 | 360 |
}); |
395 | 361 |
|
396 |
-=head2 C<read> |
|
362 |
+=head2 read |
|
397 | 363 |
|
398 | 364 |
$content->on(read => sub { |
399 |
- my ($content, $chunk) = @_; |
|
365 |
+ my ($content, $bytes) = @_; |
|
400 | 366 |
... |
401 | 367 |
}); |
402 | 368 |
|
... | ... |
@@ -404,29 +370,29 @@ Emitted when a new chunk of content arrives. |
404 | 370 |
|
405 | 371 |
$content->unsubscribe('read'); |
406 | 372 |
$content->on(read => sub { |
407 |
- my ($content, $chunk) = @_; |
|
408 |
- say "Streaming: $chunk"; |
|
373 |
+ my ($content, $bytes) = @_; |
|
374 |
+ say "Streaming: $bytes"; |
|
409 | 375 |
}); |
410 | 376 |
|
411 | 377 |
=head1 ATTRIBUTES |
412 | 378 |
|
413 | 379 |
L<Mojo::Content> implements the following attributes. |
414 | 380 |
|
415 |
-=head2 C<auto_relax> |
|
381 |
+=head2 auto_relax |
|
416 | 382 |
|
417 | 383 |
my $relax = $content->auto_relax; |
418 | 384 |
$content = $content->auto_relax(1); |
419 | 385 |
|
420 | 386 |
Try to detect when relaxed parsing is necessary. |
421 | 387 |
|
422 |
-=head2 C<headers> |
|
388 |
+=head2 headers |
|
423 | 389 |
|
424 | 390 |
my $headers = $content->headers; |
425 | 391 |
$content = $content->headers(Mojo::Headers->new); |
426 | 392 |
|
427 | 393 |
Content headers, defaults to a L<Mojo::Headers> object. |
428 | 394 |
|
429 |
-=head2 C<max_buffer_size> |
|
395 |
+=head2 max_buffer_size |
|
430 | 396 |
|
431 | 397 |
my $size = $content->max_buffer_size; |
432 | 398 |
$content = $content->max_buffer_size(1024); |
... | ... |
@@ -434,7 +400,7 @@ Content headers, defaults to a L<Mojo::Headers> object. |
434 | 400 |
Maximum size in bytes of buffer for content parser, defaults to the value of |
435 | 401 |
the C<MOJO_MAX_BUFFER_SIZE> environment variable or C<262144>. |
436 | 402 |
|
437 |
-=head2 C<max_leftover_size> |
|
403 |
+=head2 max_leftover_size |
|
438 | 404 |
|
439 | 405 |
my $size = $content->max_leftover_size; |
440 | 406 |
$content = $content->max_leftover_size(1024); |
... | ... |
@@ -442,7 +408,7 @@ the C<MOJO_MAX_BUFFER_SIZE> environment variable or C<262144>. |
442 | 408 |
Maximum size in bytes of buffer for pipelined HTTP requests, defaults to the |
443 | 409 |
value of the C<MOJO_MAX_LEFTOVER_SIZE> environment variable or C<262144>. |
444 | 410 |
|
445 |
-=head2 C<relaxed> |
|
411 |
+=head2 relaxed |
|
446 | 412 |
|
447 | 413 |
my $relaxed = $content->relaxed; |
448 | 414 |
$content = $content->relaxed(1); |
... | ... |
@@ -450,7 +416,7 @@ value of the C<MOJO_MAX_LEFTOVER_SIZE> environment variable or C<262144>. |
450 | 416 |
Activate relaxed parsing for responses that are terminated with a connection |
451 | 417 |
close. |
452 | 418 |
|
453 |
-=head2 C<skip_body> |
|
419 |
+=head2 skip_body |
|
454 | 420 |
|
455 | 421 |
my $skip = $content->skip_body; |
456 | 422 |
$content = $content->skip_body(1); |
... | ... |
@@ -462,159 +428,160 @@ Skip body parsing and finish after headers. |
462 | 428 |
L<Mojo::Content> inherits all methods from L<Mojo::EventEmitter> and |
463 | 429 |
implements the following new ones. |
464 | 430 |
|
465 |
-=head2 C<body_contains> |
|
431 |
+=head2 body_contains |
|
466 | 432 |
|
467 | 433 |
my $success = $content->body_contains('foo bar baz'); |
468 | 434 |
|
469 | 435 |
Check if content contains a specific string. Meant to be overloaded in a |
470 | 436 |
subclass. |
471 | 437 |
|
472 |
-=head2 C<body_size> |
|
438 |
+=head2 body_size |
|
473 | 439 |
|
474 | 440 |
my $size = $content->body_size; |
475 | 441 |
|
476 | 442 |
Content size in bytes. Meant to be overloaded in a subclass. |
477 | 443 |
|
478 |
-=head2 C<boundary> |
|
444 |
+=head2 boundary |
|
479 | 445 |
|
480 | 446 |
my $boundary = $content->boundary; |
481 | 447 |
|
482 | 448 |
Extract multipart boundary from C<Content-Type> header. |
483 | 449 |
|
484 |
-=head2 C<build_body> |
|
450 |
+=head2 build_body |
|
485 | 451 |
|
486 | 452 |
my $string = $content->build_body; |
487 | 453 |
|
488 | 454 |
Render whole body. |
489 | 455 |
|
490 |
-=head2 C<build_headers> |
|
456 |
+=head2 build_headers |
|
491 | 457 |
|
492 | 458 |
my $string = $content->build_headers; |
493 | 459 |
|
494 | 460 |
Render all headers. |
495 | 461 |
|
496 |
-=head2 C<charset> |
|
462 |
+=head2 charset |
|
497 | 463 |
|
498 | 464 |
my $charset = $content->charset; |
499 | 465 |
|
500 | 466 |
Extract charset from C<Content-Type> header. |
501 | 467 |
|
502 |
-=head2 C<clone> |
|
468 |
+=head2 clone |
|
503 | 469 |
|
504 | 470 |
my $clone = $content->clone; |
505 | 471 |
|
506 | 472 |
Clone content if possible, otherwise return C<undef>. |
507 | 473 |
|
508 |
-=head2 C<generate_body_chunk> |
|
474 |
+=head2 generate_body_chunk |
|
509 | 475 |
|
510 |
- my $chunk = $content->generate_body_chunk(0); |
|
476 |
+ my $bytes = $content->generate_body_chunk(0); |
|
511 | 477 |
|
512 | 478 |
Generate dynamic content. |
513 | 479 |
|
514 |
-=head2 C<get_body_chunk> |
|
480 |
+=head2 get_body_chunk |
|
515 | 481 |
|
516 |
- my $chunk = $content->get_body_chunk(0); |
|
482 |
+ my $bytes = $content->get_body_chunk(0); |
|
517 | 483 |
|
518 | 484 |
Get a chunk of content starting from a specfic position. Meant to be |
519 | 485 |
overloaded in a subclass. |
520 | 486 |
|
521 |
-=head2 C<get_header_chunk> |
|
487 |
+=head2 get_header_chunk |
|
522 | 488 |
|
523 |
- my $chunk = $content->get_header_chunk(13); |
|
489 |
+ my $bytes = $content->get_header_chunk(13); |
|
524 | 490 |
|
525 | 491 |
Get a chunk of the headers starting from a specfic position. |
526 | 492 |
|
527 |
-=head2 C<has_leftovers> |
|
493 |
+=head2 has_leftovers |
|
528 | 494 |
|
529 | 495 |
my $success = $content->has_leftovers; |
530 | 496 |
|
531 | 497 |
Check if there are leftovers. |
532 | 498 |
|
533 |
-=head2 C<header_size> |
|
499 |
+=head2 header_size |
|
534 | 500 |
|
535 | 501 |
my $size = $content->header_size; |
536 | 502 |
|
537 | 503 |
Size of headers in bytes. |
538 | 504 |
|
539 |
-=head2 C<is_chunked> |
|
505 |
+=head2 is_chunked |
|
540 | 506 |
|
541 | 507 |
my $success = $content->is_chunked; |
542 | 508 |
|
543 | 509 |
Check if content is chunked. |
544 | 510 |
|
545 |
-=head2 C<is_compressed> |
|
511 |
+=head2 is_compressed |
|
546 | 512 |
|
547 | 513 |
my $success = $content->is_compressed; |
548 | 514 |
|
549 | 515 |
Check if content is C<gzip> compressed. |
550 | 516 |
|
551 |
-=head2 C<is_dynamic> |
|
517 |
+=head2 is_dynamic |
|
552 | 518 |
|
553 | 519 |
my $success = $content->is_dynamic; |
554 | 520 |
|
555 | 521 |
Check if content will be dynamically generated, which prevents C<clone> from |
556 | 522 |
working. |
557 | 523 |
|
558 |
-=head2 C<is_finished> |
|
524 |
+=head2 is_finished |
|
559 | 525 |
|
560 | 526 |
my $success = $content->is_finished; |
561 | 527 |
|
562 | 528 |
Check if parser is finished. |
563 | 529 |
|
564 |
-=head2 C<is_limit_exceeded> |
|
530 |
+=head2 is_limit_exceeded |
|
565 | 531 |
|
566 | 532 |
my $success = $content->is_limit_exceeded; |
567 | 533 |
|
568 | 534 |
Check if buffer has exceeded C<max_buffer_size>. |
569 | 535 |
|
570 |
-=head2 C<is_multipart> |
|
536 |
+=head2 is_multipart |
|
571 | 537 |
|
572 | 538 |
my $false = $content->is_multipart; |
573 | 539 |
|
574 | 540 |
False. |
575 | 541 |
|
576 |
-=head2 C<is_parsing_body> |
|
542 |
+=head2 is_parsing_body |
|
577 | 543 |
|
578 | 544 |
my $success = $content->is_parsing_body; |
579 | 545 |
|
580 | 546 |
Check if body parsing started yet. |
581 | 547 |
|
582 |
-=head2 C<leftovers> |
|
548 |
+=head2 leftovers |
|
583 | 549 |
|
584 | 550 |
my $bytes = $content->leftovers; |
585 | 551 |
|
586 | 552 |
Get leftover data from content parser. |
587 | 553 |
|
588 |
-=head2 C<parse> |
|
554 |
+=head2 parse |
|
589 | 555 |
|
590 |
- $content = $content->parse("Content-Length: 12\r\n\r\nHello World!"); |
|
556 |
+ $content |
|
557 |
+ = $content->parse("Content-Length: 12\x0d\x0a\x0d\x0aHello World!"); |
|
591 | 558 |
|
592 | 559 |
Parse content chunk. |
593 | 560 |
|
594 |
-=head2 C<parse_body> |
|
561 |
+=head2 parse_body |
|
595 | 562 |
|
596 | 563 |
$content = $content->parse_body('Hi!'); |
597 | 564 |
|
598 | 565 |
Parse body chunk and skip headers. |
599 | 566 |
|
600 |
-=head2 C<progress> |
|
567 |
+=head2 progress |
|
601 | 568 |
|
602 | 569 |
my $size = $content->progress; |
603 | 570 |
|
604 | 571 |
Size of content already received from message in bytes. |
605 | 572 |
|
606 |
-=head2 C<write> |
|
573 |
+=head2 write |
|
607 | 574 |
|
608 |
- $content = $content->write('Hello!'); |
|
609 |
- $content = $content->write('Hello!' => sub {...}); |
|
575 |
+ $content = $content->write($bytes); |
|
576 |
+ $content = $content->write($bytes => sub {...}); |
|
610 | 577 |
|
611 | 578 |
Write dynamic content non-blocking, the optional drain callback will be |
612 | 579 |
invoked once all data has been written. |
613 | 580 |
|
614 |
-=head2 C<write_chunk> |
|
581 |
+=head2 write_chunk |
|
615 | 582 |
|
616 |
- $content = $content->write_chunk('Hello!'); |
|
617 |
- $content = $content->write_chunk('Hello!' => sub {...}); |
|
583 |
+ $content = $content->write_chunk($bytes); |
|
584 |
+ $content = $content->write_chunk($bytes => sub {...}); |
|
618 | 585 |
|
619 | 586 |
Write dynamic content non-blocking with C<chunked> transfer encoding, the |
620 | 587 |
optional drain callback will be invoked once all data has been written. |
... | ... |
@@ -23,7 +23,7 @@ sub body_contains { |
23 | 23 |
sub body_size { |
24 | 24 |
my $self = shift; |
25 | 25 |
|
26 |
- # Check for Content-Lenght header |
|
26 |
+ # Check for existing Content-Lenght header |
|
27 | 27 |
my $content_len = $self->headers->content_length; |
28 | 28 |
return $content_len if $content_len; |
29 | 29 |
|
... | ... |
@@ -78,7 +78,7 @@ sub get_body_chunk { |
78 | 78 |
my $len = $boundary_len - 2; |
79 | 79 |
return substr "--$boundary\x0d\x0a", $offset if $len > $offset; |
80 | 80 |
|
81 |
- # Parts |
|
81 |
+ # Prepare content part by part |
|
82 | 82 |
my $parts = $self->parts; |
83 | 83 |
for (my $i = 0; $i < @$parts; $i++) { |
84 | 84 |
my $part = $parts->[$i]; |
... | ... |
@@ -150,8 +150,6 @@ sub _parse_multipart_boundary { |
150 | 150 |
my $end = "\x0d\x0a--$boundary--"; |
151 | 151 |
if ((index $self->{multipart}, $end) == 0) { |
152 | 152 |
substr $self->{multipart}, 0, length $end, ''; |
153 |
- |
|
154 |
- # Finished |
|
155 | 153 |
$self->{multi_state} = 'finished'; |
156 | 154 |
} |
157 | 155 |
|
... | ... |
@@ -174,7 +172,6 @@ sub _parse_multipart_preamble { |
174 | 172 |
sub _read { |
175 | 173 |
my ($self, $chunk) = @_; |
176 | 174 |
|
177 |
- # Parse |
|
178 | 175 |
$self->{multipart} .= $chunk; |
179 | 176 |
my $boundary = $self->boundary; |
180 | 177 |
until (($self->{multi_state} = defined $self->{multi_state} ? $self->{multi_state} : 'multipart_preamble') eq 'finished') { |
... | ... |
@@ -224,7 +221,7 @@ described in RFC 2616. |
224 | 221 |
L<Mojo::Content::Multipart> inherits all events from L<Mojo::Content> and can |
225 | 222 |
emit the following new ones. |
226 | 223 |
|
227 |
-=head2 C<part> |
|
224 |
+=head2 part |
|
228 | 225 |
|
229 | 226 |
$multi->on(part => sub { |
230 | 227 |
my ($multi, $single) = @_; |
... | ... |
@@ -244,7 +241,7 @@ Emitted when a new L<Mojo::Content::Single> part starts. |
244 | 241 |
L<Mojo::Content::MultiPart> inherits all attributes from L<Mojo::Content> and |
245 | 242 |
implements the following new ones. |
246 | 243 |
|
247 |
-=head2 C<parts> |
|
244 |
+=head2 parts |
|
248 | 245 |
|
249 | 246 |
my $parts = $multi->parts; |
250 | 247 |
$multi = $multi->parts([]); |
... | ... |
@@ -257,44 +254,44 @@ L<Mojo::Content::Single> objects. |
257 | 254 |
L<Mojo::Content::MultiPart> inherits all methods from L<Mojo::Content> and |
258 | 255 |
implements the following new ones. |
259 | 256 |
|
260 |
-=head2 C<new> |
|
257 |
+=head2 new |
|
261 | 258 |
|
262 | 259 |
my $multi = Mojo::Content::MultiPart->new; |
263 | 260 |
|
264 | 261 |
Construct a new L<Mojo::Content::MultiPart> object and subscribe to C<read> |
265 | 262 |
event with default content parser. |
266 | 263 |
|
267 |
-=head2 C<body_contains> |
|
264 |
+=head2 body_contains |
|
268 | 265 |
|
269 | 266 |
my $success = $multi->body_contains('foobarbaz'); |
270 | 267 |
|
271 | 268 |
Check if content parts contain a specific string. |
272 | 269 |
|
273 |
-=head2 C<body_size> |
|
270 |
+=head2 body_size |
|
274 | 271 |
|
275 | 272 |
my $size = $multi->body_size; |
276 | 273 |
|
277 | 274 |
Content size in bytes. |
278 | 275 |
|
279 |
-=head2 C<build_boundary> |
|
276 |
+=head2 build_boundary |
|
280 | 277 |
|
281 | 278 |
my $boundary = $multi->build_boundary; |
282 | 279 |
|
283 | 280 |
Generate a suitable boundary for content and add it to C<Content-Type> header. |
284 | 281 |
|
285 |
-=head2 C<clone> |
|
282 |
+=head2 clone |
|
286 | 283 |
|
287 | 284 |
my $clone = $multi->clone; |
288 | 285 |
|
289 | 286 |
Clone content if possible, otherwise return C<undef>. |
290 | 287 |
|
291 |
-=head2 C<get_body_chunk> |
|
288 |
+=head2 get_body_chunk |
|
292 | 289 |
|
293 |
- my $chunk = $multi->get_body_chunk(0); |
|
290 |
+ my $bytes = $multi->get_body_chunk(0); |
|
294 | 291 |
|
295 | 292 |
Get a chunk of content starting from a specfic position. |
296 | 293 |
|
297 |
-=head2 C<is_multipart> |
|
294 |
+=head2 is_multipart |
|
298 | 295 |
|
299 | 296 |
my $true = $multi->is_multipart; |
300 | 297 |
|
... | ... |
@@ -9,7 +9,8 @@ has auto_upgrade => 1; |
9 | 9 |
|
10 | 10 |
sub new { |
11 | 11 |
my $self = shift->SUPER::new(@_); |
12 |
- $self->{read} = $self->on(read => \&_read); |
|
12 |
+ $self->{read} |
|
13 |
+ = $self->on(read => sub { $_[0]->asset($_[0]->asset->add_chunk($_[1])) }); |
|
13 | 14 |
return $self; |
14 | 15 |
} |
15 | 16 |
|
... | ... |
@@ -29,11 +30,7 @@ sub clone { |
29 | 30 |
|
30 | 31 |
sub get_body_chunk { |
31 | 32 |
my ($self, $offset) = @_; |
32 |
- |
|
33 |
- # Body generator |
|
34 | 33 |
return $self->generate_body_chunk($offset) if $self->{dynamic}; |
35 |
- |
|
36 |
- # Normal content |
|
37 | 34 |
return $self->asset->get_chunk($offset); |
38 | 35 |
} |
39 | 36 |
|
... | ... |
@@ -54,11 +51,6 @@ sub parse { |
54 | 51 |
return $multi->parse; |
55 | 52 |
} |
56 | 53 |
|
57 |
-sub _read { |
|
58 |
- my ($self, $chunk) = @_; |
|
59 |
- $self->asset($self->asset->add_chunk($chunk)); |
|
60 |
-} |
|
61 |
- |
|
62 | 54 |
1; |
63 | 55 |
|
64 | 56 |
=head1 NAME |
... | ... |
@@ -70,7 +62,7 @@ Mojo::Content::Single - HTTP content |
70 | 62 |
use Mojo::Content::Single; |
71 | 63 |
|
72 | 64 |
my $single = Mojo::Content::Single->new; |
73 |
- $single->parse("Content-Length: 12\r\n\r\nHello World!"); |
|
65 |
+ $single->parse("Content-Length: 12\x0d\x0a\x0d\x0aHello World!"); |
|
74 | 66 |
say $single->headers->content_length; |
75 | 67 |
|
76 | 68 |
=head1 DESCRIPTION |
... | ... |
@@ -83,7 +75,7 @@ L<Mojo::Content::Single> is a container for HTTP content as described in RFC |
83 | 75 |
L<Mojo::Content::Single> inherits all events from L<Mojo::Content> and can |
84 | 76 |
emit the following new ones. |
85 | 77 |
|
86 |
-=head2 C<upgrade> |
|
78 |
+=head2 upgrade |
|
87 | 79 |
|
88 | 80 |
$single->on(upgrade => sub { |
89 | 81 |
my ($single, $multi) = @_; |
... | ... |
@@ -103,7 +95,7 @@ Emitted when content gets upgraded to a L<Mojo::Content::MultiPart> object. |
103 | 95 |
L<Mojo::Content::Single> inherits all attributes from L<Mojo::Content> and |
104 | 96 |
implements the following new ones. |
105 | 97 |
|
106 |
-=head2 C<asset> |
|
98 |
+=head2 asset |
|
107 | 99 |
|
108 | 100 |
my $asset = $single->asset; |
109 | 101 |
$single = $single->asset(Mojo::Asset::Memory->new); |
... | ... |
@@ -111,7 +103,7 @@ implements the following new ones. |
111 | 103 |
The actual content, defaults to a L<Mojo::Asset::Memory> object with |
112 | 104 |
C<auto_upgrade> enabled. |
113 | 105 |
|
114 |
-=head2 C<auto_upgrade> |
|
106 |
+=head2 auto_upgrade |
|
115 | 107 |
|
116 | 108 |
my $upgrade = $single->auto_upgrade; |
117 | 109 |
$single = $single->auto_upgrade(0); |
... | ... |
@@ -124,41 +116,42 @@ L<Mojo::Content::MultiPart> object, defaults to C<1>. |
124 | 116 |
L<Mojo::Content::Single> inherits all methods from L<Mojo::Content> and |
125 | 117 |
implements the following new ones. |
126 | 118 |
|
127 |
-=head2 C<new> |
|
119 |
+=head2 new |
|
128 | 120 |
|
129 | 121 |
my $single = Mojo::Content::Single->new; |
130 | 122 |
|
131 | 123 |
Construct a new L<Mojo::Content::Single> object and subscribe to C<read> event |
132 | 124 |
with default content parser. |
133 | 125 |
|
134 |
-=head2 C<body_contains> |
|
126 |
+=head2 body_contains |
|
135 | 127 |
|
136 | 128 |
my $success = $single->body_contains('1234567'); |
137 | 129 |
|
138 | 130 |
Check if content contains a specific string. |
139 | 131 |
|
140 |
-=head2 C<body_size> |
|
132 |
+=head2 body_size |
|
141 | 133 |
|
142 | 134 |
my $size = $single->body_size; |
143 | 135 |
|
144 | 136 |
Content size in bytes. |
145 | 137 |
|
146 |
-=head2 C<clone> |
|
138 |
+=head2 clone |
|
147 | 139 |
|
148 | 140 |
my $clone = $single->clone; |
149 | 141 |
|
150 | 142 |
Clone content if possible, otherwise return C<undef>. |
151 | 143 |
|
152 |
-=head2 C<get_body_chunk> |
|
144 |
+=head2 get_body_chunk |
|
153 | 145 |
|
154 |
- my $chunk = $single->get_body_chunk(0); |
|
146 |
+ my $bytes = $single->get_body_chunk(0); |
|
155 | 147 |
|
156 | 148 |
Get a chunk of content starting from a specfic position. |
157 | 149 |
|
158 |
-=head2 C<parse> |
|
150 |
+=head2 parse |
|
159 | 151 |
|
160 |
- $single = $single->parse("Content-Length: 12\r\n\r\nHello World!"); |
|
161 |
- my $multi = $single->parse("Content-Type: multipart/form-data\r\n\r\n"); |
|
152 |
+ $single = $single->parse("Content-Length: 12\x0d\x0a\x0d\x0aHello World!"); |
|
153 |
+ my $multi |
|
154 |
+ = $single->parse("Content-Type: multipart/form-data\x0d\x0a\x0d\x0a"); |
|
162 | 155 |
|
163 | 156 |
Parse content chunk and upgrade to L<Mojo::Content::MultiPart> object if |
164 | 157 |
possible. |
... | ... |
@@ -30,8 +30,6 @@ sub _tokenize { |
30 | 30 |
# Value |
31 | 31 |
my $value; |
32 | 32 |
$value = unquote $1 if $string =~ s/^("(?:\\\\|\\"|[^"])+"|[^;,]+)\s*//; |
33 |
- |
|
34 |
- # Token |
|
35 | 33 |
push @token, [$name, $value]; |
36 | 34 |
|
37 | 35 |
# Separator |
... | ... |
@@ -68,14 +66,14 @@ L<Mojo::Cookie> is an abstract base class for HTTP cookies. |
68 | 66 |
|
69 | 67 |
L<Mojo::Cookie> implements the following attributes. |
70 | 68 |
|
71 |
-=head2 C<name> |
|
69 |
+=head2 name |
|
72 | 70 |
|
73 | 71 |
my $name = $cookie->name; |
74 | 72 |
$cookie = $cookie->name('foo'); |
75 | 73 |
|
76 | 74 |
Cookie name. |
77 | 75 |
|
78 |
-=head2 C<value> |
|
76 |
+=head2 value |
|
79 | 77 |
|
80 | 78 |
my $value = $cookie->value; |
81 | 79 |
$cookie = $cookie->value('/test'); |
... | ... |
@@ -87,13 +85,13 @@ Cookie value. |
87 | 85 |
L<Mojo::Cookie> inherits all methods from L<Mojo::Base> and implements the |
88 | 86 |
following new ones. |
89 | 87 |
|
90 |
-=head2 C<parse> |
|
88 |
+=head2 parse |
|
91 | 89 |
|
92 | 90 |
my $cookies = $cookie->parse($string); |
93 | 91 |
|
94 | 92 |
Parse cookies. Meant to be overloaded in a subclass. |
95 | 93 |
|
96 |
-=head2 C<to_string> |
|
94 |
+=head2 to_string |
|
97 | 95 |
|
98 | 96 |
my $string = $cookie->to_string; |
99 | 97 |
my $string = "$cookie"; |
... | ... |
@@ -6,7 +6,6 @@ use Mojo::Util 'quote'; |
6 | 6 |
sub parse { |
7 | 7 |
my ($self, $string) = @_; |
8 | 8 |
|
9 |
- # Walk tree |
|
10 | 9 |
my @cookies; |
11 | 10 |
for my $token (map {@$_} $self->_tokenize($string)) { |
12 | 11 |
my ($name, $value) = @$token; |
... | ... |
@@ -54,13 +53,13 @@ L<Mojo::Cookie::Request> inherits all attributes from L<Mojo::Cookie>. |
54 | 53 |
L<Mojo::Cookie::Request> inherits all methods from L<Mojo::Cookie> and |
55 | 54 |
implements the following new ones. |
56 | 55 |
|
57 |
-=head2 C<parse> |
|
56 |
+=head2 parse |
|
58 | 57 |
|
59 | 58 |
my $cookies = $cookie->parse('f=b; g=a'); |
60 | 59 |
|
61 | 60 |
Parse cookies. |
62 | 61 |
|
63 |
-=head2 C<to_string> |
|
62 |
+=head2 to_string |
|
64 | 63 |
|
65 | 64 |
my $string = $cookie->to_string; |
66 | 65 |
|
... | ... |
@@ -15,8 +15,6 @@ sub expires { |
15 | 15 |
? Mojo::Date->new($self->{expires}) |
16 | 16 |
: $self->{expires} |
17 | 17 |
unless @_; |
18 |
- |
|
19 |
- # New expires value |
|
20 | 18 |
$self->{expires} = shift; |
21 | 19 |
|
22 | 20 |
return $self; |
... | ... |
@@ -25,7 +23,6 @@ sub expires { |
25 | 23 |
sub parse { |
26 | 24 |
my ($self, $string) = @_; |
27 | 25 |
|
28 |
- # Walk tree |
|
29 | 26 |
my @cookies; |
30 | 27 |
for my $token ($self->_tokenize($string)) { |
31 | 28 |
for my $i (0 .. $#$token) { |
... | ... |
@@ -104,14 +101,14 @@ L<Mojo::Cookie::Response> is a container for HTTP response cookies. |
104 | 101 |
L<Mojo::Cookie::Response> inherits all attributes from L<Mojo::Cookie> and |
105 | 102 |
implements the followign new ones. |
106 | 103 |
|
107 |
-=head2 C<domain> |
|
104 |
+=head2 domain |
|
108 | 105 |
|
109 | 106 |
my $domain = $cookie->domain; |
110 | 107 |
$cookie = $cookie->domain('localhost'); |
111 | 108 |
|
112 | 109 |
Cookie domain. |
113 | 110 |
|
114 |
-=head2 C<httponly> |
|
111 |
+=head2 httponly |
|
115 | 112 |
|
116 | 113 |
my $httponly = $cookie->httponly; |
117 | 114 |
$cookie = $cookie->httponly(1); |
... | ... |
@@ -119,21 +116,21 @@ Cookie domain. |
119 | 116 |
HttpOnly flag, which can prevent client-side scripts from accessing this |
120 | 117 |
cookie. |
121 | 118 |
|
122 |
-=head2 C<max_age> |
|
119 |
+=head2 max_age |
|
123 | 120 |
|
124 | 121 |
my $max_age = $cookie->max_age; |
125 | 122 |
$cookie = $cookie->max_age(60); |
126 | 123 |
|
127 | 124 |
Max age for cookie. |
128 | 125 |
|
129 |
-=head2 C<path> |
|
126 |
+=head2 path |
|
130 | 127 |
|
131 | 128 |
my $path = $cookie->path; |
132 | 129 |
$cookie = $cookie->path('/test'); |
133 | 130 |
|
134 | 131 |
Cookie path. |
135 | 132 |
|
136 |
-=head2 C<secure> |
|
133 |
+=head2 secure |
|
137 | 134 |
|
138 | 135 |
my $secure = $cookie->secure; |
139 | 136 |
$cookie = $cookie->secure(1); |
... | ... |
@@ -146,7 +143,7 @@ connections. |
146 | 143 |
L<Mojo::Cookie::Response> inherits all methods from L<Mojo::Cookie> and |
147 | 144 |
implements the following new ones. |
148 | 145 |
|
149 |
-=head2 C<expires> |
|
146 |
+=head2 expires |
|
150 | 147 |
|
151 | 148 |
my $expires = $cookie->expires; |
152 | 149 |
$cookie = $cookie->expires(time + 60); |
... | ... |
@@ -154,13 +151,13 @@ implements the following new ones. |
154 | 151 |
|
155 | 152 |
Expiration for cookie. |
156 | 153 |
|
157 |
-=head2 C<parse> |
|
154 |
+=head2 parse |
|
158 | 155 |
|
159 | 156 |
my $cookies = $cookie->parse('f=b; path=/'); |
160 | 157 |
|
161 | 158 |
Parse cookies. |
162 | 159 |
|
163 |
-=head2 C<to_string> |
|
160 |
+=head2 to_string |
|
164 | 161 |
|
165 | 162 |
my $string = $cookie->to_string; |
166 | 163 |
|
... | ... |
@@ -71,24 +71,21 @@ sub attrs { |
71 | 71 |
return $self; |
72 | 72 |
} |
73 | 73 |
|
74 |
-sub charset { shift->_parser(charset => @_) } |
|
74 |
+sub charset { shift->_html(charset => @_) } |
|
75 | 75 |
|
76 | 76 |
sub children { |
77 | 77 |
my ($self, $type) = @_; |
78 | 78 |
|
79 |
- # Walk tree |
|
80 | 79 |
my @children; |
81 |
- my $tree = $self->tree; |
|
82 |
- my $start = $tree->[0] eq 'root' ? 1 : 4; |
|
83 |
- for my $e (@$tree[$start .. $#$tree]) { |
|
80 |
+ my $charset = $self->charset; |
|
81 |
+ my $xml = $self->xml; |
|
82 |
+ my $tree = $self->tree; |
|
83 |
+ for my $e (@$tree[($tree->[0] eq 'root' ? 1 : 4) .. $#$tree]) { |
|
84 | 84 |
|
85 |
- # Make sure child is a tag |
|
85 |
+ # Make sure child is the right type |
|
86 | 86 |
next unless $e->[0] eq 'tag'; |
87 | 87 |
next if defined $type && $e->[1] ne $type; |
88 |
- |
|
89 |
- # Add child |
|
90 |
- push @children, |
|
91 |
- $self->new->charset($self->charset)->tree($e)->xml($self->xml); |
|
88 |
+ push @children, $self->new->charset($charset)->tree($e)->xml($xml); |
|
92 | 89 |
} |
93 | 90 |
|
94 | 91 |
return Mojo::Collection->new(@children); |
... | ... |
@@ -97,43 +94,31 @@ sub children { |
97 | 94 |
sub content_xml { |
98 | 95 |
my $self = shift; |
99 | 96 |
|
100 |
- # Walk tree |
|
101 |
- my $result = ''; |
|
102 |
- my $tree = $self->tree; |
|
103 |
- my $start = $tree->[0] eq 'root' ? 1 : 4; |
|
104 |
- for my $e (@$tree[$start .. $#$tree]) { |
|
105 |
- $result .= Mojo::DOM::HTML->new( |
|
106 |
- charset => $self->charset, |
|
107 |
- tree => $e, |
|
108 |
- xml => $self->xml |
|
109 |
- )->render; |
|
110 |
- } |
|
111 |
- |
|
112 |
- return $result; |
|
97 |
+ # Render children |
|
98 |
+ my $tree = $self->tree; |
|
99 |
+ my $charset = $self->charset; |
|
100 |
+ my $xml = $self->xml; |
|
101 |
+ return join '', map { |
|
102 |
+ Mojo::DOM::HTML->new(charset => $charset, tree => $_, xml => $xml)->render |
|
103 |
+ } @$tree[($tree->[0] eq 'root' ? 1 : 4) .. $#$tree]; |
|
113 | 104 |
} |
114 | 105 |
|
115 | 106 |
sub find { |
116 | 107 |
my ($self, $selector) = @_; |
117 | 108 |
|
118 |
- # Match selector against tree |
|
119 |
- my $results = Mojo::DOM::CSS->new(tree => $self->tree)->select($selector); |
|
120 |
- |
|
121 |
- # Upgrade results |
|
122 |
- @$results |
|
123 |
- = map { $self->new->charset($self->charset)->tree($_)->xml($self->xml) } |
|
124 |
- @$results; |
|
125 |
- |
|
126 |
- return Mojo::Collection->new(@$results); |
|
109 |
+ my $charset = $self->charset; |
|
110 |
+ my $xml = $self->xml; |
|
111 |
+ return Mojo::Collection->new( |
|
112 |
+ map { $self->new->charset($charset)->tree($_)->xml($xml) } |
|
113 |
+ @{Mojo::DOM::CSS->new(tree => $self->tree)->select($selector)}); |
|
127 | 114 |
} |
128 | 115 |
|
129 | 116 |
sub namespace { |
130 | 117 |
my $self = shift; |
131 | 118 |
|
132 |
- # Namespace prefix |
|
119 |
+ # Extract namespace prefix and search parents |
|
133 | 120 |
return '' if (my $current = $self->tree)->[0] eq 'root'; |
134 | 121 |
my $ns = $current->[1] =~ /^(.*?):/ ? "xmlns:$1" : undef; |
135 |
- |
|
136 |
- # Walk tree |
|
137 | 122 |
while ($current) { |
138 | 123 |
last if $current->[0] eq 'root'; |
139 | 124 |
|
... | ... |
@@ -155,11 +140,7 @@ sub next { shift->_sibling(1) } |
155 | 140 |
|
156 | 141 |
sub parent { |
157 | 142 |
my $self = shift; |
158 |
- |
|
159 |
- # Not a tag |
|
160 | 143 |
return undef if (my $tree = $self->tree)->[0] eq 'root'; |
161 |
- |
|
162 |
- # Parent |
|
163 | 144 |
return $self->new->charset($self->charset)->tree($tree->[3]) |
164 | 145 |
->xml($self->xml); |
165 | 146 |
} |
... | ... |
@@ -206,29 +187,15 @@ sub replace { |
206 | 187 |
|
207 | 188 |
sub replace_content { |
208 | 189 |
my ($self, $new) = @_; |
209 |
- |
|
210 |
- # Parse |
|
211 |
- $new = $self->_parse("$new"); |
|
212 |
- |
|
213 |
- # Replacements |
|
214 | 190 |
my $tree = $self->tree; |
215 |
- my @new; |
|
216 |
- for my $e (@$new[1 .. $#$new]) { |
|
217 |
- $e->[3] = $tree if $e->[0] eq 'tag'; |
|
218 |
- push @new, $e; |
|
219 |
- } |
|
220 |
- |
|
221 |
- # Replace |
|
222 |
- my $start = $tree->[0] eq 'root' ? 1 : 4; |
|
223 |
- splice @$tree, $start, $#$tree, @new; |
|
224 |
- |
|
191 |
+ splice @$tree, $tree->[0] eq 'root' ? 1 : 4, $#$tree, |
|
192 |
+ @{_parent($self->_parse("$new"), $tree)}; |
|
225 | 193 |
return $self; |
226 | 194 |
} |
227 | 195 |
|
228 | 196 |
sub root { |
229 | 197 |
my $self = shift; |
230 | 198 |
|
231 |
- # Find root |
|
232 | 199 |
my $root = $self->tree; |
233 | 200 |
while ($root->[0] eq 'tag') { |
234 | 201 |
last unless my $parent = $root->[3]; |
... | ... |
@@ -277,7 +244,7 @@ sub text_before { |
277 | 244 |
|
278 | 245 |
sub to_xml { shift->[0]->render } |
279 | 246 |
|
280 |
-sub tree { shift->_parser(tree => @_) } |
|
247 |
+sub tree { shift->_html(tree => @_) } |
|
281 | 248 |
|
282 | 249 |
sub type { |
283 | 250 |
my ($self, $type) = @_; |
... | ... |
@@ -292,18 +259,15 @@ sub type { |
292 | 259 |
return $self; |
293 | 260 |
} |
294 | 261 |
|
295 |
-sub xml { shift->_parser(xml => @_) } |
|
262 |
+sub xml { shift->_html(xml => @_) } |
|
296 | 263 |
|
297 | 264 |
sub _add { |
298 | 265 |
my ($self, $offset, $new) = @_; |
299 | 266 |
|
300 |
- # Parse |
|
301 |
- $new = $self->_parse("$new"); |
|
302 |
- |
|
303 | 267 |
# Not a tag |
304 | 268 |
return $self if (my $tree = $self->tree)->[0] eq 'root'; |
305 | 269 |
|
306 |
- # Find |
|
270 |
+ # Find parent |
|
307 | 271 |
my $parent = $tree->[3]; |
308 | 272 |
my $i = $parent->[0] eq 'root' ? 1 : 4; |
309 | 273 |
for my $e (@$parent[$i .. $#$parent]) { |
... | ... |
@@ -311,8 +275,8 @@ sub _add { |
311 | 275 |
$i++; |
312 | 276 |
} |
313 | 277 |
|
314 |
- # Add |
|
315 |
- splice @$parent, $i + $offset, 0, @{_parent($new, $parent)}; |
|
278 |
+ # Add children |
|
279 |
+ splice @$parent, $i + $offset, 0, @{_parent($self->_parse("$new"), $parent)}; |
|
316 | 280 |
|
317 | 281 |
return $self; |
318 | 282 |
} |
... | ... |
@@ -322,8 +286,17 @@ sub _elements { |
322 | 286 |
return [@$e[($e->[0] eq 'root' ? 1 : 4) .. $#$e]]; |
323 | 287 |
} |
324 | 288 |
|
289 |
+sub _html { |
|
290 |
+ my ($self, $method) = (shift, shift); |
|
291 |
+ return $self->[0]->$method unless @_; |
|
292 |
+ $self->[0]->$method(@_); |
|
293 |
+ return $self; |
|
294 |
+} |
|
295 |
+ |
|
325 | 296 |
sub _parent { |
326 | 297 |
my ($children, $parent) = @_; |
298 |
+ |
|
299 |
+ # Link parent to children |
|
327 | 300 |
my @new; |
328 | 301 |
for my $e (@$children[1 .. $#$children]) { |
329 | 302 |
if ($e->[0] eq 'tag') { |
... | ... |
@@ -332,6 +305,7 @@ sub _parent { |
332 | 305 |
} |
333 | 306 |
push @new, $e; |
334 | 307 |
} |
308 |
+ |
|
335 | 309 |
return \@new; |
336 | 310 |
} |
337 | 311 |
|
... | ... |
@@ -341,17 +315,10 @@ sub _parse { |
341 | 315 |
->parse(shift)->tree; |
342 | 316 |
} |
343 | 317 |
|
344 |
-sub _parser { |
|
345 |
- my ($self, $method) = (shift, shift); |
|
346 |
- return $self->[0]->$method unless @_; |
|
347 |
- $self->[0]->$method(@_); |
|
348 |
- return $self; |
|
349 |
-} |
|
350 |
- |
|
351 | 318 |
sub _sibling { |
352 | 319 |
my ($self, $next) = @_; |
353 | 320 |
|
354 |
- # Root |
|
321 |
+ # Make sure we have a parent |
|
355 | 322 |
return undef unless my $parent = $self->parent; |
356 | 323 |
|
357 | 324 |
# Find previous or next sibling |
... | ... |
@@ -369,7 +336,6 @@ sub _sibling { |
369 | 336 |
sub _text { |
370 | 337 |
my ($elements, $recurse, $trim) = @_; |
371 | 338 |
|
372 |
- # Walk tree |
|
373 | 339 |
my $text = ''; |
374 | 340 |
for my $e (@$elements) { |
375 | 341 |
my $type = $e->[0]; |
... | ... |
@@ -481,14 +447,14 @@ XML detection can also be disabled with the C<xml> method. |
481 | 447 |
L<Mojo::DOM> inherits all methods from L<Mojo::Base> and implements the |
482 | 448 |
following new ones. |
483 | 449 |
|
484 |
-=head2 C<new> |
|
450 |
+=head2 new |
|
485 | 451 |
|
486 | 452 |
my $dom = Mojo::DOM->new; |
487 | 453 |
my $dom = Mojo::DOM->new('<foo bar="baz">test</foo>'); |
488 | 454 |
|
489 | 455 |
Construct a new array-based L<Mojo::DOM> object. |
490 | 456 |
|
491 |
-=head2 C<all_text> |
|
457 |
+=head2 all_text |
|
492 | 458 |
|
493 | 459 |
my $trimmed = $dom->all_text; |
494 | 460 |
my $untrimmed = $dom->all_text(0); |
... | ... |
@@ -502,7 +468,7 @@ enabled by default. |
502 | 468 |
# "foo\nbarbaz\n" |
503 | 469 |
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->div->all_text(0); |
504 | 470 |
|
505 |
-=head2 C<append> |
|
471 |
+=head2 append |
|
506 | 472 |
|
507 | 473 |
$dom = $dom->append('<p>Hi!</p>'); |
508 | 474 |
|
... | ... |
@@ -511,7 +477,7 @@ Append to element. |
511 | 477 |
# "<div><h1>A</h1><h2>B</h2></div>" |
512 | 478 |
$dom->parse('<div><h1>A</h1></div>')->at('h1')->append('<h2>B</h2>')->root; |
513 | 479 |
|
514 |
-=head2 C<append_content> |
|
480 |
+=head2 append_content |
|
515 | 481 |
|
516 | 482 |
$dom = $dom->append_content('<p>Hi!</p>'); |
517 | 483 |
|
... | ... |
@@ -520,7 +486,7 @@ Append to element content. |
520 | 486 |
# "<div><h1>AB</h1></div>" |
521 | 487 |
$dom->parse('<div><h1>A</h1></div>')->at('h1')->append_content('B')->root; |
522 | 488 |
|
523 |
-=head2 C<at> |
|
489 |
+=head2 at |
|
524 | 490 |
|
525 | 491 |
my $result = $dom->at('html title'); |
526 | 492 |
|
... | ... |
@@ -530,7 +496,7 @@ are supported. |
530 | 496 |
# Find first element with "svg" namespace definition |
531 | 497 |
my $namespace = $dom->at('[xmlns\:svg]')->{'xmlns:svg'}; |
532 | 498 |
|
533 |
-=head2 C<attrs> |
|
499 |
+=head2 attrs |
|
534 | 500 |
|
535 | 501 |
my $attrs = $dom->attrs; |
536 | 502 |
my $foo = $dom->attrs('foo'); |
... | ... |
@@ -539,14 +505,14 @@ are supported. |
539 | 505 |
|
540 | 506 |
Element attributes. |
541 | 507 |
|
542 |
-=head2 C<charset> |
|
508 |
+=head2 charset |
|
543 | 509 |
|
544 | 510 |
my $charset = $dom->charset; |
545 | 511 |
$dom = $dom->charset('UTF-8'); |
546 | 512 |
|
547 | 513 |
Charset used for decoding and encoding HTML/XML. |
548 | 514 |
|
549 |
-=head2 C<children> |
|
515 |
+=head2 children |
|
550 | 516 |
|
551 | 517 |
my $collection = $dom->children; |
552 | 518 |
my $collection = $dom->children('div'); |
... | ... |
@@ -557,7 +523,7 @@ similar to C<find>. |
557 | 523 |
# Show type of random child element |
558 | 524 |
say $dom->children->shuffle->first->type; |
559 | 525 |
|
560 |
-=head2 C<content_xml> |
|
526 |
+=head2 content_xml |
|
561 | 527 |
|
562 | 528 |
my $xml = $dom->content_xml; |
563 | 529 |
|
... | ... |
@@ -567,7 +533,7 @@ C<charset> has been defined. |
567 | 533 |
# "<b>test</b>" |
568 | 534 |
$dom->parse('<div><b>test</b></div>')->div->content_xml; |
569 | 535 |
|
570 |
-=head2 C<find> |
|
536 |
+=head2 find |
|
571 | 537 |
|
572 | 538 |
my $collection = $dom->find('html title'); |
573 | 539 |
|
... | ... |
@@ -580,7 +546,7 @@ selectors from L<Mojo::DOM::CSS> are supported. |
580 | 546 |
# Extract information from multiple elements |
581 | 547 |
my @headers = $dom->find('h1, h2, h3')->pluck('text')->each; |
582 | 548 |
|
583 |
-=head2 C<namespace> |
|
549 |
+=head2 namespace |
|
584 | 550 |
|
585 | 551 |
my $namespace = $dom->namespace; |
586 | 552 |
|
... | ... |
@@ -592,7 +558,7 @@ Find element namespace. |
592 | 558 |
# Find namespace for an element that may or may not have a namespace prefix |
593 | 559 |
my $namespace = $dom->at('svg > circle')->namespace; |
594 | 560 |
|
595 |
-=head2 C<next> |
|
561 |
+=head2 next |
|
596 | 562 |
|
597 | 563 |
my $sibling = $dom->next; |
598 | 564 |
|
... | ... |
@@ -601,13 +567,13 @@ Next sibling of element. |
601 | 567 |
# "<h2>B</h2>" |
602 | 568 |
$dom->parse('<div><h1>A</h1><h2>B</h2></div>')->at('h1')->next; |
603 | 569 |
|
604 |
-=head2 C<parent> |
|
570 |
+=head2 parent |
|
605 | 571 |
|
606 | 572 |
my $parent = $dom->parent; |
607 | 573 |
|
608 | 574 |
Parent of element. |
609 | 575 |
|
610 |
-=head2 C<parse> |
|
576 |
+=head2 parse |
|
611 | 577 |
|
612 | 578 |
$dom = $dom->parse('<foo bar="baz">test</foo>'); |
613 | 579 |
|
... | ... |
@@ -616,7 +582,7 @@ Parse HTML/XML document with L<Mojo::DOM::HTML>. |
616 | 582 |
# Parse UTF-8 encoded XML |
617 | 583 |
my $dom = Mojo::DOM->new->charset('UTF-8')->xml(1)->parse($xml); |
618 | 584 |
|
619 |
-=head2 C<prepend> |
|
585 |
+=head2 prepend |
|
620 | 586 |
|
621 | 587 |
$dom = $dom->prepend('<p>Hi!</p>'); |
622 | 588 |
|
... | ... |
@@ -625,7 +591,7 @@ Prepend to element. |
625 | 591 |
# "<div><h1>A</h1><h2>B</h2></div>" |
626 | 592 |
$dom->parse('<div><h2>B</h2></div>')->at('h2')->prepend('<h1>A</h1>')->root; |
627 | 593 |
|
628 |
-=head2 C<prepend_content> |
|
594 |
+=head2 prepend_content |
|
629 | 595 |
|
630 | 596 |
$dom = $dom->prepend_content('<p>Hi!</p>'); |
631 | 597 |
|
... | ... |
@@ -634,7 +600,7 @@ Prepend to element content. |
634 | 600 |
# "<div><h2>AB</h2></div>" |
635 | 601 |
$dom->parse('<div><h2>B</h2></div>')->at('h2')->prepend_content('A')->root; |
636 | 602 |
|
637 |
-=head2 C<previous> |
|
603 |
+=head2 previous |
|
638 | 604 |
|
639 | 605 |
my $sibling = $dom->previous; |
640 | 606 |
|
... | ... |
@@ -643,7 +609,7 @@ Previous sibling of element. |
643 | 609 |
# "<h1>A</h1>" |
644 | 610 |
$dom->parse('<div><h1>A</h1><h2>B</h2></div>')->at('h2')->previous; |
645 | 611 |
|
646 |
-=head2 C<remove> |
|
612 |
+=head2 remove |
|
647 | 613 |
|
648 | 614 |
my $old = $dom->remove; |
649 | 615 |
|
... | ... |
@@ -652,7 +618,7 @@ Remove element. |
652 | 618 |
# "<div></div>" |
653 | 619 |
$dom->parse('<div><h1>A</h1></div>')->at('h1')->remove->root; |
654 | 620 |
|
655 |
-=head2 C<replace> |
|
621 |
+=head2 replace |
|
656 | 622 |
|
657 | 623 |
my $old = $dom->replace('<div>test</div>'); |
658 | 624 |
|
... | ... |
@@ -664,7 +630,7 @@ Replace element. |
664 | 630 |
# "<div></div>" |
665 | 631 |
$dom->parse('<div><h1>A</h1></div>')->at('h1')->replace('')->root; |
666 | 632 |
|
667 |
-=head2 C<replace_content> |
|
633 |
+=head2 replace_content |
|
668 | 634 |
|
669 | 635 |
$dom = $dom->replace_content('test'); |
670 | 636 |
|
... | ... |
@@ -676,13 +642,13 @@ Replace element content. |
676 | 642 |
# "<div><h1></h1></div>" |
677 | 643 |
$dom->parse('<div><h1>A</h1></div>')->at('h1')->replace_content('')->root; |
678 | 644 |
|
679 |
-=head2 C<root> |
|
645 |
+=head2 root |
|
680 | 646 |
|
681 | 647 |
my $root = $dom->root; |
682 | 648 |
|
683 | 649 |
Find root node. |
684 | 650 |
|
685 |
-=head2 C<text> |
|
651 |
+=head2 text |
|
686 | 652 |
|
687 | 653 |
my $trimmed = $dom->text; |
688 | 654 |
my $untrimmed = $dom->text(0); |
... | ... |
@@ -696,7 +662,7 @@ whitespace trimming is enabled by default. |
696 | 662 |
# "foo\nbaz\n" |
697 | 663 |
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->div->text(0); |
698 | 664 |
|
699 |
-=head2 C<text_after> |
|
665 |
+=head2 text_after |
|
700 | 666 |
|
701 | 667 |
my $trimmed = $dom->text_after; |
702 | 668 |
my $untrimmed = $dom->text_after(0); |
... | ... |
@@ -710,7 +676,7 @@ is enabled by default. |
710 | 676 |
# "baz\n" |
711 | 677 |
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->div->p->text_after(0); |
712 | 678 |
|
713 |
-=head2 C<text_before> |
|
679 |
+=head2 text_before |
|
714 | 680 |
|
715 | 681 |
my $trimmed = $dom->text_before; |
716 | 682 |
my $untrimmed = $dom->text_before(0); |
... | ... |
@@ -724,7 +690,7 @@ is enabled by default. |
724 | 690 |
# "foo\n" |
725 | 691 |
$dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->div->p->text_before(0); |
726 | 692 |
|
727 |
-=head2 C<to_xml> |
|
693 |
+=head2 to_xml |
|
728 | 694 |
|
729 | 695 |
my $xml = $dom->to_xml; |
730 | 696 |
my $xml = "$dom"; |
... | ... |
@@ -735,14 +701,14 @@ if a C<charset> has been defined. |
735 | 701 |
# "<b>test</b>" |
736 | 702 |
$dom->parse('<div><b>test</b></div>')->div->b->to_xml; |
737 | 703 |
|
738 |
-=head2 C<tree> |
|
704 |
+=head2 tree |
|
739 | 705 |
|
740 | 706 |
my $tree = $dom->tree; |
741 | 707 |
$dom = $dom->tree(['root', [qw(text lalala)]]); |
742 | 708 |
|
743 | 709 |
Document Object Model. |
744 | 710 |
|
745 |
-=head2 C<type> |
|
711 |
+=head2 type |
|
746 | 712 |
|
747 | 713 |
my $type = $dom->type; |
748 | 714 |
$dom = $dom->type('div'); |
... | ... |
@@ -752,7 +718,7 @@ Element type. |
752 | 718 |
# List types of child elements |
753 | 719 |
say $dom->children->pluck('type'); |
754 | 720 |
|
755 |
-=head2 C<xml> |
|
721 |
+=head2 xml |
|
756 | 722 |
|
757 | 723 |
my $xml = $dom->xml; |
758 | 724 |
$dom = $dom->xml(1); |
... | ... |
@@ -36,13 +36,10 @@ my $TOKEN_RE = qr/ |
36 | 36 |
sub select { |
37 | 37 |
my $self = shift; |
38 | 38 |
|
39 |
- # Compile selectors |
|
40 |
- my $pattern = $self->_compile(shift); |
|
41 |
- |
|
42 |
- # Walk tree |
|
43 | 39 |
my @results; |
44 |
- my $tree = $self->tree; |
|
45 |
- my @queue = ($tree); |
|
40 |
+ my $pattern = $self->_compile(shift); |
|
41 |
+ my $tree = $self->tree; |
|
42 |
+ my @queue = ($tree); |
|
46 | 43 |
while (my $current = shift @queue) { |
47 | 44 |
my $type = $current->[0]; |
48 | 45 |
|
... | ... |
@@ -123,7 +120,6 @@ sub _combinator { |
123 | 120 |
sub _compile { |
124 | 121 |
my ($self, $css) = @_; |
125 | 122 |
|
126 |
- # Tokenize |
|
127 | 123 |
my $pattern = [[]]; |
128 | 124 |
while ($css =~ /$TOKEN_RE/g) { |
129 | 125 |
my ($separator, $element, $pc, $attrs, $combinator) |
... | ... |
@@ -321,7 +317,6 @@ sub _regex { |
321 | 317 |
sub _selector { |
322 | 318 |
my ($self, $selector, $current) = @_; |
323 | 319 |
|
324 |
- # Selectors |
|
325 | 320 |
for my $s (@$selector[1 .. $#$selector]) { |
326 | 321 |
my $type = $s->[0]; |
327 | 322 |
|
... | ... |
@@ -348,7 +343,6 @@ sub _selector { |
348 | 343 |
sub _sibling { |
349 | 344 |
my ($self, $selectors, $current, $tree, $immediate) = @_; |
350 | 345 |
|
351 |
- # Find preceding elements |
|
352 | 346 |
my $parent = $current->[3]; |
353 | 347 |
my $found; |
354 | 348 |
my $start = $parent->[0] eq 'root' ? 1 : 4; |
... | ... |
@@ -403,77 +397,77 @@ L<Mojo::DOM::CSS> is the CSS selector engine used by L<Mojo::DOM>. |
403 | 397 |
|
404 | 398 |
All CSS selectors that make sense for a standalone parser are supported. |
405 | 399 |
|
406 |
-=head2 C<*> |
|
400 |
+=head2 * |
|
407 | 401 |
|
408 | 402 |
Any element. |
409 | 403 |
|
410 | 404 |
my $all = $css->select('*'); |
411 | 405 |
|
412 |
-=head2 C<E> |
|
406 |
+=head2 E |
|
413 | 407 |
|
414 | 408 |
An element of type C<E>. |
415 | 409 |
|
416 | 410 |
my $title = $css->select('title'); |
417 | 411 |
|
418 |
-=head2 C<E[foo]> |
|
412 |
+=head2 E[foo] |
|
419 | 413 |
|
420 | 414 |
An C<E> element with a C<foo> attribute. |
421 | 415 |
|
422 | 416 |
my $links = $css->select('a[href]'); |
423 | 417 |
|
424 |
-=head2 C<E[foo="bar"]> |
|
418 |
+=head2 E[foo="bar"] |
|
425 | 419 |
|
426 | 420 |
An C<E> element whose C<foo> attribute value is exactly equal to C<bar>. |
427 | 421 |
|
428 | 422 |
my $fields = $css->select('input[name="foo"]'); |
429 | 423 |
|
430 |
-=head2 C<E[foo~="bar"]> |
|
424 |
+=head2 E[foo~="bar"] |
|
431 | 425 |
|
432 | 426 |
An C<E> element whose C<foo> attribute value is a list of |
433 | 427 |
whitespace-separated values, one of which is exactly equal to C<bar>. |
434 | 428 |
|
435 | 429 |
my $fields = $css->select('input[name~="foo"]'); |
436 | 430 |
|
437 |
-=head2 C<E[foo^="bar"]> |
|
431 |
+=head2 E[foo^="bar"] |
|
438 | 432 |
|
439 | 433 |
An C<E> element whose C<foo> attribute value begins exactly with the string |
440 | 434 |
C<bar>. |
441 | 435 |
|
442 | 436 |
my $fields = $css->select('input[name^="f"]'); |
443 | 437 |
|
444 |
-=head2 C<E[foo$="bar"]> |
|
438 |
+=head2 E[foo$="bar"] |
|
445 | 439 |
|
446 | 440 |
An C<E> element whose C<foo> attribute value ends exactly with the string |
447 | 441 |
C<bar>. |
448 | 442 |
|
449 | 443 |
my $fields = $css->select('input[name$="o"]'); |
450 | 444 |
|
451 |
-=head2 C<E[foo*="bar"]> |
|
445 |
+=head2 E[foo*="bar"] |
|
452 | 446 |
|
453 | 447 |
An C<E> element whose C<foo> attribute value contains the substring C<bar>. |
454 | 448 |
|
455 | 449 |
my $fields = $css->select('input[name*="fo"]'); |
456 | 450 |
|
457 |
-=head2 C<E:root> |
|
451 |
+=head2 E:root |
|
458 | 452 |
|
459 | 453 |
An C<E> element, root of the document. |
460 | 454 |
|
461 | 455 |
my $root = $css->select(':root'); |
462 | 456 |
|
463 |
-=head2 C<E:checked> |
|
457 |
+=head2 E:checked |
|
464 | 458 |
|
465 | 459 |
A user interface element C<E> which is checked (for instance a radio-button or |
466 | 460 |
checkbox). |
467 | 461 |
|
468 | 462 |
my $input = $css->select(':checked'); |
469 | 463 |
|
470 |
-=head2 C<E:empty> |
|
464 |
+=head2 E:empty |
|
471 | 465 |
|
472 | 466 |
An C<E> element that has no children (including text nodes). |
473 | 467 |
|
474 | 468 |
my $empty = $css->select(':empty'); |
475 | 469 |
|
476 |
-=head2 C<E:nth-child(n)> |
|
470 |
+=head2 E:nth-child(n) |
|
477 | 471 |
|
478 | 472 |
An C<E> element, the C<n-th> child of its parent. |
479 | 473 |
|
... | ... |
@@ -482,7 +476,7 @@ An C<E> element, the C<n-th> child of its parent. |
482 | 476 |
my $even = $css->select('div:nth-child(even)'); |
483 | 477 |
my $top3 = $css->select('div:nth-child(-n+3)'); |
484 | 478 |
|
485 |
-=head2 C<E:nth-last-child(n)> |
|
479 |
+=head2 E:nth-last-child(n) |
|
486 | 480 |
|
487 | 481 |
An C<E> element, the C<n-th> child of its parent, counting from the last one. |
488 | 482 |
|
... | ... |
@@ -491,7 +485,7 @@ An C<E> element, the C<n-th> child of its parent, counting from the last one. |
491 | 485 |
my $even = $css->select('div:nth-last-child(even)'); |
492 | 486 |
my $bottom3 = $css->select('div:nth-last-child(-n+3)'); |
493 | 487 |
|
494 |
-=head2 C<E:nth-of-type(n)> |
|
488 |
+=head2 E:nth-of-type(n) |
|
495 | 489 |
|
496 | 490 |
An C<E> element, the C<n-th> sibling of its type. |
497 | 491 |
|
... | ... |
@@ -500,7 +494,7 @@ An C<E> element, the C<n-th> sibling of its type. |
500 | 494 |
my $even = $css->select('div:nth-of-type(even)'); |
501 | 495 |
my $top3 = $css->select('div:nth-of-type(-n+3)'); |
502 | 496 |
|
503 |
-=head2 C<E:nth-last-of-type(n)> |
|
497 |
+=head2 E:nth-last-of-type(n) |
|
504 | 498 |
|
505 | 499 |
An C<E> element, the C<n-th> sibling of its type, counting from the last one. |
506 | 500 |
|
... | ... |
@@ -509,91 +503,91 @@ An C<E> element, the C<n-th> sibling of its type, counting from the last one. |
509 | 503 |
my $even = $css->select('div:nth-last-of-type(even)'); |
510 | 504 |
my $bottom3 = $css->select('div:nth-last-of-type(-n+3)'); |
511 | 505 |
|
512 |
-=head2 C<E:first-child> |
|
506 |
+=head2 E:first-child |
|
513 | 507 |
|
514 | 508 |
An C<E> element, first child of its parent. |
515 | 509 |
|
516 | 510 |
my $first = $css->select('div p:first-child'); |
517 | 511 |
|
518 |
-=head2 C<E:last-child> |
|
512 |
+=head2 E:last-child |
|
519 | 513 |
|
520 | 514 |
An C<E> element, last child of its parent. |
521 | 515 |
|
522 | 516 |
my $last = $css->select('div p:last-child'); |
523 | 517 |
|
524 |
-=head2 C<E:first-of-type> |
|
518 |
+=head2 E:first-of-type |
|
525 | 519 |
|
526 | 520 |
An C<E> element, first sibling of its type. |
527 | 521 |
|
528 | 522 |
my $first = $css->select('div p:first-of-type'); |
529 | 523 |
|
530 |
-=head2 C<E:last-of-type> |
|
524 |
+=head2 E:last-of-type |
|
531 | 525 |
|
532 | 526 |
An C<E> element, last sibling of its type. |
533 | 527 |
|
534 | 528 |
my $last = $css->select('div p:last-of-type'); |
535 | 529 |
|
536 |
-=head2 C<E:only-child> |
|
530 |
+=head2 E:only-child |
|
537 | 531 |
|
538 | 532 |
An C<E> element, only child of its parent. |
539 | 533 |
|
540 | 534 |
my $lonely = $css->select('div p:only-child'); |
541 | 535 |
|
542 |
-=head2 C<E:only-of-type> |
|
536 |
+=head2 E:only-of-type |
|
543 | 537 |
|
544 | 538 |
An C<E> element, only sibling of its type. |
545 | 539 |
|
546 | 540 |
my $lonely = $css->select('div p:only-of-type'); |
547 | 541 |
|
548 |
-=head2 C<E.warning> |
|
542 |
+=head2 E.warning |
|
549 | 543 |
|
550 | 544 |
my $warning = $css->select('div.warning'); |
551 | 545 |
|
552 | 546 |
An C<E> element whose class is "warning". |
553 | 547 |
|
554 |
-=head2 C<E#myid> |
|
548 |
+=head2 E#myid |
|
555 | 549 |
|
556 | 550 |
my $foo = $css->select('div#foo'); |
557 | 551 |
|
558 | 552 |
An C<E> element with C<ID> equal to "myid". |
559 | 553 |
|
560 |
-=head2 C<E:not(s)> |
|
554 |
+=head2 E:not(s) |
|
561 | 555 |
|
562 | 556 |
An C<E> element that does not match simple selector C<s>. |
563 | 557 |
|
564 | 558 |
my $others = $css->select('div p:not(:first-child)'); |
565 | 559 |
|
566 |
-=head2 C<E F> |
|
560 |
+=head2 E F |
|
567 | 561 |
|
568 | 562 |
An C<F> element descendant of an C<E> element. |
569 | 563 |
|
570 | 564 |
my $headlines = $css->select('div h1'); |
571 | 565 |
|
572 |
-=head2 C<E E<gt> F> |
|
566 |
+=head2 E E<gt> F |
|
573 | 567 |
|
574 | 568 |
An C<F> element child of an C<E> element. |
575 | 569 |
|
576 | 570 |
my $headlines = $css->select('html > body > div > h1'); |
577 | 571 |
|
578 |
-=head2 C<E + F> |
|
572 |
+=head2 E + F |
|
579 | 573 |
|
580 | 574 |
An C<F> element immediately preceded by an C<E> element. |
581 | 575 |
|
582 | 576 |
my $second = $css->select('h1 + h2'); |
583 | 577 |
|
584 |
-=head2 C<E ~ F> |
|
578 |
+=head2 E ~ F |
|
585 | 579 |
|
586 | 580 |
An C<F> element preceded by an C<E> element. |
587 | 581 |
|
588 | 582 |
my $second = $css->select('h1 ~ h2'); |
589 | 583 |
|
590 |
-=head2 C<E, F, G> |
|
584 |
+=head2 E, F, G |
|
591 | 585 |
|
592 | 586 |
Elements of type C<E>, C<F> and C<G>. |
593 | 587 |
|
594 | 588 |
my $headlines = $css->select('h1, h2, h3'); |
595 | 589 |
|
596 |
-=head2 C<E[foo=bar][bar=baz]> |
|
590 |
+=head2 E[foo=bar][bar=baz] |
|
597 | 591 |
|
598 | 592 |
An C<E> element whose attributes match all following attribute selectors. |
599 | 593 |
|
... | ... |
@@ -603,7 +597,7 @@ An C<E> element whose attributes match all following attribute selectors. |
603 | 597 |
|
604 | 598 |
L<Mojo::DOM::CSS> implements the following attributes. |
605 | 599 |
|
606 |
-=head2 C<tree> |
|
600 |
+=head2 tree |
|
607 | 601 |
|
608 | 602 |
my $tree = $css->tree; |
609 | 603 |
$css = $css->tree(['root', [qw(text lalala)]]); |
... | ... |
@@ -615,7 +609,7 @@ Document Object Model. |
615 | 609 |
L<Mojo::DOM::CSS> inherits all methods from L<Mojo::Base> and implements the |
616 | 610 |
following new ones. |
617 | 611 |
|
618 |
-=head2 C<select> |
|
612 |
+=head2 select |
|
619 | 613 |
|
620 | 614 |
my $results = $css->select('head > title'); |
621 | 615 |
|
... | ... |
@@ -76,11 +76,9 @@ my %INLINE = map { $_ => 1 } ( |
76 | 76 |
sub parse { |
77 | 77 |
my ($self, $html) = @_; |
78 | 78 |
|
79 |
- # Try to decode |
|
80 | 79 |
my $charset = $self->charset; |
81 | 80 |
defined ($html = decode($charset, $html)) || return $self->charset(undef) if $charset; |
82 | 81 |
|
83 |
- # Tokenize |
|
84 | 82 |
my $tree = ['root']; |
85 | 83 |
my $current = $tree; |
86 | 84 |
while ($html =~ m/\G$TOKEN_RE/gcs) { |
... | ... |
@@ -269,14 +267,10 @@ sub _render { |
269 | 267 |
# Processing instruction |
270 | 268 |
return "<?" . $tree->[1] . "?>" if $e eq 'pi'; |
271 | 269 |
|
272 |
- # Offset |
|
273 |
- my $start = $e eq 'root' ? 1 : 2; |
|
274 |
- |
|
275 | 270 |
# Start tag |
271 |
+ my $start = $e eq 'root' ? 1 : 2; |
|
276 | 272 |
my $content = ''; |
277 | 273 |
if ($e eq 'tag') { |
278 |
- |
|
279 |
- # Offset |
|
280 | 274 |
$start = 4; |
281 | 275 |
|
282 | 276 |
# Open tag |
... | ... |
@@ -305,7 +299,7 @@ sub _render { |
305 | 299 |
$content .= '>'; |
306 | 300 |
} |
307 | 301 |
|
308 |
- # Walk tree |
|
302 |
+ # Render whole tree |
|
309 | 303 |
$content .= $self->_render($tree->[$_]) for $start .. $#$tree; |
310 | 304 |
|
311 | 305 |
# End tag |
... | ... |
@@ -362,7 +356,7 @@ sub _start { |
362 | 356 |
} |
363 | 357 |
} |
364 | 358 |
|
365 |
- # New |
|
359 |
+ # New tag |
|
366 | 360 |
my $new = ['tag', $start, $attrs, $$current]; |
367 | 361 |
weaken $new->[3]; |
368 | 362 |
push @$$current, $new; |
... | ... |
@@ -397,21 +391,21 @@ L<Mojo::DOM::HTML> is the HTML/XML engine used by L<Mojo::DOM>. |
397 | 391 |
|
398 | 392 |
L<Mojo::DOM::HTML> implements the following attributes. |
399 | 393 |
|
400 |
-=head2 C<charset> |
|
394 |
+=head2 charset |
|
401 | 395 |
|
402 | 396 |
my $charset = $html->charset; |
403 | 397 |
$html = $html->charset('UTF-8'); |
404 | 398 |
|
405 | 399 |
Charset used for decoding and encoding HTML/XML. |
406 | 400 |
|
407 |
-=head2 C<tree> |
|
401 |
+=head2 tree |
|
408 | 402 |
|
409 | 403 |
my $tree = $html->tree; |
410 | 404 |
$html = $html->tree(['root', [qw(text lalala)]]); |
411 | 405 |
|
412 | 406 |
Document Object Model. |
413 | 407 |
|
414 |
-=head2 C<xml> |
|
408 |
+=head2 xml |
|
415 | 409 |
|
416 | 410 |
my $xml = $html->xml; |
417 | 411 |
$html = $html->xml(1); |
... | ... |
@@ -424,13 +418,13 @@ auto detection based on processing instructions. |
424 | 418 |
L<Mojo::DOM::HTML> inherits all methods from L<Mojo::Base> and implements the |
425 | 419 |
following new ones. |
426 | 420 |
|
427 |
-=head2 C<parse> |
|
421 |
+=head2 parse |
|
428 | 422 |
|
429 | 423 |
$html = $html->parse('<foo bar="baz">test</foo>'); |
430 | 424 |
|
431 | 425 |
Parse HTML/XML document. |
432 | 426 |
|
433 |
-=head2 C<render> |
|
427 |
+=head2 render |
|
434 | 428 |
|
435 | 429 |
my $xml = $html->render; |
436 | 430 |
|
... | ... |
@@ -9,7 +9,6 @@ use Time::Local 'timegm'; |
9 | 9 |
|
10 | 10 |
has 'epoch'; |
11 | 11 |
|
12 |
-# Days and months |
|
13 | 12 |
my @DAYS = qw(Sun Mon Tue Wed Thu Fri Sat); |
14 | 13 |
my @MONTHS = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); |
15 | 14 |
my %MONTHS; |
... | ... |
@@ -93,7 +92,7 @@ L<Mojo::Date> implements HTTP date and time functions as described in RFC |
93 | 92 |
|
94 | 93 |
L<Mojo::Date> implements the following attributes. |
95 | 94 |
|
96 |
-=head2 C<epoch> |
|
95 |
+=head2 epoch |
|
97 | 96 |
|
98 | 97 |
my $epoch = $date->epoch; |
99 | 98 |
$date = $date->epoch(784111777); |
... | ... |
@@ -105,14 +104,14 @@ Epoch seconds. |
105 | 104 |
L<Mojo::Date> inherits all methods from L<Mojo::Base> and implements the |
106 | 105 |
following new ones. |
107 | 106 |
|
108 |
-=head2 C<new> |
|
107 |
+=head2 new |
|
109 | 108 |
|
110 | 109 |
my $date = Mojo::Date->new; |
111 | 110 |
my $date = Mojo::Date->new('Sun Nov 6 08:49:37 1994'); |
112 | 111 |
|
113 | 112 |
Construct a new L<Mojo::Date> object. |
114 | 113 |
|
115 |
-=head2 C<parse> |
|
114 |
+=head2 parse |
|
116 | 115 |
|
117 | 116 |
$date = $date->parse('Sun Nov 6 08:49:37 1994'); |
118 | 117 |
|
... | ... |
@@ -130,7 +129,7 @@ Parse date. |
130 | 129 |
# Ansi C asctime() |
131 | 130 |
say Mojo::Date->new('Sun Nov 6 08:49:37 1994')->epoch; |
132 | 131 |
|
133 |
-=head2 C<to_string> |
|
132 |
+=head2 to_string |
|
134 | 133 |
|
135 | 134 |
my $string = $date->to_string; |
136 | 135 |
my $string = "$date"; |
... | ... |
@@ -12,7 +12,10 @@ sub emit { |
12 | 12 |
warn "-- Emit $name in @{[blessed($self)]} (@{[scalar(@$s)]})\n" if DEBUG; |
13 | 13 |
for my $cb (@$s) { $self->$cb(@_) } |
14 | 14 |
} |
15 |
- elsif (DEBUG) { warn "-- Emit $name in @{[blessed($self)]} (0)\n" } |
|
15 |
+ else { |
|
16 |
+ warn "-- Emit $name in @{[blessed($self)]} (0)\n" if DEBUG; |
|
17 |
+ warn $_[0] if $name eq 'error'; |
|
18 |
+ } |
|
16 | 19 |
|
17 | 20 |
return $self; |
18 | 21 |
} |
... | ... |
@@ -30,15 +33,14 @@ sub emit_safe { |
30 | 33 |
if ($name eq 'error') { warn qq{Event "error" failed: $@} } |
31 | 34 |
|
32 | 35 |
# Normal event failed |
33 |
- else { |
|
34 |
- $self->once(error => sub { warn $_[1] }) |
|
35 |
- unless $self->has_subscribers('error'); |
|
36 |
- $self->emit_safe('error', qq{Event "$name" failed: $@}); |
|
37 |
- } |
|
36 |
+ else { $self->emit_safe('error', qq{Event "$name" failed: $@}) } |
|
38 | 37 |
} |
39 | 38 |
} |
40 | 39 |
} |
41 |
- elsif (DEBUG) { warn "-- Emit $name in @{[blessed($self)]} safely (0)\n" } |
|
40 |
+ else { |
|
41 |
+ warn "-- Emit $name in @{[blessed($self)]} safely (0)\n" if DEBUG; |
|
42 |
+ warn $_[0] if $name eq 'error'; |
|
43 |
+ } |
|
42 | 44 |
|
43 | 45 |
return $self; |
44 | 46 |
} |
... | ... |
@@ -113,32 +115,50 @@ Mojo::EventEmitter - Event emitter base class |
113 | 115 |
|
114 | 116 |
L<Mojo::EventEmitter> is a simple base class for event emitting objects. |
115 | 117 |
|
118 |
+=head1 EVENTS |
|
119 |
+ |
|
120 |
+L<Mojo::EventEmitter> can emit the following events. |
|
121 |
+ |
|
122 |
+=head2 error |
|
123 |
+ |
|
124 |
+ $e->on(error => sub { |
|
125 |
+ my ($e, $err) = @_; |
|
126 |
+ ... |
|
127 |
+ }); |
|
128 |
+ |
|
129 |
+Emitted safely for event errors. |
|
130 |
+ |
|
131 |
+ $e->on(error => sub { |
|
132 |
+ my ($e, $err) = @_; |
|
133 |
+ say "This looks bad: $err"; |
|
134 |
+ }); |
|
135 |
+ |
|
116 | 136 |
=head1 METHODS |
117 | 137 |
|
118 | 138 |
L<Mojo::EventEmitter> inherits all methods from L<Mojo::Base> and |
119 | 139 |
implements the following new ones. |
120 | 140 |
|
121 |
-=head2 C<emit> |
|
141 |
+=head2 emit |
|
122 | 142 |
|
123 | 143 |
$e = $e->emit('foo'); |
124 | 144 |
$e = $e->emit('foo', 123); |
125 | 145 |
|
126 | 146 |
Emit event. |
127 | 147 |
|
128 |
-=head2 C<emit_safe> |
|
148 |
+=head2 emit_safe |
|
129 | 149 |
|
130 | 150 |
$e = $e->emit_safe('foo'); |
131 | 151 |
$e = $e->emit_safe('foo', 123); |
132 | 152 |
|
133 | 153 |
Emit event safely and emit C<error> event on failure. |
134 | 154 |
|
135 |
-=head2 C<has_subscribers> |
|
155 |
+=head2 has_subscribers |
|
136 | 156 |
|
137 | 157 |
my $success = $e->has_subscribers('foo'); |
138 | 158 |
|
139 | 159 |
Check if event has subscribers. |
140 | 160 |
|
141 |
-=head2 C<on> |
|
161 |
+=head2 on |
|
142 | 162 |
|
143 | 163 |
my $cb = $e->on(foo => sub {...}); |
144 | 164 |
|
... | ... |
@@ -149,7 +169,7 @@ Subscribe to event. |
149 | 169 |
... |
150 | 170 |
}); |
151 | 171 |
|
152 |
-=head2 C<once> |
|
172 |
+=head2 once |
|
153 | 173 |
|
154 | 174 |
my $cb = $e->once(foo => sub {...}); |
155 | 175 |
|
... | ... |
@@ -160,7 +180,7 @@ Subscribe to event and unsubscribe again after it has been emitted once. |
160 | 180 |
... |
161 | 181 |
}); |
162 | 182 |
|
163 |
-=head2 C<subscribers> |
|
183 |
+=head2 subscribers |
|
164 | 184 |
|
165 | 185 |
my $subscribers = $e->subscribers('foo'); |
166 | 186 |
|
... | ... |
@@ -169,7 +189,7 @@ All subscribers for event. |
169 | 189 |
# Unsubscribe last subscriber |
170 | 190 |
$e->unsubscribe(foo => $e->subscribers('foo')->[-1]); |
171 | 191 |
|
172 |
-=head2 C<unsubscribe> |
|
192 |
+=head2 unsubscribe |
|
173 | 193 |
|
174 | 194 |
$e = $e->unsubscribe('foo'); |
175 | 195 |
$e = $e->unsubscribe(foo => $cb); |
... | ... |
@@ -16,18 +16,11 @@ sub new { |
16 | 16 |
return @_ ? $self->_detect(@_) : $self; |
17 | 17 |
} |
18 | 18 |
|
19 |
-# DEPRECATED in Rainbow! |
|
20 |
-sub raw_message { |
|
21 |
- warn "Mojo::Exception->raw_message has been DEPRECATED!\n"; |
|
22 |
- shift->message(@_); |
|
23 |
-} |
|
24 |
- |
|
25 | 19 |
sub throw { die shift->new->trace(2)->_detect(@_) } |
26 | 20 |
|
27 | 21 |
sub to_string { |
28 | 22 |
my $self = shift; |
29 | 23 |
|
30 |
- # Message |
|
31 | 24 |
return $self->message unless $self->verbose; |
32 | 25 |
my $string = $self->message ? $self->message : ''; |
33 | 26 |
|
... | ... |
@@ -94,7 +87,6 @@ sub _context { |
94 | 87 |
sub _detect { |
95 | 88 |
my ($self, $msg, $files) = @_; |
96 | 89 |
|
97 |
- # Message |
|
98 | 90 |
return $msg if blessed $msg && $msg->isa('Mojo::Exception'); |
99 | 91 |
$self->message($msg); |
100 | 92 |
|
... | ... |
@@ -144,76 +136,76 @@ L<Mojo::Exception> is a container for exceptions with context information. |
144 | 136 |
|
145 | 137 |
L<Mojo::Exception> implements the following attributes. |
146 | 138 |
|
147 |
-=head2 C<frames> |
|
139 |
+=head2 frames |
|
148 | 140 |
|
149 | 141 |
my $frames = $e->frames; |
150 | 142 |
$e = $e->frames($frames); |
151 | 143 |
|
152 | 144 |
Stacktrace. |
153 | 145 |
|
154 |
-=head2 C<line> |
|
146 |
+=head2 line |
|
155 | 147 |
|
156 | 148 |
my $line = $e->line; |
157 | 149 |
$e = $e->line([3 => 'foo']); |
158 | 150 |
|
159 | 151 |
The line where the exception occured. |
160 | 152 |
|
161 |
-=head2 C<lines_after> |
|
153 |
+=head2 lines_after |
|
162 | 154 |
|
163 | 155 |
my $lines = $e->lines_after; |
164 | 156 |
$e = $e->lines_after([[1 => 'bar'], [2 => 'baz']]); |
165 | 157 |
|
166 | 158 |
Lines after the line where the exception occured. |
167 | 159 |
|
168 |
-=head2 C<lines_before> |
|
160 |
+=head2 lines_before |
|
169 | 161 |
|
170 | 162 |
my $lines = $e->lines_before; |
171 | 163 |
$e = $e->lines_before([[4 => 'bar'], [5 => 'baz']]); |
172 | 164 |
|
173 | 165 |
Lines before the line where the exception occured. |
174 | 166 |
|
175 |
-=head2 C<message> |
|
167 |
+=head2 message |
|
176 | 168 |
|
177 | 169 |
my $msg = $e->message; |
178 | 170 |
$e = $e->message('Oops!'); |
179 | 171 |
|
180 | 172 |
Exception message. |
181 | 173 |
|
182 |
-=head2 C<verbose> |
|
174 |
+=head2 verbose |
|
183 | 175 |
|
184 | 176 |
my $verbose = $e->verbose; |
185 | 177 |
$e = $e->verbose(1); |
186 | 178 |
|
187 |
-Activate verbose rendering, defaults to the value of |
|
188 |
-C<MOJO_EXCEPTION_VERBOSE> or C<0>. |
|
179 |
+Activate verbose rendering, defaults to the value of the |
|
180 |
+C<MOJO_EXCEPTION_VERBOSE> environment variable or C<0>. |
|
189 | 181 |
|
190 | 182 |
=head1 METHODS |
191 | 183 |
|
192 | 184 |
L<Mojo::Exception> inherits all methods from L<Mojo::Base> and implements the |
193 | 185 |
following new ones. |
194 | 186 |
|
195 |
-=head2 C<new> |
|
187 |
+=head2 new |
|
196 | 188 |
|
197 | 189 |
my $e = Mojo::Exception->new('Oops!'); |
198 | 190 |
my $e = Mojo::Exception->new('Oops!', $files); |
199 | 191 |
|
200 | 192 |
Construct a new L<Mojo::Exception> object. |
201 | 193 |
|
202 |
-=head2 C<throw> |
|
194 |
+=head2 throw |
|
203 | 195 |
|
204 | 196 |
Mojo::Exception->throw('Oops!'); |
205 | 197 |
Mojo::Exception->throw('Oops!', $files); |
206 | 198 |
|
207 | 199 |
Throw exception with stacktrace. |
208 | 200 |
|
209 |
-=head2 C<to_string> |
|
201 |
+=head2 to_string |
|
210 | 202 |
|
211 | 203 |
my $string = $e->to_string; |
212 | 204 |
my $string = "$e"; |
213 | 205 |
|
214 | 206 |
Render exception. |
215 | 207 |
|
216 |
-=head2 C<trace> |
|
208 |
+=head2 trace |
|
217 | 209 |
|
218 | 210 |
$e = $e->trace; |
219 | 211 |
$e = $e->trace(2); |
... | ... |
@@ -89,7 +89,6 @@ sub names { |
89 | 89 |
sub parse { |
90 | 90 |
my $self = shift; |
91 | 91 |
|
92 |
- # Parse headers with size limit |
|
93 | 92 |
$self->{state} = 'headers'; |
94 | 93 |
$self->{buffer} .= do {my $buffer = shift; defined $buffer ? $buffer : ''}; |
95 | 94 |
my $headers = $self->{cache} ||= []; |
... | ... |
@@ -134,7 +133,6 @@ sub remove { |
134 | 133 |
sub to_hash { |
135 | 134 |
my ($self, $multi) = @_; |
136 | 135 |
|
137 |
- # Build |
|
138 | 136 |
my %hash; |
139 | 137 |
for my $header (@{$self->names}) { |
140 | 138 |
my @headers = $self->header($header); |
... | ... |
@@ -163,7 +161,6 @@ sub to_string { |
163 | 161 |
push @headers, "$name: " . join("\x0d\x0a ", @$_) for $self->header($name); |
164 | 162 |
} |
165 | 163 |
|
166 |
- # Format headers |
|
167 | 164 |
return join "\x0d\x0a", @headers; |
168 | 165 |
} |
169 | 166 |
|
... | ... |
@@ -179,8 +176,8 @@ Mojo::Headers - Headers |
179 | 176 |
|
180 | 177 |
# Parse |
181 | 178 |
my $headers = Mojo::Headers->new; |
182 |
- $headers->parse("Content-Length: 42\r\n"); |
|
183 |
- $headers->parse("Content-Type: text/html\r\n\r\n"); |
|
179 |
+ $headers->parse("Content-Length: 42\x0d\x0a"); |
|
180 |
+ $headers->parse("Content-Type: text/html\x0d\x0a\x0d\x0a"); |
|
184 | 181 |
say $headers->content_length; |
185 | 182 |
say $headers->content_type; |
186 | 183 |
|
... | ... |
@@ -198,7 +195,7 @@ L<Mojo::Headers> is a container for HTTP headers as described in RFC 2616. |
198 | 195 |
|
199 | 196 |
L<Mojo::Headers> implements the following attributes. |
200 | 197 |
|
201 |
-=head2 C<max_line_size> |
|
198 |
+=head2 max_line_size |
|
202 | 199 |
|
203 | 200 |
my $size = $headers->max_line_size; |
204 | 201 |
$headers = $headers->max_line_size(1024); |
... | ... |
@@ -211,124 +208,124 @@ C<MOJO_MAX_LINE_SIZE> environment variable or C<10240>. |
211 | 208 |
L<Mojo::Headers> inherits all methods from L<Mojo::Base> and implements the |
212 | 209 |
following new ones. |
213 | 210 |
|
214 |
-=head2 C<accept> |
|
211 |
+=head2 accept |
|
215 | 212 |
|
216 | 213 |
my $accept = $headers->accept; |
217 | 214 |
$headers = $headers->accept('application/json'); |
218 | 215 |
|
219 | 216 |
Shortcut for the C<Accept> header. |
220 | 217 |
|
221 |
-=head2 C<accept_charset> |
|
218 |
+=head2 accept_charset |
|
222 | 219 |
|
223 | 220 |
my $charset = $headers->accept_charset; |
224 | 221 |
$headers = $headers->accept_charset('UTF-8'); |
225 | 222 |
|
226 | 223 |
Shortcut for the C<Accept-Charset> header. |
227 | 224 |
|
228 |
-=head2 C<accept_encoding> |
|
225 |
+=head2 accept_encoding |
|
229 | 226 |
|
230 | 227 |
my $encoding = $headers->accept_encoding; |
231 | 228 |
$headers = $headers->accept_encoding('gzip'); |
232 | 229 |
|
233 | 230 |
Shortcut for the C<Accept-Encoding> header. |
234 | 231 |
|
235 |
-=head2 C<accept_language> |
|
232 |
+=head2 accept_language |
|
236 | 233 |
|
237 | 234 |
my $language = $headers->accept_language; |
238 | 235 |
$headers = $headers->accept_language('de, en'); |
239 | 236 |
|
240 | 237 |
Shortcut for the C<Accept-Language> header. |
241 | 238 |
|
242 |
-=head2 C<accept_ranges> |
|
239 |
+=head2 accept_ranges |
|
243 | 240 |
|
244 | 241 |
my $ranges = $headers->accept_ranges; |
245 | 242 |
$headers = $headers->accept_ranges('bytes'); |
246 | 243 |
|
247 | 244 |
Shortcut for the C<Accept-Ranges> header. |
248 | 245 |
|
249 |
-=head2 C<add> |
|
246 |
+=head2 add |
|
250 | 247 |
|
251 | 248 |
$headers = $headers->add('Content-Type', 'text/plain'); |
252 | 249 |
|
253 | 250 |
Add one or more header lines. |
254 | 251 |
|
255 |
-=head2 C<authorization> |
|
252 |
+=head2 authorization |
|
256 | 253 |
|
257 | 254 |
my $authorization = $headers->authorization; |
258 | 255 |
$headers = $headers->authorization('Basic Zm9vOmJhcg=='); |
259 | 256 |
|
260 | 257 |
Shortcut for the C<Authorization> header. |
261 | 258 |
|
262 |
-=head2 C<cache_control> |
|
259 |
+=head2 cache_control |
|
263 | 260 |
|
264 | 261 |
my $cache_control = $headers->cache_control; |
265 | 262 |
$headers = $headers->cache_control('max-age=1, no-cache'); |
266 | 263 |
|
267 | 264 |
Shortcut for the C<Cache-Control> header. |
268 | 265 |
|
269 |
-=head2 C<clone> |
|
266 |
+=head2 clone |
|
270 | 267 |
|
271 | 268 |
my $clone = $headers->clone; |
272 | 269 |
|
273 | 270 |
Clone headers. |
274 | 271 |
|
275 |
-=head2 C<connection> |
|
272 |
+=head2 connection |
|
276 | 273 |
|
277 | 274 |
my $connection = $headers->connection; |
278 | 275 |
$headers = $headers->connection('close'); |
279 | 276 |
|
280 | 277 |
Shortcut for the C<Connection> header. |
281 | 278 |
|
282 |
-=head2 C<content_disposition> |
|
279 |
+=head2 content_disposition |
|
283 | 280 |
|
284 | 281 |
my $disposition = $headers->content_disposition; |
285 | 282 |
$headers = $headers->content_disposition('foo'); |
286 | 283 |
|
287 | 284 |
Shortcut for the C<Content-Disposition> header. |
288 | 285 |
|
289 |
-=head2 C<content_encoding> |
|
286 |
+=head2 content_encoding |
|
290 | 287 |
|
291 | 288 |
my $encoding = $headers->content_encoding; |
292 | 289 |
$headers = $headers->content_encoding('gzip'); |
293 | 290 |
|
294 | 291 |
Shortcut for the C<Content-Encoding> header. |
295 | 292 |
|
296 |
-=head2 C<content_length> |
|
293 |
+=head2 content_length |
|
297 | 294 |
|
298 | 295 |
my $len = $headers->content_length; |
299 | 296 |
$headers = $headers->content_length(4000); |
300 | 297 |
|
301 | 298 |
Shortcut for the C<Content-Length> header. |
302 | 299 |
|
303 |
-=head2 C<content_range> |
|
300 |
+=head2 content_range |
|
304 | 301 |
|
305 | 302 |
my $range = $headers->content_range; |
306 | 303 |
$headers = $headers->content_range('bytes 2-8/100'); |
307 | 304 |
|
308 | 305 |
Shortcut for the C<Content-Range> header. |
309 | 306 |
|
310 |
-=head2 C<content_type> |
|
307 |
+=head2 content_type |
|
311 | 308 |
|
312 | 309 |
my $type = $headers->content_type; |
313 | 310 |
$headers = $headers->content_type('text/plain'); |
314 | 311 |
|
315 | 312 |
Shortcut for the C<Content-Type> header. |
316 | 313 |
|
317 |
-=head2 C<cookie> |
|
314 |
+=head2 cookie |
|
318 | 315 |
|
319 | 316 |
my $cookie = $headers->cookie; |
320 | 317 |
$headers = $headers->cookie('f=b'); |
321 | 318 |
|
322 | 319 |
Shortcut for the C<Cookie> header from RFC 6265. |
323 | 320 |
|
324 |
-=head2 C<date> |
|
321 |
+=head2 date |
|
325 | 322 |
|
326 | 323 |
my $date = $headers->date; |
327 | 324 |
$headers = $headers->date('Sun, 17 Aug 2008 16:27:35 GMT'); |
328 | 325 |
|
329 | 326 |
Shortcut for the C<Date> header. |
330 | 327 |
|
331 |
-=head2 C<dnt> |
|
328 |
+=head2 dnt |
|
332 | 329 |
|
333 | 330 |
my $dnt = $headers->dnt; |
334 | 331 |
$headers = $headers->dnt(1); |
... | ... |
@@ -336,35 +333,35 @@ Shortcut for the C<Date> header. |
336 | 333 |
Shortcut for the C<DNT> (Do Not Track) header, which has no specification yet, |
337 | 334 |
but is very commonly used. |
338 | 335 |
|
339 |
-=head2 C<etag> |
|
336 |
+=head2 etag |
|
340 | 337 |
|
341 | 338 |
my $etag = $headers->etag; |
342 | 339 |
$headers = $headers->etag('abc321'); |
343 | 340 |
|
344 | 341 |
Shortcut for the C<ETag> header. |
345 | 342 |
|
346 |
-=head2 C<expect> |
|
343 |
+=head2 expect |
|
347 | 344 |
|
348 | 345 |
my $expect = $headers->expect; |
349 | 346 |
$headers = $headers->expect('100-continue'); |
350 | 347 |
|
351 | 348 |
Shortcut for the C<Expect> header. |
352 | 349 |
|
353 |
-=head2 C<expires> |
|
350 |
+=head2 expires |
|
354 | 351 |
|
355 | 352 |
my $expires = $headers->expires; |
356 | 353 |
$headers = $headers->expires('Thu, 01 Dec 1994 16:00:00 GMT'); |
357 | 354 |
|
358 | 355 |
Shortcut for the C<Expires> header. |
359 | 356 |
|
360 |
-=head2 C<from_hash> |
|
357 |
+=head2 from_hash |
|
361 | 358 |
|
362 | 359 |
$headers = $headers->from_hash({'Content-Type' => 'text/html'}); |
363 | 360 |
$headers = $headers->from_hash({}); |
364 | 361 |
|
365 | 362 |
Parse headers from a hash reference. |
366 | 363 |
|
367 |
-=head2 C<header> |
|
364 |
+=head2 header |
|
368 | 365 |
|
369 | 366 |
my $string = $headers->header('Content-Type'); |
370 | 367 |
my @lines = $headers->header('Content-Type'); |
... | ... |
@@ -380,93 +377,93 @@ Get or replace the current header values. |
380 | 377 |
say for @$header; |
381 | 378 |
} |
382 | 379 |
|
383 |
-=head2 C<host> |
|
380 |
+=head2 host |
|
384 | 381 |
|
385 | 382 |
my $host = $headers->host; |
386 | 383 |
$headers = $headers->host('127.0.0.1'); |
387 | 384 |
|
388 | 385 |
Shortcut for the C<Host> header. |
389 | 386 |
|
390 |
-=head2 C<if_modified_since> |
|
387 |
+=head2 if_modified_since |
|
391 | 388 |
|
392 | 389 |
my $date = $headers->if_modified_since; |
393 | 390 |
$headers = $headers->if_modified_since('Sun, 17 Aug 2008 16:27:35 GMT'); |
394 | 391 |
|
395 | 392 |
Shortcut for the C<If-Modified-Since> header. |
396 | 393 |
|
397 |
-=head2 C<is_finished> |
|
394 |
+=head2 is_finished |
|
398 | 395 |
|
399 | 396 |
my $success = $headers->is_finished; |
400 | 397 |
|
401 | 398 |
Check if header parser is finished. |
402 | 399 |
|
403 |
-=head2 C<is_limit_exceeded> |
|
400 |
+=head2 is_limit_exceeded |
|
404 | 401 |
|
405 | 402 |
my $success = $headers->is_limit_exceeded; |
406 | 403 |
|
407 | 404 |
Check if a header has exceeded C<max_line_size>. |
408 | 405 |
|
409 |
-=head2 C<last_modified> |
|
406 |
+=head2 last_modified |
|
410 | 407 |
|
411 | 408 |
my $date = $headers->last_modified; |
412 | 409 |
$headers = $headers->last_modified('Sun, 17 Aug 2008 16:27:35 GMT'); |
413 | 410 |
|
414 | 411 |
Shortcut for the C<Last-Modified> header. |
415 | 412 |
|
416 |
-=head2 C<leftovers> |
|
413 |
+=head2 leftovers |
|
417 | 414 |
|
418 | 415 |
my $bytes = $headers->leftovers; |
419 | 416 |
|
420 | 417 |
Get leftover data from header parser. |
421 | 418 |
|
422 |
-=head2 C<location> |
|
419 |
+=head2 location |
|
423 | 420 |
|
424 | 421 |
my $location = $headers->location; |
425 | 422 |
$headers = $headers->location('http://127.0.0.1/foo'); |
426 | 423 |
|
427 | 424 |
Shortcut for the C<Location> header. |
428 | 425 |
|
429 |
-=head2 C<names> |
|
426 |
+=head2 names |
|
430 | 427 |
|
431 | 428 |
my $names = $headers->names; |
432 | 429 |
|
433 | 430 |
Generate a list of all currently defined headers. |
434 | 431 |
|
435 |
-=head2 C<origin> |
|
432 |
+=head2 origin |
|
436 | 433 |
|
437 | 434 |
my $origin = $headers->origin; |
438 | 435 |
$headers = $headers->origin('http://example.com'); |
439 | 436 |
|
440 | 437 |
Shortcut for the C<Origin> header from RFC 6454. |
441 | 438 |
|
442 |
-=head2 C<parse> |
|
439 |
+=head2 parse |
|
443 | 440 |
|
444 |
- $headers = $headers->parse("Content-Type: text/plain\r\n\r\n"); |
|
441 |
+ $headers = $headers->parse("Content-Type: text/plain\x0d\x0a\x0d\x0a"); |
|
445 | 442 |
|
446 | 443 |
Parse formatted headers. |
447 | 444 |
|
448 |
-=head2 C<proxy_authenticate> |
|
445 |
+=head2 proxy_authenticate |
|
449 | 446 |
|
450 | 447 |
my $authenticate = $headers->proxy_authenticate; |
451 | 448 |
$headers = $headers->proxy_authenticate('Basic "realm"'); |
452 | 449 |
|
453 | 450 |
Shortcut for the C<Proxy-Authenticate> header. |
454 | 451 |
|
455 |
-=head2 C<proxy_authorization> |
|
452 |
+=head2 proxy_authorization |
|
456 | 453 |
|
457 | 454 |
my $authorization = $headers->proxy_authorization; |
458 | 455 |
$headers = $headers->proxy_authorization('Basic Zm9vOmJhcg=='); |
459 | 456 |
|
460 | 457 |
Shortcut for the C<Proxy-Authorization> header. |
461 | 458 |
|
462 |
-=head2 C<range> |
|
459 |
+=head2 range |
|
463 | 460 |
|
464 | 461 |
my $range = $headers->range; |
465 | 462 |
$headers = $headers->range('bytes=2-8'); |
466 | 463 |
|
467 | 464 |
Shortcut for the C<Range> header. |
468 | 465 |
|
469 |
-=head2 C<referrer> |
|
466 |
+=head2 referrer |
|
470 | 467 |
|
471 | 468 |
my $referrer = $headers->referrer; |
472 | 469 |
$headers = $headers->referrer('http://mojolicio.us'); |
... | ... |
@@ -474,76 +471,76 @@ Shortcut for the C<Range> header. |
474 | 471 |
Shortcut for the C<Referer> header, there was a typo in RFC 2068 which |
475 | 472 |
resulted in C<Referer> becoming an official header. |
476 | 473 |
|
477 |
-=head2 C<remove> |
|
474 |
+=head2 remove |
|
478 | 475 |
|
479 | 476 |
$headers = $headers->remove('Content-Type'); |
480 | 477 |
|
481 | 478 |
Remove a header. |
482 | 479 |
|
483 |
-=head2 C<sec_websocket_accept> |
|
480 |
+=head2 sec_websocket_accept |
|
484 | 481 |
|
485 | 482 |
my $accept = $headers->sec_websocket_accept; |
486 | 483 |
$headers = $headers->sec_websocket_accept('s3pPLMBiTxaQ9kYGzzhZRbK+xOo='); |
487 | 484 |
|
488 | 485 |
Shortcut for the C<Sec-WebSocket-Accept> header from RFC 6455. |
489 | 486 |
|
490 |
-=head2 C<sec_websocket_extensions> |
|
487 |
+=head2 sec_websocket_extensions |
|
491 | 488 |
|
492 | 489 |
my $extensions = $headers->sec_websocket_extensions; |
493 | 490 |
$headers = $headers->sec_websocket_extensions('foo'); |
494 | 491 |
|
495 | 492 |
Shortcut for the C<Sec-WebSocket-Extensions> header from RFC 6455. |
496 | 493 |
|
497 |
-=head2 C<sec_websocket_key> |
|
494 |
+=head2 sec_websocket_key |
|
498 | 495 |
|
499 | 496 |
my $key = $headers->sec_websocket_key; |
500 | 497 |
$headers = $headers->sec_websocket_key('dGhlIHNhbXBsZSBub25jZQ=='); |
501 | 498 |
|
502 | 499 |
Shortcut for the C<Sec-WebSocket-Key> header from RFC 6455. |
503 | 500 |
|
504 |
-=head2 C<sec_websocket_protocol> |
|
501 |
+=head2 sec_websocket_protocol |
|
505 | 502 |
|
506 | 503 |
my $protocol = $headers->sec_websocket_protocol; |
507 | 504 |
$headers = $headers->sec_websocket_protocol('sample'); |
508 | 505 |
|
509 | 506 |
Shortcut for the C<Sec-WebSocket-Protocol> header from RFC 6455. |
510 | 507 |
|
511 |
-=head2 C<sec_websocket_version> |
|
508 |
+=head2 sec_websocket_version |
|
512 | 509 |
|
513 | 510 |
my $version = $headers->sec_websocket_version; |
514 | 511 |
$headers = $headers->sec_websocket_version(13); |
515 | 512 |
|
516 | 513 |
Shortcut for the C<Sec-WebSocket-Version> header from RFC 6455. |
517 | 514 |
|
518 |
-=head2 C<server> |
|
515 |
+=head2 server |
|
519 | 516 |
|
520 | 517 |
my $server = $headers->server; |
521 | 518 |
$headers = $headers->server('Mojo'); |
522 | 519 |
|
523 | 520 |
Shortcut for the C<Server> header. |
524 | 521 |
|
525 |
-=head2 C<set_cookie> |
|
522 |
+=head2 set_cookie |
|
526 | 523 |
|
527 | 524 |
my $cookie = $headers->set_cookie; |
528 | 525 |
$headers = $headers->set_cookie('f=b; path=/'); |
529 | 526 |
|
530 | 527 |
Shortcut for the C<Set-Cookie> header from RFC 6265. |
531 | 528 |
|
532 |
-=head2 C<status> |
|
529 |
+=head2 status |
|
533 | 530 |
|
534 | 531 |
my $status = $headers->status; |
535 | 532 |
$headers = $headers->status('200 OK'); |
536 | 533 |
|
537 | 534 |
Shortcut for the C<Status> header from RFC 3875. |
538 | 535 |
|
539 |
-=head2 C<te> |
|
536 |
+=head2 te |
|
540 | 537 |
|
541 | 538 |
my $te = $headers->te; |
542 | 539 |
$headers = $headers->te('chunked'); |
543 | 540 |
|
544 | 541 |
Shortcut for the C<TE> header. |
545 | 542 |
|
546 |
-=head2 C<to_hash> |
|
543 |
+=head2 to_hash |
|
547 | 544 |
|
548 | 545 |
my $single = $headers->to_hash; |
549 | 546 |
my $multi = $headers->to_hash(1); |
... | ... |
@@ -553,41 +550,41 @@ line values are disabled by default. |
553 | 550 |
|
554 | 551 |
say $headers->to_hash->{DNT}; |
555 | 552 |
|
556 |
-=head2 C<to_string> |
|
553 |
+=head2 to_string |
|
557 | 554 |
|
558 | 555 |
my $string = $headers->to_string; |
559 | 556 |
|
560 | 557 |
Turn headers into a string, suitable for HTTP messages. |
561 | 558 |
|
562 |
-=head2 C<trailer> |
|
559 |
+=head2 trailer |
|
563 | 560 |
|
564 | 561 |
my $trailer = $headers->trailer; |
565 | 562 |
$headers = $headers->trailer('X-Foo'); |
566 | 563 |
|
567 | 564 |
Shortcut for the C<Trailer> header. |
568 | 565 |
|
569 |
-=head2 C<transfer_encoding> |
|
566 |
+=head2 transfer_encoding |
|
570 | 567 |
|
571 | 568 |
my $encoding = $headers->transfer_encoding; |
572 | 569 |
$headers = $headers->transfer_encoding('chunked'); |
573 | 570 |
|
574 | 571 |
Shortcut for the C<Transfer-Encoding> header. |
575 | 572 |
|
576 |
-=head2 C<upgrade> |
|
573 |
+=head2 upgrade |
|
577 | 574 |
|
578 | 575 |
my $upgrade = $headers->upgrade; |
579 | 576 |
$headers = $headers->upgrade('websocket'); |
580 | 577 |
|
581 | 578 |
Shortcut for the C<Upgrade> header. |
582 | 579 |
|
583 |
-=head2 C<user_agent> |
|
580 |
+=head2 user_agent |
|
584 | 581 |
|
585 | 582 |
my $agent = $headers->user_agent; |
586 | 583 |
$headers = $headers->user_agent('Mojo/1.0'); |
587 | 584 |
|
588 | 585 |
Shortcut for the C<User-Agent> header. |
589 | 586 |
|
590 |
-=head2 C<www_authenticate> |
|
587 |
+=head2 www_authenticate |
|
591 | 588 |
|
592 | 589 |
my $authenticate = $headers->www_authenticate; |
593 | 590 |
$headers = $headers->www_authenticate('Basic realm="realm"'); |
... | ... |
@@ -80,7 +80,13 @@ sub parse { |
80 | 80 |
sub rel_dir { catdir(@{shift->{parts} || []}, split '/', shift) } |
81 | 81 |
sub rel_file { catfile(@{shift->{parts} || []}, split '/', shift) } |
82 | 82 |
|
83 |
-sub slurp_rel_file { slurp shift->rel_file(@_) } |
|
83 |
+# DEPRECATED in Rainbow! |
|
84 |
+sub slurp_rel_file { |
|
85 |
+ warn <<EOF; |
|
86 |
+Mojo::Home->slurp_rel_file is DEPRECATED in favor of Mojo::Util->slurp!!! |
|
87 |
+EOF |
|
88 |
+ slurp shift->rel_file(@_); |
|
89 |
+} |
|
84 | 90 |
|
85 | 91 |
sub to_string { catdir(@{shift->{parts} || []}) } |
86 | 92 |
|
... | ... |
@@ -110,14 +116,14 @@ L<Mojo::Home> is a container for home directories. |
110 | 116 |
L<Mojo::Home> inherits all methods from L<Mojo::Base> and implements the |
111 | 117 |
following new ones. |
112 | 118 |
|
113 |
-=head2 C<new> |
|
119 |
+=head2 new |
|
114 | 120 |
|
115 | 121 |
my $home = Mojo::Home->new; |
116 | 122 |
my $home = Mojo::Home->new('/home/sri/myapp'); |
117 | 123 |
|
118 | 124 |
Construct a new L<Mojo::Home> object. |
119 | 125 |
|
120 |
-=head2 C<detect> |
|
126 |
+=head2 detect |
|
121 | 127 |
|
122 | 128 |
$home = $home->detect; |
123 | 129 |
$home = $home->detect('My::App'); |
... | ... |
@@ -125,13 +131,13 @@ Construct a new L<Mojo::Home> object. |
125 | 131 |
Detect home directory from the value of the C<MOJO_HOME> environment variable |
126 | 132 |
or application class. |
127 | 133 |
|
128 |
-=head2 C<lib_dir> |
|
134 |
+=head2 lib_dir |
|
129 | 135 |
|
130 | 136 |
my $path = $home->lib_dir; |
131 | 137 |
|
132 | 138 |
Path to C<lib> directory of application. |
133 | 139 |
|
134 |
-=head2 C<list_files> |
|
140 |
+=head2 list_files |
|
135 | 141 |
|
136 | 142 |
my $files = $home->list_files; |
137 | 143 |
my $files = $home->list_files('foo/bar'); |
... | ... |
@@ -141,40 +147,32 @@ diectory. |
141 | 147 |
|
142 | 148 |
$home->rel_file($home->list_files('templates/layouts')->[1]); |
143 | 149 |
|
144 |
-=head2 C<mojo_lib_dir> |
|
150 |
+=head2 mojo_lib_dir |
|
145 | 151 |
|
146 | 152 |
my $path = $home->mojo_lib_dir; |
147 | 153 |
|
148 | 154 |
Path to C<lib> directory in which L<Mojolicious> is installed. |
149 | 155 |
|
150 |
-=head2 C<parse> |
|
156 |
+=head2 parse |
|
151 | 157 |
|
152 | 158 |
$home = $home->parse('/home/sri/myapp'); |
153 | 159 |
|
154 | 160 |
Parse home directory. |
155 | 161 |
|
156 |
-=head2 C<rel_dir> |
|
162 |
+=head2 rel_dir |
|
157 | 163 |
|
158 | 164 |
my $path = $home->rel_dir('foo/bar'); |
159 | 165 |
|
160 | 166 |
Portably generate an absolute path for a directory relative to the home |
161 | 167 |
directory. |
162 | 168 |
|
163 |
-=head2 C<rel_file> |
|
169 |
+=head2 rel_file |
|
164 | 170 |
|
165 | 171 |
my $path = $home->rel_file('foo/bar.html'); |
166 | 172 |
|
167 | 173 |
Portably generate an absolute path for a file relative to the home directory. |
168 | 174 |
|
169 |
-=head2 C<slurp_rel_file> |
|
170 |
- |
|
171 |
- my $content = $home->slurp_rel_file('foo/bar.html'); |
|
172 |
- |
|
173 |
-Portably read all data at once from file relative to the home directory. |
|
174 |
- |
|
175 |
- my $content = $home->slurp_rel_file($home->list_files('public')->[1]); |
|
176 |
- |
|
177 |
-=head2 C<to_string> |
|
175 |
+=head2 to_string |
|
178 | 176 |
|
179 | 177 |
my $string = $home->to_string; |
180 | 178 |
my $string = "$home"; |
... | ... |
@@ -42,13 +42,13 @@ sub acceptor { |
42 | 42 |
# Make sure connection manager is running |
43 | 43 |
$self->_manager; |
44 | 44 |
|
45 |
- # New acceptor |
|
45 |
+ # Connect acceptor with reactor |
|
46 | 46 |
my $id = $self->_id; |
47 | 47 |
$self->{acceptors}{$id} = $acceptor; |
48 | 48 |
weaken $acceptor->reactor($self->reactor)->{reactor}; |
49 | 49 |
$self->{accepts} = $self->max_accepts if $self->max_accepts; |
50 | 50 |
|
51 |
- # Stop accepting |
|
51 |
+ # Stop accepting so new acceptor can get picked up |
|
52 | 52 |
$self->_not_accepting; |
53 | 53 |
|
54 | 54 |
return $id; |
... | ... |
@@ -61,25 +61,22 @@ sub client { |
61 | 61 |
# Make sure connection manager is running |
62 | 62 |
$self->_manager; |
63 | 63 |
|
64 |
- # New client |
|
65 | 64 |
my $id = $self->_id; |
66 | 65 |
my $c = $self->{connections}{$id} ||= {}; |
67 | 66 |
my $client = $c->{client} = Mojo::IOLoop::Client->new; |
68 | 67 |
weaken $client->reactor($self->reactor)->{reactor}; |
69 | 68 |
|
70 |
- # Connect |
|
71 | 69 |
weaken $self; |
72 | 70 |
$client->on( |
73 | 71 |
connect => sub { |
74 | 72 |
my $handle = pop; |
75 | 73 |
|
76 |
- # New stream |
|
74 |
+ # Turn handle into stream |
|
77 | 75 |
my $c = $self->{connections}{$id}; |
78 | 76 |
delete $c->{client}; |
79 | 77 |
my $stream = $c->{stream} = Mojo::IOLoop::Stream->new($handle); |
80 | 78 |
$self->_stream($stream => $id); |
81 | 79 |
|
82 |
- # Connected |
|
83 | 80 |
$self->$cb(undef, $stream); |
84 | 81 |
} |
85 | 82 |
); |
... | ... |
@@ -128,14 +125,13 @@ sub server { |
128 | 125 |
my ($self, $cb) = (shift, pop); |
129 | 126 |
$self = $self->singleton unless ref $self; |
130 | 127 |
|
131 |
- # New server |
|
132 | 128 |
my $server = Mojo::IOLoop::Server->new; |
133 | 129 |
weaken $self; |
134 | 130 |
$server->on( |
135 | 131 |
accept => sub { |
136 | 132 |
my $handle = pop; |
137 | 133 |
|
138 |
- # Accept |
|
134 |
+ # Turn handle into stream |
|
139 | 135 |
my $stream = Mojo::IOLoop::Stream->new($handle); |
140 | 136 |
$self->$cb($stream, $self->stream($stream)); |
141 | 137 |
|
... | ... |
@@ -144,7 +140,7 @@ sub server { |
144 | 140 |
if defined $self->{accepts} |
145 | 141 |
&& ($self->{accepts} -= int(rand 2) + 1) <= 0; |
146 | 142 |
|
147 |
- # Stop accepting |
|
143 |
+ # Stop accepting to release accept mutex |
|
148 | 144 |
$self->_not_accepting; |
149 | 145 |
} |
150 | 146 |
); |
... | ... |
@@ -214,7 +210,7 @@ sub _id { |
214 | 210 |
sub _manage { |
215 | 211 |
my $self = shift; |
216 | 212 |
|
217 |
- # Start accepting if possible |
|
213 |
+ # Try to acquire accept mutex |
|
218 | 214 |
$self->_accepting; |
219 | 215 |
|
220 | 216 |
# Close connections gracefully |
... | ... |
@@ -241,9 +237,8 @@ sub _not_accepting { |
241 | 237 |
# Release accept mutex |
242 | 238 |
return unless delete $self->{accepting}; |
243 | 239 |
return unless my $cb = $self->unlock; |
244 |
- $self->$cb(); |
|
240 |
+ $self->$cb; |
|
245 | 241 |
|
246 |
- # Stop accepting |
|
247 | 242 |
$_->stop for values %{$self->{acceptors} || {}}; |
248 | 243 |
} |
249 | 244 |
|
... | ... |
@@ -274,7 +269,7 @@ sub _stream { |
274 | 269 |
$self->{connections}{$id}{stream} = $stream; |
275 | 270 |
weaken $stream->reactor($self->reactor)->{reactor}; |
276 | 271 |
|
277 |
- # Stream |
|
272 |
+ # Start streaming |
|
278 | 273 |
weaken $self; |
279 | 274 |
$stream->on(close => sub { $self->{connections}{$id}{finish} = 1 }); |
280 | 275 |
$stream->start; |
... | ... |
@@ -297,12 +292,12 @@ Mojo::IOLoop - Minimalistic event loop |
297 | 292 |
my ($loop, $stream) = @_; |
298 | 293 |
|
299 | 294 |
$stream->on(read => sub { |
300 |
- my ($stream, $chunk) = @_; |
|
295 |
+ my ($stream, $bytes) = @_; |
|
301 | 296 |
|
302 |
- # Process input |
|
303 |
- say $chunk; |
|
297 |
+ # Process input chunk |
|
298 |
+ say $bytes; |
|
304 | 299 |
|
305 |
- # Got some data, time to write |
|
300 |
+ # Write response |
|
306 | 301 |
$stream->write('HTTP/1.1 200 OK'); |
307 | 302 |
}); |
308 | 303 |
}); |
... | ... |
@@ -312,14 +307,14 @@ Mojo::IOLoop - Minimalistic event loop |
312 | 307 |
my ($loop, $err, $stream) = @_; |
313 | 308 |
|
314 | 309 |
$stream->on(read => sub { |
315 |
- my ($stream, $chunk) = @_; |
|
310 |
+ my ($stream, $bytes) = @_; |
|
316 | 311 |
|
317 | 312 |
# Process input |
318 |
- say "Input: $chunk"; |
|
313 |
+ say "Input: $bytes"; |
|
319 | 314 |
}); |
320 | 315 |
|
321 | 316 |
# Write request |
322 |
- $stream->write("GET / HTTP/1.1\r\n\r\n"); |
|
317 |
+ $stream->write("GET / HTTP/1.1\x0d\x0a\x0d\x0a"); |
|
323 | 318 |
}); |
324 | 319 |
|
325 | 320 |
# Add a timer |
... | ... |
@@ -352,7 +347,7 @@ See L<Mojolicious::Guides::Cookbook> for more. |
352 | 347 |
|
353 | 348 |
L<Mojo::IOLoop> implements the following attributes. |
354 | 349 |
|
355 |
-=head2 C<accept_interval> |
|
350 |
+=head2 accept_interval |
|
356 | 351 |
|
357 | 352 |
my $interval = $loop->accept_interval; |
358 | 353 |
$loop = $loop->accept_interval(0.5); |
... | ... |
@@ -361,7 +356,7 @@ Interval in seconds for trying to reacquire the accept mutex and connection |
361 | 356 |
management, defaults to C<0.025>. Note that changing this value can affect |
362 | 357 |
performance and idle CPU usage. |
363 | 358 |
|
364 |
-=head2 C<lock> |
|
359 |
+=head2 lock |
|
365 | 360 |
|
366 | 361 |
my $cb = $loop->lock; |
367 | 362 |
$loop = $loop->lock(sub {...}); |
... | ... |
@@ -377,7 +372,7 @@ this callback are not captured. |
377 | 372 |
return 1; |
378 | 373 |
}); |
379 | 374 |
|
380 |
-=head2 C<max_accepts> |
|
375 |
+=head2 max_accepts |
|
381 | 376 |
|
382 | 377 |
my $max = $loop->max_accepts; |
383 | 378 |
$loop = $loop->max_accepts(1000); |
... | ... |
@@ -388,7 +383,7 @@ to C<0>. Setting the value to C<0> will allow this event loop to accept new |
388 | 383 |
connections indefinitely. Note that up to half of this value can be subtracted |
389 | 384 |
randomly to improve load balancing between multiple server processes. |
390 | 385 |
|
391 |
-=head2 C<max_connections> |
|
386 |
+=head2 max_connections |
|
392 | 387 |
|
393 | 388 |
my $max = $loop->max_connections; |
394 | 389 |
$loop = $loop->max_connections(1000); |
... | ... |
@@ -399,14 +394,14 @@ C<1000>. Setting the value to C<0> will make this event loop stop accepting |
399 | 394 |
new connections and allow it to shut down gracefully without interrupting |
400 | 395 |
existing connections. |
401 | 396 |
|
402 |
-=head2 C<multi_accept> |
|
397 |
+=head2 multi_accept |
|
403 | 398 |
|
404 | 399 |
my $multi = $loop->multi_accept; |
405 | 400 |
$loop = $loop->multi_accept(100); |
406 | 401 |
|
407 | 402 |
Number of connections to accept at once, defaults to C<50>. |
408 | 403 |
|
409 |
-=head2 C<reactor> |
|
404 |
+=head2 reactor |
|
410 | 405 |
|
411 | 406 |
my $reactor = $loop->reactor; |
412 | 407 |
$loop = $loop->reactor(Mojo::Reactor->new); |
... | ... |
@@ -423,7 +418,7 @@ L<Mojo::Reactor::EV> object. |
423 | 418 |
# Change to watching only if handle becomes writable |
424 | 419 |
$loop->reactor->watch($handle, 0, 1); |
425 | 420 |
|
426 |
-=head2 C<unlock> |
|
421 |
+=head2 unlock |
|
427 | 422 |
|
428 | 423 |
my $cb = $loop->unlock; |
429 | 424 |
$loop = $loop->unlock(sub {...}); |
... | ... |
@@ -436,7 +431,7 @@ processes. Note that exceptions in this callback are not captured. |
436 | 431 |
L<Mojo::IOLoop> inherits all methods from L<Mojo::Base> and implements the |
437 | 432 |
following new ones. |
438 | 433 |
|
439 |
-=head2 C<acceptor> |
|
434 |
+=head2 acceptor |
|
440 | 435 |
|
441 | 436 |
my $server = Mojo::IOLoop->acceptor($id); |
442 | 437 |
my $server = $loop->acceptor($id); |
... | ... |
@@ -444,7 +439,7 @@ following new ones. |
444 | 439 |
|
445 | 440 |
Get L<Mojo::IOLoop::Server> object for id or turn object into an acceptor. |
446 | 441 |
|
447 |
-=head2 C<client> |
|
442 |
+=head2 client |
|
448 | 443 |
|
449 | 444 |
my $id |
450 | 445 |
= Mojo::IOLoop->client(address => '127.0.0.1', port => 3000, sub {...}); |
... | ... |
@@ -460,7 +455,7 @@ L<Mojo::IOLoop::Client/"connect">. |
460 | 455 |
... |
461 | 456 |
}); |
462 | 457 |
|
463 |
-=head2 C<delay> |
|
458 |
+=head2 delay |
|
464 | 459 |
|
465 | 460 |
my $delay = Mojo::IOLoop->delay; |
466 | 461 |
my $delay = $loop->delay; |
... | ... |
@@ -506,14 +501,14 @@ ones as a chain of steps. |
506 | 501 |
# Wait for events if necessary |
507 | 502 |
$delay->wait unless Mojo::IOLoop->is_running; |
508 | 503 |
|
509 |
-=head2 C<generate_port> |
|
504 |
+=head2 generate_port |
|
510 | 505 |
|
511 | 506 |
my $port = Mojo::IOLoop->generate_port; |
512 | 507 |
my $port = $loop->generate_port; |
513 | 508 |
|
514 | 509 |
Find a free TCP port, this is a utility function primarily used for tests. |
515 | 510 |
|
516 |
-=head2 C<is_running> |
|
511 |
+=head2 is_running |
|
517 | 512 |
|
518 | 513 |
my $success = Mojo::IOLoop->is_running; |
519 | 514 |
my $success = $loop->is_running; |
... | ... |
@@ -522,7 +517,7 @@ Check if event loop is running. |
522 | 517 |
|
523 | 518 |
exit unless Mojo::IOLoop->is_running; |
524 | 519 |
|
525 |
-=head2 C<one_tick> |
|
520 |
+=head2 one_tick |
|
526 | 521 |
|
527 | 522 |
Mojo::IOLoop->one_tick; |
528 | 523 |
$loop->one_tick; |
... | ... |
@@ -530,7 +525,7 @@ Check if event loop is running. |
530 | 525 |
Run event loop until an event occurs. Note that this method can recurse back |
531 | 526 |
into the reactor, so you need to be careful. |
532 | 527 |
|
533 |
-=head2 C<recurring> |
|
528 |
+=head2 recurring |
|
534 | 529 |
|
535 | 530 |
my $id = Mojo::IOLoop->recurring(0.5 => sub {...}); |
536 | 531 |
my $id = $loop->recurring(3 => sub {...}); |
... | ... |
@@ -541,7 +536,7 @@ amount of time in seconds. |
541 | 536 |
# Invoke as soon as possible |
542 | 537 |
Mojo::IOLoop->recurring(0 => sub { say 'Reactor tick.' }); |
543 | 538 |
|
544 |
-=head2 C<remove> |
|
539 |
+=head2 remove |
|
545 | 540 |
|
546 | 541 |
Mojo::IOLoop->remove($id); |
547 | 542 |
$loop->remove($id); |
... | ... |
@@ -549,7 +544,7 @@ amount of time in seconds. |
549 | 544 |
Remove anything with an id, connections will be dropped gracefully by allowing |
550 | 545 |
them to finish writing all data in their write buffers. |
551 | 546 |
|
552 |
-=head2 C<server> |
|
547 |
+=head2 server |
|
553 | 548 |
|
554 | 549 |
my $id = Mojo::IOLoop->server(port => 3000, sub {...}); |
555 | 550 |
my $id = $loop->server(port => 3000, sub {...}); |
... | ... |
@@ -564,7 +559,7 @@ as L<Mojo::IOLoop::Server/"listen">. |
564 | 559 |
... |
565 | 560 |
}); |
566 | 561 |
|
567 |
-=head2 C<singleton> |
|
562 |
+=head2 singleton |
|
568 | 563 |
|
569 | 564 |
my $loop = Mojo::IOLoop->singleton; |
570 | 565 |
|
... | ... |
@@ -575,7 +570,7 @@ loop object from everywhere inside the process. |
575 | 570 |
Mojo::IOLoop->timer(2 => sub { Mojo::IOLoop->stop }); |
576 | 571 |
Mojo::IOLoop->start; |
577 | 572 |
|
578 |
-=head2 C<start> |
|
573 |
+=head2 start |
|
579 | 574 |
|
580 | 575 |
Mojo::IOLoop->start; |
581 | 576 |
$loop->start; |
... | ... |
@@ -586,7 +581,7 @@ reactors stop automatically if there are no events being watched anymore. |
586 | 581 |
# Start event loop only if it is not running already |
587 | 582 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
588 | 583 |
|
589 |
-=head2 C<stop> |
|
584 |
+=head2 stop |
|
590 | 585 |
|
591 | 586 |
Mojo::IOLoop->stop; |
592 | 587 |
$loop->stop; |
... | ... |
@@ -594,7 +589,7 @@ reactors stop automatically if there are no events being watched anymore. |
594 | 589 |
Stop the event loop, this will not interrupt any existing connections and the |
595 | 590 |
event loop can be restarted by running C<start> again. |
596 | 591 |
|
597 |
-=head2 C<stream> |
|
592 |
+=head2 stream |
|
598 | 593 |
|
599 | 594 |
my $stream = Mojo::IOLoop->stream($id); |
600 | 595 |
my $stream = $loop->stream($id); |
... | ... |
@@ -605,7 +600,7 @@ Get L<Mojo::IOLoop::Stream> object for id or turn object into a connection. |
605 | 600 |
# Increase inactivity timeout for connection to 300 seconds |
606 | 601 |
Mojo::IOLoop->stream($id)->timeout(300); |
607 | 602 |
|
608 |
-=head2 C<timer> |
|
603 |
+=head2 timer |
|
609 | 604 |
|
610 | 605 |
my $id = Mojo::IOLoop->timer(5 => sub {...}); |
611 | 606 |
my $id = $loop->timer(5 => sub {...}); |
... | ... |
@@ -43,7 +43,6 @@ sub _cleanup { |
43 | 43 |
sub _connect { |
44 | 44 |
my ($self, $args) = @_; |
45 | 45 |
|
46 |
- # New socket |
|
47 | 46 |
my $handle; |
48 | 47 |
my $reactor = $self->reactor; |
49 | 48 |
my $address = $args->{address} ||= 'localhost'; |
... | ... |
@@ -83,7 +82,6 @@ sub _tls { |
83 | 82 |
return; |
84 | 83 |
} |
85 | 84 |
|
86 |
- # Connected |
|
87 | 85 |
$self->_cleanup->emit_safe(connect => $handle); |
88 | 86 |
} |
89 | 87 |
|
... | ... |
@@ -102,8 +100,6 @@ sub _try { |
102 | 100 |
|
103 | 101 |
# TLS |
104 | 102 |
if ($args->{tls} && !$handle->isa('IO::Socket::SSL')) { |
105 |
- |
|
106 |
- # No TLS support |
|
107 | 103 |
return $self->emit_safe( |
108 | 104 |
error => 'IO::Socket::SSL 1.75 required for TLS support') |
109 | 105 |
unless TLS; |
... | ... |
@@ -130,7 +126,6 @@ sub _try { |
130 | 126 |
return $reactor->io($handle => sub { $self->_tls })->watch($handle, 0, 1); |
131 | 127 |
} |
132 | 128 |
|
133 |
- # Connected |
|
134 | 129 |
$self->_cleanup->emit_safe(connect => $handle); |
135 | 130 |
} |
136 | 131 |
|
... | ... |
@@ -165,9 +160,10 @@ L<Mojo::IOLoop::Client> opens TCP connections for L<Mojo::IOLoop>. |
165 | 160 |
|
166 | 161 |
=head1 EVENTS |
167 | 162 |
|
168 |
-L<Mojo::IOLoop::Client> can emit the following events. |
|
163 |
+L<Mojo::IOLoop::Client> inherits all events from L<Mojo::EventEmitter> and can |
|
164 |
+emit the following new ones. |
|
169 | 165 |
|
170 |
-=head2 C<connect> |
|
166 |
+=head2 connect |
|
171 | 167 |
|
172 | 168 |
$client->on(connect => sub { |
173 | 169 |
my ($client, $handle) = @_; |
... | ... |
@@ -176,7 +172,7 @@ L<Mojo::IOLoop::Client> can emit the following events. |
176 | 172 |
|
177 | 173 |
Emitted safely once the connection is established. |
178 | 174 |
|
179 |
-=head2 C<error> |
|
175 |
+=head2 error |
|
180 | 176 |
|
181 | 177 |
$client->on(error => sub { |
182 | 178 |
my ($client, $err) = @_; |
... | ... |
@@ -189,7 +185,7 @@ Emitted safely if an error occurs on the connection. |
189 | 185 |
|
190 | 186 |
L<Mojo::IOLoop::Client> implements the following attributes. |
191 | 187 |
|
192 |
-=head2 C<reactor> |
|
188 |
+=head2 reactor |
|
193 | 189 |
|
194 | 190 |
my $reactor = $client->reactor; |
195 | 191 |
$client = $client->reactor(Mojo::Reactor::Poll->new); |
... | ... |
@@ -202,7 +198,7 @@ global L<Mojo::IOLoop> singleton. |
202 | 198 |
L<Mojo::IOLoop::Client> inherits all methods from L<Mojo::EventEmitter> and |
203 | 199 |
implements the following new ones. |
204 | 200 |
|
205 |
-=head2 C<connect> |
|
201 |
+=head2 connect |
|
206 | 202 |
|
207 | 203 |
$client->connect(address => '127.0.0.1', port => 3000); |
208 | 204 |
|
... | ... |
@@ -213,40 +209,40 @@ These options are currently available: |
213 | 209 |
|
214 | 210 |
=over 2 |
215 | 211 |
|
216 |
-=item C<address> |
|
212 |
+=item address |
|
217 | 213 |
|
218 | 214 |
Address or host name of the peer to connect to, defaults to C<localhost>. |
219 | 215 |
|
220 |
-=item C<handle> |
|
216 |
+=item handle |
|
221 | 217 |
|
222 | 218 |
Use an already prepared handle. |
223 | 219 |
|
224 |
-=item C<local_address> |
|
220 |
+=item local_address |
|
225 | 221 |
|
226 | 222 |
Local address to bind to. |
227 | 223 |
|
228 |
-=item C<port> |
|
224 |
+=item port |
|
229 | 225 |
|
230 | 226 |
Port to connect to. |
231 | 227 |
|
232 |
-=item C<timeout> |
|
228 |
+=item timeout |
|
233 | 229 |
|
234 | 230 |
Maximum amount of time in seconds establishing connection may take before |
235 | 231 |
getting canceled, defaults to C<10>. |
236 | 232 |
|
237 |
-=item C<tls> |
|
233 |
+=item tls |
|
238 | 234 |
|
239 | 235 |
Enable TLS. |
240 | 236 |
|
241 |
-=item C<tls_ca> |
|
237 |
+=item tls_ca |
|
242 | 238 |
|
243 | 239 |
Path to TLS certificate authority file. Also activates hostname verification. |
244 | 240 |
|
245 |
-=item C<tls_cert> |
|
241 |
+=item tls_cert |
|
246 | 242 |
|
247 | 243 |
Path to the TLS certificate file. |
248 | 244 |
|
249 |
-=item C<tls_key> |
|
245 |
+=item tls_key |
|
250 | 246 |
|
251 | 247 |
Path to the TLS key file. |
252 | 248 |
|
... | ... |
@@ -109,9 +109,10 @@ L<Mojo::IOLoop::Delay> controls the flow of events for L<Mojo::IOLoop>. |
109 | 109 |
|
110 | 110 |
=head1 EVENTS |
111 | 111 |
|
112 |
-L<Mojo::IOLoop::Delay> can emit the following events. |
|
112 |
+L<Mojo::IOLoop::Delay> inherits all events from L<Mojo::EventEmitter> and can |
|
113 |
+emit the following new ones. |
|
113 | 114 |
|
114 |
-=head2 C<finish> |
|
115 |
+=head2 finish |
|
115 | 116 |
|
116 | 117 |
$delay->on(finish => sub { |
117 | 118 |
my ($delay, @args) = @_; |
... | ... |
@@ -125,7 +126,7 @@ steps. |
125 | 126 |
|
126 | 127 |
L<Mojo::IOLoop::Delay> implements the following attributes. |
127 | 128 |
|
128 |
-=head2 C<ioloop> |
|
129 |
+=head2 ioloop |
|
129 | 130 |
|
130 | 131 |
my $ioloop = $delay->ioloop; |
131 | 132 |
$delay = $delay->ioloop(Mojo::IOLoop->new); |
... | ... |
@@ -138,7 +139,7 @@ singleton. |
138 | 139 |
L<Mojo::IOLoop::Delay> inherits all methods from L<Mojo::EventEmitter> and |
139 | 140 |
implements the following new ones. |
140 | 141 |
|
141 |
-=head2 C<begin> |
|
142 |
+=head2 begin |
|
142 | 143 |
|
143 | 144 |
my $cb = $delay->begin; |
144 | 145 |
|
... | ... |
@@ -150,7 +151,7 @@ that the first argument passed to the callback will be ignored. |
150 | 151 |
Mojo::UserAgent->new->get('mojolicio.us' => $delay->begin); |
151 | 152 |
my $tx = $delay->wait; |
152 | 153 |
|
153 |
-=head2 C<end> |
|
154 |
+=head2 end |
|
154 | 155 |
|
155 | 156 |
my $remaining = $delay->end; |
156 | 157 |
my $remaining = $delay->end(@args); |
... | ... |
@@ -158,7 +159,7 @@ that the first argument passed to the callback will be ignored. |
158 | 159 |
Decrement active event counter, all arguments are queued for the next step or |
159 | 160 |
C<finish> event and C<wait> method. |
160 | 161 |
|
161 |
-=head2 C<steps> |
|
162 |
+=head2 steps |
|
162 | 163 |
|
163 | 164 |
$delay = $delay->steps(sub {...}, sub {...}); |
164 | 165 |
|
... | ... |
@@ -166,7 +167,7 @@ Sequentialize multiple events, the first callback will run right away, and the |
166 | 167 |
next one once the active event counter reaches zero, this chain will continue |
167 | 168 |
until there are no more callbacks left. |
168 | 169 |
|
169 |
-=head2 C<wait> |
|
170 |
+=head2 wait |
|
170 | 171 |
|
171 | 172 |
my @args = $delay->wait; |
172 | 173 |
|
... | ... |
@@ -78,7 +78,6 @@ sub listen { |
78 | 78 |
$handle->blocking(0); |
79 | 79 |
$self->{handle} = $handle; |
80 | 80 |
|
81 |
- # TLS |
|
82 | 81 |
return unless $args->{tls}; |
83 | 82 |
croak "IO::Socket::SSL 1.75 required for TLS support" unless TLS; |
84 | 83 |
|
... | ... |
@@ -115,7 +114,6 @@ sub stop { $_[0]->reactor->remove($_[0]->{handle}) } |
115 | 114 |
sub _accept { |
116 | 115 |
my $self = shift; |
117 | 116 |
|
118 |
- # Accept |
|
119 | 117 |
return unless my $handle = $self->{handle}->accept; |
120 | 118 |
$handle->blocking(0); |
121 | 119 |
|
... | ... |
@@ -182,9 +180,10 @@ L<Mojo::IOLoop::Server> accepts TCP connections for L<Mojo::IOLoop>. |
182 | 180 |
|
183 | 181 |
=head1 EVENTS |
184 | 182 |
|
185 |
-L<Mojo::IOLoop::Server> can emit the following events. |
|
183 |
+L<Mojo::IOLoop::Server> inherits all events from L<Mojo::EventEmitter> and can |
|
184 |
+emit the following new ones. |
|
186 | 185 |
|
187 |
-=head2 C<accept> |
|
186 |
+=head2 accept |
|
188 | 187 |
|
189 | 188 |
$server->on(accept => sub { |
190 | 189 |
my ($server, $handle) = @_; |
... | ... |
@@ -197,14 +196,14 @@ Emitted safely for each accepted connection. |
197 | 196 |
|
198 | 197 |
L<Mojo::IOLoop::Server> implements the following attributes. |
199 | 198 |
|
200 |
-=head2 C<multi_accept> |
|
199 |
+=head2 multi_accept |
|
201 | 200 |
|
202 | 201 |
my $multi = $server->multi_accept; |
203 | 202 |
$server = $server->multi_accept(100); |
204 | 203 |
|
205 | 204 |
Number of connections to accept at once, defaults to C<50>. |
206 | 205 |
|
207 |
-=head2 C<reactor> |
|
206 |
+=head2 reactor |
|
208 | 207 |
|
209 | 208 |
my $reactor = $server->reactor; |
210 | 209 |
$server = $server->reactor(Mojo::Reactor::Poll->new); |
... | ... |
@@ -217,7 +216,7 @@ global L<Mojo::IOLoop> singleton. |
217 | 216 |
L<Mojo::IOLoop::Server> inherits all methods from L<Mojo::EventEmitter> and |
218 | 217 |
implements the following new ones. |
219 | 218 |
|
220 |
-=head2 C<listen> |
|
219 |
+=head2 listen |
|
221 | 220 |
|
222 | 221 |
$server->listen(port => 3000); |
223 | 222 |
|
... | ... |
@@ -228,53 +227,53 @@ These options are currently available: |
228 | 227 |
|
229 | 228 |
=over 2 |
230 | 229 |
|
231 |
-=item C<address> |
|
230 |
+=item address |
|
232 | 231 |
|
233 | 232 |
Local address to listen on, defaults to all. |
234 | 233 |
|
235 |
-=item C<backlog> |
|
234 |
+=item backlog |
|
236 | 235 |
|
237 | 236 |
Maximum backlog size, defaults to C<SOMAXCONN>. |
238 | 237 |
|
239 |
-=item C<port> |
|
238 |
+=item port |
|
240 | 239 |
|
241 | 240 |
Port to listen on. |
242 | 241 |
|
243 |
-=item C<tls> |
|
242 |
+=item tls |
|
244 | 243 |
|
245 | 244 |
Enable TLS. |
246 | 245 |
|
247 |
-=item C<tls_ca> |
|
246 |
+=item tls_ca |
|
248 | 247 |
|
249 | 248 |
Path to TLS certificate authority file. |
250 | 249 |
|
251 |
-=item C<tls_cert> |
|
250 |
+=item tls_cert |
|
252 | 251 |
|
253 | 252 |
Path to the TLS cert file, defaults to a built-in test certificate. |
254 | 253 |
|
255 |
-=item C<tls_key> |
|
254 |
+=item tls_key |
|
256 | 255 |
|
257 | 256 |
Path to the TLS key file, defaults to a built-in test key. |
258 | 257 |
|
259 |
-=item C<tls_verify> |
|
258 |
+=item tls_verify |
|
260 | 259 |
|
261 | 260 |
TLS verification mode, defaults to C<0x03>. |
262 | 261 |
|
263 | 262 |
=back |
264 | 263 |
|
265 |
-=head2 C<generate_port> |
|
264 |
+=head2 generate_port |
|
266 | 265 |
|
267 | 266 |
my $port = $server->generate_port; |
268 | 267 |
|
269 | 268 |
Find a free TCP port, this is a utility function primarily used for tests. |
270 | 269 |
|
271 |
-=head2 C<start> |
|
270 |
+=head2 start |
|
272 | 271 |
|
273 | 272 |
$server->start; |
274 | 273 |
|
275 | 274 |
Start accepting connections. |
276 | 275 |
|
277 |
-=head2 C<stop> |
|
276 |
+=head2 stop |
|
278 | 277 |
|
279 | 278 |
$server->stop; |
280 | 279 |
|
... | ... |
@@ -24,7 +24,6 @@ sub close { |
24 | 24 |
return unless my $handle = delete $self->{handle}; |
25 | 25 |
$reactor->remove($handle); |
26 | 26 |
|
27 |
- # Close |
|
28 | 27 |
close $handle; |
29 | 28 |
$self->emit_safe('close'); |
30 | 29 |
} |
... | ... |
@@ -65,14 +64,9 @@ sub steal_handle { |
65 | 64 |
sub write { |
66 | 65 |
my ($self, $chunk, $cb) = @_; |
67 | 66 |
|
68 |
- # Prepare chunk for writing |
|
69 | 67 |
$self->{buffer} .= $chunk; |
70 |
- |
|
71 |
- # Write with roundtrip |
|
72 | 68 |
if ($cb) { $self->once(drain => $cb) } |
73 | 69 |
else { return $self unless length $self->{buffer} } |
74 |
- |
|
75 |
- # Start writing |
|
76 | 70 |
$self->reactor->watch($self->{handle}, !$self->{paused}, 1) |
77 | 71 |
if $self->{handle}; |
78 | 72 |
|
... | ... |
@@ -82,10 +76,7 @@ sub write { |
82 | 76 |
sub _read { |
83 | 77 |
my $self = shift; |
84 | 78 |
|
85 |
- # Read |
|
86 | 79 |
my $read = $self->{handle}->sysread(my $buffer, 131072, 0); |
87 |
- |
|
88 |
- # Error |
|
89 | 80 |
unless (defined $read) { |
90 | 81 |
|
91 | 82 |
# Retry |
... | ... |
@@ -101,7 +92,6 @@ sub _read { |
101 | 92 |
# EOF |
102 | 93 |
return $self->close if $read == 0; |
103 | 94 |
|
104 |
- # Handle read |
|
105 | 95 |
$self->emit_safe(read => $buffer)->{active} = time; |
106 | 96 |
} |
107 | 97 |
|
... | ... |
@@ -118,19 +108,15 @@ sub _startup { |
118 | 108 |
} |
119 | 109 |
); |
120 | 110 |
|
121 |
- # Start streaming |
|
122 | 111 |
$reactor->io($self->{handle}, sub { pop() ? $self->_write : $self->_read }); |
123 | 112 |
} |
124 | 113 |
|
125 | 114 |
sub _write { |
126 | 115 |
my $self = shift; |
127 | 116 |
|
128 |
- # Write as much as possible |
|
129 | 117 |
my $handle = $self->{handle}; |
130 | 118 |
if (length $self->{buffer}) { |
131 | 119 |
my $written = $handle->syswrite($self->{buffer}); |
132 |
- |
|
133 |
- # Error |
|
134 | 120 |
unless (defined $written) { |
135 | 121 |
|
136 | 122 |
# Retry |
... | ... |
@@ -143,15 +129,11 @@ sub _write { |
143 | 129 |
return $self->emit_safe(error => $!)->close; |
144 | 130 |
} |
145 | 131 |
|
146 |
- # Remove written chunk from buffer |
|
147 | 132 |
$self->emit_safe(write => substr($self->{buffer}, 0, $written, '')); |
148 | 133 |
$self->{active} = time; |
149 | 134 |
} |
150 | 135 |
|
151 |
- # Handle drain |
|
152 | 136 |
$self->emit_safe('drain') if !length $self->{buffer}; |
153 |
- |
|
154 |
- # Stop writing |
|
155 | 137 |
return if $self->is_writing; |
156 | 138 |
$self->reactor->watch($handle, !$self->{paused}, 0); |
157 | 139 |
} |
... | ... |
@@ -169,7 +151,7 @@ Mojo::IOLoop::Stream - Non-blocking I/O stream |
169 | 151 |
# Create stream |
170 | 152 |
my $stream = Mojo::IOLoop::Stream->new($handle); |
171 | 153 |
$stream->on(read => sub { |
172 |
- my ($stream, $chunk) = @_; |
|
154 |
+ my ($stream, $bytes) = @_; |
|
173 | 155 |
... |
174 | 156 |
}); |
175 | 157 |
$stream->on(close => sub { |
... | ... |
@@ -195,9 +177,10 @@ L<Mojo::IOLoop>. |
195 | 177 |
|
196 | 178 |
=head1 EVENTS |
197 | 179 |
|
198 |
-L<Mojo::IOLoop::Stream> can emit the following events. |
|
180 |
+L<Mojo::IOLoop::Stream> inherits all events from L<Mojo::EventEmitter> and can |
|
181 |
+emit the following new ones. |
|
199 | 182 |
|
200 |
-=head2 C<close> |
|
183 |
+=head2 close |
|
201 | 184 |
|
202 | 185 |
$stream->on(close => sub { |
203 | 186 |
my $stream = shift; |
... | ... |
@@ -206,7 +189,7 @@ L<Mojo::IOLoop::Stream> can emit the following events. |
206 | 189 |
|
207 | 190 |
Emitted safely if the stream gets closed. |
208 | 191 |
|
209 |
-=head2 C<drain> |
|
192 |
+=head2 drain |
|
210 | 193 |
|
211 | 194 |
$stream->on(drain => sub { |
212 | 195 |
my $stream = shift; |
... | ... |
@@ -215,7 +198,7 @@ Emitted safely if the stream gets closed. |
215 | 198 |
|
216 | 199 |
Emitted safely once all data has been written. |
217 | 200 |
|
218 |
-=head2 C<error> |
|
201 |
+=head2 error |
|
219 | 202 |
|
220 | 203 |
$stream->on(error => sub { |
221 | 204 |
my ($stream, $err) = @_; |
... | ... |
@@ -224,16 +207,16 @@ Emitted safely once all data has been written. |
224 | 207 |
|
225 | 208 |
Emitted safely if an error occurs on the stream. |
226 | 209 |
|
227 |
-=head2 C<read> |
|
210 |
+=head2 read |
|
228 | 211 |
|
229 | 212 |
$stream->on(read => sub { |
230 |
- my ($stream, $chunk) = @_; |
|
213 |
+ my ($stream, $bytes) = @_; |
|
231 | 214 |
... |
232 | 215 |
}); |
233 | 216 |
|
234 | 217 |
Emitted safely if new data arrives on the stream. |
235 | 218 |
|
236 |
-=head2 C<timeout> |
|
219 |
+=head2 timeout |
|
237 | 220 |
|
238 | 221 |
$stream->on(timeout => sub { |
239 | 222 |
my $stream = shift; |
... | ... |
@@ -243,10 +226,10 @@ Emitted safely if new data arrives on the stream. |
243 | 226 |
Emitted safely if the stream has been inactive for too long and will get |
244 | 227 |
closed automatically. |
245 | 228 |
|
246 |
-=head2 C<write> |
|
229 |
+=head2 write |
|
247 | 230 |
|
248 | 231 |
$stream->on(write => sub { |
249 |
- my ($stream, $chunk) = @_; |
|
232 |
+ my ($stream, $bytes) = @_; |
|
250 | 233 |
... |
251 | 234 |
}); |
252 | 235 |
|
... | ... |
@@ -256,7 +239,7 @@ Emitted safely if new data has been written to the stream. |
256 | 239 |
|
257 | 240 |
L<Mojo::IOLoop::Stream> implements the following attributes. |
258 | 241 |
|
259 |
-=head2 C<reactor> |
|
242 |
+=head2 reactor |
|
260 | 243 |
|
261 | 244 |
my $reactor = $stream->reactor; |
262 | 245 |
$stream = $stream->reactor(Mojo::Reactor::Poll->new); |
... | ... |
@@ -264,7 +247,7 @@ L<Mojo::IOLoop::Stream> implements the following attributes. |
264 | 247 |
Low level event reactor, defaults to the C<reactor> attribute value of the |
265 | 248 |
global L<Mojo::IOLoop> singleton. |
266 | 249 |
|
267 |
-=head2 C<timeout> |
|
250 |
+=head2 timeout |
|
268 | 251 |
|
269 | 252 |
my $timeout = $stream->timeout; |
270 | 253 |
$stream = $stream->timeout(45); |
... | ... |
@@ -278,59 +261,59 @@ stream to be inactive indefinitely. |
278 | 261 |
L<Mojo::IOLoop::Stream> inherits all methods from L<Mojo::EventEmitter> and |
279 | 262 |
implements the following new ones. |
280 | 263 |
|
281 |
-=head2 C<new> |
|
264 |
+=head2 new |
|
282 | 265 |
|
283 | 266 |
my $stream = Mojo::IOLoop::Stream->new($handle); |
284 | 267 |
|
285 | 268 |
Construct a new L<Mojo::IOLoop::Stream> object. |
286 | 269 |
|
287 |
-=head2 C<close> |
|
270 |
+=head2 close |
|
288 | 271 |
|
289 | 272 |
$stream->close; |
290 | 273 |
|
291 | 274 |
Close stream immediately. |
292 | 275 |
|
293 |
-=head2 C<handle> |
|
276 |
+=head2 handle |
|
294 | 277 |
|
295 | 278 |
my $handle = $stream->handle; |
296 | 279 |
|
297 | 280 |
Get handle for stream. |
298 | 281 |
|
299 |
-=head2 C<is_readable> |
|
282 |
+=head2 is_readable |
|
300 | 283 |
|
301 | 284 |
my $success = $stream->is_readable; |
302 | 285 |
|
303 | 286 |
Quick non-blocking check if stream is readable, useful for identifying tainted |
304 | 287 |
sockets. |
305 | 288 |
|
306 |
-=head2 C<is_writing> |
|
289 |
+=head2 is_writing |
|
307 | 290 |
|
308 | 291 |
my $success = $stream->is_writing; |
309 | 292 |
|
310 | 293 |
Check if stream is writing. |
311 | 294 |
|
312 |
-=head2 C<start> |
|
295 |
+=head2 start |
|
313 | 296 |
|
314 | 297 |
$stream->start; |
315 | 298 |
|
316 | 299 |
Start watching for new data on the stream. |
317 | 300 |
|
318 |
-=head2 C<stop> |
|
301 |
+=head2 stop |
|
319 | 302 |
|
320 | 303 |
$stream->stop; |
321 | 304 |
|
322 | 305 |
Stop watching for new data on the stream. |
323 | 306 |
|
324 |
-=head2 C<steal_handle> |
|
307 |
+=head2 steal_handle |
|
325 | 308 |
|
326 | 309 |
my $handle = $stream->steal_handle; |
327 | 310 |
|
328 | 311 |
Steal handle from stream and prevent it from getting closed automatically. |
329 | 312 |
|
330 |
-=head2 C<write> |
|
313 |
+=head2 write |
|
331 | 314 |
|
332 |
- $stream = $stream->write('Hello!'); |
|
333 |
- $stream = $stream->write('Hello!' => sub {...}); |
|
315 |
+ $stream = $stream->write($bytes); |
|
316 |
+ $stream = $stream->write($bytes => sub {...}); |
|
334 | 317 |
|
335 | 318 |
Write data to stream, the optional drain callback will be invoked once all |
336 | 319 |
data has been written. |
... | ... |
@@ -2,11 +2,14 @@ package Mojo::JSON; |
2 | 2 |
use Mojo::Base -base; |
3 | 3 |
|
4 | 4 |
use B; |
5 |
+use Exporter 'import'; |
|
5 | 6 |
use Mojo::Util; |
6 | 7 |
use Scalar::Util 'blessed'; |
7 | 8 |
|
8 | 9 |
has 'error'; |
9 | 10 |
|
11 |
+our @EXPORT_OK = ('j'); |
|
12 |
+ |
|
10 | 13 |
# Literal names |
11 | 14 |
my $FALSE = bless \(my $false = 0), 'Mojo::JSON::_Bool'; |
12 | 15 |
my $TRUE = bless \(my $true = 1), 'Mojo::JSON::_Bool'; |
... | ... |
@@ -40,7 +43,7 @@ my $WHITESPACE_RE = qr/[\x20\x09\x0a\x0d]*/; |
40 | 43 |
sub decode { |
41 | 44 |
my ($self, $bytes) = @_; |
42 | 45 |
|
43 |
- # Cleanup |
|
46 |
+ # Clean start |
|
44 | 47 |
$self->error(undef); |
45 | 48 |
|
46 | 49 |
# Missing input |
... | ... |
@@ -99,7 +102,14 @@ sub encode { |
99 | 102 |
} |
100 | 103 |
|
101 | 104 |
sub false {$FALSE} |
102 |
-sub true {$TRUE} |
|
105 |
+ |
|
106 |
+sub j { |
|
107 |
+ my $d = shift; |
|
108 |
+ return __PACKAGE__->new->encode($d) if ref $d eq 'ARRAY' || ref $d eq 'HASH'; |
|
109 |
+ return __PACKAGE__->new->decode($d); |
|
110 |
+} |
|
111 |
+ |
|
112 |
+sub true {$TRUE} |
|
103 | 113 |
|
104 | 114 |
sub _decode_array { |
105 | 115 |
my @array; |
... | ... |
@@ -246,22 +256,14 @@ sub _encode_array { |
246 | 256 |
|
247 | 257 |
sub _encode_object { |
248 | 258 |
my $object = shift; |
249 |
- |
|
250 |
- # Encode pairs |
|
251 | 259 |
my @pairs = map { _encode_string($_) . ':' . _encode_values($object->{$_}) } |
252 | 260 |
keys %$object; |
253 |
- |
|
254 |
- # Stringify |
|
255 | 261 |
return '{' . join(',', @pairs) . '}'; |
256 | 262 |
} |
257 | 263 |
|
258 | 264 |
sub _encode_string { |
259 | 265 |
my $string = shift; |
260 |
- |
|
261 |
- # Escape string |
|
262 | 266 |
$string =~ s!([\x00-\x1F\x7F\x{2028}\x{2029}\\"/\b\f\n\r\t])!$REVERSE{$1}!gs; |
263 |
- |
|
264 |
- # Stringify |
|
265 | 267 |
return "\"$string\""; |
266 | 268 |
} |
267 | 269 |
|
... | ... |
@@ -312,7 +314,6 @@ sub _exception { |
312 | 314 |
$context .= ' at line ' . @lines . ', offset ' . length(pop @lines || ''); |
313 | 315 |
} |
314 | 316 |
|
315 |
- # Throw |
|
316 | 317 |
die "$context\n"; |
317 | 318 |
} |
318 | 319 |
|
... | ... |
@@ -328,12 +329,22 @@ Mojo::JSON - Minimalistic JSON |
328 | 329 |
|
329 | 330 |
=head1 SYNOPSIS |
330 | 331 |
|
332 |
+ # Encode and decode JSON |
|
331 | 333 |
use Mojo::JSON; |
332 |
- |
|
333 | 334 |
my $json = Mojo::JSON->new; |
334 | 335 |
my $bytes = $json->encode({foo => [1, 2], bar => 'hello!', baz => \1}); |
335 | 336 |
my $hash = $json->decode($bytes); |
336 | 337 |
|
338 |
+ # Check for errors |
|
339 |
+ my $json = Mojo::JSON->new; |
|
340 |
+ if (defined(my $hash = $json->decode($bytes))) { say $hash->{message} } |
|
341 |
+ else { say 'Error: ', $json->error } |
|
342 |
+ |
|
343 |
+ # Use the alternative interface |
|
344 |
+ use Mojo::JSON 'j'; |
|
345 |
+ my $bytes = j({foo => [1, 2], bar => 'hello!', baz => \1}); |
|
346 |
+ my $hash = j($bytes); |
|
347 |
+ |
|
337 | 348 |
=head1 DESCRIPTION |
338 | 349 |
|
339 | 350 |
L<Mojo::JSON> is a minimalistic and relaxed implementation of RFC 4627. While |
... | ... |
@@ -359,11 +370,25 @@ Decoding UTF-16 (LE/BE) and UTF-32 (LE/BE) will be handled transparently, |
359 | 370 |
encoding will only generate UTF-8. The two Unicode whitespace characters |
360 | 371 |
C<u2028> and C<u2029> will always be escaped to make JSONP easier. |
361 | 372 |
|
373 |
+=head1 FUNCTIONS |
|
374 |
+ |
|
375 |
+L<Mojo::JSON> implements the following functions. |
|
376 |
+ |
|
377 |
+=head2 j |
|
378 |
+ |
|
379 |
+ my $bytes = j([1, 2, 3]); |
|
380 |
+ my $bytes = j({foo => 'bar'}); |
|
381 |
+ my $array = j($bytes); |
|
382 |
+ my $hash = j($bytes); |
|
383 |
+ |
|
384 |
+Encode Perl data structure or decode JSON and return C<undef> if decoding |
|
385 |
+fails. |
|
386 |
+ |
|
362 | 387 |
=head1 ATTRIBUTES |
363 | 388 |
|
364 | 389 |
L<Mojo::JSON> implements the following attributes. |
365 | 390 |
|
366 |
-=head2 C<error> |
|
391 |
+=head2 error |
|
367 | 392 |
|
368 | 393 |
my $err = $json->error; |
369 | 394 |
$json = $json->error('Parser error'); |
... | ... |
@@ -375,27 +400,28 @@ Parser errors. |
375 | 400 |
L<Mojo::JSON> inherits all methods from L<Mojo::Base> and implements the |
376 | 401 |
following new ones. |
377 | 402 |
|
378 |
-=head2 C<decode> |
|
403 |
+=head2 decode |
|
379 | 404 |
|
380 | 405 |
my $array = $json->decode($bytes); |
381 | 406 |
my $hash = $json->decode($bytes); |
382 | 407 |
|
383 |
-Decode JSON. |
|
408 |
+Decode JSON to Perl data structure and return C<undef> if decoding fails. |
|
384 | 409 |
|
385 |
-=head2 C<encode> |
|
410 |
+=head2 encode |
|
386 | 411 |
|
412 |
+ my $bytes = $json->encode([1, 2, 3]); |
|
387 | 413 |
my $bytes = $json->encode({foo => 'bar'}); |
388 | 414 |
|
389 |
-Encode Perl data structure. |
|
415 |
+Encode Perl data structure to JSON. |
|
390 | 416 |
|
391 |
-=head2 C<false> |
|
417 |
+=head2 false |
|
392 | 418 |
|
393 | 419 |
my $false = Mojo::JSON->false; |
394 | 420 |
my $false = $json->false; |
395 | 421 |
|
396 | 422 |
False value, used because Perl has no native equivalent. |
397 | 423 |
|
398 |
-=head2 C<true> |
|
424 |
+=head2 true |
|
399 | 425 |
|
400 | 426 |
my $true = Mojo::JSON->true; |
401 | 427 |
my $true = $json->true; |
... | ... |
@@ -10,7 +10,6 @@ sub get { shift->_pointer(0, @_) } |
10 | 10 |
sub _pointer { |
11 | 11 |
my ($self, $contains, $data, $pointer) = @_; |
12 | 12 |
|
13 |
- # Parse pointer and walk data structure |
|
14 | 13 |
$pointer = decode('UTF-8', url_unescape $pointer); |
15 | 14 |
return $data unless $pointer =~ s!^/!!; |
16 | 15 |
for my $p (split '/', $pointer) { |
... | ... |
@@ -52,7 +51,7 @@ L<Mojo::JSON::Pointer> implements JSON Pointers. |
52 | 51 |
|
53 | 52 |
=head1 METHODS |
54 | 53 |
|
55 |
-=head2 C<contains> |
|
54 |
+=head2 contains |
|
56 | 55 |
|
57 | 56 |
my $success = $pointer->contains($data, '/foo/1'); |
58 | 57 |
|
... | ... |
@@ -67,7 +66,7 @@ JSON Pointer. |
67 | 66 |
$pointer->contains({foo => 'bar', baz => [4, 5, 6]}, '/bar'); |
68 | 67 |
$pointer->contains({foo => 'bar', baz => [4, 5, 6]}, '/baz/9'); |
69 | 68 |
|
70 |
-=head2 C<get> |
|
69 |
+=head2 get |
|
71 | 70 |
|
72 | 71 |
my $value = $pointer->get($data, '/foo/bar'); |
73 | 72 |
|
... | ... |
@@ -6,7 +6,6 @@ use File::Spec::Functions qw(catdir catfile splitdir); |
6 | 6 |
use Mojo::Exception; |
7 | 7 |
use Mojo::Util qw(b64_decode class_to_path); |
8 | 8 |
|
9 |
-# Cache |
|
10 | 9 |
my %CACHE; |
11 | 10 |
|
12 | 11 |
sub data { |
... | ... |
@@ -34,7 +33,6 @@ sub load { |
34 | 33 |
sub search { |
35 | 34 |
my ($self, $namespace) = @_; |
36 | 35 |
|
37 |
- # Check all directories |
|
38 | 36 |
my (@modules, %found); |
39 | 37 |
for my $directory (@INC) { |
40 | 38 |
next unless -d (my $path = catdir $directory, split(/::|'/, $namespace)); |
... | ... |
@@ -43,8 +41,6 @@ sub search { |
43 | 41 |
opendir(my $dir, $path); |
44 | 42 |
for my $file (grep /\.pm$/, readdir $dir) { |
45 | 43 |
next if -d catfile splitdir($path), $file; |
46 |
- |
|
47 |
- # Module found |
|
48 | 44 |
my $class = "${namespace}::" . fileparse $file, qr/\.pm/; |
49 | 45 |
push @modules, $class unless $found{$class}++; |
50 | 46 |
} |
... | ... |
@@ -69,7 +65,7 @@ sub _all { |
69 | 65 |
# Ignore everything after __END__ |
70 | 66 |
$content =~ s/\n__END__\r?\n.*$/\n/s; |
71 | 67 |
|
72 |
- # Split |
|
68 |
+ # Split files |
|
73 | 69 |
my @data = split /^@@\s*(.+?)\s*\r?\n/m, $content; |
74 | 70 |
shift @data; |
75 | 71 |
|
... | ... |
@@ -115,7 +111,7 @@ L<Mojo::Loader> is a class loader and plugin framework. |
115 | 111 |
L<Mojo::Loader> inherits all methods from L<Mojo::Base> and implements the |
116 | 112 |
following new ones. |
117 | 113 |
|
118 |
-=head2 C<data> |
|
114 |
+=head2 data |
|
119 | 115 |
|
120 | 116 |
my $all = $loader->data('Foo::Bar'); |
121 | 117 |
my $index = $loader->data('Foo::Bar', 'index.html'); |
... | ... |
@@ -124,7 +120,7 @@ Extract embedded file from the C<DATA> section of a class. |
124 | 120 |
|
125 | 121 |
say for keys %{$loader->data('Foo::Bar')}; |
126 | 122 |
|
127 |
-=head2 C<load> |
|
123 |
+=head2 load |
|
128 | 124 |
|
129 | 125 |
my $e = $loader->load('Foo::Bar'); |
130 | 126 |
|
... | ... |
@@ -135,7 +131,7 @@ method to see if they are already loaded. |
135 | 131 |
die ref $e ? "Exception: $e" : 'Already loaded!'; |
136 | 132 |
} |
137 | 133 |
|
138 |
-=head2 C<search> |
|
134 |
+=head2 search |
|
139 | 135 |
|
140 | 136 |
my $modules = $loader->search('MyApp::Namespace'); |
141 | 137 |
|
... | ... |
@@ -59,10 +59,8 @@ sub warn { shift->log(warn => @_) } |
59 | 59 |
sub _message { |
60 | 60 |
my ($self, $level, @lines) = @_; |
61 | 61 |
|
62 |
- # Check level |
|
63 | 62 |
return unless $self->is_level($level) && (my $handle = $self->handle); |
64 | 63 |
|
65 |
- # Format lines and write to handle |
|
66 | 64 |
flock $handle, LOCK_EX; |
67 | 65 |
croak "Can't write to log: $!" |
68 | 66 |
unless defined $handle->syswrite($self->format($level, @lines)); |
... | ... |
@@ -98,9 +96,10 @@ L<Mojo::Log> is a simple logger for L<Mojo> projects. |
98 | 96 |
|
99 | 97 |
=head1 EVENTS |
100 | 98 |
|
101 |
-L<Mojo::Log> can emit the following events. |
|
99 |
+L<Mojo::Log> inherits all events from L<Mojo::EventEmitter> and can emit the |
|
100 |
+following new ones. |
|
102 | 101 |
|
103 |
-=head2 C<message> |
|
102 |
+=head2 message |
|
104 | 103 |
|
105 | 104 |
$log->on(message => sub { |
106 | 105 |
my ($log, $level, @lines) = @_; |
... | ... |
@@ -119,7 +118,7 @@ Emitted when a new message gets logged. |
119 | 118 |
|
120 | 119 |
L<Mojo::Log> implements the following attributes. |
121 | 120 |
|
122 |
-=head2 C<handle> |
|
121 |
+=head2 handle |
|
123 | 122 |
|
124 | 123 |
my $handle = $log->handle; |
125 | 124 |
$log = $log->handle(IO::Handle->new); |
... | ... |
@@ -127,7 +126,7 @@ L<Mojo::Log> implements the following attributes. |
127 | 126 |
Log file handle used by default C<message> event, defaults to opening C<path> |
128 | 127 |
or C<STDERR>. |
129 | 128 |
|
130 |
-=head2 C<level> |
|
129 |
+=head2 level |
|
131 | 130 |
|
132 | 131 |
my $level = $log->level; |
133 | 132 |
$log = $log->level('debug'); |
... | ... |
@@ -139,19 +138,19 @@ These levels are currently available: |
139 | 138 |
|
140 | 139 |
=over 2 |
141 | 140 |
|
142 |
-=item C<debug> |
|
141 |
+=item debug |
|
143 | 142 |
|
144 |
-=item C<info> |
|
143 |
+=item info |
|
145 | 144 |
|
146 |
-=item C<warn> |
|
145 |
+=item warn |
|
147 | 146 |
|
148 |
-=item C<error> |
|
147 |
+=item error |
|
149 | 148 |
|
150 |
-=item C<fatal> |
|
149 |
+=item fatal |
|
151 | 150 |
|
152 | 151 |
=back |
153 | 152 |
|
154 |
-=head2 C<path> |
|
153 |
+=head2 path |
|
155 | 154 |
|
156 | 155 |
my $path = $log->path |
157 | 156 |
$log = $log->path('/var/log/mojo.log'); |
... | ... |
@@ -163,87 +162,87 @@ Log file path used by C<handle>. |
163 | 162 |
L<Mojo::Log> inherits all methods from L<Mojo::EventEmitter> and implements |
164 | 163 |
the following new ones. |
165 | 164 |
|
166 |
-=head2 C<new> |
|
165 |
+=head2 new |
|
167 | 166 |
|
168 | 167 |
my $log = Mojo::Log->new; |
169 | 168 |
|
170 | 169 |
Construct a new L<Mojo::Log> object and subscribe to C<message> event with |
171 | 170 |
default logger. |
172 | 171 |
|
173 |
-=head2 C<debug> |
|
172 |
+=head2 debug |
|
174 | 173 |
|
175 | 174 |
$log = $log->debug('You screwed up, but that is ok'); |
176 | 175 |
|
177 | 176 |
Log debug message. |
178 | 177 |
|
179 |
-=head2 C<error> |
|
178 |
+=head2 error |
|
180 | 179 |
|
181 | 180 |
$log = $log->error('You really screwed up this time'); |
182 | 181 |
|
183 | 182 |
Log error message. |
184 | 183 |
|
185 |
-=head2 C<fatal> |
|
184 |
+=head2 fatal |
|
186 | 185 |
|
187 | 186 |
$log = $log->fatal('Its over...'); |
188 | 187 |
|
189 | 188 |
Log fatal message. |
190 | 189 |
|
191 |
-=head2 C<format> |
|
190 |
+=head2 format |
|
192 | 191 |
|
193 | 192 |
my $msg = $log->format('debug', 'Hi there!'); |
194 | 193 |
my $msg = $log->format('debug', 'Hi', 'there!'); |
195 | 194 |
|
196 | 195 |
Format log message. |
197 | 196 |
|
198 |
-=head2 C<info> |
|
197 |
+=head2 info |
|
199 | 198 |
|
200 | 199 |
$log = $log->info('You are bad, but you prolly know already'); |
201 | 200 |
|
202 | 201 |
Log info message. |
203 | 202 |
|
204 |
-=head2 C<is_level> |
|
203 |
+=head2 is_level |
|
205 | 204 |
|
206 | 205 |
my $success = $log->is_level('debug'); |
207 | 206 |
|
208 | 207 |
Check log level. |
209 | 208 |
|
210 |
-=head2 C<is_debug> |
|
209 |
+=head2 is_debug |
|
211 | 210 |
|
212 | 211 |
my $success = $log->is_debug; |
213 | 212 |
|
214 | 213 |
Check for debug log level. |
215 | 214 |
|
216 |
-=head2 C<is_error> |
|
215 |
+=head2 is_error |
|
217 | 216 |
|
218 | 217 |
my $success = $log->is_error; |
219 | 218 |
|
220 | 219 |
Check for error log level. |
221 | 220 |
|
222 |
-=head2 C<is_fatal> |
|
221 |
+=head2 is_fatal |
|
223 | 222 |
|
224 | 223 |
my $success = $log->is_fatal; |
225 | 224 |
|
226 | 225 |
Check for fatal log level. |
227 | 226 |
|
228 |
-=head2 C<is_info> |
|
227 |
+=head2 is_info |
|
229 | 228 |
|
230 | 229 |
my $success = $log->is_info; |
231 | 230 |
|
232 | 231 |
Check for info log level. |
233 | 232 |
|
234 |
-=head2 C<is_warn> |
|
233 |
+=head2 is_warn |
|
235 | 234 |
|
236 | 235 |
my $success = $log->is_warn; |
237 | 236 |
|
238 | 237 |
Check for warn log level. |
239 | 238 |
|
240 |
-=head2 C<log> |
|
239 |
+=head2 log |
|
241 | 240 |
|
242 | 241 |
$log = $log->log(debug => 'This should work'); |
243 | 242 |
|
244 | 243 |
Emit C<message> event. |
245 | 244 |
|
246 |
-=head2 C<warn> |
|
245 |
+=head2 warn |
|
247 | 246 |
|
248 | 247 |
$log = $log->warn('Dont do that Dave...'); |
249 | 248 |
|
... | ... |
@@ -43,10 +43,7 @@ sub body { |
43 | 43 |
sub body_params { |
44 | 44 |
my $self = shift; |
45 | 45 |
|
46 |
- # Cached |
|
47 | 46 |
return $self->{body_params} if $self->{body_params}; |
48 |
- |
|
49 |
- # Charset |
|
50 | 47 |
my $params = $self->{body_params} = Mojo::Parameters->new; |
51 | 48 |
$params->charset($self->content->charset || $self->default_charset); |
52 | 49 |
|
... | ... |
@@ -59,15 +56,9 @@ sub body_params { |
59 | 56 |
# "multipart/formdata" |
60 | 57 |
elsif ($type =~ m!multipart/form-data!i) { |
61 | 58 |
my $formdata = $self->_parse_formdata; |
62 |
- |
|
63 |
- # Formdata |
|
64 | 59 |
for my $data (@$formdata) { |
65 | 60 |
my ($name, $filename, $value) = @$data; |
66 |
- |
|
67 |
- # File |
|
68 | 61 |
next if defined $filename; |
69 |
- |
|
70 |
- # Form value |
|
71 | 62 |
$params->append($name, $value); |
72 | 63 |
} |
73 | 64 |
} |
... | ... |
@@ -143,14 +134,9 @@ sub fix_headers { |
143 | 134 |
sub get_body_chunk { |
144 | 135 |
my ($self, $offset) = @_; |
145 | 136 |
|
146 |
- # Progress |
|
147 | 137 |
$self->emit('progress', 'body', $offset); |
148 |
- |
|
149 |
- # Chunk |
|
150 | 138 |
my $chunk = $self->content->get_body_chunk($offset); |
151 | 139 |
return $chunk if !defined $chunk || length $chunk; |
152 |
- |
|
153 |
- # Finish |
|
154 | 140 |
$self->finish; |
155 | 141 |
|
156 | 142 |
return $chunk; |
... | ... |
@@ -197,9 +183,10 @@ sub param { shift->body_params->param(@_) } |
197 | 183 |
sub parse { |
198 | 184 |
my ($self, $chunk) = @_; |
199 | 185 |
|
200 |
- # Check message size and add chunk |
|
186 |
+ # Check message size |
|
201 | 187 |
return $self->error('Maximum message size exceeded', 413) |
202 | 188 |
if ($self->{raw_size} += length($chunk = defined $chunk ? $chunk : '')) > $self->max_message_size; |
189 |
+ |
|
203 | 190 |
$self->{buffer} .= $chunk; |
204 | 191 |
|
205 | 192 |
# Start line |
... | ... |
@@ -211,7 +198,6 @@ sub parse { |
211 | 198 |
return $self->error('Maximum line size exceeded', 431) |
212 | 199 |
if $len > $self->max_line_size; |
213 | 200 |
|
214 |
- # Extract |
|
215 | 201 |
$self->{state} = 'content' if $self->extract_start_line(\$self->{buffer}); |
216 | 202 |
} |
217 | 203 |
|
... | ... |
@@ -227,7 +213,6 @@ sub parse { |
227 | 213 |
return $self->error('Maximum buffer size exceeded', 400) |
228 | 214 |
if $self->content->is_limit_exceeded; |
229 | 215 |
|
230 |
- # Progress |
|
231 | 216 |
return $self->emit('progress')->content->is_finished ? $self->finish : $self; |
232 | 217 |
} |
233 | 218 |
|
... | ... |
@@ -249,11 +234,7 @@ sub upload { |
249 | 234 |
sub uploads { |
250 | 235 |
my $self = shift; |
251 | 236 |
|
252 |
- # Only multipart messages have uploads |
|
253 | 237 |
my @uploads; |
254 |
- return \@uploads unless $self->is_multipart; |
|
255 |
- |
|
256 |
- # Extract formdata |
|
257 | 238 |
my $formdata = $self->_parse_formdata; |
258 | 239 |
for my $data (@$formdata) { |
259 | 240 |
my ($name, $filename, $part) = @$data; |
... | ... |
@@ -280,7 +261,6 @@ sub write_chunk { shift->_write(write_chunk => @_) } |
280 | 261 |
sub _build { |
281 | 262 |
my ($self, $method) = @_; |
282 | 263 |
|
283 |
- # Build part from chunks |
|
284 | 264 |
my $buffer = ''; |
285 | 265 |
my $offset = 0; |
286 | 266 |
while (1) { |
... | ... |
@@ -291,7 +271,6 @@ sub _build { |
291 | 271 |
# End of part |
292 | 272 |
last unless my $len = length $chunk; |
293 | 273 |
|
294 |
- # Part |
|
295 | 274 |
$offset += $len; |
296 | 275 |
$buffer .= $chunk; |
297 | 276 |
} |
... | ... |
@@ -323,37 +302,35 @@ sub _nest { |
323 | 302 |
sub _parse_formdata { |
324 | 303 |
my $self = shift; |
325 | 304 |
|
326 |
- # Check content |
|
305 |
+ # Check for multipart content |
|
327 | 306 |
my @formdata; |
328 | 307 |
my $content = $self->content; |
329 | 308 |
return \@formdata unless $content->is_multipart; |
330 | 309 |
my $charset = $content->charset || $self->default_charset; |
331 | 310 |
|
332 |
- # Walk the tree |
|
311 |
+ # Check all parts for form data |
|
333 | 312 |
my @parts; |
334 | 313 |
push @parts, $content; |
335 | 314 |
while (my $part = shift @parts) { |
336 | 315 |
|
337 |
- # Multipart |
|
316 |
+ # Nested multipart content |
|
338 | 317 |
if ($part->is_multipart) { |
339 | 318 |
unshift @parts, @{$part->parts}; |
340 | 319 |
next; |
341 | 320 |
} |
342 | 321 |
|
343 |
- # Content-Disposition header |
|
322 |
+ # Extract information from Content-Disposition header |
|
344 | 323 |
my $disposition = $part->headers->content_disposition; |
345 | 324 |
next unless $disposition; |
346 | 325 |
my ($name) = $disposition =~ /[; ]name="?([^";]+)"?/; |
347 | 326 |
my ($filename) = $disposition =~ /[; ]filename="?([^"]*)"?/; |
348 |
- my $value = $part; |
|
349 |
- |
|
350 |
- # Decode |
|
351 | 327 |
if ($charset) { |
352 | 328 |
$name = do {my $tmp = decode($charset, $name); defined $tmp ? $tmp : $name} if $name; |
353 | 329 |
$filename = do {my $tmp = decode($charset, $filename); defined $tmp ? $tmp : $filename} if $filename; |
354 | 330 |
} |
355 | 331 |
|
356 |
- # Form value |
|
332 |
+ # Check for file upload |
|
333 |
+ my $value = $part; |
|
357 | 334 |
unless (defined $filename) { |
358 | 335 |
$value = $part->asset->slurp; |
359 | 336 |
$value = do {my $tmp = decode($charset, $value); defined $tmp ? $tmp : $value} if $charset; |
... | ... |
@@ -394,9 +371,10 @@ RFC 2616 and RFC 2388. |
394 | 371 |
|
395 | 372 |
=head1 EVENTS |
396 | 373 |
|
397 |
-L<Mojo::Message> can emit the following events. |
|
374 |
+L<Mojo::Message> inherits all events from L<Mojo::EventEmitter> and can emit |
|
375 |
+the following new ones. |
|
398 | 376 |
|
399 |
-=head2 C<finish> |
|
377 |
+=head2 finish |
|
400 | 378 |
|
401 | 379 |
$msg->on(finish => sub { |
402 | 380 |
my $msg = shift; |
... | ... |
@@ -411,7 +389,7 @@ Emitted after message building or parsing is finished. |
411 | 389 |
$msg->headers->header('X-Parser-Time' => time - $before); |
412 | 390 |
}); |
413 | 391 |
|
414 |
-=head2 C<progress> |
|
392 |
+=head2 progress |
|
415 | 393 |
|
416 | 394 |
$msg->on(progress => sub { |
417 | 395 |
my $msg = shift; |
... | ... |
@@ -438,21 +416,21 @@ Emitted when message building or parsing makes progress. |
438 | 416 |
|
439 | 417 |
L<Mojo::Message> implements the following attributes. |
440 | 418 |
|
441 |
-=head2 C<content> |
|
419 |
+=head2 content |
|
442 | 420 |
|
443 | 421 |
my $msg = $msg->content; |
444 | 422 |
$msg = $msg->content(Mojo::Content::Single->new); |
445 | 423 |
|
446 | 424 |
Message content, defaults to a L<Mojo::Content::Single> object. |
447 | 425 |
|
448 |
-=head2 C<default_charset> |
|
426 |
+=head2 default_charset |
|
449 | 427 |
|
450 | 428 |
my $charset = $msg->default_charset; |
451 | 429 |
$msg = $msg->default_charset('UTF-8'); |
452 | 430 |
|
453 | 431 |
Default charset used for form data parsing, defaults to C<UTF-8>. |
454 | 432 |
|
455 |
-=head2 C<max_line_size> |
|
433 |
+=head2 max_line_size |
|
456 | 434 |
|
457 | 435 |
my $size = $msg->max_line_size; |
458 | 436 |
$msg = $msg->max_line_size(1024); |
... | ... |
@@ -460,7 +438,7 @@ Default charset used for form data parsing, defaults to C<UTF-8>. |
460 | 438 |
Maximum start line size in bytes, defaults to the value of the |
461 | 439 |
C<MOJO_MAX_LINE_SIZE> environment variable or C<10240>. |
462 | 440 |
|
463 |
-=head2 C<max_message_size> |
|
441 |
+=head2 max_message_size |
|
464 | 442 |
|
465 | 443 |
my $size = $msg->max_message_size; |
466 | 444 |
$msg = $msg->max_message_size(1024); |
... | ... |
@@ -471,7 +449,7 @@ increasing this value can also drastically increase memory usage, should you |
471 | 449 |
for example attempt to parse an excessively large message body with the |
472 | 450 |
C<body_params>, C<dom> or C<json> methods. |
473 | 451 |
|
474 |
-=head2 C<version> |
|
452 |
+=head2 version |
|
475 | 453 |
|
476 | 454 |
my $version = $msg->version; |
477 | 455 |
$msg = $msg->version('1.1'); |
... | ... |
@@ -483,20 +461,20 @@ HTTP version of message, defaults to C<1.1>. |
483 | 461 |
L<Mojo::Message> inherits all methods from L<Mojo::EventEmitter> and |
484 | 462 |
implements the following new ones. |
485 | 463 |
|
486 |
-=head2 C<body> |
|
464 |
+=head2 body |
|
487 | 465 |
|
488 |
- my $string = $msg->body; |
|
489 |
- $msg = $msg->body('Hello!'); |
|
490 |
- my $cb = $msg->body(sub {...}); |
|
466 |
+ my $bytes = $msg->body; |
|
467 |
+ $msg = $msg->body('Hello!'); |
|
468 |
+ my $cb = $msg->body(sub {...}); |
|
491 | 469 |
|
492 | 470 |
Access C<content> data or replace all subscribers of the C<read> event. |
493 | 471 |
|
494 | 472 |
$msg->body(sub { |
495 |
- my ($msg, $chunk) = @_; |
|
496 |
- say "Streaming: $chunk"; |
|
473 |
+ my ($msg, $bytes) = @_; |
|
474 |
+ say "Streaming: $bytes"; |
|
497 | 475 |
}); |
498 | 476 |
|
499 |
-=head2 C<body_params> |
|
477 |
+=head2 body_params |
|
500 | 478 |
|
501 | 479 |
my $params = $msg->body_params; |
502 | 480 |
|
... | ... |
@@ -508,31 +486,31 @@ so it should not be called before the entire message body has been received. |
508 | 486 |
# Get POST parameter value |
509 | 487 |
say $msg->body_params->param('foo'); |
510 | 488 |
|
511 |
-=head2 C<body_size> |
|
489 |
+=head2 body_size |
|
512 | 490 |
|
513 | 491 |
my $size = $msg->body_size; |
514 | 492 |
|
515 | 493 |
Content size in bytes. |
516 | 494 |
|
517 |
-=head2 C<build_body> |
|
495 |
+=head2 build_body |
|
518 | 496 |
|
519 |
- my $string = $msg->build_body; |
|
497 |
+ my $bytes = $msg->build_body; |
|
520 | 498 |
|
521 | 499 |
Render whole body. |
522 | 500 |
|
523 |
-=head2 C<build_headers> |
|
501 |
+=head2 build_headers |
|
524 | 502 |
|
525 |
- my $string = $msg->build_headers; |
|
503 |
+ my $bytes = $msg->build_headers; |
|
526 | 504 |
|
527 | 505 |
Render all headers. |
528 | 506 |
|
529 |
-=head2 C<build_start_line> |
|
507 |
+=head2 build_start_line |
|
530 | 508 |
|
531 |
- my $string = $msg->build_start_line; |
|
509 |
+ my $bytes = $msg->build_start_line; |
|
532 | 510 |
|
533 | 511 |
Render start line. |
534 | 512 |
|
535 |
-=head2 C<cookie> |
|
513 |
+=head2 cookie |
|
536 | 514 |
|
537 | 515 |
my $cookie = $msg->cookie('foo'); |
538 | 516 |
my @cookies = $msg->cookie('foo'); |
... | ... |
@@ -544,13 +522,13 @@ it should not be called before all headers have been received. |
544 | 522 |
# Get cookie value |
545 | 523 |
say $msg->cookie('foo')->value; |
546 | 524 |
|
547 |
-=head2 C<cookies> |
|
525 |
+=head2 cookies |
|
548 | 526 |
|
549 | 527 |
my $cookies = $msg->cookies; |
550 | 528 |
|
551 | 529 |
Access message cookies. Meant to be overloaded in a subclass. |
552 | 530 |
|
553 |
-=head2 C<dom> |
|
531 |
+=head2 dom |
|
554 | 532 |
|
555 | 533 |
my $dom = $msg->dom; |
556 | 534 |
my $collection = $msg->dom('a[href]'); |
... | ... |
@@ -567,7 +545,7 @@ before the entire message body has been received. |
567 | 545 |
say $msg->dom->at('title')->text; |
568 | 546 |
say $msg->dom->html->body->children->pluck('type')->uniq; |
569 | 547 |
|
570 |
-=head2 C<error> |
|
548 |
+=head2 error |
|
571 | 549 |
|
572 | 550 |
my $err = $msg->error; |
573 | 551 |
my ($err, $code) = $msg->error; |
... | ... |
@@ -576,93 +554,93 @@ before the entire message body has been received. |
576 | 554 |
|
577 | 555 |
Error and code. |
578 | 556 |
|
579 |
-=head2 C<extract_start_line> |
|
557 |
+=head2 extract_start_line |
|
580 | 558 |
|
581 | 559 |
my $success = $msg->extract_start_line(\$string); |
582 | 560 |
|
583 | 561 |
Extract start line from string. Meant to be overloaded in a subclass. |
584 | 562 |
|
585 |
-=head2 C<finish> |
|
563 |
+=head2 finish |
|
586 | 564 |
|
587 | 565 |
$msg = $msg->finish; |
588 | 566 |
|
589 | 567 |
Finish message parser/generator. |
590 | 568 |
|
591 |
-=head2 C<fix_headers> |
|
569 |
+=head2 fix_headers |
|
592 | 570 |
|
593 | 571 |
$msg = $msg->fix_headers; |
594 | 572 |
|
595 | 573 |
Make sure message has all required headers. |
596 | 574 |
|
597 |
-=head2 C<get_body_chunk> |
|
575 |
+=head2 get_body_chunk |
|
598 | 576 |
|
599 |
- my $string = $msg->get_body_chunk($offset); |
|
577 |
+ my $bytes = $msg->get_body_chunk($offset); |
|
600 | 578 |
|
601 | 579 |
Get a chunk of body data starting from a specific position. |
602 | 580 |
|
603 |
-=head2 C<get_header_chunk> |
|
581 |
+=head2 get_header_chunk |
|
604 | 582 |
|
605 |
- my $string = $msg->get_header_chunk($offset); |
|
583 |
+ my $bytes = $msg->get_header_chunk($offset); |
|
606 | 584 |
|
607 | 585 |
Get a chunk of header data, starting from a specific position. |
608 | 586 |
|
609 |
-=head2 C<get_start_line_chunk> |
|
587 |
+=head2 get_start_line_chunk |
|
610 | 588 |
|
611 |
- my $string = $msg->get_start_line_chunk($offset); |
|
589 |
+ my $bytes = $msg->get_start_line_chunk($offset); |
|
612 | 590 |
|
613 | 591 |
Get a chunk of start line data starting from a specific position. Meant to be |
614 | 592 |
overloaded in a subclass. |
615 | 593 |
|
616 |
-=head2 C<has_leftovers> |
|
594 |
+=head2 has_leftovers |
|
617 | 595 |
|
618 | 596 |
my $success = $msg->has_leftovers; |
619 | 597 |
|
620 | 598 |
Check if there are leftovers. |
621 | 599 |
|
622 |
-=head2 C<header_size> |
|
600 |
+=head2 header_size |
|
623 | 601 |
|
624 | 602 |
my $size = $msg->header_size; |
625 | 603 |
|
626 | 604 |
Size of headers in bytes. |
627 | 605 |
|
628 |
-=head2 C<headers> |
|
606 |
+=head2 headers |
|
629 | 607 |
|
630 | 608 |
my $headers = $msg->headers; |
631 | 609 |
|
632 | 610 |
Message headers, usually a L<Mojo::Headers> object. |
633 | 611 |
|
634 |
-=head2 C<is_chunked> |
|
612 |
+=head2 is_chunked |
|
635 | 613 |
|
636 | 614 |
my $success = $msg->is_chunked; |
637 | 615 |
|
638 | 616 |
Check if content is chunked. |
639 | 617 |
|
640 |
-=head2 C<is_dynamic> |
|
618 |
+=head2 is_dynamic |
|
641 | 619 |
|
642 | 620 |
my $success = $msg->is_dynamic; |
643 | 621 |
|
644 | 622 |
Check if content will be dynamically generated, which prevents C<clone> from |
645 | 623 |
working. |
646 | 624 |
|
647 |
-=head2 C<is_finished> |
|
625 |
+=head2 is_finished |
|
648 | 626 |
|
649 | 627 |
my $success = $msg->is_finished; |
650 | 628 |
|
651 | 629 |
Check if message parser/generator is finished. |
652 | 630 |
|
653 |
-=head2 C<is_limit_exceeded> |
|
631 |
+=head2 is_limit_exceeded |
|
654 | 632 |
|
655 | 633 |
my $success = $msg->is_limit_exceeded; |
656 | 634 |
|
657 | 635 |
Check if message has exceeded C<max_line_size> or C<max_message_size>. |
658 | 636 |
|
659 |
-=head2 C<is_multipart> |
|
637 |
+=head2 is_multipart |
|
660 | 638 |
|
661 | 639 |
my $success = $msg->is_multipart; |
662 | 640 |
|
663 | 641 |
Check if content is a L<Mojo::Content::MultiPart> object. |
664 | 642 |
|
665 |
-=head2 C<json> |
|
643 |
+=head2 json |
|
666 | 644 |
|
667 | 645 |
my $hash = $msg->json; |
668 | 646 |
my $array = $msg->json; |
... | ... |
@@ -677,13 +655,13 @@ it should not be called before the entire message body has been received. |
677 | 655 |
say $msg->json->{foo}{bar}[23]; |
678 | 656 |
say $msg->json('/foo/bar/23'); |
679 | 657 |
|
680 |
-=head2 C<leftovers> |
|
658 |
+=head2 leftovers |
|
681 | 659 |
|
682 | 660 |
my $bytes = $msg->leftovers; |
683 | 661 |
|
684 | 662 |
Get leftover data from content parser. |
685 | 663 |
|
686 |
-=head2 C<param> |
|
664 |
+=head2 param |
|
687 | 665 |
|
688 | 666 |
my @names = $msg->param; |
689 | 667 |
my $foo = $msg->param('foo'); |
... | ... |
@@ -692,25 +670,25 @@ Get leftover data from content parser. |
692 | 670 |
Access C<POST> parameters. Note that this method caches all data, so it should |
693 | 671 |
not be called before the entire message body has been received. |
694 | 672 |
|
695 |
-=head2 C<parse> |
|
673 |
+=head2 parse |
|
696 | 674 |
|
697 | 675 |
$msg = $msg->parse('HTTP/1.1 200 OK...'); |
698 | 676 |
|
699 | 677 |
Parse message chunk. |
700 | 678 |
|
701 |
-=head2 C<start_line_size> |
|
679 |
+=head2 start_line_size |
|
702 | 680 |
|
703 | 681 |
my $size = $msg->start_line_size; |
704 | 682 |
|
705 | 683 |
Size of the start line in bytes. |
706 | 684 |
|
707 |
-=head2 C<to_string> |
|
685 |
+=head2 to_string |
|
708 | 686 |
|
709 | 687 |
my $string = $msg->to_string; |
710 | 688 |
|
711 | 689 |
Render whole message. |
712 | 690 |
|
713 |
-=head2 C<upload> |
|
691 |
+=head2 upload |
|
714 | 692 |
|
715 | 693 |
my $upload = $msg->upload('foo'); |
716 | 694 |
my @uploads = $msg->upload('foo'); |
... | ... |
@@ -722,24 +700,24 @@ entire message body has been received. |
722 | 700 |
# Get content of uploaded file |
723 | 701 |
say $msg->upload('foo')->asset->slurp; |
724 | 702 |
|
725 |
-=head2 C<uploads> |
|
703 |
+=head2 uploads |
|
726 | 704 |
|
727 | 705 |
my $uploads = $msg->uploads; |
728 | 706 |
|
729 | 707 |
All C<multipart/form-data> file uploads, usually L<Mojo::Upload> objects. |
730 | 708 |
|
731 |
-=head2 C<write> |
|
709 |
+=head2 write |
|
732 | 710 |
|
733 |
- $msg = $msg->write('Hello!'); |
|
734 |
- $msg = $msg->write('Hello!' => sub {...}); |
|
711 |
+ $msg = $msg->write($bytes); |
|
712 |
+ $msg = $msg->write($bytes => sub {...}); |
|
735 | 713 |
|
736 | 714 |
Write dynamic content non-blocking, the optional drain callback will be |
737 | 715 |
invoked once all data has been written. |
738 | 716 |
|
739 |
-=head2 C<write_chunk> |
|
717 |
+=head2 write_chunk |
|
740 | 718 |
|
741 |
- $msg = $msg->write_chunk('Hello!'); |
|
742 |
- $msg = $msg->write_chunk('Hello!' => sub {...}); |
|
719 |
+ $msg = $msg->write_chunk($bytes); |
|
720 |
+ $msg = $msg->write_chunk($bytes => sub {...}); |
|
743 | 721 |
|
744 | 722 |
Write dynamic content non-blocking with C<chunked> transfer encoding, the |
745 | 723 |
optional drain callback will be invoked once all data has been written. |
... | ... |
@@ -55,11 +55,11 @@ sub cookies { |
55 | 55 |
} |
56 | 56 |
|
57 | 57 |
sub extract_start_line { |
58 |
- my ($self, $bufferref) = @_; |
|
58 |
+ my ($self, $bufref) = @_; |
|
59 | 59 |
|
60 | 60 |
# Ignore any leading empty lines |
61 |
- $$bufferref =~ s/^\s+//; |
|
62 |
- return undef unless defined(my $line = get_line $bufferref); |
|
61 |
+ $$bufref =~ s/^\s+//; |
|
62 |
+ return undef unless defined(my $line = get_line $bufref); |
|
63 | 63 |
|
64 | 64 |
# We have a (hopefully) full request line |
65 | 65 |
$self->error('Bad request start line', 400) and return undef |
... | ... |
@@ -100,7 +100,6 @@ sub fix_headers { |
100 | 100 |
sub get_start_line_chunk { |
101 | 101 |
my ($self, $offset) = @_; |
102 | 102 |
|
103 |
- # Request line |
|
104 | 103 |
unless (defined $self->{start_buffer}) { |
105 | 104 |
|
106 | 105 |
# Path |
... | ... |
@@ -128,10 +127,7 @@ sub get_start_line_chunk { |
128 | 127 |
$self->{start_buffer} = "$method $path HTTP/@{[$self->version]}\x0d\x0a"; |
129 | 128 |
} |
130 | 129 |
|
131 |
- # Progress |
|
132 | 130 |
$self->emit(progress => 'start_line', $offset); |
133 |
- |
|
134 |
- # Chunk |
|
135 | 131 |
return substr $self->{start_buffer}, $offset, 131072; |
136 | 132 |
} |
137 | 133 |
|
... | ... |
@@ -306,7 +302,7 @@ L<Mojo::Message::Request> inherits all events from L<Mojo::Message>. |
306 | 302 |
L<Mojo::Message::Request> inherits all attributes from L<Mojo::Message> and |
307 | 303 |
implements the following new ones. |
308 | 304 |
|
309 |
-=head2 C<env> |
|
305 |
+=head2 env |
|
310 | 306 |
|
311 | 307 |
my $env = $req->env; |
312 | 308 |
$req = $req->env({}); |
... | ... |
@@ -319,14 +315,14 @@ Direct access to the C<CGI> or C<PSGI> environment hash if available. |
319 | 315 |
# Check PSGI version |
320 | 316 |
my $version = $req->env->{'psgi.version'}; |
321 | 317 |
|
322 |
-=head2 C<method> |
|
318 |
+=head2 method |
|
323 | 319 |
|
324 | 320 |
my $method = $req->method; |
325 | 321 |
$req = $req->method('POST'); |
326 | 322 |
|
327 | 323 |
HTTP request method, defaults to C<GET>. |
328 | 324 |
|
329 |
-=head2 C<url> |
|
325 |
+=head2 url |
|
330 | 326 |
|
331 | 327 |
my $url = $req->url; |
332 | 328 |
$req = $req->url(Mojo::URL->new); |
... | ... |
@@ -341,13 +337,13 @@ HTTP request URL, defaults to a L<Mojo::URL> object. |
341 | 337 |
L<Mojo::Message::Request> inherits all methods from L<Mojo::Message> and |
342 | 338 |
implements the following new ones. |
343 | 339 |
|
344 |
-=head2 C<clone> |
|
340 |
+=head2 clone |
|
345 | 341 |
|
346 | 342 |
my $clone = $req->clone; |
347 | 343 |
|
348 | 344 |
Clone request if possible, otherwise return C<undef>. |
349 | 345 |
|
350 |
-=head2 C<cookies> |
|
346 |
+=head2 cookies |
|
351 | 347 |
|
352 | 348 |
my $cookies = $req->cookies; |
353 | 349 |
$req = $req->cookies(Mojo::Cookie::Request->new); |
... | ... |
@@ -355,37 +351,37 @@ Clone request if possible, otherwise return C<undef>. |
355 | 351 |
|
356 | 352 |
Access request cookies, usually L<Mojo::Cookie::Request> objects. |
357 | 353 |
|
358 |
-=head2 C<extract_start_line> |
|
354 |
+=head2 extract_start_line |
|
359 | 355 |
|
360 | 356 |
my $success = $req->extract_start_line(\$string); |
361 | 357 |
|
362 | 358 |
Extract request line from string. |
363 | 359 |
|
364 |
-=head2 C<fix_headers> |
|
360 |
+=head2 fix_headers |
|
365 | 361 |
|
366 | 362 |
$req = $req->fix_headers; |
367 | 363 |
|
368 | 364 |
Make sure request has all required headers. |
369 | 365 |
|
370 |
-=head2 C<get_start_line_chunk> |
|
366 |
+=head2 get_start_line_chunk |
|
371 | 367 |
|
372 |
- my $string = $req->get_start_line_chunk($offset); |
|
368 |
+ my $bytes = $req->get_start_line_chunk($offset); |
|
373 | 369 |
|
374 | 370 |
Get a chunk of request line data starting from a specific position. |
375 | 371 |
|
376 |
-=head2 C<is_secure> |
|
372 |
+=head2 is_secure |
|
377 | 373 |
|
378 | 374 |
my $success = $req->is_secure; |
379 | 375 |
|
380 | 376 |
Check if connection is secure. |
381 | 377 |
|
382 |
-=head2 C<is_xhr> |
|
378 |
+=head2 is_xhr |
|
383 | 379 |
|
384 | 380 |
my $success = $req->is_xhr; |
385 | 381 |
|
386 | 382 |
Check C<X-Requested-With> header for C<XMLHttpRequest> value. |
387 | 383 |
|
388 |
-=head2 C<param> |
|
384 |
+=head2 param |
|
389 | 385 |
|
390 | 386 |
my @names = $req->param; |
391 | 387 |
my $foo = $req->param('foo'); |
... | ... |
@@ -394,7 +390,7 @@ Check C<X-Requested-With> header for C<XMLHttpRequest> value. |
394 | 390 |
Access C<GET> and C<POST> parameters. Note that this method caches all data, |
395 | 391 |
so it should not be called before the entire request body has been received. |
396 | 392 |
|
397 |
-=head2 C<params> |
|
393 |
+=head2 params |
|
398 | 394 |
|
399 | 395 |
my $params = $req->params; |
400 | 396 |
|
... | ... |
@@ -405,7 +401,7 @@ request body has been received. |
405 | 401 |
# Get parameter value |
406 | 402 |
say $req->params->param('foo'); |
407 | 403 |
|
408 |
-=head2 C<parse> |
|
404 |
+=head2 parse |
|
409 | 405 |
|
410 | 406 |
$req = $req->parse('GET /foo/bar HTTP/1.1'); |
411 | 407 |
$req = $req->parse(REQUEST_METHOD => 'GET'); |
... | ... |
@@ -413,7 +409,7 @@ request body has been received. |
413 | 409 |
|
414 | 410 |
Parse HTTP request chunks or environment hash. |
415 | 411 |
|
416 |
-=head2 C<proxy> |
|
412 |
+=head2 proxy |
|
417 | 413 |
|
418 | 414 |
my $proxy = $req->proxy; |
419 | 415 |
$req = $req->proxy('http://foo:bar@127.0.0.1:3000'); |
... | ... |
@@ -424,7 +420,7 @@ Proxy URL for request. |
424 | 420 |
# Disable proxy |
425 | 421 |
$req->proxy(0); |
426 | 422 |
|
427 |
-=head2 C<query_params> |
|
423 |
+=head2 query_params |
|
428 | 424 |
|
429 | 425 |
my $params = $req->query_params; |
430 | 426 |
|
... | ... |
@@ -92,10 +92,10 @@ sub cookies { |
92 | 92 |
sub default_message { $MESSAGES{$_[1] || $_[0]->code || 404} || '' } |
93 | 93 |
|
94 | 94 |
sub extract_start_line { |
95 |
- my ($self, $bufferref) = @_; |
|
95 |
+ my ($self, $bufref) = @_; |
|
96 | 96 |
|
97 | 97 |
# We have a full response line |
98 |
- return undef unless defined(my $line = get_line $bufferref); |
|
98 |
+ return undef unless defined(my $line = get_line $bufref); |
|
99 | 99 |
$self->error('Bad response start line') and return undef |
100 | 100 |
unless $line =~ m!^\s*HTTP/(\d\.\d)\s+(\d\d\d)\s*(.+)?$!; |
101 | 101 |
$self->content->skip_body(1) if $self->code($2)->is_empty; |
... | ... |
@@ -116,17 +116,13 @@ sub fix_headers { |
116 | 116 |
sub get_start_line_chunk { |
117 | 117 |
my ($self, $offset) = @_; |
118 | 118 |
|
119 |
- # Status line |
|
120 | 119 |
unless (defined $self->{start_buffer}) { |
121 | 120 |
my $code = $self->code || 404; |
122 | 121 |
my $msg = $self->message || $self->default_message; |
123 | 122 |
$self->{start_buffer} = "HTTP/@{[$self->version]} $code $msg\x0d\x0a"; |
124 | 123 |
} |
125 | 124 |
|
126 |
- # Progress |
|
127 | 125 |
$self->emit(progress => 'start_line', $offset); |
128 |
- |
|
129 |
- # Chunk |
|
130 | 126 |
return substr $self->{start_buffer}, $offset, 131072; |
131 | 127 |
} |
132 | 128 |
|
... | ... |
@@ -183,14 +179,14 @@ L<Mojo::Message::Response> inherits all events from L<Mojo::Message>. |
183 | 179 |
L<Mojo::Message::Response> inherits all attributes from L<Mojo::Message> and |
184 | 180 |
implements the following new ones. |
185 | 181 |
|
186 |
-=head2 C<code> |
|
182 |
+=head2 code |
|
187 | 183 |
|
188 | 184 |
my $code = $res->code; |
189 | 185 |
$res = $res->code(200); |
190 | 186 |
|
191 | 187 |
HTTP response code. |
192 | 188 |
|
193 |
-=head2 C<message> |
|
189 |
+=head2 message |
|
194 | 190 |
|
195 | 191 |
my $msg = $res->message; |
196 | 192 |
$res = $res->message('OK'); |
... | ... |
@@ -202,7 +198,7 @@ HTTP response message. |
202 | 198 |
L<Mojo::Message::Response> inherits all methods from L<Mojo::Message> and |
203 | 199 |
implements the following new ones. |
204 | 200 |
|
205 |
-=head2 C<cookies> |
|
201 |
+=head2 cookies |
|
206 | 202 |
|
207 | 203 |
my $cookies = $res->cookies; |
208 | 204 |
$res = $res->cookies(Mojo::Cookie::Response->new); |
... | ... |
@@ -210,37 +206,37 @@ implements the following new ones. |
210 | 206 |
|
211 | 207 |
Access response cookies, usually L<Mojo::Cookie::Response> objects. |
212 | 208 |
|
213 |
-=head2 C<default_message> |
|
209 |
+=head2 default_message |
|
214 | 210 |
|
215 | 211 |
my $msg = $res->default_message; |
216 | 212 |
|
217 | 213 |
Generate default response message for code. |
218 | 214 |
|
219 |
-=head2 C<extract_start_line> |
|
215 |
+=head2 extract_start_line |
|
220 | 216 |
|
221 | 217 |
my $success = $req->extract_start_line(\$string); |
222 | 218 |
|
223 | 219 |
Extract status line from string. |
224 | 220 |
|
225 |
-=head2 C<fix_headers> |
|
221 |
+=head2 fix_headers |
|
226 | 222 |
|
227 | 223 |
$res = $res->fix_headers; |
228 | 224 |
|
229 | 225 |
Make sure response has all required headers. |
230 | 226 |
|
231 |
-=head2 C<get_start_line_chunk> |
|
227 |
+=head2 get_start_line_chunk |
|
232 | 228 |
|
233 |
- my $string = $res->get_start_line_chunk($offset); |
|
229 |
+ my $bytes = $res->get_start_line_chunk($offset); |
|
234 | 230 |
|
235 | 231 |
Get a chunk of status line data starting from a specific position. |
236 | 232 |
|
237 |
-=head2 C<is_empty> |
|
233 |
+=head2 is_empty |
|
238 | 234 |
|
239 | 235 |
my $success = $res->is_empty; |
240 | 236 |
|
241 | 237 |
Check if this is a C<1xx>, C<204> or C<304> response. |
242 | 238 |
|
243 |
-=head2 C<is_status_class> |
|
239 |
+=head2 is_status_class |
|
244 | 240 |
|
245 | 241 |
my $success = $res->is_status_class(200); |
246 | 242 |
|
... | ... |
@@ -88,16 +88,12 @@ sub params { |
88 | 88 |
# W3C suggests to also accept ";" as a separator |
89 | 89 |
my $charset = $self->charset; |
90 | 90 |
for my $pair (split /[\&\;]+/, $string) { |
91 |
- |
|
92 |
- # Parse |
|
93 | 91 |
$pair =~ /^([^=]*)(?:=(.*))?$/; |
94 | 92 |
my $name = defined $1 ? $1 : ''; |
95 | 93 |
my $value = defined $2 ? $2 : ''; |
96 | 94 |
|
97 |
- # Replace "+" with whitespace |
|
95 |
+ # Replace "+" with whitespace, unescape and decode |
|
98 | 96 |
s/\+/ /g for $name, $value; |
99 |
- |
|
100 |
- # Unescape |
|
101 | 97 |
$name = url_unescape $name; |
102 | 98 |
$name = do { my $tmp = decode($charset, $name); defined $tmp ? $tmp : $name } if $charset; |
103 | 99 |
$value = url_unescape $value; |
... | ... |
@@ -126,7 +122,6 @@ sub remove { |
126 | 122 |
my $self = shift; |
127 | 123 |
my $name = do {my $tmp = shift; defined $tmp ? $tmp : ''}; |
128 | 124 |
|
129 |
- # Remove |
|
130 | 125 |
my $params = $self->params; |
131 | 126 |
for (my $i = 0; $i < @$params;) { |
132 | 127 |
if ($params->[$i] eq $name) { splice @$params, $i, 2 } |
... | ... |
@@ -139,7 +134,6 @@ sub remove { |
139 | 134 |
sub to_hash { |
140 | 135 |
my $self = shift; |
141 | 136 |
|
142 |
- # Format |
|
143 | 137 |
my $params = $self->params; |
144 | 138 |
my %hash; |
145 | 139 |
for (my $i = 0; $i < @$params; $i += 2) { |
... | ... |
@@ -188,7 +182,6 @@ sub to_string { |
188 | 182 |
push @pairs, defined $value ? "$name=$value" : $name; |
189 | 183 |
} |
190 | 184 |
|
191 |
- # Concatenate pairs |
|
192 | 185 |
return join $self->pair_separator, @pairs; |
193 | 186 |
} |
194 | 187 |
|
... | ... |
@@ -218,7 +211,7 @@ L<Mojo::Parameters> is a container for form parameters. |
218 | 211 |
|
219 | 212 |
L<Mojo::Parameters> implements the following attributes. |
220 | 213 |
|
221 |
-=head2 C<charset> |
|
214 |
+=head2 charset |
|
222 | 215 |
|
223 | 216 |
my $charset = $params->charset; |
224 | 217 |
$params = $params->charset('UTF-8'); |
... | ... |
@@ -228,7 +221,7 @@ Charset used for encoding and decoding parameters, defaults to C<UTF-8>. |
228 | 221 |
# Disable encoding and decoding |
229 | 222 |
$params->charset(undef); |
230 | 223 |
|
231 |
-=head2 C<pair_separator> |
|
224 |
+=head2 pair_separator |
|
232 | 225 |
|
233 | 226 |
my $separator = $params->pair_separator; |
234 | 227 |
$params = $params->pair_separator(';'); |
... | ... |
@@ -240,7 +233,7 @@ Separator for parameter pairs, defaults to C<&>. |
240 | 233 |
L<Mojo::Parameters> inherits all methods from L<Mojo::Base> and implements the |
241 | 234 |
following new ones. |
242 | 235 |
|
243 |
-=head2 C<new> |
|
236 |
+=head2 new |
|
244 | 237 |
|
245 | 238 |
my $params = Mojo::Parameters->new; |
246 | 239 |
my $params = Mojo::Parameters->new('foo=b%3Bar&baz=23'); |
... | ... |
@@ -250,7 +243,7 @@ following new ones. |
250 | 243 |
|
251 | 244 |
Construct a new L<Mojo::Parameters> object. |
252 | 245 |
|
253 |
-=head2 C<append> |
|
246 |
+=head2 append |
|
254 | 247 |
|
255 | 248 |
$params = $params->append(foo => 'ba;r'); |
256 | 249 |
$params = $params->append(foo => ['ba;r', 'b;az']); |
... | ... |
@@ -267,19 +260,19 @@ Append parameters. |
267 | 260 |
# "foo=bar&foo=baz&foo=yada&bar=23" |
268 | 261 |
Mojo::Parameters->new('foo=bar')->append(foo => ['baz', 'yada'], bar => 23); |
269 | 262 |
|
270 |
-=head2 C<clone> |
|
263 |
+=head2 clone |
|
271 | 264 |
|
272 | 265 |
my $params2 = $params->clone; |
273 | 266 |
|
274 | 267 |
Clone parameters. |
275 | 268 |
|
276 |
-=head2 C<merge> |
|
269 |
+=head2 merge |
|
277 | 270 |
|
278 | 271 |
$params = $params->merge(Mojo::Parameters->new(foo => 'b;ar', baz => 23)); |
279 | 272 |
|
280 | 273 |
Merge L<Mojo::Parameters> objects. |
281 | 274 |
|
282 |
-=head2 C<param> |
|
275 |
+=head2 param |
|
283 | 276 |
|
284 | 277 |
my @names = $params->param; |
285 | 278 |
my $foo = $params->param('foo'); |
... | ... |
@@ -289,20 +282,20 @@ Merge L<Mojo::Parameters> objects. |
289 | 282 |
|
290 | 283 |
Check and replace parameter values. |
291 | 284 |
|
292 |
-=head2 C<params> |
|
285 |
+=head2 params |
|
293 | 286 |
|
294 | 287 |
my $array = $params->params; |
295 | 288 |
$params = $params->params([foo => 'b;ar', baz => 23]); |
296 | 289 |
|
297 | 290 |
Parsed parameters. |
298 | 291 |
|
299 |
-=head2 C<parse> |
|
292 |
+=head2 parse |
|
300 | 293 |
|
301 | 294 |
$params = $params->parse('foo=b%3Bar&baz=23'); |
302 | 295 |
|
303 | 296 |
Parse parameters. |
304 | 297 |
|
305 |
-=head2 C<remove> |
|
298 |
+=head2 remove |
|
306 | 299 |
|
307 | 300 |
$params = $params->remove('foo'); |
308 | 301 |
|
... | ... |
@@ -311,7 +304,7 @@ Remove parameters. |
311 | 304 |
# "bar=yada" |
312 | 305 |
Mojo::Parameters->new('foo=bar&foo=baz&bar=yada')->remove('foo'); |
313 | 306 |
|
314 |
-=head2 C<to_hash> |
|
307 |
+=head2 to_hash |
|
315 | 308 |
|
316 | 309 |
my $hash = $params->to_hash; |
317 | 310 |
|
... | ... |
@@ -320,7 +313,7 @@ Turn parameters into a hash reference. |
320 | 313 |
# "baz" |
321 | 314 |
Mojo::Parameters->new('foo=bar&foo=baz')->to_hash->{foo}[1]; |
322 | 315 |
|
323 |
-=head2 C<to_string> |
|
316 |
+=head2 to_string |
|
324 | 317 |
|
325 | 318 |
my $string = $params->to_string; |
326 | 319 |
my $string = "$params"; |
... | ... |
@@ -16,7 +16,6 @@ sub new { shift->SUPER::new->parse(@_) } |
16 | 16 |
sub canonicalize { |
17 | 17 |
my $self = shift; |
18 | 18 |
|
19 |
- # Resolve path |
|
20 | 19 |
my @parts; |
21 | 20 |
for my $part (@{$self->parts}) { |
22 | 21 |
|
... | ... |
@@ -30,7 +29,6 @@ sub canonicalize { |
30 | 29 |
# "." |
31 | 30 |
next if grep { $_ eq $part } '.', ''; |
32 | 31 |
|
33 |
- # Part |
|
34 | 32 |
push @parts, $part; |
35 | 33 |
} |
36 | 34 |
$self->trailing_slash(undef) unless @parts; |
... | ... |
@@ -83,9 +81,17 @@ sub parse { |
83 | 81 |
return $self->parts([split '/', $path, -1]); |
84 | 82 |
} |
85 | 83 |
|
86 |
-sub to_abs_string { |
|
84 |
+sub to_abs_string { $_[0]->leading_slash ? "$_[0]" : "/$_[0]" } |
|
85 |
+ |
|
86 |
+sub to_dir { |
|
87 |
+ my $clone = shift->clone; |
|
88 |
+ pop @{$clone->parts} unless $clone->trailing_slash; |
|
89 |
+ return $clone->trailing_slash(@{$clone->parts} ? 1 : 0); |
|
90 |
+} |
|
91 |
+ |
|
92 |
+sub to_route { |
|
87 | 93 |
my $self = shift; |
88 |
- return $self->leading_slash ? "$self" : "/$self"; |
|
94 |
+ return '/' . join('/', @{$self->parts}) . ($self->trailing_slash ? '/' : ''); |
|
89 | 95 |
} |
90 | 96 |
|
91 | 97 |
sub to_string { |
... | ... |
@@ -104,6 +110,8 @@ sub to_string { |
104 | 110 |
|
105 | 111 |
1; |
106 | 112 |
|
113 |
+=encoding utf8 |
|
114 |
+ |
|
107 | 115 |
=head1 NAME |
108 | 116 |
|
109 | 117 |
Mojo::Path - Path |
... | ... |
@@ -124,7 +132,7 @@ L<Mojo::Path> is a container for URL paths. |
124 | 132 |
|
125 | 133 |
L<Mojo::Path> implements the following attributes. |
126 | 134 |
|
127 |
-=head2 C<charset> |
|
135 |
+=head2 charset |
|
128 | 136 |
|
129 | 137 |
my $charset = $path->charset; |
130 | 138 |
$path = $path->charset('UTF-8'); |
... | ... |
@@ -134,14 +142,14 @@ Charset used for encoding and decoding, defaults to C<UTF-8>. |
134 | 142 |
# Disable encoding and decoding |
135 | 143 |
$path->charset(undef); |
136 | 144 |
|
137 |
-=head2 C<leading_slash> |
|
145 |
+=head2 leading_slash |
|
138 | 146 |
|
139 | 147 |
my $leading_slash = $path->leading_slash; |
140 | 148 |
$path = $path->leading_slash(1); |
141 | 149 |
|
142 | 150 |
Path has a leading slash. |
143 | 151 |
|
144 |
-=head2 C<parts> |
|
152 |
+=head2 parts |
|
145 | 153 |
|
146 | 154 |
my $parts = $path->parts; |
147 | 155 |
$path = $path->parts([qw(foo bar baz)]); |
... | ... |
@@ -151,7 +159,7 @@ The path parts. |
151 | 159 |
# Part with slash |
152 | 160 |
push @{$path->parts}, 'foo/bar'; |
153 | 161 |
|
154 |
-=head2 C<trailing_slash> |
|
162 |
+=head2 trailing_slash |
|
155 | 163 |
|
156 | 164 |
my $trailing_slash = $path->trailing_slash; |
157 | 165 |
$path = $path->trailing_slash(1); |
... | ... |
@@ -163,14 +171,14 @@ Path has a trailing slash. |
163 | 171 |
L<Mojo::Path> inherits all methods from L<Mojo::Base> and implements the |
164 | 172 |
following new ones. |
165 | 173 |
|
166 |
-=head2 C<new> |
|
174 |
+=head2 new |
|
167 | 175 |
|
168 | 176 |
my $path = Mojo::Path->new; |
169 | 177 |
my $path = Mojo::Path->new('/foo%2Fbar%3B/baz.html'); |
170 | 178 |
|
171 | 179 |
Construct a new L<Mojo::Path> object. |
172 | 180 |
|
173 |
-=head2 C<canonicalize> |
|
181 |
+=head2 canonicalize |
|
174 | 182 |
|
175 | 183 |
$path = $path->canonicalize; |
176 | 184 |
|
... | ... |
@@ -179,15 +187,15 @@ Canonicalize path. |
179 | 187 |
# "/foo/baz" |
180 | 188 |
Mojo::Path->new('/foo/bar/../baz')->canonicalize; |
181 | 189 |
|
182 |
-=head2 C<clone> |
|
190 |
+=head2 clone |
|
183 | 191 |
|
184 | 192 |
my $clone = $path->clone; |
185 | 193 |
|
186 | 194 |
Clone path. |
187 | 195 |
|
188 |
-=head2 C<contains> |
|
196 |
+=head2 contains |
|
189 | 197 |
|
190 |
- my $success = $path->contains('/foo'); |
|
198 |
+ my $success = $path->contains('/i/♥/mojolicious'); |
|
191 | 199 |
|
192 | 200 |
Check if path contains given prefix. |
193 | 201 |
|
... | ... |
@@ -201,7 +209,7 @@ Check if path contains given prefix. |
201 | 209 |
Mojo::Path->new('/foo/bar')->contains('/bar'); |
202 | 210 |
Mojo::Path->new('/foo/bar')->contains('/whatever'); |
203 | 211 |
|
204 |
-=head2 C<merge> |
|
212 |
+=head2 merge |
|
205 | 213 |
|
206 | 214 |
$path = $path->merge('/foo/bar'); |
207 | 215 |
$path = $path->merge('foo/bar'); |
... | ... |
@@ -218,25 +226,49 @@ Merge paths. |
218 | 226 |
# "/foo/bar/baz/yada" |
219 | 227 |
Mojo::Path->new('/foo/bar/')->merge('baz/yada'); |
220 | 228 |
|
221 |
-=head2 C<parse> |
|
229 |
+=head2 parse |
|
222 | 230 |
|
223 | 231 |
$path = $path->parse('/foo%2Fbar%3B/baz.html'); |
224 | 232 |
|
225 | 233 |
Parse path. Note that C<%2F> will be treated as C</> for security reasons. |
226 | 234 |
|
227 |
-=head2 C<to_abs_string> |
|
235 |
+=head2 to_abs_string |
|
228 | 236 |
|
229 | 237 |
my $string = $path->to_abs_string; |
230 | 238 |
|
231 | 239 |
Turn path into an absolute string. |
232 | 240 |
|
233 |
-=head2 C<to_string> |
|
241 |
+ # "/i/%E2%99%A5/mojolicious" |
|
242 |
+ Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_abs_string; |
|
243 |
+ |
|
244 |
+=head2 to_dir |
|
245 |
+ |
|
246 |
+ my $dir = $route->to_dir; |
|
247 |
+ |
|
248 |
+Clone path and remove everything after the right-most slash. |
|
249 |
+ |
|
250 |
+ # "/i/%E2%99%A5/" |
|
251 |
+ Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_dir->to_abs_string; |
|
252 |
+ |
|
253 |
+=head2 to_route |
|
254 |
+ |
|
255 |
+ my $route = $path->to_route; |
|
256 |
+ |
|
257 |
+Turn path into a route. |
|
258 |
+ |
|
259 |
+ # "/i/♥/mojolicious" |
|
260 |
+ Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_route; |
|
261 |
+ |
|
262 |
+=head2 to_string |
|
234 | 263 |
|
235 | 264 |
my $string = $path->to_string; |
236 | 265 |
my $string = "$path"; |
237 | 266 |
|
238 | 267 |
Turn path into a string. |
239 | 268 |
|
269 |
+ # "i/%E2%99%A5/mojolicious" |
|
270 |
+ Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_string; |
|
271 |
+ |
|
240 | 272 |
=head1 SEE ALSO |
241 | 273 |
|
242 | 274 |
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>. |
... | ... |
@@ -62,9 +62,10 @@ L<Mojo::Reactor> is an abstract base class for low level event reactors. |
62 | 62 |
|
63 | 63 |
=head1 EVENTS |
64 | 64 |
|
65 |
-L<Mojo::Reactor> can emit the following events. |
|
65 |
+L<Mojo::Reactor> inherits all events from L<Mojo::EventEmitter> and can emit |
|
66 |
+the following new ones. |
|
66 | 67 |
|
67 |
-=head2 C<error> |
|
68 |
+=head2 error |
|
68 | 69 |
|
69 | 70 |
$reactor->on(error => sub { |
70 | 71 |
my ($reactor, $err) = @_; |
... | ... |
@@ -83,7 +84,7 @@ Emitted safely for exceptions caught in callbacks. |
83 | 84 |
L<Mojo::Reactor> inherits all methods from L<Mojo::EventEmitter> and |
84 | 85 |
implements the following new ones. |
85 | 86 |
|
86 |
-=head2 C<detect> |
|
87 |
+=head2 detect |
|
87 | 88 |
|
88 | 89 |
my $class = Mojo::Reactor->detect; |
89 | 90 |
|
... | ... |
@@ -94,7 +95,7 @@ L<Mojo::Reactor::Poll>. |
94 | 95 |
# Instantiate best reactor implementation available |
95 | 96 |
my $reactor = Mojo::Reactor->detect->new; |
96 | 97 |
|
97 |
-=head2 C<io> |
|
98 |
+=head2 io |
|
98 | 99 |
|
99 | 100 |
$reactor = $reactor->io($handle => sub {...}); |
100 | 101 |
|
... | ... |
@@ -107,20 +108,20 @@ readable or writable. Meant to be overloaded in a subclass. |
107 | 108 |
say $writable ? 'Handle is writable' : 'Handle is readable'; |
108 | 109 |
}); |
109 | 110 |
|
110 |
-=head2 C<is_readable> |
|
111 |
+=head2 is_readable |
|
111 | 112 |
|
112 | 113 |
my $success = $reactor->is_readable($handle); |
113 | 114 |
|
114 | 115 |
Quick non-blocking check if a handle is readable, useful for identifying |
115 | 116 |
tainted sockets. |
116 | 117 |
|
117 |
-=head2 C<is_running> |
|
118 |
+=head2 is_running |
|
118 | 119 |
|
119 | 120 |
my $success = $reactor->is_running; |
120 | 121 |
|
121 | 122 |
Check if reactor is running. Meant to be overloaded in a subclass. |
122 | 123 |
|
123 |
-=head2 C<one_tick> |
|
124 |
+=head2 one_tick |
|
124 | 125 |
|
125 | 126 |
$reactor->one_tick; |
126 | 127 |
|
... | ... |
@@ -132,7 +133,7 @@ the reactor, so you need to be careful. Meant to be overloaded in a subclass. |
132 | 133 |
$reactor->one_tick; |
133 | 134 |
$reactor->remove($id); |
134 | 135 |
|
135 |
-=head2 C<recurring> |
|
136 |
+=head2 recurring |
|
136 | 137 |
|
137 | 138 |
my $id = $reactor->recurring(0.25 => sub {...}); |
138 | 139 |
|
... | ... |
@@ -142,14 +143,14 @@ amount of time in seconds. Meant to be overloaded in a subclass. |
142 | 143 |
# Invoke as soon as possible |
143 | 144 |
$reactor->recurring(0 => sub { say 'Reactor tick.' }); |
144 | 145 |
|
145 |
-=head2 C<remove> |
|
146 |
+=head2 remove |
|
146 | 147 |
|
147 | 148 |
my $success = $reactor->remove($handle); |
148 | 149 |
my $success = $reactor->remove($id); |
149 | 150 |
|
150 | 151 |
Remove handle or timer. Meant to be overloaded in a subclass. |
151 | 152 |
|
152 |
-=head2 C<start> |
|
153 |
+=head2 start |
|
153 | 154 |
|
154 | 155 |
$reactor->start; |
155 | 156 |
|
... | ... |
@@ -157,13 +158,13 @@ Start watching for I/O and timer events, this will block until C<stop> is |
157 | 158 |
called. Note that some reactors stop automatically if there are no events |
158 | 159 |
being watched anymore. Meant to be overloaded in a subclass. |
159 | 160 |
|
160 |
-=head2 C<stop> |
|
161 |
+=head2 stop |
|
161 | 162 |
|
162 | 163 |
$reactor->stop; |
163 | 164 |
|
164 | 165 |
Stop watching for I/O and timer events. Meant to be overloaded in a subclass. |
165 | 166 |
|
166 |
-=head2 C<timer> |
|
167 |
+=head2 timer |
|
167 | 168 |
|
168 | 169 |
my $id = $reactor->timer(0.5 => sub {...}); |
169 | 170 |
|
... | ... |
@@ -173,7 +174,7 @@ seconds. Meant to be overloaded in a subclass. |
173 | 174 |
# Invoke as soon as possible |
174 | 175 |
$reactor->timer(0 => sub { say 'Next tick.' }); |
175 | 176 |
|
176 |
-=head2 C<watch> |
|
177 |
+=head2 watch |
|
177 | 178 |
|
178 | 179 |
$reactor = $reactor->watch($handle, $readable, $writable); |
179 | 180 |
|
... | ... |
@@ -111,53 +111,53 @@ L<Mojo::Reactor::EV> inherits all events from L<Mojo::Reactor::Poll>. |
111 | 111 |
L<Mojo::Reactor::EV> inherits all methods from L<Mojo::Reactor::Poll> and |
112 | 112 |
implements the following new ones. |
113 | 113 |
|
114 |
-=head2 C<new> |
|
114 |
+=head2 new |
|
115 | 115 |
|
116 | 116 |
my $reactor = Mojo::Reactor::EV->new; |
117 | 117 |
|
118 | 118 |
Construct a new L<Mojo::Reactor::EV> object. |
119 | 119 |
|
120 |
-=head2 C<is_running> |
|
120 |
+=head2 is_running |
|
121 | 121 |
|
122 | 122 |
my $success = $reactor->is_running; |
123 | 123 |
|
124 | 124 |
Check if reactor is running. |
125 | 125 |
|
126 |
-=head2 C<one_tick> |
|
126 |
+=head2 one_tick |
|
127 | 127 |
|
128 | 128 |
$reactor->one_tick; |
129 | 129 |
|
130 | 130 |
Run reactor until an event occurs or no events are being watched anymore. Note |
131 | 131 |
that this method can recurse back into the reactor, so you need to be careful. |
132 | 132 |
|
133 |
-=head2 C<recurring> |
|
133 |
+=head2 recurring |
|
134 | 134 |
|
135 | 135 |
my $id = $reactor->recurring(0.25 => sub {...}); |
136 | 136 |
|
137 | 137 |
Create a new recurring timer, invoking the callback repeatedly after a given |
138 | 138 |
amount of time in seconds. |
139 | 139 |
|
140 |
-=head2 C<start> |
|
140 |
+=head2 start |
|
141 | 141 |
|
142 | 142 |
$reactor->start; |
143 | 143 |
|
144 | 144 |
Start watching for I/O and timer events, this will block until C<stop> is |
145 | 145 |
called or no events are being watched anymore. |
146 | 146 |
|
147 |
-=head2 C<stop> |
|
147 |
+=head2 stop |
|
148 | 148 |
|
149 | 149 |
$reactor->stop; |
150 | 150 |
|
151 | 151 |
Stop watching for I/O and timer events. |
152 | 152 |
|
153 |
-=head2 C<timer> |
|
153 |
+=head2 timer |
|
154 | 154 |
|
155 | 155 |
my $id = $reactor->timer(0.5 => sub {...}); |
156 | 156 |
|
157 | 157 |
Create a new timer, invoking the callback after a given amount of time in |
158 | 158 |
seconds. |
159 | 159 |
|
160 |
-=head2 C<watch> |
|
160 |
+=head2 watch |
|
161 | 161 |
|
162 | 162 |
$reactor = $reactor->watch($handle, $readable, $writable); |
163 | 163 |
|
... | ... |
@@ -17,7 +17,7 @@ sub is_running { !!shift->{running} } |
17 | 17 |
sub one_tick { |
18 | 18 |
my $self = shift; |
19 | 19 |
|
20 |
- # Remember state |
|
20 |
+ # Remember state for later |
|
21 | 21 |
my $running = $self->{running}; |
22 | 22 |
$self->{running} = 1; |
23 | 23 |
|
... | ... |
@@ -56,7 +56,6 @@ sub one_tick { |
56 | 56 |
# Normal timer |
57 | 57 |
else { $self->remove($id) } |
58 | 58 |
|
59 |
- # Handle timer |
|
60 | 59 |
++$i and $self->_sandbox("Timer $id", $t->{cb}) if $t->{cb}; |
61 | 60 |
} |
62 | 61 |
} |
... | ... |
@@ -100,18 +99,17 @@ sub _poll { shift->{poll} ||= IO::Poll->new } |
100 | 99 |
|
101 | 100 |
sub _sandbox { |
102 | 101 |
my ($self, $desc, $cb) = (shift, shift, shift); |
103 |
- return if eval { $self->$cb(@_); 1 }; |
|
104 |
- $self->once(error => sub { warn $_[1] }) |
|
105 |
- unless $self->has_subscribers('error'); |
|
106 |
- $self->emit_safe(error => "$desc failed: $@"); |
|
102 |
+ eval { $self->$cb(@_); 1 } or $self->emit_safe(error => "$desc failed: $@"); |
|
107 | 103 |
} |
108 | 104 |
|
109 | 105 |
sub _timer { |
110 | 106 |
my ($self, $recurring, $after, $cb) = @_; |
107 |
+ |
|
111 | 108 |
my $id; |
112 | 109 |
do { $id = md5_sum('t' . time . rand 999) } while $self->{timers}{$id}; |
113 | 110 |
my $t = $self->{timers}{$id} = {cb => $cb, time => time + $after}; |
114 | 111 |
$t->{recurring} = $after if $recurring; |
112 |
+ |
|
115 | 113 |
return $id; |
116 | 114 |
} |
117 | 115 |
|
... | ... |
@@ -160,61 +158,61 @@ L<Mojo::Reactor::Poll> inherits all events from L<Mojo::Reactor>. |
160 | 158 |
L<Mojo::Reactor::Poll> inherits all methods from L<Mojo::Reactor> and |
161 | 159 |
implements the following new ones. |
162 | 160 |
|
163 |
-=head2 C<io> |
|
161 |
+=head2 io |
|
164 | 162 |
|
165 | 163 |
$reactor = $reactor->io($handle => sub {...}); |
166 | 164 |
|
167 | 165 |
Watch handle for I/O events, invoking the callback whenever handle becomes |
168 | 166 |
readable or writable. |
169 | 167 |
|
170 |
-=head2 C<is_running> |
|
168 |
+=head2 is_running |
|
171 | 169 |
|
172 | 170 |
my $success = $reactor->is_running; |
173 | 171 |
|
174 | 172 |
Check if reactor is running. |
175 | 173 |
|
176 |
-=head2 C<one_tick> |
|
174 |
+=head2 one_tick |
|
177 | 175 |
|
178 | 176 |
$reactor->one_tick; |
179 | 177 |
|
180 | 178 |
Run reactor until an event occurs or no events are being watched anymore. Note |
181 | 179 |
that this method can recurse back into the reactor, so you need to be careful. |
182 | 180 |
|
183 |
-=head2 C<recurring> |
|
181 |
+=head2 recurring |
|
184 | 182 |
|
185 | 183 |
my $id = $reactor->recurring(0.25 => sub {...}); |
186 | 184 |
|
187 | 185 |
Create a new recurring timer, invoking the callback repeatedly after a given |
188 | 186 |
amount of time in seconds. |
189 | 187 |
|
190 |
-=head2 C<remove> |
|
188 |
+=head2 remove |
|
191 | 189 |
|
192 | 190 |
my $success = $reactor->remove($handle); |
193 | 191 |
my $success = $reactor->remove($id); |
194 | 192 |
|
195 | 193 |
Remove handle or timer. |
196 | 194 |
|
197 |
-=head2 C<start> |
|
195 |
+=head2 start |
|
198 | 196 |
|
199 | 197 |
$reactor->start; |
200 | 198 |
|
201 | 199 |
Start watching for I/O and timer events, this will block until C<stop> is |
202 | 200 |
called or no events are being watched anymore. |
203 | 201 |
|
204 |
-=head2 C<stop> |
|
202 |
+=head2 stop |
|
205 | 203 |
|
206 | 204 |
$reactor->stop; |
207 | 205 |
|
208 | 206 |
Stop watching for I/O and timer events. |
209 | 207 |
|
210 |
-=head2 C<timer> |
|
208 |
+=head2 timer |
|
211 | 209 |
|
212 | 210 |
my $id = $reactor->timer(0.5 => sub {...}); |
213 | 211 |
|
214 | 212 |
Create a new timer, invoking the callback after a given amount of time in |
215 | 213 |
seconds. |
216 | 214 |
|
217 |
-=head2 C<watch> |
|
215 |
+=head2 watch |
|
218 | 216 |
|
219 | 217 |
$reactor = $reactor->watch($handle, $readable, $writable); |
220 | 218 |
|
... | ... |
@@ -18,7 +18,6 @@ sub new { |
18 | 18 |
sub build_app { |
19 | 19 |
my ($self, $app) = @_; |
20 | 20 |
local $ENV{MOJO_EXE}; |
21 |
- local $ENV{MOJO_APP} = $app; |
|
22 | 21 |
return $app->new unless my $e = Mojo::Loader->new->load($app); |
23 | 22 |
die ref $e ? $e : qq{Couldn't find application class "$app".\n}; |
24 | 23 |
} |
... | ... |
@@ -80,9 +79,10 @@ L<Mojo::Server> is an abstract HTTP server base class. |
80 | 79 |
|
81 | 80 |
=head1 EVENTS |
82 | 81 |
|
83 |
-L<Mojo::Server> can emit the following events. |
|
82 |
+L<Mojo::Server> inherits all events from L<Mojo::EventEmitter> and can emit |
|
83 |
+the following new ones. |
|
84 | 84 |
|
85 |
-=head2 C<request> |
|
85 |
+=head2 request |
|
86 | 86 |
|
87 | 87 |
$server->on(request => sub { |
88 | 88 |
my ($server, $tx) = @_; |
... | ... |
@@ -104,7 +104,7 @@ Emitted when a request is ready and needs to be handled. |
104 | 104 |
|
105 | 105 |
L<Mojo::Server> implements the following attributes. |
106 | 106 |
|
107 |
-=head2 C<app> |
|
107 |
+=head2 app |
|
108 | 108 |
|
109 | 109 |
my $app = $server->app; |
110 | 110 |
$server = $server->app(MojoSubclass->new); |
... | ... |
@@ -116,26 +116,26 @@ Application this server handles, defaults to a L<Mojo::HelloWorld> object. |
116 | 116 |
L<Mojo::Server> inherits all methods from L<Mojo::EventEmitter> and implements |
117 | 117 |
the following new ones. |
118 | 118 |
|
119 |
-=head2 C<new> |
|
119 |
+=head2 new |
|
120 | 120 |
|
121 | 121 |
my $server = Mojo::Server->new; |
122 | 122 |
|
123 | 123 |
Construct a new L<Mojo::Server> object and subscribe to C<request> event with |
124 | 124 |
default request handling. |
125 | 125 |
|
126 |
-=head2 C<build_app> |
|
126 |
+=head2 build_app |
|
127 | 127 |
|
128 | 128 |
my $app = $server->build_app('Mojo::HelloWorld'); |
129 | 129 |
|
130 | 130 |
Build application from class. |
131 | 131 |
|
132 |
-=head2 C<build_tx> |
|
132 |
+=head2 build_tx |
|
133 | 133 |
|
134 | 134 |
my $tx = $server->build_tx; |
135 | 135 |
|
136 | 136 |
Let application build a transaction. |
137 | 137 |
|
138 |
-=head2 C<load_app> |
|
138 |
+=head2 load_app |
|
139 | 139 |
|
140 | 140 |
my $app = $server->load_app('/home/sri/myapp.pl'); |
141 | 141 |
|
... | ... |
@@ -143,7 +143,7 @@ Load application from script. |
143 | 143 |
|
144 | 144 |
say Mojo::Server->new->load_app('./myapp.pl')->home; |
145 | 145 |
|
146 |
-=head2 C<run> |
|
146 |
+=head2 run |
|
147 | 147 |
|
148 | 148 |
$server->run; |
149 | 149 |
|
... | ... |
@@ -6,11 +6,8 @@ has 'nph'; |
6 | 6 |
sub run { |
7 | 7 |
my $self = shift; |
8 | 8 |
|
9 |
- # Environment |
|
10 | 9 |
my $tx = $self->build_tx; |
11 | 10 |
my $req = $tx->req->parse(\%ENV); |
12 |
- |
|
13 |
- # Store connection information |
|
14 | 11 |
$tx->local_port($ENV{SERVER_PORT})->remote_address($ENV{REMOTE_ADDR}); |
15 | 12 |
|
16 | 13 |
# Request body |
... | ... |
@@ -20,7 +17,7 @@ sub run { |
20 | 17 |
$req->parse($buffer); |
21 | 18 |
} |
22 | 19 |
|
23 |
- # Handle |
|
20 |
+ # Handle request |
|
24 | 21 |
$self->emit(request => $tx); |
25 | 22 |
|
26 | 23 |
# Response start line |
... | ... |
@@ -48,7 +45,6 @@ sub run { |
48 | 45 |
sub _write { |
49 | 46 |
my ($res, $method) = @_; |
50 | 47 |
|
51 |
- # Write chunks to STDOUT |
|
52 | 48 |
my $offset = 0; |
53 | 49 |
while (1) { |
54 | 50 |
|
... | ... |
@@ -58,7 +54,7 @@ sub _write { |
58 | 54 |
# End of part |
59 | 55 |
last unless my $len = length $chunk; |
60 | 56 |
|
61 |
- # Part |
|
57 |
+ # Make sure we can still write |
|
62 | 58 |
$offset += $len; |
63 | 59 |
return undef unless STDOUT->opened; |
64 | 60 |
print STDOUT $chunk; |
... | ... |
@@ -111,7 +107,7 @@ L<Mojo::Server::CGI> inherits all events from L<Mojo::Server>. |
111 | 107 |
L<Mojo::Server::CGI> inherits all attributes from L<Mojo::Server> and |
112 | 108 |
implements the following new ones. |
113 | 109 |
|
114 |
-=head2 C<nph> |
|
110 |
+=head2 nph |
|
115 | 111 |
|
116 | 112 |
my $nph = $cgi->nph; |
117 | 113 |
$cgi = $cgi->nph(1); |
... | ... |
@@ -123,7 +119,7 @@ Activate non parsed header mode. |
123 | 119 |
L<Mojo::Server::CGI> inherits all methods from L<Mojo::Server> and implements |
124 | 120 |
the following new ones. |
125 | 121 |
|
126 |
-=head2 C<run> |
|
122 |
+=head2 run |
|
127 | 123 |
|
128 | 124 |
my $status = $cgi->run; |
129 | 125 |
|
... | ... |
@@ -25,11 +25,7 @@ sub DESTROY { |
25 | 25 |
|
26 | 26 |
sub run { |
27 | 27 |
my $self = shift; |
28 |
- |
|
29 |
- # Signals |
|
30 |
- $SIG{INT} = $SIG{TERM} = sub { exit 0 }; |
|
31 |
- |
|
32 |
- # Change user/group and start accepting connections |
|
28 |
+ local $SIG{INT} = local $SIG{TERM} = sub { $self->ioloop->stop }; |
|
33 | 29 |
$self->start->setuidgid->ioloop->start; |
34 | 30 |
} |
35 | 31 |
|
... | ... |
@@ -73,7 +69,7 @@ sub start { |
73 | 69 |
sub stop { |
74 | 70 |
my $self = shift; |
75 | 71 |
|
76 |
- # Pause accepting connections |
|
72 |
+ # Suspend accepting connections but keep listen sockets open |
|
77 | 73 |
my $loop = $self->ioloop; |
78 | 74 |
while (my $id = shift @{$self->{acceptors}}) { |
79 | 75 |
my $server = $self->{servers}{$id} = $loop->acceptor($id); |
... | ... |
@@ -87,18 +83,11 @@ sub stop { |
87 | 83 |
sub _build_tx { |
88 | 84 |
my ($self, $id, $c) = @_; |
89 | 85 |
|
90 |
- # Build transaction |
|
91 | 86 |
my $tx = $self->build_tx->connection($id); |
92 |
- |
|
93 |
- # Identify |
|
94 | 87 |
$tx->res->headers->server('Mojolicious (Perl)'); |
95 |
- |
|
96 |
- # Store connection information |
|
97 | 88 |
my $handle = $self->ioloop->stream($id)->handle; |
98 | 89 |
$tx->local_address($handle->sockhost)->local_port($handle->sockport); |
99 | 90 |
$tx->remote_address($handle->peerhost)->remote_port($handle->peerport); |
100 |
- |
|
101 |
- # TLS |
|
102 | 91 |
$tx->req->url->base->scheme('https') if $c->{tls}; |
103 | 92 |
|
104 | 93 |
# Handle upgrades and requests |
... | ... |
@@ -130,7 +119,6 @@ sub _close { |
130 | 119 |
# Finish gracefully |
131 | 120 |
if (my $tx = $self->{connections}{$id}{tx}) { $tx->server_close } |
132 | 121 |
|
133 |
- # Remove connection |
|
134 | 122 |
delete $self->{connections}{$id}; |
135 | 123 |
} |
136 | 124 |
|
... | ... |
@@ -173,7 +161,6 @@ sub _finish { |
173 | 161 |
sub _listen { |
174 | 162 |
my ($self, $listen) = @_; |
175 | 163 |
|
176 |
- # Options |
|
177 | 164 |
my $url = Mojo::URL->new($listen); |
178 | 165 |
my $query = $url->query; |
179 | 166 |
my $options = { |
... | ... |
@@ -189,20 +176,15 @@ sub _listen { |
189 | 176 |
delete $options->{address} if $options->{address} eq '*'; |
190 | 177 |
my $tls = $options->{tls} = $url->protocol eq 'https' ? 1 : undef; |
191 | 178 |
|
192 |
- # Listen |
|
193 | 179 |
weaken $self; |
194 | 180 |
my $id = $self->ioloop->server( |
195 | 181 |
$options => sub { |
196 | 182 |
my ($loop, $stream, $id) = @_; |
197 | 183 |
|
198 |
- # Add new connection |
|
199 | 184 |
my $c = $self->{connections}{$id} = {tls => $tls}; |
200 | 185 |
warn "-- Accept (@{[$stream->handle->peerhost]})\n" if DEBUG; |
201 |
- |
|
202 |
- # Inactivity timeout |
|
203 | 186 |
$stream->timeout($self->inactivity_timeout); |
204 | 187 |
|
205 |
- # Events |
|
206 | 188 |
$stream->on(close => sub { $self->_close($id) }); |
207 | 189 |
$stream->on( |
208 | 190 |
error => sub { |
... | ... |
@@ -218,7 +200,6 @@ sub _listen { |
218 | 200 |
); |
219 | 201 |
push @{$self->{acceptors} ||= []}, $id; |
220 | 202 |
|
221 |
- # Friendly message |
|
222 | 203 |
return if $self->silent; |
223 | 204 |
$self->app->log->info(qq{Listening at "$listen".}); |
224 | 205 |
$listen =~ s!//\*!//127.0.0.1!i; |
... | ... |
@@ -228,11 +209,9 @@ sub _listen { |
228 | 209 |
sub _read { |
229 | 210 |
my ($self, $id, $chunk) = @_; |
230 | 211 |
|
231 |
- # Make sure we have a transaction |
|
212 |
+ # Make sure we have a transaction and parse chunk |
|
232 | 213 |
my $c = $self->{connections}{$id}; |
233 | 214 |
my $tx = $c->{tx} ||= $self->_build_tx($id, $c); |
234 |
- |
|
235 |
- # Parse chunk |
|
236 | 215 |
warn "-- Server <<< Client (@{[$tx->req->url->to_abs]})\n$chunk\n" if DEBUG; |
237 | 216 |
$tx->server_read($chunk); |
238 | 217 |
|
... | ... |
@@ -259,13 +238,11 @@ sub _write { |
259 | 238 |
return unless my $tx = $c->{tx}; |
260 | 239 |
return unless $tx->is_writing; |
261 | 240 |
|
262 |
- # Get chunk |
|
241 |
+ # Get chunk and write |
|
263 | 242 |
return if $c->{writing}++; |
264 | 243 |
my $chunk = $tx->server_write; |
265 | 244 |
delete $c->{writing}; |
266 | 245 |
warn "-- Server >>> Client (@{[$tx->req->url->to_abs]})\n$chunk\n" if DEBUG; |
267 |
- |
|
268 |
- # Write chunk |
|
269 | 246 |
my $stream = $self->ioloop->stream($id)->write($chunk); |
270 | 247 |
|
271 | 248 |
# Finish or continue writing |
... | ... |
@@ -334,21 +311,21 @@ L<Mojo::Server::Daemon> inherits all events from L<Mojo::Server>. |
334 | 311 |
L<Mojo::Server::Daemon> inherits all attributes from L<Mojo::Server> and |
335 | 312 |
implements the following new ones. |
336 | 313 |
|
337 |
-=head2 C<backlog> |
|
314 |
+=head2 backlog |
|
338 | 315 |
|
339 | 316 |
my $backlog = $daemon->backlog; |
340 | 317 |
$daemon = $daemon->backlog(128); |
341 | 318 |
|
342 | 319 |
Listen backlog size, defaults to C<SOMAXCONN>. |
343 | 320 |
|
344 |
-=head2 C<group> |
|
321 |
+=head2 group |
|
345 | 322 |
|
346 | 323 |
my $group = $daemon->group; |
347 | 324 |
$daemon = $daemon->group('users'); |
348 | 325 |
|
349 | 326 |
Group for server process. |
350 | 327 |
|
351 |
-=head2 C<inactivity_timeout> |
|
328 |
+=head2 inactivity_timeout |
|
352 | 329 |
|
353 | 330 |
my $timeout = $daemon->inactivity_timeout; |
354 | 331 |
$daemon = $daemon->inactivity_timeout(5); |
... | ... |
@@ -358,7 +335,7 @@ closed, defaults to the value of the C<MOJO_INACTIVITY_TIMEOUT> environment |
358 | 335 |
variable or C<15>. Setting the value to C<0> will allow connections to be |
359 | 336 |
inactive indefinitely. |
360 | 337 |
|
361 |
-=head2 C<ioloop> |
|
338 |
+=head2 ioloop |
|
362 | 339 |
|
363 | 340 |
my $loop = $daemon->ioloop; |
364 | 341 |
$daemon = $daemon->ioloop(Mojo::IOLoop->new); |
... | ... |
@@ -366,7 +343,7 @@ inactive indefinitely. |
366 | 343 |
Event loop object to use for I/O operations, defaults to the global |
367 | 344 |
L<Mojo::IOLoop> singleton. |
368 | 345 |
|
369 |
-=head2 C<listen> |
|
346 |
+=head2 listen |
|
370 | 347 |
|
371 | 348 |
my $listen = $daemon->listen; |
372 | 349 |
$daemon = $daemon->listen(['https://localhost:3000']); |
... | ... |
@@ -391,46 +368,46 @@ These parameters are currently available: |
391 | 368 |
|
392 | 369 |
=over 4 |
393 | 370 |
|
394 |
-=item C<ca> |
|
371 |
+=item ca |
|
395 | 372 |
|
396 | 373 |
Path to TLS certificate authority file. |
397 | 374 |
|
398 |
-=item C<cert> |
|
375 |
+=item cert |
|
399 | 376 |
|
400 | 377 |
Path to the TLS cert file, defaults to a built-in test certificate. |
401 | 378 |
|
402 |
-=item C<key> |
|
379 |
+=item key |
|
403 | 380 |
|
404 | 381 |
Path to the TLS key file, defaults to a built-in test key. |
405 | 382 |
|
406 |
-=item C<verify> |
|
383 |
+=item verify |
|
407 | 384 |
|
408 | 385 |
TLS verification mode, defaults to C<0x03>. |
409 | 386 |
|
410 | 387 |
=back |
411 | 388 |
|
412 |
-=head2 C<max_clients> |
|
389 |
+=head2 max_clients |
|
413 | 390 |
|
414 | 391 |
my $max = $daemon->max_clients; |
415 | 392 |
$daemon = $daemon->max_clients(1000); |
416 | 393 |
|
417 | 394 |
Maximum number of parallel client connections, defaults to C<1000>. |
418 | 395 |
|
419 |
-=head2 C<max_requests> |
|
396 |
+=head2 max_requests |
|
420 | 397 |
|
421 | 398 |
my $max = $daemon->max_requests; |
422 | 399 |
$daemon = $daemon->max_requests(100); |
423 | 400 |
|
424 | 401 |
Maximum number of keep alive requests per connection, defaults to C<25>. |
425 | 402 |
|
426 |
-=head2 C<silent> |
|
403 |
+=head2 silent |
|
427 | 404 |
|
428 | 405 |
my $silent = $daemon->silent; |
429 | 406 |
$daemon = $daemon->silent(1); |
430 | 407 |
|
431 | 408 |
Disable console messages. |
432 | 409 |
|
433 |
-=head2 C<user> |
|
410 |
+=head2 user |
|
434 | 411 |
|
435 | 412 |
my $user = $daemon->user; |
436 | 413 |
$daemon = $daemon->user('web'); |
... | ... |
@@ -442,25 +419,25 @@ User for the server process. |
442 | 419 |
L<Mojo::Server::Daemon> inherits all methods from L<Mojo::Server> and |
443 | 420 |
implements the following new ones. |
444 | 421 |
|
445 |
-=head2 C<run> |
|
422 |
+=head2 run |
|
446 | 423 |
|
447 | 424 |
$daemon->run; |
448 | 425 |
|
449 | 426 |
Run server. |
450 | 427 |
|
451 |
-=head2 C<setuidgid> |
|
428 |
+=head2 setuidgid |
|
452 | 429 |
|
453 | 430 |
$daemon = $daemon->setuidgid; |
454 | 431 |
|
455 | 432 |
Set user and group for process. |
456 | 433 |
|
457 |
-=head2 C<start> |
|
434 |
+=head2 start |
|
458 | 435 |
|
459 | 436 |
$daemon = $daemon->start; |
460 | 437 |
|
461 | 438 |
Start accepting connections. |
462 | 439 |
|
463 |
-=head2 C<stop> |
|
440 |
+=head2 stop |
|
464 | 441 |
|
465 | 442 |
$daemon = $daemon->stop; |
466 | 443 |
|
... | ... |
@@ -4,26 +4,11 @@ use Mojo::Base -base; |
4 | 4 |
# "Bender: I was God once. |
5 | 5 |
# God: Yes, I saw. You were doing well, until everyone died." |
6 | 6 |
use Cwd 'abs_path'; |
7 |
-use Fcntl ':flock'; |
|
8 | 7 |
use File::Basename 'dirname'; |
9 |
-use File::Spec::Functions qw(catfile tmpdir); |
|
10 |
-use IO::Poll 'POLLIN'; |
|
11 |
-use List::Util 'shuffle'; |
|
12 |
-use Mojo::Server::Daemon; |
|
13 |
-use POSIX qw(setsid WNOHANG); |
|
8 |
+use File::Spec::Functions 'catfile'; |
|
9 |
+use Mojo::Server::Prefork; |
|
10 |
+use POSIX 'setsid'; |
|
14 | 11 |
use Scalar::Util 'weaken'; |
15 |
-use Time::HiRes 'ualarm'; |
|
16 |
- |
|
17 |
-sub DESTROY { |
|
18 |
- my $self = shift; |
|
19 |
- |
|
20 |
- # Worker or command |
|
21 |
- return unless $self->{finished}; |
|
22 |
- |
|
23 |
- # Manager |
|
24 |
- if (my $file = $self->{config}{pid_file}) { unlink $file if -w $file } |
|
25 |
- if (my $file = $self->{config}{lock_file}) { unlink $file if -w $file } |
|
26 |
-} |
|
27 | 12 |
|
28 | 13 |
sub run { |
29 | 14 |
my ($self, $path) = @_; |
... | ... |
@@ -31,13 +16,13 @@ sub run { |
31 | 16 |
# No Windows support |
32 | 17 |
_exit('Hypnotoad not available for Windows.') if $^O eq 'MSWin32'; |
33 | 18 |
|
34 |
- # Application |
|
19 |
+ # Remember application for later |
|
35 | 20 |
$ENV{HYPNOTOAD_APP} ||= abs_path $path; |
36 | 21 |
|
37 | 22 |
# This is a production server |
38 | 23 |
$ENV{MOJO_MODE} ||= 'production'; |
39 | 24 |
|
40 |
- # Executable |
|
25 |
+ # Remember executable for later |
|
41 | 26 |
$ENV{HYPNOTOAD_EXE} ||= $0; |
42 | 27 |
$0 = $ENV{HYPNOTOAD_APP}; |
43 | 28 |
|
... | ... |
@@ -45,9 +30,13 @@ sub run { |
45 | 30 |
die "Can't exec: $!" if !$ENV{HYPNOTOAD_REV}++ && !exec $ENV{HYPNOTOAD_EXE}; |
46 | 31 |
|
47 | 32 |
# Preload application and configure server |
48 |
- my $daemon = $self->{daemon} = Mojo::Server::Daemon->new; |
|
49 |
- my $app = $daemon->load_app($ENV{HYPNOTOAD_APP}); |
|
33 |
+ my $prefork = $self->{prefork} = Mojo::Server::Prefork->new; |
|
34 |
+ my $app = $prefork->load_app($ENV{HYPNOTOAD_APP}); |
|
50 | 35 |
$self->_config($app); |
36 |
+ weaken $self; |
|
37 |
+ $prefork->on(wait => sub { $self->_manage }); |
|
38 |
+ $prefork->on(reap => sub { $self->_reap(pop) }); |
|
39 |
+ $prefork->on(finish => sub { $self->{finished} = 1 }); |
|
51 | 40 |
|
52 | 41 |
# Testing |
53 | 42 |
_exit('Everything looks good!') if $ENV{HYPNOTOAD_TEST}; |
... | ... |
@@ -73,87 +62,38 @@ sub run { |
73 | 62 |
} |
74 | 63 |
|
75 | 64 |
# Start accepting connections |
76 |
- my $log = $self->{log} = $app->log; |
|
77 |
- $log->info(qq[Hypnotoad server $$ started for "$ENV{HYPNOTOAD_APP}".]); |
|
78 |
- $daemon->start; |
|
79 |
- |
|
80 |
- # Pipe for worker communication |
|
81 |
- pipe($self->{reader}, $self->{writer}) or die "Can't create pipe: $!"; |
|
82 |
- $self->{poll} = IO::Poll->new; |
|
83 |
- $self->{poll}->mask($self->{reader}, POLLIN); |
|
84 |
- |
|
85 |
- # Clean manager environment |
|
86 |
- my $c = $self->{config}; |
|
87 |
- $SIG{INT} = $SIG{TERM} = sub { $self->{finished} = 1 }; |
|
88 |
- $SIG{CHLD} = sub { |
|
89 |
- while ((my $pid = waitpid -1, WNOHANG) > 0) { $self->_reap($pid) } |
|
90 |
- }; |
|
91 |
- $SIG{QUIT} = sub { $self->{finished} = $self->{graceful} = 1 }; |
|
92 |
- $SIG{USR2} = sub { $self->{upgrade} ||= time }; |
|
93 |
- $SIG{TTIN} = sub { $c->{workers}++ }; |
|
94 |
- $SIG{TTOU} = sub { |
|
95 |
- return unless $c->{workers} && $c->{workers}--; |
|
96 |
- $self->{workers}{shuffle keys %{$self->{workers}}}{graceful} ||= time; |
|
97 |
- }; |
|
98 |
- |
|
99 |
- # Mainloop |
|
100 |
- $self->_manage while 1; |
|
65 |
+ local $SIG{USR2} = sub { $self->{upgrade} ||= time }; |
|
66 |
+ $prefork->run; |
|
101 | 67 |
} |
102 | 68 |
|
103 | 69 |
sub _config { |
104 | 70 |
my ($self, $app) = @_; |
105 | 71 |
|
106 | 72 |
# Hypnotoad settings |
107 |
- my $c = $self->{config} = $app->config('hypnotoad') || {}; |
|
108 |
- $c->{graceful_timeout} ||= 20; |
|
109 |
- $c->{heartbeat_interval} ||= 5; |
|
110 |
- $c->{heartbeat_timeout} ||= 20; |
|
111 |
- $c->{lock_file} ||= catfile tmpdir, 'hypnotoad.lock'; |
|
112 |
- $c->{lock_file} .= ".$$"; |
|
113 |
- $c->{lock_timeout} ||= 0.5; |
|
114 |
- $c->{pid_file} ||= catfile dirname($ENV{HYPNOTOAD_APP}), 'hypnotoad.pid'; |
|
115 |
- $c->{upgrade_timeout} ||= 60; |
|
116 |
- $c->{workers} ||= 4; |
|
117 |
- |
|
118 |
- # Daemon settings |
|
73 |
+ my $c = $app->config('hypnotoad') || {}; |
|
74 |
+ $self->{upgrade_timeout} = $c->{upgrade_timeout} || 60; |
|
75 |
+ |
|
76 |
+ # Prefork settings |
|
119 | 77 |
$ENV{MOJO_REVERSE_PROXY} = $c->{proxy} if defined $c->{proxy}; |
120 |
- my $daemon = $self->{daemon}; |
|
121 |
- defined $c->{$_} and $daemon->$_($c->{$_}) for qw(backlog group user); |
|
122 |
- $daemon->max_clients($c->{clients} || 1000); |
|
123 |
- $daemon->max_requests($c->{keep_alive_requests} || 25); |
|
124 |
- $daemon->inactivity_timeout(defined $c->{inactivity_timeout} ? $c->{inactivity_timeout} : 15); |
|
125 |
- $daemon->listen($c->{listen} || ['http://*:8080']); |
|
126 |
- |
|
127 |
- # Event loop settings |
|
128 |
- my $loop = $daemon->ioloop; |
|
129 |
- $loop->max_accepts(defined $c->{accepts} ? $c->{accepts} : 1000); |
|
130 |
- defined $c->{$_} and $loop->$_($c->{$_}) |
|
131 |
- for qw(accept_interval multi_accept); |
|
78 |
+ my $prefork = $self->{prefork}->listen($c->{listen} || ['http://*:8080']); |
|
79 |
+ my $file = catfile dirname($ENV{HYPNOTOAD_APP}), 'hypnotoad.pid'; |
|
80 |
+ $prefork->pid_file($c->{pid_file} || $file); |
|
81 |
+ $prefork->max_clients($c->{clients}) if $c->{clients}; |
|
82 |
+ $prefork->max_requests($c->{keep_alive_requests}) |
|
83 |
+ if $c->{keep_alive_requests}; |
|
84 |
+ defined $c->{$_} and $prefork->$_($c->{$_}) |
|
85 |
+ for qw(accept_interval accepts backlog graceful_timeout group), |
|
86 |
+ qw(heartbeat_interval heartbeat_timeout inactivity_timeout lock_file), |
|
87 |
+ qw(lock_timeout multi_accept user workers); |
|
132 | 88 |
} |
133 | 89 |
|
134 | 90 |
sub _exit { say shift and exit 0 } |
135 | 91 |
|
136 |
-sub _heartbeat { |
|
137 |
- my $self = shift; |
|
138 |
- |
|
139 |
- # Poll for heartbeats |
|
140 |
- my $poll = $self->{poll}; |
|
141 |
- $poll->poll(1); |
|
142 |
- return unless $poll->handles(POLLIN); |
|
143 |
- return unless $self->{reader}->sysread(my $chunk, 4194304); |
|
144 |
- |
|
145 |
- # Update heartbeats |
|
146 |
- $self->{workers}{$1} and $self->{workers}{$1}{time} = time |
|
147 |
- while $chunk =~ /(\d+)\n/g; |
|
148 |
-} |
|
149 |
- |
|
150 | 92 |
sub _hot_deploy { |
151 | 93 |
my $self = shift; |
152 | 94 |
|
153 |
- # Make sure server is running and clean up PID file if necessary |
|
154 |
- return unless defined(my $pid = $self->_pid); |
|
155 |
- my $file = $self->{config}{pid_file}; |
|
156 |
- return -w $file ? unlink $file : undef unless $pid && kill 0, $pid; |
|
95 |
+ # Make sure server is running |
|
96 |
+ return unless my $pid = $self->{prefork}->check_pid; |
|
157 | 97 |
|
158 | 98 |
# Start hot deployment |
159 | 99 |
kill 'USR2', $pid; |
... | ... |
@@ -163,173 +103,42 @@ sub _hot_deploy { |
163 | 103 |
sub _manage { |
164 | 104 |
my $self = shift; |
165 | 105 |
|
166 |
- # Housekeeping |
|
167 |
- my $c = $self->{config}; |
|
168 |
- if (!$self->{finished}) { |
|
169 |
- |
|
170 |
- # Spawn more workers |
|
171 |
- $self->_spawn while keys %{$self->{workers}} < $c->{workers}; |
|
172 |
- |
|
173 |
- # Check PID file |
|
174 |
- $self->_pid_file; |
|
175 |
- } |
|
176 |
- |
|
177 |
- # Shutdown |
|
178 |
- elsif (!keys %{$self->{workers}}) { exit 0 } |
|
179 |
- |
|
180 | 106 |
# Upgraded |
107 |
+ my $log = $self->{prefork}->app->log; |
|
181 | 108 |
if ($ENV{HYPNOTOAD_PID} && $ENV{HYPNOTOAD_PID} ne $$) { |
182 |
- $self->{log}->info("Upgrade successful, stopping $ENV{HYPNOTOAD_PID}."); |
|
109 |
+ $log->info("Upgrade successful, stopping $ENV{HYPNOTOAD_PID}."); |
|
183 | 110 |
kill 'QUIT', $ENV{HYPNOTOAD_PID}; |
184 | 111 |
} |
185 |
- $ENV{HYPNOTOAD_PID} = $$; |
|
186 |
- |
|
187 |
- # Check heartbeat |
|
188 |
- $self->_heartbeat; |
|
112 |
+ $ENV{HYPNOTOAD_PID} = $$ unless (defined $ENV{HYPNOTOAD_PID} ? $ENV{HYPNOTOAD_PID} : '') eq $$; |
|
189 | 113 |
|
190 | 114 |
# Upgrade |
191 | 115 |
if ($self->{upgrade} && !$self->{finished}) { |
192 | 116 |
|
193 | 117 |
# Fresh start |
194 | 118 |
unless ($self->{new}) { |
195 |
- $self->{log}->info('Starting zero downtime software upgrade.'); |
|
119 |
+ $log->info('Starting zero downtime software upgrade.'); |
|
196 | 120 |
die "Can't fork: $!" unless defined(my $pid = $self->{new} = fork); |
197 | 121 |
exec($ENV{HYPNOTOAD_EXE}) or die("Can't exec: $!") unless $pid; |
198 | 122 |
} |
199 | 123 |
|
200 | 124 |
# Timeout |
201 | 125 |
kill 'KILL', $self->{new} |
202 |
- if $self->{upgrade} + $c->{upgrade_timeout} <= time; |
|
126 |
+ if $self->{upgrade} + $self->{upgrade_timeout} <= time; |
|
203 | 127 |
} |
204 |
- |
|
205 |
- # Workers |
|
206 |
- while (my ($pid, $w) = each %{$self->{workers}}) { |
|
207 |
- |
|
208 |
- # No heartbeat (graceful stop) |
|
209 |
- my $interval = $c->{heartbeat_interval}; |
|
210 |
- my $timeout = $c->{heartbeat_timeout}; |
|
211 |
- if (!$w->{graceful} && ($w->{time} + $interval + $timeout <= time)) { |
|
212 |
- $self->{log}->info("Worker $pid has no heartbeat, restarting."); |
|
213 |
- $w->{graceful} = time; |
|
214 |
- } |
|
215 |
- |
|
216 |
- # Graceful stop with timeout |
|
217 |
- $w->{graceful} ||= time if $self->{graceful}; |
|
218 |
- if ($w->{graceful}) { |
|
219 |
- $self->{log}->debug("Trying to stop worker $pid gracefully."); |
|
220 |
- kill 'QUIT', $pid; |
|
221 |
- $w->{force} = 1 if $w->{graceful} + $c->{graceful_timeout} <= time; |
|
222 |
- } |
|
223 |
- |
|
224 |
- # Normal stop |
|
225 |
- if (($self->{finished} && !$self->{graceful}) || $w->{force}) { |
|
226 |
- $self->{log}->debug("Stopping worker $pid."); |
|
227 |
- kill 'KILL', $pid; |
|
228 |
- } |
|
229 |
- } |
|
230 |
-} |
|
231 |
- |
|
232 |
-sub _pid { |
|
233 |
- return undef unless open my $file, '<', shift->{config}{pid_file}; |
|
234 |
- my $pid = <$file>; |
|
235 |
- chomp $pid; |
|
236 |
- return $pid; |
|
237 |
-} |
|
238 |
- |
|
239 |
-sub _pid_file { |
|
240 |
- my $self = shift; |
|
241 |
- |
|
242 |
- # Don't need a PID file anymore |
|
243 |
- return if $self->{finished}; |
|
244 |
- |
|
245 |
- # Check if PID file already exists |
|
246 |
- return if -e (my $file = $self->{config}{pid_file}); |
|
247 |
- |
|
248 |
- # Create PID file |
|
249 |
- $self->{log}->info(qq{Creating process id file "$file".}); |
|
250 |
- die qq{Can't create process id file "$file": $!} |
|
251 |
- unless open my $pid, '>', $file; |
|
252 |
- chmod 0644, $pid; |
|
253 |
- print $pid $$; |
|
254 | 128 |
} |
255 | 129 |
|
256 | 130 |
sub _reap { |
257 | 131 |
my ($self, $pid) = @_; |
258 | 132 |
|
259 | 133 |
# Clean up failed upgrade |
260 |
- if (($self->{new} || '') eq $pid) { |
|
261 |
- $self->{log}->info('Zero downtime software upgrade failed.'); |
|
262 |
- delete $self->{$_} for qw(new upgrade); |
|
263 |
- } |
|
264 |
- |
|
265 |
- # Clean up worker |
|
266 |
- else { |
|
267 |
- $self->{log}->debug("Worker $pid stopped."); |
|
268 |
- delete $self->{workers}{$pid}; |
|
269 |
- } |
|
270 |
-} |
|
271 |
- |
|
272 |
-sub _spawn { |
|
273 |
- my $self = shift; |
|
274 |
- |
|
275 |
- # Manager |
|
276 |
- die "Can't fork: $!" unless defined(my $pid = fork); |
|
277 |
- return $self->{workers}{$pid} = {time => time} if $pid; |
|
278 |
- |
|
279 |
- # Prepare lock file |
|
280 |
- my $c = $self->{config}; |
|
281 |
- my $file = $c->{lock_file}; |
|
282 |
- die qq{Can't open lock file "$file": $!} unless open my $lock, '>', $file; |
|
283 |
- |
|
284 |
- # Change user/group |
|
285 |
- my $loop = $self->{daemon}->setuidgid->ioloop; |
|
286 |
- |
|
287 |
- # Accept mutex |
|
288 |
- $loop->lock( |
|
289 |
- sub { |
|
290 |
- |
|
291 |
- # Blocking |
|
292 |
- my $l; |
|
293 |
- if ($_[1]) { |
|
294 |
- eval { |
|
295 |
- local $SIG{ALRM} = sub { die "alarm\n" }; |
|
296 |
- my $old = ualarm $c->{lock_timeout} * 1000000; |
|
297 |
- $l = flock $lock, LOCK_EX; |
|
298 |
- ualarm $old; |
|
299 |
- }; |
|
300 |
- if ($@) { $l = $@ eq "alarm\n" ? 0 : die($@) } |
|
301 |
- } |
|
302 |
- |
|
303 |
- # Non blocking |
|
304 |
- else { $l = flock $lock, LOCK_EX | LOCK_NB } |
|
305 |
- |
|
306 |
- return $l; |
|
307 |
- } |
|
308 |
- ); |
|
309 |
- $loop->unlock(sub { flock $lock, LOCK_UN }); |
|
310 |
- |
|
311 |
- # Heartbeat messages (stop sending during graceful stop) |
|
312 |
- weaken $self; |
|
313 |
- $loop->recurring( |
|
314 |
- $c->{heartbeat_interval} => sub { |
|
315 |
- return unless shift->max_connections; |
|
316 |
- $self->{writer}->syswrite("$$\n") or exit 0; |
|
317 |
- } |
|
318 |
- ); |
|
319 |
- |
|
320 |
- # Clean worker environment |
|
321 |
- $SIG{$_} = 'DEFAULT' for qw(INT TERM CHLD USR2 TTIN TTOU); |
|
322 |
- $SIG{QUIT} = sub { $loop->max_connections(0) }; |
|
323 |
- delete $self->{$_} for qw(poll reader); |
|
324 |
- |
|
325 |
- # Start |
|
326 |
- $self->{log}->debug("Worker $$ started."); |
|
327 |
- $loop->start; |
|
328 |
- exit 0; |
|
134 |
+ return unless ($self->{new} || '') eq $pid; |
|
135 |
+ $self->{prefork}->app->log->info('Zero downtime software upgrade failed.'); |
|
136 |
+ delete $self->{$_} for qw(new upgrade); |
|
329 | 137 |
} |
330 | 138 |
|
331 | 139 |
sub _stop { |
332 |
- _exit('Hypnotoad server not running.') unless my $pid = shift->_pid; |
|
140 |
+ _exit('Hypnotoad server not running.') |
|
141 |
+ unless my $pid = shift->{prefork}->check_pid; |
|
333 | 142 |
kill 'QUIT', $pid; |
334 | 143 |
_exit("Stopping Hypnotoad server $pid gracefully."); |
335 | 144 |
} |
... | ... |
@@ -351,7 +160,7 @@ Mojo::Server::Hypnotoad - ALL GLORY TO THE HYPNOTOAD! |
351 | 160 |
|
352 | 161 |
L<Mojo::Server::Hypnotoad> is a full featured, UNIX optimized, preforking |
353 | 162 |
non-blocking I/O HTTP and WebSocket server, built around the very well tested |
354 |
-and reliable L<Mojo::Server::Daemon>, with C<IPv6>, C<TLS>, C<Comet> (long |
|
163 |
+and reliable L<Mojo::Server::Prefork>, with C<IPv6>, C<TLS>, C<Comet> (long |
|
355 | 164 |
polling), multiple event loop and hot deployment support that just works. Note |
356 | 165 |
that the server uses signals for process management, so you should avoid |
357 | 166 |
modifying signal handlers in your applications. |
... | ... |
@@ -385,23 +194,23 @@ signals. |
385 | 194 |
|
386 | 195 |
=over 2 |
387 | 196 |
|
388 |
-=item C<INT>, C<TERM> |
|
197 |
+=item INT, TERM |
|
389 | 198 |
|
390 | 199 |
Shutdown server immediately. |
391 | 200 |
|
392 |
-=item C<QUIT> |
|
201 |
+=item QUIT |
|
393 | 202 |
|
394 | 203 |
Shutdown server gracefully. |
395 | 204 |
|
396 |
-=item C<TTIN> |
|
205 |
+=item TTIN |
|
397 | 206 |
|
398 | 207 |
Increase worker pool by one. |
399 | 208 |
|
400 |
-=item C<TTOU> |
|
209 |
+=item TTOU |
|
401 | 210 |
|
402 | 211 |
Decrease worker pool by one. |
403 | 212 |
|
404 |
-=item C<USR2> |
|
213 |
+=item USR2 |
|
405 | 214 |
|
406 | 215 |
Attempt zero downtime software upgrade (hot deployment) without losing any |
407 | 216 |
incoming connections. |
... | ... |
@@ -426,11 +235,11 @@ and take over serving requests after starting up successfully. |
426 | 235 |
|
427 | 236 |
=over 2 |
428 | 237 |
|
429 |
-=item C<INT>, C<TERM> |
|
238 |
+=item INT, TERM |
|
430 | 239 |
|
431 | 240 |
Stop worker immediately. |
432 | 241 |
|
433 |
-=item C<QUIT> |
|
242 |
+=item QUIT |
|
434 | 243 |
|
435 | 244 |
Stop worker gracefully. |
436 | 245 |
|
... | ... |
@@ -441,7 +250,7 @@ Stop worker gracefully. |
441 | 250 |
L<Mojo::Server::Hypnotoad> can be configured with the following settings, see |
442 | 251 |
L<Mojolicious::Guides::Cookbook/"Hypnotoad"> for examples. |
443 | 252 |
|
444 |
-=head2 C<accept_interval> |
|
253 |
+=head2 accept_interval |
|
445 | 254 |
|
446 | 255 |
accept_interval => 0.5 |
447 | 256 |
|
... | ... |
@@ -449,7 +258,7 @@ Interval in seconds for trying to reacquire the accept mutex and connection |
449 | 258 |
management, defaults to C<0.025>. Note that changing this value can affect |
450 | 259 |
performance and idle CPU usage. |
451 | 260 |
|
452 |
-=head2 C<accepts> |
|
261 |
+=head2 accepts |
|
453 | 262 |
|
454 | 263 |
accepts => 100 |
455 | 264 |
|
... | ... |
@@ -459,13 +268,13 @@ to accept new connections indefinitely. Note that up to half of this value can |
459 | 268 |
be subtracted randomly to improve load balancing, and that worker processes |
460 | 269 |
will stop sending heartbeat messages once the limit has been reached. |
461 | 270 |
|
462 |
-=head2 C<backlog> |
|
271 |
+=head2 backlog |
|
463 | 272 |
|
464 | 273 |
backlog => 128 |
465 | 274 |
|
466 | 275 |
Listen backlog size, defaults to C<SOMAXCONN>. |
467 | 276 |
|
468 |
-=head2 C<clients> |
|
277 |
+=head2 clients |
|
469 | 278 |
|
470 | 279 |
clients => 100 |
471 | 280 |
|
... | ... |
@@ -474,33 +283,33 @@ C<1000>. Note that depending on how much your application may block, you might |
474 | 283 |
want to decrease this value and increase C<workers> instead for better |
475 | 284 |
performance. |
476 | 285 |
|
477 |
-=head2 C<graceful_timeout> |
|
286 |
+=head2 graceful_timeout |
|
478 | 287 |
|
479 | 288 |
graceful_timeout => 15 |
480 | 289 |
|
481 | 290 |
Maximum amount of time in seconds stopping a worker gracefully may take before |
482 | 291 |
being forced, defaults to C<20>. |
483 | 292 |
|
484 |
-=head2 C<group> |
|
293 |
+=head2 group |
|
485 | 294 |
|
486 | 295 |
group => 'staff' |
487 | 296 |
|
488 | 297 |
Group name for worker processes. |
489 | 298 |
|
490 |
-=head2 C<heartbeat_interval> |
|
299 |
+=head2 heartbeat_interval |
|
491 | 300 |
|
492 | 301 |
heartbeat_interval => 3 |
493 | 302 |
|
494 | 303 |
Heartbeat interval in seconds, defaults to C<5>. |
495 | 304 |
|
496 |
-=head2 C<heartbeat_timeout> |
|
305 |
+=head2 heartbeat_timeout |
|
497 | 306 |
|
498 | 307 |
heartbeat_timeout => 2 |
499 | 308 |
|
500 | 309 |
Maximum amount of time in seconds before a worker without a heartbeat will be |
501 | 310 |
stopped gracefully, defaults to C<20>. |
502 | 311 |
|
503 |
-=head2 C<inactivity_timeout> |
|
312 |
+=head2 inactivity_timeout |
|
504 | 313 |
|
505 | 314 |
inactivity_timeout => 10 |
506 | 315 |
|
... | ... |
@@ -508,40 +317,40 @@ Maximum amount of time in seconds a connection can be inactive before getting |
508 | 317 |
closed, defaults to C<15>. Setting the value to C<0> will allow connections to |
509 | 318 |
be inactive indefinitely. |
510 | 319 |
|
511 |
-=head2 C<keep_alive_requests> |
|
320 |
+=head2 keep_alive_requests |
|
512 | 321 |
|
513 | 322 |
keep_alive_requests => 50 |
514 | 323 |
|
515 | 324 |
Number of keep alive requests per connection, defaults to C<25>. |
516 | 325 |
|
517 |
-=head2 C<listen> |
|
326 |
+=head2 listen |
|
518 | 327 |
|
519 | 328 |
listen => ['http://*:80'] |
520 | 329 |
|
521 | 330 |
List of one or more locations to listen on, defaults to C<http://*:8080>. See |
522 | 331 |
also L<Mojo::Server::Daemon/"listen"> for more examples. |
523 | 332 |
|
524 |
-=head2 C<lock_file> |
|
333 |
+=head2 lock_file |
|
525 | 334 |
|
526 | 335 |
lock_file => '/tmp/hypnotoad.lock' |
527 | 336 |
|
528 | 337 |
Full path of accept mutex lock file prefix, to which the process id will be |
529 | 338 |
appended, defaults to a random temporary path. |
530 | 339 |
|
531 |
-=head2 C<lock_timeout> |
|
340 |
+=head2 lock_timeout |
|
532 | 341 |
|
533 | 342 |
lock_timeout => 1 |
534 | 343 |
|
535 | 344 |
Maximum amount of time in seconds a worker may block when waiting for the |
536 | 345 |
accept mutex, defaults to C<0.5>. |
537 | 346 |
|
538 |
-=head2 C<multi_accept> |
|
347 |
+=head2 multi_accept |
|
539 | 348 |
|
540 | 349 |
multi_accept => 100 |
541 | 350 |
|
542 | 351 |
Number of connections to accept at once, defaults to C<50>. |
543 | 352 |
|
544 |
-=head2 C<pid_file> |
|
353 |
+=head2 pid_file |
|
545 | 354 |
|
546 | 355 |
pid_file => '/var/run/hypnotoad.pid' |
547 | 356 |
|
... | ... |
@@ -549,7 +358,7 @@ Full path to process id file, defaults to C<hypnotoad.pid> in the same |
549 | 358 |
directory as the application. Note that this value can only be changed after |
550 | 359 |
the server has been stopped. |
551 | 360 |
|
552 |
-=head2 C<proxy> |
|
361 |
+=head2 proxy |
|
553 | 362 |
|
554 | 363 |
proxy => 1 |
555 | 364 |
|
... | ... |
@@ -557,20 +366,20 @@ Activate reverse proxy support, which allows for the C<X-Forwarded-For> and |
557 | 366 |
C<X-Forwarded-HTTPS> headers to be picked up automatically, defaults to the |
558 | 367 |
value of the C<MOJO_REVERSE_PROXY> environment variable. |
559 | 368 |
|
560 |
-=head2 C<upgrade_timeout> |
|
369 |
+=head2 upgrade_timeout |
|
561 | 370 |
|
562 | 371 |
upgrade_timeout => 45 |
563 | 372 |
|
564 | 373 |
Maximum amount of time in seconds a zero downtime software upgrade may take |
565 | 374 |
before getting canceled, defaults to C<60>. |
566 | 375 |
|
567 |
-=head2 C<user> |
|
376 |
+=head2 user |
|
568 | 377 |
|
569 | 378 |
user => 'sri' |
570 | 379 |
|
571 | 380 |
Username for worker processes. |
572 | 381 |
|
573 |
-=head2 C<workers> |
|
382 |
+=head2 workers |
|
574 | 383 |
|
575 | 384 |
workers => 10 |
576 | 385 |
|
... | ... |
@@ -582,7 +391,7 @@ worker processes per CPU core. |
582 | 391 |
L<Mojo::Server::Hypnotoad> inherits all methods from L<Mojo::Base> and |
583 | 392 |
implements the following new ones. |
584 | 393 |
|
585 |
-=head2 C<run> |
|
394 |
+=head2 run |
|
586 | 395 |
|
587 | 396 |
$toad->run('script/myapp'); |
588 | 397 |
|
... | ... |
@@ -26,8 +26,8 @@ sub run { |
26 | 26 |
my ($self, $app) = @_; |
27 | 27 |
|
28 | 28 |
# Prepare environment |
29 |
- $SIG{CHLD} = sub { $self->_reap }; |
|
30 |
- $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = sub { |
|
29 |
+ local $SIG{CHLD} = sub { $self->_reap }; |
|
30 |
+ local $SIG{INT} = local $SIG{TERM} = local $SIG{QUIT} = sub { |
|
31 | 31 |
$self->{finished} = 1; |
32 | 32 |
kill 'TERM', $self->{running} if $self->{running}; |
33 | 33 |
}; |
... | ... |
@@ -63,7 +63,6 @@ sub _manage { |
63 | 63 |
$self->{modified} = 1; |
64 | 64 |
} |
65 | 65 |
|
66 |
- # Housekeeping |
|
67 | 66 |
$self->_reap; |
68 | 67 |
delete $self->{running} if $self->{running} && !kill 0, $self->{running}; |
69 | 68 |
$self->_spawn if !$self->{running} && delete $self->{modified}; |
... | ... |
@@ -136,7 +135,7 @@ See L<Mojolicious::Guides::Cookbook> for more. |
136 | 135 |
|
137 | 136 |
L<Mojo::Server::Morbo> implements the following attributes. |
138 | 137 |
|
139 |
-=head2 C<watch> |
|
138 |
+=head2 watch |
|
140 | 139 |
|
141 | 140 |
my $watch = $morbo->watch; |
142 | 141 |
$morbo = $morbo->watch(['/home/sri/myapp']); |
... | ... |
@@ -150,13 +149,13 @@ directory. |
150 | 149 |
L<Mojo::Server::Morbo> inherits all methods from L<Mojo::Base> and implements |
151 | 150 |
the following new ones. |
152 | 151 |
|
153 |
-=head2 C<check_file> |
|
152 |
+=head2 check_file |
|
154 | 153 |
|
155 | 154 |
my $success = $morbo->check_file('/home/sri/lib/MyApp.pm'); |
156 | 155 |
|
157 | 156 |
Check if file has been modified since last check. |
158 | 157 |
|
159 |
-=head2 C<run> |
|
158 |
+=head2 run |
|
160 | 159 |
|
161 | 160 |
$morbo->run('script/myapp'); |
162 | 161 |
|
... | ... |
@@ -4,11 +4,8 @@ use Mojo::Base 'Mojo::Server'; |
4 | 4 |
sub run { |
5 | 5 |
my ($self, $env) = @_; |
6 | 6 |
|
7 |
- # Environment |
|
8 | 7 |
my $tx = $self->build_tx; |
9 | 8 |
my $req = $tx->req->parse($env); |
10 |
- |
|
11 |
- # Store connection information |
|
12 | 9 |
$tx->local_port($env->{SERVER_PORT})->remote_address($env->{REMOTE_ADDR}); |
13 | 10 |
|
14 | 11 |
# Request body |
... | ... |
@@ -20,7 +17,7 @@ sub run { |
20 | 17 |
last if ($len -= $read) <= 0; |
21 | 18 |
} |
22 | 19 |
|
23 |
- # Handle |
|
20 |
+ # Handle request |
|
24 | 21 |
$self->emit(request => $tx); |
25 | 22 |
|
26 | 23 |
# Response headers |
... | ... |
@@ -47,6 +44,7 @@ sub to_psgi_app { |
47 | 44 |
package Mojo::Server::PSGI::_IO; |
48 | 45 |
use Mojo::Base -base; |
49 | 46 |
|
47 |
+# Finish transaction |
|
50 | 48 |
sub close { shift->{tx}->server_close } |
51 | 49 |
|
52 | 50 |
sub getline { |
... | ... |
@@ -59,7 +57,6 @@ sub getline { |
59 | 57 |
# End of content |
60 | 58 |
return undef unless length $chunk; |
61 | 59 |
|
62 |
- # Content |
|
63 | 60 |
$self->{offset} += length $chunk; |
64 | 61 |
return $chunk; |
65 | 62 |
} |
... | ... |
@@ -109,13 +106,13 @@ L<Mojo::Server::PSGI> inherits all events from L<Mojo::Server>. |
109 | 106 |
L<Mojo::Server::PSGI> inherits all methods from L<Mojo::Server> and implements |
110 | 107 |
the following new ones. |
111 | 108 |
|
112 |
-=head2 C<run> |
|
109 |
+=head2 run |
|
113 | 110 |
|
114 | 111 |
my $res = $psgi->run($env); |
115 | 112 |
|
116 | 113 |
Run L<PSGI>. |
117 | 114 |
|
118 |
-=head2 C<to_psgi_app> |
|
115 |
+=head2 to_psgi_app |
|
119 | 116 |
|
120 | 117 |
my $app = $psgi->to_psgi_app; |
121 | 118 |
|
... | ... |
@@ -0,0 +1,495 @@ |
1 |
+package Mojo::Server::Prefork; |
|
2 |
+use Mojo::Base 'Mojo::Server::Daemon'; |
|
3 |
+ |
|
4 |
+use Fcntl ':flock'; |
|
5 |
+use File::Spec::Functions qw(catfile tmpdir); |
|
6 |
+use IO::Poll 'POLLIN'; |
|
7 |
+use List::Util 'shuffle'; |
|
8 |
+use POSIX 'WNOHANG'; |
|
9 |
+use Scalar::Util 'weaken'; |
|
10 |
+use Time::HiRes (); |
|
11 |
+ |
|
12 |
+has accepts => 1000; |
|
13 |
+has accept_interval => 0.025; |
|
14 |
+has [qw(graceful_timeout heartbeat_timeout)] => 20; |
|
15 |
+has heartbeat_interval => 5; |
|
16 |
+has lock_file => sub { catfile tmpdir, 'prefork.lock' }; |
|
17 |
+has lock_timeout => 0.5; |
|
18 |
+has multi_accept => 50; |
|
19 |
+has pid_file => sub { catfile tmpdir, 'prefork.pid' }; |
|
20 |
+has workers => 4; |
|
21 |
+ |
|
22 |
+sub DESTROY { |
|
23 |
+ my $self = shift; |
|
24 |
+ |
|
25 |
+ # Worker |
|
26 |
+ return unless $self->{finished}; |
|
27 |
+ |
|
28 |
+ # Manager |
|
29 |
+ if (my $file = $self->{lock_file}) { unlink $file if -w $file } |
|
30 |
+ if (my $file = $self->pid_file) { unlink $file if -w $file } |
|
31 |
+} |
|
32 |
+ |
|
33 |
+sub check_pid { |
|
34 |
+ my $file = shift->pid_file; |
|
35 |
+ return undef unless open my $handle, '<', $file; |
|
36 |
+ my $pid = <$handle>; |
|
37 |
+ chomp $pid; |
|
38 |
+ |
|
39 |
+ # Running |
|
40 |
+ return $pid if $pid && kill 0, $pid; |
|
41 |
+ |
|
42 |
+ # Not running |
|
43 |
+ unlink $file if -w $file; |
|
44 |
+ return undef; |
|
45 |
+} |
|
46 |
+ |
|
47 |
+sub run { |
|
48 |
+ my $self = shift; |
|
49 |
+ |
|
50 |
+ # No Windows support |
|
51 |
+ say 'Preforking not available for Windows.' and exit 0 if $^O eq 'MSWin32'; |
|
52 |
+ |
|
53 |
+ # Prepare lock file and event loop |
|
54 |
+ $self->{lock_file} = $self->lock_file . ".$$"; |
|
55 |
+ my $loop = $self->ioloop->max_accepts($self->accepts); |
|
56 |
+ $loop->$_($self->$_) for qw(accept_interval multi_accept); |
|
57 |
+ |
|
58 |
+ # Pipe for worker communication |
|
59 |
+ pipe($self->{reader}, $self->{writer}) or die "Can't create pipe: $!"; |
|
60 |
+ $self->{poll} = IO::Poll->new; |
|
61 |
+ $self->{poll}->mask($self->{reader}, POLLIN); |
|
62 |
+ |
|
63 |
+ # Clean manager environment |
|
64 |
+ local $SIG{INT} = local $SIG{TERM} = sub { $self->_term }; |
|
65 |
+ local $SIG{CHLD} = sub { |
|
66 |
+ while ((my $pid = waitpid -1, WNOHANG) > 0) { $self->_reap($pid) } |
|
67 |
+ }; |
|
68 |
+ local $SIG{QUIT} = sub { $self->_term(1) }; |
|
69 |
+ local $SIG{TTIN} = sub { $self->workers($self->workers + 1) }; |
|
70 |
+ local $SIG{TTOU} = sub { |
|
71 |
+ $self->workers($self->workers - 1) if $self->workers > 0; |
|
72 |
+ return unless $self->workers; |
|
73 |
+ $self->{pool}{shuffle keys %{$self->{pool}}}{graceful} ||= time; |
|
74 |
+ }; |
|
75 |
+ |
|
76 |
+ # Preload application and start accepting connections |
|
77 |
+ $self->start->app->log->info("Manager $$ started."); |
|
78 |
+ $self->{running} = 1; |
|
79 |
+ $self->_manage while $self->{running}; |
|
80 |
+} |
|
81 |
+ |
|
82 |
+sub _heartbeat { |
|
83 |
+ my $self = shift; |
|
84 |
+ |
|
85 |
+ # Poll for heartbeats |
|
86 |
+ my $poll = $self->{poll}; |
|
87 |
+ $poll->poll(1); |
|
88 |
+ return unless $poll->handles(POLLIN); |
|
89 |
+ return unless $self->{reader}->sysread(my $chunk, 4194304); |
|
90 |
+ |
|
91 |
+ # Update heartbeats |
|
92 |
+ $self->{pool}{$1} and $self->emit(heartbeat => $1)->{pool}{$1}{time} = time |
|
93 |
+ while $chunk =~ /(\d+)\n/g; |
|
94 |
+} |
|
95 |
+ |
|
96 |
+sub _manage { |
|
97 |
+ my $self = shift; |
|
98 |
+ |
|
99 |
+ # Spawn more workers and check PID file |
|
100 |
+ if (!$self->{finished}) { |
|
101 |
+ $self->_spawn while keys %{$self->{pool}} < $self->workers; |
|
102 |
+ $self->_pid_file; |
|
103 |
+ } |
|
104 |
+ |
|
105 |
+ # Shutdown |
|
106 |
+ elsif (!keys %{$self->{pool}}) { return delete $self->{running} } |
|
107 |
+ |
|
108 |
+ # Manage workers |
|
109 |
+ $self->emit('wait')->_heartbeat; |
|
110 |
+ my $log = $self->app->log; |
|
111 |
+ while (my ($pid, $w) = each %{$self->{pool}}) { |
|
112 |
+ |
|
113 |
+ # No heartbeat (graceful stop) |
|
114 |
+ my $interval = $self->heartbeat_interval; |
|
115 |
+ my $timeout = $self->heartbeat_timeout; |
|
116 |
+ if (!$w->{graceful} && ($w->{time} + $interval + $timeout <= time)) { |
|
117 |
+ $log->info("Worker $pid has no heartbeat, restarting."); |
|
118 |
+ $w->{graceful} = time; |
|
119 |
+ } |
|
120 |
+ |
|
121 |
+ # Graceful stop with timeout |
|
122 |
+ $w->{graceful} ||= time if $self->{graceful}; |
|
123 |
+ if ($w->{graceful}) { |
|
124 |
+ $log->debug("Trying to stop worker $pid gracefully."); |
|
125 |
+ kill 'QUIT', $pid; |
|
126 |
+ $w->{force} = 1 if $w->{graceful} + $self->graceful_timeout <= time; |
|
127 |
+ } |
|
128 |
+ |
|
129 |
+ # Normal stop |
|
130 |
+ if (($self->{finished} && !$self->{graceful}) || $w->{force}) { |
|
131 |
+ $log->debug("Stopping worker $pid."); |
|
132 |
+ kill 'KILL', $pid; |
|
133 |
+ } |
|
134 |
+ } |
|
135 |
+} |
|
136 |
+ |
|
137 |
+sub _pid_file { |
|
138 |
+ my $self = shift; |
|
139 |
+ |
|
140 |
+ # Check if PID file already exists |
|
141 |
+ return if -e (my $file = $self->pid_file); |
|
142 |
+ |
|
143 |
+ # Create PID file |
|
144 |
+ $self->app->log->info(qq{Creating process id file "$file".}); |
|
145 |
+ die qq{Can't create process id file "$file": $!} |
|
146 |
+ unless open my $handle, '>', $file; |
|
147 |
+ chmod 0644, $handle; |
|
148 |
+ print $handle $$; |
|
149 |
+} |
|
150 |
+ |
|
151 |
+sub _reap { |
|
152 |
+ my ($self, $pid) = @_; |
|
153 |
+ |
|
154 |
+ # CLean up dead worker |
|
155 |
+ $self->app->log->debug("Worker $pid stopped.") |
|
156 |
+ if delete $self->emit(reap => $pid)->{pool}{$pid}; |
|
157 |
+} |
|
158 |
+ |
|
159 |
+sub _spawn { |
|
160 |
+ my $self = shift; |
|
161 |
+ |
|
162 |
+ # Manager |
|
163 |
+ die "Can't fork: $!" unless defined(my $pid = fork); |
|
164 |
+ return $self->emit(spawn => $pid)->{pool}{$pid} = {time => time} if $pid; |
|
165 |
+ |
|
166 |
+ # Prepare lock file |
|
167 |
+ my $file = $self->{lock_file}; |
|
168 |
+ die qq{Can't open lock file "$file": $!} unless open my $handle, '>', $file; |
|
169 |
+ |
|
170 |
+ # Change user/group |
|
171 |
+ my $loop = $self->setuidgid->ioloop; |
|
172 |
+ |
|
173 |
+ # Accept mutex |
|
174 |
+ $loop->lock( |
|
175 |
+ sub { |
|
176 |
+ |
|
177 |
+ # Blocking ("ualarm" can't be imported on Windows) |
|
178 |
+ my $l; |
|
179 |
+ if ($_[1]) { |
|
180 |
+ eval { |
|
181 |
+ local $SIG{ALRM} = sub { die "alarm\n" }; |
|
182 |
+ my $old = Time::HiRes::ualarm $self->lock_timeout * 1000000; |
|
183 |
+ $l = flock $handle, LOCK_EX; |
|
184 |
+ Time::HiRes::ualarm $old; |
|
185 |
+ }; |
|
186 |
+ if ($@) { $l = $@ eq "alarm\n" ? 0 : die($@) } |
|
187 |
+ } |
|
188 |
+ |
|
189 |
+ # Non blocking |
|
190 |
+ else { $l = flock $handle, LOCK_EX | LOCK_NB } |
|
191 |
+ |
|
192 |
+ return $l; |
|
193 |
+ } |
|
194 |
+ ); |
|
195 |
+ $loop->unlock(sub { flock $handle, LOCK_UN }); |
|
196 |
+ |
|
197 |
+ # Heartbeat messages (stop sending during graceful stop) |
|
198 |
+ weaken $self; |
|
199 |
+ $loop->recurring( |
|
200 |
+ $self->heartbeat_interval => sub { |
|
201 |
+ return unless shift->max_connections; |
|
202 |
+ $self->{writer}->syswrite("$$\n") or exit 0; |
|
203 |
+ } |
|
204 |
+ ); |
|
205 |
+ |
|
206 |
+ # Clean worker environment |
|
207 |
+ $SIG{$_} = 'DEFAULT' for qw(INT TERM CHLD TTIN TTOU); |
|
208 |
+ $SIG{QUIT} = sub { $loop->max_connections(0) }; |
|
209 |
+ delete $self->{$_} for qw(poll reader); |
|
210 |
+ |
|
211 |
+ # Start event loop |
|
212 |
+ $self->app->log->debug("Worker $$ started."); |
|
213 |
+ $loop->start; |
|
214 |
+ exit 0; |
|
215 |
+} |
|
216 |
+ |
|
217 |
+sub _term { |
|
218 |
+ my ($self, $graceful) = @_; |
|
219 |
+ $self->emit(finish => $graceful)->{finished} = 1; |
|
220 |
+ $self->{graceful} = 1 if $graceful; |
|
221 |
+} |
|
222 |
+ |
|
223 |
+1; |
|
224 |
+ |
|
225 |
+=head1 NAME |
|
226 |
+ |
|
227 |
+Mojo::Server::Prefork - Preforking non-blocking I/O HTTP and WebSocket server |
|
228 |
+ |
|
229 |
+=head1 SYNOPSIS |
|
230 |
+ |
|
231 |
+ use Mojo::Server::Prefork; |
|
232 |
+ |
|
233 |
+ my $prefork = Mojo::Server::Prefork->new(listen => ['http://*:8080']); |
|
234 |
+ $prefork->unsubscribe('request'); |
|
235 |
+ $prefork->on(request => sub { |
|
236 |
+ my ($prefork, $tx) = @_; |
|
237 |
+ |
|
238 |
+ # Request |
|
239 |
+ my $method = $tx->req->method; |
|
240 |
+ my $path = $tx->req->url->path; |
|
241 |
+ |
|
242 |
+ # Response |
|
243 |
+ $tx->res->code(200); |
|
244 |
+ $tx->res->headers->content_type('text/plain'); |
|
245 |
+ $tx->res->body("$method request for $path!"); |
|
246 |
+ |
|
247 |
+ # Resume transaction |
|
248 |
+ $tx->resume; |
|
249 |
+ }); |
|
250 |
+ $prefork->run; |
|
251 |
+ |
|
252 |
+=head1 DESCRIPTION |
|
253 |
+ |
|
254 |
+L<Mojo::Server::Prefork> is a full featured, UNIX optimized, preforking |
|
255 |
+non-blocking I/O HTTP and WebSocket server, built around the very well tested |
|
256 |
+and reliable L<Mojo::Server::Daemon>, with C<IPv6>, C<TLS>, C<Comet> (long |
|
257 |
+polling) and multiple event loop support. Note that the server uses signals |
|
258 |
+for process management, so you should avoid modifying signal handlers in your |
|
259 |
+applications. |
|
260 |
+ |
|
261 |
+Optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and |
|
262 |
+L<IO::Socket::SSL> (1.75+) are supported transparently through |
|
263 |
+L<Mojo::IOLoop>, and used if installed. Individual features can also be |
|
264 |
+disabled with the C<MOJO_NO_IPV6> and C<MOJO_NO_TLS> environment variables. |
|
265 |
+ |
|
266 |
+See L<Mojolicious::Guides::Cookbook> for more. |
|
267 |
+ |
|
268 |
+=head1 SIGNALS |
|
269 |
+ |
|
270 |
+L<Mojo::Server::Prefork> can be controlled at runtime with the following |
|
271 |
+signals. |
|
272 |
+ |
|
273 |
+=head2 Manager |
|
274 |
+ |
|
275 |
+=over 2 |
|
276 |
+ |
|
277 |
+=item INT, TERM |
|
278 |
+ |
|
279 |
+Shutdown server immediately. |
|
280 |
+ |
|
281 |
+=item QUIT |
|
282 |
+ |
|
283 |
+Shutdown server gracefully. |
|
284 |
+ |
|
285 |
+=item TTIN |
|
286 |
+ |
|
287 |
+Increase worker pool by one. |
|
288 |
+ |
|
289 |
+=item TTOU |
|
290 |
+ |
|
291 |
+Decrease worker pool by one. |
|
292 |
+ |
|
293 |
+=back |
|
294 |
+ |
|
295 |
+=head2 Worker |
|
296 |
+ |
|
297 |
+=over 2 |
|
298 |
+ |
|
299 |
+=item INT, TERM |
|
300 |
+ |
|
301 |
+Stop worker immediately. |
|
302 |
+ |
|
303 |
+=item QUIT |
|
304 |
+ |
|
305 |
+Stop worker gracefully. |
|
306 |
+ |
|
307 |
+=back |
|
308 |
+ |
|
309 |
+=head1 EVENTS |
|
310 |
+ |
|
311 |
+L<Mojo::Server::Prefork> inherits all events from L<Mojo::Server::Daemon> and |
|
312 |
+can emit the following new ones. |
|
313 |
+ |
|
314 |
+=head2 finish |
|
315 |
+ |
|
316 |
+ $prefork->on(finish => sub { |
|
317 |
+ my ($prefork, $graceful) = @_; |
|
318 |
+ ... |
|
319 |
+ }); |
|
320 |
+ |
|
321 |
+Emitted when the server shuts down. |
|
322 |
+ |
|
323 |
+ $prefork->on(finish => sub { |
|
324 |
+ my ($prefork, $graceful) = @_; |
|
325 |
+ say $graceful ? 'Graceful server shutdown' : 'Server shutdown'; |
|
326 |
+ }); |
|
327 |
+ |
|
328 |
+=head2 heartbeat |
|
329 |
+ |
|
330 |
+ $prefork->on(heartbeat => sub { |
|
331 |
+ my ($prefork, $pid) = @_; |
|
332 |
+ ... |
|
333 |
+ }); |
|
334 |
+ |
|
335 |
+Emitted when a heartbeat message has been received from a worker. |
|
336 |
+ |
|
337 |
+ $prefork->on(heartbeat => sub { |
|
338 |
+ my ($prefork, $pid) = @_; |
|
339 |
+ say "Worker $pid has a heartbeat"; |
|
340 |
+ }); |
|
341 |
+ |
|
342 |
+=head2 reap |
|
343 |
+ |
|
344 |
+ $prefork->on(reap => sub { |
|
345 |
+ my ($prefork, $pid) = @_; |
|
346 |
+ ... |
|
347 |
+ }); |
|
348 |
+ |
|
349 |
+Emitted when a child process dies. |
|
350 |
+ |
|
351 |
+ $prefork->on(reap => sub { |
|
352 |
+ my ($prefork, $pid) = @_; |
|
353 |
+ say "Worker $pid stopped"; |
|
354 |
+ }); |
|
355 |
+ |
|
356 |
+=head2 spawn |
|
357 |
+ |
|
358 |
+ $prefork->on(spawn => sub { |
|
359 |
+ my ($prefork, $pid) = @_; |
|
360 |
+ ... |
|
361 |
+ }); |
|
362 |
+ |
|
363 |
+Emitted when a worker process is spawned. |
|
364 |
+ |
|
365 |
+ $prefork->on(spawn => sub { |
|
366 |
+ my ($prefork, $pid) = @_; |
|
367 |
+ say "Worker $pid started"; |
|
368 |
+ }); |
|
369 |
+ |
|
370 |
+=head2 wait |
|
371 |
+ |
|
372 |
+ $prefork->on(wait => sub { |
|
373 |
+ my $prefork = shift; |
|
374 |
+ ... |
|
375 |
+ }); |
|
376 |
+ |
|
377 |
+Emitted when the manager starts waiting for new heartbeat messages. |
|
378 |
+ |
|
379 |
+ $prefork->on(wait => sub { |
|
380 |
+ my $prefork = shift; |
|
381 |
+ my $workers = $prefork->workers; |
|
382 |
+ say "Waiting for heartbeat messages from $workers workers"; |
|
383 |
+ }); |
|
384 |
+ |
|
385 |
+=head1 ATTRIBUTES |
|
386 |
+ |
|
387 |
+L<Mojo::Server::Prefork> inherits all attributes from L<Mojo::Server::Daemon> |
|
388 |
+and implements the following new ones. |
|
389 |
+ |
|
390 |
+=head2 accept_interval |
|
391 |
+ |
|
392 |
+ my $interval = $prefork->accept_interval; |
|
393 |
+ $prefork = $prefork->accept_interval(0.5); |
|
394 |
+ |
|
395 |
+Interval in seconds for trying to reacquire the accept mutex and connection |
|
396 |
+management, defaults to C<0.025>. Note that changing this value can affect |
|
397 |
+performance and idle CPU usage. |
|
398 |
+ |
|
399 |
+=head2 accepts |
|
400 |
+ |
|
401 |
+ my $accepts = $prefork->accepts; |
|
402 |
+ $prefork = $prefork->accepts(100); |
|
403 |
+ |
|
404 |
+Maximum number of connections a worker is allowed to accept before stopping |
|
405 |
+gracefully, defaults to C<1000>. Setting the value to C<0> will allow workers |
|
406 |
+to accept new connections indefinitely. Note that up to half of this value can |
|
407 |
+be subtracted randomly to improve load balancing, and that worker processes |
|
408 |
+will stop sending heartbeat messages once the limit has been reached. |
|
409 |
+ |
|
410 |
+=head2 graceful_timeout |
|
411 |
+ |
|
412 |
+ my $timeout = $prefork->graceful_timeout; |
|
413 |
+ $prefork = $prefork->graceful_timeout(15); |
|
414 |
+ |
|
415 |
+Maximum amount of time in seconds stopping a worker gracefully may take before |
|
416 |
+being forced, defaults to C<20>. |
|
417 |
+ |
|
418 |
+=head2 heartbeat_interval |
|
419 |
+ |
|
420 |
+ my $interval = $prefork->heartbeat_intrval; |
|
421 |
+ $prefork = $prefork->heartbeat_interval(3); |
|
422 |
+ |
|
423 |
+Heartbeat interval in seconds, defaults to C<5>. |
|
424 |
+ |
|
425 |
+=head2 heartbeat_timeout |
|
426 |
+ |
|
427 |
+ my $timeout = $prefork->heartbeat_timeout; |
|
428 |
+ $prefork = $prefork->heartbeat_timeout(2); |
|
429 |
+ |
|
430 |
+Maximum amount of time in seconds before a worker without a heartbeat will be |
|
431 |
+stopped gracefully, defaults to C<20>. |
|
432 |
+ |
|
433 |
+=head2 lock_file |
|
434 |
+ |
|
435 |
+ my $file = $prefork->lock_file; |
|
436 |
+ $prefork = $prefork->lock_file('/tmp/prefork.lock'); |
|
437 |
+ |
|
438 |
+Full path of accept mutex lock file prefix, to which the process id will be |
|
439 |
+appended, defaults to a random temporary path. |
|
440 |
+ |
|
441 |
+=head2 lock_timeout |
|
442 |
+ |
|
443 |
+ my $timeout = $prefork->lock_timeout; |
|
444 |
+ $prefork = $prefork->lock_timeout(1); |
|
445 |
+ |
|
446 |
+Maximum amount of time in seconds a worker may block when waiting for the |
|
447 |
+accept mutex, defaults to C<0.5>. |
|
448 |
+ |
|
449 |
+=head2 multi_accept |
|
450 |
+ |
|
451 |
+ my $multi = $prefork->multi_accept; |
|
452 |
+ $prefork = $prefork->multi_accept(100); |
|
453 |
+ |
|
454 |
+Number of connections to accept at once, defaults to C<50>. |
|
455 |
+ |
|
456 |
+=head2 pid_file |
|
457 |
+ |
|
458 |
+ my $file = $prefork->pid_file; |
|
459 |
+ $prefork = $prefork->pid_file('/tmp/prefork.pid'); |
|
460 |
+ |
|
461 |
+Full path of process id file, defaults to a random temporary path. |
|
462 |
+ |
|
463 |
+=head2 workers |
|
464 |
+ |
|
465 |
+ my $workers = $prefork->workers; |
|
466 |
+ $prefork = $prefork->workers(10); |
|
467 |
+ |
|
468 |
+Number of worker processes, defaults to C<4>. A good rule of thumb is two |
|
469 |
+worker processes per CPU core. |
|
470 |
+ |
|
471 |
+=head1 METHODS |
|
472 |
+ |
|
473 |
+L<Mojo::Server::Prefork> inherits all methods from L<Mojo::Server::Daemon> and |
|
474 |
+implements the following new ones. |
|
475 |
+ |
|
476 |
+=head2 check_pid |
|
477 |
+ |
|
478 |
+ my $pid = $prefork->check_pid; |
|
479 |
+ |
|
480 |
+Get process id for running server from C<pid_file> or delete it if server is |
|
481 |
+not running. |
|
482 |
+ |
|
483 |
+ say 'Server is not running' unless $prefork->check_pid; |
|
484 |
+ |
|
485 |
+=head2 run |
|
486 |
+ |
|
487 |
+ $prefork->run; |
|
488 |
+ |
|
489 |
+Run server. |
|
490 |
+ |
|
491 |
+=head1 SEE ALSO |
|
492 |
+ |
|
493 |
+L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>. |
|
494 |
+ |
|
495 |
+=cut |
... | ... |
@@ -26,11 +26,8 @@ has tree => sub { [] }; |
26 | 26 |
sub build { |
27 | 27 |
my $self = shift; |
28 | 28 |
|
29 |
- # Lines |
|
30 | 29 |
my (@lines, $cpst, $multi); |
31 | 30 |
for my $line (@{$self->tree}) { |
32 |
- |
|
33 |
- # New line |
|
34 | 31 |
push @lines, ''; |
35 | 32 |
for (my $j = 0; $j < @{$line}; $j += 2) { |
36 | 33 |
my $type = $line->[$j]; |
... | ... |
@@ -118,12 +115,11 @@ sub interpret { |
118 | 115 |
Mojo::Exception->throw(shift, [$self->template, $self->code]); |
119 | 116 |
}; |
120 | 117 |
|
121 |
- # Interpret |
|
122 | 118 |
return undef unless my $compiled = $self->compiled; |
123 | 119 |
my $output = eval { $compiled->(@_) }; |
124 | 120 |
return $output unless $@; |
125 | 121 |
|
126 |
- # Exception |
|
122 |
+ # Exception with template context |
|
127 | 123 |
return Mojo::Exception->new($@, [$self->template])->verbose(1); |
128 | 124 |
} |
129 | 125 |
|
... | ... |
@@ -133,7 +129,6 @@ sub parse { |
133 | 129 |
# Clean start |
134 | 130 |
delete $self->template($tmpl)->{tree}; |
135 | 131 |
|
136 |
- # Token |
|
137 | 132 |
my $tag = $self->tag_start; |
138 | 133 |
my $replace = $self->replace_mark; |
139 | 134 |
my $expr = $self->expression_mark; |
... | ... |
@@ -202,7 +197,7 @@ sub parse { |
202 | 197 |
# Normal line ending |
203 | 198 |
else { $line .= "\n" } |
204 | 199 |
|
205 |
- # Tokenize |
|
200 |
+ # Mixed line |
|
206 | 201 |
my @token; |
207 | 202 |
for my $token (split $token_re, $line) { |
208 | 203 |
|
... | ... |
@@ -270,14 +265,12 @@ sub render { |
270 | 265 |
sub render_file { |
271 | 266 |
my ($self, $path) = (shift, shift); |
272 | 267 |
|
273 |
- # Slurp file |
|
274 | 268 |
$self->name($path) unless defined $self->{name}; |
275 |
- my $tmpl = slurp $path; |
|
276 |
- |
|
277 |
- # Decode and render |
|
269 |
+ my $tmpl = slurp $path; |
|
278 | 270 |
my $encoding = $self->encoding; |
279 | 271 |
croak qq{Template "$path" has invalid encoding.} |
280 | 272 |
if $encoding && !defined($tmpl = decode $encoding, $tmpl); |
273 |
+ |
|
281 | 274 |
return $self->render($tmpl, @_); |
282 | 275 |
} |
283 | 276 |
|
... | ... |
@@ -310,7 +303,7 @@ sub _wrap { |
310 | 303 |
|
311 | 304 |
# Escape function |
312 | 305 |
my $escape = $self->escape; |
313 |
- monkey_patch $self->namespace, '_escape', sub { |
|
306 |
+ monkey_patch $self->namespace, _escape => sub { |
|
314 | 307 |
no warnings 'uninitialized'; |
315 | 308 |
ref $_[0] eq 'Mojo::ByteStream' ? $_[0] : $escape->("$_[0]"); |
316 | 309 |
}; |
... | ... |
@@ -321,7 +314,6 @@ sub _wrap { |
321 | 314 |
$lines->[0] .= "sub { my \$_M = ''; @{[$self->prepend]}; do { $first"; |
322 | 315 |
$lines->[-1] .= "@{[$self->append]}; \$_M } };"; |
323 | 316 |
|
324 |
- # Code |
|
325 | 317 |
my $code = join "\n", @$lines; |
326 | 318 |
warn "-- Code for @{[$self->name]}\n@{[encode 'UTF-8', $code]}\n\n" if DEBUG; |
327 | 319 |
return $code; |
... | ... |
@@ -402,7 +394,8 @@ the default in L<Mojolicious> C<.ep> templates for example. |
402 | 394 |
|
403 | 395 |
L<Mojo::ByteStream> objects are always excluded from automatic escaping. |
404 | 396 |
|
405 |
- <%= Mojo::ByteStream->new('<div>excluded!</div>') %> |
|
397 |
+ % use Mojo::ByteStream 'b'; |
|
398 |
+ <%= b('<div>excluded!</div>') %> |
|
406 | 399 |
|
407 | 400 |
Newline characters can be escaped with a backslash. |
408 | 401 |
|
... | ... |
@@ -461,14 +454,14 @@ error messages with context. |
461 | 454 |
|
462 | 455 |
L<Mojo::Template> implements the following attributes. |
463 | 456 |
|
464 |
-=head2 C<auto_escape> |
|
457 |
+=head2 auto_escape |
|
465 | 458 |
|
466 | 459 |
my $escape = $mt->auto_escape; |
467 | 460 |
$mt = $mt->auto_escape(1); |
468 | 461 |
|
469 | 462 |
Activate automatic escaping. |
470 | 463 |
|
471 |
-=head2 C<append> |
|
464 |
+=head2 append |
|
472 | 465 |
|
473 | 466 |
my $code = $mt->append; |
474 | 467 |
$mt = $mt->append('warn "Processed template"'); |
... | ... |
@@ -477,7 +470,7 @@ Append Perl code to compiled template. Note that this code should not contain |
477 | 470 |
newline characters, or line numbers in error messages might end up being |
478 | 471 |
wrong. |
479 | 472 |
|
480 |
-=head2 C<capture_end> |
|
473 |
+=head2 capture_end |
|
481 | 474 |
|
482 | 475 |
my $end = $mt->capture_end; |
483 | 476 |
$mt = $mt->capture_end('end'); |
... | ... |
@@ -488,7 +481,7 @@ Keyword indicating the end of a capture block, defaults to C<end>. |
488 | 481 |
Some data! |
489 | 482 |
<% end %> |
490 | 483 |
|
491 |
-=head2 C<capture_start> |
|
484 |
+=head2 capture_start |
|
492 | 485 |
|
493 | 486 |
my $start = $mt->capture_start; |
494 | 487 |
$mt = $mt->capture_start('begin'); |
... | ... |
@@ -499,14 +492,14 @@ Keyword indicating the start of a capture block, defaults to C<begin>. |
499 | 492 |
Some data! |
500 | 493 |
<% end %> |
501 | 494 |
|
502 |
-=head2 C<code> |
|
495 |
+=head2 code |
|
503 | 496 |
|
504 | 497 |
my $code = $mt->code; |
505 | 498 |
$mt = $mt->code($code); |
506 | 499 |
|
507 | 500 |
Perl code for template. |
508 | 501 |
|
509 |
-=head2 C<comment_mark> |
|
502 |
+=head2 comment_mark |
|
510 | 503 |
|
511 | 504 |
my $mark = $mt->comment_mark; |
512 | 505 |
$mt = $mt->comment_mark('#'); |
... | ... |
@@ -515,21 +508,21 @@ Character indicating the start of a comment, defaults to C<#>. |
515 | 508 |
|
516 | 509 |
<%# This is a comment %> |
517 | 510 |
|
518 |
-=head2 C<compiled> |
|
511 |
+=head2 compiled |
|
519 | 512 |
|
520 | 513 |
my $compiled = $mt->compiled; |
521 | 514 |
$mt = $mt->compiled($compiled); |
522 | 515 |
|
523 | 516 |
Compiled template code. |
524 | 517 |
|
525 |
-=head2 C<encoding> |
|
518 |
+=head2 encoding |
|
526 | 519 |
|
527 | 520 |
my $encoding = $mt->encoding; |
528 | 521 |
$mt = $mt->encoding('UTF-8'); |
529 | 522 |
|
530 | 523 |
Encoding used for template files. |
531 | 524 |
|
532 |
-=head2 C<escape> |
|
525 |
+=head2 escape |
|
533 | 526 |
|
534 | 527 |
my $cb = $mt->escape; |
535 | 528 |
$mt = $mt->escape(sub { reverse $_[0] }); |
... | ... |
@@ -537,7 +530,7 @@ Encoding used for template files. |
537 | 530 |
A callback used to escape the results of escaped expressions, defaults to |
538 | 531 |
L<Mojo::Util/"xml_escape">. |
539 | 532 |
|
540 |
-=head2 C<escape_mark> |
|
533 |
+=head2 escape_mark |
|
541 | 534 |
|
542 | 535 |
my $mark = $mt->escape_mark; |
543 | 536 |
$mt = $mt->escape_mark('='); |
... | ... |
@@ -546,7 +539,7 @@ Character indicating the start of an escaped expression, defaults to C<=>. |
546 | 539 |
|
547 | 540 |
<%== $foo %> |
548 | 541 |
|
549 |
-=head2 C<expression_mark> |
|
542 |
+=head2 expression_mark |
|
550 | 543 |
|
551 | 544 |
my $mark = $mt->expression_mark; |
552 | 545 |
$mt = $mt->expression_mark('='); |
... | ... |
@@ -555,7 +548,7 @@ Character indicating the start of an expression, defaults to C<=>. |
555 | 548 |
|
556 | 549 |
<%= $foo %> |
557 | 550 |
|
558 |
-=head2 C<line_start> |
|
551 |
+=head2 line_start |
|
559 | 552 |
|
560 | 553 |
my $start = $mt->line_start; |
561 | 554 |
$mt = $mt->line_start('%'); |
... | ... |
@@ -564,7 +557,7 @@ Character indicating the start of a code line, defaults to C<%>. |
564 | 557 |
|
565 | 558 |
% $foo = 23; |
566 | 559 |
|
567 |
-=head2 C<name> |
|
560 |
+=head2 name |
|
568 | 561 |
|
569 | 562 |
my $name = $mt->name; |
570 | 563 |
$mt = $mt->name('foo.mt'); |
... | ... |
@@ -573,7 +566,7 @@ Name of template currently being processed, defaults to C<template>. Note that |
573 | 566 |
this value should not contain quotes or newline characters, or error messages |
574 | 567 |
might end up being wrong. |
575 | 568 |
|
576 |
-=head2 C<namespace> |
|
569 |
+=head2 namespace |
|
577 | 570 |
|
578 | 571 |
my $namespace = $mt->namespace; |
579 | 572 |
$mt = $mt->namespace('main'); |
... | ... |
@@ -582,7 +575,7 @@ Namespace used to compile templates, defaults to C<Mojo::Template::SandBox>. |
582 | 575 |
Note that namespaces should only be shared very carefully between templates, |
583 | 576 |
since functions and global variables will not be cleared automatically. |
584 | 577 |
|
585 |
-=head2 C<prepend> |
|
578 |
+=head2 prepend |
|
586 | 579 |
|
587 | 580 |
my $code = $mt->prepend; |
588 | 581 |
$mt = $mt->prepend('my $self = shift;'); |
... | ... |
@@ -591,7 +584,7 @@ Prepend Perl code to compiled template. Note that this code should not contain |
591 | 584 |
newline characters, or line numbers in error messages might end up being |
592 | 585 |
wrong. |
593 | 586 |
|
594 |
-=head2 C<replace_mark> |
|
587 |
+=head2 replace_mark |
|
595 | 588 |
|
596 | 589 |
my $mark = $mt->replace_mark; |
597 | 590 |
$mt = $mt->replace_mark('%'); |
... | ... |
@@ -600,7 +593,7 @@ Character used for escaping the start of a tag or line, defaults to C<%>. |
600 | 593 |
|
601 | 594 |
<%% my $foo = 23; %> |
602 | 595 |
|
603 |
-=head2 C<tag_start> |
|
596 |
+=head2 tag_start |
|
604 | 597 |
|
605 | 598 |
my $start = $mt->tag_start; |
606 | 599 |
$mt = $mt->tag_start('<%'); |
... | ... |
@@ -609,7 +602,7 @@ Characters indicating the start of a tag, defaults to C<E<lt>%>. |
609 | 602 |
|
610 | 603 |
<% $foo = 23; %> |
611 | 604 |
|
612 |
-=head2 C<tag_end> |
|
605 |
+=head2 tag_end |
|
613 | 606 |
|
614 | 607 |
my $end = $mt->tag_end; |
615 | 608 |
$mt = $mt->tag_end('%>'); |
... | ... |
@@ -618,21 +611,21 @@ Characters indicating the end of a tag, defaults to C<%E<gt>>. |
618 | 611 |
|
619 | 612 |
<%= $foo %> |
620 | 613 |
|
621 |
-=head2 C<template> |
|
614 |
+=head2 template |
|
622 | 615 |
|
623 | 616 |
my $template = $mt->template; |
624 | 617 |
$mt = $mt->template($template); |
625 | 618 |
|
626 | 619 |
Raw template. |
627 | 620 |
|
628 |
-=head2 C<tree> |
|
621 |
+=head2 tree |
|
629 | 622 |
|
630 | 623 |
my $tree = $mt->tree; |
631 | 624 |
$mt = $mt->tree($tree); |
632 | 625 |
|
633 | 626 |
Parsed tree. |
634 | 627 |
|
635 |
-=head2 C<trim_mark> |
|
628 |
+=head2 trim_mark |
|
636 | 629 |
|
637 | 630 |
my $mark = $mt->trim_mark; |
638 | 631 |
$mt = $mt->trim_mark('-'); |
... | ... |
@@ -646,25 +639,25 @@ Character activating automatic whitespace trimming, defaults to C<=>. |
646 | 639 |
L<Mojo::Template> inherits all methods from L<Mojo::Base> and implements the |
647 | 640 |
following new ones. |
648 | 641 |
|
649 |
-=head2 C<new> |
|
642 |
+=head2 new |
|
650 | 643 |
|
651 | 644 |
my $mt = Mojo::Template->new; |
652 | 645 |
|
653 | 646 |
Construct a new L<Mojo::Template> object. |
654 | 647 |
|
655 |
-=head2 C<build> |
|
648 |
+=head2 build |
|
656 | 649 |
|
657 | 650 |
$mt = $mt->build; |
658 | 651 |
|
659 | 652 |
Build Perl code from tree. |
660 | 653 |
|
661 |
-=head2 C<compile> |
|
654 |
+=head2 compile |
|
662 | 655 |
|
663 | 656 |
my $exception = $mt->compile; |
664 | 657 |
|
665 | 658 |
Compile Perl code for template. |
666 | 659 |
|
667 |
-=head2 C<interpret> |
|
660 |
+=head2 interpret |
|
668 | 661 |
|
669 | 662 |
my $output = $mt->interpret; |
670 | 663 |
my $output = $mt->interpret(@args); |
... | ... |
@@ -676,13 +669,13 @@ Interpret compiled template code. |
676 | 669 |
say $mt->interpret('Fry'); |
677 | 670 |
say $mt->interpret('Leela'); |
678 | 671 |
|
679 |
-=head2 C<parse> |
|
672 |
+=head2 parse |
|
680 | 673 |
|
681 | 674 |
$mt = $mt->parse($template); |
682 | 675 |
|
683 | 676 |
Parse template into tree. |
684 | 677 |
|
685 |
-=head2 C<render> |
|
678 |
+=head2 render |
|
686 | 679 |
|
687 | 680 |
my $output = $mt->render($template); |
688 | 681 |
my $output = $mt->render($template, @args); |
... | ... |
@@ -691,7 +684,7 @@ Render template. |
691 | 684 |
|
692 | 685 |
say $mt->render('Hello <%= $_[0] %>!', 'Bender'); |
693 | 686 |
|
694 |
-=head2 C<render_file> |
|
687 |
+=head2 render_file |
|
695 | 688 |
|
696 | 689 |
my $output = $mt->render_file('/tmp/foo.mt'); |
697 | 690 |
my $output = $mt->render_file('/tmp/foo.mt', @args); |
... | ... |
@@ -101,9 +101,10 @@ L<Mojo::Transaction> is an abstract base class for transactions. |
101 | 101 |
|
102 | 102 |
=head1 EVENTS |
103 | 103 |
|
104 |
-L<Mojo::Transaction> can emit the following events. |
|
104 |
+L<Mojo::Transaction> inherits all events from L<Mojo::EventEmitter> and can |
|
105 |
+emit the following new ones. |
|
105 | 106 |
|
106 |
-=head2 C<connection> |
|
107 |
+=head2 connection |
|
107 | 108 |
|
108 | 109 |
$tx->on(connection => sub { |
109 | 110 |
my ($tx, $connection) = @_; |
... | ... |
@@ -112,7 +113,7 @@ L<Mojo::Transaction> can emit the following events. |
112 | 113 |
|
113 | 114 |
Emitted when a connection has been assigned to transaction. |
114 | 115 |
|
115 |
-=head2 C<finish> |
|
116 |
+=head2 finish |
|
116 | 117 |
|
117 | 118 |
$tx->on(finish => sub { |
118 | 119 |
my $tx = shift; |
... | ... |
@@ -121,7 +122,7 @@ Emitted when a connection has been assigned to transaction. |
121 | 122 |
|
122 | 123 |
Emitted when transaction is finished. |
123 | 124 |
|
124 |
-=head2 C<resume> |
|
125 |
+=head2 resume |
|
125 | 126 |
|
126 | 127 |
$tx->on(resume => sub { |
127 | 128 |
my $tx = shift; |
... | ... |
@@ -134,28 +135,28 @@ Emitted when transaction is resumed. |
134 | 135 |
|
135 | 136 |
L<Mojo::Transaction> implements the following attributes. |
136 | 137 |
|
137 |
-=head2 C<kept_alive> |
|
138 |
+=head2 kept_alive |
|
138 | 139 |
|
139 | 140 |
my $kept_alive = $tx->kept_alive; |
140 | 141 |
$tx = $tx->kept_alive(1); |
141 | 142 |
|
142 | 143 |
Connection has been kept alive. |
143 | 144 |
|
144 |
-=head2 C<local_address> |
|
145 |
+=head2 local_address |
|
145 | 146 |
|
146 | 147 |
my $address = $tx->local_address; |
147 | 148 |
$tx = $tx->local_address('127.0.0.1'); |
148 | 149 |
|
149 | 150 |
Local interface address. |
150 | 151 |
|
151 |
-=head2 C<local_port> |
|
152 |
+=head2 local_port |
|
152 | 153 |
|
153 | 154 |
my $port = $tx->local_port; |
154 | 155 |
$tx = $tx->local_port(8080); |
155 | 156 |
|
156 | 157 |
Local interface port. |
157 | 158 |
|
158 |
-=head2 C<previous> |
|
159 |
+=head2 previous |
|
159 | 160 |
|
160 | 161 |
my $previous = $tx->previous; |
161 | 162 |
$tx = $tx->previous(Mojo::Transaction->new); |
... | ... |
@@ -165,21 +166,21 @@ Previous transaction that triggered this followup transaction. |
165 | 166 |
# Path of previous request |
166 | 167 |
say $tx->previous->req->url->path; |
167 | 168 |
|
168 |
-=head2 C<remote_port> |
|
169 |
+=head2 remote_port |
|
169 | 170 |
|
170 | 171 |
my $port = $tx->remote_port; |
171 | 172 |
$tx = $tx->remote_port(8081); |
172 | 173 |
|
173 | 174 |
Remote interface port. |
174 | 175 |
|
175 |
-=head2 C<req> |
|
176 |
+=head2 req |
|
176 | 177 |
|
177 | 178 |
my $req = $tx->req; |
178 | 179 |
$tx = $tx->req(Mojo::Message::Request->new); |
179 | 180 |
|
180 | 181 |
HTTP request, defaults to a L<Mojo::Message::Request> object. |
181 | 182 |
|
182 |
-=head2 C<res> |
|
183 |
+=head2 res |
|
183 | 184 |
|
184 | 185 |
my $res = $tx->res; |
185 | 186 |
$tx = $tx->res(Mojo::Message::Response->new); |
... | ... |
@@ -191,92 +192,92 @@ HTTP response, defaults to a L<Mojo::Message::Response> object. |
191 | 192 |
L<Mojo::Transaction> inherits all methods from L<Mojo::EventEmitter> and |
192 | 193 |
implements the following new ones. |
193 | 194 |
|
194 |
-=head2 C<client_close> |
|
195 |
+=head2 client_close |
|
195 | 196 |
|
196 | 197 |
$tx->client_close; |
197 | 198 |
|
198 | 199 |
Transaction closed client-side, used to implement user agents. |
199 | 200 |
|
200 |
-=head2 C<client_read> |
|
201 |
+=head2 client_read |
|
201 | 202 |
|
202 |
- $tx->client_read($chunk); |
|
203 |
+ $tx->client_read($bytes); |
|
203 | 204 |
|
204 | 205 |
Read data client-side, used to implement user agents. Meant to be overloaded |
205 | 206 |
in a subclass. |
206 | 207 |
|
207 |
-=head2 C<client_write> |
|
208 |
+=head2 client_write |
|
208 | 209 |
|
209 |
- my $chunk = $tx->client_write; |
|
210 |
+ my $bytes = $tx->client_write; |
|
210 | 211 |
|
211 | 212 |
Write data client-side, used to implement user agents. Meant to be overloaded |
212 | 213 |
in a subclass. |
213 | 214 |
|
214 |
-=head2 C<connection> |
|
215 |
+=head2 connection |
|
215 | 216 |
|
216 | 217 |
my $connection = $tx->connection; |
217 | 218 |
$tx = $tx->connection($connection); |
218 | 219 |
|
219 | 220 |
Connection identifier or socket. |
220 | 221 |
|
221 |
-=head2 C<error> |
|
222 |
+=head2 error |
|
222 | 223 |
|
223 | 224 |
my $err = $tx->error; |
224 | 225 |
my ($err, $code) = $tx->error; |
225 | 226 |
|
226 | 227 |
Error and code. |
227 | 228 |
|
228 |
-=head2 C<is_finished> |
|
229 |
+=head2 is_finished |
|
229 | 230 |
|
230 | 231 |
my $success = $tx->is_finished; |
231 | 232 |
|
232 | 233 |
Check if transaction is finished. |
233 | 234 |
|
234 |
-=head2 C<is_websocket> |
|
235 |
+=head2 is_websocket |
|
235 | 236 |
|
236 | 237 |
my $false = $tx->is_websocket; |
237 | 238 |
|
238 | 239 |
False. |
239 | 240 |
|
240 |
-=head2 C<is_writing> |
|
241 |
+=head2 is_writing |
|
241 | 242 |
|
242 | 243 |
my $success = $tx->is_writing; |
243 | 244 |
|
244 | 245 |
Check if transaction is writing. |
245 | 246 |
|
246 |
-=head2 C<resume> |
|
247 |
+=head2 resume |
|
247 | 248 |
|
248 | 249 |
$tx = $tx->resume; |
249 | 250 |
|
250 | 251 |
Resume transaction. |
251 | 252 |
|
252 |
-=head2 C<remote_address> |
|
253 |
+=head2 remote_address |
|
253 | 254 |
|
254 | 255 |
my $address = $tx->remote_address; |
255 | 256 |
$tx = $tx->remote_address('127.0.0.1'); |
256 | 257 |
|
257 | 258 |
Remote interface address. |
258 | 259 |
|
259 |
-=head2 C<server_close> |
|
260 |
+=head2 server_close |
|
260 | 261 |
|
261 | 262 |
$tx->server_close; |
262 | 263 |
|
263 | 264 |
Transaction closed server-side, used to implement web servers. |
264 | 265 |
|
265 |
-=head2 C<server_read> |
|
266 |
+=head2 server_read |
|
266 | 267 |
|
267 |
- $tx->server_read($chunk); |
|
268 |
+ $tx->server_read($bytes); |
|
268 | 269 |
|
269 | 270 |
Read data server-side, used to implement web servers. Meant to be overloaded |
270 | 271 |
in a subclass. |
271 | 272 |
|
272 |
-=head2 C<server_write> |
|
273 |
+=head2 server_write |
|
273 | 274 |
|
274 |
- my $chunk = $tx->server_write; |
|
275 |
+ my $bytes = $tx->server_write; |
|
275 | 276 |
|
276 | 277 |
Write data server-side, used to implement web servers. Meant to be overloaded |
277 | 278 |
in a subclass. |
278 | 279 |
|
279 |
-=head2 C<success> |
|
280 |
+=head2 success |
|
280 | 281 |
|
281 | 282 |
my $res = $tx->success; |
282 | 283 |
|
... | ... |
@@ -57,7 +57,7 @@ sub server_write { shift->_write(1) } |
57 | 57 |
sub _body { |
58 | 58 |
my ($self, $msg, $finish) = @_; |
59 | 59 |
|
60 |
- # Chunk |
|
60 |
+ # Prepare chunk |
|
61 | 61 |
my $buffer = $msg->get_body_chunk($self->{offset}); |
62 | 62 |
my $written = defined $buffer ? length $buffer : 0; |
63 | 63 |
$self->{write} = $msg->is_dynamic ? 1 : ($self->{write} - $written); |
... | ... |
@@ -80,7 +80,7 @@ sub _body { |
80 | 80 |
sub _headers { |
81 | 81 |
my ($self, $msg, $head) = @_; |
82 | 82 |
|
83 |
- # Chunk |
|
83 |
+ # Prepare chunk |
|
84 | 84 |
my $buffer = $msg->get_header_chunk($self->{offset}); |
85 | 85 |
my $written = defined $buffer ? length $buffer : 0; |
86 | 86 |
$self->{write} = $self->{write} - $written; |
... | ... |
@@ -107,7 +107,7 @@ sub _headers { |
107 | 107 |
sub _start_line { |
108 | 108 |
my ($self, $msg) = @_; |
109 | 109 |
|
110 |
- # Chunk |
|
110 |
+ # Prepare chunk |
|
111 | 111 |
my $buffer = $msg->get_start_line_chunk($self->{offset}); |
112 | 112 |
my $written = defined $buffer ? length $buffer : 0; |
113 | 113 |
$self->{write} = $self->{write} - $written; |
... | ... |
@@ -195,7 +195,7 @@ in RFC 2616. |
195 | 195 |
L<Mojo::Transaction::HTTP> inherits all events from L<Mojo::Transaction> and |
196 | 196 |
can emit the following new ones. |
197 | 197 |
|
198 |
-=head2 C<request> |
|
198 |
+=head2 request |
|
199 | 199 |
|
200 | 200 |
$tx->on(request => sub { |
201 | 201 |
my $tx = shift; |
... | ... |
@@ -209,7 +209,7 @@ Emitted when a request is ready and needs to be handled. |
209 | 209 |
$tx->res->headers->header('X-Bender' => 'Bite my shiny metal ass!'); |
210 | 210 |
}); |
211 | 211 |
|
212 |
-=head2 C<unexpected> |
|
212 |
+=head2 unexpected |
|
213 | 213 |
|
214 | 214 |
$tx->on(unexpected => sub { |
215 | 215 |
my ($tx, $res) = @_; |
... | ... |
@@ -223,7 +223,7 @@ Emitted for unexpected C<1xx> responses that will be ignored. |
223 | 223 |
$tx->res->on(finish => sub { say 'Followup response is finished.' }); |
224 | 224 |
}); |
225 | 225 |
|
226 |
-=head2 C<upgrade> |
|
226 |
+=head2 upgrade |
|
227 | 227 |
|
228 | 228 |
$tx->on(upgrade => sub { |
229 | 229 |
my ($tx, $ws) = @_; |
... | ... |
@@ -247,33 +247,33 @@ L<Mojo::Transaction::HTTP> inherits all attributes from L<Mojo::Transaction>. |
247 | 247 |
L<Mojo::Transaction::HTTP> inherits all methods from L<Mojo::Transaction> and |
248 | 248 |
implements the following new ones. |
249 | 249 |
|
250 |
-=head2 C<client_read> |
|
250 |
+=head2 client_read |
|
251 | 251 |
|
252 |
- $tx->client_read($chunk); |
|
252 |
+ $tx->client_read($bytes); |
|
253 | 253 |
|
254 | 254 |
Read data client-side, used to implement user agents. |
255 | 255 |
|
256 |
-=head2 C<client_write> |
|
256 |
+=head2 client_write |
|
257 | 257 |
|
258 |
- my $chunk = $tx->client_write; |
|
258 |
+ my $bytes = $tx->client_write; |
|
259 | 259 |
|
260 | 260 |
Write data client-side, used to implement user agents. |
261 | 261 |
|
262 |
-=head2 C<keep_alive> |
|
262 |
+=head2 keep_alive |
|
263 | 263 |
|
264 | 264 |
my $success = $tx->keep_alive; |
265 | 265 |
|
266 | 266 |
Check if connection can be kept alive. |
267 | 267 |
|
268 |
-=head2 C<server_read> |
|
268 |
+=head2 server_read |
|
269 | 269 |
|
270 |
- $tx->server_read($chunk); |
|
270 |
+ $tx->server_read($bytes); |
|
271 | 271 |
|
272 | 272 |
Read data server-side, used to implement web servers. |
273 | 273 |
|
274 |
-=head2 C<server_write> |
|
274 |
+=head2 server_write |
|
275 | 275 |
|
276 |
- my $chunk = $tx->server_write; |
|
276 |
+ my $bytes = $tx->server_write; |
|
277 | 277 |
|
278 | 278 |
Write data server-side, used to implement web servers. |
279 | 279 |
|
... | ... |
@@ -88,7 +88,6 @@ sub client_challenge { |
88 | 88 |
sub client_handshake { |
89 | 89 |
my $self = shift; |
90 | 90 |
|
91 |
- # Default headers |
|
92 | 91 |
my $headers = $self->req->headers; |
93 | 92 |
$headers->upgrade('websocket') unless $headers->upgrade; |
94 | 93 |
$headers->connection('Upgrade') unless $headers->connection; |
... | ... |
@@ -205,12 +204,10 @@ sub send { |
205 | 204 |
# Text |
206 | 205 |
elsif (!ref $frame) { $frame = [1, 0, 0, 0, TEXT, encode('UTF-8', $frame)] } |
207 | 206 |
|
208 |
- # Prepare frame |
|
209 | 207 |
$self->once(drain => $cb) if $cb; |
210 | 208 |
$self->{write} .= $self->build_frame(@$frame); |
211 | 209 |
$self->{state} = 'write'; |
212 | 210 |
|
213 |
- # Resume |
|
214 | 211 |
return $self->emit('resume'); |
215 | 212 |
} |
216 | 213 |
|
... | ... |
@@ -230,28 +227,23 @@ sub server_handshake { |
230 | 227 |
sub server_read { |
231 | 228 |
my ($self, $chunk) = @_; |
232 | 229 |
|
233 |
- # Parse frames |
|
234 | 230 |
$self->{read} .= defined $chunk ? $chunk : ''; |
235 | 231 |
while (my $frame = $self->parse_frame(\$self->{read})) { |
236 | 232 |
$self->emit(frame => $frame); |
237 | 233 |
} |
238 | 234 |
|
239 |
- # Resume |
|
240 | 235 |
$self->emit('resume'); |
241 | 236 |
} |
242 | 237 |
|
243 | 238 |
sub server_write { |
244 | 239 |
my $self = shift; |
245 | 240 |
|
246 |
- # Drain |
|
247 | 241 |
unless (length(defined $self->{write} ? $self->{write} : '')) { |
248 | 242 |
$self->{state} = $self->{finished} ? 'finished' : 'read'; |
249 | 243 |
$self->emit('drain'); |
250 | 244 |
} |
251 | 245 |
|
252 |
- # Empty buffer |
|
253 |
- my $chunk = delete $self->{write}; |
|
254 |
- return $chunk ? $chunk : ''; |
|
246 |
+ return do { my $tmp = delete $self->{write}; defined $tmp ? $tmp : '' }; |
|
255 | 247 |
} |
256 | 248 |
|
257 | 249 |
sub _challenge { b64_encode(sha1_bytes(($_[0] || '') . GUID), '') } |
... | ... |
@@ -280,7 +272,11 @@ sub _message { |
280 | 272 |
|
281 | 273 |
# Message |
282 | 274 |
my $msg = delete $self->{message}; |
283 |
- $msg = decode 'UTF-8', $msg if $msg && delete $self->{op} == TEXT; |
|
275 |
+ if (delete $self->{op} == TEXT) { |
|
276 |
+ $self->emit(text => $msg); |
|
277 |
+ $msg = decode 'UTF-8', $msg if $msg; |
|
278 |
+ } |
|
279 |
+ else { $self->emit(binary => $msg); } |
|
284 | 280 |
$self->emit(message => $msg); |
285 | 281 |
} |
286 | 282 |
|
... | ... |
@@ -317,7 +313,21 @@ integer support, or they are limited to 32bit. |
317 | 313 |
L<Mojo::Transaction::WebSocket> inherits all events from L<Mojo::Transaction> |
318 | 314 |
and can emit the following new ones. |
319 | 315 |
|
320 |
-=head2 C<drain> |
|
316 |
+=head2 binary |
|
317 |
+ |
|
318 |
+ $ws->on(binary => sub { |
|
319 |
+ my ($ws, $bytes) = @_; |
|
320 |
+ ... |
|
321 |
+ }); |
|
322 |
+ |
|
323 |
+Emitted when a complete WebSocket binary message has been received. |
|
324 |
+ |
|
325 |
+ $ws->on(binary => sub { |
|
326 |
+ my ($ws, $bytes) = @_; |
|
327 |
+ say "Binary: $bytes"; |
|
328 |
+ }); |
|
329 |
+ |
|
330 |
+=head2 drain |
|
321 | 331 |
|
322 | 332 |
$ws->on(drain => sub { |
323 | 333 |
my $ws = shift; |
... | ... |
@@ -331,7 +341,7 @@ Emitted once all data has been sent. |
331 | 341 |
$ws->send(time); |
332 | 342 |
}); |
333 | 343 |
|
334 |
-=head2 C<frame> |
|
344 |
+=head2 frame |
|
335 | 345 |
|
336 | 346 |
$ws->on(frame => sub { |
337 | 347 |
my ($ws, $frame) = @_; |
... | ... |
@@ -351,26 +361,41 @@ Emitted when a WebSocket frame has been received. |
351 | 361 |
say "Payload: $frame->[5]"; |
352 | 362 |
}); |
353 | 363 |
|
354 |
-=head2 C<message> |
|
364 |
+=head2 message |
|
355 | 365 |
|
356 | 366 |
$ws->on(message => sub { |
357 | 367 |
my ($ws, $msg) = @_; |
358 | 368 |
... |
359 | 369 |
}); |
360 | 370 |
|
361 |
-Emitted when a complete WebSocket message has been received. |
|
371 |
+Emitted when a complete WebSocket message has been received, text messages |
|
372 |
+will be automatically decoded. |
|
362 | 373 |
|
363 | 374 |
$ws->on(message => sub { |
364 | 375 |
my ($ws, $msg) = @_; |
365 | 376 |
say "Message: $msg"; |
366 | 377 |
}); |
367 | 378 |
|
379 |
+=head2 text |
|
380 |
+ |
|
381 |
+ $ws->on(text => sub { |
|
382 |
+ my ($ws, $bytes) = @_; |
|
383 |
+ ... |
|
384 |
+ }); |
|
385 |
+ |
|
386 |
+Emitted when a complete WebSocket text message has been received. |
|
387 |
+ |
|
388 |
+ $ws->on(text => sub { |
|
389 |
+ my ($ws, $bytes) = @_; |
|
390 |
+ say "Text: $bytes"; |
|
391 |
+ }); |
|
392 |
+ |
|
368 | 393 |
=head1 ATTRIBUTES |
369 | 394 |
|
370 | 395 |
L<Mojo::Transaction::WebSocket> inherits all attributes from |
371 | 396 |
L<Mojo::Transaction> and implements the following new ones. |
372 | 397 |
|
373 |
-=head2 C<handshake> |
|
398 |
+=head2 handshake |
|
374 | 399 |
|
375 | 400 |
my $handshake = $ws->handshake; |
376 | 401 |
$ws = $ws->handshake(Mojo::Transaction::HTTP->new); |
... | ... |
@@ -378,14 +403,14 @@ L<Mojo::Transaction> and implements the following new ones. |
378 | 403 |
The original handshake transaction, defaults to a L<Mojo::Transaction::HTTP> |
379 | 404 |
object. |
380 | 405 |
|
381 |
-=head2 C<masked> |
|
406 |
+=head2 masked |
|
382 | 407 |
|
383 | 408 |
my $masked = $ws->masked; |
384 | 409 |
$ws = $ws->masked(1); |
385 | 410 |
|
386 | 411 |
Mask outgoing frames with XOR cipher and a random 32bit key. |
387 | 412 |
|
388 |
-=head2 C<max_websocket_size> |
|
413 |
+=head2 max_websocket_size |
|
389 | 414 |
|
390 | 415 |
my $size = $ws->max_websocket_size; |
391 | 416 |
$ws = $ws->max_websocket_size(1024); |
... | ... |
@@ -398,7 +423,7 @@ C<MOJO_MAX_WEBSOCKET_SIZE> environment variable or C<262144>. |
398 | 423 |
L<Mojo::Transaction::WebSocket> inherits all methods from |
399 | 424 |
L<Mojo::Transaction> and implements the following new ones. |
400 | 425 |
|
401 |
-=head2 C<new> |
|
426 |
+=head2 new |
|
402 | 427 |
|
403 | 428 |
my $multi = Mojo::Content::MultiPart->new; |
404 | 429 |
|
... | ... |
@@ -406,7 +431,7 @@ Construct a new L<Mojo::Transaction::WebSocket> object and subscribe to |
406 | 431 |
C<frame> event with default message parser, which also handles C<PING> and |
407 | 432 |
C<CLOSE> frames automatically. |
408 | 433 |
|
409 |
-=head2 C<build_frame> |
|
434 |
+=head2 build_frame |
|
410 | 435 |
|
411 | 436 |
my $bytes = $ws->build_frame($fin, $rsv1, $rsv2, $rsv3, $op, $payload); |
412 | 437 |
|
... | ... |
@@ -430,68 +455,68 @@ Build WebSocket frame. |
430 | 455 |
# Pong frame with FIN bit and payload |
431 | 456 |
say $ws->build_frame(1, 0, 0, 0, 10, 'Test 123'); |
432 | 457 |
|
433 |
-=head2 C<client_challenge> |
|
458 |
+=head2 client_challenge |
|
434 | 459 |
|
435 | 460 |
my $success = $ws->client_challenge; |
436 | 461 |
|
437 | 462 |
Check WebSocket handshake challenge client-side, used to implement user |
438 | 463 |
agents. |
439 | 464 |
|
440 |
-=head2 C<client_handshake> |
|
465 |
+=head2 client_handshake |
|
441 | 466 |
|
442 | 467 |
$ws->client_handshake; |
443 | 468 |
|
444 | 469 |
Perform WebSocket handshake client-side, used to implement user agents. |
445 | 470 |
|
446 |
-=head2 C<client_read> |
|
471 |
+=head2 client_read |
|
447 | 472 |
|
448 | 473 |
$ws->client_read($data); |
449 | 474 |
|
450 | 475 |
Read data client-side, used to implement user agents. |
451 | 476 |
|
452 |
-=head2 C<client_write> |
|
477 |
+=head2 client_write |
|
453 | 478 |
|
454 |
- my $chunk = $ws->client_write; |
|
479 |
+ my $bytes = $ws->client_write; |
|
455 | 480 |
|
456 | 481 |
Write data client-side, used to implement user agents. |
457 | 482 |
|
458 |
-=head2 C<connection> |
|
483 |
+=head2 connection |
|
459 | 484 |
|
460 | 485 |
my $connection = $ws->connection; |
461 | 486 |
|
462 | 487 |
Connection identifier or socket. |
463 | 488 |
|
464 |
-=head2 C<finish> |
|
489 |
+=head2 finish |
|
465 | 490 |
|
466 | 491 |
$ws = $ws->finish; |
467 | 492 |
|
468 | 493 |
Finish the WebSocket connection gracefully. |
469 | 494 |
|
470 |
-=head2 C<is_websocket> |
|
495 |
+=head2 is_websocket |
|
471 | 496 |
|
472 | 497 |
my $true = $ws->is_websocket; |
473 | 498 |
|
474 | 499 |
True. |
475 | 500 |
|
476 |
-=head2 C<kept_alive> |
|
501 |
+=head2 kept_alive |
|
477 | 502 |
|
478 | 503 |
my $kept_alive = $ws->kept_alive; |
479 | 504 |
|
480 | 505 |
Connection has been kept alive. |
481 | 506 |
|
482 |
-=head2 C<local_address> |
|
507 |
+=head2 local_address |
|
483 | 508 |
|
484 | 509 |
my $address = $ws->local_address; |
485 | 510 |
|
486 | 511 |
Local interface address. |
487 | 512 |
|
488 |
-=head2 C<local_port> |
|
513 |
+=head2 local_port |
|
489 | 514 |
|
490 | 515 |
my $port = $ws->local_port; |
491 | 516 |
|
492 | 517 |
Local interface port. |
493 | 518 |
|
494 |
-=head2 C<parse_frame> |
|
519 |
+=head2 parse_frame |
|
495 | 520 |
|
496 | 521 |
my $frame = $ws->parse_frame(\$bytes); |
497 | 522 |
|
... | ... |
@@ -506,37 +531,37 @@ Parse WebSocket frame. |
506 | 531 |
say "Opcode: $frame->[4]"; |
507 | 532 |
say "Payload: $frame->[5]"; |
508 | 533 |
|
509 |
-=head2 C<remote_address> |
|
534 |
+=head2 remote_address |
|
510 | 535 |
|
511 | 536 |
my $address = $ws->remote_address; |
512 | 537 |
|
513 | 538 |
Remote interface address. |
514 | 539 |
|
515 |
-=head2 C<remote_port> |
|
540 |
+=head2 remote_port |
|
516 | 541 |
|
517 | 542 |
my $port = $ws->remote_port; |
518 | 543 |
|
519 | 544 |
Remote interface port. |
520 | 545 |
|
521 |
-=head2 C<req> |
|
546 |
+=head2 req |
|
522 | 547 |
|
523 | 548 |
my $req = $ws->req; |
524 | 549 |
|
525 | 550 |
Handshake request, usually a L<Mojo::Message::Request> object. |
526 | 551 |
|
527 |
-=head2 C<res> |
|
552 |
+=head2 res |
|
528 | 553 |
|
529 | 554 |
my $res = $ws->res; |
530 | 555 |
|
531 | 556 |
Handshake response, usually a L<Mojo::Message::Response> object. |
532 | 557 |
|
533 |
-=head2 C<resume> |
|
558 |
+=head2 resume |
|
534 | 559 |
|
535 | 560 |
$ws = $ws->resume; |
536 | 561 |
|
537 | 562 |
Resume C<handshake> transaction. |
538 | 563 |
|
539 |
-=head2 C<send> |
|
564 |
+=head2 send |
|
540 | 565 |
|
541 | 566 |
$ws = $ws->send({binary => $bytes}); |
542 | 567 |
$ws = $ws->send({text => $bytes}); |
... | ... |
@@ -550,21 +575,21 @@ will be invoked once all data has been written. |
550 | 575 |
# Send "Ping" frame |
551 | 576 |
$ws->send([1, 0, 0, 0, 9, 'Hello World!']); |
552 | 577 |
|
553 |
-=head2 C<server_handshake> |
|
578 |
+=head2 server_handshake |
|
554 | 579 |
|
555 | 580 |
$ws->server_handshake; |
556 | 581 |
|
557 | 582 |
Perform WebSocket handshake server-side, used to implement web servers. |
558 | 583 |
|
559 |
-=head2 C<server_read> |
|
584 |
+=head2 server_read |
|
560 | 585 |
|
561 | 586 |
$ws->server_read($data); |
562 | 587 |
|
563 | 588 |
Read data server-side, used to implement web servers. |
564 | 589 |
|
565 |
-=head2 C<server_write> |
|
590 |
+=head2 server_write |
|
566 | 591 |
|
567 |
- my $chunk = $ws->server_write; |
|
592 |
+ my $bytes = $ws->server_write; |
|
568 | 593 |
|
569 | 594 |
Write data server-side, used to implement web servers. |
570 | 595 |
|
... | ... |
@@ -31,7 +31,7 @@ sub authority { |
31 | 31 |
return $host =~ /[^\x00-\x7f]/ ? $self->ihost($host) : $self->host($host); |
32 | 32 |
} |
33 | 33 |
|
34 |
- # Format |
|
34 |
+ # Build authority |
|
35 | 35 |
my $userinfo = $self->userinfo; |
36 | 36 |
$authority .= url_escape($userinfo, '^A-Za-z0-9\-._~!$&\'()*+,;=:') . '@' |
37 | 37 |
if $userinfo; |
... | ... |
@@ -137,7 +137,6 @@ sub query { |
137 | 137 |
sub to_abs { |
138 | 138 |
my $self = shift; |
139 | 139 |
|
140 |
- # Already absolute |
|
141 | 140 |
my $abs = $self->clone; |
142 | 141 |
return $abs if $abs->is_abs; |
143 | 142 |
|
... | ... |
@@ -173,7 +172,6 @@ sub to_abs { |
173 | 172 |
sub to_rel { |
174 | 173 |
my $self = shift; |
175 | 174 |
|
176 |
- # Already relative |
|
177 | 175 |
my $rel = $self->clone; |
178 | 176 |
return $rel unless $rel->is_abs; |
179 | 177 |
|
... | ... |
@@ -274,42 +272,42 @@ Resource Locators with support for IDNA and IRIs. |
274 | 272 |
|
275 | 273 |
L<Mojo::URL> implements the following attributes. |
276 | 274 |
|
277 |
-=head2 C<base> |
|
275 |
+=head2 base |
|
278 | 276 |
|
279 | 277 |
my $base = $url->base; |
280 | 278 |
$url = $url->base(Mojo::URL->new); |
281 | 279 |
|
282 | 280 |
Base of this URL. |
283 | 281 |
|
284 |
-=head2 C<fragment> |
|
282 |
+=head2 fragment |
|
285 | 283 |
|
286 | 284 |
my $fragment = $url->fragment; |
287 | 285 |
$url = $url->fragment('foo'); |
288 | 286 |
|
289 | 287 |
Fragment part of this URL. |
290 | 288 |
|
291 |
-=head2 C<host> |
|
289 |
+=head2 host |
|
292 | 290 |
|
293 | 291 |
my $host = $url->host; |
294 | 292 |
$url = $url->host('127.0.0.1'); |
295 | 293 |
|
296 | 294 |
Host part of this URL. |
297 | 295 |
|
298 |
-=head2 C<port> |
|
296 |
+=head2 port |
|
299 | 297 |
|
300 | 298 |
my $port = $url->port; |
301 | 299 |
$url = $url->port(8080); |
302 | 300 |
|
303 | 301 |
Port part of this URL. |
304 | 302 |
|
305 |
-=head2 C<scheme> |
|
303 |
+=head2 scheme |
|
306 | 304 |
|
307 | 305 |
my $scheme = $url->scheme; |
308 | 306 |
$url = $url->scheme('http'); |
309 | 307 |
|
310 | 308 |
Scheme part of this URL. |
311 | 309 |
|
312 |
-=head2 C<userinfo> |
|
310 |
+=head2 userinfo |
|
313 | 311 |
|
314 | 312 |
my $userinfo = $url->userinfo; |
315 | 313 |
$url = $url->userinfo('root:pass%3Bw0rd'); |
... | ... |
@@ -321,27 +319,27 @@ Userinfo part of this URL. |
321 | 319 |
L<Mojo::URL> inherits all methods from L<Mojo::Base> and implements the |
322 | 320 |
following new ones. |
323 | 321 |
|
324 |
-=head2 C<new> |
|
322 |
+=head2 new |
|
325 | 323 |
|
326 | 324 |
my $url = Mojo::URL->new; |
327 | 325 |
my $url = Mojo::URL->new('http://127.0.0.1:3000/foo?f=b&baz=2#foo'); |
328 | 326 |
|
329 | 327 |
Construct a new L<Mojo::URL> object. |
330 | 328 |
|
331 |
-=head2 C<authority> |
|
329 |
+=head2 authority |
|
332 | 330 |
|
333 | 331 |
my $authority = $url->authority; |
334 | 332 |
$url = $url->authority('root:pass%3Bw0rd@localhost:8080'); |
335 | 333 |
|
336 | 334 |
Authority part of this URL. |
337 | 335 |
|
338 |
-=head2 C<clone> |
|
336 |
+=head2 clone |
|
339 | 337 |
|
340 | 338 |
my $url2 = $url->clone; |
341 | 339 |
|
342 | 340 |
Clone this URL. |
343 | 341 |
|
344 |
-=head2 C<ihost> |
|
342 |
+=head2 ihost |
|
345 | 343 |
|
346 | 344 |
my $ihost = $url->ihost; |
347 | 345 |
$url = $url->ihost('xn--bcher-kva.ch'); |
... | ... |
@@ -351,19 +349,19 @@ Host part of this URL in punycode format. |
351 | 349 |
# "xn--da5b0n.net" |
352 | 350 |
Mojo::URL->new('http://☃.net')->ihost; |
353 | 351 |
|
354 |
-=head2 C<is_abs> |
|
352 |
+=head2 is_abs |
|
355 | 353 |
|
356 | 354 |
my $success = $url->is_abs; |
357 | 355 |
|
358 | 356 |
Check if URL is absolute. |
359 | 357 |
|
360 |
-=head2 C<parse> |
|
358 |
+=head2 parse |
|
361 | 359 |
|
362 | 360 |
$url = $url->parse('http://127.0.0.1:3000/foo/bar?fo=o&baz=23#foo'); |
363 | 361 |
|
364 | 362 |
Parse URL. |
365 | 363 |
|
366 |
-=head2 C<path> |
|
364 |
+=head2 path |
|
367 | 365 |
|
368 | 366 |
my $path = $url->path; |
369 | 367 |
$url = $url->path('/foo/bar'); |
... | ... |
@@ -382,7 +380,7 @@ defaults to a L<Mojo::Path> object. |
382 | 380 |
# "http://mojolicio.us/perldoc/Mojo/DOM/HTML" |
383 | 381 |
Mojo::URL->new('http://mojolicio.us/perldoc/Mojo/')->path('DOM/HTML'); |
384 | 382 |
|
385 |
-=head2 C<protocol> |
|
383 |
+=head2 protocol |
|
386 | 384 |
|
387 | 385 |
my $proto = $url->protocol; |
388 | 386 |
|
... | ... |
@@ -391,7 +389,7 @@ Normalized version of C<scheme>. |
391 | 389 |
# "http" |
392 | 390 |
Mojo::URL->new('HtTp://mojolicio.us')->protocol; |
393 | 391 |
|
394 |
-=head2 C<query> |
|
392 |
+=head2 query |
|
395 | 393 |
|
396 | 394 |
my $query = $url->query; |
397 | 395 |
$url = $url->query(replace => 'with'); |
... | ... |
@@ -419,21 +417,21 @@ Query part of this URL, defaults to a L<Mojo::Parameters> object. |
419 | 417 |
# "http://mojolicio.us?a=1&b=2&a=2&c=3" |
420 | 418 |
Mojo::URL->new('http://mojolicio.us?a=1&b=2')->query({a => 2, c => 3}); |
421 | 419 |
|
422 |
-=head2 C<to_abs> |
|
420 |
+=head2 to_abs |
|
423 | 421 |
|
424 | 422 |
my $abs = $url->to_abs; |
425 | 423 |
my $abs = $url->to_abs(Mojo::URL->new('http://kraih.com/foo')); |
426 | 424 |
|
427 | 425 |
Clone relative URL and turn it into an absolute one. |
428 | 426 |
|
429 |
-=head2 C<to_rel> |
|
427 |
+=head2 to_rel |
|
430 | 428 |
|
431 | 429 |
my $rel = $url->to_rel; |
432 | 430 |
my $rel = $url->to_rel(Mojo::URL->new('http://kraih.com/foo')); |
433 | 431 |
|
434 | 432 |
Clone absolute URL and turn it into a relative one. |
435 | 433 |
|
436 |
-=head2 C<to_string> |
|
434 |
+=head2 to_string |
|
437 | 435 |
|
438 | 436 |
my $string = $url->to_string; |
439 | 437 |
my $string = "$url"; |
... | ... |
@@ -40,28 +40,28 @@ L<Mojo::Upload> is a container for uploaded files. |
40 | 40 |
|
41 | 41 |
L<Mojo::Upload> implements the following attributes. |
42 | 42 |
|
43 |
-=head2 C<asset> |
|
43 |
+=head2 asset |
|
44 | 44 |
|
45 | 45 |
my $asset = $upload->asset; |
46 | 46 |
$upload = $upload->asset(Mojo::Asset::File->new); |
47 | 47 |
|
48 | 48 |
Asset containing the uploaded data, defaults to a L<Mojo::Asset::File> object. |
49 | 49 |
|
50 |
-=head2 C<filename> |
|
50 |
+=head2 filename |
|
51 | 51 |
|
52 | 52 |
my $filename = $upload->filename; |
53 | 53 |
$upload = $upload->filename('foo.txt'); |
54 | 54 |
|
55 | 55 |
Name of the uploaded file. |
56 | 56 |
|
57 |
-=head2 C<headers> |
|
57 |
+=head2 headers |
|
58 | 58 |
|
59 | 59 |
my $headers = $upload->headers; |
60 | 60 |
$upload = $upload->headers(Mojo::Headers->new); |
61 | 61 |
|
62 | 62 |
Headers for upload, defaults to a L<Mojo::Headers> object. |
63 | 63 |
|
64 |
-=head2 C<name> |
|
64 |
+=head2 name |
|
65 | 65 |
|
66 | 66 |
my $name = $upload->name; |
67 | 67 |
$upload = $upload->name('foo'); |
... | ... |
@@ -73,21 +73,21 @@ Name of the upload. |
73 | 73 |
L<Mojo::Upload> inherits all methods from L<Mojo::Base> and implements the |
74 | 74 |
following new ones. |
75 | 75 |
|
76 |
-=head2 C<move_to> |
|
76 |
+=head2 move_to |
|
77 | 77 |
|
78 | 78 |
$upload = $upload->move_to('/home/sri/foo.txt'); |
79 | 79 |
|
80 | 80 |
Move uploaded data into a specific file. |
81 | 81 |
|
82 |
-=head2 C<size> |
|
82 |
+=head2 size |
|
83 | 83 |
|
84 | 84 |
my $size = $upload->size; |
85 | 85 |
|
86 | 86 |
Size of uploaded data in bytes. |
87 | 87 |
|
88 |
-=head2 C<slurp> |
|
88 |
+=head2 slurp |
|
89 | 89 |
|
90 |
- my $string = $upload->slurp; |
|
90 |
+ my $bytes = $upload->slurp; |
|
91 | 91 |
|
92 | 92 |
Read all uploaded data at once. |
93 | 93 |
|
... | ... |
@@ -99,18 +99,19 @@ sub start { |
99 | 99 |
unless ($self->{nb}) { |
100 | 100 |
croak 'Blocking request in progress' if keys %{$self->{connections}}; |
101 | 101 |
warn "-- Switching to non-blocking mode\n" if DEBUG; |
102 |
+ $self->_cleanup; |
|
102 | 103 |
$self->{nb}++; |
103 |
- $self->_cleanup(1); |
|
104 | 104 |
} |
105 | 105 |
return $self->_start($tx, $cb); |
106 | 106 |
} |
107 | 107 |
|
108 | 108 |
# Start blocking |
109 | 109 |
warn "-- Blocking request (@{[$tx->req->url->to_abs]})\n" if DEBUG; |
110 |
- if (delete $self->{nb}) { |
|
110 |
+ if ($self->{nb}) { |
|
111 | 111 |
croak 'Non-blocking requests in progress' if keys %{$self->{connections}}; |
112 | 112 |
warn "-- Switching to blocking mode\n" if DEBUG; |
113 |
- $self->_cleanup(1); |
|
113 |
+ $self->_cleanup; |
|
114 |
+ delete $self->{nb}; |
|
114 | 115 |
} |
115 | 116 |
$self->_start($tx => sub { $tx = pop }); |
116 | 117 |
|
... | ... |
@@ -159,7 +160,7 @@ sub _cache { |
159 | 160 |
} |
160 | 161 |
|
161 | 162 |
sub _cleanup { |
162 |
- my ($self, $restart) = @_; |
|
163 |
+ my $self = shift; |
|
163 | 164 |
return unless my $loop = $self->_loop; |
164 | 165 |
|
165 | 166 |
# Clean up active connections (by closing them) |
... | ... |
@@ -168,15 +169,13 @@ sub _cleanup { |
168 | 169 |
# Clean up keep alive connections |
169 | 170 |
$loop->remove($_->[1]) for @{delete $self->{cache} || []}; |
170 | 171 |
|
171 |
- # Stop or restart server |
|
172 |
+ # Stop server |
|
172 | 173 |
delete $self->{server}; |
173 |
- $self->_server if $restart; |
|
174 | 174 |
} |
175 | 175 |
|
176 | 176 |
sub _connect { |
177 | 177 |
my ($self, $proto, $host, $port, $handle, $cb) = @_; |
178 | 178 |
|
179 |
- # Open connection |
|
180 | 179 |
weaken $self; |
181 | 180 |
my $id; |
182 | 181 |
return $id = $self->_loop->client( |
... | ... |
@@ -301,7 +300,6 @@ sub _finish { |
301 | 300 |
my $res = $tx->res; |
302 | 301 |
if (my $err = $res->error) { $res->error($err) } |
303 | 302 |
|
304 |
- # Common errors |
|
305 | 303 |
else { |
306 | 304 |
|
307 | 305 |
# Premature connection close |
... | ... |
@@ -335,6 +333,7 @@ sub _handle { |
335 | 333 |
|
336 | 334 |
# Upgrade connection to WebSocket |
337 | 335 |
elsif ($old && (my $new = $self->_upgrade($id))) { |
336 |
+ if (my $jar = $self->cookie_jar) { $jar->extract($old) } |
|
338 | 337 |
$old->client_close; |
339 | 338 |
$self->_finish($new, $c->{cb}); |
340 | 339 |
$new->client_read($old->res->leftovers); |
... | ... |
@@ -387,13 +386,12 @@ sub _remove { |
387 | 386 |
sub _redirect { |
388 | 387 |
my ($self, $c, $old) = @_; |
389 | 388 |
|
390 |
- # Try to build followup transaction |
|
391 |
- return undef unless my $new = $self->transactor->redirect($old); |
|
392 |
- |
|
393 | 389 |
# Follow redirect unless the maximum has been reached already |
390 |
+ return undef unless my $new = $self->transactor->redirect($old); |
|
394 | 391 |
my $redirects = delete $c->{redirects} || 0; |
395 | 392 |
return undef unless $redirects < $self->max_redirects; |
396 | 393 |
my $id = $self->_start($new, delete $c->{cb}); |
394 |
+ |
|
397 | 395 |
return $self->{connections}{$id}{redirects} = $redirects + 1; |
398 | 396 |
} |
399 | 397 |
|
... | ... |
@@ -444,7 +442,7 @@ sub _start { |
444 | 442 |
# We identify ourselves and accept gzip compression |
445 | 443 |
my $headers = $req->headers; |
446 | 444 |
$headers->user_agent($self->name) unless $headers->user_agent; |
447 |
- $headers->accept_encoding('gzip') unless $headers->accept_encoding && $Compress::Raw::Zlib::VERSION; |
|
445 |
+ $headers->accept_encoding('gzip') if (! $headers->accept_encoding && $Compress::Raw::Zlib::VERSION); |
|
448 | 446 |
if (my $jar = $self->cookie_jar) { $jar->inject($tx) } |
449 | 447 |
|
450 | 448 |
# Connect and add request timeout if necessary |
... | ... |
@@ -461,18 +459,18 @@ sub _start { |
461 | 459 |
sub _upgrade { |
462 | 460 |
my ($self, $id) = @_; |
463 | 461 |
|
464 |
- # Try to upgrade transaction |
|
465 | 462 |
my $c = $self->{connections}{$id}; |
466 | 463 |
return undef unless my $new = $self->transactor->upgrade($c->{tx}); |
467 | 464 |
weaken $self; |
468 | 465 |
$new->on(resume => sub { $self->_write($id) }); |
466 |
+ |
|
469 | 467 |
return $c->{tx} = $new; |
470 | 468 |
} |
471 | 469 |
|
472 | 470 |
sub _write { |
473 | 471 |
my ($self, $id) = @_; |
474 | 472 |
|
475 |
- # Get chunk |
|
473 |
+ # Get and write chunk |
|
476 | 474 |
return unless my $c = $self->{connections}{$id}; |
477 | 475 |
return unless my $tx = $c->{tx}; |
478 | 476 |
return unless $tx->is_writing; |
... | ... |
@@ -480,8 +478,6 @@ sub _write { |
480 | 478 |
my $chunk = $tx->client_write; |
481 | 479 |
delete $c->{writing}; |
482 | 480 |
warn "-- Client >>> Server (@{[$tx->req->url->to_abs]})\n$chunk\n" if DEBUG; |
483 |
- |
|
484 |
- # Write chunk |
|
485 | 481 |
my $stream = $self->_loop->stream($id)->write($chunk); |
486 | 482 |
$self->_handle($id) if $tx->is_finished; |
487 | 483 |
|
... | ... |
@@ -596,9 +592,10 @@ See L<Mojolicious::Guides::Cookbook> for more. |
596 | 592 |
|
597 | 593 |
=head1 EVENTS |
598 | 594 |
|
599 |
-L<Mojo::UserAgent> can emit the following events. |
|
595 |
+L<Mojo::UserAgent> inherits all events from L<Mojo::EventEmitter> and can emit |
|
596 |
+the following new ones. |
|
600 | 597 |
|
601 |
-=head2 C<error> |
|
598 |
+=head2 error |
|
602 | 599 |
|
603 | 600 |
$ua->on(error => sub { |
604 | 601 |
my ($ua, $err) = @_; |
... | ... |
@@ -612,7 +609,7 @@ Emitted if an error occurs that can't be associated with a transaction. |
612 | 609 |
say "This looks bad: $err"; |
613 | 610 |
}); |
614 | 611 |
|
615 |
-=head2 C<start> |
|
612 |
+=head2 start |
|
616 | 613 |
|
617 | 614 |
$ua->on(start => sub { |
618 | 615 |
my ($ua, $tx) = @_; |
... | ... |
@@ -631,7 +628,7 @@ automatically prepared proxy C<CONNECT> requests and followed redirects. |
631 | 628 |
|
632 | 629 |
L<Mojo::UserAgent> implements the following attributes. |
633 | 630 |
|
634 |
-=head2 C<ca> |
|
631 |
+=head2 ca |
|
635 | 632 |
|
636 | 633 |
my $ca = $ua->ca; |
637 | 634 |
$ua = $ua->ca('/etc/tls/ca.crt'); |
... | ... |
@@ -643,7 +640,7 @@ C<MOJO_CA_FILE> environment variable. Also activates hostname verification. |
643 | 640 |
IO::Socket::SSL::set_defaults( |
644 | 641 |
SSL_verify_callback => sub { say "Authority: $_[2]" and return $_[0] }); |
645 | 642 |
|
646 |
-=head2 C<cert> |
|
643 |
+=head2 cert |
|
647 | 644 |
|
648 | 645 |
my $cert = $ua->cert; |
649 | 646 |
$ua = $ua->cert('/etc/tls/client.crt'); |
... | ... |
@@ -651,7 +648,7 @@ C<MOJO_CA_FILE> environment variable. Also activates hostname verification. |
651 | 648 |
Path to TLS certificate file, defaults to the value of the C<MOJO_CERT_FILE> |
652 | 649 |
environment variable. |
653 | 650 |
|
654 |
-=head2 C<connect_timeout> |
|
651 |
+=head2 connect_timeout |
|
655 | 652 |
|
656 | 653 |
my $timeout = $ua->connect_timeout; |
657 | 654 |
$ua = $ua->connect_timeout(5); |
... | ... |
@@ -660,7 +657,7 @@ Maximum amount of time in seconds establishing a connection may take before |
660 | 657 |
getting canceled, defaults to the value of the C<MOJO_CONNECT_TIMEOUT> |
661 | 658 |
environment variable or C<10>. |
662 | 659 |
|
663 |
-=head2 C<cookie_jar> |
|
660 |
+=head2 cookie_jar |
|
664 | 661 |
|
665 | 662 |
my $cookie_jar = $ua->cookie_jar; |
666 | 663 |
$ua = $ua->cookie_jar(Mojo::UserAgent::CookieJar->new); |
... | ... |
@@ -671,21 +668,21 @@ L<Mojo::UserAgent::CookieJar> object. |
671 | 668 |
# Disable cookie jar |
672 | 669 |
$ua->cookie_jar(0); |
673 | 670 |
|
674 |
-=head2 C<http_proxy> |
|
671 |
+=head2 http_proxy |
|
675 | 672 |
|
676 | 673 |
my $proxy = $ua->http_proxy; |
677 | 674 |
$ua = $ua->http_proxy('http://sri:secret@127.0.0.1:8080'); |
678 | 675 |
|
679 | 676 |
Proxy server to use for HTTP and WebSocket requests. |
680 | 677 |
|
681 |
-=head2 C<https_proxy> |
|
678 |
+=head2 https_proxy |
|
682 | 679 |
|
683 | 680 |
my $proxy = $ua->https_proxy; |
684 | 681 |
$ua = $ua->https_proxy('http://sri:secret@127.0.0.1:8080'); |
685 | 682 |
|
686 | 683 |
Proxy server to use for HTTPS and WebSocket requests. |
687 | 684 |
|
688 |
-=head2 C<inactivity_timeout> |
|
685 |
+=head2 inactivity_timeout |
|
689 | 686 |
|
690 | 687 |
my $timeout = $ua->inactivity_timeout; |
691 | 688 |
$ua = $ua->inactivity_timeout(15); |
... | ... |
@@ -695,7 +692,7 @@ closed, defaults to the value of the C<MOJO_INACTIVITY_TIMEOUT> environment |
695 | 692 |
variable or C<20>. Setting the value to C<0> will allow connections to be |
696 | 693 |
inactive indefinitely. |
697 | 694 |
|
698 |
-=head2 C<ioloop> |
|
695 |
+=head2 ioloop |
|
699 | 696 |
|
700 | 697 |
my $loop = $ua->ioloop; |
701 | 698 |
$ua = $ua->ioloop(Mojo::IOLoop->new); |
... | ... |
@@ -703,7 +700,7 @@ inactive indefinitely. |
703 | 700 |
Event loop object to use for blocking I/O operations, defaults to a |
704 | 701 |
L<Mojo::IOLoop> object. |
705 | 702 |
|
706 |
-=head2 C<key> |
|
703 |
+=head2 key |
|
707 | 704 |
|
708 | 705 |
my $key = $ua->key; |
709 | 706 |
$ua = $ua->key('/etc/tls/client.crt'); |
... | ... |
@@ -711,14 +708,14 @@ L<Mojo::IOLoop> object. |
711 | 708 |
Path to TLS key file, defaults to the value of the C<MOJO_KEY_FILE> |
712 | 709 |
environment variable. |
713 | 710 |
|
714 |
-=head2 C<local_address> |
|
711 |
+=head2 local_address |
|
715 | 712 |
|
716 | 713 |
my $address = $ua->local_address; |
717 | 714 |
$ua = $ua->local_address('127.0.0.1'); |
718 | 715 |
|
719 | 716 |
Local address to bind to. |
720 | 717 |
|
721 |
-=head2 C<max_connections> |
|
718 |
+=head2 max_connections |
|
722 | 719 |
|
723 | 720 |
my $max = $ua->max_connections; |
724 | 721 |
$ua = $ua->max_connections(5); |
... | ... |
@@ -726,7 +723,7 @@ Local address to bind to. |
726 | 723 |
Maximum number of keep alive connections that the user agent will retain |
727 | 724 |
before it starts closing the oldest cached ones, defaults to C<5>. |
728 | 725 |
|
729 |
-=head2 C<max_redirects> |
|
726 |
+=head2 max_redirects |
|
730 | 727 |
|
731 | 728 |
my $max = $ua->max_redirects; |
732 | 729 |
$ua = $ua->max_redirects(3); |
... | ... |
@@ -735,21 +732,21 @@ Maximum number of redirects the user agent will follow before it fails, |
735 | 732 |
defaults to the value of the C<MOJO_MAX_REDIRECTS> environment variable or |
736 | 733 |
C<0>. |
737 | 734 |
|
738 |
-=head2 C<name> |
|
735 |
+=head2 name |
|
739 | 736 |
|
740 | 737 |
my $name = $ua->name; |
741 | 738 |
$ua = $ua->name('Mojolicious'); |
742 | 739 |
|
743 | 740 |
Value for C<User-Agent> request header, defaults to C<Mojolicious (Perl)>. |
744 | 741 |
|
745 |
-=head2 C<no_proxy> |
|
742 |
+=head2 no_proxy |
|
746 | 743 |
|
747 | 744 |
my $no_proxy = $ua->no_proxy; |
748 | 745 |
$ua = $ua->no_proxy([qw(localhost intranet.mojolicio.us)]); |
749 | 746 |
|
750 | 747 |
Domains that don't require a proxy server to be used. |
751 | 748 |
|
752 |
-=head2 C<request_timeout> |
|
749 |
+=head2 request_timeout |
|
753 | 750 |
|
754 | 751 |
my $timeout = $ua->request_timeout; |
755 | 752 |
$ua = $ua->request_timeout(5); |
... | ... |
@@ -763,7 +760,7 @@ indefinitely. The timeout will reset for every followed redirect. |
763 | 760 |
# Total limit of 5 seconds, of which 3 seconds may be spent connecting |
764 | 761 |
$ua->max_redirects(0)->connect_timeout(3)->request_timeout(5); |
765 | 762 |
|
766 |
-=head2 C<transactor> |
|
763 |
+=head2 transactor |
|
767 | 764 |
|
768 | 765 |
my $t = $ua->transactor; |
769 | 766 |
$ua = $ua->transactor(Mojo::UserAgent::Transactor->new); |
... | ... |
@@ -775,7 +772,7 @@ Transaction builder, defaults to a L<Mojo::UserAgent::Transactor> object. |
775 | 772 |
L<Mojo::UserAgent> inherits all methods from L<Mojo::EventEmitter> and |
776 | 773 |
implements the following new ones. |
777 | 774 |
|
778 |
-=head2 C<app> |
|
775 |
+=head2 app |
|
779 | 776 |
|
780 | 777 |
my $app = Mojo::UserAgent->app; |
781 | 778 |
Mojo::UserAgent->app(MyApp->new); |
... | ... |
@@ -794,7 +791,7 @@ applications override the global default. |
794 | 791 |
# Change application behavior |
795 | 792 |
$ua->app->defaults(testing => 'oh yea!'); |
796 | 793 |
|
797 |
-=head2 C<app_url> |
|
794 |
+=head2 app_url |
|
798 | 795 |
|
799 | 796 |
my $url = $ua->app_url; |
800 | 797 |
my $url = $ua->app_url('http'); |
... | ... |
@@ -805,7 +802,7 @@ Get absolute L<Mojo::URL> object for C<app> and switch protocol if necessary. |
805 | 802 |
# Port currently used for processing relative URLs |
806 | 803 |
say $ua->app_url->port; |
807 | 804 |
|
808 |
-=head2 C<build_form_tx> |
|
805 |
+=head2 build_form_tx |
|
809 | 806 |
|
810 | 807 |
my $tx = $ua->build_form_tx('http://kraih.com' => {a => 'b'}); |
811 | 808 |
my $tx = $ua->build_form_tx('kraih.com', 'UTF-8', {a => 'b'}, {DNT => 1}); |
... | ... |
@@ -813,7 +810,7 @@ Get absolute L<Mojo::URL> object for C<app> and switch protocol if necessary. |
813 | 810 |
Generate L<Mojo::Transaction::HTTP> object with |
814 | 811 |
L<Mojo::UserAgent::Transactor/"form">. |
815 | 812 |
|
816 |
-=head2 C<build_json_tx> |
|
813 |
+=head2 build_json_tx |
|
817 | 814 |
|
818 | 815 |
my $tx = $ua->build_json_tx('http://kraih.com' => {a => 'b'}); |
819 | 816 |
my $tx = $ua->build_json_tx('kraih.com' => {a => 'b'} => {DNT => 1}); |
... | ... |
@@ -821,7 +818,7 @@ L<Mojo::UserAgent::Transactor/"form">. |
821 | 818 |
Generate L<Mojo::Transaction::HTTP> object with |
822 | 819 |
L<Mojo::UserAgent::Transactor/"json">. |
823 | 820 |
|
824 |
-=head2 C<build_tx> |
|
821 |
+=head2 build_tx |
|
825 | 822 |
|
826 | 823 |
my $tx = $ua->build_tx(GET => 'kraih.com'); |
827 | 824 |
my $tx = $ua->build_tx(PUT => 'http://kraih.com' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -834,7 +831,7 @@ L<Mojo::UserAgent::Transactor/"tx">. |
834 | 831 |
$tx->req->cookies({name => 'foo', value => 'bar'}); |
835 | 832 |
$ua->start($tx); |
836 | 833 |
|
837 |
-=head2 C<build_websocket_tx> |
|
834 |
+=head2 build_websocket_tx |
|
838 | 835 |
|
839 | 836 |
my $tx = $ua->build_websocket_tx('ws://localhost:3000'); |
840 | 837 |
my $tx = $ua->build_websocket_tx('ws://localhost:3000' => {DNT => 1}); |
... | ... |
@@ -842,7 +839,7 @@ L<Mojo::UserAgent::Transactor/"tx">. |
842 | 839 |
Generate L<Mojo::Transaction::HTTP> object with |
843 | 840 |
L<Mojo::UserAgent::Transactor/"websocket">. |
844 | 841 |
|
845 |
-=head2 C<delete> |
|
842 |
+=head2 delete |
|
846 | 843 |
|
847 | 844 |
my $tx = $ua->delete('kraih.com'); |
848 | 845 |
my $tx = $ua->delete('http://kraih.com' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -858,7 +855,7 @@ append a callback to perform requests non-blocking. |
858 | 855 |
}); |
859 | 856 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
860 | 857 |
|
861 |
-=head2 C<detect_proxy> |
|
858 |
+=head2 detect_proxy |
|
862 | 859 |
|
863 | 860 |
$ua = $ua->detect_proxy; |
864 | 861 |
|
... | ... |
@@ -866,7 +863,7 @@ Check environment variables C<HTTP_PROXY>, C<http_proxy>, C<HTTPS_PROXY>, |
866 | 863 |
C<https_proxy>, C<NO_PROXY> and C<no_proxy> for proxy information. Automatic |
867 | 864 |
proxy detection can be enabled with the C<MOJO_PROXY> environment variable. |
868 | 865 |
|
869 |
-=head2 C<get> |
|
866 |
+=head2 get |
|
870 | 867 |
|
871 | 868 |
my $tx = $ua->get('kraih.com'); |
872 | 869 |
my $tx = $ua->get('http://kraih.com' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -882,7 +879,7 @@ append a callback to perform requests non-blocking. |
882 | 879 |
}); |
883 | 880 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
884 | 881 |
|
885 |
-=head2 C<head> |
|
882 |
+=head2 head |
|
886 | 883 |
|
887 | 884 |
my $tx = $ua->head('kraih.com'); |
888 | 885 |
my $tx = $ua->head('http://kraih.com' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -898,13 +895,13 @@ append a callback to perform requests non-blocking. |
898 | 895 |
}); |
899 | 896 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
900 | 897 |
|
901 |
-=head2 C<need_proxy> |
|
898 |
+=head2 need_proxy |
|
902 | 899 |
|
903 | 900 |
my $success = $ua->need_proxy('intranet.mojolicio.us'); |
904 | 901 |
|
905 | 902 |
Check if request for domain would use a proxy server. |
906 | 903 |
|
907 |
-=head2 C<options> |
|
904 |
+=head2 options |
|
908 | 905 |
|
909 | 906 |
my $tx = $ua->options('kraih.com'); |
910 | 907 |
my $tx = $ua->options('http://kraih.com' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -920,7 +917,7 @@ append a callback to perform requests non-blocking. |
920 | 917 |
}); |
921 | 918 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
922 | 919 |
|
923 |
-=head2 C<patch> |
|
920 |
+=head2 patch |
|
924 | 921 |
|
925 | 922 |
my $tx = $ua->patch('kraih.com'); |
926 | 923 |
my $tx = $ua->patch('http://kraih.com' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -936,7 +933,7 @@ append a callback to perform requests non-blocking. |
936 | 933 |
}); |
937 | 934 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
938 | 935 |
|
939 |
-=head2 C<post> |
|
936 |
+=head2 post |
|
940 | 937 |
|
941 | 938 |
my $tx = $ua->post('kraih.com'); |
942 | 939 |
my $tx = $ua->post('http://kraih.com' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -952,7 +949,7 @@ append a callback to perform requests non-blocking. |
952 | 949 |
}); |
953 | 950 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
954 | 951 |
|
955 |
-=head2 C<post_form> |
|
952 |
+=head2 post_form |
|
956 | 953 |
|
957 | 954 |
my $tx = $ua->post_form('http://kraih.com' => {a => 'b'}); |
958 | 955 |
my $tx = $ua->post_form('kraih.com', 'UTF-8', {a => 'b'}, {DNT => 1}); |
... | ... |
@@ -968,7 +965,7 @@ perform requests non-blocking. |
968 | 965 |
}); |
969 | 966 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
970 | 967 |
|
971 |
-=head2 C<post_json> |
|
968 |
+=head2 post_json |
|
972 | 969 |
|
973 | 970 |
my $tx = $ua->post_json('http://kraih.com' => {a => 'b'}); |
974 | 971 |
my $tx = $ua->post_json('kraih.com' => {a => 'b'} => {DNT => 1}); |
... | ... |
@@ -984,7 +981,7 @@ perform requests non-blocking. |
984 | 981 |
}); |
985 | 982 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
986 | 983 |
|
987 |
-=head2 C<put> |
|
984 |
+=head2 put |
|
988 | 985 |
|
989 | 986 |
my $tx = $ua->put('kraih.com'); |
990 | 987 |
my $tx = $ua->put('http://kraih.com' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -1000,7 +997,7 @@ append a callback to perform requests non-blocking. |
1000 | 997 |
}); |
1001 | 998 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
1002 | 999 |
|
1003 |
-=head2 C<start> |
|
1000 |
+=head2 start |
|
1004 | 1001 |
|
1005 | 1002 |
my $tx = $ua->start(Mojo::Transaction::HTTP->new); |
1006 | 1003 |
|
... | ... |
@@ -1014,7 +1011,7 @@ non-blocking. |
1014 | 1011 |
}); |
1015 | 1012 |
Mojo::IOLoop->start unless Mojo::IOLoop->is_running; |
1016 | 1013 |
|
1017 |
-=head2 C<websocket> |
|
1014 |
+=head2 websocket |
|
1018 | 1015 |
|
1019 | 1016 |
$ua->websocket('ws://localhost:3000' => sub {...}); |
1020 | 1017 |
$ua->websocket('ws://localhost:3000' => {DNT => 1} => sub {...}); |
... | ... |
@@ -2,13 +2,13 @@ package Mojo::UserAgent::CookieJar; |
2 | 2 |
use Mojo::Base -base; |
3 | 3 |
|
4 | 4 |
use Mojo::Cookie::Request; |
5 |
+use Mojo::Path; |
|
5 | 6 |
|
6 | 7 |
has max_cookie_size => 4096; |
7 | 8 |
|
8 | 9 |
sub add { |
9 | 10 |
my ($self, @cookies) = @_; |
10 | 11 |
|
11 |
- # Add cookies |
|
12 | 12 |
my $size = $self->max_cookie_size; |
13 | 13 |
for my $cookie (@cookies) { |
14 | 14 |
|
... | ... |
@@ -41,18 +41,28 @@ sub extract { |
41 | 41 |
my ($self, $tx) = @_; |
42 | 42 |
my $url = $tx->req->url; |
43 | 43 |
for my $cookie (@{$tx->res->cookies}) { |
44 |
- $cookie->domain($url->host) unless $cookie->domain; |
|
45 |
- $cookie->path($url->path) unless $cookie->path; |
|
46 |
- $self->add($cookie); |
|
44 |
+ |
|
45 |
+ # Validate domain |
|
46 |
+ my $host = lc $url->ihost; |
|
47 |
+ my $domain = lc(defined $cookie->domain ? $cookie->domain : $host); |
|
48 |
+ $domain =~ s/^\.//; |
|
49 |
+ next unless $host eq $domain || $host =~ /\Q.$domain\E$/; |
|
50 |
+ next if $host =~ /\.\d+$/; |
|
51 |
+ $cookie->domain($domain); |
|
52 |
+ |
|
53 |
+ # Validate path |
|
54 |
+ my $path = defined $cookie->path ? $cookie->path : $url->path->to_dir->to_abs_string; |
|
55 |
+ $path = Mojo::Path->new($path)->trailing_slash(0)->to_abs_string; |
|
56 |
+ next unless _path($path, $url->path->to_abs_string); |
|
57 |
+ $self->add($cookie->path($path)); |
|
47 | 58 |
} |
48 | 59 |
} |
49 | 60 |
|
50 | 61 |
sub find { |
51 | 62 |
my ($self, $url) = @_; |
52 | 63 |
|
53 |
- # Look through the jar |
|
54 |
- return unless my $domain = $url->host; |
|
55 |
- my $path = $url->path->to_string || '/'; |
|
64 |
+ return unless my $domain = lc(defined $url->ihost ? $url->ihost : ''); |
|
65 |
+ my $path = $url->path->to_abs_string; |
|
56 | 66 |
my @found; |
57 | 67 |
while ($domain =~ /[^.]+\.[^.]+|localhost$/) { |
58 | 68 |
next unless my $old = $self->{jar}{$domain}; |
... | ... |
@@ -68,7 +78,7 @@ sub find { |
68 | 78 |
|
69 | 79 |
# Taste cookie |
70 | 80 |
next if $cookie->secure && $url->protocol ne 'https'; |
71 |
- next unless $path =~ /^\Q@{[$cookie->path]}/; |
|
81 |
+ next unless _path($cookie->path, $path); |
|
72 | 82 |
my $name = $cookie->name; |
73 | 83 |
my $value = $cookie->value; |
74 | 84 |
push @found, Mojo::Cookie::Request->new(name => $name, value => $value); |
... | ... |
@@ -88,6 +98,8 @@ sub inject { |
88 | 98 |
$req->cookies($self->find($req->url)); |
89 | 99 |
} |
90 | 100 |
|
101 |
+sub _path { $_[0] eq '/' || $_[0] eq $_[1] || $_[1] =~ m!^\Q$_[0]/! } |
|
102 |
+ |
|
91 | 103 |
1; |
92 | 104 |
|
93 | 105 |
=head1 NAME |
... | ... |
@@ -124,7 +136,7 @@ L<Mojo::UserAgent>. |
124 | 136 |
|
125 | 137 |
L<Mojo::UserAgent::CookieJar> implements the following attributes. |
126 | 138 |
|
127 |
-=head2 C<max_cookie_size> |
|
139 |
+=head2 max_cookie_size |
|
128 | 140 |
|
129 | 141 |
my $size = $jar->max_cookie_size; |
130 | 142 |
$jar = $jar->max_cookie_size(4096); |
... | ... |
@@ -136,38 +148,38 @@ Maximum cookie size in bytes, defaults to C<4096>. |
136 | 148 |
L<Mojo::UserAgent::CookieJar> inherits all methods from L<Mojo::Base> and |
137 | 149 |
implements the following new ones. |
138 | 150 |
|
139 |
-=head2 C<add> |
|
151 |
+=head2 add |
|
140 | 152 |
|
141 | 153 |
$jar = $jar->add(@cookies); |
142 | 154 |
|
143 | 155 |
Add multiple L<Mojo::Cookie::Response> objects to the jar. |
144 | 156 |
|
145 |
-=head2 C<all> |
|
157 |
+=head2 all |
|
146 | 158 |
|
147 | 159 |
my @cookies = $jar->all; |
148 | 160 |
|
149 | 161 |
Return all L<Mojo::Cookie::Response> objects that are currently stored in the |
150 | 162 |
jar. |
151 | 163 |
|
152 |
-=head2 C<empty> |
|
164 |
+=head2 empty |
|
153 | 165 |
|
154 | 166 |
$jar->empty; |
155 | 167 |
|
156 | 168 |
Empty the jar. |
157 | 169 |
|
158 |
-=head2 C<extract> |
|
170 |
+=head2 extract |
|
159 | 171 |
|
160 | 172 |
$jar->extract($tx); |
161 | 173 |
|
162 | 174 |
Extract response cookies from transaction. |
163 | 175 |
|
164 |
-=head2 C<find> |
|
176 |
+=head2 find |
|
165 | 177 |
|
166 | 178 |
my @cookies = $jar->find($url); |
167 | 179 |
|
168 | 180 |
Find L<Mojo::Cookie::Request> objects in the jar for L<Mojo::URL> object. |
169 | 181 |
|
170 |
-=head2 C<inject> |
|
182 |
+=head2 inject |
|
171 | 183 |
|
172 | 184 |
$jar->inject($tx); |
173 | 185 |
|
... | ... |
@@ -1,7 +1,7 @@ |
1 | 1 |
package Mojo::UserAgent::Transactor; |
2 | 2 |
use Mojo::Base -base; |
3 | 3 |
|
4 |
-use File::Spec::Functions 'splitpath'; |
|
4 |
+use File::Basename 'basename'; |
|
5 | 5 |
use Mojo::Asset::File; |
6 | 6 |
use Mojo::Asset::Memory; |
7 | 7 |
use Mojo::Content::MultiPart; |
... | ... |
@@ -31,57 +31,25 @@ sub endpoint { |
31 | 31 |
} |
32 | 32 |
|
33 | 33 |
sub form { |
34 |
- my ($self, $url) = (shift, shift); |
|
35 |
- |
|
36 |
- # Form |
|
37 |
- my $encoding = shift; |
|
34 |
+ my ($self, $url, $encoding) = (shift, shift, shift); |
|
38 | 35 |
my $form = ref $encoding ? $encoding : shift; |
39 | 36 |
$encoding = undef if ref $encoding; |
40 | 37 |
|
41 |
- # Parameters |
|
42 |
- my $params = Mojo::Parameters->new; |
|
43 |
- $params->charset($encoding) if defined $encoding; |
|
44 |
- my $multipart; |
|
45 |
- for my $name (sort keys %$form) { |
|
46 |
- my $value = $form->{$name}; |
|
47 |
- |
|
48 |
- # Array |
|
49 |
- if (ref $value eq 'ARRAY') { $params->append($name, $_) for @$value } |
|
50 |
- |
|
51 |
- # Hash |
|
52 |
- elsif (ref $value eq 'HASH') { |
|
53 |
- |
|
54 |
- # Enforce "multipart/form-data" |
|
55 |
- $multipart++; |
|
56 |
- |
|
57 |
- # File |
|
58 |
- if (my $file = $value->{file}) { |
|
59 |
- $value->{file} = Mojo::Asset::File->new(path => $file) if !ref $file; |
|
60 |
- $value->{filename} ||= (splitpath($value->{file}->path))[2] |
|
61 |
- if $value->{file}->isa('Mojo::Asset::File'); |
|
62 |
- } |
|
63 |
- |
|
64 |
- # Memory |
|
65 |
- elsif (defined(my $content = delete $value->{content})) { |
|
66 |
- $value->{file} = Mojo::Asset::Memory->new->add_chunk($content); |
|
67 |
- } |
|
68 |
- |
|
69 |
- push @{$params->params}, $name, $value; |
|
70 |
- } |
|
71 |
- |
|
72 |
- # Single value |
|
73 |
- else { $params->append($name, $value) } |
|
74 |
- } |
|
75 |
- |
|
76 |
- # New transaction |
|
38 |
+ # Start with normal POST transaction |
|
77 | 39 |
my $tx = $self->tx(POST => $url, @_); |
78 | 40 |
|
79 |
- # Multipart |
|
41 |
+ # Check for uploads and force multipart if necessary |
|
42 |
+ my $multipart; |
|
43 |
+ for my $value (map { ref $_ eq 'ARRAY' ? @$_ : $_ } values %$form) { |
|
44 |
+ ++$multipart and last if ref $value eq 'HASH'; |
|
45 |
+ } |
|
80 | 46 |
my $req = $tx->req; |
81 | 47 |
my $headers = $req->headers; |
82 | 48 |
$headers->content_type('multipart/form-data') if $multipart; |
49 |
+ |
|
50 |
+ # Multipart |
|
83 | 51 |
if ((defined $headers->content_type ? $headers->content_type : '') eq 'multipart/form-data') { |
84 |
- my $parts = $self->_multipart($encoding, $params->to_hash); |
|
52 |
+ my $parts = $self->_multipart($encoding, $form); |
|
85 | 53 |
$req->content( |
86 | 54 |
Mojo::Content::MultiPart->new(headers => $headers, parts => $parts)); |
87 | 55 |
} |
... | ... |
@@ -89,7 +57,9 @@ sub form { |
89 | 57 |
# Urlencoded |
90 | 58 |
else { |
91 | 59 |
$headers->content_type('application/x-www-form-urlencoded'); |
92 |
- $req->body($params->to_string); |
|
60 |
+ my $p = Mojo::Parameters->new(map { $_ => $form->{$_} } sort keys %$form); |
|
61 |
+ $p->charset($encoding) if defined $encoding; |
|
62 |
+ $req->body($p->to_string); |
|
93 | 63 |
} |
94 | 64 |
|
95 | 65 |
return $tx; |
... | ... |
@@ -203,36 +173,48 @@ sub websocket { |
203 | 173 |
sub _multipart { |
204 | 174 |
my ($self, $encoding, $form) = @_; |
205 | 175 |
|
206 |
- # Parts |
|
207 | 176 |
my @parts; |
208 | 177 |
for my $name (sort keys %$form) { |
209 | 178 |
my $values = $form->{$name}; |
210 |
- my $part = Mojo::Content::Single->new; |
|
211 |
- |
|
212 |
- # File |
|
213 |
- my $filename; |
|
214 |
- my $headers = $part->headers; |
|
215 |
- if (ref $values eq 'HASH') { |
|
216 |
- $filename = delete $values->{filename} || $name; |
|
217 |
- $filename = encode $encoding, $filename if $encoding; |
|
218 |
- push @parts, $part->asset(delete $values->{file}); |
|
219 |
- $headers->from_hash($values); |
|
220 |
- } |
|
179 |
+ for my $value (ref $values eq 'ARRAY' ? @$values : ($values)) { |
|
180 |
+ push @parts, my $part = Mojo::Content::Single->new; |
|
181 |
+ |
|
182 |
+ # Upload |
|
183 |
+ my $filename; |
|
184 |
+ my $headers = $part->headers; |
|
185 |
+ if (ref $value eq 'HASH') { |
|
186 |
+ |
|
187 |
+ # File |
|
188 |
+ if (my $file = delete $value->{file}) { |
|
189 |
+ $file = Mojo::Asset::File->new(path => $file) unless ref $file; |
|
190 |
+ $part->asset($file); |
|
191 |
+ $value->{filename} ||= basename $file->path |
|
192 |
+ if $file->isa('Mojo::Asset::File'); |
|
193 |
+ } |
|
194 |
+ |
|
195 |
+ # Memory |
|
196 |
+ elsif (defined(my $content = delete $value->{content})) { |
|
197 |
+ $part->asset(Mojo::Asset::Memory->new->add_chunk($content)); |
|
198 |
+ } |
|
199 |
+ |
|
200 |
+ # Filename and headers |
|
201 |
+ $filename = delete $value->{filename} || $name; |
|
202 |
+ $filename = encode $encoding, $filename if $encoding; |
|
203 |
+ $headers->from_hash($value); |
|
204 |
+ } |
|
221 | 205 |
|
222 |
- # Fields |
|
223 |
- else { |
|
224 |
- for my $value (ref $values ? @$values : ($values)) { |
|
225 |
- push @parts, $part = Mojo::Content::Single->new(headers => $headers); |
|
206 |
+ # Field |
|
207 |
+ else { |
|
226 | 208 |
$value = encode $encoding, $value if $encoding; |
227 |
- $part->asset->add_chunk($value); |
|
209 |
+ $part->asset(Mojo::Asset::Memory->new->add_chunk($value)); |
|
228 | 210 |
} |
229 |
- } |
|
230 | 211 |
|
231 |
- # Content-Disposition |
|
232 |
- $name = encode $encoding, $name if $encoding; |
|
233 |
- my $disposition = qq{form-data; name="$name"}; |
|
234 |
- $disposition .= qq{; filename="$filename"} if $filename; |
|
235 |
- $headers->content_disposition($disposition); |
|
212 |
+ # Content-Disposition |
|
213 |
+ $name = encode $encoding, $name if $encoding; |
|
214 |
+ my $disposition = qq{form-data; name="$name"}; |
|
215 |
+ $disposition .= qq{; filename="$filename"} if $filename; |
|
216 |
+ $headers->content_disposition($disposition); |
|
217 |
+ } |
|
236 | 218 |
} |
237 | 219 |
|
238 | 220 |
return \@parts; |
... | ... |
@@ -284,19 +266,21 @@ framework used by L<Mojo::UserAgent>. |
284 | 266 |
L<Mojo::UserAgent::Transactor> inherits all methods from L<Mojo::Base> and |
285 | 267 |
implements the following new ones. |
286 | 268 |
|
287 |
-=head2 C<endpoint> |
|
269 |
+=head2 endpoint |
|
288 | 270 |
|
289 | 271 |
my ($proto, $host, $port) = $t->endpoint(Mojo::Transaction::HTTP->new); |
290 | 272 |
|
291 | 273 |
Actual endpoint for transaction. |
292 | 274 |
|
293 |
-=head2 C<form> |
|
275 |
+=head2 form |
|
294 | 276 |
|
295 | 277 |
my $tx = $t->form('kraih.com' => {a => 'b'}); |
296 | 278 |
my $tx = $t->form('http://kraih.com' => {a => 'b'}); |
297 | 279 |
my $tx = $t->form('http://kraih.com' => {a => [qw(b c d)]}); |
298 | 280 |
my $tx = $t->form('http://kraih.com' => {mytext => {file => '/foo.txt'}}); |
299 | 281 |
my $tx = $t->form('http://kraih.com' => {mytext => {content => 'lalala'}}); |
282 |
+ my $tx = $t->form('http://kraih.com' => |
|
283 |
+ {mytexts => [{content => 'first'}, {content => 'second'}]}); |
|
300 | 284 |
my $tx = $t->form('http://kraih.com' => { |
301 | 285 |
myzip => { |
302 | 286 |
file => Mojo::Asset::Memory->new->add_chunk('lalala'), |
... | ... |
@@ -329,7 +313,7 @@ enforce it by setting the header manually. |
329 | 313 |
{'Content-Type' => 'multipart/form-data'} |
330 | 314 |
); |
331 | 315 |
|
332 |
-=head2 C<json> |
|
316 |
+=head2 json |
|
333 | 317 |
|
334 | 318 |
my $tx = $t->json('kraih.com' => {a => 'b'}); |
335 | 319 |
my $tx = $t->json('http://kraih.com' => [1, 2, 3]); |
... | ... |
@@ -343,27 +327,27 @@ with JSON data. |
343 | 327 |
my $tx = $t->json('mojolicio.us/hello', {hello => 'world'}); |
344 | 328 |
$tx->req->method('PATCH'); |
345 | 329 |
|
346 |
-=head2 C<peer> |
|
330 |
+=head2 peer |
|
347 | 331 |
|
348 | 332 |
my ($proto, $host, $port) = $t->peer(Mojo::Transaction::HTTP->new); |
349 | 333 |
|
350 | 334 |
Actual peer for transaction. |
351 | 335 |
|
352 |
-=head2 C<proxy_connect> |
|
336 |
+=head2 proxy_connect |
|
353 | 337 |
|
354 | 338 |
my $tx = $t->proxy_connect(Mojo::Transaction::HTTP->new); |
355 | 339 |
|
356 | 340 |
Build L<Mojo::Transaction::HTTP> proxy connect request for transaction if |
357 | 341 |
possible. |
358 | 342 |
|
359 |
-=head2 C<redirect> |
|
343 |
+=head2 redirect |
|
360 | 344 |
|
361 | 345 |
my $tx = $t->redirect(Mojo::Transaction::HTTP->new); |
362 | 346 |
|
363 | 347 |
Build L<Mojo::Transaction::HTTP> followup request for C<301>, C<302>, C<303>, |
364 | 348 |
C<307> or C<308> redirect response if possible. |
365 | 349 |
|
366 |
-=head2 C<tx> |
|
350 |
+=head2 tx |
|
367 | 351 |
|
368 | 352 |
my $tx = $t->tx(GET => 'kraih.com'); |
369 | 353 |
my $tx = $t->tx(POST => 'http://kraih.com'); |
... | ... |
@@ -385,14 +369,14 @@ requests. |
385 | 369 |
my $tx = $t->tx(GET => 'http://mojolicio.us'); |
386 | 370 |
$tx->connection($sock); |
387 | 371 |
|
388 |
-=head2 C<upgrade> |
|
372 |
+=head2 upgrade |
|
389 | 373 |
|
390 | 374 |
my $tx = $t->upgrade(Mojo::Transaction::HTTP->new); |
391 | 375 |
|
392 | 376 |
Build L<Mojo::Transaction::WebSocket> followup transaction for WebSocket |
393 | 377 |
handshake if possible. |
394 | 378 |
|
395 |
-=head2 C<websocket> |
|
379 |
+=head2 websocket |
|
396 | 380 |
|
397 | 381 |
my $tx = $t->websocket('ws://localhost:3000'); |
398 | 382 |
my $tx = $t->websocket('ws://localhost:3000' => {DNT => 1}); |
... | ... |
@@ -20,18 +20,18 @@ use constant { |
20 | 20 |
PC_INITIAL_N => 128 |
21 | 21 |
}; |
22 | 22 |
|
23 |
-# Punycode delimiter |
|
24 |
-my $DELIMITER = chr 0x2D; |
|
25 |
- |
|
26 | 23 |
# To update HTML5 entities run this command |
27 | 24 |
# perl examples/entities.pl > lib/Mojo/entities.txt |
28 | 25 |
my %ENTITIES; |
29 | 26 |
{ |
30 | 27 |
open my $entities, '<', catfile(dirname(__FILE__), 'entities.txt'); |
31 |
- /^(\S+)\s+U\+(\S+)/ and $ENTITIES{$1} = chr hex($2) for <$entities>; |
|
28 |
+ for my $entity (<$entities>) { |
|
29 |
+ next unless $entity =~ /^(\S+)\s+U\+(\S+)(?:\s+U\+(\S+))?/; |
|
30 |
+ $ENTITIES{$1} = defined $3 ? (chr(hex $2) . chr(hex $3)) : chr(hex $2); |
|
31 |
+ } |
|
32 | 32 |
} |
33 | 33 |
|
34 |
-# Reverse entities for html_escape (without "apos") |
|
34 |
+# DEPRECATED in Rainbow! |
|
35 | 35 |
my %REVERSE = ("\x{0027}" => '#39;'); |
36 | 36 |
$REVERSE{$ENTITIES{$_}} = defined $REVERSE{$ENTITIES{$_}} ? $REVERSE{$ENTITIES{$_}} : $_ |
37 | 37 |
for sort { @{[$a =~ /[A-Z]/g]} <=> @{[$b =~ /[A-Z]/g]} } |
... | ... |
@@ -42,12 +42,15 @@ my %CACHE; |
42 | 42 |
|
43 | 43 |
our @EXPORT_OK = ( |
44 | 44 |
qw(b64_decode b64_encode camelize class_to_file class_to_path decamelize), |
45 |
- qw(decode encode get_line hmac_md5_sum hmac_sha1_sum html_escape), |
|
46 |
- qw(html_unescape md5_bytes md5_sum monkey_patch punycode_decode), |
|
47 |
- qw(punycode_encode quote secure_compare sha1_bytes sha1_sum slurp spurt), |
|
48 |
- qw(squish trim unquote url_escape url_unescape xml_escape xor_encode) |
|
45 |
+ qw(decode encode get_line hmac_md5_sum hmac_sha1_sum html_unescape), |
|
46 |
+ qw(md5_bytes md5_sum monkey_patch punycode_decode punycode_encode quote), |
|
47 |
+ qw(secure_compare sha1_bytes sha1_sum slurp spurt squish trim unquote), |
|
48 |
+ qw(url_escape url_unescape xml_escape xor_encode) |
|
49 | 49 |
); |
50 | 50 |
|
51 |
+# DEPRECATED in Rainbow! |
|
52 |
+push @EXPORT_OK, 'html_escape'; |
|
53 |
+ |
|
51 | 54 |
sub b64_decode { decode_base64($_[0]) } |
52 | 55 |
|
53 | 56 |
sub b64_encode { encode_base64($_[0], $_[1]) } |
... | ... |
@@ -112,7 +115,11 @@ sub get_line { |
112 | 115 |
sub hmac_md5_sum { _hmac(\&md5, @_) } |
113 | 116 |
sub hmac_sha1_sum { _hmac(\&sha1, @_) } |
114 | 117 |
|
118 |
+# DEPRECATED in Rainbow! |
|
115 | 119 |
sub html_escape { |
120 |
+ warn <<EOF; |
|
121 |
+Mojo::Util->html_escape is DEPRECATED in favor of Mojo::Util->xml_escape!!! |
|
122 |
+EOF |
|
116 | 123 |
my ($string, $pattern) = @_; |
117 | 124 |
$pattern ||= '^\n\r\t !#$%(-;=?-~'; |
118 | 125 |
return $string unless $string =~ /[^$pattern]/; |
... | ... |
@@ -131,26 +138,24 @@ sub md5_bytes { md5(@_) } |
131 | 138 |
sub md5_sum { md5_hex(@_) } |
132 | 139 |
|
133 | 140 |
sub monkey_patch { |
134 |
- my ($class, $name, $cb) = @_; |
|
141 |
+ my ($class, %patch) = @_; |
|
135 | 142 |
no strict 'refs'; |
136 | 143 |
no warnings 'redefine'; |
137 |
- *{"${class}::$name"} = $cb; |
|
144 |
+ *{"${class}::$_"} = $patch{$_} for keys %patch; |
|
138 | 145 |
} |
139 | 146 |
|
147 |
+# Direct translation of RFC 3492 |
|
140 | 148 |
sub punycode_decode { |
141 | 149 |
my $input = shift; |
142 | 150 |
use integer; |
143 | 151 |
|
144 |
- # Defaults |
|
152 |
+ # Delimiter |
|
153 |
+ my @output; |
|
154 |
+ push @output, split //, $1 if $input =~ s/(.*)\x2d//s; |
|
155 |
+ |
|
145 | 156 |
my $n = PC_INITIAL_N; |
146 | 157 |
my $i = 0; |
147 | 158 |
my $bias = PC_INITIAL_BIAS; |
148 |
- my @output; |
|
149 |
- |
|
150 |
- # Delimiter |
|
151 |
- if ($input =~ s/(.*)$DELIMITER//s) { push @output, split //, $1 } |
|
152 |
- |
|
153 |
- # Decode (direct translation of RFC 3492) |
|
154 | 159 |
while (length $input) { |
155 | 160 |
my $oldi = $i; |
156 | 161 |
my $w = 1; |
... | ... |
@@ -174,47 +179,37 @@ sub punycode_decode { |
174 | 179 |
$n += $i / (@output + 1); |
175 | 180 |
$i = $i % (@output + 1); |
176 | 181 |
|
177 |
- # Insert |
|
178 |
- splice @output, $i, 0, chr($n); |
|
179 |
- $i++; |
|
182 |
+ splice @output, $i++, 0, chr $n; |
|
180 | 183 |
} |
181 | 184 |
|
182 | 185 |
return join '', @output; |
183 | 186 |
} |
184 | 187 |
|
188 |
+# Direct translation of RFC 3492 |
|
185 | 189 |
sub punycode_encode { |
186 |
- use integer; |
|
187 |
- |
|
188 |
- # Defaults |
|
189 | 190 |
my $output = shift; |
190 |
- my $len = length $output; |
|
191 |
+ use integer; |
|
191 | 192 |
|
192 | 193 |
# Split input |
193 |
- my @input = map ord, split //, $output; |
|
194 |
+ my $len = length $output; |
|
195 |
+ my @input = map {ord} split //, $output; |
|
194 | 196 |
my @chars = sort grep { $_ >= PC_INITIAL_N } @input; |
195 | 197 |
|
196 |
- # Remove non basic characters |
|
198 |
+ # Handle non basic characters |
|
197 | 199 |
$output =~ s/[^\x00-\x7f]+//gs; |
198 |
- |
|
199 |
- # Non basic characters in input |
|
200 | 200 |
my $h = my $b = length $output; |
201 |
- $output .= $DELIMITER if $b > 0; |
|
201 |
+ $output .= "\x2d" if $b > 0; |
|
202 | 202 |
|
203 |
- # Defaults |
|
204 | 203 |
my $n = PC_INITIAL_N; |
205 | 204 |
my $delta = 0; |
206 | 205 |
my $bias = PC_INITIAL_BIAS; |
207 |
- |
|
208 |
- # Encode (direct translation of RFC 3492) |
|
209 | 206 |
for my $m (@chars) { |
210 | 207 |
|
211 | 208 |
# Basic character |
212 | 209 |
next if $m < $n; |
213 | 210 |
|
214 |
- # Delta |
|
215 |
- $delta += ($m - $n) * ($h + 1); |
|
216 |
- |
|
217 | 211 |
# Walk all code points in order |
212 |
+ $delta += ($m - $n) * ($h + 1); |
|
218 | 213 |
$n = $m; |
219 | 214 |
for (my $i = 0; $i < $len; $i++) { |
220 | 215 |
my $c = $input[$i]; |
... | ... |
@@ -376,6 +371,7 @@ sub _decode { |
376 | 371 |
return "&$_[1]"; |
377 | 372 |
} |
378 | 373 |
|
374 |
+# DEPRECATED in Rainbow! |
|
379 | 375 |
sub _encode { |
380 | 376 |
return exists $REVERSE{$_[0]} ? "&$REVERSE{$_[0]}" : "&#@{[ord($_[0])]};"; |
381 | 377 |
} |
... | ... |
@@ -420,20 +416,20 @@ L<Mojo::Util> provides portable utility functions for L<Mojo>. |
420 | 416 |
|
421 | 417 |
L<Mojo::Util> implements the following functions. |
422 | 418 |
|
423 |
-=head2 C<b64_decode> |
|
419 |
+=head2 b64_decode |
|
424 | 420 |
|
425 | 421 |
my $string = b64_decode $b64; |
426 | 422 |
|
427 | 423 |
Base64 decode string. |
428 | 424 |
|
429 |
-=head2 C<b64_encode> |
|
425 |
+=head2 b64_encode |
|
430 | 426 |
|
431 | 427 |
my $b64 = b64_encode $string; |
432 | 428 |
my $b64 = b64_encode $string, "\n"; |
433 | 429 |
|
434 | 430 |
Base64 encode string, the line ending defaults to a newline. |
435 | 431 |
|
436 |
-=head2 C<camelize> |
|
432 |
+=head2 camelize |
|
437 | 433 |
|
438 | 434 |
my $camelcase = camelize $snakecase; |
439 | 435 |
|
... | ... |
@@ -448,7 +444,7 @@ Convert snake case string to camel case and replace C<-> with C<::>. |
448 | 444 |
# "FooBar::Baz" |
449 | 445 |
camelize 'FooBar::Baz'; |
450 | 446 |
|
451 |
-=head2 C<class_to_file> |
|
447 |
+=head2 class_to_file |
|
452 | 448 |
|
453 | 449 |
my $file = class_to_file 'Foo::Bar'; |
454 | 450 |
|
... | ... |
@@ -459,7 +455,7 @@ Convert a class name to a file. |
459 | 455 |
FooBar -> foo_bar |
460 | 456 |
FOOBar -> foobar |
461 | 457 |
|
462 |
-=head2 C<class_to_path> |
|
458 |
+=head2 class_to_path |
|
463 | 459 |
|
464 | 460 |
my $path = class_to_path 'Foo::Bar'; |
465 | 461 |
|
... | ... |
@@ -468,7 +464,7 @@ Convert class name to path. |
468 | 464 |
Foo::Bar -> Foo/Bar.pm |
469 | 465 |
FooBar -> FooBar.pm |
470 | 466 |
|
471 |
-=head2 C<decamelize> |
|
467 |
+=head2 decamelize |
|
472 | 468 |
|
473 | 469 |
my $snakecase = decamelize $camelcase; |
474 | 470 |
|
... | ... |
@@ -483,139 +479,135 @@ Convert camel case string to snake case and replace C<::> with C<->. |
483 | 479 |
# "foo_bar-baz" |
484 | 480 |
decamelize 'foo_bar-baz'; |
485 | 481 |
|
486 |
-=head2 C<decode> |
|
482 |
+=head2 decode |
|
487 | 483 |
|
488 | 484 |
my $chars = decode 'UTF-8', $bytes; |
489 | 485 |
|
490 | 486 |
Decode bytes to characters and return C<undef> if decoding failed. |
491 | 487 |
|
492 |
-=head2 C<encode> |
|
488 |
+=head2 encode |
|
493 | 489 |
|
494 | 490 |
my $bytes = encode 'UTF-8', $chars; |
495 | 491 |
|
496 | 492 |
Encode characters to bytes. |
497 | 493 |
|
498 |
-=head2 C<get_line> |
|
494 |
+=head2 get_line |
|
499 | 495 |
|
500 | 496 |
my $line = get_line \$string; |
501 | 497 |
|
502 | 498 |
Extract whole line from string or return C<undef>. Lines are expected to end |
503 | 499 |
with C<0x0d 0x0a> or C<0x0a>. |
504 | 500 |
|
505 |
-=head2 C<hmac_md5_sum> |
|
501 |
+=head2 hmac_md5_sum |
|
506 | 502 |
|
507 | 503 |
my $checksum = hmac_md5_sum $string, 'passw0rd'; |
508 | 504 |
|
509 | 505 |
Generate HMAC-MD5 checksum for string. |
510 | 506 |
|
511 |
-=head2 C<hmac_sha1_sum> |
|
507 |
+=head2 hmac_sha1_sum |
|
512 | 508 |
|
513 | 509 |
my $checksum = hmac_sha1_sum $string, 'passw0rd'; |
514 | 510 |
|
515 | 511 |
Generate HMAC-SHA1 checksum for string. |
516 | 512 |
|
517 |
-=head2 C<html_escape> |
|
518 |
- |
|
519 |
- my $escaped = html_escape $string; |
|
520 |
- my $escaped = html_escape $string, '^\n\r\t !#$%(-;=?-~'; |
|
521 |
- |
|
522 |
-Escape unsafe characters in string with HTML entities, the pattern used |
|
523 |
-defaults to C<^\n\r\t !#$%(-;=?-~>. |
|
524 |
- |
|
525 |
-=head2 C<html_unescape> |
|
513 |
+=head2 html_unescape |
|
526 | 514 |
|
527 | 515 |
my $string = html_unescape $escaped; |
528 | 516 |
|
529 | 517 |
Unescape all HTML entities in string. |
530 | 518 |
|
531 |
-=head2 C<md5_bytes> |
|
519 |
+=head2 md5_bytes |
|
532 | 520 |
|
533 | 521 |
my $checksum = md5_bytes $string; |
534 | 522 |
|
535 | 523 |
Generate binary MD5 checksum for string. |
536 | 524 |
|
537 |
-=head2 C<md5_sum> |
|
525 |
+=head2 md5_sum |
|
538 | 526 |
|
539 | 527 |
my $checksum = md5_sum $string; |
540 | 528 |
|
541 | 529 |
Generate MD5 checksum for string. |
542 | 530 |
|
543 |
-=head2 C<monkey_patch> |
|
531 |
+=head2 monkey_patch |
|
544 | 532 |
|
545 |
- monkey_patch $package, $name, sub {...}; |
|
533 |
+ monkey_patch $package, foo => sub {...}; |
|
534 |
+ monkey_patch $package, foo => sub {...}, bar => sub {...}; |
|
546 | 535 |
|
547 |
-Monkey patch function into package. |
|
536 |
+Monkey patch functions into package. |
|
548 | 537 |
|
549 |
- monkey_patch 'MyApp', 'hello', sub { say 'Hello!' }; |
|
538 |
+ monkey_patch 'MyApp', |
|
539 |
+ one => sub { say 'One!' }, |
|
540 |
+ two => sub { say 'Two!' }, |
|
541 |
+ three => sub { say 'Three!' }; |
|
550 | 542 |
|
551 |
-=head2 C<punycode_decode> |
|
543 |
+=head2 punycode_decode |
|
552 | 544 |
|
553 | 545 |
my $string = punycode_decode $punycode; |
554 | 546 |
|
555 | 547 |
Punycode decode string. |
556 | 548 |
|
557 |
-=head2 C<punycode_encode> |
|
549 |
+=head2 punycode_encode |
|
558 | 550 |
|
559 | 551 |
my $punycode = punycode_encode $string; |
560 | 552 |
|
561 | 553 |
Punycode encode string. |
562 | 554 |
|
563 |
-=head2 C<quote> |
|
555 |
+=head2 quote |
|
564 | 556 |
|
565 | 557 |
my $quoted = quote $string; |
566 | 558 |
|
567 | 559 |
Quote string. |
568 | 560 |
|
569 |
-=head2 C<secure_compare> |
|
561 |
+=head2 secure_compare |
|
570 | 562 |
|
571 | 563 |
my $success = secure_compare $string1, $string2; |
572 | 564 |
|
573 | 565 |
Constant time comparison algorithm to prevent timing attacks. |
574 | 566 |
|
575 |
-=head2 C<sha1_bytes> |
|
567 |
+=head2 sha1_bytes |
|
576 | 568 |
|
577 | 569 |
my $checksum = sha1_bytes $string; |
578 | 570 |
|
579 | 571 |
Generate binary SHA1 checksum for string. |
580 | 572 |
|
581 |
-=head2 C<sha1_sum> |
|
573 |
+=head2 sha1_sum |
|
582 | 574 |
|
583 | 575 |
my $checksum = sha1_sum $string; |
584 | 576 |
|
585 | 577 |
Generate SHA1 checksum for string. |
586 | 578 |
|
587 |
-=head2 C<slurp> |
|
579 |
+=head2 slurp |
|
588 | 580 |
|
589 | 581 |
my $content = slurp '/etc/passwd'; |
590 | 582 |
|
591 | 583 |
Read all data at once from file. |
592 | 584 |
|
593 |
-=head2 C<spurt> |
|
585 |
+=head2 spurt |
|
594 | 586 |
|
595 | 587 |
$content = spurt $content, '/etc/passwd'; |
596 | 588 |
|
597 | 589 |
Write all data at once to file. |
598 | 590 |
|
599 |
-=head2 C<squish> |
|
591 |
+=head2 squish |
|
600 | 592 |
|
601 | 593 |
my $squished = squish $string; |
602 | 594 |
|
603 | 595 |
Trim whitespace characters from both ends of string and then change all |
604 | 596 |
consecutive groups of whitespace into one space each. |
605 | 597 |
|
606 |
-=head2 C<trim> |
|
598 |
+=head2 trim |
|
607 | 599 |
|
608 | 600 |
my $trimmed = trim $string; |
609 | 601 |
|
610 | 602 |
Trim whitespace characters from both ends of string. |
611 | 603 |
|
612 |
-=head2 C<unquote> |
|
604 |
+=head2 unquote |
|
613 | 605 |
|
614 | 606 |
my $string = unquote $quoted; |
615 | 607 |
|
616 | 608 |
Unquote string. |
617 | 609 |
|
618 |
-=head2 C<url_escape> |
|
610 |
+=head2 url_escape |
|
619 | 611 |
|
620 | 612 |
my $escaped = url_escape $string; |
621 | 613 |
my $escaped = url_escape $string, '^A-Za-z0-9\-._~'; |
... | ... |
@@ -623,24 +615,23 @@ Unquote string. |
623 | 615 |
Percent encode unsafe characters in string, the pattern used defaults to |
624 | 616 |
C<^A-Za-z0-9\-._~>. |
625 | 617 |
|
626 |
-=head2 C<url_unescape> |
|
618 |
+=head2 url_unescape |
|
627 | 619 |
|
628 | 620 |
my $string = url_unescape $escaped; |
629 | 621 |
|
630 | 622 |
Decode percent encoded characters in string. |
631 | 623 |
|
632 |
-=head2 C<xml_escape> |
|
624 |
+=head2 xml_escape |
|
633 | 625 |
|
634 | 626 |
my $escaped = xml_escape $string; |
635 | 627 |
|
636 |
-Escape only the characters C<&>, C<E<lt>>, C<E<gt>>, C<"> and C<'> in string, |
|
637 |
-this is a much faster version of C<html_escape>. |
|
628 |
+Escape unsafe characters C<&>, C<E<lt>>, C<E<gt>>, C<"> and C<'> in string. |
|
638 | 629 |
|
639 |
-=head2 C<xor_encode> |
|
630 |
+=head2 xor_encode |
|
640 | 631 |
|
641 | 632 |
my $encoded = xor_encode $string, $key; |
642 | 633 |
|
643 |
-XOR encode string. |
|
634 |
+XOR encode string with variable length key. |
|
644 | 635 |
|
645 | 636 |
=head1 SEE ALSO |
646 | 637 |
|
... | ... |
@@ -4,6 +4,7 @@ use Mojo::Base 'Mojo'; |
4 | 4 |
# "Fry: Shut up and take my money!" |
5 | 5 |
use Carp 'croak'; |
6 | 6 |
use Mojo::Exception; |
7 |
+use Mojo::Util 'decamelize'; |
|
7 | 8 |
use Mojolicious::Commands; |
8 | 9 |
use Mojolicious::Controller; |
9 | 10 |
use Mojolicious::Plugins; |
... | ... |
@@ -21,6 +22,7 @@ has commands => sub { |
21 | 22 |
}; |
22 | 23 |
has controller_class => 'Mojolicious::Controller'; |
23 | 24 |
has mode => sub { $ENV{MOJO_MODE} || 'development' }; |
25 |
+has moniker => sub { decamelize ref shift }; |
|
24 | 26 |
has plugins => sub { Mojolicious::Plugins->new }; |
25 | 27 |
has renderer => sub { Mojolicious::Renderer->new }; |
26 | 28 |
has routes => sub { Mojolicious::Routes->new }; |
... | ... |
@@ -38,7 +40,7 @@ has static => sub { Mojolicious::Static->new }; |
38 | 40 |
has types => sub { Mojolicious::Types->new }; |
39 | 41 |
|
40 | 42 |
our $CODENAME = 'Rainbow'; |
41 |
-our $VERSION = '3.70'; |
|
43 |
+our $VERSION = '3.84'; |
|
42 | 44 |
|
43 | 45 |
sub AUTOLOAD { |
44 | 46 |
my $self = shift; |
... | ... |
@@ -61,7 +63,6 @@ sub DESTROY { } |
61 | 63 |
sub new { |
62 | 64 |
my $self = shift->SUPER::new(@_); |
63 | 65 |
|
64 |
- # Paths |
|
65 | 66 |
my $home = $self->home; |
66 | 67 |
push @{$self->renderer->paths}, $home->rel_dir('templates'); |
67 | 68 |
push @{$self->static->paths}, $home->rel_dir('public'); |
... | ... |
@@ -76,25 +77,22 @@ sub new { |
76 | 77 |
$r->hide(qw(rendered req res respond_to send session signed_cookie stash)); |
77 | 78 |
$r->hide(qw(tx ua url_for write write_chunk)); |
78 | 79 |
|
79 |
- # Prepare log |
|
80 |
+ # Check if we have a log directory |
|
80 | 81 |
my $mode = $self->mode; |
81 | 82 |
$self->log->path($home->rel_file("log/$mode.log")) |
82 | 83 |
if -w $home->rel_file('log'); |
83 | 84 |
|
84 |
- # Load default plugins |
|
85 | 85 |
$self->plugin($_) for qw(HeaderCondition DefaultHelpers TagHelpers); |
86 | 86 |
$self->plugin($_) for qw(EPLRenderer EPRenderer RequestTimer PoweredBy); |
87 | 87 |
|
88 |
- # Exception handling |
|
88 |
+ # Exception handling should be first in chain |
|
89 | 89 |
$self->hook(around_dispatch => \&_exception); |
90 | 90 |
|
91 | 91 |
# Reduced log output outside of development mode |
92 | 92 |
$self->log->level('info') unless $mode eq 'development'; |
93 | 93 |
|
94 |
- # Run mode |
|
94 |
+ # Run mode before startup |
|
95 | 95 |
if (my $sub = $self->can("${mode}_mode")) { $self->$sub(@_) } |
96 |
- |
|
97 |
- # Startup |
|
98 | 96 |
$self->startup(@_); |
99 | 97 |
|
100 | 98 |
return $self; |
... | ... |
@@ -119,10 +117,18 @@ sub dispatch { |
119 | 117 |
my $plugins = $self->plugins->emit_hook(before_dispatch => $c); |
120 | 118 |
|
121 | 119 |
# Try to find a static file |
122 |
- $self->static->dispatch($c) unless $tx->res->code; |
|
123 |
- $plugins->emit_hook_reverse(after_static_dispatch => $c); |
|
120 |
+ $self->static->dispatch($c) and $plugins->emit_hook(after_static => $c) |
|
121 |
+ unless $tx->res->code; |
|
122 |
+ |
|
123 |
+ # DEPRECATED in Rainbow! |
|
124 |
+ if ($plugins->has_subscribers('after_static_dispatch')) { |
|
125 |
+ warn <<EOF and $plugins->emit_hook_reverse(after_static_dispatch => $c); |
|
126 |
+after_static_dispatch hook is DEPRECATED in favor of before_routes!!! |
|
127 |
+EOF |
|
128 |
+ } |
|
124 | 129 |
|
125 | 130 |
# Routes |
131 |
+ $plugins->emit_hook(before_routes => $c); |
|
126 | 132 |
my $res = $tx->res; |
127 | 133 |
return if $res->code; |
128 | 134 |
if (my $code = ($tx->req->error)[1]) { $res->code($code) } |
... | ... |
@@ -145,18 +151,19 @@ sub handler { |
145 | 151 |
= $self->controller_class->new(app => $self, stash => $stash, tx => $tx); |
146 | 152 |
weaken $c->{$_} for qw(app tx); |
147 | 153 |
|
148 |
- # Dispatcher |
|
149 |
- ++$self->{dispatch} and $self->hook(around_dispatch => \&_dispatch) |
|
154 |
+ # Dispatcher has to be last in the chain |
|
155 |
+ ++$self->{dispatch} |
|
156 |
+ and $self->hook(around_dispatch => sub { $_[1]->app->dispatch($_[1]) }) |
|
150 | 157 |
unless $self->{dispatch}; |
151 | 158 |
|
152 |
- # Process |
|
159 |
+ # Process with chain |
|
153 | 160 |
unless (eval { $self->plugins->emit_chain(around_dispatch => $c) }) { |
154 | 161 |
$self->log->fatal("Processing request failed: $@"); |
155 | 162 |
$tx->res->code(500); |
156 | 163 |
$tx->resume; |
157 | 164 |
} |
158 | 165 |
|
159 |
- # Delayed |
|
166 |
+ # Delayed response |
|
160 | 167 |
$self->log->debug('Nothing has been rendered, expecting delayed response.') |
161 | 168 |
unless $stash->{'mojo.rendered'} || $tx->is_writing; |
162 | 169 |
} |
... | ... |
@@ -180,11 +187,6 @@ sub start { shift->commands->run(@_ ? @_ : @ARGV) } |
180 | 187 |
|
181 | 188 |
sub startup { } |
182 | 189 |
|
183 |
-sub _dispatch { |
|
184 |
- my ($next, $c) = @_; |
|
185 |
- $c->app->dispatch($c); |
|
186 |
-} |
|
187 |
- |
|
188 | 190 |
sub _exception { |
189 | 191 |
my ($next, $c) = @_; |
190 | 192 |
local $SIG{__DIE__} |
... | ... |
@@ -229,7 +231,7 @@ Take a look at our excellent documentation in L<Mojolicious::Guides>! |
229 | 231 |
L<Mojolicious> inherits all attributes from L<Mojo> and implements the |
230 | 232 |
following new ones. |
231 | 233 |
|
232 |
-=head2 C<commands> |
|
234 |
+=head2 commands |
|
233 | 235 |
|
234 | 236 |
my $commands = $app->commands; |
235 | 237 |
$app = $app->commands(Mojolicious::Commands->new); |
... | ... |
@@ -240,7 +242,7 @@ L<Mojolicious::Commands> object. |
240 | 242 |
# Add another namespace to load commands from |
241 | 243 |
push @{$app->commands->namespaces}, 'MyApp::Command'; |
242 | 244 |
|
243 |
-=head2 C<controller_class> |
|
245 |
+=head2 controller_class |
|
244 | 246 |
|
245 | 247 |
my $class = $app->controller_class; |
246 | 248 |
$app = $app->controller_class('Mojolicious::Controller'); |
... | ... |
@@ -248,7 +250,7 @@ L<Mojolicious::Commands> object. |
248 | 250 |
Class to be used for the default controller, defaults to |
249 | 251 |
L<Mojolicious::Controller>. |
250 | 252 |
|
251 |
-=head2 C<mode> |
|
253 |
+=head2 mode |
|
252 | 254 |
|
253 | 255 |
my $mode = $app->mode; |
254 | 256 |
$app = $app->mode('production'); |
... | ... |
@@ -272,7 +274,16 @@ Right before calling C<startup> and mode specific methods, L<Mojolicious> |
272 | 274 |
will pick up the current mode, name the log file after it and raise the log |
273 | 275 |
level from C<debug> to C<info> if it has a value other than C<development>. |
274 | 276 |
|
275 |
-=head2 C<plugins> |
|
277 |
+=head2 moniker |
|
278 |
+ |
|
279 |
+ my $moniker = $app->moniker; |
|
280 |
+ $app = $app->moniker('foo_bar'); |
|
281 |
+ |
|
282 |
+Moniker of this application, often used as default filename for configuration |
|
283 |
+files and the like, defaults to decamelizing the application class with |
|
284 |
+L<Mojo::Util/"decamelize">. |
|
285 |
+ |
|
286 |
+=head2 plugins |
|
276 | 287 |
|
277 | 288 |
my $plugins = $app->plugins; |
278 | 289 |
$app = $app->plugins(Mojolicious::Plugins->new); |
... | ... |
@@ -283,7 +294,7 @@ C<plugin> method below if you want to load a plugin. |
283 | 294 |
# Add another namespace to load plugins from |
284 | 295 |
push @{$app->plugins->namespaces}, 'MyApp::Plugin'; |
285 | 296 |
|
286 |
-=head2 C<renderer> |
|
297 |
+=head2 renderer |
|
287 | 298 |
|
288 | 299 |
my $renderer = $app->renderer; |
289 | 300 |
$app = $app->renderer(Mojolicious::Renderer->new); |
... | ... |
@@ -299,7 +310,7 @@ contain more information. |
299 | 310 |
# Add another class with templates in DATA section |
300 | 311 |
push @{$app->renderer->classes}, 'Mojolicious::Plugin::Fun'; |
301 | 312 |
|
302 |
-=head2 C<routes> |
|
313 |
+=head2 routes |
|
303 | 314 |
|
304 | 315 |
my $routes = $app->routes; |
305 | 316 |
$app = $app->routes(Mojolicious::Routes->new); |
... | ... |
@@ -307,14 +318,15 @@ contain more information. |
307 | 318 |
The router, defaults to a L<Mojolicious::Routes> object. You use this in your |
308 | 319 |
startup method to define the url endpoints for your application. |
309 | 320 |
|
310 |
- sub startup { |
|
311 |
- my $self = shift; |
|
321 |
+ # Add routes |
|
322 |
+ my $r = $app->routes; |
|
323 |
+ $r->get('/foo/bar')->to('test#foo', title => 'Hello Mojo!'); |
|
324 |
+ $r->post('/baz')->to('test#baz'); |
|
312 | 325 |
|
313 |
- my $r = $self->routes; |
|
314 |
- $r->get('/:controller/:action')->to('test#welcome'); |
|
315 |
- } |
|
326 |
+ # Add another namespace to load controllers from |
|
327 |
+ push @{$app->routes->namespaces}, 'MyApp::Controller'; |
|
316 | 328 |
|
317 |
-=head2 C<secret> |
|
329 |
+=head2 secret |
|
318 | 330 |
|
319 | 331 |
my $secret = $app->secret; |
320 | 332 |
$app = $app->secret('passw0rd'); |
... | ... |
@@ -324,7 +336,7 @@ application name which is not very secure, so you should change it!!! As long |
324 | 336 |
as you are using the insecure default there will be debug messages in the log |
325 | 337 |
file reminding you to change your passphrase. |
326 | 338 |
|
327 |
-=head2 C<sessions> |
|
339 |
+=head2 sessions |
|
328 | 340 |
|
329 | 341 |
my $sessions = $app->sessions; |
330 | 342 |
$app = $app->sessions(Mojolicious::Sessions->new); |
... | ... |
@@ -334,7 +346,7 @@ object. You can usually leave this alone, see |
334 | 346 |
L<Mojolicious::Controller/"session"> for more information about working with |
335 | 347 |
session data. |
336 | 348 |
|
337 |
-=head2 C<static> |
|
349 |
+=head2 static |
|
338 | 350 |
|
339 | 351 |
my $static = $app->static; |
340 | 352 |
$app = $app->static(Mojolicious::Static->new); |
... | ... |
@@ -348,7 +360,7 @@ L<Mojolicious::Static> object. |
348 | 360 |
# Add another class with static files in DATA section |
349 | 361 |
push @{$app->static->classes}, 'Mojolicious::Plugin::Fun'; |
350 | 362 |
|
351 |
-=head2 C<types> |
|
363 |
+=head2 types |
|
352 | 364 |
|
353 | 365 |
my $types = $app->types; |
354 | 366 |
$app = $app->types(Mojolicious::Types->new); |
... | ... |
@@ -363,23 +375,23 @@ L<Mojolicious::Types> object. |
363 | 375 |
L<Mojolicious> inherits all methods from L<Mojo> and implements the following |
364 | 376 |
new ones. |
365 | 377 |
|
366 |
-=head2 C<new> |
|
378 |
+=head2 new |
|
367 | 379 |
|
368 | 380 |
my $app = Mojolicious->new; |
369 | 381 |
|
370 | 382 |
Construct a new L<Mojolicious> application, calling C<${mode}_mode> and |
371 | 383 |
C<startup> in the process. Will automatically detect your home directory and |
372 | 384 |
set up logging based on your current operating mode. Also sets up the |
373 |
-renderer, static dispatcher and a default set of plugins. |
|
385 |
+renderer, static file server and a default set of plugins. |
|
374 | 386 |
|
375 |
-=head2 C<build_tx> |
|
387 |
+=head2 build_tx |
|
376 | 388 |
|
377 | 389 |
my $tx = $app->build_tx; |
378 | 390 |
|
379 | 391 |
Transaction builder, defaults to building a L<Mojo::Transaction::HTTP> |
380 | 392 |
object. |
381 | 393 |
|
382 |
-=head2 C<defaults> |
|
394 |
+=head2 defaults |
|
383 | 395 |
|
384 | 396 |
my $defaults = $app->defaults; |
385 | 397 |
my $foo = $app->defaults('foo'); |
... | ... |
@@ -394,7 +406,7 @@ request. |
394 | 406 |
my $foo = $app->defaults->{foo}; |
395 | 407 |
delete $app->defaults->{foo}; |
396 | 408 |
|
397 |
-=head2 C<dispatch> |
|
409 |
+=head2 dispatch |
|
398 | 410 |
|
399 | 411 |
$app->dispatch(Mojolicious::Controller->new); |
400 | 412 |
|
... | ... |
@@ -402,14 +414,14 @@ The heart of every Mojolicious application, calls the C<static> and C<routes> |
402 | 414 |
dispatchers for every request and passes them a L<Mojolicious::Controller> |
403 | 415 |
object. |
404 | 416 |
|
405 |
-=head2 C<handler> |
|
417 |
+=head2 handler |
|
406 | 418 |
|
407 | 419 |
$app->handler(Mojo::Transaction::HTTP->new); |
408 | 420 |
$app->handler(Mojolicious::Controller->new); |
409 | 421 |
|
410 | 422 |
Sets up the default controller and calls process for every request. |
411 | 423 |
|
412 |
-=head2 C<helper> |
|
424 |
+=head2 helper |
|
413 | 425 |
|
414 | 426 |
$app->helper(foo => sub {...}); |
415 | 427 |
|
... | ... |
@@ -427,7 +439,7 @@ and the application object, as well as a function in C<ep> templates. |
427 | 439 |
% cache->{foo} = 'bar'; |
428 | 440 |
%= cache->{foo} |
429 | 441 |
|
430 |
-=head2 C<hook> |
|
442 |
+=head2 hook |
|
431 | 443 |
|
432 | 444 |
$app->hook(after_dispatch => sub {...}); |
433 | 445 |
|
... | ... |
@@ -438,14 +450,14 @@ requests indiscriminately. |
438 | 450 |
$app->hook(before_dispatch => sub { |
439 | 451 |
my $c = shift; |
440 | 452 |
$c->render(text => 'Skipped dispatchers!') |
441 |
- if $c->req->url->path->contains('/do_not_dispatch'); |
|
453 |
+ if $c->req->url->path->to_route =~ /do_not_dispatch/; |
|
442 | 454 |
}); |
443 | 455 |
|
444 | 456 |
These hooks are currently available and are emitted in the listed order: |
445 | 457 |
|
446 | 458 |
=over 2 |
447 | 459 |
|
448 |
-=item C<after_build_tx> |
|
460 |
+=item after_build_tx |
|
449 | 461 |
|
450 | 462 |
Emitted right after the transaction is built and before the HTTP request gets |
451 | 463 |
parsed. |
... | ... |
@@ -460,9 +472,9 @@ rather advanced features such as upload progress bars possible. Note that this |
460 | 472 |
hook will not work for embedded applications. (Passed the transaction and |
461 | 473 |
application object) |
462 | 474 |
|
463 |
-=item C<before_dispatch> |
|
475 |
+=item before_dispatch |
|
464 | 476 |
|
465 |
-Emitted right before the static dispatcher and router start their work. |
|
477 |
+Emitted right before the static file server and router start their work. |
|
466 | 478 |
|
467 | 479 |
$app->hook(before_dispatch => sub { |
468 | 480 |
my $c = shift; |
... | ... |
@@ -472,25 +484,51 @@ Emitted right before the static dispatcher and router start their work. |
472 | 484 |
Very useful for rewriting incoming requests and other preprocessing tasks. |
473 | 485 |
(Passed the default controller object) |
474 | 486 |
|
475 |
-=item C<after_static_dispatch> |
|
487 |
+=item after_static |
|
476 | 488 |
|
477 |
-Emitted in reverse order after the static dispatcher determined if a static |
|
478 |
-file should be served and before the router starts its work. |
|
489 |
+Emitted after the static file server decided to serve a static file. |
|
479 | 490 |
|
480 |
- $app->hook(after_static_dispatch => sub { |
|
491 |
+ $app->hook(after_static => sub { |
|
481 | 492 |
my $c = shift; |
482 | 493 |
... |
483 | 494 |
}); |
484 | 495 |
|
485 |
-Mostly used for custom dispatchers and post-processing static file responses. |
|
486 |
-(Passed the default controller object) |
|
496 |
+Mostly used for post-processing static file responses. (Passed the default |
|
497 |
+controller object) |
|
498 |
+ |
|
499 |
+=item before_routes |
|
500 |
+ |
|
501 |
+Emitted after the static file server decided if a static file should be served |
|
502 |
+and before the router starts its work. |
|
503 |
+ |
|
504 |
+ $app->hook(before_routes => sub { |
|
505 |
+ my $c = shift; |
|
506 |
+ ... |
|
507 |
+ }); |
|
508 |
+ |
|
509 |
+Mostly used for custom dispatchers and collecting metrics. (Passed the default |
|
510 |
+controller object) |
|
511 |
+ |
|
512 |
+=item after_render |
|
487 | 513 |
|
488 |
-=item C<after_dispatch> |
|
514 |
+Emitted after content has been generated by the renderer that is not partial. |
|
515 |
+Note that this hook can trigger out of order due to its dynamic nature, and |
|
516 |
+with embedded applications will only work for the application that is |
|
517 |
+rendering. |
|
518 |
+ |
|
519 |
+ $app->hook(after_render => sub { |
|
520 |
+ my ($c, $output, $format) = @_; |
|
521 |
+ ... |
|
522 |
+ }); |
|
523 |
+ |
|
524 |
+Mostly used for post-processing dynamically generated content. (Passed the |
|
525 |
+current controller object, a reference to the content and the format) |
|
526 |
+ |
|
527 |
+=item after_dispatch |
|
489 | 528 |
|
490 | 529 |
Emitted in reverse order after a response has been rendered. Note that this |
491 |
-hook can trigger before C<after_static_dispatch> due to its dynamic nature, |
|
492 |
-and with embedded applications will only work for the application rendering |
|
493 |
-the response. |
|
530 |
+hook can trigger out of order due to its dynamic nature, and with embedded |
|
531 |
+applications will only work for the application that is rendering. |
|
494 | 532 |
|
495 | 533 |
$app->hook(after_dispatch => sub { |
496 | 534 |
my $c = shift; |
... | ... |
@@ -500,7 +538,7 @@ the response. |
500 | 538 |
Useful for rewriting outgoing responses and other post-processing tasks. |
501 | 539 |
(Passed the current controller object) |
502 | 540 |
|
503 |
-=item C<around_dispatch> |
|
541 |
+=item around_dispatch |
|
504 | 542 |
|
505 | 543 |
Emitted right before the C<before_dispatch> hook and wraps around the whole |
506 | 544 |
dispatch process, so you have to manually forward to the next hook if you want |
... | ... |
@@ -522,7 +560,7 @@ the default controller object) |
522 | 560 |
|
523 | 561 |
=back |
524 | 562 |
|
525 |
-=head2 C<plugin> |
|
563 |
+=head2 plugin |
|
526 | 564 |
|
527 | 565 |
$app->plugin('some_thing'); |
528 | 566 |
$app->plugin('some_thing', foo => 23); |
... | ... |
@@ -534,76 +572,21 @@ the default controller object) |
534 | 572 |
$app->plugin('MyApp::Plugin::SomeThing', foo => 23); |
535 | 573 |
$app->plugin('MyApp::Plugin::SomeThing', {foo => 23}); |
536 | 574 |
|
537 |
-Load a plugin with L<Mojolicious::Plugins/"register_plugin">. |
|
538 |
- |
|
539 |
-These plugins are included in the L<Mojolicious> distribution as examples: |
|
540 |
- |
|
541 |
-=over 2 |
|
542 |
- |
|
543 |
-=item L<Mojolicious::Plugin::Charset> |
|
544 |
- |
|
545 |
-Change the application charset. |
|
546 |
- |
|
547 |
-=item L<Mojolicious::Plugin::Config> |
|
548 |
- |
|
549 |
-Perl-ish configuration files. |
|
550 |
- |
|
551 |
-=item L<Mojolicious::Plugin::DefaultHelpers> |
|
552 |
- |
|
553 |
-General purpose helper collection, loaded automatically. |
|
575 |
+Load a plugin, for a full list of example plugins included in the |
|
576 |
+L<Mojolicious> distribution see L<Mojolicious::Plugins/"PLUGINS">. |
|
554 | 577 |
|
555 |
-=item L<Mojolicious::Plugin::EPLRenderer> |
|
556 |
- |
|
557 |
-Renderer for plain embedded Perl templates, loaded automatically. |
|
558 |
- |
|
559 |
-=item L<Mojolicious::Plugin::EPRenderer> |
|
560 |
- |
|
561 |
-Renderer for more sophisiticated embedded Perl templates, loaded |
|
562 |
-automatically. |
|
563 |
- |
|
564 |
-=item L<Mojolicious::Plugin::HeaderCondition> |
|
565 |
- |
|
566 |
-Route condition for all kinds of headers, loaded automatically. |
|
567 |
- |
|
568 |
-=item L<Mojolicious::Plugin::JSONConfig> |
|
569 |
- |
|
570 |
-JSON configuration files. |
|
571 |
- |
|
572 |
-=item L<Mojolicious::Plugin::Mount> |
|
573 |
- |
|
574 |
-Mount whole L<Mojolicious> applications. |
|
575 |
- |
|
576 |
-=item L<Mojolicious::Plugin::PODRenderer> |
|
577 |
- |
|
578 |
-Renderer for turning POD into HTML and documentation browser for |
|
579 |
-L<Mojolicious::Guides>. |
|
580 |
- |
|
581 |
-=item L<Mojolicious::Plugin::PoweredBy> |
|
582 |
- |
|
583 |
-Add an C<X-Powered-By> header to outgoing responses, loaded automatically. |
|
584 |
- |
|
585 |
-=item L<Mojolicious::Plugin::RequestTimer> |
|
586 |
- |
|
587 |
-Log timing information, loaded automatically. |
|
588 |
- |
|
589 |
-=item L<Mojolicious::Plugin::TagHelpers> |
|
590 |
- |
|
591 |
-Template specific helper collection, loaded automatically. |
|
592 |
- |
|
593 |
-=back |
|
594 |
- |
|
595 |
-=head2 C<start> |
|
578 |
+=head2 start |
|
596 | 579 |
|
597 | 580 |
$app->start; |
598 | 581 |
$app->start(@ARGV); |
599 | 582 |
|
600 |
-Start the command line interface for your application with |
|
601 |
-L<Mojolicious::Commands/"start">. |
|
583 |
+Start the command line interface for your application, for a full list of |
|
584 |
+commands available by default see L<Mojolicious::Commands/"COMMANDS">. |
|
602 | 585 |
|
603 | 586 |
# Always start daemon and ignore @ARGV |
604 | 587 |
$app->start('daemon', '-l', 'http://*:8080'); |
605 | 588 |
|
606 |
-=head2 C<startup> |
|
589 |
+=head2 startup |
|
607 | 590 |
|
608 | 591 |
$app->startup; |
609 | 592 |
|
... | ... |
@@ -626,26 +609,6 @@ request, response and stash. |
626 | 609 |
|
627 | 610 |
$app->log->debug($app->dumper({foo => 'bar'})); |
628 | 611 |
|
629 |
-=head1 SUPPORT |
|
630 |
- |
|
631 |
-=head2 Web |
|
632 |
- |
|
633 |
-L<http://mojolicio.us> |
|
634 |
- |
|
635 |
-=head2 IRC |
|
636 |
- |
|
637 |
-C<#mojo> on C<irc.perl.org> |
|
638 |
- |
|
639 |
-=head2 Mailing-List |
|
640 |
- |
|
641 |
-L<http://groups.google.com/group/mojolicious> |
|
642 |
- |
|
643 |
-=head1 DEVELOPMENT |
|
644 |
- |
|
645 |
-=head2 Repository |
|
646 |
- |
|
647 |
-L<http://github.com/kraih/mojo> |
|
648 |
- |
|
649 | 612 |
=head1 BUNDLED FILES |
650 | 613 |
|
651 | 614 |
The L<Mojolicious> distribution includes a few files with different licenses |
... | ... |
@@ -653,14 +616,14 @@ that have been bundled for internal use. |
653 | 616 |
|
654 | 617 |
=head2 Mojolicious Artwork |
655 | 618 |
|
656 |
- Copyright (C) 2010-2012, Sebastian Riedel. |
|
619 |
+ Copyright (C) 2010-2013, Sebastian Riedel. |
|
657 | 620 |
|
658 | 621 |
Licensed under the CC-SA License, Version 3.0 |
659 | 622 |
L<http://creativecommons.org/licenses/by-sa/3.0>. |
660 | 623 |
|
661 | 624 |
=head2 jQuery |
662 | 625 |
|
663 |
- Copyright (C) 2011, John Resig. |
|
626 |
+ Copyright (C) 2005, 2012 jQuery Foundation, Inc. |
|
664 | 627 |
|
665 | 628 |
Licensed under the MIT License, L<http://creativecommons.org/licenses/MIT>. |
666 | 629 |
|
... | ... |
@@ -810,6 +773,8 @@ James Duncan |
810 | 773 |
|
811 | 774 |
Jan Jona Javorsek |
812 | 775 |
|
776 |
+Jan Schmidt |
|
777 |
+ |
|
813 | 778 |
Jaroslav Muhin |
814 | 779 |
|
815 | 780 |
Jesse Vincent |
... | ... |
@@ -940,9 +905,13 @@ Zak B. Elep |
940 | 905 |
|
941 | 906 |
=head1 COPYRIGHT AND LICENSE |
942 | 907 |
|
943 |
-Copyright (C) 2008-2012, Sebastian Riedel. |
|
908 |
+Copyright (C) 2008-2013, Sebastian Riedel. |
|
944 | 909 |
|
945 | 910 |
This program is free software, you can redistribute it and/or modify it under |
946 | 911 |
the terms of the Artistic License version 2.0. |
947 | 912 |
|
913 |
+=head1 SEE ALSO |
|
914 |
+ |
|
915 |
+L<Mojolicious::Guides>, L<http://mojolicio.us>. |
|
916 |
+ |
|
948 | 917 |
=cut |
... | ... |
@@ -32,10 +32,7 @@ sub chmod_rel_file { |
32 | 32 |
sub create_dir { |
33 | 33 |
my ($self, $path) = @_; |
34 | 34 |
|
35 |
- # Exists |
|
36 | 35 |
if (-d $path) { say " [exist] $path" unless $self->quiet } |
37 |
- |
|
38 |
- # Create |
|
39 | 36 |
else { |
40 | 37 |
mkpath $path or croak qq{Can't make directory "$path": $!}; |
41 | 38 |
say " [mkdir] $path" unless $self->quiet; |
... | ... |
@@ -129,7 +126,7 @@ default. |
129 | 126 |
|
130 | 127 |
L<Mojolicious::Command> implements the following attributes. |
131 | 128 |
|
132 |
-=head2 C<app> |
|
129 |
+=head2 app |
|
133 | 130 |
|
134 | 131 |
my $app = $command->app; |
135 | 132 |
$command = $command->app(MyApp->new); |
... | ... |
@@ -139,21 +136,21 @@ Application for command, defaults to a L<Mojo::HelloWorld> object. |
139 | 136 |
# Introspect |
140 | 137 |
say "Template path: $_" for @{$command->app->renderer->paths}; |
141 | 138 |
|
142 |
-=head2 C<description> |
|
139 |
+=head2 description |
|
143 | 140 |
|
144 | 141 |
my $description = $command->description; |
145 | 142 |
$command = $command->description('Foo!'); |
146 | 143 |
|
147 | 144 |
Short description of command, used for the command list. |
148 | 145 |
|
149 |
-=head2 C<quiet> |
|
146 |
+=head2 quiet |
|
150 | 147 |
|
151 | 148 |
my $quiet = $command->quiet; |
152 | 149 |
$command = $command->quiet(1); |
153 | 150 |
|
154 | 151 |
Limited command output. |
155 | 152 |
|
156 |
-=head2 C<usage> |
|
153 |
+=head2 usage |
|
157 | 154 |
|
158 | 155 |
my $usage = $command->usage; |
159 | 156 |
$command = $command->usage('Foo!'); |
... | ... |
@@ -165,51 +162,51 @@ Usage information for command, used for the help screen. |
165 | 162 |
L<Mojolicious::Command> inherits all methods from L<Mojo::Base> and implements |
166 | 163 |
the following new ones. |
167 | 164 |
|
168 |
-=head2 C<chmod_file> |
|
165 |
+=head2 chmod_file |
|
169 | 166 |
|
170 | 167 |
$command = $command->chmod_file('/home/sri/foo.txt', 0644); |
171 | 168 |
|
172 | 169 |
Change mode of a file. |
173 | 170 |
|
174 |
-=head2 C<chmod_rel_file> |
|
171 |
+=head2 chmod_rel_file |
|
175 | 172 |
|
176 | 173 |
$command = $command->chmod_rel_file('foo/foo.txt', 0644); |
177 | 174 |
|
178 | 175 |
Portably change mode of a file relative to the current working directory. |
179 | 176 |
|
180 |
-=head2 C<create_dir> |
|
177 |
+=head2 create_dir |
|
181 | 178 |
|
182 | 179 |
$command = $command->create_dir('/home/sri/foo/bar'); |
183 | 180 |
|
184 | 181 |
Create a directory. |
185 | 182 |
|
186 |
-=head2 C<create_rel_dir> |
|
183 |
+=head2 create_rel_dir |
|
187 | 184 |
|
188 | 185 |
$command = $command->create_rel_dir('foo/bar/baz'); |
189 | 186 |
|
190 | 187 |
Portably create a directory relative to the current working directory. |
191 | 188 |
|
192 |
-=head2 C<help> |
|
189 |
+=head2 help |
|
193 | 190 |
|
194 | 191 |
$command->help; |
195 | 192 |
|
196 | 193 |
Print usage information for command. |
197 | 194 |
|
198 |
-=head2 C<rel_dir> |
|
195 |
+=head2 rel_dir |
|
199 | 196 |
|
200 | 197 |
my $path = $command->rel_dir('foo/bar'); |
201 | 198 |
|
202 | 199 |
Portably generate an absolute path for a directory relative to the current |
203 | 200 |
working directory. |
204 | 201 |
|
205 |
-=head2 C<rel_file> |
|
202 |
+=head2 rel_file |
|
206 | 203 |
|
207 | 204 |
my $path = $command->rel_file('foo/bar.txt'); |
208 | 205 |
|
209 | 206 |
Portably generate an absolute path for a file relative to the current working |
210 | 207 |
directory. |
211 | 208 |
|
212 |
-=head2 C<render_data> |
|
209 |
+=head2 render_data |
|
213 | 210 |
|
214 | 211 |
|
215 | 212 |
my $data = $command->render_data('foo_bar'); |
... | ... |
@@ -218,7 +215,7 @@ directory. |
218 | 215 |
Render a template from the C<DATA> section of the command class with |
219 | 216 |
L<Mojo::Template>. |
220 | 217 |
|
221 |
-=head2 C<render_to_file> |
|
218 |
+=head2 render_to_file |
|
222 | 219 |
|
223 | 220 |
$command = $command->render_to_file('foo_bar', '/home/sri/foo.txt'); |
224 | 221 |
$command = $command->render_to_file('foo_bar', '/home/sri/foo.txt', @args); |
... | ... |
@@ -226,7 +223,7 @@ L<Mojo::Template>. |
226 | 223 |
Render a template from the C<DATA> section of the command class with |
227 | 224 |
L<Mojo::Template> to a file and create directory if necessary. |
228 | 225 |
|
229 |
-=head2 C<render_to_rel_file> |
|
226 |
+=head2 render_to_rel_file |
|
230 | 227 |
|
231 | 228 |
$command = $command->render_to_rel_file('foo_bar', 'foo/bar.txt'); |
232 | 229 |
$command = $command->render_to_rel_file('foo_bar', 'foo/bar.txt', @args); |
... | ... |
@@ -235,20 +232,20 @@ Portably render a template from the C<DATA> section of the command class with |
235 | 232 |
L<Mojo::Template> to a file relative to the current working directory and |
236 | 233 |
create directory if necessary. |
237 | 234 |
|
238 |
-=head2 C<run> |
|
235 |
+=head2 run |
|
239 | 236 |
|
240 | 237 |
$command->run; |
241 | 238 |
$command->run(@ARGV); |
242 | 239 |
|
243 | 240 |
Run command. Meant to be overloaded in a subclass. |
244 | 241 |
|
245 |
-=head2 C<write_file> |
|
242 |
+=head2 write_file |
|
246 | 243 |
|
247 | 244 |
$command = $command->write_file('/home/sri/foo.txt', 'Hello World!'); |
248 | 245 |
|
249 | 246 |
Write text to a file and create directory if necessary. |
250 | 247 |
|
251 |
-=head2 C<write_rel_file> |
|
248 |
+=head2 write_rel_file |
|
252 | 249 |
|
253 | 250 |
$command = $command->write_rel_file('foo/bar.txt', 'Hello World!'); |
254 | 251 |
|
... | ... |
@@ -45,14 +45,14 @@ example for learning to build new commands, you're welcome to fork it. |
45 | 45 |
L<Mojolicious::Command::cgi> inherits all attributes from |
46 | 46 |
L<Mojolicious::Command> and implements the following new ones. |
47 | 47 |
|
48 |
-=head2 C<description> |
|
48 |
+=head2 description |
|
49 | 49 |
|
50 | 50 |
my $description = $cgi->description; |
51 | 51 |
$cgi = $cgi->description('Foo!'); |
52 | 52 |
|
53 | 53 |
Short description of this command, used for the command list. |
54 | 54 |
|
55 |
-=head2 C<usage> |
|
55 |
+=head2 usage |
|
56 | 56 |
|
57 | 57 |
my $usage = $cgi->usage; |
58 | 58 |
$cgi = $cgi->usage('Foo!'); |
... | ... |
@@ -64,7 +64,7 @@ Usage information for this command, used for the help screen. |
64 | 64 |
L<Mojolicious::Command::cgi> inherits all methods from L<Mojolicious::Command> |
65 | 65 |
and implements the following new ones. |
66 | 66 |
|
67 |
-=head2 C<run> |
|
67 |
+=head2 run |
|
68 | 68 |
|
69 | 69 |
$cgi->run(@ARGV); |
70 | 70 |
|
... | ... |
@@ -19,13 +19,11 @@ EOF |
19 | 19 |
sub run { |
20 | 20 |
my ($self, @args) = @_; |
21 | 21 |
|
22 |
- # Options |
|
23 | 22 |
GetOptionsFromArray \@args, |
24 | 23 |
'p|password=s' => \(my $password = ''), |
25 | 24 |
'u|user=s' => \(my $user = ''); |
26 | 25 |
die $self->usage unless my $file = shift @args; |
27 | 26 |
|
28 |
- # Upload |
|
29 | 27 |
my $tx = Mojo::UserAgent->new->detect_proxy->post_form( |
30 | 28 |
"https://$user:$password\@pause.perl.org/pause/authenquery" => { |
31 | 29 |
HIDDENNAME => $user, |
... | ... |
@@ -37,7 +35,6 @@ sub run { |
37 | 35 |
} |
38 | 36 |
); |
39 | 37 |
|
40 |
- # Error |
|
41 | 38 |
unless ($tx->success) { |
42 | 39 |
my $code = $tx->res->code || ''; |
43 | 40 |
my $msg = $tx->error; |
... | ... |
@@ -45,6 +42,7 @@ sub run { |
45 | 42 |
elsif ($code eq '409') { $msg = 'File already exists on CPAN.' } |
46 | 43 |
die qq{Problem uploading file "$file". ($msg)\n}; |
47 | 44 |
} |
45 |
+ |
|
48 | 46 |
say 'Upload successful!'; |
49 | 47 |
} |
50 | 48 |
|
... | ... |
@@ -73,14 +71,14 @@ example for learning to build new commands, you're welcome to fork it. |
73 | 71 |
L<Mojolicious::Command::cpanify> inherits all attributes from |
74 | 72 |
L<Mojolicious::Command> and implements the following new ones. |
75 | 73 |
|
76 |
-=head2 C<description> |
|
74 |
+=head2 description |
|
77 | 75 |
|
78 | 76 |
my $description = $cpanify->description; |
79 | 77 |
$cpanify = $cpanify->description('Foo!'); |
80 | 78 |
|
81 | 79 |
Short description of this command, used for the command list. |
82 | 80 |
|
83 |
-=head2 C<usage> |
|
81 |
+=head2 usage |
|
84 | 82 |
|
85 | 83 |
my $usage = $cpanify->usage; |
86 | 84 |
$cpanify = $cpanify->usage('Foo!'); |
... | ... |
@@ -92,7 +90,7 @@ Usage information for this command, used for the help screen. |
92 | 90 |
L<Mojolicious::Command::cpanify> inherits all methods from |
93 | 91 |
L<Mojolicious::Command> and implements the following new ones. |
94 | 92 |
|
95 |
-=head2 C<run> |
|
93 |
+=head2 run |
|
96 | 94 |
|
97 | 95 |
$cpanify->run(@ARGV); |
98 | 96 |
|
... | ... |
@@ -9,27 +9,25 @@ has usage => <<"EOF"; |
9 | 9 |
usage: $0 daemon [OPTIONS] |
10 | 10 |
|
11 | 11 |
These options are available: |
12 |
- -b, --backlog <size> Set listen backlog size, defaults to |
|
13 |
- SOMAXCONN. |
|
14 |
- -c, --clients <number> Set maximum number of concurrent clients, |
|
15 |
- defaults to 1000. |
|
16 |
- -g, --group <name> Set group name for process. |
|
17 |
- -i, --inactivity <seconds> Set inactivity timeout, defaults to the value |
|
18 |
- of MOJO_INACTIVITY_TIMEOUT or 15. |
|
19 |
- -l, --listen <location> Set one or more locations you want to listen |
|
20 |
- on, defaults to the value of MOJO_LISTEN or |
|
12 |
+ -b, --backlog <size> Listen backlog size, defaults to SOMAXCONN. |
|
13 |
+ -c, --clients <number> Maximum number of concurrent clients, defaults |
|
14 |
+ to 1000. |
|
15 |
+ -g, --group <name> Group name for process. |
|
16 |
+ -i, --inactivity <seconds> Inactivity timeout, defaults to the value of |
|
17 |
+ MOJO_INACTIVITY_TIMEOUT or 15. |
|
18 |
+ -l, --listen <location> One or more locations you want to listen on, |
|
19 |
+ defaults to the value of MOJO_LISTEN or |
|
21 | 20 |
"http://*:3000". |
22 | 21 |
-p, --proxy Activate reverse proxy support, defaults to |
23 | 22 |
the value of MOJO_REVERSE_PROXY. |
24 |
- -r, --requests <number> Set maximum number of requests per keep-alive |
|
23 |
+ -r, --requests <number> Maximum number of requests per keep-alive |
|
25 | 24 |
connection, defaults to 25. |
26 |
- -u, --user <name> Set username for process. |
|
25 |
+ -u, --user <name> Username for process. |
|
27 | 26 |
EOF |
28 | 27 |
|
29 | 28 |
sub run { |
30 | 29 |
my ($self, @args) = @_; |
31 | 30 |
|
32 |
- # Options |
|
33 | 31 |
my $daemon = Mojo::Server::Daemon->new(app => $self->app); |
34 | 32 |
GetOptionsFromArray \@args, |
35 | 33 |
'b|backlog=i' => sub { $daemon->backlog($_[1]) }, |
... | ... |
@@ -41,7 +39,6 @@ sub run { |
41 | 39 |
'r|requests=i' => sub { $daemon->max_requests($_[1]) }, |
42 | 40 |
'u|user=s' => sub { $daemon->user($_[1]) }; |
43 | 41 |
|
44 |
- # Start |
|
45 | 42 |
$daemon->listen(\@listen) if @listen; |
46 | 43 |
$daemon->run; |
47 | 44 |
} |
... | ... |
@@ -72,14 +69,14 @@ example for learning to build new commands, you're welcome to fork it. |
72 | 69 |
L<Mojolicious::Command::daemon> inherits all attributes from |
73 | 70 |
L<Mojolicious::Command> and implements the following new ones. |
74 | 71 |
|
75 |
-=head2 C<description> |
|
72 |
+=head2 description |
|
76 | 73 |
|
77 | 74 |
my $description = $daemon->description; |
78 | 75 |
$daemon = $daemon->description('Foo!'); |
79 | 76 |
|
80 | 77 |
Short description of this command, used for the command list. |
81 | 78 |
|
82 |
-=head2 C<usage> |
|
79 |
+=head2 usage |
|
83 | 80 |
|
84 | 81 |
my $usage = $daemon->usage; |
85 | 82 |
$daemon = $daemon->usage('Foo!'); |
... | ... |
@@ -91,7 +88,7 @@ Usage information for this command, used for the help screen. |
91 | 88 |
L<Mojolicious::Command::daemon> inherits all methods from |
92 | 89 |
L<Mojolicious::Command> and implements the following new ones. |
93 | 90 |
|
94 |
-=head2 C<run> |
|
91 |
+=head2 run |
|
95 | 92 |
|
96 | 93 |
$daemon->run(@ARGV); |
97 | 94 |
|
... | ... |
@@ -17,7 +17,6 @@ EOF |
17 | 17 |
sub run { |
18 | 18 |
my ($self, @args) = @_; |
19 | 19 |
|
20 |
- # Options |
|
21 | 20 |
GetOptionsFromArray \@args, 'v|verbose' => \my $verbose; |
22 | 21 |
my $code = shift @args || ''; |
23 | 22 |
|
... | ... |
@@ -54,14 +53,14 @@ example for learning to build new commands, you're welcome to fork it. |
54 | 53 |
L<Mojolicious::Command::eval> inherits all attributes from |
55 | 54 |
L<Mojolicious::Command> and implements the following new ones. |
56 | 55 |
|
57 |
-=head2 C<description> |
|
56 |
+=head2 description |
|
58 | 57 |
|
59 | 58 |
my $description = $eval->description; |
60 | 59 |
$eval = $eval->description('Foo!'); |
61 | 60 |
|
62 | 61 |
Short description of this command, used for the command list. |
63 | 62 |
|
64 |
-=head2 C<usage> |
|
63 |
+=head2 usage |
|
65 | 64 |
|
66 | 65 |
my $usage = $eval->usage; |
67 | 66 |
$eval = $eval->usage('Foo!'); |
... | ... |
@@ -73,7 +72,7 @@ Usage information for this command, used for the help screen. |
73 | 72 |
L<Mojolicious::Command::eval> inherits all methods from |
74 | 73 |
L<Mojolicious::Command> and implements the following new ones. |
75 | 74 |
|
76 |
-=head2 C<run> |
|
75 |
+=head2 run |
|
77 | 76 |
|
78 | 77 |
$eval->run(@ARGV); |
79 | 78 |
|
... | ... |
@@ -41,35 +41,35 @@ example for learning to build new commands, you're welcome to fork it. |
41 | 41 |
L<Mojolicious::Command::generate> inherits all attributes from |
42 | 42 |
L<Mojolicious::Commands> and implements the following new ones. |
43 | 43 |
|
44 |
-=head2 C<description> |
|
44 |
+=head2 description |
|
45 | 45 |
|
46 | 46 |
my $description = $generator->description; |
47 | 47 |
$generator = $generator->description('Foo!'); |
48 | 48 |
|
49 | 49 |
Short description of this command, used for the command list. |
50 | 50 |
|
51 |
-=head2 C<hint> |
|
51 |
+=head2 hint |
|
52 | 52 |
|
53 | 53 |
my $hint = $generator->hint; |
54 | 54 |
$generator = $generator->hint('Foo!'); |
55 | 55 |
|
56 | 56 |
Short hint shown after listing available generator commands. |
57 | 57 |
|
58 |
-=head2 C<usage> |
|
58 |
+=head2 usage |
|
59 | 59 |
|
60 | 60 |
my $usage = $generator->usage; |
61 | 61 |
$generator = $generator->usage('Foo!'); |
62 | 62 |
|
63 | 63 |
Usage information for this command, used for the help screen. |
64 | 64 |
|
65 |
-=head2 C<message> |
|
65 |
+=head2 message |
|
66 | 66 |
|
67 | 67 |
my $msg = $generator->message; |
68 | 68 |
$generator = $generator->message('Bar!'); |
69 | 69 |
|
70 | 70 |
Short usage message shown before listing available generator commands. |
71 | 71 |
|
72 |
-=head2 C<namespaces> |
|
72 |
+=head2 namespaces |
|
73 | 73 |
|
74 | 74 |
my $namespaces = $generator->namespaces; |
75 | 75 |
$generator = $generator->namespaces(['MyApp::Command::generate']); |
... | ... |
@@ -82,7 +82,7 @@ L<Mojolicious::Command::generate>. |
82 | 82 |
L<Mojolicious::Command::generate> inherits all methods from |
83 | 83 |
L<Mojolicious::Commands> and implements the following new ones. |
84 | 84 |
|
85 |
-=head2 C<help> |
|
85 |
+=head2 help |
|
86 | 86 |
|
87 | 87 |
$generator->help('app'); |
88 | 88 |
|
... | ... |
@@ -59,7 +59,7 @@ use warnings; |
59 | 59 |
use FindBin; |
60 | 60 |
use lib "$FindBin::Bin/../lib"; |
61 | 61 |
|
62 |
-# Start commands for application |
|
62 |
+# Start command line interface for application |
|
63 | 63 |
require Mojolicious::Commands; |
64 | 64 |
Mojolicious::Commands->start_app('<%= $class %>'); |
65 | 65 |
|
... | ... |
@@ -166,14 +166,14 @@ example for learning to build new commands, you're welcome to fork it. |
166 | 166 |
L<Mojolicious::Command::generate::app> inherits all attributes from |
167 | 167 |
L<Mojolicious::Command> and implements the following new ones. |
168 | 168 |
|
169 |
-=head2 C<description> |
|
169 |
+=head2 description |
|
170 | 170 |
|
171 | 171 |
my $description = $app->description; |
172 | 172 |
$app = $app->description('Foo!'); |
173 | 173 |
|
174 | 174 |
Short description of this command, used for the command list. |
175 | 175 |
|
176 |
-=head2 C<usage> |
|
176 |
+=head2 usage |
|
177 | 177 |
|
178 | 178 |
my $usage = $app->usage; |
179 | 179 |
$app = $app->usage('Foo!'); |
... | ... |
@@ -185,7 +185,7 @@ Usage information for this command, used for the help screen. |
185 | 185 |
L<Mojolicious::Command::generate::app> inherits all methods from |
186 | 186 |
L<Mojolicious::Command> and implements the following new ones. |
187 | 187 |
|
188 |
-=head2 C<run> |
|
188 |
+=head2 run |
|
189 | 189 |
|
190 | 190 |
$app->run(@ARGV); |
191 | 191 |
|
... | ... |
@@ -66,14 +66,14 @@ example for learning to build new commands, you're welcome to fork it. |
66 | 66 |
L<Mojolicious::Command::generate::lite_app> inherits all attributes from |
67 | 67 |
L<Mojolicious::Command> and implements the following new ones. |
68 | 68 |
|
69 |
-=head2 C<description> |
|
69 |
+=head2 description |
|
70 | 70 |
|
71 | 71 |
my $description = $app->description; |
72 | 72 |
$app = $app->description('Foo!'); |
73 | 73 |
|
74 | 74 |
Short description of this command, used for the command list. |
75 | 75 |
|
76 |
-=head2 C<usage> |
|
76 |
+=head2 usage |
|
77 | 77 |
|
78 | 78 |
my $usage = $app->usage; |
79 | 79 |
$app = $app->usage('Foo!'); |
... | ... |
@@ -85,7 +85,7 @@ Usage information for this command, used for the help screen. |
85 | 85 |
L<Mojolicious::Command::generate::lite_app> inherits all methods from |
86 | 86 |
L<Mojolicious::Command> and implements the following new ones. |
87 | 87 |
|
88 |
-=head2 C<run> |
|
88 |
+=head2 run |
|
89 | 89 |
|
90 | 90 |
$app->run(@ARGV); |
91 | 91 |
|
... | ... |
@@ -48,14 +48,14 @@ example for learning to build new commands, you're welcome to fork it. |
48 | 48 |
L<Mojolicious::Command::generate::makefile> inherits all attributes from |
49 | 49 |
L<Mojolicious::Command> and implements the following new ones. |
50 | 50 |
|
51 |
-=head2 C<description> |
|
51 |
+=head2 description |
|
52 | 52 |
|
53 | 53 |
my $description = $makefile->description; |
54 | 54 |
$makefile = $makefile->description('Foo!'); |
55 | 55 |
|
56 | 56 |
Short description of this command, used for the command list. |
57 | 57 |
|
58 |
-=head2 C<usage> |
|
58 |
+=head2 usage |
|
59 | 59 |
|
60 | 60 |
my $usage = $makefile->usage; |
61 | 61 |
$makefile = $makefile->usage('Foo!'); |
... | ... |
@@ -67,7 +67,7 @@ Usage information for this command, used for the help screen. |
67 | 67 |
L<Mojolicious::Command::generate::makefile> inherits all methods from |
68 | 68 |
L<Mojolicious::Command> and implements the following new ones. |
69 | 69 |
|
70 |
-=head2 C<run> |
|
70 |
+=head2 run |
|
71 | 71 |
|
72 | 72 |
$makefile->run(@ARGV); |
73 | 73 |
|
... | ... |
@@ -62,7 +62,7 @@ L<<%= $class %>> is a L<Mojolicious> plugin. |
62 | 62 |
L<<%= $class %>> inherits all methods from |
63 | 63 |
L<Mojolicious::Plugin> and implements the following new ones. |
64 | 64 |
|
65 |
-<% %>=head2 C<register> |
|
65 |
+<% %>=head2 register |
|
66 | 66 |
|
67 | 67 |
$plugin->register(Mojolicious->new); |
68 | 68 |
|
... | ... |
@@ -134,14 +134,14 @@ example for learning to build new commands, you're welcome to fork it. |
134 | 134 |
L<Mojolicious::Command::generate::plugin> inherits all attributes from |
135 | 135 |
L<Mojolicious::Command> and implements the following new ones. |
136 | 136 |
|
137 |
-=head2 C<description> |
|
137 |
+=head2 description |
|
138 | 138 |
|
139 | 139 |
my $description = $plugin->description; |
140 | 140 |
$plugin = $plugin->description('Foo!'); |
141 | 141 |
|
142 | 142 |
Short description of this command, used for the command list. |
143 | 143 |
|
144 |
-=head2 C<usage> |
|
144 |
+=head2 usage |
|
145 | 145 |
|
146 | 146 |
my $usage = $plugin->usage; |
147 | 147 |
$plugin = $plugin->usage('Foo!'); |
... | ... |
@@ -153,7 +153,7 @@ Usage information for this command, used for the help screen. |
153 | 153 |
L<Mojolicious::Command::generate::plugin> inherits all methods from |
154 | 154 |
L<Mojolicious::Command> and implements the following new ones. |
155 | 155 |
|
156 |
-=head2 C<run> |
|
156 |
+=head2 run |
|
157 | 157 |
|
158 | 158 |
$plugin->run(@ARGV); |
159 | 159 |
|
... | ... |
@@ -38,7 +38,6 @@ EOF |
38 | 38 |
sub run { |
39 | 39 |
my ($self, @args) = @_; |
40 | 40 |
|
41 |
- # Options |
|
42 | 41 |
GetOptionsFromArray \@args, |
43 | 42 |
'C|charset=s' => \my $charset, |
44 | 43 |
'c|content=s' => \(my $content = ''), |
... | ... |
@@ -46,37 +45,28 @@ sub run { |
46 | 45 |
'M|method=s' => \(my $method = 'GET'), |
47 | 46 |
'r|redirect' => \my $redirect, |
48 | 47 |
'v|verbose' => \my $verbose; |
49 |
- $verbose = 1 if $method eq 'HEAD'; |
|
50 |
- |
|
51 |
- # Headers |
|
52 |
- my %headers; |
|
53 |
- /^\s*([^:]+)\s*:\s*(.+)$/ and $headers{$1} = $2 for @headers; |
|
54 | 48 |
|
55 |
- # URL and selector |
|
56 | 49 |
die $self->usage unless my $url = decode 'UTF-8', do {my $tmp = shift @args; defined $tmp ? $tmp : ''}; |
57 | 50 |
my $selector = shift @args; |
58 | 51 |
|
59 |
- # Fresh user agent |
|
52 |
+ # Parse header pairs |
|
53 |
+ my %headers; |
|
54 |
+ /^\s*([^:]+)\s*:\s*(.+)$/ and $headers{$1} = $2 for @headers; |
|
55 |
+ |
|
56 |
+ # Use global event loop singleton |
|
60 | 57 |
my $ua = Mojo::UserAgent->new(ioloop => Mojo::IOLoop->singleton); |
61 | 58 |
$ua->max_redirects(10) if $redirect; |
62 | 59 |
|
63 |
- # Absolute URL |
|
64 |
- if ($url !~ m!/!) { $ua->detect_proxy } |
|
65 |
- |
|
66 |
- # Application |
|
67 |
- else { $ua->app($self->app) } |
|
60 |
+ # Detect proxy for absolute URLs |
|
61 |
+ if ($url !~ m!/!) { $ua->detect_proxy } |
|
62 |
+ else { $ua->app($self->app) } |
|
68 | 63 |
|
69 |
- # Start |
|
64 |
+ # Do the real work with "start" event |
|
70 | 65 |
my $v = my $buffer = ''; |
71 | 66 |
$ua->on( |
72 | 67 |
start => sub { |
73 | 68 |
my $tx = pop; |
74 | 69 |
|
75 |
- # Prepare request information |
|
76 |
- my $req = $tx->req; |
|
77 |
- my $startline = $req->build_start_line; |
|
78 |
- my $req_headers = $req->build_headers; |
|
79 |
- |
|
80 | 70 |
# Verbose callback |
81 | 71 |
my $v = $verbose; |
82 | 72 |
my $cb = sub { |
... | ... |
@@ -84,22 +74,21 @@ sub run { |
84 | 74 |
|
85 | 75 |
# Wait for headers |
86 | 76 |
return unless $v && $res->headers->is_finished; |
77 |
+ $v = undef; |
|
87 | 78 |
|
88 |
- # Request |
|
79 |
+ # Show request |
|
80 |
+ my $req = $tx->req; |
|
81 |
+ my $startline = $req->build_start_line; |
|
82 |
+ my $req_headers = $req->build_headers; |
|
89 | 83 |
warn "$startline$req_headers"; |
90 | 84 |
|
91 |
- # Response |
|
85 |
+ # Show response |
|
92 | 86 |
my $version = $res->version; |
93 | 87 |
my $code = $res->code; |
94 | 88 |
my $msg = $res->message; |
95 | 89 |
my $res_headers = $res->headers->to_string; |
96 | 90 |
warn "HTTP/$version $code $msg\n$res_headers\n\n"; |
97 |
- |
|
98 |
- # Finished |
|
99 |
- $v = undef; |
|
100 | 91 |
}; |
101 |
- |
|
102 |
- # Progress |
|
103 | 92 |
$tx->res->on(progress => $cb); |
104 | 93 |
|
105 | 94 |
# Stream content |
... | ... |
@@ -109,19 +98,16 @@ sub run { |
109 | 98 |
|
110 | 99 |
# Ignore intermediate content |
111 | 100 |
return if $redirect && $res->is_status_class(300); |
112 |
- |
|
113 |
- # Chunk |
|
114 | 101 |
$selector ? ($buffer .= pop) : print(pop); |
115 | 102 |
} |
116 | 103 |
); |
117 | 104 |
} |
118 | 105 |
); |
119 | 106 |
|
120 |
- # Get |
|
107 |
+ # Switch to verbose for HEAD requests |
|
108 |
+ $verbose = 1 if $method eq 'HEAD'; |
|
121 | 109 |
STDOUT->autoflush(1); |
122 | 110 |
my $tx = $ua->start($ua->build_tx($method, $url, \%headers, $content)); |
123 |
- |
|
124 |
- # Error |
|
125 | 111 |
my ($err, $code) = $tx->error; |
126 | 112 |
$url = encode 'UTF-8', $url; |
127 | 113 |
warn qq{Problem loading URL "$url". ($err)\n} if $err && !$code; |
... | ... |
@@ -151,11 +137,9 @@ sub _say { |
151 | 137 |
sub _select { |
152 | 138 |
my ($buffer, $selector, $charset, @args) = @_; |
153 | 139 |
|
154 |
- # Find |
|
155 | 140 |
my $dom = Mojo::DOM->new->charset($charset)->parse($buffer); |
156 | 141 |
my $results = $dom->find($selector); |
157 | 142 |
|
158 |
- # Commands |
|
159 | 143 |
my $finished; |
160 | 144 |
while (defined(my $command = shift @args)) { |
161 | 145 |
|
... | ... |
@@ -182,7 +166,6 @@ sub _select { |
182 | 166 |
$finished++; |
183 | 167 |
} |
184 | 168 |
|
185 |
- # Render |
|
186 | 169 |
unless ($finished) { _say($_) for @$results } |
187 | 170 |
} |
188 | 171 |
|
... | ... |
@@ -211,14 +194,14 @@ example for learning to build new commands, you're welcome to fork it. |
211 | 194 |
L<Mojolicious::Command::get> performs requests to remote hosts or local |
212 | 195 |
applications. |
213 | 196 |
|
214 |
-=head2 C<description> |
|
197 |
+=head2 description |
|
215 | 198 |
|
216 | 199 |
my $description = $get->description; |
217 | 200 |
$get = $get->description('Foo!'); |
218 | 201 |
|
219 | 202 |
Short description of this command, used for the command list. |
220 | 203 |
|
221 |
-=head2 C<usage> |
|
204 |
+=head2 usage |
|
222 | 205 |
|
223 | 206 |
my $usage = $get->usage; |
224 | 207 |
$get = $get->usage('Foo!'); |
... | ... |
@@ -230,7 +213,7 @@ Usage information for this command, used for the help screen. |
230 | 213 |
L<Mojolicious::Command::get> inherits all methods from L<Mojolicious::Command> |
231 | 214 |
and implements the following new ones. |
232 | 215 |
|
233 |
-=head2 C<run> |
|
216 |
+=head2 run |
|
234 | 217 |
|
235 | 218 |
$get->run(@ARGV); |
236 | 219 |
|
... | ... |
@@ -51,14 +51,14 @@ example for learning to build new commands, you're welcome to fork it. |
51 | 51 |
L<Mojolicious::Command::inflate> inherits all attributes from |
52 | 52 |
L<Mojolicious::Command> and implements the following new ones. |
53 | 53 |
|
54 |
-=head2 C<description> |
|
54 |
+=head2 description |
|
55 | 55 |
|
56 | 56 |
my $description = $inflate->description; |
57 | 57 |
$inflate = $inflate->description('Foo!'); |
58 | 58 |
|
59 | 59 |
Short description of this command, used for the command list. |
60 | 60 |
|
61 |
-=head2 C<usage> |
|
61 |
+=head2 usage |
|
62 | 62 |
|
63 | 63 |
my $usage = $inflate->usage; |
64 | 64 |
$inflate = $inflate->usage('Foo!'); |
... | ... |
@@ -70,7 +70,7 @@ Usage information for this command, used for the help screen. |
70 | 70 |
L<Mojolicious::Command::inflate> inherits all methods from |
71 | 71 |
L<Mojolicious::Command> and implements the following new ones. |
72 | 72 |
|
73 |
-=head2 C<run> |
|
73 |
+=head2 run |
|
74 | 74 |
|
75 | 75 |
$inflate->run(@ARGV); |
76 | 76 |
|
... | ... |
@@ -0,0 +1,128 @@ |
1 |
+package Mojolicious::Command::prefork; |
|
2 |
+use Mojo::Base 'Mojolicious::Command'; |
|
3 |
+ |
|
4 |
+use Getopt::Long qw(GetOptionsFromArray :config no_auto_abbrev no_ignore_case); |
|
5 |
+use Mojo::Server::Prefork; |
|
6 |
+ |
|
7 |
+has description => |
|
8 |
+ "Start application with preforking HTTP and WebSocket server.\n"; |
|
9 |
+has usage => <<"EOF"; |
|
10 |
+usage: $0 prefork [OPTIONS] |
|
11 |
+ |
|
12 |
+These options are available: |
|
13 |
+ -A, --accepts <number> Number of connections for workers to |
|
14 |
+ accept, defaults to 1000. |
|
15 |
+ -a, --accept-interval <seconds> Accept interval, defaults to 0.025. |
|
16 |
+ -b, --backlog <size> Listen backlog size, defaults to |
|
17 |
+ SOMAXCONN. |
|
18 |
+ -c, --clients <number> Maximum number of concurrent clients, |
|
19 |
+ defaults to 1000. |
|
20 |
+ -G, --graceful-timeout <seconds> Graceful timeout, defaults to 20. |
|
21 |
+ -g, --group <name> Group name for process. |
|
22 |
+ --heartbeat-interval <seconds> Heartbeat interval, defaults to 5. |
|
23 |
+ -H, --heartbeat-timeout <seconds> Heartbeat timeout, defaults to 20. |
|
24 |
+ -i, --inactivity <seconds> Inactivity timeout, defaults to the |
|
25 |
+ value of MOJO_INACTIVITY_TIMEOUT or 15. |
|
26 |
+ --lock-file <path> Path to lock file, defaults to a random |
|
27 |
+ file. |
|
28 |
+ -L, --lock-timeout <seconds> Lock timeout, defaults to 0.5. |
|
29 |
+ -l, --listen <location> One or more locations you want to |
|
30 |
+ listen on, defaults to the value of |
|
31 |
+ MOJO_LISTEN or "http://*:3000". |
|
32 |
+ --multi-accept <number> Number of connection to accept at once, |
|
33 |
+ defaults to 50. |
|
34 |
+ -P, --pid-file <path> Path to process id file, defaults to a |
|
35 |
+ random file. |
|
36 |
+ -p, --proxy Activate reverse proxy support, |
|
37 |
+ defaults to the value of |
|
38 |
+ MOJO_REVERSE_PROXY. |
|
39 |
+ -r, --requests <number> Maximum number of requests per |
|
40 |
+ keep-alive connection, defaults to 25. |
|
41 |
+ -u, --user <name> Username for process. |
|
42 |
+ -w, --workers <number> Number of workers, defaults to 4. |
|
43 |
+EOF |
|
44 |
+ |
|
45 |
+sub run { |
|
46 |
+ my ($self, @args) = @_; |
|
47 |
+ |
|
48 |
+ my $prefork = Mojo::Server::Prefork->new(app => $self->app); |
|
49 |
+ GetOptionsFromArray \@args, |
|
50 |
+ 'A|accepts=i' => sub { $prefork->accepts($_[1]) }, |
|
51 |
+ 'a|accept-interval=i' => sub { $prefork->accept_interval($_[1]) }, |
|
52 |
+ 'b|backlog=i' => sub { $prefork->backlog($_[1]) }, |
|
53 |
+ 'c|clients=i' => sub { $prefork->max_clients($_[1]) }, |
|
54 |
+ 'G|graceful-timeout=i' => sub { $prefork->graceful_timeout($_[1]) }, |
|
55 |
+ 'g|group=s' => sub { $prefork->group($_[1]) }, |
|
56 |
+ 'heartbeat-interval=i' => sub { $prefork->heartbeat_interval($_[1]) }, |
|
57 |
+ 'H|heartbeat-timeout=i' => sub { $prefork->heartbeat_timeout($_[1]) }, |
|
58 |
+ 'i|inactivity=i' => sub { $prefork->inactivity_timeout($_[1]) }, |
|
59 |
+ 'lock-file=s' => sub { $prefork->lock_file($_[1]) }, |
|
60 |
+ 'L|lock-timeout=i' => sub { $prefork->lock_timeout($_[1]) }, |
|
61 |
+ 'l|listen=s' => \my @listen, |
|
62 |
+ 'multi-accept=i' => sub { $prefork->multi_accept($_[1]) }, |
|
63 |
+ 'P|pid-file=s' => sub { $prefork->pid_file($_[1]) }, |
|
64 |
+ 'p|proxy' => sub { $ENV{MOJO_REVERSE_PROXY} = 1 }, |
|
65 |
+ 'r|requests=i' => sub { $prefork->max_requests($_[1]) }, |
|
66 |
+ 'u|user=s' => sub { $prefork->user($_[1]) }, |
|
67 |
+ 'w|workers=i' => sub { $prefork->workers($_[1]) }; |
|
68 |
+ |
|
69 |
+ $prefork->listen(\@listen) if @listen; |
|
70 |
+ $prefork->run; |
|
71 |
+} |
|
72 |
+ |
|
73 |
+1; |
|
74 |
+ |
|
75 |
+=head1 NAME |
|
76 |
+ |
|
77 |
+Mojolicious::Command::prefork - Prefork command |
|
78 |
+ |
|
79 |
+=head1 SYNOPSIS |
|
80 |
+ |
|
81 |
+ use Mojolicious::Command::prefork; |
|
82 |
+ |
|
83 |
+ my $prefork = Mojolicious::Command::prefork->new; |
|
84 |
+ $prefork->run(@ARGV); |
|
85 |
+ |
|
86 |
+=head1 DESCRIPTION |
|
87 |
+ |
|
88 |
+L<Mojolicious::Command::prefork> starts applications with |
|
89 |
+L<Mojo::Server::Prefork> backend. |
|
90 |
+ |
|
91 |
+This is a core command, that means it is always enabled and its code a good |
|
92 |
+example for learning to build new commands, you're welcome to fork it. |
|
93 |
+ |
|
94 |
+=head1 ATTRIBUTES |
|
95 |
+ |
|
96 |
+L<Mojolicious::Command::prefork> inherits all attributes from |
|
97 |
+L<Mojolicious::Command> and implements the following new ones. |
|
98 |
+ |
|
99 |
+=head2 description |
|
100 |
+ |
|
101 |
+ my $description = $prefork->description; |
|
102 |
+ $prefork = $prefork->description('Foo!'); |
|
103 |
+ |
|
104 |
+Short description of this command, used for the command list. |
|
105 |
+ |
|
106 |
+=head2 usage |
|
107 |
+ |
|
108 |
+ my $usage = $prefork->usage; |
|
109 |
+ $prefork = $prefork->usage('Foo!'); |
|
110 |
+ |
|
111 |
+Usage information for this command, used for the help screen. |
|
112 |
+ |
|
113 |
+=head1 METHODS |
|
114 |
+ |
|
115 |
+L<Mojolicious::Command::prefork> inherits all methods from |
|
116 |
+L<Mojolicious::Command> and implements the following new ones. |
|
117 |
+ |
|
118 |
+=head2 run |
|
119 |
+ |
|
120 |
+ $prefork->run(@ARGV); |
|
121 |
+ |
|
122 |
+Run this command. |
|
123 |
+ |
|
124 |
+=head1 SEE ALSO |
|
125 |
+ |
|
126 |
+L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>. |
|
127 |
+ |
|
128 |
+=cut |
... | ... |
@@ -34,14 +34,14 @@ example for learning to build new commands, you're welcome to fork it. |
34 | 34 |
L<Mojolicious::Command::psgi> inherits all attributes from |
35 | 35 |
L<Mojolicious::Command> and implements the following new ones. |
36 | 36 |
|
37 |
-=head2 C<description> |
|
37 |
+=head2 description |
|
38 | 38 |
|
39 | 39 |
my $description = $psgi->description; |
40 | 40 |
$psgi = $psgi->description('Foo!'); |
41 | 41 |
|
42 | 42 |
Short description of this command, used for the command list. |
43 | 43 |
|
44 |
-=head2 C<usage> |
|
44 |
+=head2 usage |
|
45 | 45 |
|
46 | 46 |
my $usage = $psgi->usage; |
47 | 47 |
$psgi = $psgi->usage('Foo!'); |
... | ... |
@@ -53,7 +53,7 @@ Usage information for this command, used for the help screen. |
53 | 53 |
L<Mojolicious::Command::psgi> inherits all methods from |
54 | 54 |
L<Mojolicious::Command> and implements the following new ones. |
55 | 55 |
|
56 |
-=head2 C<run> |
|
56 |
+=head2 run |
|
57 | 57 |
|
58 | 58 |
my $app = $psgi->run; |
59 | 59 |
|
... | ... |
@@ -15,10 +15,8 @@ EOF |
15 | 15 |
sub run { |
16 | 16 |
my ($self, @args) = @_; |
17 | 17 |
|
18 |
- # Options |
|
19 | 18 |
GetOptionsFromArray \@args, 'v|verbose' => \my $verbose; |
20 | 19 |
|
21 |
- # Walk and draw |
|
22 | 20 |
my $routes = []; |
23 | 21 |
$self->_walk($_, 0, $routes) for @{$self->app->routes->children}; |
24 | 22 |
$self->_draw($routes, $verbose); |
... | ... |
@@ -27,7 +25,7 @@ sub run { |
27 | 25 |
sub _draw { |
28 | 26 |
my ($self, $routes, $verbose) = @_; |
29 | 27 |
|
30 |
- # Length |
|
28 |
+ # Calculate column widths |
|
31 | 29 |
my @length = (0, 0, 0); |
32 | 30 |
for my $node (@$routes) { |
33 | 31 |
|
... | ... |
@@ -46,7 +44,7 @@ sub _draw { |
46 | 44 |
$length[2] = $len if $len > $length[2]; |
47 | 45 |
} |
48 | 46 |
|
49 |
- # Draw |
|
47 |
+ # Draw all routes |
|
50 | 48 |
for my $node (@$routes) { |
51 | 49 |
my @parts; |
52 | 50 |
|
... | ... |
@@ -75,7 +73,6 @@ sub _draw { |
75 | 73 |
$format .= '?' if $format && $optional; |
76 | 74 |
push @parts, $format ? "$regex$format" : $regex if $verbose; |
77 | 75 |
|
78 |
- # Route |
|
79 | 76 |
say join(' ', @parts); |
80 | 77 |
} |
81 | 78 |
} |
... | ... |
@@ -83,12 +80,10 @@ sub _draw { |
83 | 80 |
sub _walk { |
84 | 81 |
my ($self, $node, $depth, $routes) = @_; |
85 | 82 |
|
86 |
- # Pattern |
|
87 | 83 |
my $prefix = ''; |
88 | 84 |
if (my $i = $depth * 2) { $prefix .= ' ' x $i . '+' } |
89 | 85 |
push @$routes, [$prefix . ($node->pattern->pattern || '/'), $node]; |
90 | 86 |
|
91 |
- # Walk |
|
92 | 87 |
$depth++; |
93 | 88 |
$self->_walk($_, $depth, $routes) for @{$node->children}; |
94 | 89 |
$depth--; |
... | ... |
@@ -119,14 +114,14 @@ example for learning to build new commands, you're welcome to fork it. |
119 | 114 |
L<Mojolicious::Command::routes> inherits all attributes from |
120 | 115 |
L<Mojolicious::Command> and implements the following new ones. |
121 | 116 |
|
122 |
-=head2 C<description> |
|
117 |
+=head2 description |
|
123 | 118 |
|
124 | 119 |
my $description = $routes->description; |
125 | 120 |
$routes = $routes->description('Foo!'); |
126 | 121 |
|
127 | 122 |
Short description of this command, used for the command list. |
128 | 123 |
|
129 |
-=head2 C<usage> |
|
124 |
+=head2 usage |
|
130 | 125 |
|
131 | 126 |
my $usage = $routes->usage; |
132 | 127 |
$routes = $routes->usage('Foo!'); |
... | ... |
@@ -138,7 +133,7 @@ Usage information for this command, used for the help screen. |
138 | 133 |
L<Mojolicious::Command::routes> inherits all methods from |
139 | 134 |
L<Mojolicious::Command> and implements the following new ones. |
140 | 135 |
|
141 |
-=head2 C<run> |
|
136 |
+=head2 run |
|
142 | 137 |
|
143 | 138 |
$routes->run(@ARGV); |
144 | 139 |
|
... | ... |
@@ -18,28 +18,23 @@ EOF |
18 | 18 |
sub run { |
19 | 19 |
my ($self, @args) = @_; |
20 | 20 |
|
21 |
- # Options |
|
22 | 21 |
GetOptionsFromArray \@args, 'v|verbose' => sub { $ENV{HARNESS_VERBOSE} = 1 }; |
23 | 22 |
|
24 |
- # Search tests |
|
25 | 23 |
unless (@args) { |
26 | 24 |
my @base = splitdir(abs2rel $FindBin::Bin); |
27 | 25 |
|
28 |
- # Test directory in the same directory as "mojo" (t) |
|
26 |
+ # "./t" |
|
29 | 27 |
my $path = catdir @base, 't'; |
30 | 28 |
|
31 |
- # Test dirctory in the directory above "mojo" (../t) |
|
29 |
+ # "../t" |
|
32 | 30 |
$path = catdir @base, '..', 't' unless -d $path; |
33 | 31 |
die "Can't find test directory.\n" unless -d $path; |
34 | 32 |
|
35 |
- # List test files |
|
36 | 33 |
my $home = Mojo::Home->new($path); |
37 | 34 |
/\.t$/ and push(@args, $home->rel_file($_)) for @{$home->list_files}; |
38 |
- |
|
39 | 35 |
say "Running tests from '", realpath($path), "'."; |
40 | 36 |
} |
41 | 37 |
|
42 |
- # Run tests |
|
43 | 38 |
$ENV{HARNESS_OPTIONS} = defined $ENV{HARNESS_OPTIONS} ? $ENV{HARNESS_OPTIONS} : 'c'; |
44 | 39 |
require Test::Harness; |
45 | 40 |
Test::Harness::runtests(sort @args); |
... | ... |
@@ -70,14 +65,14 @@ example for learning to build new commands, you're welcome to fork it. |
70 | 65 |
L<Mojolicious::Command::test> inherits all attributes from |
71 | 66 |
L<Mojolicious::Command> and implements the following new ones. |
72 | 67 |
|
73 |
-=head2 C<description> |
|
68 |
+=head2 description |
|
74 | 69 |
|
75 | 70 |
my $description = $test->description; |
76 | 71 |
$test = $test->description('Foo!'); |
77 | 72 |
|
78 | 73 |
Short description of this command, used for the command list. |
79 | 74 |
|
80 |
-=head2 C<usage> |
|
75 |
+=head2 usage |
|
81 | 76 |
|
82 | 77 |
my $usage = $test->usage; |
83 | 78 |
$test = $test->usage('Foo!'); |
... | ... |
@@ -89,7 +84,7 @@ Usage information for this command, used for the help screen. |
89 | 84 |
L<Mojolicious::Command::test> inherits all methods from |
90 | 85 |
L<Mojolicious::Command> and implements the following new ones. |
91 | 86 |
|
92 |
-=head2 C<run> |
|
87 |
+=head2 run |
|
93 | 88 |
|
94 | 89 |
$test->run(@ARGV); |
95 | 90 |
|
... | ... |
@@ -11,14 +11,9 @@ has usage => "usage: $0 version\n"; |
11 | 11 |
sub run { |
12 | 12 |
my $self = shift; |
13 | 13 |
|
14 |
- # EV |
|
15 | 14 |
my $ev = eval 'use Mojo::Reactor::EV; 1' ? $EV::VERSION : 'not installed'; |
16 |
- |
|
17 |
- # IPv6 |
|
18 | 15 |
my $ipv6 |
19 | 16 |
= Mojo::IOLoop::Server::IPV6 ? $IO::Socket::IP::VERSION : 'not installed'; |
20 |
- |
|
21 |
- # TLS |
|
22 | 17 |
my $tls |
23 | 18 |
= Mojo::IOLoop::Server::TLS ? $IO::Socket::SSL::VERSION : 'not installed'; |
24 | 19 |
|
... | ... |
@@ -34,13 +29,12 @@ OPTIONAL |
34 | 29 |
|
35 | 30 |
EOF |
36 | 31 |
|
37 |
- # Latest version |
|
32 |
+ # Check latest version on CPAN |
|
38 | 33 |
my $latest = eval { |
39 | 34 |
my $ua = Mojo::UserAgent->new(max_redirects => 10)->detect_proxy; |
40 | 35 |
$ua->get('api.metacpan.org/v0/release/Mojolicious')->res->json->{version}; |
41 | 36 |
}; |
42 | 37 |
|
43 |
- # Message |
|
44 | 38 |
return unless $latest; |
45 | 39 |
my $msg = 'This version is up to date, have fun!'; |
46 | 40 |
$msg = 'Thanks for testing a development release, you are awesome!' |
... | ... |
@@ -76,14 +70,14 @@ example for learning to build new commands, you're welcome to fork it. |
76 | 70 |
L<Mojolicious::Command::version> inherits all attributes from |
77 | 71 |
L<Mojolicious::Command> and implements the following new ones. |
78 | 72 |
|
79 |
-=head2 C<description> |
|
73 |
+=head2 description |
|
80 | 74 |
|
81 | 75 |
my $description = $v->description; |
82 | 76 |
$v = $v->description('Foo!'); |
83 | 77 |
|
84 | 78 |
Short description of this command, used for the command list. |
85 | 79 |
|
86 |
-=head2 C<usage> |
|
80 |
+=head2 usage |
|
87 | 81 |
|
88 | 82 |
my $usage = $v->usage; |
89 | 83 |
$v = $v->usage('Foo!'); |
... | ... |
@@ -95,7 +89,7 @@ Usage information for this command, used for the help screen. |
95 | 89 |
L<Mojolicious::Command::version> inherits all methods from |
96 | 90 |
L<Mojolicious::Command> and implements the following new ones. |
97 | 91 |
|
98 |
-=head2 C<run> |
|
92 |
+=head2 run |
|
99 | 93 |
|
100 | 94 |
$v->run(@ARGV); |
101 | 95 |
|
... | ... |
@@ -1,8 +1,8 @@ |
1 | 1 |
package Mojolicious::Commands; |
2 | 2 |
use Mojo::Base 'Mojolicious::Command'; |
3 | 3 |
|
4 |
-use Getopt::Long |
|
5 |
- qw(GetOptions :config no_auto_abbrev no_ignore_case pass_through); |
|
4 |
+use Getopt::Long 'GetOptions'; |
|
5 |
+use List::Util 'max'; |
|
6 | 6 |
use Mojo::Server; |
7 | 7 |
|
8 | 8 |
has hint => <<"EOF"; |
... | ... |
@@ -41,11 +41,13 @@ sub detect { |
41 | 41 |
|
42 | 42 |
# Command line options for MOJO_HELP, MOJO_HOME and MOJO_MODE |
43 | 43 |
BEGIN { |
44 |
+ Getopt::Long::Configure(qw(no_auto_abbrev no_ignore_case pass_through)); |
|
44 | 45 |
GetOptions( |
45 | 46 |
'h|help' => sub { $ENV{MOJO_HELP} = 1 }, |
46 | 47 |
'home=s' => sub { $ENV{MOJO_HOME} = $_[1] }, |
47 | 48 |
'm|mode=s' => sub { $ENV{MOJO_MODE} = $_[1] } |
48 | 49 |
) unless __PACKAGE__->detect; |
50 |
+ Getopt::Long::Configure('default'); |
|
49 | 51 |
} |
50 | 52 |
|
51 | 53 |
sub run { |
... | ... |
@@ -64,7 +66,6 @@ sub run { |
64 | 66 |
$name = shift @args if my $help = $name eq 'help'; |
65 | 67 |
$help = $ENV{MOJO_HELP} = $ENV{MOJO_HELP} ? 1 : $help; |
66 | 68 |
|
67 |
- # Try all namespaces |
|
68 | 69 |
my $module; |
69 | 70 |
$module = _command("${_}::$name", 1) and last for @{$self->namespaces}; |
70 | 71 |
|
... | ... |
@@ -72,15 +73,15 @@ sub run { |
72 | 73 |
die qq{Unknown command "$name", maybe you need to install it?\n} |
73 | 74 |
unless $module; |
74 | 75 |
|
75 |
- # Run |
|
76 |
+ # Run command |
|
76 | 77 |
my $command = $module->new(app => $self->app); |
77 | 78 |
return $help ? $command->help(@args) : $command->run(@args); |
78 | 79 |
} |
79 | 80 |
|
80 |
- # Test |
|
81 |
+ # Hide list for tests |
|
81 | 82 |
return 1 if $ENV{HARNESS_ACTIVE}; |
82 | 83 |
|
83 |
- # Try all namespaces |
|
84 |
+ # Find all available commands |
|
84 | 85 |
my (@commands, %seen); |
85 | 86 |
my $loader = Mojo::Loader->new; |
86 | 87 |
for my $namespace (@{$self->namespaces}) { |
... | ... |
@@ -91,25 +92,23 @@ sub run { |
91 | 92 |
} |
92 | 93 |
} |
93 | 94 |
|
94 |
- # Make list |
|
95 |
- my @list; |
|
96 |
- my $max = 0; |
|
97 |
- for my $command (@commands) { |
|
98 |
- my $len = length $command->[0]; |
|
99 |
- $max = $len if $len > $max; |
|
100 |
- push @list, [$command->[0], $command->[1]->new->description]; |
|
101 |
- } |
|
102 |
- |
|
103 |
- # Print list |
|
95 |
+ # Print list of all available commands |
|
96 |
+ my $max = max map { length $_->[0] } @commands; |
|
104 | 97 |
print $self->message; |
105 |
- for my $command (@list) { |
|
106 |
- my ($name, $description) = @$command; |
|
107 |
- print " $name" . (' ' x ($max - length $name)) . " $description"; |
|
98 |
+ for my $command (@commands) { |
|
99 |
+ my $name = $command->[0]; |
|
100 |
+ my $description = $command->[1]->new->description; |
|
101 |
+ print " $name", (' ' x ($max - length $name)), " $description"; |
|
108 | 102 |
} |
109 | 103 |
return print $self->hint; |
110 | 104 |
} |
111 | 105 |
|
106 |
+# DEPRECATED in Rainbow! |
|
112 | 107 |
sub start { |
108 |
+ warn <<EOF; |
|
109 |
+Mojolicious::Commands->start is DEPRECATED in favor of |
|
110 |
+Mojolicious::Commands->start_app!!! |
|
111 |
+EOF |
|
113 | 112 |
my $self = shift; |
114 | 113 |
return $self->start_app($ENV{MOJO_APP} => @_) if $ENV{MOJO_APP}; |
115 | 114 |
return $self->new->app->start(@_); |
... | ... |
@@ -151,7 +150,7 @@ the C<Mojolicious::Command> namespace. |
151 | 150 |
|
152 | 151 |
These commands are available by default. |
153 | 152 |
|
154 |
-=head2 C<help> |
|
153 |
+=head2 help |
|
155 | 154 |
|
156 | 155 |
$ mojo |
157 | 156 |
$ mojo help |
... | ... |
@@ -164,31 +163,31 @@ List available commands with short descriptions. |
164 | 163 |
|
165 | 164 |
List available options for the command with short descriptions. |
166 | 165 |
|
167 |
-=head2 C<cgi> |
|
166 |
+=head2 cgi |
|
168 | 167 |
|
169 | 168 |
$ ./myapp.pl cgi |
170 | 169 |
|
171 | 170 |
Start application with CGI backend, usually auto detected. |
172 | 171 |
|
173 |
-=head2 C<cpanify> |
|
172 |
+=head2 cpanify |
|
174 | 173 |
|
175 | 174 |
$ mojo cpanify -u sri -p secr3t Mojolicious-Plugin-Fun-0.1.tar.gz |
176 | 175 |
|
177 | 176 |
Upload files to CPAN. |
178 | 177 |
|
179 |
-=head2 C<daemon> |
|
178 |
+=head2 daemon |
|
180 | 179 |
|
181 | 180 |
$ ./myapp.pl daemon |
182 | 181 |
|
183 |
-Start application with standalone HTTP server backend. |
|
182 |
+Start application with standalone HTTP and WebSocket server server. |
|
184 | 183 |
|
185 |
-=head2 C<eval> |
|
184 |
+=head2 eval |
|
186 | 185 |
|
187 | 186 |
$ ./myapp.pl eval 'say app->home' |
188 | 187 |
|
189 | 188 |
Run code against application. |
190 | 189 |
|
191 |
-=head2 C<generate> |
|
190 |
+=head2 generate |
|
192 | 191 |
|
193 | 192 |
$ mojo generate |
194 | 193 |
$ mojo generate help |
... | ... |
@@ -201,66 +200,72 @@ List available generator commands with short descriptions. |
201 | 200 |
|
202 | 201 |
List available options for generator command with short descriptions. |
203 | 202 |
|
204 |
-=head2 C<generate app> |
|
203 |
+=head2 generate app |
|
205 | 204 |
|
206 | 205 |
$ mojo generate app <AppName> |
207 | 206 |
|
208 | 207 |
Generate application directory structure for a fully functional L<Mojolicious> |
209 | 208 |
application. |
210 | 209 |
|
211 |
-=head2 C<generate lite_app> |
|
210 |
+=head2 generate lite_app |
|
212 | 211 |
|
213 | 212 |
$ mojo generate lite_app |
214 | 213 |
|
215 | 214 |
Generate a fully functional L<Mojolicious::Lite> application. |
216 | 215 |
|
217 |
-=head2 C<generate makefile> |
|
216 |
+=head2 generate makefile |
|
218 | 217 |
|
219 | 218 |
$ mojo generate makefile |
220 | 219 |
$ ./myapp.pl generate makefile |
221 | 220 |
|
222 | 221 |
Generate C<Makefile.PL> file for application. |
223 | 222 |
|
224 |
-=head2 C<generate plugin> |
|
223 |
+=head2 generate plugin |
|
225 | 224 |
|
226 | 225 |
$ mojo generate plugin <PluginName> |
227 | 226 |
|
228 | 227 |
Generate directory structure for a fully functional L<Mojolicious> plugin. |
229 | 228 |
|
230 |
-=head2 C<get> |
|
229 |
+=head2 get |
|
231 | 230 |
|
232 | 231 |
$ mojo get http://mojolicio.us |
233 | 232 |
$ ./myapp.pl get /foo |
234 | 233 |
|
235 | 234 |
Perform requests to remote host or local application. |
236 | 235 |
|
237 |
-=head2 C<inflate> |
|
236 |
+=head2 inflate |
|
238 | 237 |
|
239 | 238 |
$ ./myapp.pl inflate |
240 | 239 |
|
241 | 240 |
Turn templates and static files embedded in the C<DATA> sections of your |
242 | 241 |
application into real files. |
243 | 242 |
|
244 |
-=head2 C<psgi> |
|
243 |
+=head2 prefork |
|
244 |
+ |
|
245 |
+ $ ./myapp.pl prefork |
|
246 |
+ |
|
247 |
+Start application with standalone preforking HTTP and WebSocket server. |
|
248 |
+ |
|
249 |
+=head2 psgi |
|
245 | 250 |
|
246 | 251 |
$ ./myapp.pl psgi |
247 | 252 |
|
248 | 253 |
Start application with PSGI backend, usually auto detected. |
249 | 254 |
|
250 |
-=head2 C<routes> |
|
255 |
+=head2 routes |
|
251 | 256 |
|
252 | 257 |
$ ./myapp.pl routes |
253 | 258 |
|
254 | 259 |
List application routes. |
255 | 260 |
|
256 |
-=head2 C<test> |
|
261 |
+=head2 test |
|
257 | 262 |
|
258 | 263 |
$ ./myapp.pl test |
259 | 264 |
$ ./myapp.pl test t/fun.t |
260 | 265 |
|
261 | 266 |
Runs application tests from the C<t> directory. |
262 | 267 |
|
263 |
-=head2 C<version> |
|
268 |
+=head2 version |
|
264 | 269 |
|
265 | 270 |
$ mojo version |
266 | 271 |
$ ./myapp.pl version |
... | ... |
@@ -273,21 +278,21 @@ for debugging. |
273 | 278 |
L<Mojolicious::Commands> inherits all attributes from L<Mojolicious::Command> |
274 | 279 |
and implements the following new ones. |
275 | 280 |
|
276 |
-=head2 C<hint> |
|
281 |
+=head2 hint |
|
277 | 282 |
|
278 | 283 |
my $hint = $commands->hint; |
279 | 284 |
$commands = $commands->hint('Foo!'); |
280 | 285 |
|
281 | 286 |
Short hint shown after listing available commands. |
282 | 287 |
|
283 |
-=head2 C<message> |
|
288 |
+=head2 message |
|
284 | 289 |
|
285 | 290 |
my $msg = $commands->message; |
286 | 291 |
$commands = $commands->message('Hello World!'); |
287 | 292 |
|
288 | 293 |
Short usage message shown before listing available commands. |
289 | 294 |
|
290 |
-=head2 C<namespaces> |
|
295 |
+=head2 namespaces |
|
291 | 296 |
|
292 | 297 |
my $namespaces = $commands->namespaces; |
293 | 298 |
$commands = $commands->namespaces(['MyApp::Command']); |
... | ... |
@@ -302,14 +307,14 @@ Namespaces to load commands from, defaults to C<Mojolicious::Command>. |
302 | 307 |
L<Mojolicious::Commands> inherits all methods from L<Mojolicious::Command> and |
303 | 308 |
implements the following new ones. |
304 | 309 |
|
305 |
-=head2 C<detect> |
|
310 |
+=head2 detect |
|
306 | 311 |
|
307 | 312 |
my $env = $commands->detect; |
308 | 313 |
my $env = $commands->detect($guess); |
309 | 314 |
|
310 | 315 |
Try to detect environment. |
311 | 316 |
|
312 |
-=head2 C<run> |
|
317 |
+=head2 run |
|
313 | 318 |
|
314 | 319 |
$commands->run; |
315 | 320 |
$commands->run(@ARGV); |
... | ... |
@@ -317,18 +322,7 @@ Try to detect environment. |
317 | 322 |
Load and run commands. Automatic deployment environment detection can be |
318 | 323 |
disabled with the C<MOJO_NO_DETECT> environment variable. |
319 | 324 |
|
320 |
-=head2 C<start> |
|
321 |
- |
|
322 |
- Mojolicious::Commands->start; |
|
323 |
- Mojolicious::Commands->start(@ARGV); |
|
324 |
- |
|
325 |
-Start the command line interface for application from the value of the |
|
326 |
-C<MOJO_APP> environment variable or L<Mojo::HelloWorld>. |
|
327 |
- |
|
328 |
- # Always start daemon and ignore @ARGV |
|
329 |
- Mojolicious::Commands->start('daemon', '-l', 'http://*:8080'); |
|
330 |
- |
|
331 |
-=head2 C<start_app> |
|
325 |
+=head2 start_app |
|
332 | 326 |
|
333 | 327 |
Mojolicious::Commands->start_app('MyApp'); |
334 | 328 |
Mojolicious::Commands->start_app(MyApp => @ARGV); |
... | ... |
@@ -1,6 +1,7 @@ |
1 | 1 |
package Mojolicious::Controller; |
2 | 2 |
use Mojo::Base -base; |
3 | 3 |
|
4 |
+# No imports, for security reasons! |
|
4 | 5 |
use Carp (); |
5 | 6 |
use Mojo::ByteStream; |
6 | 7 |
use Mojo::Cookie::Response; |
... | ... |
@@ -29,11 +30,11 @@ sub AUTOLOAD { |
29 | 30 |
|
30 | 31 |
# Method |
31 | 32 |
my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/; |
32 |
- Carp::croak("Undefined subroutine &${package}::$method called") |
|
33 |
- unless Scalar::Util::blessed($self) && $self->isa(__PACKAGE__); |
|
33 |
+ Carp::croak "Undefined subroutine &${package}::$method called" |
|
34 |
+ unless Scalar::Util::blessed $self && $self->isa(__PACKAGE__); |
|
34 | 35 |
|
35 | 36 |
# Call helper |
36 |
- Carp::croak(qq{Can't locate object method "$method" via package "$package"}) |
|
37 |
+ Carp::croak qq{Can't locate object method "$method" via package "$package"} |
|
37 | 38 |
unless my $helper = $self->app->renderer->helpers->{$method}; |
38 | 39 |
return $self->$helper(@_); |
39 | 40 |
} |
... | ... |
@@ -59,8 +60,6 @@ sub cookie { |
59 | 60 |
|
60 | 61 |
# Request cookies |
61 | 62 |
return map { $_->value } $self->req->cookie($name) if wantarray; |
62 |
- |
|
63 |
- # Request cookie |
|
64 | 63 |
return undef unless my $cookie = $self->req->cookie($name); |
65 | 64 |
return $cookie->value; |
66 | 65 |
} |
... | ... |
@@ -133,9 +132,8 @@ sub param { |
133 | 132 |
return ref $value eq 'ARRAY' ? wantarray ? @$value : $$value[0] : $value; |
134 | 133 |
} |
135 | 134 |
|
136 |
- # Upload |
|
137 |
- my $upload = $req->upload($name); |
|
138 |
- return $upload if $upload; |
|
135 |
+ # Uploads |
|
136 |
+ return $req->upload($name) if $req->upload($name); |
|
139 | 137 |
|
140 | 138 |
# Param values |
141 | 139 |
return $req->param($name); |
... | ... |
@@ -158,7 +156,7 @@ sub render { |
158 | 156 |
my $args = ref $_[0] ? $_[0] : {@_}; |
159 | 157 |
$args->{template} = $template if $template; |
160 | 158 |
|
161 |
- # Template |
|
159 |
+ # Detect template name |
|
162 | 160 |
my $stash = $self->stash; |
163 | 161 |
unless ($args->{template} || $stash->{template}) { |
164 | 162 |
|
... | ... |
@@ -177,13 +175,16 @@ sub render { |
177 | 175 |
} |
178 | 176 |
|
179 | 177 |
# Render |
180 |
- my ($output, $type) = $self->app->renderer->render($self, $args); |
|
178 |
+ my $app = $self->app; |
|
179 |
+ my ($output, $format) = $app->renderer->render($self, $args); |
|
181 | 180 |
return undef unless defined $output; |
182 | 181 |
return Mojo::ByteStream->new($output) if $args->{partial}; |
183 | 182 |
|
184 | 183 |
# Prepare response |
184 |
+ $app->plugins->emit_hook(after_render => $self, \$output, $format); |
|
185 | 185 |
my $headers = $self->res->body($output)->headers; |
186 |
- $headers->content_type($type) unless $headers->content_type; |
|
186 |
+ $headers->content_type($app->types->type($format) || 'text/plain') |
|
187 |
+ unless $headers->content_type; |
|
187 | 188 |
return !!$self->rendered($stash->{status}); |
188 | 189 |
} |
189 | 190 |
|
... | ... |
@@ -192,7 +193,6 @@ sub render_data { shift->render(data => @_) } |
192 | 193 |
sub render_exception { |
193 | 194 |
my ($self, $e) = @_; |
194 | 195 |
|
195 |
- # Log exception |
|
196 | 196 |
my $app = $self->app; |
197 | 197 |
$app->log->error($e = Mojo::Exception->new($e)); |
198 | 198 |
|
... | ... |
@@ -310,7 +310,7 @@ sub respond_to { |
310 | 310 |
sub send { |
311 | 311 |
my ($self, $msg, $cb) = @_; |
312 | 312 |
my $tx = $self->tx; |
313 |
- Carp::croak('No WebSocket connection to send message to') |
|
313 |
+ Carp::croak 'No WebSocket connection to send message to' |
|
314 | 314 |
unless $tx->is_websocket; |
315 | 315 |
$tx->send($msg => sub { shift and $self->$cb(@_) if $cb }); |
316 | 316 |
return $self->rendered(101); |
... | ... |
@@ -395,8 +395,7 @@ sub url_for { |
395 | 395 |
my $target = shift; $target = defined $target ? $target : ''; |
396 | 396 |
|
397 | 397 |
# Absolute URL |
398 |
- return $target |
|
399 |
- if Scalar::Util::blessed($target) && $target->isa('Mojo::URL'); |
|
398 |
+ return $target if Scalar::Util::blessed $target && $target->isa('Mojo::URL'); |
|
400 | 399 |
return Mojo::URL->new($target) if $target =~ m!^\w+://!; |
401 | 400 |
|
402 | 401 |
# Base |
... | ... |
@@ -408,8 +407,7 @@ sub url_for { |
408 | 407 |
my $path = $url->path; |
409 | 408 |
if ($target =~ m!^/!) { |
410 | 409 |
if (my $prefix = $self->stash->{path}) { |
411 |
- my $real = Mojo::Util::url_unescape($req->url->path->to_abs_string); |
|
412 |
- $real = do {my $tmp = Mojo::Util::decode('UTF-8', $real); defined $tmp ? $tmp : $real}; |
|
410 |
+ my $real = $req->url->path->to_route; |
|
413 | 411 |
$real =~ s!/?$prefix$!$target!; |
414 | 412 |
$target = $real; |
415 | 413 |
} |
... | ... |
@@ -457,7 +455,7 @@ sub _fallbacks { |
457 | 455 |
# Mode specific template |
458 | 456 |
return 1 if $self->render($options); |
459 | 457 |
|
460 |
- # Template |
|
458 |
+ # Normal template |
|
461 | 459 |
$options->{template} = $template; |
462 | 460 |
return 1 if $self->render($options); |
463 | 461 |
|
... | ... |
@@ -471,6 +469,8 @@ sub _fallbacks { |
471 | 469 |
|
472 | 470 |
1; |
473 | 471 |
|
472 |
+=encoding utf8 |
|
473 |
+ |
|
474 | 474 |
=head1 NAME |
475 | 475 |
|
476 | 476 |
Mojolicious::Controller - Controller base class |
... | ... |
@@ -500,7 +500,7 @@ unless you set C<controller_class> in your application. |
500 | 500 |
L<Mojolicious::Controller> inherits all attributes from L<Mojo::Base> and |
501 | 501 |
implements the following new ones. |
502 | 502 |
|
503 |
-=head2 C<app> |
|
503 |
+=head2 app |
|
504 | 504 |
|
505 | 505 |
my $app = $c->app; |
506 | 506 |
$c = $c->app(Mojolicious->new); |
... | ... |
@@ -511,7 +511,7 @@ defaults to a L<Mojolicious> object. |
511 | 511 |
# Use application logger |
512 | 512 |
$c->app->log->debug('Hello Mojo!'); |
513 | 513 |
|
514 |
-=head2 C<match> |
|
514 |
+=head2 match |
|
515 | 515 |
|
516 | 516 |
my $m = $c->match; |
517 | 517 |
$c = $c->match(Mojolicious::Routes::Match->new); |
... | ... |
@@ -522,7 +522,7 @@ L<Mojolicious::Routes::Match> object. |
522 | 522 |
# Introspect |
523 | 523 |
my $foo = $c->match->endpoint->pattern->defaults->{foo}; |
524 | 524 |
|
525 |
-=head2 C<tx> |
|
525 |
+=head2 tx |
|
526 | 526 |
|
527 | 527 |
my $tx = $c->tx; |
528 | 528 |
$c = $c->tx(Mojo::Transaction::HTTP->new); |
... | ... |
@@ -538,7 +538,7 @@ L<Mojo::Transaction::HTTP> or L<Mojo::Transaction::WebSocket> object. |
538 | 538 |
L<Mojolicious::Controller> inherits all methods from L<Mojo::Base> and |
539 | 539 |
implements the following new ones. |
540 | 540 |
|
541 |
-=head2 C<cookie> |
|
541 |
+=head2 cookie |
|
542 | 542 |
|
543 | 543 |
my $value = $c->cookie('foo'); |
544 | 544 |
my @values = $c->cookie('foo'); |
... | ... |
@@ -547,17 +547,17 @@ implements the following new ones. |
547 | 547 |
|
548 | 548 |
Access request cookie values and create new response cookies. |
549 | 549 |
|
550 |
- # Create response cookie with domain |
|
551 |
- $c->cookie(name => 'sebastian', {domain => 'mojolicio.us'}); |
|
550 |
+ # Create response cookie with domain and expiration date |
|
551 |
+ $c->cookie(user => 'sri', {domain => 'mojolicio.us', expires => time + 60}); |
|
552 | 552 |
|
553 |
-=head2 C<finish> |
|
553 |
+=head2 finish |
|
554 | 554 |
|
555 | 555 |
$c = $c->finish; |
556 | 556 |
$c = $c->finish('Bye!'); |
557 | 557 |
|
558 | 558 |
Gracefully end WebSocket connection or long poll stream. |
559 | 559 |
|
560 |
-=head2 C<flash> |
|
560 |
+=head2 flash |
|
561 | 561 |
|
562 | 562 |
my $foo = $c->flash('foo'); |
563 | 563 |
$c = $c->flash({foo => 'bar'}); |
... | ... |
@@ -569,26 +569,42 @@ Data storage persistent only for the next request, stored in the C<session>. |
569 | 569 |
$c->flash(message => 'User created successfully!'); |
570 | 570 |
$c->redirect_to('show_user', id => 23); |
571 | 571 |
|
572 |
-=head2 C<on> |
|
572 |
+=head2 on |
|
573 | 573 |
|
574 | 574 |
my $cb = $c->on(finish => sub {...}); |
575 | 575 |
|
576 | 576 |
Subscribe to events of C<tx>, which is usually a L<Mojo::Transaction::HTTP> or |
577 | 577 |
L<Mojo::Transaction::WebSocket> object. |
578 | 578 |
|
579 |
- # Emitted when the transaction has been finished |
|
579 |
+ # Do something after the transaction has been finished |
|
580 | 580 |
$c->on(finish => sub { |
581 | 581 |
my $c = shift; |
582 | 582 |
$c->app->log->debug('We are done!'); |
583 | 583 |
}); |
584 | 584 |
|
585 |
- # Emitted when new WebSocket messages arrive |
|
585 |
+ # Receive WebSocket message |
|
586 | 586 |
$c->on(message => sub { |
587 | 587 |
my ($c, $msg) = @_; |
588 | 588 |
$c->app->log->debug("Message: $msg"); |
589 | 589 |
}); |
590 | 590 |
|
591 |
-=head2 C<param> |
|
591 |
+ # Receive JSON object via WebSocket "Text" message |
|
592 |
+ use Mojo::JSON 'j'; |
|
593 |
+ $c->on(text => sub { |
|
594 |
+ my ($c, $bytes) = @_; |
|
595 |
+ my $test = j($bytes)->{test}; |
|
596 |
+ $c->app->log->debug("Test: $test"); |
|
597 |
+ }); |
|
598 |
+ |
|
599 |
+ # Receive JSON object via WebSocket "Binary" message |
|
600 |
+ use Mojo::JSON 'j'; |
|
601 |
+ $c->on(binary => sub { |
|
602 |
+ my ($c, $bytes) = @_; |
|
603 |
+ my $test = j($bytes)->{test}; |
|
604 |
+ $c->app->log->debug("Test: $test"); |
|
605 |
+ }); |
|
606 |
+ |
|
607 |
+=head2 param |
|
592 | 608 |
|
593 | 609 |
my @names = $c->param; |
594 | 610 |
my $foo = $c->param('foo'); |
... | ... |
@@ -622,7 +638,7 @@ For more control you can also access request information directly. |
622 | 638 |
# Only file uploads |
623 | 639 |
my $foo = $c->req->upload('foo'); |
624 | 640 |
|
625 |
-=head2 C<redirect_to> |
|
641 |
+=head2 redirect_to |
|
626 | 642 |
|
627 | 643 |
$c = $c->redirect_to('named'); |
628 | 644 |
$c = $c->redirect_to('named', foo => 'bar'); |
... | ... |
@@ -638,7 +654,7 @@ Prepare a C<302> redirect response, takes the same arguments as C<url_for>. |
638 | 654 |
$c->res->code(301); |
639 | 655 |
$c->redirect_to('some_route'); |
640 | 656 |
|
641 |
-=head2 C<render> |
|
657 |
+=head2 render |
|
642 | 658 |
|
643 | 659 |
my $success = $c->render; |
644 | 660 |
my $success = $c->render(controller => 'foo', action => 'bar'); |
... | ... |
@@ -652,11 +668,12 @@ Prepare a C<302> redirect response, takes the same arguments as C<url_for>. |
652 | 668 |
my $success = $c->render('foo/index'); |
653 | 669 |
my $output = $c->render('foo/index', partial => 1); |
654 | 670 |
|
655 |
-Render content using L<Mojolicious::Renderer/"render">, if no template is |
|
671 |
+Render content using L<Mojolicious::Renderer/"render"> and emit |
|
672 |
+C<after_render> hook unless the result is C<partial>. If no template is |
|
656 | 673 |
provided a default one based on controller and action or route name will be |
657 |
-generated. All additional values get merged into the C<stash>. |
|
674 |
+generated, all additional values get merged into the C<stash>. |
|
658 | 675 |
|
659 |
-=head2 C<render_data> |
|
676 |
+=head2 render_data |
|
660 | 677 |
|
661 | 678 |
$c->render_data($bytes); |
662 | 679 |
$c->render_data($bytes, format => 'png'); |
... | ... |
@@ -667,7 +684,7 @@ not be encoded. All additional values get merged into the C<stash>. |
667 | 684 |
# Longer version |
668 | 685 |
$c->render(data => $bytes); |
669 | 686 |
|
670 |
-=head2 C<render_exception> |
|
687 |
+=head2 render_exception |
|
671 | 688 |
|
672 | 689 |
$c->render_exception('Oops!'); |
673 | 690 |
$c->render_exception(Mojo::Exception->new('Oops!')); |
... | ... |
@@ -675,7 +692,7 @@ not be encoded. All additional values get merged into the C<stash>. |
675 | 692 |
Render the exception template C<exception.$mode.$format.*> or |
676 | 693 |
C<exception.$format.*> and set the response status code to C<500>. |
677 | 694 |
|
678 |
-=head2 C<render_json> |
|
695 |
+=head2 render_json |
|
679 | 696 |
|
680 | 697 |
$c->render_json({foo => 'bar'}); |
681 | 698 |
$c->render_json([1, 2, -3], status => 201); |
... | ... |
@@ -686,7 +703,7 @@ C<stash>. |
686 | 703 |
# Longer version |
687 | 704 |
$c->render(json => {foo => 'bar'}); |
688 | 705 |
|
689 |
-=head2 C<render_later> |
|
706 |
+=head2 render_later |
|
690 | 707 |
|
691 | 708 |
$c = $c->render_later; |
692 | 709 |
|
... | ... |
@@ -699,14 +716,14 @@ automatic rendring would result in a response. |
699 | 716 |
$c->render(text => 'Delayed by 2 seconds!'); |
700 | 717 |
}); |
701 | 718 |
|
702 |
-=head2 C<render_not_found> |
|
719 |
+=head2 render_not_found |
|
703 | 720 |
|
704 | 721 |
$c->render_not_found; |
705 | 722 |
|
706 | 723 |
Render the not found template C<not_found.$mode.$format.*> or |
707 | 724 |
C<not_found.$format.*> and set the response status code to C<404>. |
708 | 725 |
|
709 |
-=head2 C<render_partial> |
|
726 |
+=head2 render_partial |
|
710 | 727 |
|
711 | 728 |
my $output = $c->render_partial('menubar'); |
712 | 729 |
my $output = $c->render_partial('menubar', format => 'txt'); |
... | ... |
@@ -717,7 +734,7 @@ Same as C<render> but returns the rendered result. |
717 | 734 |
# Longer version |
718 | 735 |
my $output = $c->render('menubar', partial => 1); |
719 | 736 |
|
720 |
-=head2 C<render_static> |
|
737 |
+=head2 render_static |
|
721 | 738 |
|
722 | 739 |
my $success = $c->render_static('images/logo.png'); |
723 | 740 |
my $success = $c->render_static('../lib/MyApp.pm'); |
... | ... |
@@ -726,7 +743,7 @@ Render a static file using L<Mojolicious::Static/"serve">, usually from the |
726 | 743 |
C<public> directories or C<DATA> sections of your application. Note that this |
727 | 744 |
method does not protect from traversing to parent directories. |
728 | 745 |
|
729 |
-=head2 C<render_text> |
|
746 |
+=head2 render_text |
|
730 | 747 |
|
731 | 748 |
$c->render_text('Hello World!'); |
732 | 749 |
$c->render_text('Hello World!', layout => 'green'); |
... | ... |
@@ -742,15 +759,15 @@ of the response, which is C<text/html;charset=UTF-8> by default. |
742 | 759 |
# Render "text/plain" response |
743 | 760 |
$c->render_text('Hello World!', format => 'txt'); |
744 | 761 |
|
745 |
-=head2 C<rendered> |
|
762 |
+=head2 rendered |
|
746 | 763 |
|
747 | 764 |
$c = $c->rendered; |
748 | 765 |
$c = $c->rendered(302); |
749 | 766 |
|
750 |
-Finalize response and emit C<after_dispatch> plugin hook, defaults to using a |
|
751 |
-C<200> response code. |
|
767 |
+Finalize response and emit C<after_dispatch> hook, defaults to using a C<200> |
|
768 |
+response code. |
|
752 | 769 |
|
753 |
-=head2 C<req> |
|
770 |
+=head2 req |
|
754 | 771 |
|
755 | 772 |
my $req = $c->req; |
756 | 773 |
|
... | ... |
@@ -766,7 +783,7 @@ Get L<Mojo::Message::Request> object from L<Mojo::Transaction/"req">. |
766 | 783 |
my $foo = $c->req->json('/23/foo'); |
767 | 784 |
my $bar = $c->req->dom('div.bar')->first->text; |
768 | 785 |
|
769 |
-=head2 C<res> |
|
786 |
+=head2 res |
|
770 | 787 |
|
771 | 788 |
my $res = $c->res; |
772 | 789 |
|
... | ... |
@@ -778,7 +795,7 @@ Get L<Mojo::Message::Response> object from L<Mojo::Transaction/"res">. |
778 | 795 |
# Force file download by setting a custom response header |
779 | 796 |
$c->res->headers->content_disposition('attachment; filename=foo.png;'); |
780 | 797 |
|
781 |
-=head2 C<respond_to> |
|
798 |
+=head2 respond_to |
|
782 | 799 |
|
783 | 800 |
$c->respond_to( |
784 | 801 |
json => {json => {message => 'Welcome!'}}, |
... | ... |
@@ -799,7 +816,7 @@ is set to the value C<XMLHttpRequest>. |
799 | 816 |
any => {data => '', status => 204} |
800 | 817 |
); |
801 | 818 |
|
802 |
-=head2 C<send> |
|
819 |
+=head2 send |
|
803 | 820 |
|
804 | 821 |
$c = $c->send({binary => $bytes}); |
805 | 822 |
$c = $c->send({text => $bytes}); |
... | ... |
@@ -810,14 +827,16 @@ is set to the value C<XMLHttpRequest>. |
810 | 827 |
Send message or frame non-blocking via WebSocket, the optional drain callback |
811 | 828 |
will be invoked once all data has been written. |
812 | 829 |
|
813 |
- # Send "Text" frame |
|
814 |
- $c->send('Hello World!'); |
|
830 |
+ # Send "Text" message |
|
831 |
+ $c->send('I ♥ Mojolicious!'); |
|
815 | 832 |
|
816 |
- # Send JSON object as "Text" frame |
|
817 |
- $c->send({text => Mojo::JSON->new->encode({hello => 'world'})}); |
|
833 |
+ # Send JSON object as "Text" message |
|
834 |
+ use Mojo::JSON 'j'; |
|
835 |
+ $c->send({text => j({test => 'I ♥ Mojolicious!'})}); |
|
818 | 836 |
|
819 |
- # Send JSON object as "Binary" frame |
|
820 |
- $c->send({binary => Mojo::JSON->new->encode({hello => 'world'})}); |
|
837 |
+ # Send JSON object as "Binary" message |
|
838 |
+ use Mojo::JSON 'j'; |
|
839 |
+ $c->send({binary => j({test => 'I ♥ Mojolicious!'})}); |
|
821 | 840 |
|
822 | 841 |
# Send "Ping" frame |
823 | 842 |
$c->send([1, 0, 0, 0, 9, 'Hello World!']); |
... | ... |
@@ -828,7 +847,7 @@ timeout, which usually defaults to C<15> seconds. |
828 | 847 |
# Increase inactivity timeout for connection to 300 seconds |
829 | 848 |
Mojo::IOLoop->stream($c->tx->connection)->timeout(300); |
830 | 849 |
|
831 |
-=head2 C<session> |
|
850 |
+=head2 session |
|
832 | 851 |
|
833 | 852 |
my $session = $c->session; |
834 | 853 |
my $foo = $c->session('foo'); |
... | ... |
@@ -853,7 +872,7 @@ usually have a 4096 byte limit, depending on browser. |
853 | 872 |
# Delete whole session by setting an expiration date in the past |
854 | 873 |
$c->session(expires => 1); |
855 | 874 |
|
856 |
-=head2 C<signed_cookie> |
|
875 |
+=head2 signed_cookie |
|
857 | 876 |
|
858 | 877 |
my $value = $c->signed_cookie('foo'); |
859 | 878 |
my @values = $c->signed_cookie('foo'); |
... | ... |
@@ -864,7 +883,7 @@ Access signed request cookie values and create new signed response cookies. |
864 | 883 |
Cookies failing C<HMAC-SHA1> signature verification will be automatically |
865 | 884 |
discarded. |
866 | 885 |
|
867 |
-=head2 C<stash> |
|
886 |
+=head2 stash |
|
868 | 887 |
|
869 | 888 |
my $stash = $c->stash; |
870 | 889 |
my $foo = $c->stash('foo'); |
... | ... |
@@ -883,7 +902,7 @@ that all stash values with a C<mojo.*> prefix are reserved for internal use. |
883 | 902 |
my $foo = $c->stash->{foo}; |
884 | 903 |
delete $c->stash->{foo}; |
885 | 904 |
|
886 |
-=head2 C<ua> |
|
905 |
+=head2 ua |
|
887 | 906 |
|
888 | 907 |
my $ua = $c->ua; |
889 | 908 |
|
... | ... |
@@ -915,7 +934,7 @@ Get L<Mojo::UserAgent> object from L<Mojo/"ua">. |
915 | 934 |
}); |
916 | 935 |
} |
917 | 936 |
|
918 |
-=head2 C<url_for> |
|
937 |
+=head2 url_for |
|
919 | 938 |
|
920 | 939 |
my $url = $c->url_for; |
921 | 940 |
my $url = $c->url_for(name => 'sebastian'); |
... | ... |
@@ -937,12 +956,12 @@ to inherit query parameters from the current request. |
937 | 956 |
# "/list?q=mojo&page=2" if current request was for "/list?q=mojo&page=1" |
938 | 957 |
$c->url_with->query([page => 2]); |
939 | 958 |
|
940 |
-=head2 C<write> |
|
959 |
+=head2 write |
|
941 | 960 |
|
942 | 961 |
$c = $c->write; |
943 |
- $c = $c->write('Hello!'); |
|
962 |
+ $c = $c->write($bytes); |
|
944 | 963 |
$c = $c->write(sub {...}); |
945 |
- $c = $c->write('Hello!' => sub {...}); |
|
964 |
+ $c = $c->write($bytes => sub {...}); |
|
946 | 965 |
|
947 | 966 |
Write dynamic content non-blocking, the optional drain callback will be |
948 | 967 |
invoked once all data has been written. |
... | ... |
@@ -963,18 +982,18 @@ invoked once all data has been written. |
963 | 982 |
}); |
964 | 983 |
}); |
965 | 984 |
|
966 |
-For Comet (C<long polling>) you might also want to increase the inactivity |
|
985 |
+For Comet (long polling) you might also want to increase the inactivity |
|
967 | 986 |
timeout, which usually defaults to C<15> seconds. |
968 | 987 |
|
969 | 988 |
# Increase inactivity timeout for connection to 300 seconds |
970 | 989 |
Mojo::IOLoop->stream($c->tx->connection)->timeout(300); |
971 | 990 |
|
972 |
-=head2 C<write_chunk> |
|
991 |
+=head2 write_chunk |
|
973 | 992 |
|
974 | 993 |
$c = $c->write_chunk; |
975 |
- $c = $c->write_chunk('Hello!'); |
|
994 |
+ $c = $c->write_chunk($bytes); |
|
976 | 995 |
$c = $c->write_chunk(sub {...}); |
977 |
- $c = $c->write_chunk('Hello!' => sub {...}); |
|
996 |
+ $c = $c->write_chunk($bytes => sub {...}); |
|
978 | 997 |
|
979 | 998 |
Write dynamic content non-blocking with C<chunked> transfer encoding, the |
980 | 999 |
optional drain callback will be invoked once all data has been written. |
... | ... |
@@ -20,6 +20,12 @@ available in many formats. Both are excellent introductions to the language. |
20 | 20 |
For more books and documentation, check out |
21 | 21 |
L<learn.perl.org|http://learn.perl.org/>. |
22 | 22 |
|
23 |
+=head1 SCREENCASTS |
|
24 |
+ |
|
25 |
+Before starting with the tutorial below, you should take a look at the |
|
26 |
+wonderful L<Mojocasts|http://mojocasts.com/e1>, they will give you a general |
|
27 |
+overview of what L<Mojolicious> is all about. |
|
28 |
+ |
|
23 | 29 |
=head1 TUTORIAL |
24 | 30 |
|
25 | 31 |
=over 2 |
... | ... |
@@ -90,26 +96,23 @@ Full featured, highly portable non-blocking I/O HTTP and WebSocket server, |
90 | 96 |
with self-restart support through L<Mojo::Server::Morbo>, perfect for |
91 | 97 |
development and testing. |
92 | 98 |
|
93 |
-=item L<Mojo::Server::Hypnotoad> |
|
99 |
+=item L<Mojo::Server::Prefork> |
|
94 | 100 |
|
95 | 101 |
Full featured, UNIX optimized, preforking non-blocking I/O HTTP and WebSocket |
96 |
-server with support for zero downtime software upgrades (hot deployment). |
|
102 |
+server with support for zero downtime software upgrades (hot deployment) |
|
103 |
+through L<Mojo::Server::Hypnotoad>. |
|
97 | 104 |
|
98 | 105 |
=item L<Mojo::Server::CGI>, L<Mojo::Server::PSGI> |
99 | 106 |
|
100 | 107 |
Transparent CGI and L<PSGI> support out of the box. |
101 | 108 |
|
102 |
-=item L<Mojo::Template> |
|
103 |
- |
|
104 |
-Very Perl-ish and minimalistic template system. |
|
105 |
- |
|
106 |
-=item L<Mojo::ByteStream> |
|
109 |
+=item L<Mojo::IOLoop> |
|
107 | 110 |
|
108 |
-Countless portable and very convenient bytestream manipulation methods. |
|
111 |
+A minimalistic event loop with support for multiple reactor backends. |
|
109 | 112 |
|
110 |
-=item L<Mojolicious::Commands> |
|
113 |
+=item L<Mojo::Template> |
|
111 | 114 |
|
112 |
-Pluggable command line system and the backbone of the L<mojo> script. |
|
115 |
+Very Perl-ish and minimalistic template system. |
|
113 | 116 |
|
114 | 117 |
=item L<Test::Mojo> |
115 | 118 |
|
... | ... |
@@ -126,4 +129,11 @@ Fun oneliners using everything above. |
126 | 129 |
A lot more documentation and examples by many different authors can be found |
127 | 130 |
in the L<Mojolicious wiki|http://github.com/kraih/mojo/wiki>. |
128 | 131 |
|
132 |
+=head1 SUPPORT |
|
133 |
+ |
|
134 |
+If you have any questions the documentation might not yet answer, don't |
|
135 |
+hesitate to ask on the |
|
136 |
+L<mailing-list|http://groups.google.com/group/mojolicious> or the official IRC |
|
137 |
+channel C<#mojo> on C<irc.perl.org>. |
|
138 |
+ |
|
129 | 139 |
=cut |
... | ... |
@@ -164,9 +164,7 @@ feature branches for actual development. |
164 | 164 |
Code has to be run through L<Perl::Tidy> with the included C<.perltidyrc>, and |
165 | 165 |
everything should look like it was written by a single person. |
166 | 166 |
|
167 |
-Code should be organized in blocks and those blocks should be commented. |
|
168 |
- |
|
169 |
-No spaghetti code. |
|
167 |
+Methods and functions should be as short as possible, no spaghetti code. |
|
170 | 168 |
|
171 | 169 |
Comments should be correctly capitalized, and funny if possible, punctuation |
172 | 170 |
is optional if it doesn't increase readability. |
... | ... |
@@ -185,4 +183,11 @@ You can continue with L<Mojolicious::Guides> now or take a look at the |
185 | 183 |
L<Mojolicious wiki|http://github.com/kraih/mojo/wiki>, which contains a lot |
186 | 184 |
more documentation and examples by many different authors. |
187 | 185 |
|
186 |
+=head1 SUPPORT |
|
187 |
+ |
|
188 |
+If you have any questions the documentation might not yet answer, don't |
|
189 |
+hesitate to ask on the |
|
190 |
+L<mailing-list|http://groups.google.com/group/mojolicious> or the official IRC |
|
191 |
+channel C<#mojo> on C<irc.perl.org>. |
|
192 |
+ |
|
188 | 193 |
=cut |
... | ... |
@@ -5,7 +5,7 @@ Mojolicious::Guides::Cookbook - Cookbook |
5 | 5 |
|
6 | 6 |
=head1 OVERVIEW |
7 | 7 |
|
8 |
-This document cotains many fun recipes for cooking with L<Mojolicious>. |
|
8 |
+This document contains many fun recipes for cooking with L<Mojolicious>. |
|
9 | 9 |
|
10 | 10 |
=head1 DEPLOYMENT |
11 | 11 |
|
... | ... |
@@ -30,13 +30,17 @@ works on. |
30 | 30 |
$ ./script/myapp daemon -h |
31 | 31 |
...List of available options... |
32 | 32 |
|
33 |
-Another huge advantage is that it supports TLS and WebSockets out of the box. |
|
33 |
+Another huge advantage is that it supports TLS and WebSockets out of the box, |
|
34 |
+a development certificate for testing purposes is built right in, so it just |
|
35 |
+works. |
|
34 | 36 |
|
35 | 37 |
$ ./script/myapp daemon -l https://*:3000 |
36 | 38 |
Server available at https://127.0.0.1:3000. |
37 | 39 |
|
38 |
-A development certificate for testing purposes is built right in, so it just |
|
39 |
-works. |
|
40 |
+On UNIX platforms you can also add preforking with L<Mojo::Server::Prefork>. |
|
41 |
+ |
|
42 |
+ $ ./script/myapp prefork |
|
43 |
+ Server available at http://127.0.0.1:3000. |
|
40 | 44 |
|
41 | 45 |
=head2 Morbo |
42 | 46 |
|
... | ... |
@@ -65,8 +69,9 @@ multiple CPU cores and copy-on-write. |
65 | 69 |
|- Mojo::Server::Daemon [3] |
66 | 70 |
+- Mojo::Server::Daemon [4] |
67 | 71 |
|
68 |
-It is also based on the L<Mojo::Server::Daemon> web server, but optimized |
|
69 |
-specifically for production environments out of the box. |
|
72 |
+It is based on the L<Mojo::Server::Prefork> web server, which adds preforking |
|
73 |
+to L<Mojo::Server::Daemon>, but optimized specifically for production |
|
74 |
+environments out of the box. |
|
70 | 75 |
|
71 | 76 |
$ hypnotoad script/myapp |
72 | 77 |
Server available at http://127.0.0.1:8080. |
... | ... |
@@ -512,6 +517,7 @@ L<Test::Mojo> API to be used. |
512 | 517 |
my $t = Test::Mojo->new; |
513 | 518 |
$t->websocket_ok('/echo') |
514 | 519 |
->send_ok('Hello Mojo!') |
520 |
+ ->message_ok |
|
515 | 521 |
->message_is('echo: Hello Mojo!') |
516 | 522 |
->finish_ok; |
517 | 523 |
|
... | ... |
@@ -611,10 +617,10 @@ which can be combined to solve some of hardest problems in web development. |
611 | 617 |
# Make sure we have the right part and replace "read" event |
612 | 618 |
return unless $single->headers->content_disposition =~ /example/; |
613 | 619 |
$single->unsubscribe('read')->on(read => sub { |
614 |
- my ($single, $chunk) = @_; |
|
620 |
+ my ($single, $bytes) = @_; |
|
615 | 621 |
|
616 | 622 |
# Log size of every chunk we receive |
617 |
- $self->app->log->debug(length($chunk) . ' bytes uploaded.'); |
|
623 |
+ $self->app->log->debug(length($bytes) . ' bytes uploaded.'); |
|
618 | 624 |
}); |
619 | 625 |
}); |
620 | 626 |
}) unless $self->req->is_finished; |
... | ... |
@@ -734,30 +740,23 @@ sense for a standalone parser. |
734 | 740 |
say 'Title: ', $tx->res->dom->at('head > title')->text; |
735 | 741 |
|
736 | 742 |
# Extract headings |
737 |
- $tx->res->dom('h1, h2, h3')->each(sub { |
|
738 |
- say 'Heading: ', shift->all_text; |
|
739 |
- }); |
|
743 |
+ $tx->res->dom('h1, h2, h3')->each(sub { say 'Heading: ', shift->all_text }); |
|
740 | 744 |
|
741 |
- # Recurse through children manually to extract more than just text |
|
742 |
- sub text_and_images { |
|
743 |
- my $elements = shift; |
|
744 |
- for my $e ($elements->each) { |
|
745 |
+ # Visit all elements recursively to extract more than just text |
|
746 |
+ for my $e ($tx->res->dom('*')->each) { |
|
745 | 747 |
|
746 |
- # Text before this element |
|
747 |
- print $e->text_before(0); |
|
748 |
+ # Text before this element |
|
749 |
+ print $e->text_before(0); |
|
748 | 750 |
|
749 |
- # Also include alternate text for images |
|
750 |
- print $e->{alt} if $e->type eq 'img'; |
|
751 |
+ # Also include alternate text for images |
|
752 |
+ print $e->{alt} if $e->type eq 'img'; |
|
751 | 753 |
|
752 |
- # Text from children |
|
753 |
- my $children = $e->children; |
|
754 |
- $children->size ? text_and_images($children) : print $e->text(0); |
|
755 |
- } |
|
754 |
+ # Text for elements without children |
|
755 |
+ print $e->text(0) unless $e->children->size; |
|
756 | 756 |
|
757 | 757 |
# Text after last element |
758 |
- print $elements->[-1]->text_after(0); |
|
758 |
+ print $e->text_after(0) unless $e->next; |
|
759 | 759 |
} |
760 |
- text_and_images($tx->res->dom->children); |
|
761 | 760 |
|
762 | 761 |
Especially for unit testing your L<Mojolicious> applications this can be a |
763 | 762 |
very powerful tool. |
... | ... |
@@ -834,8 +833,8 @@ L<Mojo::UserAgent> makes it actually easy. |
834 | 833 |
|
835 | 834 |
# Replace "read" events to disable default content parser |
836 | 835 |
$tx->res->content->unsubscribe('read')->on(read => sub { |
837 |
- my ($content, $chunk) = @_; |
|
838 |
- say "Streaming: $chunk"; |
|
836 |
+ my ($content, $bytes) = @_; |
|
837 |
+ say "Streaming: $bytes"; |
|
839 | 838 |
}); |
840 | 839 |
|
841 | 840 |
# Process transaction |
... | ... |
@@ -1179,4 +1178,11 @@ You can continue with L<Mojolicious::Guides> now or take a look at the |
1179 | 1178 |
L<Mojolicious wiki|http://github.com/kraih/mojo/wiki>, which contains a lot |
1180 | 1179 |
more documentation and examples by many different authors. |
1181 | 1180 |
|
1181 |
+=head1 SUPPORT |
|
1182 |
+ |
|
1183 |
+If you have any questions the documentation might not yet answer, don't |
|
1184 |
+hesitate to ask on the |
|
1185 |
+L<mailing-list|http://groups.google.com/group/mojolicious> or the official IRC |
|
1186 |
+channel C<#mojo> on C<irc.perl.org>. |
|
1187 |
+ |
|
1182 | 1188 |
=cut |
... | ... |
@@ -69,9 +69,9 @@ variable to change this value. |
69 | 69 |
|
70 | 70 |
This is a very similar protection mechanism to the one described in the |
71 | 71 |
previous answer, but a little more specific. It limits the maximum length of |
72 |
-any C<\r\n> terminated part of a HTTP message, such as request line, status |
|
73 |
-line and headers. This limit is around C<10KB> by default, you can use the |
|
74 |
-C<MOJO_MAX_LINE_SIZE> environment variable to change this value. |
|
72 |
+any C<\x0d\x0a> terminated part of a HTTP message, such as request line, |
|
73 |
+status line and headers. This limit is around C<10KB> by default, you can use |
|
74 |
+the C<MOJO_MAX_LINE_SIZE> environment variable to change this value. |
|
75 | 75 |
|
76 | 76 |
=head2 What does the error "Maximum buffer size exceeded" mean? |
77 | 77 |
|
... | ... |
@@ -140,4 +140,11 @@ You can continue with L<Mojolicious::Guides> now or take a look at the |
140 | 140 |
L<Mojolicious wiki|http://github.com/kraih/mojo/wiki>, which contains a lot |
141 | 141 |
more documentation and examples by many different authors. |
142 | 142 |
|
143 |
+=head1 SUPPORT |
|
144 |
+ |
|
145 |
+If you have any questions the documentation might not yet answer, don't |
|
146 |
+hesitate to ask on the |
|
147 |
+L<mailing-list|http://groups.google.com/group/mojolicious> or the official IRC |
|
148 |
+channel C<#mojo> on C<irc.perl.org>. |
|
149 |
+ |
|
143 | 150 |
=cut |
... | ... |
@@ -551,7 +551,7 @@ allow running unit tests again. |
551 | 551 |
use lib 'lib'; |
552 | 552 |
use Mojolicious::Commands; |
553 | 553 |
|
554 |
- # Start commands for application |
|
554 |
+ # Start command line interface for application |
|
555 | 555 |
Mojolicious::Commands->start_app('MyApp'); |
556 | 556 |
|
557 | 557 |
=head2 Controller class |
... | ... |
@@ -651,7 +651,7 @@ Only a few small details change. |
651 | 651 |
use FindBin; |
652 | 652 |
use lib "$FindBin::Bin/../lib"; |
653 | 653 |
|
654 |
- # Start commands for application |
|
654 |
+ # Start command line interface for application |
|
655 | 655 |
require Mojolicious::Commands; |
656 | 656 |
Mojolicious::Commands->start_app('MyApp'); |
657 | 657 |
|
... | ... |
@@ -694,4 +694,11 @@ You can continue with L<Mojolicious::Guides> now or take a look at the |
694 | 694 |
L<Mojolicious wiki|http://github.com/kraih/mojo/wiki>, which contains a lot |
695 | 695 |
more documentation and examples by many different authors. |
696 | 696 |
|
697 |
+=head1 SUPPORT |
|
698 |
+ |
|
699 |
+If you have any questions the documentation might not yet answer, don't |
|
700 |
+hesitate to ask on the |
|
701 |
+L<mailing-list|http://groups.google.com/group/mojolicious> or the official IRC |
|
702 |
+channel C<#mojo> on C<irc.perl.org>. |
|
703 |
+ |
|
697 | 704 |
=cut |
... | ... |
@@ -114,7 +114,8 @@ which is the default to prevent XSS attacks against your application. |
114 | 114 |
|
115 | 115 |
Only L<Mojo::ByteStream> objects are excluded from automatic escaping. |
116 | 116 |
|
117 |
- <%= Mojo::ByteStream->new('<p>test</p>') %> |
|
117 |
+ % use Mojo::ByteStream 'b'; |
|
118 |
+ <%= b('<p>test</p>') %> |
|
118 | 119 |
|
119 | 120 |
Newline characters can be escaped with a backslash. |
120 | 121 |
|
... | ... |
@@ -186,7 +187,7 @@ shortcut. |
186 | 187 |
|
187 | 188 |
Some renderers such as C<ep> allow templates to be passed inline. |
188 | 189 |
|
189 |
- $self->render(inline => 'The result is <%= 1 + 1%>.'); |
|
190 |
+ $self->render(inline => 'The result is <%= 1 + 1 %>.'); |
|
190 | 191 |
|
191 | 192 |
Since auto detection depends on a path you might have to supply a C<handler> |
192 | 193 |
too. |
... | ... |
@@ -489,7 +490,7 @@ the partial template. |
489 | 490 |
=head2 Reusable template blocks |
490 | 491 |
|
491 | 492 |
It's never fun to repeat yourself, that's why you can build reusable template |
492 |
-blocks in C<ep> that work very similar normal Perl functions. |
|
493 |
+blocks in C<ep> that work very similar to normal Perl functions. |
|
493 | 494 |
|
494 | 495 |
@@ welcome.html.ep |
495 | 496 |
<% my $block = begin %> |
... | ... |
@@ -605,14 +606,14 @@ everything. |
605 | 606 |
|
606 | 607 |
get '/' => sub { |
607 | 608 |
my $self = shift; |
608 |
- $self->debug('action'); |
|
609 |
+ $self->debug('Hello from an action!'); |
|
609 | 610 |
} => 'index'; |
610 | 611 |
|
611 | 612 |
app->start; |
612 | 613 |
__DATA__ |
613 | 614 |
|
614 | 615 |
@@ index.html.ep |
615 |
- % debug 'template'; |
|
616 |
+ % debug 'Hello from a template!'; |
|
616 | 617 |
|
617 | 618 |
Helpers can also accept template blocks as last argument, this for example |
618 | 619 |
allows very pleasant to use tag helpers and filters. |
... | ... |
@@ -674,14 +675,14 @@ The C<register> method will be called when you load the plugin. |
674 | 675 |
|
675 | 676 |
app->start; |
676 | 677 |
|
677 |
-A skeleton for a full C<CPAN> compatible plugin distribution can be |
|
678 |
-automatically generated. |
|
678 |
+A skeleton for a full CPAN compatible plugin distribution can be automatically |
|
679 |
+generated. |
|
679 | 680 |
|
680 | 681 |
$ mojo generate plugin DebugHelper |
681 | 682 |
|
682 | 683 |
And if you have a C<PAUSE> account (which can be requested at |
683 | 684 |
L<http://pause.perl.org>), you are only a few commands away from relasing it |
684 |
-to C<CPAN>. |
|
685 |
+to CPAN. |
|
685 | 686 |
|
686 | 687 |
$ perl Makefile.PL |
687 | 688 |
$ make test |
... | ... |
@@ -692,7 +693,7 @@ to C<CPAN>. |
692 | 693 |
=head2 Bundling assets with plugins |
693 | 694 |
|
694 | 695 |
Assets such as templates and static files can be easily bundled with your |
695 |
-plugins, even if you plan to release them to C<CPAN>. |
|
696 |
+plugins, even if you plan to release them to CPAN. |
|
696 | 697 |
|
697 | 698 |
$ mojo generate plugin AlertAssets |
698 | 699 |
$ mkdir AlertAssets/lib/Mojolicious/Plugin/AlertAssets |
... | ... |
@@ -790,10 +791,46 @@ that a response has been generated. |
790 | 791 |
$self->res->content->asset(Mojo::Asset::File->new(path => '/etc/passwd')); |
791 | 792 |
$self->rendered(200); |
792 | 793 |
|
794 |
+=head2 Post-processing dynamic content |
|
795 |
+ |
|
796 |
+While post-processing tasks are generally very easy with the C<after_dispatch> |
|
797 |
+hook, for content generated by the renderer it is a lot more efficient to use |
|
798 |
+C<after_render>. |
|
799 |
+ |
|
800 |
+ use Mojolicious::Lite; |
|
801 |
+ use IO::Compress::Gzip 'gzip'; |
|
802 |
+ |
|
803 |
+ hook after_render => sub { |
|
804 |
+ my ($self, $output, $format) = @_; |
|
805 |
+ |
|
806 |
+ # Check if "gzip => 1" has been set in the stash |
|
807 |
+ return unless $self->stash->{gzip}; |
|
808 |
+ |
|
809 |
+ # Check if user agent accepts GZip compression |
|
810 |
+ return unless ($self->req->headers->accept_encoding // '') =~ /gzip/i; |
|
811 |
+ |
|
812 |
+ # Compress content with GZip |
|
813 |
+ $self->res->headers->content_encoding('gzip'); |
|
814 |
+ gzip $output, \my $compressed; |
|
815 |
+ $$output = $compressed; |
|
816 |
+ }; |
|
817 |
+ |
|
818 |
+ get '/' => {template => 'hello', title => 'Hello', gzip => 1}; |
|
819 |
+ |
|
820 |
+ app->start; |
|
821 |
+ __DATA__ |
|
822 |
+ |
|
823 |
+ @@ hello.html.ep |
|
824 |
+ <!DOCTYPE html> |
|
825 |
+ <html> |
|
826 |
+ <head><title><%= title %></title></head> |
|
827 |
+ <body>Compressed content.</body> |
|
828 |
+ </html> |
|
829 |
+ |
|
793 | 830 |
=head2 Chunked transfer encoding |
794 | 831 |
|
795 |
-For very dynamic content you might not know the response C<Content-Length> in |
|
796 |
-advance, that's where the C<chunked> C<Transfer-Encoding> comes in handy. A |
|
832 |
+For very dynamic content you might not know the response content length in |
|
833 |
+advance, that's where the C<chunked> transfer encoding comes in handy. A |
|
797 | 834 |
common use would be to send the C<head> section of an HTML document to the |
798 | 835 |
browser in advance and speed up preloading of referenced images and |
799 | 836 |
stylesheets. |
... | ... |
@@ -814,8 +851,8 @@ L<Mojolicious::Controller/"finish"> marks the end of the stream. |
814 | 851 |
0 |
815 | 852 |
|
816 | 853 |
Especially in combination with long inactivity timeouts this can be very |
817 |
-useful for Comet (C<long polling>). Due to limitations in some web servers |
|
818 |
-this might not work perfectly in all deployment environments. |
|
854 |
+useful for Comet (long polling). Due to limitations in some web servers this |
|
855 |
+might not work perfectly in all deployment environments. |
|
819 | 856 |
|
820 | 857 |
=head2 Encoding |
821 | 858 |
|
... | ... |
@@ -893,23 +930,28 @@ L<Mojo::Template> contains the whole list of available options. |
893 | 930 |
|
894 | 931 |
=head2 Adding your favorite template system |
895 | 932 |
|
896 |
-Maybe you would prefer a different template system than C<ep>, all you have to |
|
897 |
-do is add a new C<handler>. |
|
933 |
+Maybe you would prefer a different template system than C<ep>, and there is |
|
934 |
+not already a plugin on CPAN for your favorite one, all you have to do is add |
|
935 |
+a new C<handler> when C<register> is called. |
|
898 | 936 |
|
899 |
- use Mojolicious::Lite; |
|
937 |
+ package Mojolicious::Plugin::MyRenderer; |
|
938 |
+ use Mojo::Base 'Mojolicious::Plugin'; |
|
939 |
+ |
|
940 |
+ sub register { |
|
941 |
+ my ($self, $app) = @_; |
|
900 | 942 |
|
901 |
- app->renderer->add_handler( |
|
902 |
- mine => sub { |
|
943 |
+ # Add "mine" handler |
|
944 |
+ $app->renderer->add_handler(mine => sub { |
|
903 | 945 |
my ($renderer, $c, $output, $options) = @_; |
904 | 946 |
|
905 |
- # Check for one time use inline template |
|
947 |
+ # Check for one-time use inline template |
|
906 | 948 |
my $inline = $options->{inline}; |
907 | 949 |
|
908 | 950 |
# Check for absolute template path |
909 |
- my $path = $r->template_path($options); |
|
951 |
+ my $path = $renderer->template_path($options); |
|
910 | 952 |
|
911 | 953 |
# Check for appropriate template in DATA section |
912 |
- my $data = $r->get_data_template($options); |
|
954 |
+ my $data = $renderer->get_data_template($options); |
|
913 | 955 |
|
914 | 956 |
# This part is up to you and your template system :) |
915 | 957 |
... |
... | ... |
@@ -922,63 +964,25 @@ do is add a new C<handler>. |
922 | 964 |
|
923 | 965 |
# And return true if something has been rendered or false otherwise |
924 | 966 |
return 1; |
925 |
- } |
|
926 |
- ); |
|
927 |
- |
|
928 |
- get '/' => 'index'; |
|
929 |
- |
|
930 |
- app->start; |
|
931 |
- __DATA__ |
|
967 |
+ }); |
|
968 |
+ } |
|
932 | 969 |
|
933 |
- @@ index.html.mine |
|
934 |
- ... |
|
970 |
+ 1; |
|
935 | 971 |
|
936 | 972 |
Since most template systems don't support templates in the C<DATA> section, |
937 | 973 |
the renderer provides methods to help you with that. |
938 | 974 |
|
939 |
-=head2 Post-processing content |
|
940 |
- |
|
941 |
-While post-processing tasks are generally very easy with the C<after_dispatch> |
|
942 |
-hook, especially for content generated by the renderer, there are a few things |
|
943 |
-you need to watch out for, such as multipart content, dynamically generated |
|
944 |
-content, content that is streamed directly from files and content with range |
|
945 |
-constraints. |
|
946 |
- |
|
947 | 975 |
use Mojolicious::Lite; |
948 |
- use IO::Compress::Gzip 'gzip'; |
|
949 | 976 |
|
950 |
- hook after_dispatch => sub { |
|
951 |
- my $self = shift; |
|
977 |
+ plugin 'MyRenderer'; |
|
952 | 978 |
|
953 |
- # Check if "gzip => 1" has been set in the stash |
|
954 |
- return unless $self->stash->{gzip}; |
|
955 |
- |
|
956 |
- # Check if user agent accepts GZip compression |
|
957 |
- return unless ($self->req->headers->accept_encoding // '') =~ /gzip/i; |
|
958 |
- |
|
959 |
- # Check for multipart content or if content will be dynamically generated |
|
960 |
- return if $self->res->is_multipart || $self->res->is_dynamic; |
|
961 |
- |
|
962 |
- # Check if content is streamed from a file or has a range constraint |
|
963 |
- my $asset = $self->res->content->asset; |
|
964 |
- return if $asset->is_file || $asset->is_range; |
|
965 |
- |
|
966 |
- # Compress content |
|
967 |
- gzip \(my $dummy = $asset->slurp), \my $compressed; |
|
968 |
- $self->res->body($compressed)->headers->content_encoding('gzip'); |
|
969 |
- }; |
|
970 |
- |
|
971 |
- get '/' => {template => 'hello', title => 'Hello', gzip => 1}; |
|
979 |
+ get '/' => 'index'; |
|
972 | 980 |
|
973 | 981 |
app->start; |
974 | 982 |
__DATA__ |
975 | 983 |
|
976 |
- @@ hello.html.ep |
|
977 |
- <!DOCTYPE html> |
|
978 |
- <html> |
|
979 |
- <head><title><%= title %></title></head> |
|
980 |
- <body>Compressed content.</body> |
|
981 |
- </html> |
|
984 |
+ @@ index.html.mine |
|
985 |
+ ... |
|
982 | 986 |
|
983 | 987 |
=head1 MORE |
984 | 988 |
|
... | ... |
@@ -986,4 +990,11 @@ You can continue with L<Mojolicious::Guides> now or take a look at the |
986 | 990 |
L<Mojolicious wiki|http://github.com/kraih/mojo/wiki>, which contains a lot |
987 | 991 |
more documentation and examples by many different authors. |
988 | 992 |
|
993 |
+=head1 SUPPORT |
|
994 |
+ |
|
995 |
+If you have any questions the documentation might not yet answer, don't |
|
996 |
+hesitate to ask on the |
|
997 |
+L<mailing-list|http://groups.google.com/group/mojolicious> or the official IRC |
|
998 |
+channel C<#mojo> on C<irc.perl.org>. |
|
999 |
+ |
|
989 | 1000 |
=cut |
... | ... |
@@ -623,10 +623,9 @@ Post-processing tasks such as setting additional response headers are a very |
623 | 623 |
common use. |
624 | 624 |
|
625 | 625 |
# Make sure static files are cached |
626 |
- $self->hook(after_static_dispatch => sub { |
|
626 |
+ $self->hook(after_static => sub { |
|
627 | 627 |
my $self = shift; |
628 |
- $self->res->headers->cache_control('max-age=3600, must-revalidate') |
|
629 |
- if $self->res->code; |
|
628 |
+ $self->res->headers->cache_control('max-age=3600, must-revalidate'); |
|
630 | 629 |
}); |
631 | 630 |
|
632 | 631 |
Same for monitoring tasks. |
... | ... |
@@ -746,17 +745,15 @@ You can also package your conditions as reusable plugins. |
746 | 745 |
my ($self, $app) = @_; |
747 | 746 |
|
748 | 747 |
# Add "werewolf" condition |
749 |
- $app->routes->add_condition( |
|
750 |
- werewolf => sub { |
|
751 |
- my ($route, $c, $captures, $days) = @_; |
|
748 |
+ $app->routes->add_condition(werewolf => sub { |
|
749 |
+ my ($route, $c, $captures, $days) = @_; |
|
752 | 750 |
|
753 |
- # Keep the werewolfs out! |
|
754 |
- return undef if abs(14 - (phase(time))[2]) > ($days / 2); |
|
751 |
+ # Keep the werewolfs out! |
|
752 |
+ return undef if abs(14 - (phase(time))[2]) > ($days / 2); |
|
755 | 753 |
|
756 |
- # It's ok, no werewolf |
|
757 |
- return 1; |
|
758 |
- } |
|
759 |
- ); |
|
754 |
+ # It's ok, no werewolf |
|
755 |
+ return 1; |
|
756 |
+ }); |
|
760 | 757 |
} |
761 | 758 |
|
762 | 759 |
1; |
... | ... |
@@ -885,4 +882,11 @@ You can continue with L<Mojolicious::Guides> now or take a look at the |
885 | 882 |
L<Mojolicious wiki|http://github.com/kraih/mojo/wiki>, which contains a lot |
886 | 883 |
more documentation and examples by many different authors. |
887 | 884 |
|
885 |
+=head1 SUPPORT |
|
886 |
+ |
|
887 |
+If you have any questions the documentation might not yet answer, don't |
|
888 |
+hesitate to ask on the |
|
889 |
+L<mailing-list|http://groups.google.com/group/mojolicious> or the official IRC |
|
890 |
+channel C<#mojo> on C<irc.perl.org>. |
|
891 |
+ |
|
888 | 892 |
=cut |
... | ... |
@@ -2,50 +2,55 @@ package Mojolicious::Lite; |
2 | 2 |
use Mojo::Base 'Mojolicious'; |
3 | 3 |
|
4 | 4 |
# "Bender: Bite my shiny metal ass!" |
5 |
-use File::Basename 'dirname'; |
|
5 |
+use File::Basename qw(basename dirname); |
|
6 | 6 |
use File::Spec::Functions 'catdir'; |
7 | 7 |
use Mojo::UserAgent; |
8 | 8 |
use Mojo::Util 'monkey_patch'; |
9 | 9 |
|
10 | 10 |
sub import { |
11 |
- my $class = shift; |
|
12 | 11 |
|
13 |
- # Executable |
|
12 |
+ # Remember executable for later |
|
14 | 13 |
$ENV{MOJO_EXE} ||= (caller)[1]; |
15 | 14 |
|
16 |
- # Home |
|
17 |
- local $ENV{MOJO_HOME} = catdir(split '/', dirname($ENV{MOJO_EXE})) |
|
15 |
+ # Reuse home directory if possible |
|
16 |
+ local $ENV{MOJO_HOME} = catdir(split '/', dirname $ENV{MOJO_EXE}) |
|
18 | 17 |
unless $ENV{MOJO_HOME}; |
19 | 18 |
|
20 |
- # Initialize app |
|
19 |
+ # Initialize application class |
|
21 | 20 |
my $caller = caller; |
22 | 21 |
no strict 'refs'; |
23 | 22 |
push @{"${caller}::ISA"}, 'Mojo'; |
24 |
- my $app = $class->new; |
|
23 |
+ my $app = shift->new; |
|
25 | 24 |
|
26 |
- # Initialize routes |
|
25 |
+ # Generate moniker based on filename |
|
26 |
+ my $moniker = basename $ENV{MOJO_EXE}; |
|
27 |
+ $moniker =~ s/\.(?:pl|pm|t)$//i; |
|
28 |
+ $app->moniker($moniker); |
|
29 |
+ |
|
30 |
+ # Initialize routes without namespaces |
|
27 | 31 |
my $routes = $app->routes->namespaces([]); |
28 | 32 |
|
29 | 33 |
# Default static and template class |
30 | 34 |
$app->static->classes->[0] = $app->renderer->classes->[0] = $caller; |
31 | 35 |
|
32 |
- # Export |
|
36 |
+ # The Mojolicious::Lite DSL |
|
33 | 37 |
my $root = $routes; |
34 | 38 |
for my $name (qw(any get options patch post put websocket)) { |
35 | 39 |
monkey_patch $caller, $name, sub { $routes->$name(@_) }; |
36 | 40 |
} |
37 | 41 |
monkey_patch $caller, $_, sub {$app} |
38 | 42 |
for qw(new app); |
39 |
- monkey_patch $caller, 'del', sub { $routes->delete(@_) }; |
|
40 |
- monkey_patch $caller, 'group', sub (&) { |
|
43 |
+ monkey_patch $caller, del => sub { $routes->delete(@_) }; |
|
44 |
+ monkey_patch $caller, group => sub (&) { |
|
41 | 45 |
my $old = $root; |
42 | 46 |
$_[0]->($root = $routes); |
43 | 47 |
($routes, $root) = ($root, $old); |
44 | 48 |
}; |
45 |
- monkey_patch $caller, 'helper', sub { $app->helper(@_) }; |
|
46 |
- monkey_patch $caller, 'hook', sub { $app->hook(@_) }; |
|
47 |
- monkey_patch $caller, 'plugin', sub { $app->plugin(@_) }; |
|
48 |
- monkey_patch $caller, 'under', sub { $routes = $root->under(@_) }; |
|
49 |
+ monkey_patch $caller, |
|
50 |
+ helper => sub { $app->helper(@_) }, |
|
51 |
+ hook => sub { $app->hook(@_) }, |
|
52 |
+ plugin => sub { $app->plugin(@_) }, |
|
53 |
+ under => sub { $routes = $root->under(@_) }; |
|
49 | 54 |
|
50 | 55 |
# Make sure there's a default application for testing |
51 | 56 |
Mojo::UserAgent->app($app) unless Mojo::UserAgent->app; |
... | ... |
@@ -929,7 +934,7 @@ fun! |
929 | 934 |
|
930 | 935 |
L<Mojolicious::Lite> implements the following functions. |
931 | 936 |
|
932 |
-=head2 C<any> |
|
937 |
+=head2 any |
|
933 | 938 |
|
934 | 939 |
my $route = any '/:foo' => sub {...}; |
935 | 940 |
my $route = any [qw(GET POST)] => '/:foo' => sub {...}; |
... | ... |
@@ -938,45 +943,45 @@ Generate route with L<Mojolicious::Routes::Route/"any">, matching any of the |
938 | 943 |
listed HTTP request methods or all. See also the tutorial above for more |
939 | 944 |
argument variations. |
940 | 945 |
|
941 |
-=head2 C<app> |
|
946 |
+=head2 app |
|
942 | 947 |
|
943 | 948 |
my $app = app; |
944 | 949 |
|
945 | 950 |
The L<Mojolicious::Lite> application. |
946 | 951 |
|
947 |
-=head2 C<del> |
|
952 |
+=head2 del |
|
948 | 953 |
|
949 | 954 |
my $route = del '/:foo' => sub {...}; |
950 | 955 |
|
951 | 956 |
Generate route with L<Mojolicious::Routes::Route/"delete">, matching only |
952 | 957 |
C<DELETE> requests. See also the tutorial above for more argument variations. |
953 | 958 |
|
954 |
-=head2 C<get> |
|
959 |
+=head2 get |
|
955 | 960 |
|
956 | 961 |
my $route = get '/:foo' => sub {...}; |
957 | 962 |
|
958 | 963 |
Generate route with L<Mojolicious::Routes::Route/"get">, matching only C<GET> |
959 | 964 |
requests. See also the tutorial above for more argument variations. |
960 | 965 |
|
961 |
-=head2 C<group> |
|
966 |
+=head2 group |
|
962 | 967 |
|
963 | 968 |
group {...}; |
964 | 969 |
|
965 | 970 |
Start a new route group. |
966 | 971 |
|
967 |
-=head2 C<helper> |
|
972 |
+=head2 helper |
|
968 | 973 |
|
969 | 974 |
helper foo => sub {...}; |
970 | 975 |
|
971 | 976 |
Add a new helper with L<Mojolicious/"helper">. |
972 | 977 |
|
973 |
-=head2 C<hook> |
|
978 |
+=head2 hook |
|
974 | 979 |
|
975 | 980 |
hook after_dispatch => sub {...}; |
976 | 981 |
|
977 | 982 |
Share code with L<Mojolicious/"hook">. |
978 | 983 |
|
979 |
-=head2 C<options> |
|
984 |
+=head2 options |
|
980 | 985 |
|
981 | 986 |
my $route = options '/:foo' => sub {...}; |
982 | 987 |
|
... | ... |
@@ -984,34 +989,34 @@ Generate route with L<Mojolicious::Routes::Route/"options">, matching only |
984 | 989 |
C<OPTIONS> requests. See also the tutorial above for more argument |
985 | 990 |
variations. |
986 | 991 |
|
987 |
-=head2 C<patch> |
|
992 |
+=head2 patch |
|
988 | 993 |
|
989 | 994 |
my $route = patch '/:foo' => sub {...}; |
990 | 995 |
|
991 | 996 |
Generate route with L<Mojolicious::Routes::Route/"patch">, matching only |
992 | 997 |
C<PATCH> requests. See also the tutorial above for more argument variations. |
993 | 998 |
|
994 |
-=head2 C<plugin> |
|
999 |
+=head2 plugin |
|
995 | 1000 |
|
996 | 1001 |
plugin SomePlugin => {foo => 23}; |
997 | 1002 |
|
998 | 1003 |
Load a plugin with L<Mojolicious/"plugin">. |
999 | 1004 |
|
1000 |
-=head2 C<post> |
|
1005 |
+=head2 post |
|
1001 | 1006 |
|
1002 | 1007 |
my $route = post '/:foo' => sub {...}; |
1003 | 1008 |
|
1004 | 1009 |
Generate route with L<Mojolicious::Routes::Route/"post">, matching only |
1005 | 1010 |
C<POST> requests. See also the tutorial above for more argument variations. |
1006 | 1011 |
|
1007 |
-=head2 C<put> |
|
1012 |
+=head2 put |
|
1008 | 1013 |
|
1009 | 1014 |
my $route = put '/:foo' => sub {...}; |
1010 | 1015 |
|
1011 | 1016 |
Generate route with L<Mojolicious::Routes::Route/"put">, matching only C<PUT> |
1012 | 1017 |
requests. See also the tutorial above for more argument variations. |
1013 | 1018 |
|
1014 |
-=head2 C<under> |
|
1019 |
+=head2 under |
|
1015 | 1020 |
|
1016 | 1021 |
my $route = under sub {...}; |
1017 | 1022 |
my $route = under '/:foo'; |
... | ... |
@@ -1020,7 +1025,7 @@ Generate bridge route with L<Mojolicious::Routes::Route/"under">, to which all |
1020 | 1025 |
following routes are automatically appended. See also the tutorial above for |
1021 | 1026 |
more argument variations. |
1022 | 1027 |
|
1023 |
-=head2 C<websocket> |
|
1028 |
+=head2 websocket |
|
1024 | 1029 |
|
1025 | 1030 |
my $route = websocket '/:foo' => sub {...}; |
1026 | 1031 |
|
... | ... |
@@ -32,7 +32,7 @@ L<Mojolicious::Plugin> is an abstract base class for L<Mojolicious> plugins. |
32 | 32 |
L<Mojolicious::Plugin> inherits all methods from L<Mojo::Base> and implements |
33 | 33 |
the following new ones. |
34 | 34 |
|
35 |
-=head2 C<register> |
|
35 |
+=head2 register |
|
36 | 36 |
|
37 | 37 |
$plugin->register(Mojolicious->new); |
38 | 38 |
$plugin->register(Mojolicious->new, {foo => 'bar'}); |
... | ... |
@@ -4,7 +4,6 @@ use Mojo::Base 'Mojolicious::Plugin'; |
4 | 4 |
sub register { |
5 | 5 |
my ($self, $app, $conf) = @_; |
6 | 6 |
|
7 |
- # Change default charset on all layers |
|
8 | 7 |
return unless my $c = $conf->{charset}; |
9 | 8 |
$app->types->type(html => "text/html;charset=$c"); |
10 | 9 |
$app->renderer->encoding($c); |
... | ... |
@@ -38,7 +37,7 @@ you're welcome to fork it. |
38 | 37 |
|
39 | 38 |
L<Mojolicious::Plugin::Charset> supports the following options. |
40 | 39 |
|
41 |
-=head2 C<charset> |
|
40 |
+=head2 charset |
|
42 | 41 |
|
43 | 42 |
# Mojolicious::Lite |
44 | 43 |
plugin Charset => {charset => 'Shift_JIS'}; |
... | ... |
@@ -50,11 +49,11 @@ Application charset. |
50 | 49 |
L<Mojolicious::Plugin::Charset> inherits all methods from |
51 | 50 |
L<Mojolicious::Plugin> and implements the following new ones. |
52 | 51 |
|
53 |
-=head2 C<register> |
|
52 |
+=head2 register |
|
54 | 53 |
|
55 | 54 |
$plugin->register(Mojolicious->new, {charset => 'Shift_JIS'}); |
56 | 55 |
|
57 |
-Register plugin hooks in L<Mojolicious> application. |
|
56 |
+Register hooks in L<Mojolicious> application. |
|
58 | 57 |
|
59 | 58 |
=head1 SEE ALSO |
60 | 59 |
|
... | ... |
@@ -1,21 +1,13 @@ |
1 | 1 |
package Mojolicious::Plugin::Config; |
2 | 2 |
use Mojo::Base 'Mojolicious::Plugin'; |
3 | 3 |
|
4 |
-use File::Basename 'basename'; |
|
5 | 4 |
use File::Spec::Functions 'file_name_is_absolute'; |
6 |
-use Mojo::Util 'decamelize'; |
|
5 |
+use Mojo::Util qw(decode slurp); |
|
7 | 6 |
|
8 | 7 |
sub load { |
9 | 8 |
my ($self, $file, $conf, $app) = @_; |
10 | 9 |
$app->log->debug(qq{Reading config file "$file".}); |
11 |
- |
|
12 |
- # Slurp UTF-8 file |
|
13 |
- open my $handle, "<:encoding(UTF-8)", $file |
|
14 |
- or die qq{Couldn't open config file "$file": $!}; |
|
15 |
- my $content = do { local $/; <$handle> }; |
|
16 |
- |
|
17 |
- # Process |
|
18 |
- return $self->parse($content, $file, $conf, $app); |
|
10 |
+ return $self->parse(decode('UTF-8', slurp $file), $file, $conf, $app); |
|
19 | 11 |
} |
20 | 12 |
|
21 | 13 |
sub parse { |
... | ... |
@@ -36,21 +28,11 @@ sub register { |
36 | 28 |
|
37 | 29 |
# Config file |
38 | 30 |
my $file = $conf->{file} || $ENV{MOJO_CONFIG}; |
39 |
- unless ($file) { |
|
40 |
- |
|
41 |
- # Class or executable |
|
42 |
- $file |
|
43 |
- = $ENV{MOJO_APP} ? decamelize($ENV{MOJO_APP}) : basename($ENV{MOJO_EXE}); |
|
44 |
- |
|
45 |
- # Replace ".pl" and ".t" with default extension |
|
46 |
- $file =~ s/\.(?:pl|t)$//i; |
|
47 |
- $file .= '.' . ($conf->{ext} || 'conf'); |
|
48 |
- } |
|
31 |
+ $file ||= $app->moniker . '.' . ($conf->{ext} || 'conf'); |
|
49 | 32 |
|
50 | 33 |
# Mode specific config file |
51 | 34 |
my $mode = $file =~ /^(.*)\.([^.]+)$/ ? join('.', $1, $app->mode, $2) : ''; |
52 | 35 |
|
53 |
- # Absolute paths |
|
54 | 36 |
my $home = $app->home; |
55 | 37 |
$file = $home->rel_file($file) unless file_name_is_absolute $file; |
56 | 38 |
$mode = $home->rel_file($mode) if $mode && !file_name_is_absolute $mode; |
... | ... |
@@ -111,8 +93,7 @@ The application object can be accessed via C<$app> or the C<app> function, |
111 | 93 |
L<strict>, L<warnings>, L<utf8> and Perl 5.10 features are automatically |
112 | 94 |
enabled. You can extend the normal configuration file C<myapp.conf> with |
113 | 95 |
C<mode> specific ones like C<myapp.$mode.conf>. A default configuration |
114 |
-filename will be generated by decamelizing the application class with |
|
115 |
-L<Mojo::Util/"decamelize"> or from the application filename. |
|
96 |
+filename will be generated from the value of L<Mojolicious/"moniker">. |
|
116 | 97 |
|
117 | 98 |
The code of this plugin is a good example for learning to build new plugins, |
118 | 99 |
you're welcome to fork it. |
... | ... |
@@ -121,21 +102,21 @@ you're welcome to fork it. |
121 | 102 |
|
122 | 103 |
L<Mojolicious::Plugin::Config> supports the following options. |
123 | 104 |
|
124 |
-=head2 C<default> |
|
105 |
+=head2 default |
|
125 | 106 |
|
126 | 107 |
# Mojolicious::Lite |
127 | 108 |
plugin Config => {default => {foo => 'bar'}}; |
128 | 109 |
|
129 | 110 |
Default configuration, making configuration files optional. |
130 | 111 |
|
131 |
-=head2 C<ext> |
|
112 |
+=head2 ext |
|
132 | 113 |
|
133 | 114 |
# Mojolicious::Lite |
134 | 115 |
plugin Config => {ext => 'stuff'}; |
135 | 116 |
|
136 | 117 |
File extension for generated configuration filenames, defaults to C<conf>. |
137 | 118 |
|
138 |
-=head2 C<file> |
|
119 |
+=head2 file |
|
139 | 120 |
|
140 | 121 |
# Mojolicious::Lite |
141 | 122 |
plugin Config => {file => 'myapp.conf'}; |
... | ... |
@@ -149,7 +130,7 @@ environment variable or C<myapp.conf> in the application home directory. |
149 | 130 |
L<Mojolicious::Plugin::Config> inherits all methods from |
150 | 131 |
L<Mojolicious::Plugin> and implements the following new ones. |
151 | 132 |
|
152 |
-=head2 C<load> |
|
133 |
+=head2 load |
|
153 | 134 |
|
154 | 135 |
$plugin->load($file, $conf, $app); |
155 | 136 |
|
... | ... |
@@ -161,7 +142,7 @@ Loads configuration file and passes the content to C<parse>. |
161 | 142 |
return $self->parse($content, $file, $conf, $app); |
162 | 143 |
} |
163 | 144 |
|
164 |
-=head2 C<parse> |
|
145 |
+=head2 parse |
|
165 | 146 |
|
166 | 147 |
$plugin->parse($content, $file, $conf, $app); |
167 | 148 |
|
... | ... |
@@ -173,7 +154,7 @@ Parse configuration file. |
173 | 154 |
return $hash; |
174 | 155 |
} |
175 | 156 |
|
176 |
-=head2 C<register> |
|
157 |
+=head2 register |
|
177 | 158 |
|
178 | 159 |
my $config = $plugin->register(Mojolicious->new); |
179 | 160 |
my $config = $plugin->register(Mojolicious->new, {file => '/etc/app.conf'}); |
... | ... |
@@ -25,25 +25,13 @@ sub register { |
25 | 25 |
); |
26 | 26 |
} |
27 | 27 |
|
28 |
- # Add "config" helper |
|
29 | 28 |
$app->helper(config => sub { shift->app->config(@_) }); |
30 |
- |
|
31 |
- # Add "content" helper |
|
32 |
- $app->helper(content => \&_content); |
|
33 |
- |
|
34 |
- # Add "content_for" helper |
|
35 |
- $app->helper(content_for => \&_content_for); |
|
36 |
- |
|
37 |
- # Add "current_route" helper |
|
29 |
+ $app->helper(content => \&_content); |
|
30 |
+ $app->helper(content_for => \&_content_for); |
|
38 | 31 |
$app->helper(current_route => \&_current_route); |
32 |
+ $app->helper(dumper => \&_dumper); |
|
33 |
+ $app->helper(include => \&_include); |
|
39 | 34 |
|
40 |
- # Add "dumper" helper |
|
41 |
- $app->helper(dumper => \&_dumper); |
|
42 |
- |
|
43 |
- # Add "include" helper |
|
44 |
- $app->helper(include => \&_include); |
|
45 |
- |
|
46 |
- # Add "memorize" helper |
|
47 | 35 |
my %mem; |
48 | 36 |
$app->helper( |
49 | 37 |
memorize => sub { |
... | ... |
@@ -77,7 +65,6 @@ sub register { |
77 | 65 |
} |
78 | 66 |
); |
79 | 67 |
|
80 |
- # Add "url_with" helper |
|
81 | 68 |
$app->helper(url_with => \&_url_with); |
82 | 69 |
} |
83 | 70 |
|
... | ... |
@@ -157,19 +144,19 @@ example for learning to build new plugins, you're welcome to fork it. |
157 | 144 |
|
158 | 145 |
L<Mojolicious::Plugin::DefaultHelpers> implements the following helpers. |
159 | 146 |
|
160 |
-=head2 C<app> |
|
147 |
+=head2 app |
|
161 | 148 |
|
162 | 149 |
%= app->secret |
163 | 150 |
|
164 | 151 |
Alias for L<Mojolicious::Controller/"app">. |
165 | 152 |
|
166 |
-=head2 C<config> |
|
153 |
+=head2 config |
|
167 | 154 |
|
168 | 155 |
%= config 'something' |
169 | 156 |
|
170 | 157 |
Alias for L<Mojo/"config">. |
171 | 158 |
|
172 |
-=head2 C<content> |
|
159 |
+=head2 content |
|
173 | 160 |
|
174 | 161 |
%= content foo => begin |
175 | 162 |
test |
... | ... |
@@ -181,7 +168,7 @@ Alias for L<Mojo/"config">. |
181 | 168 |
|
182 | 169 |
Store partial rendered content in named buffer and retrieve it. |
183 | 170 |
|
184 |
-=head2 C<content_for> |
|
171 |
+=head2 content_for |
|
185 | 172 |
|
186 | 173 |
% content_for foo => begin |
187 | 174 |
test |
... | ... |
@@ -198,7 +185,7 @@ Append partial rendered content to named buffer and retrieve it. |
198 | 185 |
% end |
199 | 186 |
%= content_for 'message' |
200 | 187 |
|
201 |
-=head2 C<current_route> |
|
188 |
+=head2 current_route |
|
202 | 189 |
|
203 | 190 |
% if (current_route 'login') { |
204 | 191 |
Welcome to Mojolicious! |
... | ... |
@@ -207,26 +194,26 @@ Append partial rendered content to named buffer and retrieve it. |
207 | 194 |
|
208 | 195 |
Check or get name of current route. |
209 | 196 |
|
210 |
-=head2 C<dumper> |
|
197 |
+=head2 dumper |
|
211 | 198 |
|
212 | 199 |
%= dumper {some => 'data'} |
213 | 200 |
|
214 | 201 |
Dump a Perl data structure with L<Data::Dumper>. |
215 | 202 |
|
216 |
-=head2 C<extends> |
|
203 |
+=head2 extends |
|
217 | 204 |
|
218 | 205 |
% extends 'blue'; |
219 | 206 |
% extends 'blue', title => 'Blue!'; |
220 | 207 |
|
221 | 208 |
Extend a template. All additional values get merged into the C<stash>. |
222 | 209 |
|
223 |
-=head2 C<flash> |
|
210 |
+=head2 flash |
|
224 | 211 |
|
225 | 212 |
%= flash 'foo' |
226 | 213 |
|
227 | 214 |
Alias for L<Mojolicious::Controller/"flash">. |
228 | 215 |
|
229 |
-=head2 C<include> |
|
216 |
+=head2 include |
|
230 | 217 |
|
231 | 218 |
%= include 'menubar' |
232 | 219 |
%= include 'menubar', format => 'txt' |
... | ... |
@@ -234,7 +221,7 @@ Alias for L<Mojolicious::Controller/"flash">. |
234 | 221 |
Include a partial template, all arguments get localized automatically and are |
235 | 222 |
only available in the partial template. |
236 | 223 |
|
237 |
-=head2 C<layout> |
|
224 |
+=head2 layout |
|
238 | 225 |
|
239 | 226 |
% layout 'green'; |
240 | 227 |
% layout 'green', title => 'Green!'; |
... | ... |
@@ -242,7 +229,7 @@ only available in the partial template. |
242 | 229 |
Render this template with a layout. All additional values get merged into the |
243 | 230 |
C<stash>. |
244 | 231 |
|
245 |
-=head2 C<memorize> |
|
232 |
+=head2 memorize |
|
246 | 233 |
|
247 | 234 |
%= memorize begin |
248 | 235 |
%= time |
... | ... |
@@ -259,19 +246,19 @@ C<stash>. |
259 | 246 |
|
260 | 247 |
Memorize block result in memory and prevent future execution. |
261 | 248 |
|
262 |
-=head2 C<param> |
|
249 |
+=head2 param |
|
263 | 250 |
|
264 | 251 |
%= param 'foo' |
265 | 252 |
|
266 | 253 |
Alias for L<Mojolicious::Controller/"param">. |
267 | 254 |
|
268 |
-=head2 C<session> |
|
255 |
+=head2 session |
|
269 | 256 |
|
270 | 257 |
%= session 'foo' |
271 | 258 |
|
272 | 259 |
Alias for L<Mojolicious::Controller/"session">. |
273 | 260 |
|
274 |
-=head2 C<stash> |
|
261 |
+=head2 stash |
|
275 | 262 |
|
276 | 263 |
%= stash 'foo' |
277 | 264 |
% stash foo => 'bar'; |
... | ... |
@@ -280,7 +267,7 @@ Alias for L<Mojolicious::Controller/"stash">. |
280 | 267 |
|
281 | 268 |
%= stash 'name' // 'Somebody' |
282 | 269 |
|
283 |
-=head2 C<title> |
|
270 |
+=head2 title |
|
284 | 271 |
|
285 | 272 |
% title 'Welcome!'; |
286 | 273 |
% title 'Welcome!', foo => 'bar'; |
... | ... |
@@ -288,13 +275,13 @@ Alias for L<Mojolicious::Controller/"stash">. |
288 | 275 |
|
289 | 276 |
Page title. All additional values get merged into the C<stash>. |
290 | 277 |
|
291 |
-=head2 C<url_for> |
|
278 |
+=head2 url_for |
|
292 | 279 |
|
293 | 280 |
%= url_for 'named', controller => 'bar', action => 'baz' |
294 | 281 |
|
295 | 282 |
Alias for L<Mojolicious::Controller/"url_for">. |
296 | 283 |
|
297 |
-=head2 C<url_with> |
|
284 |
+=head2 url_with |
|
298 | 285 |
|
299 | 286 |
%= url_with 'named', controller => 'bar', action => 'baz' |
300 | 287 |
|
... | ... |
@@ -308,7 +295,7 @@ request. |
308 | 295 |
L<Mojolicious::Plugin::DefaultHelpers> inherits all methods from |
309 | 296 |
L<Mojolicious::Plugin> and implements the following new ones. |
310 | 297 |
|
311 |
-=head2 C<register> |
|
298 |
+=head2 register |
|
312 | 299 |
|
313 | 300 |
$plugin->register(Mojolicious->new); |
314 | 301 |
|
... | ... |
@@ -4,12 +4,7 @@ use Mojo::Base 'Mojolicious::Plugin'; |
4 | 4 |
use Mojo::Template; |
5 | 5 |
use Mojo::Util qw(encode md5_sum); |
6 | 6 |
|
7 |
-sub register { |
|
8 |
- my ($self, $app) = @_; |
|
9 |
- |
|
10 |
- # Add "epl" handler |
|
11 |
- $app->renderer->add_handler(epl => \&_epl); |
|
12 |
-} |
|
7 |
+sub register { $_[1]->renderer->add_handler(epl => \&_epl) } |
|
13 | 8 |
|
14 | 9 |
sub _epl { |
15 | 10 |
my ($renderer, $c, $output, $options) = @_; |
... | ... |
@@ -96,7 +91,7 @@ example for learning to build new plugins, you're welcome to fork it. |
96 | 91 |
L<Mojolicious::Plugin::EPLRenderer> inherits all methods from |
97 | 92 |
L<Mojolicious::Plugin> and implements the following new ones. |
98 | 93 |
|
99 |
-=head2 C<register> |
|
94 |
+=head2 register |
|
100 | 95 |
|
101 | 96 |
$plugin->register(Mojolicious->new); |
102 | 97 |
|
... | ... |
@@ -11,8 +11,8 @@ sub register { |
11 | 11 |
# Auto escape by default to prevent XSS attacks |
12 | 12 |
my $template = {auto_escape => 1, %{$conf->{template} || {}}}; |
13 | 13 |
|
14 |
- # Add "ep" handler |
|
15 |
- $app->renderer->add_handler( |
|
14 |
+ # Add "ep" handler and make it the default |
|
15 |
+ $app->renderer->default_handler('ep')->add_handler( |
|
16 | 16 |
$conf->{name} || 'ep' => sub { |
17 | 17 |
my ($renderer, $c, $output, $options) = @_; |
18 | 18 |
|
... | ... |
@@ -39,7 +39,7 @@ sub register { |
39 | 39 |
# Be less relaxed for everything else |
40 | 40 |
$prepend .= 'use strict;'; |
41 | 41 |
|
42 |
- # Stash |
|
42 |
+ # Stash values |
|
43 | 43 |
$prepend .= 'my $_S = $self->stash;'; |
44 | 44 |
$prepend .= " my \$$_ = \$_S->{'$_'};" |
45 | 45 |
for grep {/^\w+$/} keys %{$c->stash}; |
... | ... |
@@ -52,9 +52,6 @@ sub register { |
52 | 52 |
return $renderer->handlers->{epl}->($renderer, $c, $output, $options); |
53 | 53 |
} |
54 | 54 |
); |
55 |
- |
|
56 |
- # Set default handler |
|
57 |
- $app->renderer->default_handler('ep'); |
|
58 | 55 |
} |
59 | 56 |
|
60 | 57 |
1; |
... | ... |
@@ -92,14 +89,14 @@ example for learning to build new plugins, you're welcome to fork it. |
92 | 89 |
|
93 | 90 |
L<Mojolicious::Plugin::EPRenderer> supports the following options. |
94 | 91 |
|
95 |
-=head2 C<name> |
|
92 |
+=head2 name |
|
96 | 93 |
|
97 | 94 |
# Mojolicious::Lite |
98 | 95 |
plugin EPRenderer => {name => 'foo'}; |
99 | 96 |
|
100 | 97 |
Handler name, defaults to C<ep>. |
101 | 98 |
|
102 |
-=head2 C<template> |
|
99 |
+=head2 template |
|
103 | 100 |
|
104 | 101 |
# Mojolicious::Lite |
105 | 102 |
plugin EPRenderer => {template => {line_start => '.'}}; |
... | ... |
@@ -111,7 +108,7 @@ Attribute values passed to L<Mojo::Template> object used to render templates. |
111 | 108 |
L<Mojolicious::Plugin::EPRenderer> inherits all methods from |
112 | 109 |
L<Mojolicious::Plugin> and implements the following new ones. |
113 | 110 |
|
114 |
-=head2 C<register> |
|
111 |
+=head2 register |
|
115 | 112 |
|
116 | 113 |
$plugin->register(Mojolicious->new); |
117 | 114 |
$plugin->register(Mojolicious->new, {name => 'foo'}); |
... | ... |
@@ -4,14 +4,9 @@ use Mojo::Base 'Mojolicious::Plugin'; |
4 | 4 |
sub register { |
5 | 5 |
my ($self, $app) = @_; |
6 | 6 |
|
7 |
- # "headers" condition |
|
8 | 7 |
$app->routes->add_condition(headers => \&_headers); |
9 |
- |
|
10 |
- # "agent" condition |
|
11 | 8 |
$app->routes->add_condition( |
12 | 9 |
agent => sub { _headers(@_[0 .. 2], {'User-Agent' => $_[3]}) }); |
13 |
- |
|
14 |
- # "host" condition |
|
15 | 10 |
$app->routes->add_condition( |
16 | 11 |
host => sub { _check($_[1]->req->url->to_abs->host, $_[3]) }); |
17 | 12 |
} |
... | ... |
@@ -77,7 +72,7 @@ example for learning to build new plugins, you're welcome to fork it. |
77 | 72 |
L<Mojolicious::Plugin::HeaderCondition> inherits all methods from |
78 | 73 |
L<Mojolicious::Plugin> and implements the following new ones. |
79 | 74 |
|
80 |
-=head2 C<register> |
|
75 |
+=head2 register |
|
81 | 76 |
|
82 | 77 |
$plugin->register(Mojolicious->new); |
83 | 78 |
|
... | ... |
@@ -8,12 +8,8 @@ use Mojo::Util 'encode'; |
8 | 8 |
sub parse { |
9 | 9 |
my ($self, $content, $file, $conf, $app) = @_; |
10 | 10 |
|
11 |
- # Render |
|
12 |
- $content = $self->render($content, $file, $conf, $app); |
|
13 |
- |
|
14 |
- # Parse |
|
15 | 11 |
my $json = Mojo::JSON->new; |
16 |
- my $config = $json->decode($content); |
|
12 |
+ my $config = $json->decode($self->render($content, $file, $conf, $app)); |
|
17 | 13 |
my $err = $json->error; |
18 | 14 |
die qq{Couldn't parse config "$file": $err} if !$config && $err; |
19 | 15 |
die qq{Invalid config "$file".} if !$config || ref $config ne 'HASH'; |
... | ... |
@@ -30,7 +26,7 @@ sub render { |
30 | 26 |
my $prepend = q[my $app = shift; no strict 'refs'; no warnings 'redefine';]; |
31 | 27 |
$prepend .= q[sub app; *app = sub { $app }; use Mojo::Base -strict;]; |
32 | 28 |
|
33 |
- # Render |
|
29 |
+ # Render and encode for JSON decoding |
|
34 | 30 |
my $mt = Mojo::Template->new($conf->{template} || {})->name($file); |
35 | 31 |
my $json = $mt->prepend($prepend . $mt->prepend)->render($content, $app); |
36 | 32 |
return ref $json ? die $json : encode 'UTF-8', $json; |
... | ... |
@@ -73,8 +69,7 @@ preprocesses its input with L<Mojo::Template>. |
73 | 69 |
The application object can be accessed via C<$app> or the C<app> function. You |
74 | 70 |
can extend the normal config file C<myapp.json> with C<mode> specific ones |
75 | 71 |
like C<myapp.$mode.json>. A default configuration filename will be generated |
76 |
-by decamelizing the application class with L<Mojo::Util/"decamelize"> or from |
|
77 |
-the application filename. |
|
72 |
+from the value of L<Mojolicious/"moniker">. |
|
78 | 73 |
|
79 | 74 |
The code of this plugin is a good example for learning to build new plugins, |
80 | 75 |
you're welcome to fork it. |
... | ... |
@@ -84,7 +79,7 @@ you're welcome to fork it. |
84 | 79 |
L<Mojolicious::Plugin::JSONConfig> inherits all options from |
85 | 80 |
L<Mojolicious::Plugin::Config> and supports the following new ones. |
86 | 81 |
|
87 |
-=head2 C<template> |
|
82 |
+=head2 template |
|
88 | 83 |
|
89 | 84 |
# Mojolicious::Lite |
90 | 85 |
plugin JSONConfig => {template => {line_start => '.'}}; |
... | ... |
@@ -97,7 +92,7 @@ configuration files. |
97 | 92 |
L<Mojolicious::Plugin::JSONConfig> inherits all methods from |
98 | 93 |
L<Mojolicious::Plugin::Config> and implements the following new ones. |
99 | 94 |
|
100 |
-=head2 C<parse> |
|
95 |
+=head2 parse |
|
101 | 96 |
|
102 | 97 |
$plugin->parse($content, $file, $conf, $app); |
103 | 98 |
|
... | ... |
@@ -111,14 +106,14 @@ Process content with C<render> and parse it with L<Mojo::JSON>. |
111 | 106 |
return $hash; |
112 | 107 |
} |
113 | 108 |
|
114 |
-=head2 C<register> |
|
109 |
+=head2 register |
|
115 | 110 |
|
116 | 111 |
my $config = $plugin->register(Mojolicious->new); |
117 | 112 |
my $config = $plugin->register(Mojolicious->new, {file => '/etc/foo.conf'}); |
118 | 113 |
|
119 | 114 |
Register plugin in L<Mojolicious> application. |
120 | 115 |
|
121 |
-=head2 C<render> |
|
116 |
+=head2 render |
|
122 | 117 |
|
123 | 118 |
$plugin->render($content, $file, $conf, $app); |
124 | 119 |
|
... | ... |
@@ -6,7 +6,6 @@ use Mojo::Server; |
6 | 6 |
sub register { |
7 | 7 |
my ($self, $app, $conf) = @_; |
8 | 8 |
|
9 |
- # Load application |
|
10 | 9 |
my $path = (keys %$conf)[0]; |
11 | 10 |
my $embed = Mojo::Server->new->load_app($conf->{$path}); |
12 | 11 |
|
... | ... |
@@ -17,7 +16,6 @@ sub register { |
17 | 16 |
$path = $3; |
18 | 17 |
} |
19 | 18 |
|
20 |
- # Generate route |
|
21 | 19 |
my $route = $app->routes->route($path)->detour(app => $embed); |
22 | 20 |
$route->over(host => $host) if $host; |
23 | 21 |
|
... | ... |
@@ -64,7 +62,7 @@ you're welcome to fork it. |
64 | 62 |
L<Mojolicious::Plugin::Mount> inherits all methods from L<Mojolicious::Plugin> |
65 | 63 |
and implements the following new ones. |
66 | 64 |
|
67 |
-=head2 C<register> |
|
65 |
+=head2 register |
|
68 | 66 |
|
69 | 67 |
my $route = $plugin->register(Mojolicious->new, {'/foo' => '/some/app.pl'}); |
70 | 68 |
|
... | ... |
@@ -8,13 +8,12 @@ use Mojo::Util 'url_escape'; |
8 | 8 |
BEGIN {eval {require Pod::Simple::HTML; import Pod::Simple::HTML}} |
9 | 9 |
BEGIN {eval {require Pod::Simple::Search; import Pod::Simple::Search}} |
10 | 10 |
|
11 |
-# Paths |
|
11 |
+# Paths to search |
|
12 | 12 |
my @PATHS = map { $_, "$_/pods" } @INC; |
13 | 13 |
|
14 | 14 |
sub register { |
15 | 15 |
my ($self, $app, $conf) = @_; |
16 | 16 |
|
17 |
- # Add "pod" handler |
|
18 | 17 |
my $preprocess = $conf->{preprocess} || 'ep'; |
19 | 18 |
$app->renderer->add_handler( |
20 | 19 |
$conf->{name} || 'pod' => sub { |
... | ... |
@@ -28,10 +27,9 @@ sub register { |
28 | 27 |
} |
29 | 28 |
); |
30 | 29 |
|
31 |
- # Add "pod_to_html" helper |
|
32 | 30 |
$app->helper(pod_to_html => sub { shift; b(_pod_to_html(@_)) }); |
33 | 31 |
|
34 |
- # Perldoc |
|
32 |
+ # Perldoc browser |
|
35 | 33 |
return if $conf->{no_perldoc}; |
36 | 34 |
return $app->routes->any( |
37 | 35 |
'/perldoc/*module' => {module => 'Mojolicious/Guides'} => \&_perldoc); |
... | ... |
@@ -40,12 +38,10 @@ sub register { |
40 | 38 |
sub _perldoc { |
41 | 39 |
my $self = shift; |
42 | 40 |
|
43 |
- # Find module |
|
41 |
+ # Find module or redirect to CPAN |
|
44 | 42 |
my $module = $self->param('module'); |
45 | 43 |
$module =~ s!/!::!g; |
46 | 44 |
my $path = Pod::Simple::Search->new->find($module, @PATHS); |
47 |
- |
|
48 |
- # Redirect to CPAN |
|
49 | 45 |
return $self->redirect_to("http://metacpan.org/module/$module") |
50 | 46 |
unless $path && -r $path; |
51 | 47 |
|
... | ... |
@@ -120,14 +116,11 @@ sub _pod_to_html { |
120 | 116 |
# Block |
121 | 117 |
$pod = $pod->() if ref $pod eq 'CODE'; |
122 | 118 |
|
123 |
- # Parser |
|
124 | 119 |
my $parser = Pod::Simple::HTML->new; |
125 | 120 |
$parser->force_title(''); |
126 | 121 |
$parser->html_header_before_title(''); |
127 | 122 |
$parser->html_header_after_title(''); |
128 | 123 |
$parser->html_footer(''); |
129 |
- |
|
130 |
- # Parse |
|
131 | 124 |
$parser->output_string(\(my $output)); |
132 | 125 |
return $@ unless eval { $parser->parse_string_document("$pod"); 1 }; |
133 | 126 |
|
... | ... |
@@ -170,14 +163,14 @@ you're welcome to fork it. |
170 | 163 |
|
171 | 164 |
L<Mojolicious::Plugin::PODRenderer> supports the following options. |
172 | 165 |
|
173 |
-=head2 C<name> |
|
166 |
+=head2 name |
|
174 | 167 |
|
175 | 168 |
# Mojolicious::Lite |
176 | 169 |
plugin PODRenderer => {name => 'foo'}; |
177 | 170 |
|
178 | 171 |
Handler name, defaults to C<pod>. |
179 | 172 |
|
180 |
-=head2 C<no_perldoc> |
|
173 |
+=head2 no_perldoc |
|
181 | 174 |
|
182 | 175 |
# Mojolicious::Lite |
183 | 176 |
plugin PODRenderer => {no_perldoc => 1}; |
... | ... |
@@ -185,7 +178,7 @@ Handler name, defaults to C<pod>. |
185 | 178 |
Disable L<Mojolicious::Guides> documentation browser that will otherwise be |
186 | 179 |
available under C</perldoc>. |
187 | 180 |
|
188 |
-=head2 C<preprocess> |
|
181 |
+=head2 preprocess |
|
189 | 182 |
|
190 | 183 |
# Mojolicious::Lite |
191 | 184 |
plugin PODRenderer => {preprocess => 'epl'}; |
... | ... |
@@ -196,7 +189,7 @@ Name of handler used to preprocess POD, defaults to C<ep>. |
196 | 189 |
|
197 | 190 |
L<Mojolicious::Plugin::PODRenderer> implements the following helpers. |
198 | 191 |
|
199 |
-=head2 C<pod_to_html> |
|
192 |
+=head2 pod_to_html |
|
200 | 193 |
|
201 | 194 |
%= pod_to_html '=head2 lalala' |
202 | 195 |
<%= pod_to_html begin %>=head2 lalala<% end %> |
... | ... |
@@ -208,7 +201,7 @@ Render POD to HTML without preprocessing. |
208 | 201 |
L<Mojolicious::Plugin::PODRenderer> inherits all methods from |
209 | 202 |
L<Mojolicious::Plugin> and implements the following new ones. |
210 | 203 |
|
211 |
-=head2 C<register> |
|
204 |
+=head2 register |
|
212 | 205 |
|
213 | 206 |
my $route = $plugin->register(Mojolicious->new); |
214 | 207 |
my $route = $plugin->register(Mojolicious->new, {name => 'foo'}); |
... | ... |
@@ -36,7 +36,7 @@ example for learning to build new plugins, you're welcome to fork it. |
36 | 36 |
|
37 | 37 |
L<Mojolicious::Plugin::PoweredBy> supports the following options. |
38 | 38 |
|
39 |
-=head2 C<name> |
|
39 |
+=head2 name |
|
40 | 40 |
|
41 | 41 |
plugin PoweredBy => (name => 'MyApp 1.0'); |
42 | 42 |
|
... | ... |
@@ -47,12 +47,12 @@ Value for C<X-Powered-By> header, defaults to C<Mojolicious (Perl)>. |
47 | 47 |
L<Mojolicious::Plugin::PoweredBy> inherits all methods from |
48 | 48 |
L<Mojolicious::Plugin> and implements the following new ones. |
49 | 49 |
|
50 |
-=head2 C<register> |
|
50 |
+=head2 register |
|
51 | 51 |
|
52 | 52 |
$plugin->register(Mojolicious->new); |
53 | 53 |
$plugin->register(Mojolicious->new, {name => 'MyFramework 1.0'}); |
54 | 54 |
|
55 |
-Register plugin hooks in L<Mojolicious> application. |
|
55 |
+Register hooks in L<Mojolicious> application. |
|
56 | 56 |
|
57 | 57 |
=head1 SEE ALSO |
58 | 58 |
|
... | ... |
@@ -5,11 +5,7 @@ use Time::HiRes qw(gettimeofday tv_interval); |
5 | 5 |
|
6 | 6 |
sub register { |
7 | 7 |
my ($self, $app) = @_; |
8 |
- |
|
9 |
- # Start timer |
|
10 |
- $app->hook(after_static_dispatch => \&_start); |
|
11 |
- |
|
12 |
- # End timer |
|
8 |
+ $app->hook(before_routes => \&_start); |
|
13 | 9 |
$app->hook(after_dispatch => \&_end); |
14 | 10 |
} |
15 | 11 |
|
... | ... |
@@ -70,11 +66,11 @@ example for learning to build new plugins, you're welcome to fork it. |
70 | 66 |
L<Mojolicious::Plugin::RequestTimer> inherits all methods from |
71 | 67 |
L<Mojolicious::Plugin> and implements the following new ones. |
72 | 68 |
|
73 |
-=head2 C<register> |
|
69 |
+=head2 register |
|
74 | 70 |
|
75 | 71 |
$plugin->register(Mojolicious->new); |
76 | 72 |
|
77 |
-Register plugin hooks in L<Mojolicious> application. |
|
73 |
+Register hooks in L<Mojolicious> application. |
|
78 | 74 |
|
79 | 75 |
=head1 SEE ALSO |
80 | 76 |
|
... | ... |
@@ -13,57 +13,38 @@ sub register { |
13 | 13 |
$app->helper("${name}_field" => sub { _input(@_, type => $name) }); |
14 | 14 |
} |
15 | 15 |
|
16 |
- # Add "base_tag" helper |
|
16 |
+ # DEPRECATED in Rainbow! |
|
17 | 17 |
$app->helper( |
18 |
- base_tag => sub { _tag('base', href => shift->req->url->base, @_) }); |
|
18 |
+ base_tag => sub { |
|
19 |
+ warn "base_tag is DEPRECATED!!!\n"; |
|
20 |
+ _tag('base', href => shift->req->url->base, @_); |
|
21 |
+ } |
|
22 |
+ ); |
|
19 | 23 |
|
20 |
- # Add "checkbox" helper |
|
21 | 24 |
$app->helper(check_box => |
22 | 25 |
sub { _input(shift, shift, value => shift, @_, type => 'checkbox') }); |
23 |
- |
|
24 |
- # Add "file_field" helper |
|
25 | 26 |
$app->helper(file_field => |
26 | 27 |
sub { shift; _tag('input', name => shift, @_, type => 'file') }); |
27 | 28 |
|
28 |
- # Add "form_for" helper |
|
29 |
- $app->helper(form_for => \&_form_for); |
|
30 |
- |
|
31 |
- # Add "hidden_field" helper |
|
29 |
+ $app->helper(form_for => \&_form_for); |
|
32 | 30 |
$app->helper(hidden_field => \&_hidden_field); |
33 |
- |
|
34 |
- # Add "image" helper |
|
35 | 31 |
$app->helper(image => sub { _tag('img', src => shift->url_for(shift), @_) }); |
36 |
- |
|
37 |
- # Add "input_tag" helper |
|
38 | 32 |
$app->helper(input_tag => sub { _input(@_) }); |
39 |
- |
|
40 |
- # Add "javascript" helper |
|
41 | 33 |
$app->helper(javascript => \&_javascript); |
34 |
+ $app->helper(link_to => \&_link_to); |
|
42 | 35 |
|
43 |
- # Add "link_to" helper |
|
44 |
- $app->helper(link_to => \&_link_to); |
|
45 |
- |
|
46 |
- # Add "password_field" helper |
|
47 | 36 |
$app->helper(password_field => |
48 | 37 |
sub { shift; _tag('input', name => shift, @_, type => 'password') }); |
49 |
- |
|
50 |
- # Add "radio_button" helper |
|
51 | 38 |
$app->helper(radio_button => |
52 | 39 |
sub { _input(shift, shift, value => shift, @_, type => 'radio') }); |
53 | 40 |
|
54 |
- # Add "select_field" helper |
|
55 |
- $app->helper(select_field => \&_select_field); |
|
56 |
- |
|
57 |
- # Add "stylesheet" helper |
|
58 |
- $app->helper(stylesheet => \&_stylesheet); |
|
59 |
- |
|
60 |
- # Add "submit_button" helper |
|
41 |
+ $app->helper(select_field => \&_select_field); |
|
42 |
+ $app->helper(stylesheet => \&_stylesheet); |
|
61 | 43 |
$app->helper(submit_button => \&_submit_button); |
62 | 44 |
|
63 |
- # Add "t" and "tag" helpers |
|
45 |
+ # "t" is just a shortcut for the "tag" helper |
|
64 | 46 |
$app->helper($_ => sub { shift; _tag(@_) }) for qw(t tag); |
65 | 47 |
|
66 |
- # Add "text_area" helper |
|
67 | 48 |
$app->helper(text_area => \&_text_area); |
68 | 49 |
} |
69 | 50 |
|
... | ... |
@@ -93,14 +74,10 @@ sub _hidden_field { |
93 | 74 |
|
94 | 75 |
sub _input { |
95 | 76 |
my ($self, $name) = (shift, shift); |
96 |
- |
|
97 |
- # Attributes |
|
98 | 77 |
my %attrs = @_ % 2 ? (value => shift, @_) : @_; |
99 | 78 |
|
100 |
- # Values |
|
101 |
- my @values = $self->param($name); |
|
102 |
- |
|
103 | 79 |
# Special selection value |
80 |
+ my @values = $self->param($name); |
|
104 | 81 |
my $type = $attrs{type} || ''; |
105 | 82 |
if (@values && $type ne 'submit') { |
106 | 83 |
|
... | ... |
@@ -206,10 +183,8 @@ sub _stylesheet { |
206 | 183 |
$cb = sub { "/*<![CDATA[*/\n" . $old->() . "\n/*]]>*/" } |
207 | 184 |
} |
208 | 185 |
|
209 |
- # URL |
|
210 |
- my $href = @_ % 2 ? $self->url_for(shift) : undef; |
|
211 |
- |
|
212 | 186 |
# "link" or "style" tag |
187 |
+ my $href = @_ % 2 ? $self->url_for(shift) : undef; |
|
213 | 188 |
return $href |
214 | 189 |
? _tag('link', rel => 'stylesheet', href => $href, media => 'screen', @_) |
215 | 190 |
: _tag('style', @_, $cb); |
... | ... |
@@ -299,15 +274,7 @@ example for learning how to build new plugins, you're welcome to fork it. |
299 | 274 |
|
300 | 275 |
L<Mojolicious::Plugin::TagHelpers> implements the following helpers. |
301 | 276 |
|
302 |
-=head2 C<base_tag> |
|
303 |
- |
|
304 |
- %= base_tag |
|
305 |
- |
|
306 |
-Generate portable C<base> tag refering to the current base URL. |
|
307 |
- |
|
308 |
- <base href="http://localhost/cgi-bin/myapp.pl" /> |
|
309 |
- |
|
310 |
-=head2 C<check_box> |
|
277 |
+=head2 check_box |
|
311 | 278 |
|
312 | 279 |
%= check_box employed => 1 |
313 | 280 |
%= check_box employed => 1, id => 'foo' |
... | ... |
@@ -318,7 +285,7 @@ picked up and shown as default. |
318 | 285 |
<input name="employed" type="checkbox" value="1" /> |
319 | 286 |
<input id="foo" name="employed" type="checkbox" value="1" /> |
320 | 287 |
|
321 |
-=head2 C<color_field> |
|
288 |
+=head2 color_field |
|
322 | 289 |
|
323 | 290 |
%= color_field 'background' |
324 | 291 |
%= color_field background => '#ffffff' |
... | ... |
@@ -331,7 +298,7 @@ picked up and shown as default. |
331 | 298 |
<input name="background" type="color" value="#ffffff" /> |
332 | 299 |
<input id="foo" name="background" type="color" value="#ffffff" /> |
333 | 300 |
|
334 |
-=head2 C<date_field> |
|
301 |
+=head2 date_field |
|
335 | 302 |
|
336 | 303 |
%= date_field 'end' |
337 | 304 |
%= date_field end => '2012-12-21' |
... | ... |
@@ -344,7 +311,7 @@ picked up and shown as default. |
344 | 311 |
<input name="end" type="date" value="2012-12-21" /> |
345 | 312 |
<input id="foo" name="end" type="date" value="2012-12-21" /> |
346 | 313 |
|
347 |
-=head2 C<datetime_field> |
|
314 |
+=head2 datetime_field |
|
348 | 315 |
|
349 | 316 |
%= datetime_field 'end' |
350 | 317 |
%= datetime_field end => '2012-12-21T23:59:59Z' |
... | ... |
@@ -357,7 +324,7 @@ picked up and shown as default. |
357 | 324 |
<input name="end" type="datetime" value="2012-12-21T23:59:59Z" /> |
358 | 325 |
<input id="foo" name="end" type="datetime" value="2012-12-21T23:59:59Z" /> |
359 | 326 |
|
360 |
-=head2 C<email_field> |
|
327 |
+=head2 email_field |
|
361 | 328 |
|
362 | 329 |
%= email_field 'notify' |
363 | 330 |
%= email_field notify => 'nospam@example.com' |
... | ... |
@@ -370,7 +337,7 @@ picked up and shown as default. |
370 | 337 |
<input name="notify" type="email" value="nospam@example.com" /> |
371 | 338 |
<input id="foo" name="notify" type="email" value="nospam@example.com" /> |
372 | 339 |
|
373 |
-=head2 C<file_field> |
|
340 |
+=head2 file_field |
|
374 | 341 |
|
375 | 342 |
%= file_field 'avatar' |
376 | 343 |
%= file_field 'avatar', id => 'foo' |
... | ... |
@@ -380,7 +347,7 @@ Generate file input element. |
380 | 347 |
<input name="avatar" type="file" /> |
381 | 348 |
<input id="foo" name="avatar" type="file" /> |
382 | 349 |
|
383 |
-=head2 C<form_for> |
|
350 |
+=head2 form_for |
|
384 | 351 |
|
385 | 352 |
%= form_for login => begin |
386 | 353 |
%= text_field 'first_name' |
... | ... |
@@ -419,7 +386,7 @@ but not C<GET>, a C<method> attribute will be automatically added. |
419 | 386 |
<input value="Ok" type="submit" /> |
420 | 387 |
</form> |
421 | 388 |
|
422 |
-=head2 C<hidden_field> |
|
389 |
+=head2 hidden_field |
|
423 | 390 |
|
424 | 391 |
%= hidden_field foo => 'bar' |
425 | 392 |
%= hidden_field foo => 'bar', id => 'bar' |
... | ... |
@@ -429,7 +396,7 @@ Generate hidden input element. |
429 | 396 |
<input name="foo" type="hidden" value="bar" /> |
430 | 397 |
<input id="bar" name="foo" type="hidden" value="bar" /> |
431 | 398 |
|
432 |
-=head2 C<image> |
|
399 |
+=head2 image |
|
433 | 400 |
|
434 | 401 |
%= image '/images/foo.png' |
435 | 402 |
%= image '/images/foo.png', alt => 'Foo' |
... | ... |
@@ -439,7 +406,7 @@ Generate image tag. |
439 | 406 |
<img src="/images/foo.png" /> |
440 | 407 |
<img alt="Foo" src="/images/foo.png" /> |
441 | 408 |
|
442 |
-=head2 C<input_tag> |
|
409 |
+=head2 input_tag |
|
443 | 410 |
|
444 | 411 |
%= input_tag 'first_name' |
445 | 412 |
%= input_tag first_name => 'Default name' |
... | ... |
@@ -452,7 +419,7 @@ picked up and shown as default. |
452 | 419 |
<input name="first_name" value="Default name" /> |
453 | 420 |
<input name="employed" type="checkbox" /> |
454 | 421 |
|
455 |
-=head2 C<javascript> |
|
422 |
+=head2 javascript |
|
456 | 423 |
|
457 | 424 |
%= javascript '/script.js' |
458 | 425 |
%= javascript begin |
... | ... |
@@ -466,7 +433,7 @@ Generate portable script tag for C<Javascript> asset. |
466 | 433 |
var a = 'b'; |
467 | 434 |
]]></script> |
468 | 435 |
|
469 |
-=head2 C<link_to> |
|
436 |
+=head2 link_to |
|
470 | 437 |
|
471 | 438 |
%= link_to Home => 'index' |
472 | 439 |
%= link_to Home => 'index' => {format => 'txt'} => (class => 'links') |
... | ... |
@@ -491,7 +458,7 @@ capitalized link target as content. |
491 | 458 |
<a href="http://mojolicio.us">Mojolicious</a> |
492 | 459 |
<a href="http://127.0.0.1:3000/current/path?foo=bar">Retry</a> |
493 | 460 |
|
494 |
-=head2 C<month_field> |
|
461 |
+=head2 month_field |
|
495 | 462 |
|
496 | 463 |
%= month_field 'vacation' |
497 | 464 |
%= month_field vacation => '2012-12' |
... | ... |
@@ -504,7 +471,7 @@ picked up and shown as default. |
504 | 471 |
<input name="vacation" type="month" value="2012-12" /> |
505 | 472 |
<input id="foo" name="vacation" type="month" value="2012-12" /> |
506 | 473 |
|
507 |
-=head2 C<number_field> |
|
474 |
+=head2 number_field |
|
508 | 475 |
|
509 | 476 |
%= number_field 'age' |
510 | 477 |
%= number_field age => 25 |
... | ... |
@@ -517,7 +484,7 @@ picked up and shown as default. |
517 | 484 |
<input name="age" type="number" value="25" /> |
518 | 485 |
<input id="foo" max="200" min="0" name="age" type="number" value="25" /> |
519 | 486 |
|
520 |
-=head2 C<password_field> |
|
487 |
+=head2 password_field |
|
521 | 488 |
|
522 | 489 |
%= password_field 'pass' |
523 | 490 |
%= password_field 'pass', id => 'foo' |
... | ... |
@@ -527,7 +494,7 @@ Generate password input element. |
527 | 494 |
<input name="pass" type="password" /> |
528 | 495 |
<input id="foo" name="pass" type="password" /> |
529 | 496 |
|
530 |
-=head2 C<radio_button> |
|
497 |
+=head2 radio_button |
|
531 | 498 |
|
532 | 499 |
%= radio_button country => 'germany' |
533 | 500 |
%= radio_button country => 'germany', id => 'foo' |
... | ... |
@@ -538,7 +505,7 @@ picked up and shown as default. |
538 | 505 |
<input name="country" type="radio" value="germany" /> |
539 | 506 |
<input id="foo" name="country" type="radio" value="germany" /> |
540 | 507 |
|
541 |
-=head2 C<range_field> |
|
508 |
+=head2 range_field |
|
542 | 509 |
|
543 | 510 |
%= range_field 'age' |
544 | 511 |
%= range_field age => 25 |
... | ... |
@@ -551,7 +518,7 @@ picked up and shown as default. |
551 | 518 |
<input name="age" type="range" value="25" /> |
552 | 519 |
<input id="foo" max="200" min="200" name="age" type="range" value="25" /> |
553 | 520 |
|
554 |
-=head2 C<search_field> |
|
521 |
+=head2 search_field |
|
555 | 522 |
|
556 | 523 |
%= search_field 'q' |
557 | 524 |
%= search_field q => 'perl' |
... | ... |
@@ -564,7 +531,7 @@ picked up and shown as default. |
564 | 531 |
<input name="q" type="search" value="perl" /> |
565 | 532 |
<input id="foo" name="q" type="search" value="perl" /> |
566 | 533 |
|
567 |
-=head2 C<select_field> |
|
534 |
+=head2 select_field |
|
568 | 535 |
|
569 | 536 |
%= select_field language => [qw(de en)] |
570 | 537 |
%= select_field language => [qw(de en)], id => 'lang' |
... | ... |
@@ -598,7 +565,7 @@ automatically get picked up and shown as default. |
598 | 565 |
<option value="en">en</option> |
599 | 566 |
</select> |
600 | 567 |
|
601 |
-=head2 C<stylesheet> |
|
568 |
+=head2 stylesheet |
|
602 | 569 |
|
603 | 570 |
%= stylesheet '/foo.css' |
604 | 571 |
%= stylesheet begin |
... | ... |
@@ -612,7 +579,7 @@ Generate portable style or link tag for C<CSS> asset. |
612 | 579 |
body {color: #000} |
613 | 580 |
]]></style> |
614 | 581 |
|
615 |
-=head2 C<submit_button> |
|
582 |
+=head2 submit_button |
|
616 | 583 |
|
617 | 584 |
%= submit_button |
618 | 585 |
%= submit_button 'Ok!', id => 'foo' |
... | ... |
@@ -622,7 +589,7 @@ Generate submit input element. |
622 | 589 |
<input type="submit" value="Ok" /> |
623 | 590 |
<input id="foo" type="submit" value="Ok!" /> |
624 | 591 |
|
625 |
-=head2 C<t> |
|
592 |
+=head2 t |
|
626 | 593 |
|
627 | 594 |
%=t div => 'some & content' |
628 | 595 |
|
... | ... |
@@ -630,7 +597,7 @@ Alias for C<tag>. |
630 | 597 |
|
631 | 598 |
<div>some & content</div> |
632 | 599 |
|
633 |
-=head2 C<tag> |
|
600 |
+=head2 tag |
|
634 | 601 |
|
635 | 602 |
%= tag 'div' |
636 | 603 |
%= tag 'div', id => 'foo' |
... | ... |
@@ -653,7 +620,7 @@ Very useful for reuse in more specific tag helpers. |
653 | 620 |
Results are automatically wrapped in L<Mojo::ByteStream> objects to prevent |
654 | 621 |
accidental double escaping. |
655 | 622 |
|
656 |
-=head2 C<tel_field> |
|
623 |
+=head2 tel_field |
|
657 | 624 |
|
658 | 625 |
%= tel_field 'work' |
659 | 626 |
%= tel_field work => '123456789' |
... | ... |
@@ -666,7 +633,7 @@ picked up and shown as default. |
666 | 633 |
<input name="work" type="tel" value="123456789" /> |
667 | 634 |
<input id="foo" name="work" type="tel" value="123456789" /> |
668 | 635 |
|
669 |
-=head2 C<text_area> |
|
636 |
+=head2 text_area |
|
670 | 637 |
|
671 | 638 |
%= text_area 'foo' |
672 | 639 |
%= text_area 'foo', cols => 40 |
... | ... |
@@ -685,7 +652,7 @@ up and shown as default. |
685 | 652 |
Default! |
686 | 653 |
</textarea> |
687 | 654 |
|
688 |
-=head2 C<text_field> |
|
655 |
+=head2 text_field |
|
689 | 656 |
|
690 | 657 |
%= text_field 'first_name' |
691 | 658 |
%= text_field first_name => 'Default name' |
... | ... |
@@ -698,7 +665,7 @@ picked up and shown as default. |
698 | 665 |
<input name="first_name" type="text" value="Default name" /> |
699 | 666 |
<input class="user" name="first_name" type="text" value="Default name" /> |
700 | 667 |
|
701 |
-=head2 C<time_field> |
|
668 |
+=head2 time_field |
|
702 | 669 |
|
703 | 670 |
%= time_field 'start' |
704 | 671 |
%= time_field start => '23:59:59' |
... | ... |
@@ -711,7 +678,7 @@ picked up and shown as default. |
711 | 678 |
<input name="start" type="time" value="23:59:59" /> |
712 | 679 |
<input id="foo" name="start" type="time" value="23:59:59" /> |
713 | 680 |
|
714 |
-=head2 C<url_field> |
|
681 |
+=head2 url_field |
|
715 | 682 |
|
716 | 683 |
%= url_field 'address' |
717 | 684 |
%= url_field address => 'http://mojolicio.us' |
... | ... |
@@ -724,7 +691,7 @@ picked up and shown as default. |
724 | 691 |
<input name="address" type="url" value="http://mojolicio.us" /> |
725 | 692 |
<input id="foo" name="address" type="url" value="http://mojolicio.us" /> |
726 | 693 |
|
727 |
-=head2 C<week_field> |
|
694 |
+=head2 week_field |
|
728 | 695 |
|
729 | 696 |
%= week_field 'vacation' |
730 | 697 |
%= week_field vacation => '2012-W17' |
... | ... |
@@ -742,7 +709,7 @@ picked up and shown as default. |
742 | 709 |
L<Mojolicious::Plugin::TagHelpers> inherits all methods from |
743 | 710 |
L<Mojolicious::Plugin> and implements the following new ones. |
744 | 711 |
|
745 |
-=head2 C<register> |
|
712 |
+=head2 register |
|
746 | 713 |
|
747 | 714 |
$plugin->register(Mojolicious->new); |
748 | 715 |
|
... | ... |
@@ -37,11 +37,11 @@ sub load_plugin { |
37 | 37 |
my $class = $name =~ /^[a-z]/ ? camelize($name) : $name; |
38 | 38 |
for my $namespace (@{$self->namespaces}) { |
39 | 39 |
my $module = "${namespace}::$class"; |
40 |
- return $module->new if $self->_load($module); |
|
40 |
+ return $module->new if _load($module); |
|
41 | 41 |
} |
42 | 42 |
|
43 | 43 |
# Full module name |
44 |
- return $name->new if $self->_load($name); |
|
44 |
+ return $name->new if _load($name); |
|
45 | 45 |
|
46 | 46 |
# Not found |
47 | 47 |
die qq{Plugin "$name" missing, maybe you need to install it?\n}; |
... | ... |
@@ -52,14 +52,10 @@ sub register_plugin { |
52 | 52 |
} |
53 | 53 |
|
54 | 54 |
sub _load { |
55 |
- my ($self, $module) = @_; |
|
56 |
- |
|
57 |
- # Load |
|
55 |
+ my $module = shift; |
|
58 | 56 |
if (my $e = Mojo::Loader->new->load($module)) { |
59 | 57 |
ref $e ? die $e : return undef; |
60 | 58 |
} |
61 |
- |
|
62 |
- # Module is a plugin |
|
63 | 59 |
return $module->isa('Mojolicious::Plugin') ? 1 : undef; |
64 | 60 |
} |
65 | 61 |
|
... | ... |
@@ -80,11 +76,74 @@ Mojolicious::Plugins - Plugin manager |
80 | 76 |
|
81 | 77 |
L<Mojolicious::Plugins> is the plugin manager of L<Mojolicious>. |
82 | 78 |
|
79 |
+=head1 PLUGINS |
|
80 |
+ |
|
81 |
+The following plugins are included in the L<Mojolicious> distribution as |
|
82 |
+examples. |
|
83 |
+ |
|
84 |
+=over 2 |
|
85 |
+ |
|
86 |
+=item L<Mojolicious::Plugin::Charset> |
|
87 |
+ |
|
88 |
+Change the application charset. |
|
89 |
+ |
|
90 |
+=item L<Mojolicious::Plugin::Config> |
|
91 |
+ |
|
92 |
+Perl-ish configuration files. |
|
93 |
+ |
|
94 |
+=item L<Mojolicious::Plugin::DefaultHelpers> |
|
95 |
+ |
|
96 |
+General purpose helper collection, loaded automatically. |
|
97 |
+ |
|
98 |
+=item L<Mojolicious::Plugin::EPLRenderer> |
|
99 |
+ |
|
100 |
+Renderer for plain embedded Perl templates, loaded automatically. |
|
101 |
+ |
|
102 |
+=item L<Mojolicious::Plugin::EPRenderer> |
|
103 |
+ |
|
104 |
+Renderer for more sophisiticated embedded Perl templates, loaded |
|
105 |
+automatically. |
|
106 |
+ |
|
107 |
+=item L<Mojolicious::Plugin::HeaderCondition> |
|
108 |
+ |
|
109 |
+Route condition for all kinds of headers, loaded automatically. |
|
110 |
+ |
|
111 |
+=item L<Mojolicious::Plugin::JSONConfig> |
|
112 |
+ |
|
113 |
+JSON configuration files. |
|
114 |
+ |
|
115 |
+=item L<Mojolicious::Plugin::Mount> |
|
116 |
+ |
|
117 |
+Mount whole L<Mojolicious> applications. |
|
118 |
+ |
|
119 |
+=item L<Mojolicious::Plugin::PODRenderer> |
|
120 |
+ |
|
121 |
+Renderer for turning POD into HTML and documentation browser for |
|
122 |
+L<Mojolicious::Guides>. |
|
123 |
+ |
|
124 |
+=item L<Mojolicious::Plugin::PoweredBy> |
|
125 |
+ |
|
126 |
+Add an C<X-Powered-By> header to outgoing responses, loaded automatically. |
|
127 |
+ |
|
128 |
+=item L<Mojolicious::Plugin::RequestTimer> |
|
129 |
+ |
|
130 |
+Log timing information, loaded automatically. |
|
131 |
+ |
|
132 |
+=item L<Mojolicious::Plugin::TagHelpers> |
|
133 |
+ |
|
134 |
+Template specific helper collection, loaded automatically. |
|
135 |
+ |
|
136 |
+=back |
|
137 |
+ |
|
138 |
+=head1 EVENTS |
|
139 |
+ |
|
140 |
+L<Mojolicious::Plugins> inherits all events from L<Mojo::EventEmitter>. |
|
141 |
+ |
|
83 | 142 |
=head1 ATTRIBUTES |
84 | 143 |
|
85 | 144 |
L<Mojolicious::Plugins> implements the following attributes. |
86 | 145 |
|
87 |
-=head2 C<namespaces> |
|
146 |
+=head2 namespaces |
|
88 | 147 |
|
89 | 148 |
my $namespaces = $plugins->namespaces; |
90 | 149 |
$plugins = $plugins->namespaces(['Mojolicious::Plugin']); |
... | ... |
@@ -99,28 +158,28 @@ Namespaces to load plugins from, defaults to L<Mojolicious::Plugin>. |
99 | 158 |
L<Mojolicious::Plugins> inherits all methods from L<Mojo::EventEmitter> and |
100 | 159 |
implements the following new ones. |
101 | 160 |
|
102 |
-=head2 C<emit_chain> |
|
161 |
+=head2 emit_chain |
|
103 | 162 |
|
104 | 163 |
$plugins = $plugins->emit_chain('foo'); |
105 | 164 |
$plugins = $plugins->emit_chain(foo => 123); |
106 | 165 |
|
107 | 166 |
Emit events as chained hooks. |
108 | 167 |
|
109 |
-=head2 C<emit_hook> |
|
168 |
+=head2 emit_hook |
|
110 | 169 |
|
111 | 170 |
$plugins = $plugins->emit_hook('foo'); |
112 | 171 |
$plugins = $plugins->emit_hook(foo => 123); |
113 | 172 |
|
114 | 173 |
Emit events as hooks. |
115 | 174 |
|
116 |
-=head2 C<emit_hook_reverse> |
|
175 |
+=head2 emit_hook_reverse |
|
117 | 176 |
|
118 | 177 |
$plugins = $plugins->emit_hook_reverse('foo'); |
119 | 178 |
$plugins = $plugins->emit_hook_reverse(foo => 123); |
120 | 179 |
|
121 | 180 |
Emit events as hooks in reverse order. |
122 | 181 |
|
123 |
-=head2 C<load_plugin> |
|
182 |
+=head2 load_plugin |
|
124 | 183 |
|
125 | 184 |
my $plugin = $plugins->load_plugin('some_thing'); |
126 | 185 |
my $plugin = $plugins->load_plugin('SomeThing'); |
... | ... |
@@ -128,7 +187,7 @@ Emit events as hooks in reverse order. |
128 | 187 |
|
129 | 188 |
Load a plugin from the configured namespaces or by full module name. |
130 | 189 |
|
131 |
-=head2 C<register_plugin> |
|
190 |
+=head2 register_plugin |
|
132 | 191 |
|
133 | 192 |
$plugins->register_plugin('some_thing', Mojolicious->new); |
134 | 193 |
$plugins->register_plugin('some_thing', Mojolicious->new, foo => 23); |
... | ... |
@@ -6,7 +6,7 @@ use Mojo::Cache; |
6 | 6 |
use Mojo::JSON; |
7 | 7 |
use Mojo::Home; |
8 | 8 |
use Mojo::Loader; |
9 |
-use Mojo::Util 'encode'; |
|
9 |
+use Mojo::Util qw(encode slurp); |
|
10 | 10 |
|
11 | 11 |
has cache => sub { Mojo::Cache->new }; |
12 | 12 |
has classes => sub { ['main'] }; |
... | ... |
@@ -20,25 +20,22 @@ has paths => sub { [] }; |
20 | 20 |
my $HOME = Mojo::Home->new; |
21 | 21 |
$HOME->parse( |
22 | 22 |
$HOME->parse($HOME->mojo_lib_dir)->rel_dir('Mojolicious/templates')); |
23 |
-my %TEMPLATES = map { $_ => $HOME->slurp_rel_file($_) } @{$HOME->list_files}; |
|
23 |
+my %TEMPLATES = map { $_ => slurp $HOME->rel_file($_) } @{$HOME->list_files}; |
|
24 | 24 |
|
25 | 25 |
sub new { |
26 |
- my $self = shift->SUPER::new(@_)->add_handler(json => \&_json); |
|
27 |
- return $self->add_handler(data => \&_data)->add_handler(text => \&_text); |
|
28 |
-} |
|
26 |
+ my $self = shift->SUPER::new(@_); |
|
29 | 27 |
|
30 |
-sub add_handler { |
|
31 |
- my ($self, $name, $cb) = @_; |
|
32 |
- $self->handlers->{$name} = $cb; |
|
33 |
- return $self; |
|
34 |
-} |
|
28 |
+ $self->add_handler( |
|
29 |
+ json => sub { ${$_[2]} = Mojo::JSON->new->encode($_[3]->{json}) }); |
|
30 |
+ $self->add_handler(data => sub { ${$_[2]} = $_[3]->{data} }); |
|
31 |
+ $self->add_handler(text => sub { ${$_[2]} = $_[3]->{text} }); |
|
35 | 32 |
|
36 |
-sub add_helper { |
|
37 |
- my ($self, $name, $cb) = @_; |
|
38 |
- $self->helpers->{$name} = $cb; |
|
39 | 33 |
return $self; |
40 | 34 |
} |
41 | 35 |
|
36 |
+sub add_handler { shift->_add(handlers => @_) } |
|
37 |
+sub add_helper { shift->_add(helpers => @_) } |
|
38 |
+ |
|
42 | 39 |
sub get_data_template { |
43 | 40 |
my ($self, $options) = @_; |
44 | 41 |
|
... | ... |
@@ -131,7 +128,7 @@ sub render { |
131 | 128 |
if !$partial && $options->{encoding} && $output; |
132 | 129 |
} |
133 | 130 |
|
134 |
- return $output, $c->app->types->type($format) || 'text/plain'; |
|
131 |
+ return $output, $format; |
|
135 | 132 |
} |
136 | 133 |
|
137 | 134 |
sub template_name { |
... | ... |
@@ -158,13 +155,14 @@ sub template_path { |
158 | 155 |
return catfile($self->paths->[0], split '/', $name); |
159 | 156 |
} |
160 | 157 |
|
161 |
-sub _bundled { $TEMPLATES{"@{[pop]}.html.ep"} } |
|
162 |
- |
|
163 |
-sub _data { |
|
164 |
- my ($self, $c, $output, $options) = @_; |
|
165 |
- $$output = $options->{data}; |
|
158 |
+sub _add { |
|
159 |
+ my ($self, $attr, $name, $cb) = @_; |
|
160 |
+ $self->$attr->{$name} = $cb; |
|
161 |
+ return $self; |
|
166 | 162 |
} |
167 | 163 |
|
164 |
+sub _bundled { $TEMPLATES{"@{[pop]}.html.ep"} } |
|
165 |
+ |
|
168 | 166 |
sub _detect_handler { |
169 | 167 |
my ($self, $options) = @_; |
170 | 168 |
|
... | ... |
@@ -196,11 +194,6 @@ sub _extends { |
196 | 194 |
return delete $stash->{extends}; |
197 | 195 |
} |
198 | 196 |
|
199 |
-sub _json { |
|
200 |
- my ($self, $c, $output, $options) = @_; |
|
201 |
- $$output = Mojo::JSON->new->encode($options->{json}); |
|
202 |
-} |
|
203 |
- |
|
204 | 197 |
sub _render_template { |
205 | 198 |
my ($self, $c, $output, $options) = @_; |
206 | 199 |
|
... | ... |
@@ -216,16 +209,11 @@ sub _render_template { |
216 | 209 |
return undef; |
217 | 210 |
} |
218 | 211 |
|
219 |
-sub _text { |
|
220 |
- my ($self, $c, $output, $options) = @_; |
|
221 |
- $$output = $options->{text}; |
|
222 |
-} |
|
223 |
- |
|
224 | 212 |
1; |
225 | 213 |
|
226 | 214 |
=head1 NAME |
227 | 215 |
|
228 |
-Mojolicious::Renderer - MIME type based renderer |
|
216 |
+Mojolicious::Renderer - Generate dynamic content |
|
229 | 217 |
|
230 | 218 |
=head1 SYNOPSIS |
231 | 219 |
|
... | ... |
@@ -245,14 +233,14 @@ See L<Mojolicious::Guides::Rendering> for more. |
245 | 233 |
|
246 | 234 |
L<Mojolicious::Renderer> implements the following attributes. |
247 | 235 |
|
248 |
-=head2 C<cache> |
|
236 |
+=head2 cache |
|
249 | 237 |
|
250 | 238 |
my $cache = $renderer->cache; |
251 | 239 |
$renderer = $renderer->cache(Mojo::Cache->new); |
252 | 240 |
|
253 | 241 |
Renderer cache, defaults to a L<Mojo::Cache> object. |
254 | 242 |
|
255 |
-=head2 C<classes> |
|
243 |
+=head2 classes |
|
256 | 244 |
|
257 | 245 |
my $classes = $renderer->classes; |
258 | 246 |
$renderer = $renderer->classes(['main']); |
... | ... |
@@ -263,15 +251,14 @@ highest precedence, defaults to C<main>. |
263 | 251 |
# Add another class with templates in DATA section |
264 | 252 |
push @{$renderer->classes}, 'Mojolicious::Plugin::Fun'; |
265 | 253 |
|
266 |
-=head2 C<default_format> |
|
254 |
+=head2 default_format |
|
267 | 255 |
|
268 | 256 |
my $default = $renderer->default_format; |
269 | 257 |
$renderer = $renderer->default_format('html'); |
270 | 258 |
|
271 |
-The default format to render if C<format> is not set in the stash. The |
|
272 |
-renderer will use L<Mojolicious/"types"> to look up the content MIME type. |
|
259 |
+The default format to render if C<format> is not set in the stash. |
|
273 | 260 |
|
274 |
-=head2 C<default_handler> |
|
261 |
+=head2 default_handler |
|
275 | 262 |
|
276 | 263 |
my $default = $renderer->default_handler; |
277 | 264 |
$renderer = $renderer->default_handler('ep'); |
... | ... |
@@ -279,28 +266,28 @@ renderer will use L<Mojolicious/"types"> to look up the content MIME type. |
279 | 266 |
The default template handler to use for rendering in cases where auto |
280 | 267 |
detection doesn't work, like for C<inline> templates. |
281 | 268 |
|
282 |
-=head2 C<encoding> |
|
269 |
+=head2 encoding |
|
283 | 270 |
|
284 | 271 |
my $encoding = $renderer->encoding; |
285 | 272 |
$renderer = $renderer->encoding('koi8-r'); |
286 | 273 |
|
287 | 274 |
Will encode the content if set, defaults to C<UTF-8>. |
288 | 275 |
|
289 |
-=head2 C<handlers> |
|
276 |
+=head2 handlers |
|
290 | 277 |
|
291 | 278 |
my $handlers = $renderer->handlers; |
292 | 279 |
$renderer = $renderer->handlers({epl => sub {...}}); |
293 | 280 |
|
294 | 281 |
Registered handlers. |
295 | 282 |
|
296 |
-=head2 C<helpers> |
|
283 |
+=head2 helpers |
|
297 | 284 |
|
298 | 285 |
my $helpers = $renderer->helpers; |
299 | 286 |
$renderer = $renderer->helpers({url_for => sub {...}}); |
300 | 287 |
|
301 | 288 |
Registered helpers. |
302 | 289 |
|
303 |
-=head2 C<paths> |
|
290 |
+=head2 paths |
|
304 | 291 |
|
305 | 292 |
my $paths = $renderer->paths; |
306 | 293 |
$renderer = $renderer->paths(['/home/sri/templates']); |
... | ... |
@@ -313,28 +300,28 @@ Directories to look for templates in, first one has the highest precedence. |
313 | 300 |
=head1 METHODS |
314 | 301 |
|
315 | 302 |
L<Mojolicious::Renderer> inherits all methods from L<Mojo::Base> and |
316 |
-implements the following ones. |
|
303 |
+implements the following new ones. |
|
317 | 304 |
|
318 |
-=head2 C<new> |
|
305 |
+=head2 new |
|
319 | 306 |
|
320 | 307 |
my $renderer = Mojolicious::Renderer->new; |
321 | 308 |
|
322 | 309 |
Construct a new renderer and register C<data>, C<json> as well as C<text> |
323 | 310 |
handlers. |
324 | 311 |
|
325 |
-=head2 C<add_handler> |
|
312 |
+=head2 add_handler |
|
326 | 313 |
|
327 | 314 |
$renderer = $renderer->add_handler(epl => sub {...}); |
328 | 315 |
|
329 | 316 |
Register a new handler. |
330 | 317 |
|
331 |
-=head2 C<add_helper> |
|
318 |
+=head2 add_helper |
|
332 | 319 |
|
333 | 320 |
$renderer = $renderer->add_helper(url_for => sub {...}); |
334 | 321 |
|
335 | 322 |
Register a new helper. |
336 | 323 |
|
337 |
-=head2 C<get_data_template> |
|
324 |
+=head2 get_data_template |
|
338 | 325 |
|
339 | 326 |
my $template = $renderer->get_data_template({ |
340 | 327 |
template => 'foo/bar', |
... | ... |
@@ -344,20 +331,18 @@ Register a new helper. |
344 | 331 |
|
345 | 332 |
Get a C<DATA> section template by name, usually used by handlers. |
346 | 333 |
|
347 |
-=head2 C<render> |
|
334 |
+=head2 render |
|
348 | 335 |
|
349 |
- my ($output, $type) = $renderer->render(Mojolicious::Controller->new); |
|
350 |
- my ($output, $type) = $renderer->render(Mojolicious::Controller->new, { |
|
336 |
+ my ($output, $format) = $renderer->render(Mojolicious::Controller->new); |
|
337 |
+ my ($output, $format) = $renderer->render(Mojolicious::Controller->new, { |
|
351 | 338 |
template => 'foo/bar', |
352 | 339 |
foo => 'bar' |
353 | 340 |
}); |
354 | 341 |
|
355 |
-Render output through one of the Mojo renderers. This renderer requires some |
|
356 |
-configuration, at the very least you will need to have a default C<format> and |
|
357 |
-a default C<handler> as well as a C<template> or C<text>/C<json>. See |
|
342 |
+Render output through one of the renderers. See |
|
358 | 343 |
L<Mojolicious::Controller/"render"> for a more user-friendly interface. |
359 | 344 |
|
360 |
-=head2 C<template_name> |
|
345 |
+=head2 template_name |
|
361 | 346 |
|
362 | 347 |
my $template = $renderer->template_name({ |
363 | 348 |
template => 'foo/bar', |
... | ... |
@@ -368,7 +353,7 @@ L<Mojolicious::Controller/"render"> for a more user-friendly interface. |
368 | 353 |
Builds a template name based on an options hash reference with C<template>, |
369 | 354 |
C<format> and C<handler>, usually used by handlers. |
370 | 355 |
|
371 |
-=head2 C<template_path> |
|
356 |
+=head2 template_path |
|
372 | 357 |
|
373 | 358 |
my $path = $renderer->template_path({ |
374 | 359 |
template => 'foo/bar', |
... | ... |
@@ -14,17 +14,8 @@ has [qw(conditions shortcuts)] => sub { {} }; |
14 | 14 |
has hidden => sub { [qw(attr has new tap)] }; |
15 | 15 |
has namespaces => sub { [] }; |
16 | 16 |
|
17 |
-sub add_condition { |
|
18 |
- my ($self, $name, $cb) = @_; |
|
19 |
- $self->conditions->{$name} = $cb; |
|
20 |
- return $self; |
|
21 |
-} |
|
22 |
- |
|
23 |
-sub add_shortcut { |
|
24 |
- my ($self, $name, $cb) = @_; |
|
25 |
- $self->shortcuts->{$name} = $cb; |
|
26 |
- return $self; |
|
27 |
-} |
|
17 |
+sub add_condition { shift->_add(conditions => @_) } |
|
18 |
+sub add_shortcut { shift->_add(shortcuts => @_) } |
|
28 | 19 |
|
29 | 20 |
sub auto_render { |
30 | 21 |
my ($self, $c) = @_; |
... | ... |
@@ -40,7 +31,7 @@ sub dispatch { |
40 | 31 |
my $req = $c->req; |
41 | 32 |
my $path = $c->stash->{path}; |
42 | 33 |
if (defined $path) { $path = "/$path" if $path !~ m!^/! } |
43 |
- else { $path = $req->url->path->to_abs_string } |
|
34 |
+ else { $path = $req->url->path->to_route } |
|
44 | 35 |
|
45 | 36 |
# Prepare match |
46 | 37 |
my $method = $req->method; |
... | ... |
@@ -71,10 +62,8 @@ sub dispatch { |
71 | 62 |
} |
72 | 63 |
} |
73 | 64 |
|
74 |
- # No match |
|
75 |
- return undef unless $m && @{$m->stack}; |
|
76 |
- |
|
77 | 65 |
# Dispatch |
66 |
+ return undef unless $m && @{$m->stack}; |
|
78 | 67 |
return undef if $self->_walk($c); |
79 | 68 |
$self->auto_render($c); |
80 | 69 |
return 1; |
... | ... |
@@ -82,6 +71,14 @@ sub dispatch { |
82 | 71 |
|
83 | 72 |
sub hide { push @{shift->hidden}, @_ } |
84 | 73 |
|
74 |
+sub lookup { |
|
75 |
+ my ($self, $name) = @_; |
|
76 |
+ my $reverse = $self->{reverse} ||= {}; |
|
77 |
+ return $reverse->{$name} if exists $reverse->{$name}; |
|
78 |
+ return undef unless my $route = $self->find($name); |
|
79 |
+ return $reverse->{$name} = $route; |
|
80 |
+} |
|
81 |
+ |
|
85 | 82 |
# DEPRECATED in Rainbow! |
86 | 83 |
sub namespace { |
87 | 84 |
warn <<EOF; |
... | ... |
@@ -98,6 +95,12 @@ sub route { |
98 | 95 |
shift->add_child(Mojolicious::Routes::Route->new(@_))->children->[-1]; |
99 | 96 |
} |
100 | 97 |
|
98 |
+sub _add { |
|
99 |
+ my ($self, $attr, $name, $cb) = @_; |
|
100 |
+ $self->$attr->{$name} = $cb; |
|
101 |
+ return $self; |
|
102 |
+} |
|
103 |
+ |
|
101 | 104 |
sub _callback { |
102 | 105 |
my ($self, $c, $field, $staging) = @_; |
103 | 106 |
$c->stash->{'mojo.routed'}++; |
... | ... |
@@ -217,7 +220,6 @@ sub _method { |
217 | 220 |
sub _walk { |
218 | 221 |
my ($self, $c) = @_; |
219 | 222 |
|
220 |
- # Walk the stack |
|
221 | 223 |
my $stack = $c->match->stack; |
222 | 224 |
my $stash = $c->stash; |
223 | 225 |
my $staging = @$stack; |
... | ... |
@@ -296,7 +298,7 @@ See L<Mojolicious::Guides::Routing> for more. |
296 | 298 |
L<Mojolicious::Routes> inherits all attributes from |
297 | 299 |
L<Mojolicious::Routes::Route> and implements the following new ones. |
298 | 300 |
|
299 |
-=head2 C<base_classes> |
|
301 |
+=head2 base_classes |
|
300 | 302 |
|
301 | 303 |
my $classes = $r->base_classes; |
302 | 304 |
$r = $r->base_classes(['MyApp::Controller']); |
... | ... |
@@ -304,7 +306,7 @@ L<Mojolicious::Routes::Route> and implements the following new ones. |
304 | 306 |
Base classes used to identify controllers, defaults to |
305 | 307 |
L<Mojolicious::Controller> and L<Mojo>. |
306 | 308 |
|
307 |
-=head2 C<cache> |
|
309 |
+=head2 cache |
|
308 | 310 |
|
309 | 311 |
my $cache = $r->cache; |
310 | 312 |
$r = $r->cache(Mojo::Cache->new); |
... | ... |
@@ -314,14 +316,14 @@ Routing cache, defaults to a L<Mojo::Cache> object. |
314 | 316 |
# Disable caching |
315 | 317 |
$r->cache(0); |
316 | 318 |
|
317 |
-=head2 C<conditions> |
|
319 |
+=head2 conditions |
|
318 | 320 |
|
319 | 321 |
my $conditions = $r->conditions; |
320 | 322 |
$r = $r->conditions({foo => sub {...}}); |
321 | 323 |
|
322 | 324 |
Contains all available conditions. |
323 | 325 |
|
324 |
-=head2 C<hidden> |
|
326 |
+=head2 hidden |
|
325 | 327 |
|
326 | 328 |
my $hidden = $r->hidden; |
327 | 329 |
$r = $r->hidden([qw(attr has new)]); |
... | ... |
@@ -329,7 +331,7 @@ Contains all available conditions. |
329 | 331 |
Controller methods and attributes that are hidden from routes, defaults to |
330 | 332 |
C<attr>, C<has>, C<new> and C<tap>. |
331 | 333 |
|
332 |
-=head2 C<namespaces> |
|
334 |
+=head2 namespaces |
|
333 | 335 |
|
334 | 336 |
my $namespaces = $r->namespaces; |
335 | 337 |
$r = $r->namespaces(['Foo::Bar::Controller']); |
... | ... |
@@ -339,7 +341,7 @@ Namespaces to load controllers from. |
339 | 341 |
# Add another namespace to load controllers from |
340 | 342 |
push @{$r->namespaces}, 'MyApp::Controller'; |
341 | 343 |
|
342 |
-=head2 C<shortcuts> |
|
344 |
+=head2 shortcuts |
|
343 | 345 |
|
344 | 346 |
my $shortcuts = $r->shortcuts; |
345 | 347 |
$r = $r->shortcuts({foo => sub {...}}); |
... | ... |
@@ -349,39 +351,46 @@ Contains all available shortcuts. |
349 | 351 |
=head1 METHODS |
350 | 352 |
|
351 | 353 |
L<Mojolicious::Routes> inherits all methods from |
352 |
-L<Mojolicious::Routes::Route> and implements the following ones. |
|
354 |
+L<Mojolicious::Routes::Route> and implements the following new ones. |
|
353 | 355 |
|
354 |
-=head2 C<add_condition> |
|
356 |
+=head2 add_condition |
|
355 | 357 |
|
356 | 358 |
$r = $r->add_condition(foo => sub {...}); |
357 | 359 |
|
358 | 360 |
Add a new condition. |
359 | 361 |
|
360 |
-=head2 C<add_shortcut> |
|
362 |
+=head2 add_shortcut |
|
361 | 363 |
|
362 | 364 |
$r = $r->add_shortcut(foo => sub {...}); |
363 | 365 |
|
364 | 366 |
Add a new shortcut. |
365 | 367 |
|
366 |
-=head2 C<auto_render> |
|
368 |
+=head2 auto_render |
|
367 | 369 |
|
368 | 370 |
$r->auto_render(Mojolicious::Controller->new); |
369 | 371 |
|
370 | 372 |
Automatic rendering. |
371 | 373 |
|
372 |
-=head2 C<dispatch> |
|
374 |
+=head2 dispatch |
|
373 | 375 |
|
374 | 376 |
my $success = $r->dispatch(Mojolicious::Controller->new); |
375 | 377 |
|
376 | 378 |
Match routes with L<Mojolicious::Routes::Match> and dispatch. |
377 | 379 |
|
378 |
-=head2 C<hide> |
|
380 |
+=head2 hide |
|
379 | 381 |
|
380 | 382 |
$r = $r->hide(qw(foo bar)); |
381 | 383 |
|
382 | 384 |
Hide controller methods and attributes from routes. |
383 | 385 |
|
384 |
-=head2 C<route> |
|
386 |
+=head2 lookup |
|
387 |
+ |
|
388 |
+ my $route = $r->lookup('foo'); |
|
389 |
+ |
|
390 |
+Find route by name with L<Mojolicious::Routes::Route/"find"> and cache all |
|
391 |
+results for future lookups. |
|
392 |
+ |
|
393 |
+=head2 route |
|
385 | 394 |
|
386 | 395 |
my $route = $r->route; |
387 | 396 |
my $route = $r->route('/:action'); |
... | ... |
@@ -1,27 +1,22 @@ |
1 | 1 |
package Mojolicious::Routes::Match; |
2 | 2 |
use Mojo::Base -base; |
3 | 3 |
|
4 |
-use Mojo::Util qw(decode url_unescape); |
|
5 |
- |
|
6 | 4 |
has captures => sub { {} }; |
7 | 5 |
has [qw(endpoint root)]; |
8 | 6 |
has stack => sub { [] }; |
9 | 7 |
|
10 | 8 |
sub new { |
11 | 9 |
my $self = shift->SUPER::new; |
12 |
- |
|
13 |
- $self->{method} = uc shift; |
|
14 |
- my $path = url_unescape shift; |
|
15 |
- $self->{path} = do { my $tmp = decode('UTF-8', $path); defined $tmp ? $tmp : $path}; |
|
10 |
+ $self->{method} = uc shift; |
|
11 |
+ $self->{path} = shift; |
|
16 | 12 |
$self->{websocket} = shift; |
17 |
- |
|
18 | 13 |
return $self; |
19 | 14 |
} |
20 | 15 |
|
21 | 16 |
sub match { |
22 | 17 |
my ($self, $r, $c) = @_; |
23 | 18 |
|
24 |
- # Match |
|
19 |
+ # Pattern |
|
25 | 20 |
$self->root($r) unless $self->root; |
26 | 21 |
my $path = $self->{path}; |
27 | 22 |
my $pattern = $r->pattern; |
... | ... |
@@ -120,7 +115,7 @@ sub path_for { |
120 | 115 |
} |
121 | 116 |
|
122 | 117 |
# Find endpoint |
123 |
- else { return $name unless $endpoint = $self->root->find($name) } |
|
118 |
+ else { return $name unless $endpoint = $self->root->lookup($name) } |
|
124 | 119 |
|
125 | 120 |
# Merge values |
126 | 121 |
my $captures = $self->captures; |
... | ... |
@@ -134,7 +129,6 @@ sub path_for { |
134 | 129 |
|
135 | 130 |
# Render |
136 | 131 |
my $path = $endpoint->render('', \%values); |
137 |
- utf8::downgrade $path, 1; |
|
138 | 132 |
return wantarray ? ($path, $endpoint->has_websocket) : $path; |
139 | 133 |
} |
140 | 134 |
|
... | ... |
@@ -170,28 +164,28 @@ structures. |
170 | 164 |
|
171 | 165 |
L<Mojolicious::Routes::Match> implements the following attributes. |
172 | 166 |
|
173 |
-=head2 C<captures> |
|
167 |
+=head2 captures |
|
174 | 168 |
|
175 | 169 |
my $captures = $m->captures; |
176 | 170 |
$m = $m->captures({foo => 'bar'}); |
177 | 171 |
|
178 | 172 |
Captured parameters. |
179 | 173 |
|
180 |
-=head2 C<endpoint> |
|
174 |
+=head2 endpoint |
|
181 | 175 |
|
182 | 176 |
my $endpoint = $m->endpoint; |
183 | 177 |
$m = $m->endpoint(Mojolicious::Routes->new); |
184 | 178 |
|
185 | 179 |
The route endpoint that actually matched. |
186 | 180 |
|
187 |
-=head2 C<root> |
|
181 |
+=head2 root |
|
188 | 182 |
|
189 | 183 |
my $root = $m->root; |
190 | 184 |
$m = $m->root($routes); |
191 | 185 |
|
192 | 186 |
The root of the route tree. |
193 | 187 |
|
194 |
-=head2 C<stack> |
|
188 |
+=head2 stack |
|
195 | 189 |
|
196 | 190 |
my $stack = $m->stack; |
197 | 191 |
$m = $m->stack([{foo => 'bar'}]); |
... | ... |
@@ -201,22 +195,22 @@ Captured parameters with nesting history. |
201 | 195 |
=head1 METHODS |
202 | 196 |
|
203 | 197 |
L<Mojolicious::Routes::Match> inherits all methods from L<Mojo::Base> and |
204 |
-implements the following ones. |
|
198 |
+implements the following new ones. |
|
205 | 199 |
|
206 |
-=head2 C<new> |
|
200 |
+=head2 new |
|
207 | 201 |
|
208 | 202 |
my $m = Mojolicious::Routes::Match->new(GET => '/foo'); |
209 | 203 |
my $m = Mojolicious::Routes::Match->new(GET => '/foo', $ws); |
210 | 204 |
|
211 | 205 |
Construct a new L<Mojolicious::Routes::Match> object. |
212 | 206 |
|
213 |
-=head2 C<match> |
|
207 |
+=head2 match |
|
214 | 208 |
|
215 | 209 |
$m->match(Mojolicious::Routes->new, Mojolicious::Controller->new); |
216 | 210 |
|
217 | 211 |
Match against a route tree. |
218 | 212 |
|
219 |
-=head2 C<path_for> |
|
213 |
+=head2 path_for |
|
220 | 214 |
|
221 | 215 |
my $path = $m->path_for; |
222 | 216 |
my $path = $m->path_for(foo => 'bar'); |
... | ... |
@@ -24,11 +24,8 @@ sub parse { |
24 | 24 |
# Make sure we have a viable pattern |
25 | 25 |
my $pattern = @_ % 2 ? (shift || '/') : '/'; |
26 | 26 |
$pattern = "/$pattern" unless $pattern =~ m!^/!; |
27 |
- |
|
28 |
- # Constraints |
|
29 | 27 |
$self->constraints({@_}); |
30 | 28 |
|
31 |
- # Tokenize |
|
32 | 29 |
return $pattern eq '/' ? $self : $self->pattern($pattern)->_tokenize; |
33 | 30 |
} |
34 | 31 |
|
... | ... |
@@ -39,7 +36,6 @@ sub render { |
39 | 36 |
my $format = ($values ||= {})->{format}; |
40 | 37 |
$values = {%{$self->defaults}, %$values}; |
41 | 38 |
|
42 |
- # Turn pattern into path |
|
43 | 39 |
my $string = ''; |
44 | 40 |
my $optional = 1; |
45 | 41 |
for my $token (reverse @{$self->tree}) { |
... | ... |
@@ -104,7 +100,6 @@ sub shape_match { |
104 | 100 |
sub _compile { |
105 | 101 |
my $self = shift; |
106 | 102 |
|
107 |
- # Compile tree to regex |
|
108 | 103 |
my $block = my $regex = ''; |
109 | 104 |
my $constraints = $self->constraints; |
110 | 105 |
my $optional = 1; |
... | ... |
@@ -152,7 +147,6 @@ sub _compile { |
152 | 147 |
$compiled .= '?' if $optional; |
153 | 148 |
} |
154 | 149 |
|
155 |
- # Add to block |
|
156 | 150 |
$block = "$compiled$block"; |
157 | 151 |
} |
158 | 152 |
|
... | ... |
@@ -188,14 +182,12 @@ sub _compile_req { |
188 | 182 |
sub _tokenize { |
189 | 183 |
my $self = shift; |
190 | 184 |
|
191 |
- # Token |
|
192 | 185 |
my $quote_end = $self->quote_end; |
193 | 186 |
my $quote_start = $self->quote_start; |
194 | 187 |
my $placeholder = $self->placeholder_start; |
195 | 188 |
my $relaxed = $self->relaxed_start; |
196 | 189 |
my $wildcard = $self->wildcard_start; |
197 | 190 |
|
198 |
- # Parse the pattern character wise |
|
199 | 191 |
my $pattern = $self->pattern; |
200 | 192 |
my $state = 'text'; |
201 | 193 |
my (@tree, $quoted); |
... | ... |
@@ -278,84 +270,84 @@ L<Mojolicious::Routes::Pattern> is the core of L<Mojolicious::Routes>. |
278 | 270 |
|
279 | 271 |
L<Mojolicious::Routes::Pattern> implements the following attributes. |
280 | 272 |
|
281 |
-=head2 C<constraints> |
|
273 |
+=head2 constraints |
|
282 | 274 |
|
283 | 275 |
my $constraints = $pattern->constraints; |
284 | 276 |
$pattern = $pattern->constraints({foo => qr/\w+/}); |
285 | 277 |
|
286 | 278 |
Regular expression constraints. |
287 | 279 |
|
288 |
-=head2 C<defaults> |
|
280 |
+=head2 defaults |
|
289 | 281 |
|
290 | 282 |
my $defaults = $pattern->defaults; |
291 | 283 |
$pattern = $pattern->defaults({foo => 'bar'}); |
292 | 284 |
|
293 | 285 |
Default parameters. |
294 | 286 |
|
295 |
-=head2 C<format_regex> |
|
287 |
+=head2 format_regex |
|
296 | 288 |
|
297 | 289 |
my $regex = $pattern->format_regex; |
298 | 290 |
$pattern = $pattern->format_regex($regex); |
299 | 291 |
|
300 | 292 |
Compiled regular expression for format matching. |
301 | 293 |
|
302 |
-=head2 C<pattern> |
|
294 |
+=head2 pattern |
|
303 | 295 |
|
304 | 296 |
my $pattern = $pattern->pattern; |
305 | 297 |
$pattern = $pattern->pattern('/(foo)/(bar)'); |
306 | 298 |
|
307 | 299 |
Raw unparsed pattern. |
308 | 300 |
|
309 |
-=head2 C<placeholder_start> |
|
301 |
+=head2 placeholder_start |
|
310 | 302 |
|
311 | 303 |
my $start = $pattern->placeholder_start; |
312 | 304 |
$pattern = $pattern->placeholder_start(':'); |
313 | 305 |
|
314 | 306 |
Character indicating a placeholder, defaults to C<:>. |
315 | 307 |
|
316 |
-=head2 C<placeholders> |
|
308 |
+=head2 placeholders |
|
317 | 309 |
|
318 | 310 |
my $placeholders = $pattern->placeholders; |
319 | 311 |
$pattern = $pattern->placeholders(['foo', 'bar']); |
320 | 312 |
|
321 | 313 |
Placeholder names. |
322 | 314 |
|
323 |
-=head2 C<quote_end> |
|
315 |
+=head2 quote_end |
|
324 | 316 |
|
325 | 317 |
my $end = $pattern->quote_end; |
326 | 318 |
$pattern = $pattern->quote_end(']'); |
327 | 319 |
|
328 | 320 |
Character indicating the end of a quoted placeholder, defaults to C<)>. |
329 | 321 |
|
330 |
-=head2 C<quote_start> |
|
322 |
+=head2 quote_start |
|
331 | 323 |
|
332 | 324 |
my $start = $pattern->quote_start; |
333 | 325 |
$pattern = $pattern->quote_start('['); |
334 | 326 |
|
335 | 327 |
Character indicating the start of a quoted placeholder, defaults to C<(>. |
336 | 328 |
|
337 |
-=head2 C<regex> |
|
329 |
+=head2 regex |
|
338 | 330 |
|
339 | 331 |
my $regex = $pattern->regex; |
340 | 332 |
$pattern = $pattern->regex($regex); |
341 | 333 |
|
342 | 334 |
Pattern in compiled regular expression form. |
343 | 335 |
|
344 |
-=head2 C<relaxed_start> |
|
336 |
+=head2 relaxed_start |
|
345 | 337 |
|
346 | 338 |
my $start = $pattern->relaxed_start; |
347 | 339 |
$pattern = $pattern->relaxed_start('*'); |
348 | 340 |
|
349 | 341 |
Character indicating a relaxed placeholder, defaults to C<#>. |
350 | 342 |
|
351 |
-=head2 C<tree> |
|
343 |
+=head2 tree |
|
352 | 344 |
|
353 | 345 |
my $tree = $pattern->tree; |
354 | 346 |
$pattern = $pattern->tree([ ... ]); |
355 | 347 |
|
356 | 348 |
Pattern in parsed form. |
357 | 349 |
|
358 |
-=head2 C<wildcard_start> |
|
350 |
+=head2 wildcard_start |
|
359 | 351 |
|
360 | 352 |
my $start = $pattern->wildcard_start; |
361 | 353 |
$pattern = $pattern->wildcard_start('*'); |
... | ... |
@@ -365,9 +357,9 @@ Character indicating the start of a wildcard placeholder, defaults to C<*>. |
365 | 357 |
=head1 METHODS |
366 | 358 |
|
367 | 359 |
L<Mojolicious::Routes::Pattern> inherits all methods from L<Mojo::Base> and |
368 |
-implements the following ones. |
|
360 |
+implements the following new ones. |
|
369 | 361 |
|
370 |
-=head2 C<new> |
|
362 |
+=head2 new |
|
371 | 363 |
|
372 | 364 |
my $pattern = Mojolicious::Routes::Pattern->new('/:action'); |
373 | 365 |
my $pattern |
... | ... |
@@ -376,14 +368,14 @@ implements the following ones. |
376 | 368 |
|
377 | 369 |
Construct a new L<Mojolicious::Routes::Pattern> object. |
378 | 370 |
|
379 |
-=head2 C<match> |
|
371 |
+=head2 match |
|
380 | 372 |
|
381 | 373 |
my $result = $pattern->match('/foo/bar'); |
382 | 374 |
my $result = $pattern->match('/foo/bar', 1); |
383 | 375 |
|
384 | 376 |
Match pattern against entire path, format detection is disabled by default. |
385 | 377 |
|
386 |
-=head2 C<parse> |
|
378 |
+=head2 parse |
|
387 | 379 |
|
388 | 380 |
$pattern = $pattern->parse('/:action'); |
389 | 381 |
$pattern = $pattern->parse('/:action', action => qr/\w+/); |
... | ... |
@@ -391,7 +383,7 @@ Match pattern against entire path, format detection is disabled by default. |
391 | 383 |
|
392 | 384 |
Parse a raw pattern. |
393 | 385 |
|
394 |
-=head2 C<render> |
|
386 |
+=head2 render |
|
395 | 387 |
|
396 | 388 |
my $path = $pattern->render({action => 'foo'}); |
397 | 389 |
my $path = $pattern->render({action => 'foo'}, 1); |
... | ... |
@@ -399,7 +391,7 @@ Parse a raw pattern. |
399 | 391 |
Render pattern into a path with parameters, format rendering is disabled by |
400 | 392 |
default. |
401 | 393 |
|
402 |
-=head2 C<shape_match> |
|
394 |
+=head2 shape_match |
|
403 | 395 |
|
404 | 396 |
my $result = $pattern->shape_match(\$path); |
405 | 397 |
my $result = $pattern->shape_match(\$path, 1); |
... | ... |
@@ -45,7 +45,6 @@ sub detour { shift->partial(1)->to(@_) } |
45 | 45 |
sub find { |
46 | 46 |
my ($self, $name) = @_; |
47 | 47 |
|
48 |
- # Check all children |
|
49 | 48 |
my @children = (@{$self->children}); |
50 | 49 |
my $candidate; |
51 | 50 |
while (my $child = shift @children) { |
... | ... |
@@ -102,6 +101,7 @@ sub over { |
102 | 101 |
return $self unless @$conditions; |
103 | 102 |
$self->{over} = $conditions; |
104 | 103 |
$self->root->cache(0); |
104 |
+ |
|
105 | 105 |
return $self; |
106 | 106 |
} |
107 | 107 |
|
... | ... |
@@ -159,8 +159,6 @@ sub to { |
159 | 159 |
# Single argument |
160 | 160 |
my ($shortcut, $defaults); |
161 | 161 |
if (@_ == 1) { |
162 |
- |
|
163 |
- # Hash |
|
164 | 162 |
$defaults = shift if ref $_[0] eq 'HASH'; |
165 | 163 |
$shortcut = shift if $_[0]; |
166 | 164 |
} |
... | ... |
@@ -229,7 +227,6 @@ sub websocket { |
229 | 227 |
sub _generate_route { |
230 | 228 |
my ($self, $methods, @args) = @_; |
231 | 229 |
|
232 |
- # Route information |
|
233 | 230 |
my ($cb, @conditions, @constraints, %defaults, $name, $pattern); |
234 | 231 |
while (defined(my $arg = shift @args)) { |
235 | 232 |
|
... | ... |
@@ -286,35 +283,35 @@ L<Mojolicious::Routes>. |
286 | 283 |
|
287 | 284 |
L<Mojolicious::Routes::Route> implements the following attributes. |
288 | 285 |
|
289 |
-=head2 C<children> |
|
286 |
+=head2 children |
|
290 | 287 |
|
291 | 288 |
my $children = $r->children; |
292 | 289 |
$r = $r->children([Mojolicious::Routes::Route->new]); |
293 | 290 |
|
294 | 291 |
The children of this route, used for nesting routes. |
295 | 292 |
|
296 |
-=head2 C<inline> |
|
293 |
+=head2 inline |
|
297 | 294 |
|
298 | 295 |
my $inline = $r->inline; |
299 | 296 |
$r = $r->inline(1); |
300 | 297 |
|
301 | 298 |
Allow C<bridge> semantics for this route. |
302 | 299 |
|
303 |
-=head2 C<parent> |
|
300 |
+=head2 parent |
|
304 | 301 |
|
305 | 302 |
my $parent = $r->parent; |
306 | 303 |
$r = $r->parent(Mojolicious::Routes::Route->new); |
307 | 304 |
|
308 | 305 |
The parent of this route, used for nesting routes. |
309 | 306 |
|
310 |
-=head2 C<partial> |
|
307 |
+=head2 partial |
|
311 | 308 |
|
312 | 309 |
my $partial = $r->partial; |
313 | 310 |
$r = $r->partial(1); |
314 | 311 |
|
315 | 312 |
Route has no specific end, remaining characters will be captured in C<path>. |
316 | 313 |
|
317 |
-=head2 C<pattern> |
|
314 |
+=head2 pattern |
|
318 | 315 |
|
319 | 316 |
my $pattern = $r->pattern; |
320 | 317 |
$r = $r->pattern(Mojolicious::Routes::Pattern->new); |
... | ... |
@@ -324,16 +321,16 @@ Pattern for this route, defaults to a L<Mojolicious::Routes::Pattern> object. |
324 | 321 |
=head1 METHODS |
325 | 322 |
|
326 | 323 |
L<Mojolicious::Routes::Route> inherits all methods from L<Mojo::Base> and |
327 |
-implements the following ones. |
|
324 |
+implements the following new ones. |
|
328 | 325 |
|
329 |
-=head2 C<new> |
|
326 |
+=head2 new |
|
330 | 327 |
|
331 | 328 |
my $r = Mojolicious::Routes::Route->new; |
332 | 329 |
my $r = Mojolicious::Routes::Route->new('/:controller/:action'); |
333 | 330 |
|
334 | 331 |
Construct a new L<Mojolicious::Routes::Route> object. |
335 | 332 |
|
336 |
-=head2 C<add_child> |
|
333 |
+=head2 add_child |
|
337 | 334 |
|
338 | 335 |
$r = $r->add_child(Mojolicious::Route->new); |
339 | 336 |
|
... | ... |
@@ -343,7 +340,7 @@ current parent if necessary. |
343 | 340 |
# Reattach route |
344 | 341 |
$r->add_child($r->find('foo')); |
345 | 342 |
|
346 |
-=head2 C<any> |
|
343 |
+=head2 any |
|
347 | 344 |
|
348 | 345 |
my $route = $r->any('/:foo' => sub {...}); |
349 | 346 |
my $route = $r->any([qw(GET POST)] => '/:foo' => sub {...}); |
... | ... |
@@ -353,7 +350,7 @@ also the L<Mojolicious::Lite> tutorial for more argument variations. |
353 | 350 |
|
354 | 351 |
$r->any('/user')->to('user#whatever'); |
355 | 352 |
|
356 |
-=head2 C<bridge> |
|
353 |
+=head2 bridge |
|
357 | 354 |
|
358 | 355 |
my $bridge = $r->bridge; |
359 | 356 |
my $bridge = $r->bridge('/:action'); |
... | ... |
@@ -366,7 +363,7 @@ Generate bridge route. |
366 | 363 |
$auth->get('/show')->to('#show'); |
367 | 364 |
$auth->post('/create')->to('#create'); |
368 | 365 |
|
369 |
-=head2 C<delete> |
|
366 |
+=head2 delete |
|
370 | 367 |
|
371 | 368 |
my $route = $r->delete('/:foo' => sub {...}); |
372 | 369 |
|
... | ... |
@@ -375,7 +372,7 @@ L<Mojolicious::Lite> tutorial for more argument variations. |
375 | 372 |
|
376 | 373 |
$r->delete('/user')->to('user#remove'); |
377 | 374 |
|
378 |
-=head2 C<detour> |
|
375 |
+=head2 detour |
|
379 | 376 |
|
380 | 377 |
$r = $r->detour(action => 'foo'); |
381 | 378 |
$r = $r->detour({action => 'foo'}); |
... | ... |
@@ -392,7 +389,7 @@ L<Mojolicious::Lite> tutorial for more argument variations. |
392 | 389 |
Set default parameters for this route and allow partial matching to simplify |
393 | 390 |
application embedding. |
394 | 391 |
|
395 |
-=head2 C<find> |
|
392 |
+=head2 find |
|
396 | 393 |
|
397 | 394 |
my $route = $r->find('foo'); |
398 | 395 |
|
... | ... |
@@ -401,7 +398,7 @@ generated ones. |
401 | 398 |
|
402 | 399 |
$r->find('show_user')->to(foo => 'bar'); |
403 | 400 |
|
404 |
-=head2 C<get> |
|
401 |
+=head2 get |
|
405 | 402 |
|
406 | 403 |
my $route = $r->get('/:foo' => sub {...}); |
407 | 404 |
|
... | ... |
@@ -410,48 +407,48 @@ L<Mojolicious::Lite> tutorial for more argument variations. |
410 | 407 |
|
411 | 408 |
$r->get('/user')->to('user#show'); |
412 | 409 |
|
413 |
-=head2 C<has_conditions> |
|
410 |
+=head2 has_conditions |
|
414 | 411 |
|
415 | 412 |
my $success = $r->has_conditions; |
416 | 413 |
|
417 | 414 |
Check if this route has active conditions. |
418 | 415 |
|
419 |
-=head2 C<has_custom_name> |
|
416 |
+=head2 has_custom_name |
|
420 | 417 |
|
421 | 418 |
my $success = $r->has_custom_name; |
422 | 419 |
|
423 | 420 |
Check if this route has a custom name. |
424 | 421 |
|
425 |
-=head2 C<has_websocket> |
|
422 |
+=head2 has_websocket |
|
426 | 423 |
|
427 | 424 |
my $success = $r->has_websocket; |
428 | 425 |
|
429 | 426 |
Check if this route has a WebSocket ancestor. |
430 | 427 |
|
431 |
-=head2 C<is_endpoint> |
|
428 |
+=head2 is_endpoint |
|
432 | 429 |
|
433 | 430 |
my $success = $r->is_endpoint; |
434 | 431 |
|
435 | 432 |
Check if this route qualifies as an endpoint. |
436 | 433 |
|
437 |
-=head2 C<is_websocket> |
|
434 |
+=head2 is_websocket |
|
438 | 435 |
|
439 | 436 |
my $success = $r->is_websocket; |
440 | 437 |
|
441 | 438 |
Check if this route is a WebSocket. |
442 | 439 |
|
443 |
-=head2 C<name> |
|
440 |
+=head2 name |
|
444 | 441 |
|
445 | 442 |
my $name = $r->name; |
446 | 443 |
$r = $r->name('foo'); |
447 | 444 |
|
448 | 445 |
The name of this route, defaults to an automatically generated name based on |
449 |
-the route pattern. Note that the name C<current> is reserved for refering to |
|
446 |
+the route pattern. Note that the name C<current> is reserved for referring to |
|
450 | 447 |
the current route. |
451 | 448 |
|
452 | 449 |
$r->get('/user')->to('user#show')->name('show_user'); |
453 | 450 |
|
454 |
-=head2 C<options> |
|
451 |
+=head2 options |
|
455 | 452 |
|
456 | 453 |
my $route = $r->options('/:foo' => sub {...}); |
457 | 454 |
|
... | ... |
@@ -460,7 +457,7 @@ L<Mojolicious::Lite> tutorial for more argument variations. |
460 | 457 |
|
461 | 458 |
$r->options('/user')->to('user#overview'); |
462 | 459 |
|
463 |
-=head2 C<over> |
|
460 |
+=head2 over |
|
464 | 461 |
|
465 | 462 |
my $over = $r->over; |
466 | 463 |
$r = $r->over(foo => 1); |
... | ... |
@@ -472,7 +469,7 @@ routing cache, since conditions are too complex for caching. |
472 | 469 |
|
473 | 470 |
$r->get('/foo')->over(host => qr/mojolicio\.us/)->to('foo#bar'); |
474 | 471 |
|
475 |
-=head2 C<parse> |
|
472 |
+=head2 parse |
|
476 | 473 |
|
477 | 474 |
$r = $r->parse('/:action'); |
478 | 475 |
$r = $r->parse('/:action', action => qr/\w+/); |
... | ... |
@@ -480,7 +477,7 @@ routing cache, since conditions are too complex for caching. |
480 | 477 |
|
481 | 478 |
Parse a pattern. |
482 | 479 |
|
483 |
-=head2 C<patch> |
|
480 |
+=head2 patch |
|
484 | 481 |
|
485 | 482 |
my $route = $r->patch('/:foo' => sub {...}); |
486 | 483 |
|
... | ... |
@@ -489,7 +486,7 @@ L<Mojolicious::Lite> tutorial for more argument variations. |
489 | 486 |
|
490 | 487 |
$r->patch('/user')->to('user#update'); |
491 | 488 |
|
492 |
-=head2 C<post> |
|
489 |
+=head2 post |
|
493 | 490 |
|
494 | 491 |
my $route = $r->post('/:foo' => sub {...}); |
495 | 492 |
|
... | ... |
@@ -498,7 +495,7 @@ L<Mojolicious::Lite> tutorial for more argument variations. |
498 | 495 |
|
499 | 496 |
$r->post('/user')->to('user#create'); |
500 | 497 |
|
501 |
-=head2 C<put> |
|
498 |
+=head2 put |
|
502 | 499 |
|
503 | 500 |
my $route = $r->put('/:foo' => sub {...}); |
504 | 501 |
|
... | ... |
@@ -507,7 +504,7 @@ L<Mojolicious::Lite> tutorial for more argument variations. |
507 | 504 |
|
508 | 505 |
$r->put('/user')->to('user#replace'); |
509 | 506 |
|
510 |
-=head2 C<remove> |
|
507 |
+=head2 remove |
|
511 | 508 |
|
512 | 509 |
$r = $r->remove; |
513 | 510 |
|
... | ... |
@@ -519,14 +516,14 @@ Remove route from parent. |
519 | 516 |
# Reattach route to new parent |
520 | 517 |
$r->route('/foo')->add_child($r->find('bar')->remove); |
521 | 518 |
|
522 |
-=head2 C<render> |
|
519 |
+=head2 render |
|
523 | 520 |
|
524 | 521 |
my $path = $r->render($suffix); |
525 | 522 |
my $path = $r->render($suffix, {foo => 'bar'}); |
526 | 523 |
|
527 | 524 |
Render route with parameters into a path. |
528 | 525 |
|
529 |
-=head2 C<root> |
|
526 |
+=head2 root |
|
530 | 527 |
|
531 | 528 |
my $root = $r->root; |
532 | 529 |
|
... | ... |
@@ -534,7 +531,7 @@ The L<Mojolicious::Routes> object this route is an descendent of. |
534 | 531 |
|
535 | 532 |
$r->root->cache(0); |
536 | 533 |
|
537 |
-=head2 C<route> |
|
534 |
+=head2 route |
|
538 | 535 |
|
539 | 536 |
my $route = $r->route; |
540 | 537 |
my $route = $r->route('/:action'); |
... | ... |
@@ -543,7 +540,7 @@ The L<Mojolicious::Routes> object this route is an descendent of. |
543 | 540 |
|
544 | 541 |
Generate route matching all HTTP request methods. |
545 | 542 |
|
546 |
-=head2 C<to> |
|
543 |
+=head2 to |
|
547 | 544 |
|
548 | 545 |
my $defaults = $r->to; |
549 | 546 |
$r = $r->to(action => 'foo'); |
... | ... |
@@ -560,13 +557,13 @@ Generate route matching all HTTP request methods. |
560 | 557 |
|
561 | 558 |
Set default parameters for this route. |
562 | 559 |
|
563 |
-=head2 C<to_string> |
|
560 |
+=head2 to_string |
|
564 | 561 |
|
565 | 562 |
my $string = $r->to_string; |
566 | 563 |
|
567 | 564 |
Stringify the whole route. |
568 | 565 |
|
569 |
-=head2 C<under> |
|
566 |
+=head2 under |
|
570 | 567 |
|
571 | 568 |
my $route = $r->under(sub {...}); |
572 | 569 |
my $route = $r->under('/:foo'); |
... | ... |
@@ -578,7 +575,7 @@ argument variations. |
578 | 575 |
$auth->get('/show')->to('#show'); |
579 | 576 |
$auth->post('/create')->to('#create'); |
580 | 577 |
|
581 |
-=head2 C<via> |
|
578 |
+=head2 via |
|
582 | 579 |
|
583 | 580 |
my $methods = $r->via; |
584 | 581 |
$r = $r->via('GET'); |
... | ... |
@@ -590,7 +587,7 @@ restrictions. |
590 | 587 |
|
591 | 588 |
$r->route('/foo')->via(qw(GET POST))->to('foo#bar'); |
592 | 589 |
|
593 |
-=head2 C<websocket> |
|
590 |
+=head2 websocket |
|
594 | 591 |
|
595 | 592 |
my $websocket = $r->websocket('/:foo' => sub {...}); |
596 | 593 |
|
... | ... |
@@ -12,52 +12,43 @@ has default_expiration => 3600; |
12 | 12 |
sub load { |
13 | 13 |
my ($self, $c) = @_; |
14 | 14 |
|
15 |
- # Session cookie |
|
16 | 15 |
return unless my $value = $c->signed_cookie($self->cookie_name); |
17 |
- |
|
18 |
- # Deserialize |
|
19 | 16 |
$value =~ s/-/=/g; |
20 | 17 |
return unless my $session = Mojo::JSON->new->decode(b64_decode $value); |
21 | 18 |
|
22 |
- # Expiration |
|
19 |
+ # "expiration" value is inherited |
|
23 | 20 |
my $expiration = defined $session->{expiration} ? $session->{expiration} : $self->default_expiration; |
24 | 21 |
return if !(my $expires = delete $session->{expires}) && $expiration; |
25 | 22 |
return if defined $expires && $expires <= time; |
26 | 23 |
|
27 |
- # Content |
|
28 | 24 |
my $stash = $c->stash; |
29 | 25 |
return unless $stash->{'mojo.active_session'} = keys %$session; |
30 | 26 |
$stash->{'mojo.session'} = $session; |
31 |
- |
|
32 |
- # Flash |
|
33 | 27 |
$session->{flash} = delete $session->{new_flash} if $session->{new_flash}; |
34 | 28 |
} |
35 | 29 |
|
36 | 30 |
sub store { |
37 | 31 |
my ($self, $c) = @_; |
38 | 32 |
|
39 |
- # Session |
|
33 |
+ # Make sure session was active |
|
40 | 34 |
my $stash = $c->stash; |
41 | 35 |
return unless my $session = $stash->{'mojo.session'}; |
42 | 36 |
return unless keys %$session || $stash->{'mojo.active_session'}; |
43 | 37 |
|
44 |
- # Flash |
|
38 |
+ # Don't reset flash for static files |
|
45 | 39 |
my $old = delete $session->{flash}; |
46 | 40 |
@{$session->{new_flash}}{keys %$old} = values %$old |
47 | 41 |
if $stash->{'mojo.static'}; |
48 | 42 |
delete $session->{new_flash} unless keys %{$session->{new_flash}}; |
49 | 43 |
|
50 |
- # Expiration |
|
44 |
+ # Generate "expires" value from "expiration" if necessary |
|
51 | 45 |
my $expiration = defined $session->{expiration} ? $session->{expiration} : $self->default_expiration; |
52 | 46 |
my $default = delete $session->{expires}; |
53 | 47 |
$session->{expires} = $default || time + $expiration |
54 | 48 |
if $expiration || $default; |
55 | 49 |
|
56 |
- # Serialize |
|
57 | 50 |
my $value = b64_encode(Mojo::JSON->new->encode($session), ''); |
58 | 51 |
$value =~ s/=/-/g; |
59 |
- |
|
60 |
- # Session cookie |
|
61 | 52 |
my $options = { |
62 | 53 |
domain => $self->cookie_domain, |
63 | 54 |
expires => $session->{expires}, |
... | ... |
@@ -93,28 +84,28 @@ with a C<HMAC-SHA1> signature. |
93 | 84 |
|
94 | 85 |
L<Mojolicious::Sessions> implements the following attributes. |
95 | 86 |
|
96 |
-=head2 C<cookie_domain> |
|
87 |
+=head2 cookie_domain |
|
97 | 88 |
|
98 | 89 |
my $domain = $sessions->cookie_domain; |
99 | 90 |
$sessions = $sessions->cookie_domain('.example.com'); |
100 | 91 |
|
101 | 92 |
Domain for session cookies, not defined by default. |
102 | 93 |
|
103 |
-=head2 C<cookie_name> |
|
94 |
+=head2 cookie_name |
|
104 | 95 |
|
105 | 96 |
my $name = $sessions->cookie_name; |
106 | 97 |
$sessions = $sessions->cookie_name('session'); |
107 | 98 |
|
108 | 99 |
Name for session cookies, defaults to C<mojolicious>. |
109 | 100 |
|
110 |
-=head2 C<cookie_path> |
|
101 |
+=head2 cookie_path |
|
111 | 102 |
|
112 | 103 |
my $path = $sessions->cookie_path; |
113 | 104 |
$sessions = $sessions->cookie_path('/foo'); |
114 | 105 |
|
115 | 106 |
Path for session cookies, defaults to C</>. |
116 | 107 |
|
117 |
-=head2 C<default_expiration> |
|
108 |
+=head2 default_expiration |
|
118 | 109 |
|
119 | 110 |
my $time = $sessions->default_expiration; |
120 | 111 |
$sessions = $sessions->default_expiration(3600); |
... | ... |
@@ -134,7 +125,7 @@ C<expiration> and C<expires> session values. |
134 | 125 |
# Delete whole session by setting an expiration date in the past |
135 | 126 |
$c->session(expires => 1); |
136 | 127 |
|
137 |
-=head2 C<secure> |
|
128 |
+=head2 secure |
|
138 | 129 |
|
139 | 130 |
my $secure = $sessions->secure; |
140 | 131 |
$sessions = $sessions->secure(1); |
... | ... |
@@ -147,13 +138,13 @@ over HTTPS connections. |
147 | 138 |
L<Mojolicious::Sessions> inherits all methods from L<Mojo::Base> and |
148 | 139 |
implements the following ones. |
149 | 140 |
|
150 |
-=head2 C<load> |
|
141 |
+=head2 load |
|
151 | 142 |
|
152 | 143 |
$sessions->load(Mojolicious::Controller->new); |
153 | 144 |
|
154 | 145 |
Load session data from signed cookie. |
155 | 146 |
|
156 |
-=head2 C<store> |
|
147 |
+=head2 store |
|
157 | 148 |
|
158 | 149 |
$sessions->store(Mojolicious::Controller->new); |
159 | 150 |
|
... | ... |
@@ -24,8 +24,6 @@ sub dispatch { |
24 | 24 |
# Canonical path |
25 | 25 |
my $stash = $c->stash; |
26 | 26 |
my $path = $stash->{path} || $c->req->url->path->clone->canonicalize; |
27 |
- |
|
28 |
- # Split parts |
|
29 | 27 |
return undef unless my @parts = @{Mojo::Path->new("$path")->parts}; |
30 | 28 |
|
31 | 29 |
# Serve static file and prevent directory traversal |
... | ... |
@@ -91,7 +89,6 @@ sub serve_asset { |
91 | 89 |
->content_range("bytes $start-$end/$size"); |
92 | 90 |
} |
93 | 91 |
|
94 |
- # Serve asset |
|
95 | 92 |
return $res->content->asset($asset->start_range($start)->end_range($end)); |
96 | 93 |
} |
97 | 94 |
|
... | ... |
@@ -138,14 +135,14 @@ Mojolicious::Static - Serve static files |
138 | 135 |
|
139 | 136 |
=head1 DESCRIPTION |
140 | 137 |
|
141 |
-L<Mojolicious::Static> is a dispatcher for static files with C<Range> and |
|
138 |
+L<Mojolicious::Static> is a static file server with C<Range> and |
|
142 | 139 |
C<If-Modified-Since> support. |
143 | 140 |
|
144 | 141 |
=head1 ATTRIBUTES |
145 | 142 |
|
146 | 143 |
L<Mojolicious::Static> implements the following attributes. |
147 | 144 |
|
148 |
-=head2 C<classes> |
|
145 |
+=head2 classes |
|
149 | 146 |
|
150 | 147 |
my $classes = $static->classes; |
151 | 148 |
$static = $static->classes(['main']); |
... | ... |
@@ -156,7 +153,7 @@ highest precedence, defaults to C<main>. |
156 | 153 |
# Add another class with static files in DATA section |
157 | 154 |
push @{$static->classes}, 'Mojolicious::Plugin::Fun'; |
158 | 155 |
|
159 |
-=head2 C<paths> |
|
156 |
+=head2 paths |
|
160 | 157 |
|
161 | 158 |
my $paths = $static->paths; |
162 | 159 |
$static = $static->paths(['/home/sri/public']); |
... | ... |
@@ -169,15 +166,15 @@ Directories to serve static files from, first one has the highest precedence. |
169 | 166 |
=head1 METHODS |
170 | 167 |
|
171 | 168 |
L<Mojolicious::Static> inherits all methods from L<Mojo::Base> and implements |
172 |
-the following ones. |
|
169 |
+the following new ones. |
|
173 | 170 |
|
174 |
-=head2 C<dispatch> |
|
171 |
+=head2 dispatch |
|
175 | 172 |
|
176 | 173 |
my $success = $static->dispatch(Mojolicious::Controller->new); |
177 | 174 |
|
178 | 175 |
Serve static file for L<Mojolicious::Controller> object. |
179 | 176 |
|
180 |
-=head2 C<file> |
|
177 |
+=head2 file |
|
181 | 178 |
|
182 | 179 |
my $asset = $static->file('foo/bar.html'); |
183 | 180 |
|
... | ... |
@@ -186,13 +183,13 @@ to C<paths> or from C<classes>. |
186 | 183 |
|
187 | 184 |
my $content = $static->file('foo/bar.html')->slurp; |
188 | 185 |
|
189 |
-=head2 C<serve> |
|
186 |
+=head2 serve |
|
190 | 187 |
|
191 | 188 |
my $success = $static->serve(Mojolicious::Controller->new, 'foo/bar.html'); |
192 | 189 |
|
193 | 190 |
Serve a specific file, relative to C<paths> or from C<classes>. |
194 | 191 |
|
195 |
-=head2 C<serve_asset> |
|
192 |
+=head2 serve_asset |
|
196 | 193 |
|
197 | 194 |
$static->serve_asset(Mojolicious::Controller->new, Mojo::Asset::File->new); |
198 | 195 |
|
... | ... |
@@ -112,7 +112,7 @@ The most common ones are already defined. |
112 | 112 |
|
113 | 113 |
L<Mojolicious::Types> implements the following attributes. |
114 | 114 |
|
115 |
-=head2 C<types> |
|
115 |
+=head2 types |
|
116 | 116 |
|
117 | 117 |
my $map = $types->types; |
118 | 118 |
$types = $types->types({png => 'image/png'}); |
... | ... |
@@ -122,9 +122,9 @@ List of MIME types. |
122 | 122 |
=head1 METHODS |
123 | 123 |
|
124 | 124 |
L<Mojolicious::Types> inherits all methods from L<Mojo::Base> and implements |
125 |
-the following ones. |
|
125 |
+the following new ones. |
|
126 | 126 |
|
127 |
-=head2 C<detect> |
|
127 |
+=head2 detect |
|
128 | 128 |
|
129 | 129 |
my $exts = $types->detect('application/json;q=9'); |
130 | 130 |
my $exts = $types->detect('text/html, application/json;q=9', 1); |
... | ... |
@@ -135,7 +135,7 @@ unspecific values that contain more than one MIME type is disabled by default. |
135 | 135 |
# List detected extensions prioritized |
136 | 136 |
say for @{$types->detect('application/json, text/xml;q=0.1', 1)}; |
137 | 137 |
|
138 |
-=head2 C<type> |
|
138 |
+=head2 type |
|
139 | 139 |
|
140 | 140 |
my $type = $types->type('png'); |
141 | 141 |
$types = $types->type(png => 'image/png'); |
... | ... |
@@ -0,0 +1,4 @@ |
1 |
+/*! jQuery v1.9.0 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license */(function(e,t){"use strict";function n(e){var t=e.length,n=st.type(e);return st.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}function r(e){var t=Tt[e]={};return st.each(e.match(lt)||[],function(e,n){t[n]=!0}),t}function i(e,n,r,i){if(st.acceptData(e)){var o,a,s=st.expando,u="string"==typeof n,l=e.nodeType,c=l?st.cache:e,f=l?e[s]:e[s]&&s;if(f&&c[f]&&(i||c[f].data)||!u||r!==t)return f||(l?e[s]=f=K.pop()||st.guid++:f=s),c[f]||(c[f]={},l||(c[f].toJSON=st.noop)),("object"==typeof n||"function"==typeof n)&&(i?c[f]=st.extend(c[f],n):c[f].data=st.extend(c[f].data,n)),o=c[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[st.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[st.camelCase(n)])):a=o,a}}function o(e,t,n){if(st.acceptData(e)){var r,i,o,a=e.nodeType,u=a?st.cache:e,l=a?e[st.expando]:st.expando;if(u[l]){if(t&&(r=n?u[l]:u[l].data)){st.isArray(t)?t=t.concat(st.map(t,st.camelCase)):t in r?t=[t]:(t=st.camelCase(t),t=t in r?[t]:t.split(" "));for(i=0,o=t.length;o>i;i++)delete r[t[i]];if(!(n?s:st.isEmptyObject)(r))return}(n||(delete u[l].data,s(u[l])))&&(a?st.cleanData([e],!0):st.support.deleteExpando||u!=u.window?delete u[l]:u[l]=null)}}}function a(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(Nt,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:wt.test(r)?st.parseJSON(r):r}catch(o){}st.data(e,n,r)}else r=t}return r}function s(e){var t;for(t in e)if(("data"!==t||!st.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function u(){return!0}function l(){return!1}function c(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function f(e,t,n){if(t=t||0,st.isFunction(t))return st.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return st.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=st.grep(e,function(e){return 1===e.nodeType});if(Wt.test(t))return st.filter(t,r,!n);t=st.filter(t,r)}return st.grep(e,function(e){return st.inArray(e,t)>=0===n})}function p(e){var t=zt.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function d(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function h(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function g(e){var t=nn.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function m(e,t){for(var n,r=0;null!=(n=e[r]);r++)st._data(n,"globalEval",!t||st._data(t[r],"globalEval"))}function y(e,t){if(1===t.nodeType&&st.hasData(e)){var n,r,i,o=st._data(e),a=st._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)st.event.add(t,n,s[n][r])}a.data&&(a.data=st.extend({},a.data))}}function v(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!st.support.noCloneEvent&&t[st.expando]){r=st._data(t);for(i in r.events)st.removeEvent(t,i,r.handle);t.removeAttribute(st.expando)}"script"===n&&t.text!==e.text?(h(t).text=e.text,g(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),st.support.html5Clone&&e.innerHTML&&!st.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Zt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}function b(e,n){var r,i,o=0,a=e.getElementsByTagName!==t?e.getElementsByTagName(n||"*"):e.querySelectorAll!==t?e.querySelectorAll(n||"*"):t;if(!a)for(a=[],r=e.childNodes||e;null!=(i=r[o]);o++)!n||st.nodeName(i,n)?a.push(i):st.merge(a,b(i,n));return n===t||n&&st.nodeName(e,n)?st.merge([e],a):a}function x(e){Zt.test(e.type)&&(e.defaultChecked=e.checked)}function T(e,t){if(t in e)return t;for(var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Nn.length;i--;)if(t=Nn[i]+n,t in e)return t;return r}function w(e,t){return e=t||e,"none"===st.css(e,"display")||!st.contains(e.ownerDocument,e)}function N(e,t){for(var n,r=[],i=0,o=e.length;o>i;i++)n=e[i],n.style&&(r[i]=st._data(n,"olddisplay"),t?(r[i]||"none"!==n.style.display||(n.style.display=""),""===n.style.display&&w(n)&&(r[i]=st._data(n,"olddisplay",S(n.nodeName)))):r[i]||w(n)||st._data(n,"olddisplay",st.css(n,"display")));for(i=0;o>i;i++)n=e[i],n.style&&(t&&"none"!==n.style.display&&""!==n.style.display||(n.style.display=t?r[i]||"":"none"));return e}function C(e,t,n){var r=mn.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function k(e,t,n,r,i){for(var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;4>o;o+=2)"margin"===n&&(a+=st.css(e,n+wn[o],!0,i)),r?("content"===n&&(a-=st.css(e,"padding"+wn[o],!0,i)),"margin"!==n&&(a-=st.css(e,"border"+wn[o]+"Width",!0,i))):(a+=st.css(e,"padding"+wn[o],!0,i),"padding"!==n&&(a+=st.css(e,"border"+wn[o]+"Width",!0,i)));return a}function E(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=ln(e),a=st.support.boxSizing&&"border-box"===st.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=un(e,t,o),(0>i||null==i)&&(i=e.style[t]),yn.test(i))return i;r=a&&(st.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+k(e,t,n||(a?"border":"content"),r,o)+"px"}function S(e){var t=V,n=bn[e];return n||(n=A(e,t),"none"!==n&&n||(cn=(cn||st("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(cn[0].contentWindow||cn[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=A(e,t),cn.detach()),bn[e]=n),n}function A(e,t){var n=st(t.createElement(e)).appendTo(t.body),r=st.css(n[0],"display");return n.remove(),r}function j(e,t,n,r){var i;if(st.isArray(t))st.each(t,function(t,i){n||kn.test(e)?r(e,i):j(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==st.type(t))r(e,t);else for(i in t)j(e+"["+i+"]",t[i],n,r)}function D(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(lt)||[];if(st.isFunction(n))for(;r=o[i++];)"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function L(e,n,r,i){function o(u){var l;return a[u]=!0,st.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||s||a[c]?s?!(l=c):t:(n.dataTypes.unshift(c),o(c),!1)}),l}var a={},s=e===$n;return o(n.dataTypes[0])||!a["*"]&&o("*")}function H(e,n){var r,i,o=st.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((o[r]?e:i||(i={}))[r]=n[r]);return i&&st.extend(!0,e,i),e}function M(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(o in c)o in r&&(n[c[o]]=r[o]);for(;"*"===l[0];)l.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("Content-Type"));if(i)for(o in u)if(u[o]&&u[o].test(i)){l.unshift(o);break}if(l[0]in r)a=l[0];else{for(o in r){if(!l[0]||e.converters[o+" "+l[0]]){a=o;break}s||(s=o)}a=a||s}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function q(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=u[++s];)if("*"!==i){if("*"!==l&&l!==i){if(n=a[l+" "+i]||a["* "+i],!n)for(r in a)if(o=r.split(" "),o[1]===i&&(n=a[l+" "+o[0]]||a["* "+o[0]])){n===!0?n=a[r]:a[r]!==!0&&(i=o[0],u.splice(s--,0,i));break}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(c){return{state:"parsererror",error:n?c:"No conversion from "+l+" to "+i}}}l=i}return{state:"success",data:t}}function _(){try{return new e.XMLHttpRequest}catch(t){}}function F(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function O(){return setTimeout(function(){Qn=t}),Qn=st.now()}function B(e,t){st.each(t,function(t,n){for(var r=(rr[t]||[]).concat(rr["*"]),i=0,o=r.length;o>i;i++)if(r[i].call(e,t,n))return})}function P(e,t,n){var r,i,o=0,a=nr.length,s=st.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;for(var t=Qn||O(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:st.extend({},t),opts:st.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Qn||O(),duration:n.duration,tweens:[],createTween:function(t,n){var r=st.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(R(c,l.opts.specialEasing);a>o;o++)if(r=nr[o].call(l,e,c,l.opts))return r;return B(l,c),st.isFunction(l.opts.start)&&l.opts.start.call(e,l),st.fx.timer(st.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function R(e,t){var n,r,i,o,a;for(n in e)if(r=st.camelCase(n),i=t[r],o=e[n],st.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=st.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}function W(e,t,n){var r,i,o,a,s,u,l,c,f,p=this,d=e.style,h={},g=[],m=e.nodeType&&w(e);n.queue||(c=st._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,f=c.empty.fire,c.empty.fire=function(){c.unqueued||f()}),c.unqueued++,p.always(function(){p.always(function(){c.unqueued--,st.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===st.css(e,"display")&&"none"===st.css(e,"float")&&(st.support.inlineBlockNeedsLayout&&"inline"!==S(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",st.support.shrinkWrapBlocks||p.done(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(r in t)if(o=t[r],Zn.exec(o)){if(delete t[r],u=u||"toggle"===o,o===(m?"hide":"show"))continue;g.push(r)}if(a=g.length){s=st._data(e,"fxshow")||st._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?st(e).show():p.done(function(){st(e).hide()}),p.done(function(){var t;st._removeData(e,"fxshow");for(t in h)st.style(e,t,h[t])});for(r=0;a>r;r++)i=g[r],l=p.createTween(i,m?s[i]:0),h[i]=s[i]||st.style(e,i),i in s||(s[i]=l.start,m&&(l.end=l.start,l.start="width"===i||"height"===i?1:0))}}function $(e,t,n,r,i){return new $.prototype.init(e,t,n,r,i)}function I(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=wn[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function z(e){return st.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}var X,U,V=e.document,Y=e.location,J=e.jQuery,G=e.$,Q={},K=[],Z="1.9.0",et=K.concat,tt=K.push,nt=K.slice,rt=K.indexOf,it=Q.toString,ot=Q.hasOwnProperty,at=Z.trim,st=function(e,t){return new st.fn.init(e,t,X)},ut=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,lt=/\S+/g,ct=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,ft=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,pt=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,dt=/^[\],:{}\s]*$/,ht=/(?:^|:|,)(?:\s*\[)+/g,gt=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,mt=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,yt=/^-ms-/,vt=/-([\da-z])/gi,bt=function(e,t){return t.toUpperCase()},xt=function(){V.addEventListener?(V.removeEventListener("DOMContentLoaded",xt,!1),st.ready()):"complete"===V.readyState&&(V.detachEvent("onreadystatechange",xt),st.ready())};st.fn=st.prototype={jquery:Z,constructor:st,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:ft.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof st?n[0]:n,st.merge(this,st.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:V,!0)),pt.test(i[1])&&st.isPlainObject(n))for(i in n)st.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=V.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=V,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):st.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),st.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return nt.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=st.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return st.each(this,e,t)},ready:function(e){return st.ready.promise().done(e),this},slice:function(){return this.pushStack(nt.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(st.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:tt,sort:[].sort,splice:[].splice},st.fn.init.prototype=st.fn,st.extend=st.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||st.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(e=arguments[u]))for(n in e)r=s[n],i=e[n],s!==i&&(c&&i&&(st.isPlainObject(i)||(o=st.isArray(i)))?(o?(o=!1,a=r&&st.isArray(r)?r:[]):a=r&&st.isPlainObject(r)?r:{},s[n]=st.extend(c,a,i)):i!==t&&(s[n]=i));return s},st.extend({noConflict:function(t){return e.$===st&&(e.$=G),t&&e.jQuery===st&&(e.jQuery=J),st},isReady:!1,readyWait:1,holdReady:function(e){e?st.readyWait++:st.ready(!0)},ready:function(e){if(e===!0?!--st.readyWait:!st.isReady){if(!V.body)return setTimeout(st.ready);st.isReady=!0,e!==!0&&--st.readyWait>0||(U.resolveWith(V,[st]),st.fn.trigger&&st(V).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===st.type(e)},isArray:Array.isArray||function(e){return"array"===st.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?Q[it.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==st.type(e)||e.nodeType||st.isWindow(e))return!1;try{if(e.constructor&&!ot.call(e,"constructor")&&!ot.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||ot.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||V;var r=pt.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=st.buildFragment([e],t,i),i&&st(i).remove(),st.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=st.trim(n),n&&dt.test(n.replace(gt,"@").replace(mt,"]").replace(ht,"")))?Function("return "+n)():(st.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||st.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&st.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(yt,"ms-").replace(vt,bt)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,r){var i,o=0,a=e.length,s=n(e);if(r){if(s)for(;a>o&&(i=t.apply(e[o],r),i!==!1);o++);else for(o in e)if(i=t.apply(e[o],r),i===!1)break}else if(s)for(;a>o&&(i=t.call(e[o],o,e[o]),i!==!1);o++);else for(o in e)if(i=t.call(e[o],o,e[o]),i===!1)break;return e},trim:at&&!at.call("\ufeff\u00a0")?function(e){return null==e?"":at.call(e)}:function(e){return null==e?"":(e+"").replace(ct,"")},makeArray:function(e,t){var r=t||[];return null!=e&&(n(Object(e))?st.merge(r,"string"==typeof e?[e]:e):tt.call(r,e)),r},inArray:function(e,t,n){var r;if(t){if(rt)return rt.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else for(;n[o]!==t;)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,r){var i,o=0,a=e.length,s=n(e),u=[];if(s)for(;a>o;o++)i=t(e[o],o,r),null!=i&&(u[u.length]=i);else for(o in e)i=t(e[o],o,r),null!=i&&(u[u.length]=i);return et.apply([],u)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(r=e[n],n=e,e=r),st.isFunction(e)?(i=nt.call(arguments,2),o=function(){return e.apply(n||this,i.concat(nt.call(arguments)))},o.guid=e.guid=e.guid||st.guid++,o):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===st.type(r)){o=!0;for(u in r)st.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,st.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(st(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),st.ready.promise=function(t){if(!U)if(U=st.Deferred(),"complete"===V.readyState)setTimeout(st.ready);else if(V.addEventListener)V.addEventListener("DOMContentLoaded",xt,!1),e.addEventListener("load",st.ready,!1);else{V.attachEvent("onreadystatechange",xt),e.attachEvent("onload",st.ready);var n=!1;try{n=null==e.frameElement&&V.documentElement}catch(r){}n&&n.doScroll&&function i(){if(!st.isReady){try{n.doScroll("left")}catch(e){return setTimeout(i,50)}st.ready()}}()}return U.promise(t)},st.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){Q["[object "+t+"]"]=t.toLowerCase()}),X=st(V);var Tt={};st.Callbacks=function(e){e="string"==typeof e?Tt[e]||r(e):st.extend({},e);var n,i,o,a,s,u,l=[],c=!e.once&&[],f=function(t){for(n=e.memory&&t,i=!0,u=a||0,a=0,s=l.length,o=!0;l&&s>u;u++)if(l[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}o=!1,l&&(c?c.length&&f(c.shift()):n?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function r(t){st.each(t,function(t,n){var i=st.type(n);"function"===i?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==i&&r(n)})})(arguments),o?s=l.length:n&&(a=t,f(n))}return this},remove:function(){return l&&st.each(arguments,function(e,t){for(var n;(n=st.inArray(t,l,n))>-1;)l.splice(n,1),o&&(s>=n&&s--,u>=n&&u--)}),this},has:function(e){return st.inArray(e,l)>-1},empty:function(){return l=[],this},disable:function(){return l=c=n=t,this},disabled:function(){return!l},lock:function(){return c=t,n||p.disable(),this},locked:function(){return!c},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!l||i&&!c||(o?c.push(t):f(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},st.extend({Deferred:function(e){var t=[["resolve","done",st.Callbacks("once memory"),"resolved"],["reject","fail",st.Callbacks("once memory"),"rejected"],["notify","progress",st.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return st.Deferred(function(n){st.each(t,function(t,o){var a=o[0],s=st.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&st.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?st.extend(e,r):r}},i={};return r.pipe=r.then,st.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=nt.call(arguments),a=o.length,s=1!==a||e&&st.isFunction(e.promise)?a:0,u=1===s?e:st.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?nt.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=Array(a),n=Array(a),r=Array(a);a>i;i++)o[i]&&st.isFunction(o[i].promise)?o[i].promise().done(l(i,r,o)).fail(u.reject).progress(l(i,n,t)):--s;return s||u.resolveWith(r,o),u.promise()}}),st.support=function(){var n,r,i,o,a,s,u,l,c,f,p=V.createElement("div");if(p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",r=p.getElementsByTagName("*"),i=p.getElementsByTagName("a")[0],!r||!i||!r.length)return{};o=V.createElement("select"),a=o.appendChild(V.createElement("option")),s=p.getElementsByTagName("input")[0],i.style.cssText="top:1px;float:left;opacity:.5",n={getSetAttribute:"t"!==p.className,leadingWhitespace:3===p.firstChild.nodeType,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(i.getAttribute("style")),hrefNormalized:"/a"===i.getAttribute("href"),opacity:/^0.5/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:!!s.value,optSelected:a.selected,enctype:!!V.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==V.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===V.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},s.checked=!0,n.noCloneChecked=s.cloneNode(!0).checked,o.disabled=!0,n.optDisabled=!a.disabled;try{delete p.test}catch(d){n.deleteExpando=!1}s=V.createElement("input"),s.setAttribute("value",""),n.input=""===s.getAttribute("value"),s.value="t",s.setAttribute("type","radio"),n.radioValue="t"===s.value,s.setAttribute("checked","t"),s.setAttribute("name","t"),u=V.createDocumentFragment(),u.appendChild(s),n.appendChecked=s.checked,n.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,p.attachEvent&&(p.attachEvent("onclick",function(){n.noCloneEvent=!1}),p.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})p.setAttribute(l="on"+f,"t"),n[f+"Bubbles"]=l in e||p.attributes[l].expando===!1;return p.style.backgroundClip="content-box",p.cloneNode(!0).style.backgroundClip="",n.clearCloneStyle="content-box"===p.style.backgroundClip,st(function(){var r,i,o,a="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",s=V.getElementsByTagName("body")[0];s&&(r=V.createElement("div"),r.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",s.appendChild(r).appendChild(p),p.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=p.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",c=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",n.reliableHiddenOffsets=c&&0===o[0].offsetHeight,p.innerHTML="",p.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",n.boxSizing=4===p.offsetWidth,n.doesNotIncludeMarginInBodyOffset=1!==s.offsetTop,e.getComputedStyle&&(n.pixelPosition="1%"!==(e.getComputedStyle(p,null)||{}).top,n.boxSizingReliable="4px"===(e.getComputedStyle(p,null)||{width:"4px"}).width,i=p.appendChild(V.createElement("div")),i.style.cssText=p.style.cssText=a,i.style.marginRight=i.style.width="0",p.style.width="1px",n.reliableMarginRight=!parseFloat((e.getComputedStyle(i,null)||{}).marginRight)),p.style.zoom!==t&&(p.innerHTML="",p.style.cssText=a+"width:1px;padding:1px;display:inline;zoom:1",n.inlineBlockNeedsLayout=3===p.offsetWidth,p.style.display="block",p.innerHTML="<div></div>",p.firstChild.style.width="5px",n.shrinkWrapBlocks=3!==p.offsetWidth,s.style.zoom=1),s.removeChild(r),r=p=o=i=null)}),r=o=u=a=i=s=null,n}();var wt=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,Nt=/([A-Z])/g;st.extend({cache:{},expando:"jQuery"+(Z+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?st.cache[e[st.expando]]:e[st.expando],!!e&&!s(e)},data:function(e,t,n){return i(e,t,n,!1)},removeData:function(e,t){return o(e,t,!1)},_data:function(e,t,n){return i(e,t,n,!0)},_removeData:function(e,t){return o(e,t,!0)},acceptData:function(e){var t=e.nodeName&&st.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),st.fn.extend({data:function(e,n){var r,i,o=this[0],s=0,u=null;if(e===t){if(this.length&&(u=st.data(o),1===o.nodeType&&!st._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>s;s++)i=r[s].name,i.indexOf("data-")||(i=st.camelCase(i.substring(5)),a(o,i,u[i]));st._data(o,"parsedAttrs",!0)}return u}return"object"==typeof e?this.each(function(){st.data(this,e)}):st.access(this,function(n){return n===t?o?a(o,e,st.data(o,e)):null:(this.each(function(){st.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){st.removeData(this,e)})}}),st.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=st._data(e,n),r&&(!i||st.isArray(r)?i=st._data(e,n,st.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=st.queue(e,t),r=n.length,i=n.shift(),o=st._queueHooks(e,t),a=function(){st.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return st._data(e,n)||st._data(e,n,{empty:st.Callbacks("once memory").add(function(){st._removeData(e,t+"queue"),st._removeData(e,n)})})}}),st.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?st.queue(this[0],e):n===t?this:this.each(function(){var t=st.queue(this,e,n);st._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&st.dequeue(this,e)})},dequeue:function(e){return this.each(function(){st.dequeue(this,e)})},delay:function(e,t){return e=st.fx?st.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=st.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};for("string"!=typeof e&&(n=e,e=t),e=e||"fx";s--;)r=st._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var Ct,kt,Et=/[\t\r\n]/g,St=/\r/g,At=/^(?:input|select|textarea|button|object)$/i,jt=/^(?:a|area)$/i,Dt=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,Lt=/^(?:checked|selected)$/i,Ht=st.support.getSetAttribute,Mt=st.support.input;st.fn.extend({attr:function(e,t){return st.access(this,st.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){st.removeAttr(this,e)})},prop:function(e,t){return st.access(this,st.prop,e,t,arguments.length>1)},removeProp:function(e){return e=st.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(st.isFunction(e))return this.each(function(t){st(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(lt)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(Et," "):" ")){for(o=0;i=t[o++];)0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=st.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(st.isFunction(e))return this.each(function(t){st(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(lt)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(Et," "):"")){for(o=0;i=t[o++];)for(;r.indexOf(" "+i+" ")>=0;)r=r.replace(" "+i+" "," ");n.className=e?st.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return st.isFunction(e)?this.each(function(n){st(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n)for(var i,o=0,a=st(this),s=t,u=e.match(lt)||[];i=u[o++];)s=r?s:!a.hasClass(i),a[s?"addClass":"removeClass"](i);else("undefined"===n||"boolean"===n)&&(this.className&&st._data(this,"__className__",this.className),this.className=this.className||e===!1?"":st._data(this,"__className__")||"")})},hasClass:function(e){for(var t=" "+e+" ",n=0,r=this.length;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(Et," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=st.isFunction(e),this.each(function(r){var o,a=st(this);1===this.nodeType&&(o=i?e.call(this,r,a.val()):e,null==o?o="":"number"==typeof o?o+="":st.isArray(o)&&(o=st.map(o,function(e){return null==e?"":e+""})),n=st.valHooks[this.type]||st.valHooks[this.nodeName.toLowerCase()],n&&"set"in n&&n.set(this,o,"value")!==t||(this.value=o))});if(o)return n=st.valHooks[o.type]||st.valHooks[o.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(o,"value"))!==t?r:(r=o.value,"string"==typeof r?r.replace(St,""):null==r?"":r)}}}),st.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){for(var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(st.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&st.nodeName(n.parentNode,"optgroup"))){if(t=st(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=st.makeArray(t);return st(e).find("option").each(function(){this.selected=st.inArray(st(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return e.getAttribute===t?st.prop(e,n,r):(a=1!==s||!st.isXMLDoc(e),a&&(n=n.toLowerCase(),o=st.attrHooks[n]||(Dt.test(n)?kt:Ct)),r===t?o&&a&&"get"in o&&null!==(i=o.get(e,n))?i:(e.getAttribute!==t&&(i=e.getAttribute(n)),null==i?t:i):null!==r?o&&a&&"set"in o&&(i=o.set(e,r,n))!==t?i:(e.setAttribute(n,r+""),r):(st.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(lt);if(o&&1===e.nodeType)for(;n=o[i++];)r=st.propFix[n]||n,Dt.test(n)?!Ht&&Lt.test(n)?e[st.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:st.attr(e,n,""),e.removeAttribute(Ht?n:r)},attrHooks:{type:{set:function(e,t){if(!st.support.radioValue&&"radio"===t&&st.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!st.isXMLDoc(e),a&&(n=st.propFix[n]||n,o=st.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):At.test(e.nodeName)||jt.test(e.nodeName)&&e.href?0:t}}}}),kt={get:function(e,n){var r=st.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?Mt&&Ht?null!=i:Lt.test(n)?e[st.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?st.removeAttr(e,n):Mt&&Ht||!Lt.test(n)?e.setAttribute(!Ht&&st.propFix[n]||n,n):e[st.camelCase("default-"+n)]=e[n]=!0,n}},Mt&&Ht||(st.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return st.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t |
|
2 |
+},set:function(e,n,r){return st.nodeName(e,"input")?(e.defaultValue=n,t):Ct&&Ct.set(e,n,r)}}),Ht||(Ct=st.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},st.attrHooks.contenteditable={get:Ct.get,set:function(e,t,n){Ct.set(e,""===t?!1:t,n)}},st.each(["width","height"],function(e,n){st.attrHooks[n]=st.extend(st.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),st.support.hrefNormalized||(st.each(["href","src","width","height"],function(e,n){st.attrHooks[n]=st.extend(st.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),st.each(["href","src"],function(e,t){st.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),st.support.style||(st.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),st.support.optSelected||(st.propHooks.selected=st.extend(st.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),st.support.enctype||(st.propFix.enctype="encoding"),st.support.checkOn||st.each(["radio","checkbox"],function(){st.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),st.each(["radio","checkbox"],function(){st.valHooks[this]=st.extend(st.valHooks[this],{set:function(e,n){return st.isArray(n)?e.checked=st.inArray(st(e).val(),n)>=0:t}})});var qt=/^(?:input|select|textarea)$/i,_t=/^key/,Ft=/^(?:mouse|contextmenu)|click/,Ot=/^(?:focusinfocus|focusoutblur)$/,Bt=/^([^.]*)(?:\.(.+)|)$/;st.event={global:{},add:function(e,n,r,i,o){var a,s,u,l,c,f,p,d,h,g,m,y=3!==e.nodeType&&8!==e.nodeType&&st._data(e);if(y){for(r.handler&&(a=r,r=a.handler,o=a.selector),r.guid||(r.guid=st.guid++),(l=y.events)||(l=y.events={}),(s=y.handle)||(s=y.handle=function(e){return st===t||e&&st.event.triggered===e.type?t:st.event.dispatch.apply(s.elem,arguments)},s.elem=e),n=(n||"").match(lt)||[""],c=n.length;c--;)u=Bt.exec(n[c])||[],h=m=u[1],g=(u[2]||"").split(".").sort(),p=st.event.special[h]||{},h=(o?p.delegateType:p.bindType)||h,p=st.event.special[h]||{},f=st.extend({type:h,origType:m,data:i,handler:r,guid:r.guid,selector:o,needsContext:o&&st.expr.match.needsContext.test(o),namespace:g.join(".")},a),(d=l[h])||(d=l[h]=[],d.delegateCount=0,p.setup&&p.setup.call(e,i,g,s)!==!1||(e.addEventListener?e.addEventListener(h,s,!1):e.attachEvent&&e.attachEvent("on"+h,s))),p.add&&(p.add.call(e,f),f.handler.guid||(f.handler.guid=r.guid)),o?d.splice(d.delegateCount++,0,f):d.push(f),st.event.global[h]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,m=st.hasData(e)&&st._data(e);if(m&&(u=m.events)){for(t=(t||"").match(lt)||[""],l=t.length;l--;)if(s=Bt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){for(f=st.event.special[d]||{},d=(r?f.delegateType:f.bindType)||d,p=u[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;o--;)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&f.teardown.call(e,h,m.handle)!==!1||st.removeEvent(e,d,m.handle),delete u[d])}else for(d in u)st.event.remove(e,d+t[l],n,r,!0);st.isEmptyObject(u)&&(delete m.handle,st._removeData(e,"events"))}},trigger:function(n,r,i,o){var a,s,u,l,c,f,p,d=[i||V],h=n.type||n,g=n.namespace?n.namespace.split("."):[];if(s=u=i=i||V,3!==i.nodeType&&8!==i.nodeType&&!Ot.test(h+st.event.triggered)&&(h.indexOf(".")>=0&&(g=h.split("."),h=g.shift(),g.sort()),c=0>h.indexOf(":")&&"on"+h,n=n[st.expando]?n:new st.Event(h,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=g.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:st.makeArray(r,[n]),p=st.event.special[h]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!st.isWindow(i)){for(l=p.delegateType||h,Ot.test(l+h)||(s=s.parentNode);s;s=s.parentNode)d.push(s),u=s;u===(i.ownerDocument||V)&&d.push(u.defaultView||u.parentWindow||e)}for(a=0;(s=d[a++])&&!n.isPropagationStopped();)n.type=a>1?l:p.bindType||h,f=(st._data(s,"events")||{})[n.type]&&st._data(s,"handle"),f&&f.apply(s,r),f=c&&s[c],f&&st.acceptData(s)&&f.apply&&f.apply(s,r)===!1&&n.preventDefault();if(n.type=h,!(o||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===h&&st.nodeName(i,"a")||!st.acceptData(i)||!c||!i[h]||st.isWindow(i))){u=i[c],u&&(i[c]=null),st.event.triggered=h;try{i[h]()}catch(m){}st.event.triggered=t,u&&(i[c]=u)}return n.result}},dispatch:function(e){e=st.event.fix(e);var n,r,i,o,a,s=[],u=nt.call(arguments),l=(st._data(this,"events")||{})[e.type]||[],c=st.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){for(s=st.event.handlers.call(this,e,l),n=0;(o=s[n++])&&!e.isPropagationStopped();)for(e.currentTarget=o.elem,r=0;(a=o.handlers[r++])&&!e.isImmediatePropagationStopped();)(!e.namespace_re||e.namespace_re.test(a.namespace))&&(e.handleObj=a,e.data=a.data,i=((st.event.special[a.origType]||{}).handle||a.handler).apply(o.elem,u),i!==t&&(e.result=i)===!1&&(e.preventDefault(),e.stopPropagation()));return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(l.disabled!==!0||"click"!==e.type){for(i=[],r=0;u>r;r++)a=n[r],o=a.selector+" ",i[o]===t&&(i[o]=a.needsContext?st(o,this).index(l)>=0:st.find(o,this,null,[l]).length),i[o]&&i.push(a);i.length&&s.push({elem:l,handlers:i})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[st.expando])return e;var t,n,r=e,i=st.event.fixHooks[e.type]||{},o=i.props?this.props.concat(i.props):this.props;for(e=new st.Event(r),t=o.length;t--;)n=o[t],e[n]=r[n];return e.target||(e.target=r.srcElement||V),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,i.filter?i.filter(e,r):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,a=n.button,s=n.fromElement;return null==e.pageX&&null!=n.clientX&&(r=e.target.ownerDocument||V,i=r.documentElement,o=r.body,e.pageX=n.clientX+(i&&i.scrollLeft||o&&o.scrollLeft||0)-(i&&i.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(i&&i.scrollTop||o&&o.scrollTop||0)-(i&&i.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&s&&(e.relatedTarget=s===e.target?n.toElement:s),e.which||a===t||(e.which=1&a?1:2&a?3:4&a?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return st.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==V.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===V.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=st.extend(new st.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?st.event.trigger(i,null,t):st.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},st.removeEvent=V.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,n,r){var i="on"+n;e.detachEvent&&(e[i]===t&&(e[i]=null),e.detachEvent(i,r))},st.Event=function(e,n){return this instanceof st.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?u:l):this.type=e,n&&st.extend(this,n),this.timeStamp=e&&e.timeStamp||st.now(),this[st.expando]=!0,t):new st.Event(e,n)},st.Event.prototype={isDefaultPrevented:l,isPropagationStopped:l,isImmediatePropagationStopped:l,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=u,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=u,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u,this.stopPropagation()}},st.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){st.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!st.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),st.support.submitBubbles||(st.event.special.submit={setup:function(){return st.nodeName(this,"form")?!1:(st.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=st.nodeName(n,"input")||st.nodeName(n,"button")?n.form:t;r&&!st._data(r,"submitBubbles")&&(st.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),st._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&st.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return st.nodeName(this,"form")?!1:(st.event.remove(this,"._submit"),t)}}),st.support.changeBubbles||(st.event.special.change={setup:function(){return qt.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(st.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),st.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),st.event.simulate("change",this,e,!0)})),!1):(st.event.add(this,"beforeactivate._change",function(e){var t=e.target;qt.test(t.nodeName)&&!st._data(t,"changeBubbles")&&(st.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||st.event.simulate("change",this.parentNode,e,!0)}),st._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return st.event.remove(this,"._change"),!qt.test(this.nodeName)}}),st.support.focusinBubbles||st.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){st.event.simulate(t,e.target,st.event.fix(e),!0)};st.event.special[t]={setup:function(){0===n++&&V.addEventListener(e,r,!0)},teardown:function(){0===--n&&V.removeEventListener(e,r,!0)}}}),st.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(s in e)this.on(s,n,r,e[s],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=l;else if(!i)return this;return 1===o&&(a=i,i=function(e){return st().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=st.guid++)),this.each(function(){st.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,st(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=l),this.each(function(){st.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){st.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?st.event.trigger(e,n,r,!0):t},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),st.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){st.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)},_t.test(t)&&(st.event.fixHooks[t]=st.event.keyHooks),Ft.test(t)&&(st.event.fixHooks[t]=st.event.mouseHooks)}),function(e,t){function n(e){return ht.test(e+"")}function r(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>C.cacheLength&&delete e[t.shift()],e[n]=r}}function i(e){return e[P]=!0,e}function o(e){var t=L.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function a(e,t,n,r){var i,o,a,s,u,l,c,d,h,g;if((t?t.ownerDocument||t:R)!==L&&D(t),t=t||L,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!M&&!r){if(i=gt.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&O(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return Q.apply(n,K.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&W.getByClassName&&t.getElementsByClassName)return Q.apply(n,K.call(t.getElementsByClassName(a),0)),n}if(W.qsa&&!q.test(e)){if(c=!0,d=P,h=t,g=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){for(l=f(e),(c=t.getAttribute("id"))?d=c.replace(vt,"\\$&"):t.setAttribute("id",d),d="[id='"+d+"'] ",u=l.length;u--;)l[u]=d+p(l[u]);h=dt.test(e)&&t.parentNode||t,g=l.join(",")}if(g)try{return Q.apply(n,K.call(h.querySelectorAll(g),0)),n}catch(m){}finally{c||t.removeAttribute("id")}}}return x(e.replace(at,"$1"),t,n,r)}function s(e,t){for(var n=e&&t&&e.nextSibling;n;n=n.nextSibling)if(n===t)return-1;return e?1:-1}function u(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function l(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function c(e){return i(function(t){return t=+t,i(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function f(e,t){var n,r,i,o,s,u,l,c=X[e+" "];if(c)return t?0:c.slice(0);for(s=e,u=[],l=C.preFilter;s;){(!n||(r=ut.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(i=[])),n=!1,(r=lt.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(at," ")}),s=s.slice(n.length));for(o in C.filter)!(r=pt[o].exec(s))||l[o]&&!(r=l[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?a.error(e):X(e,u).slice(0)}function p(e){for(var t=0,n=e.length,r="";n>t;t++)r+=e[t].value;return r}function d(e,t,n){var r=t.dir,i=n&&"parentNode"===t.dir,o=I++;return t.first?function(t,n,o){for(;t=t[r];)if(1===t.nodeType||i)return e(t,n,o)}:function(t,n,a){var s,u,l,c=$+" "+o;if(a){for(;t=t[r];)if((1===t.nodeType||i)&&e(t,n,a))return!0}else for(;t=t[r];)if(1===t.nodeType||i)if(l=t[P]||(t[P]={}),(u=l[r])&&u[0]===c){if((s=u[1])===!0||s===N)return s===!0}else if(u=l[r]=[c],u[1]=e(t,n,a)||N,u[1]===!0)return!0}}function h(e){return e.length>1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function m(e,t,n,r,o,a){return r&&!r[P]&&(r=m(r)),o&&!o[P]&&(o=m(o,a)),i(function(i,a,s,u){var l,c,f,p=[],d=[],h=a.length,m=i||b(t||"*",s.nodeType?[s]:s,[]),y=!e||!i&&t?m:g(m,p,e,s,u),v=n?o||(i?e:h||r)?[]:a:y;if(n&&n(y,v,s,u),r)for(l=g(v,d),r(l,[],s,u),c=l.length;c--;)(f=l[c])&&(v[d[c]]=!(y[d[c]]=f));if(i){if(o||e){if(o){for(l=[],c=v.length;c--;)(f=v[c])&&l.push(y[c]=f);o(null,v=[],l,u)}for(c=v.length;c--;)(f=v[c])&&(l=o?Z.call(i,f):p[c])>-1&&(i[l]=!(a[l]=f))}}else v=g(v===a?v.splice(h,v.length):v),o?o(null,a,v,u):Q.apply(a,v)})}function y(e){for(var t,n,r,i=e.length,o=C.relative[e[0].type],a=o||C.relative[" "],s=o?1:0,u=d(function(e){return e===t},a,!0),l=d(function(e){return Z.call(t,e)>-1},a,!0),c=[function(e,n,r){return!o&&(r||n!==j)||((t=n).nodeType?u(e,n,r):l(e,n,r))}];i>s;s++)if(n=C.relative[e[s].type])c=[d(h(c),n)];else{if(n=C.filter[e[s].type].apply(null,e[s].matches),n[P]){for(r=++s;i>r&&!C.relative[e[r].type];r++);return m(s>1&&h(c),s>1&&p(e.slice(0,s-1)).replace(at,"$1"),n,r>s&&y(e.slice(s,r)),i>r&&y(e=e.slice(r)),i>r&&p(e))}c.push(n)}return h(c)}function v(e,t){var n=0,r=t.length>0,o=e.length>0,s=function(i,s,u,l,c){var f,p,d,h=[],m=0,y="0",v=i&&[],b=null!=c,x=j,T=i||o&&C.find.TAG("*",c&&s.parentNode||s),w=$+=null==x?1:Math.E;for(b&&(j=s!==L&&s,N=n);null!=(f=T[y]);y++){if(o&&f){for(p=0;d=e[p];p++)if(d(f,s,u)){l.push(f);break}b&&($=w,N=++n)}r&&((f=!d&&f)&&m--,i&&v.push(f))}if(m+=y,r&&y!==m){for(p=0;d=t[p];p++)d(v,h,s,u);if(i){if(m>0)for(;y--;)v[y]||h[y]||(h[y]=G.call(l));h=g(h)}Q.apply(l,h),b&&!i&&h.length>0&&m+t.length>1&&a.uniqueSort(l)}return b&&($=w,j=x),v};return r?i(s):s}function b(e,t,n){for(var r=0,i=t.length;i>r;r++)a(e,t[r],n);return n}function x(e,t,n,r){var i,o,a,s,u,l=f(e);if(!r&&1===l.length){if(o=l[0]=l[0].slice(0),o.length>2&&"ID"===(a=o[0]).type&&9===t.nodeType&&!M&&C.relative[o[1].type]){if(t=C.find.ID(a.matches[0].replace(xt,Tt),t)[0],!t)return n;e=e.slice(o.shift().value.length)}for(i=pt.needsContext.test(e)?-1:o.length-1;i>=0&&(a=o[i],!C.relative[s=a.type]);i--)if((u=C.find[s])&&(r=u(a.matches[0].replace(xt,Tt),dt.test(o[0].type)&&t.parentNode||t))){if(o.splice(i,1),e=r.length&&p(o),!e)return Q.apply(n,K.call(r,0)),n;break}}return S(e,l)(r,t,M,n,dt.test(e)),n}function T(){}var w,N,C,k,E,S,A,j,D,L,H,M,q,_,F,O,B,P="sizzle"+-new Date,R=e.document,W={},$=0,I=0,z=r(),X=r(),U=r(),V=typeof t,Y=1<<31,J=[],G=J.pop,Q=J.push,K=J.slice,Z=J.indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(this[t]===e)return t;return-1},et="[\\x20\\t\\r\\n\\f]",tt="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",nt=tt.replace("w","w#"),rt="([*^$|!~]?=)",it="\\["+et+"*("+tt+")"+et+"*(?:"+rt+et+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+nt+")|)|)"+et+"*\\]",ot=":("+tt+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+it.replace(3,8)+")*)|.*)\\)|)",at=RegExp("^"+et+"+|((?:^|[^\\\\])(?:\\\\.)*)"+et+"+$","g"),ut=RegExp("^"+et+"*,"+et+"*"),lt=RegExp("^"+et+"*([\\x20\\t\\r\\n\\f>+~])"+et+"*"),ct=RegExp(ot),ft=RegExp("^"+nt+"$"),pt={ID:RegExp("^#("+tt+")"),CLASS:RegExp("^\\.("+tt+")"),NAME:RegExp("^\\[name=['\"]?("+tt+")['\"]?\\]"),TAG:RegExp("^("+tt.replace("w","w*")+")"),ATTR:RegExp("^"+it),PSEUDO:RegExp("^"+ot),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+et+"*(even|odd|(([+-]|)(\\d*)n|)"+et+"*(?:([+-]|)"+et+"*(\\d+)|))"+et+"*\\)|)","i"),needsContext:RegExp("^"+et+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+et+"*((?:-\\d)?\\d*)"+et+"*\\)|)(?=[^-]|$)","i")},dt=/[\x20\t\r\n\f]*[+~]/,ht=/\{\s*\[native code\]\s*\}/,gt=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,mt=/^(?:input|select|textarea|button)$/i,yt=/^h\d$/i,vt=/'|\\/g,bt=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,xt=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,Tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{K.call(H.childNodes,0)[0].nodeType}catch(wt){K=function(e){for(var t,n=[];t=this[e];e++)n.push(t);return n}}E=a.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},D=a.setDocument=function(e){var r=e?e.ownerDocument||e:R;return r!==L&&9===r.nodeType&&r.documentElement?(L=r,H=r.documentElement,M=E(r),W.tagNameNoComments=o(function(e){return e.appendChild(r.createComment("")),!e.getElementsByTagName("*").length}),W.attributes=o(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),W.getByClassName=o(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),W.getByName=o(function(e){e.id=P+0,e.innerHTML="<a name='"+P+"'></a><div name='"+P+"'></div>",H.insertBefore(e,H.firstChild);var t=r.getElementsByName&&r.getElementsByName(P).length===2+r.getElementsByName(P+0).length;return W.getIdNotName=!r.getElementById(P),H.removeChild(e),t}),C.attrHandle=o(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==V&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},W.getIdNotName?(C.find.ID=function(e,t){if(typeof t.getElementById!==V&&!M){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},C.filter.ID=function(e){var t=e.replace(xt,Tt);return function(e){return e.getAttribute("id")===t}}):(C.find.ID=function(e,n){if(typeof n.getElementById!==V&&!M){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==V&&r.getAttributeNode("id").value===e?[r]:t:[]}},C.filter.ID=function(e){var t=e.replace(xt,Tt);return function(e){var n=typeof e.getAttributeNode!==V&&e.getAttributeNode("id");return n&&n.value===t}}),C.find.TAG=W.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==V?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i];i++)1===n.nodeType&&r.push(n);return r}return o},C.find.NAME=W.getByName&&function(e,n){return typeof n.getElementsByName!==V?n.getElementsByName(name):t},C.find.CLASS=W.getByClassName&&function(e,n){return typeof n.getElementsByClassName===V||M?t:n.getElementsByClassName(e)},_=[],q=[":focus"],(W.qsa=n(r.querySelectorAll))&&(o(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||q.push("\\["+et+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||q.push(":checked")}),o(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&q.push("[*^$]="+et+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),q.push(",.*:")})),(W.matchesSelector=n(F=H.matchesSelector||H.mozMatchesSelector||H.webkitMatchesSelector||H.oMatchesSelector||H.msMatchesSelector))&&o(function(e){W.disconnectedMatch=F.call(e,"div"),F.call(e,"[s!='']:x"),_.push("!=",ot)}),q=RegExp(q.join("|")),_=RegExp(_.join("|")),O=n(H.contains)||H.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},B=H.compareDocumentPosition?function(e,t){var n;return e===t?(A=!0,0):(n=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&n||e.parentNode&&11===e.parentNode.nodeType?e===r||O(R,e)?-1:t===r||O(R,t)?1:0:4&n?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var n,i=0,o=e.parentNode,a=t.parentNode,u=[e],l=[t];if(e===t)return A=!0,0;if(e.sourceIndex&&t.sourceIndex)return(~t.sourceIndex||Y)-(O(R,e)&&~e.sourceIndex||Y);if(!o||!a)return e===r?-1:t===r?1:o?-1:a?1:0;if(o===a)return s(e,t);for(n=e;n=n.parentNode;)u.unshift(n);for(n=t;n=n.parentNode;)l.unshift(n);for(;u[i]===l[i];)i++;return i?s(u[i],l[i]):u[i]===R?-1:l[i]===R?1:0},A=!1,[0,0].sort(B),W.detectDuplicates=A,L):L},a.matches=function(e,t){return a(e,null,null,t)},a.matchesSelector=function(e,t){if((e.ownerDocument||e)!==L&&D(e),t=t.replace(bt,"='$1']"),!(!W.matchesSelector||M||_&&_.test(t)||q.test(t)))try{var n=F.call(e,t);if(n||W.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return a(t,L,null,[e]).length>0},a.contains=function(e,t){return(e.ownerDocument||e)!==L&&D(e),O(e,t)},a.attr=function(e,t){var n;return(e.ownerDocument||e)!==L&&D(e),M||(t=t.toLowerCase()),(n=C.attrHandle[t])?n(e):M||W.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},a.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},a.uniqueSort=function(e){var t,n=[],r=1,i=0;if(A=!W.detectDuplicates,e.sort(B),A){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));for(;i--;)e.splice(n[i],1)}return e},k=a.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=k(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=k(t);return n},C=a.selectors={cacheLength:50,createPseudo:i,match:pt,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(xt,Tt),e[3]=(e[4]||e[5]||"").replace(xt,Tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||a.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&a.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return pt.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&ct.test(n)&&(t=f(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(xt,Tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=z[e+" "];return t||(t=RegExp("(^|"+et+")"+e+"("+et+"|$)"))&&z(e,function(e){return t.test(e.className||typeof e.getAttribute!==V&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=a.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.substr(i.length-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){for(;g;){for(f=t;f=f[g];)if(s?f.nodeName.toLowerCase()===y:1===f.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(c=m[P]||(m[P]={}),l=c[e]||[],d=l[0]===$&&l[1],p=l[0]===$&&l[2],f=d&&m.childNodes[d];f=++d&&f&&f[g]||(p=d=0)||h.pop();)if(1===f.nodeType&&++p&&f===t){c[e]=[$,d,p];break}}else if(v&&(l=(t[P]||(t[P]={}))[e])&&l[0]===$)p=l[1];else for(;(f=++d&&f&&f[g]||(p=d=0)||h.pop())&&((s?f.nodeName.toLowerCase()!==y:1!==f.nodeType)||!++p||(v&&((f[P]||(f[P]={}))[e]=[$,p]),f!==t)););return p-=i,p===r||0===p%r&&p/r>=0}}},PSEUDO:function(e,t){var n,r=C.pseudos[e]||C.setFilters[e.toLowerCase()]||a.error("unsupported pseudo: "+e);return r[P]?r(t):r.length>1?(n=[e,e,"",t],C.setFilters.hasOwnProperty(e.toLowerCase())?i(function(e,n){for(var i,o=r(e,t),a=o.length;a--;)i=Z.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:i(function(e){var t=[],n=[],r=S(e.replace(at,"$1"));return r[P]?i(function(e,t,n,i){for(var o,a=r(e,null,i,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:i(function(e){return function(t){return a(e,t).length>0}}),contains:i(function(e){return function(t){return(t.textContent||t.innerText||k(t)).indexOf(e)>-1}}),lang:i(function(e){return ft.test(e||"")||a.error("unsupported lang: "+e),e=e.replace(xt,Tt).toLowerCase(),function(t){var n;do if(n=M?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===H},focus:function(e){return e===L.activeElement&&(!L.hasFocus||L.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!C.pseudos.empty(e)},header:function(e){return yt.test(e.nodeName)},input:function(e){return mt.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:c(function(){return[0]}),last:c(function(e,t){return[t-1]}),eq:c(function(e,t,n){return[0>n?n+t:n]}),even:c(function(e,t){for(var n=0;t>n;n+=2)e.push(n);return e}),odd:c(function(e,t){for(var n=1;t>n;n+=2)e.push(n);return e}),lt:c(function(e,t,n){for(var r=0>n?n+t:n;--r>=0;)e.push(r);return e}),gt:c(function(e,t,n){for(var r=0>n?n+t:n;t>++r;)e.push(r);return e})}};for(w in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})C.pseudos[w]=u(w);for(w in{submit:!0,reset:!0})C.pseudos[w]=l(w);S=a.compile=function(e,t){var n,r=[],i=[],o=U[e+" "];if(!o){for(t||(t=f(e)),n=t.length;n--;)o=y(t[n]),o[P]?r.push(o):i.push(o);o=U(e,v(i,r))}return o},C.pseudos.nth=C.pseudos.eq,C.filters=T.prototype=C.pseudos,C.setFilters=new T,D(),a.attr=st.attr,st.find=a,st.expr=a.selectors,st.expr[":"]=st.expr.pseudos,st.unique=a.uniqueSort,st.text=a.getText,st.isXMLDoc=a.isXML,st.contains=a.contains}(e);var Pt=/Until$/,Rt=/^(?:parents|prev(?:Until|All))/,Wt=/^.[^:#\[\.,]*$/,$t=st.expr.match.needsContext,It={children:!0,contents:!0,next:!0,prev:!0};st.fn.extend({find:function(e){var t,n,r;if("string"!=typeof e)return r=this,this.pushStack(st(e).filter(function(){for(t=0;r.length>t;t++)if(st.contains(r[t],this))return!0}));for(n=[],t=0;this.length>t;t++)st.find(e,this[t],n);return n=this.pushStack(st.unique(n)),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=st(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(st.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(f(this,e,!1))},filter:function(e){return this.pushStack(f(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?$t.test(e)?st(e,this.context).index(this[0])>=0:st.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){for(var n,r=0,i=this.length,o=[],a=$t.test(e)||"string"!=typeof e?st(e,t||this.context):0;i>r;r++)for(n=this[r];n&&n.ownerDocument&&n!==t&&11!==n.nodeType;){if(a?a.index(n)>-1:st.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}return this.pushStack(o.length>1?st.unique(o):o)},index:function(e){return e?"string"==typeof e?st.inArray(this[0],st(e)):st.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?st(e,t):st.makeArray(e&&e.nodeType?[e]:e),r=st.merge(this.get(),n);return this.pushStack(st.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),st.fn.andSelf=st.fn.addBack,st.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return st.dir(e,"parentNode")},parentsUntil:function(e,t,n){return st.dir(e,"parentNode",n)},next:function(e){return c(e,"nextSibling")},prev:function(e){return c(e,"previousSibling") |
|
3 |
+},nextAll:function(e){return st.dir(e,"nextSibling")},prevAll:function(e){return st.dir(e,"previousSibling")},nextUntil:function(e,t,n){return st.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return st.dir(e,"previousSibling",n)},siblings:function(e){return st.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return st.sibling(e.firstChild)},contents:function(e){return st.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:st.merge([],e.childNodes)}},function(e,t){st.fn[e]=function(n,r){var i=st.map(this,t,n);return Pt.test(e)||(r=n),r&&"string"==typeof r&&(i=st.filter(r,i)),i=this.length>1&&!It[e]?st.unique(i):i,this.length>1&&Rt.test(e)&&(i=i.reverse()),this.pushStack(i)}}),st.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?st.find.matchesSelector(t[0],e)?[t[0]]:[]:st.find.matches(e,t)},dir:function(e,n,r){for(var i=[],o=e[n];o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!st(o).is(r));)1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});var zt="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",Xt=/ jQuery\d+="(?:null|\d+)"/g,Ut=RegExp("<(?:"+zt+")[\\s/>]","i"),Vt=/^\s+/,Yt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Jt=/<([\w:]+)/,Gt=/<tbody/i,Qt=/<|&#?\w+;/,Kt=/<(?:script|style|link)/i,Zt=/^(?:checkbox|radio)$/i,en=/checked\s*(?:[^=]|=\s*.checked.)/i,tn=/^$|\/(?:java|ecma)script/i,nn=/^true\/(.*)/,rn=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,on={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:st.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},an=p(V),sn=an.appendChild(V.createElement("div"));on.optgroup=on.option,on.tbody=on.tfoot=on.colgroup=on.caption=on.thead,on.th=on.td,st.fn.extend({text:function(e){return st.access(this,function(e){return e===t?st.text(this):this.empty().append((this[0]&&this[0].ownerDocument||V).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(st.isFunction(e))return this.each(function(t){st(this).wrapAll(e.call(this,t))});if(this[0]){var t=st(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstChild&&1===e.firstChild.nodeType;)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return st.isFunction(e)?this.each(function(t){st(this).wrapInner(e.call(this,t))}):this.each(function(){var t=st(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=st.isFunction(e);return this.each(function(n){st(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){st.nodeName(this,"body")||st(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){for(var n,r=0;null!=(n=this[r]);r++)(!e||st.filter(e,[n]).length>0)&&(t||1!==n.nodeType||st.cleanData(b(n)),n.parentNode&&(t&&st.contains(n.ownerDocument,n)&&m(b(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&st.cleanData(b(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&st.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return st.clone(this,e,t)})},html:function(e){return st.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(Xt,""):t;if(!("string"!=typeof e||Kt.test(e)||!st.support.htmlSerialize&&Ut.test(e)||!st.support.leadingWhitespace&&Vt.test(e)||on[(Jt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(Yt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(st.cleanData(b(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=st.isFunction(e);return t||"string"==typeof e||(e=st(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;(n&&1===this.nodeType||11===this.nodeType)&&(st(this).remove(),t?t.parentNode.insertBefore(e,t):n.appendChild(e))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=et.apply([],e);var i,o,a,s,u,l,c=0,f=this.length,p=this,m=f-1,y=e[0],v=st.isFunction(y);if(v||!(1>=f||"string"!=typeof y||st.support.checkClone)&&en.test(y))return this.each(function(i){var o=p.eq(i);v&&(e[0]=y.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(f&&(i=st.buildFragment(e,this[0].ownerDocument,!1,this),o=i.firstChild,1===i.childNodes.length&&(i=o),o)){for(n=n&&st.nodeName(o,"tr"),a=st.map(b(i,"script"),h),s=a.length;f>c;c++)u=i,c!==m&&(u=st.clone(u,!0,!0),s&&st.merge(a,b(u,"script"))),r.call(n&&st.nodeName(this[c],"table")?d(this[c],"tbody"):this[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,st.map(a,g),c=0;s>c;c++)u=a[c],tn.test(u.type||"")&&!st._data(u,"globalEval")&&st.contains(l,u)&&(u.src?st.ajax({url:u.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):st.globalEval((u.text||u.textContent||u.innerHTML||"").replace(rn,"")));i=o=null}return this}}),st.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){st.fn[e]=function(e){for(var n,r=0,i=[],o=st(e),a=o.length-1;a>=r;r++)n=r===a?this:this.clone(!0),st(o[r])[t](n),tt.apply(i,n.get());return this.pushStack(i)}}),st.extend({clone:function(e,t,n){var r,i,o,a,s,u=st.contains(e.ownerDocument,e);if(st.support.html5Clone||st.isXMLDoc(e)||!Ut.test("<"+e.nodeName+">")?s=e.cloneNode(!0):(sn.innerHTML=e.outerHTML,sn.removeChild(s=sn.firstChild)),!(st.support.noCloneEvent&&st.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||st.isXMLDoc(e)))for(r=b(s),i=b(e),a=0;null!=(o=i[a]);++a)r[a]&&v(o,r[a]);if(t)if(n)for(i=i||b(e),r=r||b(s),a=0;null!=(o=i[a]);a++)y(o,r[a]);else y(e,s);return r=b(s,"script"),r.length>0&&m(r,!u&&b(e,"script")),r=i=o=null,s},buildFragment:function(e,t,n,r){for(var i,o,a,s,u,l,c,f=e.length,d=p(t),h=[],g=0;f>g;g++)if(o=e[g],o||0===o)if("object"===st.type(o))st.merge(h,o.nodeType?[o]:o);else if(Qt.test(o)){for(s=s||d.appendChild(t.createElement("div")),a=(Jt.exec(o)||["",""])[1].toLowerCase(),u=on[a]||on._default,s.innerHTML=u[1]+o.replace(Yt,"<$1></$2>")+u[2],c=u[0];c--;)s=s.lastChild;if(!st.support.leadingWhitespace&&Vt.test(o)&&h.push(t.createTextNode(Vt.exec(o)[0])),!st.support.tbody)for(o="table"!==a||Gt.test(o)?"<table>"!==u[1]||Gt.test(o)?0:s:s.firstChild,c=o&&o.childNodes.length;c--;)st.nodeName(l=o.childNodes[c],"tbody")&&!l.childNodes.length&&o.removeChild(l);for(st.merge(h,s.childNodes),s.textContent="";s.firstChild;)s.removeChild(s.firstChild);s=d.lastChild}else h.push(t.createTextNode(o));for(s&&d.removeChild(s),st.support.appendChecked||st.grep(b(h,"input"),x),g=0;o=h[g++];)if((!r||-1===st.inArray(o,r))&&(i=st.contains(o.ownerDocument,o),s=b(d.appendChild(o),"script"),i&&m(s),n))for(c=0;o=s[c++];)tn.test(o.type||"")&&n.push(o);return s=null,d},cleanData:function(e,n){for(var r,i,o,a,s=0,u=st.expando,l=st.cache,c=st.support.deleteExpando,f=st.event.special;null!=(o=e[s]);s++)if((n||st.acceptData(o))&&(i=o[u],r=i&&l[i])){if(r.events)for(a in r.events)f[a]?st.event.remove(o,a):st.removeEvent(o,a,r.handle);l[i]&&(delete l[i],c?delete o[u]:o.removeAttribute!==t?o.removeAttribute(u):o[u]=null,K.push(i))}}});var un,ln,cn,fn=/alpha\([^)]*\)/i,pn=/opacity\s*=\s*([^)]*)/,dn=/^(top|right|bottom|left)$/,hn=/^(none|table(?!-c[ea]).+)/,gn=/^margin/,mn=RegExp("^("+ut+")(.*)$","i"),yn=RegExp("^("+ut+")(?!px)[a-z%]+$","i"),vn=RegExp("^([+-])=("+ut+")","i"),bn={BODY:"block"},xn={position:"absolute",visibility:"hidden",display:"block"},Tn={letterSpacing:0,fontWeight:400},wn=["Top","Right","Bottom","Left"],Nn=["Webkit","O","Moz","ms"];st.fn.extend({css:function(e,n){return st.access(this,function(e,n,r){var i,o,a={},s=0;if(st.isArray(n)){for(i=ln(e),o=n.length;o>s;s++)a[n[s]]=st.css(e,n[s],!1,i);return a}return r!==t?st.style(e,n,r):st.css(e,n)},e,n,arguments.length>1)},show:function(){return N(this,!0)},hide:function(){return N(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:w(this))?st(this).show():st(this).hide()})}}),st.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=un(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":st.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=st.camelCase(n),l=e.style;if(n=st.cssProps[u]||(st.cssProps[u]=T(l,u)),s=st.cssHooks[n]||st.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=vn.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(st.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||st.cssNumber[u]||(r+="px"),st.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=st.camelCase(n);return n=st.cssProps[u]||(st.cssProps[u]=T(e.style,u)),s=st.cssHooks[n]||st.cssHooks[u],s&&"get"in s&&(o=s.get(e,!0,r)),o===t&&(o=un(e,n,i)),"normal"===o&&n in Tn&&(o=Tn[n]),r?(a=parseFloat(o),r===!0||st.isNumeric(a)?a||0:o):o},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(ln=function(t){return e.getComputedStyle(t,null)},un=function(e,n,r){var i,o,a,s=r||ln(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||st.contains(e.ownerDocument,e)||(u=st.style(e,n)),yn.test(u)&&gn.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):V.documentElement.currentStyle&&(ln=function(e){return e.currentStyle},un=function(e,n,r){var i,o,a,s=r||ln(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),yn.test(u)&&!dn.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u}),st.each(["height","width"],function(e,n){st.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&hn.test(st.css(e,"display"))?st.swap(e,xn,function(){return E(e,n,i)}):E(e,n,i):t},set:function(e,t,r){var i=r&&ln(e);return C(e,t,r?k(e,n,r,st.support.boxSizing&&"border-box"===st.css(e,"boxSizing",!1,i),i):0)}}}),st.support.opacity||(st.cssHooks.opacity={get:function(e,t){return pn.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=st.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===st.trim(o.replace(fn,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=fn.test(o)?o.replace(fn,i):o+" "+i)}}),st(function(){st.support.reliableMarginRight||(st.cssHooks.marginRight={get:function(e,n){return n?st.swap(e,{display:"inline-block"},un,[e,"marginRight"]):t}}),!st.support.pixelPosition&&st.fn.position&&st.each(["top","left"],function(e,n){st.cssHooks[n]={get:function(e,r){return r?(r=un(e,n),yn.test(r)?st(e).position()[n]+"px":r):t}}})}),st.expr&&st.expr.filters&&(st.expr.filters.hidden=function(e){return 0===e.offsetWidth&&0===e.offsetHeight||!st.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||st.css(e,"display"))},st.expr.filters.visible=function(e){return!st.expr.filters.hidden(e)}),st.each({margin:"",padding:"",border:"Width"},function(e,t){st.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];4>r;r++)i[e+wn[r]+t]=o[r]||o[r-2]||o[0];return i}},gn.test(e)||(st.cssHooks[e+t].set=C)});var Cn=/%20/g,kn=/\[\]$/,En=/\r?\n/g,Sn=/^(?:submit|button|image|reset)$/i,An=/^(?:input|select|textarea|keygen)/i;st.fn.extend({serialize:function(){return st.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=st.prop(this,"elements");return e?st.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!st(this).is(":disabled")&&An.test(this.nodeName)&&!Sn.test(e)&&(this.checked||!Zt.test(e))}).map(function(e,t){var n=st(this).val();return null==n?null:st.isArray(n)?st.map(n,function(e){return{name:t.name,value:e.replace(En,"\r\n")}}):{name:t.name,value:n.replace(En,"\r\n")}}).get()}}),st.param=function(e,n){var r,i=[],o=function(e,t){t=st.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=st.ajaxSettings&&st.ajaxSettings.traditional),st.isArray(e)||e.jquery&&!st.isPlainObject(e))st.each(e,function(){o(this.name,this.value)});else for(r in e)j(r,e[r],n,o);return i.join("&").replace(Cn,"+")};var jn,Dn,Ln=st.now(),Hn=/\?/,Mn=/#.*$/,qn=/([?&])_=[^&]*/,_n=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Fn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,On=/^(?:GET|HEAD)$/,Bn=/^\/\//,Pn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Rn=st.fn.load,Wn={},$n={},In="*/".concat("*");try{Dn=Y.href}catch(zn){Dn=V.createElement("a"),Dn.href="",Dn=Dn.href}jn=Pn.exec(Dn.toLowerCase())||[],st.fn.load=function(e,n,r){if("string"!=typeof e&&Rn)return Rn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),st.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(o="POST"),s.length>0&&st.ajax({url:e,type:o,dataType:"html",data:n}).done(function(e){a=arguments,s.html(i?st("<div>").append(st.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,a||[e.responseText,t,e])}),this},st.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){st.fn[t]=function(e){return this.on(t,e)}}),st.each(["get","post"],function(e,n){st[n]=function(e,r,i,o){return st.isFunction(r)&&(o=o||i,i=r,r=t),st.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),st.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Dn,type:"GET",isLocal:Fn.test(jn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":In,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":st.parseJSON,"text xml":st.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?H(H(e,st.ajaxSettings),t):H(st.ajaxSettings,e)},ajaxPrefilter:D(Wn),ajaxTransport:D($n),ajax:function(e,n){function r(e,n,r,s){var l,f,v,b,T,N=n;2!==x&&(x=2,u&&clearTimeout(u),i=t,a=s||"",w.readyState=e>0?4:0,r&&(b=M(p,w,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=w.getResponseHeader("Last-Modified"),T&&(st.lastModified[o]=T),T=w.getResponseHeader("etag"),T&&(st.etag[o]=T)),304===e?(l=!0,N="notmodified"):(l=q(p,b),N=l.state,f=l.data,v=l.error,l=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),w.status=e,w.statusText=(n||N)+"",l?g.resolveWith(d,[f,N,w]):g.rejectWith(d,[w,N,v]),w.statusCode(y),y=t,c&&h.trigger(l?"ajaxSuccess":"ajaxError",[w,p,l?f:v]),m.fireWith(d,[w,N]),c&&(h.trigger("ajaxComplete",[w,p]),--st.active||st.event.trigger("ajaxStop")))}"object"==typeof e&&(n=e,e=t),n=n||{};var i,o,a,s,u,l,c,f,p=st.ajaxSetup({},n),d=p.context||p,h=p.context&&(d.nodeType||d.jquery)?st(d):st.event,g=st.Deferred(),m=st.Callbacks("once memory"),y=p.statusCode||{},v={},b={},x=0,T="canceled",w={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!s)for(s={};t=_n.exec(a);)s[t[1].toLowerCase()]=t[2];t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=b[n]=b[n]||e,v[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)y[t]=[y[t],e[t]];else w.always(e[w.status]);return this},abort:function(e){var t=e||T;return i&&i.abort(t),r(0,t),this}};if(g.promise(w).complete=m.add,w.success=w.done,w.error=w.fail,p.url=((e||p.url||Dn)+"").replace(Mn,"").replace(Bn,jn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=st.trim(p.dataType||"*").toLowerCase().match(lt)||[""],null==p.crossDomain&&(l=Pn.exec(p.url.toLowerCase()),p.crossDomain=!(!l||l[1]===jn[1]&&l[2]===jn[2]&&(l[3]||("http:"===l[1]?80:443))==(jn[3]||("http:"===jn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=st.param(p.data,p.traditional)),L(Wn,p,n,w),2===x)return w;c=p.global,c&&0===st.active++&&st.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!On.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(Hn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=qn.test(o)?o.replace(qn,"$1_="+Ln++):o+(Hn.test(o)?"&":"?")+"_="+Ln++)),p.ifModified&&(st.lastModified[o]&&w.setRequestHeader("If-Modified-Since",st.lastModified[o]),st.etag[o]&&w.setRequestHeader("If-None-Match",st.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&w.setRequestHeader("Content-Type",p.contentType),w.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+In+"; q=0.01":""):p.accepts["*"]);for(f in p.headers)w.setRequestHeader(f,p.headers[f]);if(p.beforeSend&&(p.beforeSend.call(d,w,p)===!1||2===x))return w.abort();T="abort";for(f in{success:1,error:1,complete:1})w[f](p[f]);if(i=L($n,p,n,w)){w.readyState=1,c&&h.trigger("ajaxSend",[w,p]),p.async&&p.timeout>0&&(u=setTimeout(function(){w.abort("timeout")},p.timeout));try{x=1,i.send(v,r)}catch(N){if(!(2>x))throw N;r(-1,N)}}else r(-1,"No Transport");return w},getScript:function(e,n){return st.get(e,t,n,"script")},getJSON:function(e,t,n){return st.get(e,t,n,"json")}}),st.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return st.globalEval(e),e}}}),st.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),st.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=V.head||st("head")[0]||V.documentElement;return{send:function(t,i){n=V.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Xn=[],Un=/(=)\?(?=&|$)|\?\?/;st.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xn.pop()||st.expando+"_"+Ln++;return this[e]=!0,e}}),st.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Un.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Un.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=st.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Un,"$1"+o):n.jsonp!==!1&&(n.url+=(Hn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||st.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Xn.push(o)),s&&st.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Vn,Yn,Jn=0,Gn=e.ActiveXObject&&function(){var e;for(e in Vn)Vn[e](t,!0)};st.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&_()||F()}:_,Yn=st.ajaxSettings.xhr(),st.support.cors=!!Yn&&"withCredentials"in Yn,Yn=st.support.ajax=!!Yn,Yn&&st.ajaxTransport(function(n){if(!n.crossDomain||st.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,f,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=st.noop,Gn&&delete Vn[a]),i)4!==u.readyState&&u.abort();else{f={},s=u.status,p=u.responseXML,c=u.getAllResponseHeaders(),p&&p.documentElement&&(f.xml=p),"string"==typeof u.responseText&&(f.text=u.responseText);try{l=u.statusText}catch(d){l=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=f.text?200:404}}catch(h){i||o(-1,h)}f&&o(s,l,f,c)},n.async?4===u.readyState?setTimeout(r):(a=++Jn,Gn&&(Vn||(Vn={},st(e).unload(Gn)),Vn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Qn,Kn,Zn=/^(?:toggle|show|hide)$/,er=RegExp("^(?:([+-])=|)("+ut+")([a-z%]*)$","i"),tr=/queueHooks$/,nr=[W],rr={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=er.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(st.cssNumber[e]?"":"px"),"px"!==r&&s){s=st.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,st.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};st.Animation=st.extend(P,{tweener:function(e,t){st.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");for(var n,r=0,i=e.length;i>r;r++)n=e[r],rr[n]=rr[n]||[],rr[n].unshift(t)},prefilter:function(e,t){t?nr.unshift(e):nr.push(e)}}),st.Tween=$,$.prototype={constructor:$,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(st.cssNumber[n]?"":"px")},cur:function(){var e=$.propHooks[this.prop];return e&&e.get?e.get(this):$.propHooks._default.get(this)},run:function(e){var t,n=$.propHooks[this.prop];return this.pos=t=this.options.duration?st.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):$.propHooks._default.set(this),this}},$.prototype.init.prototype=$.prototype,$.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=st.css(e.elem,e.prop,"auto"),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){st.fx.step[e.prop]?st.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[st.cssProps[e.prop]]||st.cssHooks[e.prop])?st.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},$.propHooks.scrollTop=$.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},st.each(["toggle","show","hide"],function(e,t){var n=st.fn[t];st.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(I(t,!0),e,r,i)}}),st.fn.extend({fadeTo:function(e,t,n,r){return this.filter(w).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=st.isEmptyObject(e),o=st.speed(t,n,r),a=function(){var t=P(this,st.extend({},e),o);a.finish=function(){t.stop(!0)},(i||st._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=st.timers,a=st._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&tr.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&st.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=st._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=st.timers,a=r?r.length:0;for(n.finish=!0,st.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}}),st.each({slideDown:I("show"),slideUp:I("hide"),slideToggle:I("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){st.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),st.speed=function(e,t,n){var r=e&&"object"==typeof e?st.extend({},e):{complete:n||!n&&t||st.isFunction(e)&&e,duration:e,easing:n&&t||t&&!st.isFunction(t)&&t};return r.duration=st.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in st.fx.speeds?st.fx.speeds[r.duration]:st.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){st.isFunction(r.old)&&r.old.call(this),r.queue&&st.dequeue(this,r.queue)},r},st.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},st.timers=[],st.fx=$.prototype.init,st.fx.tick=function(){var e,n=st.timers,r=0;for(Qn=st.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||st.fx.stop(),Qn=t},st.fx.timer=function(e){e()&&st.timers.push(e)&&st.fx.start()},st.fx.interval=13,st.fx.start=function(){Kn||(Kn=setInterval(st.fx.tick,st.fx.interval))},st.fx.stop=function(){clearInterval(Kn),Kn=null},st.fx.speeds={slow:600,fast:200,_default:400},st.fx.step={},st.expr&&st.expr.filters&&(st.expr.filters.animated=function(e){return st.grep(st.timers,function(t){return e===t.elem}).length}),st.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){st.offset.setOffset(this,e,t)});var n,r,i={top:0,left:0},o=this[0],a=o&&o.ownerDocument;if(a)return n=a.documentElement,st.contains(n,o)?(o.getBoundingClientRect!==t&&(i=o.getBoundingClientRect()),r=z(a),{top:i.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:i.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):i},st.offset={setOffset:function(e,t,n){var r=st.css(e,"position");"static"===r&&(e.style.position="relative");var i,o,a=st(e),s=a.offset(),u=st.css(e,"top"),l=st.css(e,"left"),c=("absolute"===r||"fixed"===r)&&st.inArray("auto",[u,l])>-1,f={},p={};c?(p=a.position(),i=p.top,o=p.left):(i=parseFloat(u)||0,o=parseFloat(l)||0),st.isFunction(t)&&(t=t.call(e,n,s)),null!=t.top&&(f.top=t.top-s.top+i),null!=t.left&&(f.left=t.left-s.left+o),"using"in t?t.using.call(e,f):a.css(f)}},st.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===st.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),st.nodeName(e[0],"html")||(n=e.offset()),n.top+=st.css(e[0],"borderTopWidth",!0),n.left+=st.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-st.css(r,"marginTop",!0),left:t.left-n.left-st.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent||V.documentElement;e&&!st.nodeName(e,"html")&&"static"===st.css(e,"position");)e=e.offsetParent;return e||V.documentElement})}}),st.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);st.fn[e]=function(i){return st.access(this,function(e,i,o){var a=z(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?st(a).scrollLeft():o,r?o:st(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}}),st.each({Height:"height",Width:"width"},function(e,n){st.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){st.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return st.access(this,function(n,r,i){var o;return st.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?st.css(n,r,s):st.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=st,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return st})})(window); |
|
4 |
+//@ sourceMappingURL=jquery.min.map |
... | ... |
@@ -0,0 +1,2 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["com",/^#[^\n\r]*/,null,"#"],["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"']],[["kwd",/^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/, |
|
2 |
+null],["typ",/^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[ES]?BANK=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[!-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["apollo","agc","aea"]); |
... | ... |
@@ -0,0 +1,18 @@ |
1 |
+/* |
|
2 |
+ Copyright (C) 2011 Google Inc. |
|
3 |
+ |
|
4 |
+ Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 |
+ you may not use this file except in compliance with the License. |
|
6 |
+ You may obtain a copy of the License at |
|
7 |
+ |
|
8 |
+ http://www.apache.org/licenses/LICENSE-2.0 |
|
9 |
+ |
|
10 |
+ Unless required by applicable law or agreed to in writing, software |
|
11 |
+ distributed under the License is distributed on an "AS IS" BASIS, |
|
12 |
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 |
+ See the License for the specific language governing permissions and |
|
14 |
+ limitations under the License. |
|
15 |
+*/ |
|
16 |
+var a=null; |
|
17 |
+PR.registerLangHandler(PR.createSimpleLexer([["opn",/^[([{]+/,a,"([{"],["clo",/^[)\]}]+/,a,")]}"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:def|if|do|let|quote|var|fn|loop|recur|throw|try|monitor-enter|monitor-exit|defmacro|defn|defn-|macroexpand|macroexpand-1|for|doseq|dosync|dotimes|and|or|when|not|assert|doto|proxy|defstruct|first|rest|cons|defprotocol|deftype|defrecord|reify|defmulti|defmethod|meta|with-meta|ns|in-ns|create-ns|import|intern|refer|alias|namespace|resolve|ref|deref|refset|new|set!|memfn|to-array|into-array|aset|gen-class|reduce|map|filter|find|nil?|empty?|hash-map|hash-set|vec|vector|seq|flatten|reverse|assoc|dissoc|list|list?|disj|get|union|difference|intersection|extend|extend-type|extend-protocol|prn)\b/,a], |
|
18 |
+["typ",/^:[\dA-Za-z-]+/]]),["clj"]); |
... | ... |
@@ -0,0 +1,2 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", |
|
2 |
+/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); |
... | ... |
@@ -0,0 +1 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]); |
... | ... |
@@ -0,0 +1,2 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^\n\f\r'\\]|\\[^&])'?/,null,"'"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^(?:--+[^\n\f\r]*|{-(?:[^-]|-+[^}-])*-})/],["kwd",/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^\d'A-Za-z]|$)/, |
|
2 |
+null],["pln",/^(?:[A-Z][\w']*\.)*[A-Za-z][\w']*/],["pun",/^[^\d\t-\r "'A-Za-z]+/]]),["hs"]); |
... | ... |
@@ -0,0 +1,3 @@ |
1 |
+var a=null; |
|
2 |
+PR.registerLangHandler(PR.createSimpleLexer([["opn",/^\(+/,a,"("],["clo",/^\)+/,a,")"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/,a], |
|
3 |
+["lit",/^[+-]?(?:[#0]x[\da-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[de][+-]?\d+)?)/i],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[_a-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/i],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["cl","el","lisp","scm"]); |
... | ... |
@@ -0,0 +1,2 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$))/,null,"\"'"]],[["com",/^--(?:\[(=*)\[[\S\s]*?(?:]\1]|$)|[^\n\r]*)/],["str",/^\[(=*)\[[\S\s]*?(?:]\1]|$)/],["kwd",/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i], |
|
2 |
+["pln",/^[_a-z]\w*/i],["pun",/^[^\w\t\n\r \xa0][^\w\t\n\r "'+=\xa0-]*/]]),["lua"]); |
... | ... |
@@ -0,0 +1,2 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["com",/^#(?:if[\t\n\r \xa0]+(?:[$_a-z][\w']*|``[^\t\n\r`]*(?:``|$))|else|endif|light)/i,null,"#"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])(?:'|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\(\*[\S\s]*?\*\))/],["kwd",/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/], |
|
2 |
+["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^(?:[_a-z][\w']*[!#?]?|``[^\t\n\r`]*(?:``|$))/i],["pun",/^[^\w\t\n\r "'\xa0]+/]]),["fs","ml"]); |
... | ... |
@@ -0,0 +1,4 @@ |
1 |
+var a=null; |
|
2 |
+PR.registerLangHandler(PR.createSimpleLexer([["str",/^(?:'(?:[^\n\r'\\]|\\.)*'|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,a,'"'],["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,a,"#"],["pln",/^\s+/,a," \r\n\t\xa0"]],[["str",/^@"(?:[^"]|"")*(?:"|$)/,a],["str",/^<#[^#>]*(?:#>|$)/,a],["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,a],["com",/^\/\/[^\n\r]*/,a],["com",/^\/\*[\S\s]*?(?:\*\/|$)/, |
|
3 |
+a],["kwd",/^(?:abstract|and|as|base|catch|class|def|delegate|enum|event|extern|false|finally|fun|implements|interface|internal|is|macro|match|matches|module|mutable|namespace|new|null|out|override|params|partial|private|protected|public|ref|sealed|static|struct|syntax|this|throw|true|try|type|typeof|using|variant|virtual|volatile|when|where|with|assert|assert2|async|break|checked|continue|do|else|ensures|for|foreach|if|late|lock|new|nolate|otherwise|regexp|repeat|requires|return|surroundwith|unchecked|unless|using|while|yield)\b/, |
|
4 |
+a],["typ",/^(?:array|bool|byte|char|decimal|double|float|int|list|long|object|sbyte|short|string|ulong|uint|ufloat|ulong|ushort|void)\b/,a],["lit",/^@[$_a-z][\w$@]*/i,a],["typ",/^@[A-Z]+[a-z][\w$@]*/,a],["pln",/^'?[$_a-z][\w$@]*/i,a],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,a,"0123456789"],["pun",/^.[^\s\w"-$'./@`]*/,a]]),["n","nemerle"]); |
... | ... |
@@ -0,0 +1 @@ |
1 |
+PR.registerLangHandler(PR.sourceDecorator({keywords:"bytes,default,double,enum,extend,extensions,false,group,import,max,message,option,optional,package,repeated,required,returns,rpc,service,syntax,to,true",types:/^(bool|(double|s?fixed|[su]?int)(32|64)|float|string)\b/,cStyleComments:!0}),["proto"]); |
... | ... |
@@ -0,0 +1,2 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["str",/^"(?:""(?:""?(?!")|[^"\\]|\\.)*"{0,3}|(?:[^\n\r"\\]|\\.)*"?)/,null,'"'],["lit",/^`(?:[^\n\r\\`]|\\.)*`?/,null,"`"],["pun",/^[!#%&(--:-@[-^{-~]+/,null,"!#%&()*+,-:;<=>?@[\\]^{|}~"]],[["str",/^'(?:[^\n\r'\\]|\\(?:'|[^\n\r']+))'/],["lit",/^'[$A-Z_a-z][\w$]*(?![\w$'])/],["kwd",/^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/], |
|
2 |
+["lit",/^(?:true|false|null|this)\b/],["lit",/^(?:0(?:[0-7]+|x[\da-f]+)l?|(?:0|[1-9]\d*)(?:(?:\.\d+)?(?:e[+-]?\d+)?f?|l?)|\\.\d+(?:e[+-]?\d+)?f?)/i],["typ",/^[$_]*[A-Z][\d$A-Z_]*[a-z][\w$]*/],["pln",/^[$A-Z_a-z][\w$]*/],["com",/^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/],["pun",/^(?:\.+|\/)/]]),["scala"]); |
... | ... |
@@ -0,0 +1,2 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["str",/^(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,null,"\"'"]],[["com",/^(?:--[^\n\r]*|\/\*[\S\s]*?(?:\*\/|$))/],["kwd",/^(?:add|all|alter|and|any|as|asc|authorization|backup|begin|between|break|browse|bulk|by|cascade|case|check|checkpoint|close|clustered|coalesce|collate|column|commit|compute|constraint|contains|containstable|continue|convert|create|cross|current|current_date|current_time|current_timestamp|current_user|cursor|database|dbcc|deallocate|declare|default|delete|deny|desc|disk|distinct|distributed|double|drop|dummy|dump|else|end|errlvl|escape|except|exec|execute|exists|exit|fetch|file|fillfactor|for|foreign|freetext|freetexttable|from|full|function|goto|grant|group|having|holdlock|identity|identitycol|identity_insert|if|in|index|inner|insert|intersect|into|is|join|key|kill|left|like|lineno|load|match|merge|national|nocheck|nonclustered|not|null|nullif|of|off|offsets|on|open|opendatasource|openquery|openrowset|openxml|option|or|order|outer|over|percent|plan|precision|primary|print|proc|procedure|public|raiserror|read|readtext|reconfigure|references|replication|restore|restrict|return|revoke|right|rollback|rowcount|rowguidcol|rule|save|schema|select|session_user|set|setuser|shutdown|some|statistics|system_user|table|textsize|then|to|top|tran|transaction|trigger|truncate|tsequal|union|unique|update|updatetext|use|user|using|values|varying|view|waitfor|when|where|while|with|writetext)(?=[^\w-]|$)/i, |
|
2 |
+null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^[_a-z][\w-]*/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'+\xa0-]*/]]),["sql"]); |
... | ... |
@@ -0,0 +1 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"],["com",/^%[^\n\r]*/,null,"%"]],[["kwd",/^\\[@-Za-z]+/],["kwd",/^\\./],["typ",/^[$&]/],["lit",/[+-]?(?:\.\d+|\d+(?:\.\d*)?)(cm|em|ex|in|pc|pt|bp|mm)/i],["pun",/^[()=[\]{}]+/]]),["latex","tex"]); |
... | ... |
@@ -0,0 +1,2 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0\u2028\u2029]+/,null,"\t\n\r �\xa0 "],["str",/^(?:["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})(?:["\u201c\u201d]c|$)|["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})*(?:["\u201c\u201d]|$))/i,null,'"“”'],["com",/^['\u2018\u2019].*/,null,"'‘’"]],[["kwd",/^(?:addhandler|addressof|alias|and|andalso|ansi|as|assembly|auto|boolean|byref|byte|byval|call|case|catch|cbool|cbyte|cchar|cdate|cdbl|cdec|char|cint|class|clng|cobj|const|cshort|csng|cstr|ctype|date|decimal|declare|default|delegate|dim|directcast|do|double|each|else|elseif|end|endif|enum|erase|error|event|exit|finally|for|friend|function|get|gettype|gosub|goto|handles|if|implements|imports|in|inherits|integer|interface|is|let|lib|like|long|loop|me|mod|module|mustinherit|mustoverride|mybase|myclass|namespace|new|next|not|notinheritable|notoverridable|object|on|option|optional|or|orelse|overloads|overridable|overrides|paramarray|preserve|private|property|protected|public|raiseevent|readonly|redim|removehandler|resume|return|select|set|shadows|shared|short|single|static|step|stop|string|structure|sub|synclock|then|throw|to|try|typeof|unicode|until|variant|wend|when|while|with|withevents|writeonly|xor|endif|gosub|let|variant|wend)\b/i, |
|
2 |
+null],["com",/^rem.*/i],["lit",/^(?:true\b|false\b|nothing\b|\d+(?:e[+-]?\d+[dfr]?|[dfilrs])?|(?:&h[\da-f]+|&o[0-7]+)[ils]?|\d*\.\d+(?:e[+-]?\d+)?[dfr]?|#\s+(?:\d+[/-]\d+[/-]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:am|pm))?)?|\d+:\d+(?::\d+)?(\s*(?:am|pm))?)\s+#)/i],["pln",/^(?:(?:[a-z]|_\w)\w*|\[(?:[a-z]|_\w)\w*])/i],["pun",/^[^\w\t\n\r "'[\]\xa0\u2018\u2019\u201c\u201d\u2028\u2029]+/],["pun",/^(?:\[|])/]]),["vb","vbs"]); |
... | ... |
@@ -0,0 +1,3 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r �\xa0"]],[["str",/^(?:[box]?"(?:[^"]|"")*"|'.')/i],["com",/^--[^\n\r]*/],["kwd",/^(?:abs|access|after|alias|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|mod|nand|new|next|nor|not|null|of|on|open|or|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|rem|report|return|rol|ror|select|severity|shared|signal|sla|sll|sra|srl|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with|xnor|xor)(?=[^\w-]|$)/i, |
|
2 |
+null],["typ",/^(?:bit|bit_vector|character|boolean|integer|real|time|string|severity_level|positive|natural|signed|unsigned|line|text|std_u?logic(?:_vector)?)(?=[^\w-]|$)/i,null],["typ",/^'(?:active|ascending|base|delayed|driving|driving_value|event|high|image|instance_name|last_active|last_event|last_value|left|leftof|length|low|path_name|pos|pred|quiet|range|reverse_range|right|rightof|simple_name|stable|succ|transaction|val|value)(?=[^\w-]|$)/i,null],["lit",/^\d+(?:_\d+)*(?:#[\w.\\]+#(?:[+-]?\d+(?:_\d+)*)?|(?:\.\d+(?:_\d+)*)?(?:e[+-]?\d+(?:_\d+)*)?)/i], |
|
3 |
+["pln",/^(?:[a-z]\w*|\\[^\\]*\\)/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'\xa0-]*/]]),["vhdl","vhd"]); |
... | ... |
@@ -0,0 +1,2 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\d\t a-gi-z\xa0]+/,null,"\t �\xa0abcdefgijklmnopqrstuvwxyz0123456789"],["pun",/^[*=[\]^~]+/,null,"=*~^[]"]],[["lang-wiki.meta",/(?:^^|\r\n?|\n)(#[a-z]+)\b/],["lit",/^[A-Z][a-z][\da-z]+[A-Z][a-z][^\W_]+\b/],["lang-",/^{{{([\S\s]+?)}}}/],["lang-",/^`([^\n\r`]+)`/],["str",/^https?:\/\/[^\s#/?]*(?:\/[^\s#?]*)?(?:\?[^\s#]*)?(?:#\S*)?/i],["pln",/^(?:\r\n|[\S\s])[^\n\r#*=A-[^`h{~]*/]]),["wiki"]); |
|
2 |
+PR.registerLangHandler(PR.createSimpleLexer([["kwd",/^#[a-z]+/i,null,"#"]],[]),["wiki.meta"]); |
... | ... |
@@ -0,0 +1,3 @@ |
1 |
+PR.registerLangHandler(PR.createSimpleLexer([["var pln",/^\$[\w-]+/,null,"$"]],[["pln",/^[\s=][<>][\s=]/],["lit",/^@[\w-]+/],["tag",/^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["com",/^\(:[\S\s]*?:\)/],["pln",/^[(),/;[\]{}]$/],["str",/^(?:"(?:[^"\\{]|\\[\S\s])*(?:"|$)|'(?:[^'\\{]|\\[\S\s])*(?:'|$))/,null,"\"'"],["kwd",/^(?:xquery|where|version|variable|union|typeswitch|treat|to|then|text|stable|sortby|some|self|schema|satisfies|returns|return|ref|processing-instruction|preceding-sibling|preceding|precedes|parent|only|of|node|namespace|module|let|item|intersect|instance|in|import|if|function|for|follows|following-sibling|following|external|except|every|else|element|descending|descendant-or-self|descendant|define|default|declare|comment|child|cast|case|before|attribute|assert|ascending|as|ancestor-or-self|ancestor|after|eq|order|by|or|and|schema-element|document-node|node|at)\b/], |
|
2 |
+["typ",/^(?:xs:yearMonthDuration|xs:unsignedLong|xs:time|xs:string|xs:short|xs:QName|xs:Name|xs:long|xs:integer|xs:int|xs:gYearMonth|xs:gYear|xs:gMonthDay|xs:gDay|xs:float|xs:duration|xs:double|xs:decimal|xs:dayTimeDuration|xs:dateTime|xs:date|xs:byte|xs:boolean|xs:anyURI|xf:yearMonthDuration)\b/,null],["fun pln",/^(?:xp:dereference|xinc:node-expand|xinc:link-references|xinc:link-expand|xhtml:restructure|xhtml:clean|xhtml:add-lists|xdmp:zip-manifest|xdmp:zip-get|xdmp:zip-create|xdmp:xquery-version|xdmp:word-convert|xdmp:with-namespaces|xdmp:version|xdmp:value|xdmp:user-roles|xdmp:user-last-login|xdmp:user|xdmp:url-encode|xdmp:url-decode|xdmp:uri-is-file|xdmp:uri-format|xdmp:uri-content-type|xdmp:unquote|xdmp:unpath|xdmp:triggers-database|xdmp:trace|xdmp:to-json|xdmp:tidy|xdmp:subbinary|xdmp:strftime|xdmp:spawn-in|xdmp:spawn|xdmp:sleep|xdmp:shutdown|xdmp:set-session-field|xdmp:set-response-encoding|xdmp:set-response-content-type|xdmp:set-response-code|xdmp:set-request-time-limit|xdmp:set|xdmp:servers|xdmp:server-status|xdmp:server-name|xdmp:server|xdmp:security-database|xdmp:security-assert|xdmp:schema-database|xdmp:save|xdmp:role-roles|xdmp:role|xdmp:rethrow|xdmp:restart|xdmp:request-timestamp|xdmp:request-status|xdmp:request-cancel|xdmp:request|xdmp:redirect-response|xdmp:random|xdmp:quote|xdmp:query-trace|xdmp:query-meters|xdmp:product-edition|xdmp:privilege-roles|xdmp:privilege|xdmp:pretty-print|xdmp:powerpoint-convert|xdmp:platform|xdmp:permission|xdmp:pdf-convert|xdmp:path|xdmp:octal-to-integer|xdmp:node-uri|xdmp:node-replace|xdmp:node-kind|xdmp:node-insert-child|xdmp:node-insert-before|xdmp:node-insert-after|xdmp:node-delete|xdmp:node-database|xdmp:mul64|xdmp:modules-root|xdmp:modules-database|xdmp:merging|xdmp:merge-cancel|xdmp:merge|xdmp:md5|xdmp:logout|xdmp:login|xdmp:log-level|xdmp:log|xdmp:lock-release|xdmp:lock-acquire|xdmp:load|xdmp:invoke-in|xdmp:invoke|xdmp:integer-to-octal|xdmp:integer-to-hex|xdmp:http-put|xdmp:http-post|xdmp:http-options|xdmp:http-head|xdmp:http-get|xdmp:http-delete|xdmp:hosts|xdmp:host-status|xdmp:host-name|xdmp:host|xdmp:hex-to-integer|xdmp:hash64|xdmp:hash32|xdmp:has-privilege|xdmp:groups|xdmp:group-serves|xdmp:group-servers|xdmp:group-name|xdmp:group-hosts|xdmp:group|xdmp:get-session-field-names|xdmp:get-session-field|xdmp:get-response-encoding|xdmp:get-response-code|xdmp:get-request-username|xdmp:get-request-user|xdmp:get-request-url|xdmp:get-request-protocol|xdmp:get-request-path|xdmp:get-request-method|xdmp:get-request-header-names|xdmp:get-request-header|xdmp:get-request-field-names|xdmp:get-request-field-filename|xdmp:get-request-field-content-type|xdmp:get-request-field|xdmp:get-request-client-certificate|xdmp:get-request-client-address|xdmp:get-request-body|xdmp:get-current-user|xdmp:get-current-roles|xdmp:get|xdmp:function-name|xdmp:function-module|xdmp:function|xdmp:from-json|xdmp:forests|xdmp:forest-status|xdmp:forest-restore|xdmp:forest-restart|xdmp:forest-name|xdmp:forest-delete|xdmp:forest-databases|xdmp:forest-counts|xdmp:forest-clear|xdmp:forest-backup|xdmp:forest|xdmp:filesystem-file|xdmp:filesystem-directory|xdmp:exists|xdmp:excel-convert|xdmp:eval-in|xdmp:eval|xdmp:estimate|xdmp:email|xdmp:element-content-type|xdmp:elapsed-time|xdmp:document-set-quality|xdmp:document-set-property|xdmp:document-set-properties|xdmp:document-set-permissions|xdmp:document-set-collections|xdmp:document-remove-properties|xdmp:document-remove-permissions|xdmp:document-remove-collections|xdmp:document-properties|xdmp:document-locks|xdmp:document-load|xdmp:document-insert|xdmp:document-get-quality|xdmp:document-get-properties|xdmp:document-get-permissions|xdmp:document-get-collections|xdmp:document-get|xdmp:document-forest|xdmp:document-delete|xdmp:document-add-properties|xdmp:document-add-permissions|xdmp:document-add-collections|xdmp:directory-properties|xdmp:directory-locks|xdmp:directory-delete|xdmp:directory-create|xdmp:directory|xdmp:diacritic-less|xdmp:describe|xdmp:default-permissions|xdmp:default-collections|xdmp:databases|xdmp:database-restore-validate|xdmp:database-restore-status|xdmp:database-restore-cancel|xdmp:database-restore|xdmp:database-name|xdmp:database-forests|xdmp:database-backup-validate|xdmp:database-backup-status|xdmp:database-backup-purge|xdmp:database-backup-cancel|xdmp:database-backup|xdmp:database|xdmp:collection-properties|xdmp:collection-locks|xdmp:collection-delete|xdmp:collation-canonical-uri|xdmp:castable-as|xdmp:can-grant-roles|xdmp:base64-encode|xdmp:base64-decode|xdmp:architecture|xdmp:apply|xdmp:amp-roles|xdmp:amp|xdmp:add64|xdmp:add-response-header|xdmp:access|trgr:trigger-set-recursive|trgr:trigger-set-permissions|trgr:trigger-set-name|trgr:trigger-set-module|trgr:trigger-set-event|trgr:trigger-set-description|trgr:trigger-remove-permissions|trgr:trigger-module|trgr:trigger-get-permissions|trgr:trigger-enable|trgr:trigger-disable|trgr:trigger-database-online-event|trgr:trigger-data-event|trgr:trigger-add-permissions|trgr:remove-trigger|trgr:property-content|trgr:pre-commit|trgr:post-commit|trgr:get-trigger-by-id|trgr:get-trigger|trgr:document-scope|trgr:document-content|trgr:directory-scope|trgr:create-trigger|trgr:collection-scope|trgr:any-property-content|thsr:set-entry|thsr:remove-term|thsr:remove-synonym|thsr:remove-entry|thsr:query-lookup|thsr:lookup|thsr:load|thsr:insert|thsr:expand|thsr:add-synonym|spell:suggest-detailed|spell:suggest|spell:remove-word|spell:make-dictionary|spell:load|spell:levenshtein-distance|spell:is-correct|spell:insert|spell:double-metaphone|spell:add-word|sec:users-collection|sec:user-set-roles|sec:user-set-password|sec:user-set-name|sec:user-set-description|sec:user-set-default-permissions|sec:user-set-default-collections|sec:user-remove-roles|sec:user-privileges|sec:user-get-roles|sec:user-get-description|sec:user-get-default-permissions|sec:user-get-default-collections|sec:user-doc-permissions|sec:user-doc-collections|sec:user-add-roles|sec:unprotect-collection|sec:uid-for-name|sec:set-realm|sec:security-version|sec:security-namespace|sec:security-installed|sec:security-collection|sec:roles-collection|sec:role-set-roles|sec:role-set-name|sec:role-set-description|sec:role-set-default-permissions|sec:role-set-default-collections|sec:role-remove-roles|sec:role-privileges|sec:role-get-roles|sec:role-get-description|sec:role-get-default-permissions|sec:role-get-default-collections|sec:role-doc-permissions|sec:role-doc-collections|sec:role-add-roles|sec:remove-user|sec:remove-role-from-users|sec:remove-role-from-role|sec:remove-role-from-privileges|sec:remove-role-from-amps|sec:remove-role|sec:remove-privilege|sec:remove-amp|sec:protect-collection|sec:privileges-collection|sec:privilege-set-roles|sec:privilege-set-name|sec:privilege-remove-roles|sec:privilege-get-roles|sec:privilege-add-roles|sec:priv-doc-permissions|sec:priv-doc-collections|sec:get-user-names|sec:get-unique-elem-id|sec:get-role-names|sec:get-role-ids|sec:get-privilege|sec:get-distinct-permissions|sec:get-collection|sec:get-amp|sec:create-user-with-role|sec:create-user|sec:create-role|sec:create-privilege|sec:create-amp|sec:collections-collection|sec:collection-set-permissions|sec:collection-remove-permissions|sec:collection-get-permissions|sec:collection-add-permissions|sec:check-admin|sec:amps-collection|sec:amp-set-roles|sec:amp-remove-roles|sec:amp-get-roles|sec:amp-doc-permissions|sec:amp-doc-collections|sec:amp-add-roles|search:unparse|search:suggest|search:snippet|search:search|search:resolve-nodes|search:resolve|search:remove-constraint|search:parse|search:get-default-options|search:estimate|search:check-options|prof:value|prof:reset|prof:report|prof:invoke|prof:eval|prof:enable|prof:disable|prof:allowed|ppt:clean|pki:template-set-request|pki:template-set-name|pki:template-set-key-type|pki:template-set-key-options|pki:template-set-description|pki:template-in-use|pki:template-get-version|pki:template-get-request|pki:template-get-name|pki:template-get-key-type|pki:template-get-key-options|pki:template-get-id|pki:template-get-description|pki:need-certificate|pki:is-temporary|pki:insert-trusted-certificates|pki:insert-template|pki:insert-signed-certificates|pki:insert-certificate-revocation-list|pki:get-trusted-certificate-ids|pki:get-template-ids|pki:get-template-certificate-authority|pki:get-template-by-name|pki:get-template|pki:get-pending-certificate-requests-xml|pki:get-pending-certificate-requests-pem|pki:get-pending-certificate-request|pki:get-certificates-for-template-xml|pki:get-certificates-for-template|pki:get-certificates|pki:get-certificate-xml|pki:get-certificate-pem|pki:get-certificate|pki:generate-temporary-certificate-if-necessary|pki:generate-temporary-certificate|pki:generate-template-certificate-authority|pki:generate-certificate-request|pki:delete-template|pki:delete-certificate|pki:create-template|pdf:make-toc|pdf:insert-toc-headers|pdf:get-toc|pdf:clean|p:status-transition|p:state-transition|p:remove|p:pipelines|p:insert|p:get-by-id|p:get|p:execute|p:create|p:condition|p:collection|p:action|ooxml:runs-merge|ooxml:package-uris|ooxml:package-parts-insert|ooxml:package-parts|msword:clean|mcgm:polygon|mcgm:point|mcgm:geospatial-query-from-elements|mcgm:geospatial-query|mcgm:circle|math:tanh|math:tan|math:sqrt|math:sinh|math:sin|math:pow|math:modf|math:log10|math:log|math:ldexp|math:frexp|math:fmod|math:floor|math:fabs|math:exp|math:cosh|math:cos|math:ceil|math:atan2|math:atan|math:asin|math:acos|map:put|map:map|map:keys|map:get|map:delete|map:count|map:clear|lnk:to|lnk:remove|lnk:insert|lnk:get|lnk:from|lnk:create|kml:polygon|kml:point|kml:interior-polygon|kml:geospatial-query-from-elements|kml:geospatial-query|kml:circle|kml:box|gml:polygon|gml:point|gml:interior-polygon|gml:geospatial-query-from-elements|gml:geospatial-query|gml:circle|gml:box|georss:point|georss:geospatial-query|georss:circle|geo:polygon|geo:point|geo:interior-polygon|geo:geospatial-query-from-elements|geo:geospatial-query|geo:circle|geo:box|fn:zero-or-one|fn:years-from-duration|fn:year-from-dateTime|fn:year-from-date|fn:upper-case|fn:unordered|fn:true|fn:translate|fn:trace|fn:tokenize|fn:timezone-from-time|fn:timezone-from-dateTime|fn:timezone-from-date|fn:sum|fn:subtract-dateTimes-yielding-yearMonthDuration|fn:subtract-dateTimes-yielding-dayTimeDuration|fn:substring-before|fn:substring-after|fn:substring|fn:subsequence|fn:string-to-codepoints|fn:string-pad|fn:string-length|fn:string-join|fn:string|fn:static-base-uri|fn:starts-with|fn:seconds-from-time|fn:seconds-from-duration|fn:seconds-from-dateTime|fn:round-half-to-even|fn:round|fn:root|fn:reverse|fn:resolve-uri|fn:resolve-QName|fn:replace|fn:remove|fn:QName|fn:prefix-from-QName|fn:position|fn:one-or-more|fn:number|fn:not|fn:normalize-unicode|fn:normalize-space|fn:node-name|fn:node-kind|fn:nilled|fn:namespace-uri-from-QName|fn:namespace-uri-for-prefix|fn:namespace-uri|fn:name|fn:months-from-duration|fn:month-from-dateTime|fn:month-from-date|fn:minutes-from-time|fn:minutes-from-duration|fn:minutes-from-dateTime|fn:min|fn:max|fn:matches|fn:lower-case|fn:local-name-from-QName|fn:local-name|fn:last|fn:lang|fn:iri-to-uri|fn:insert-before|fn:index-of|fn:in-scope-prefixes|fn:implicit-timezone|fn:idref|fn:id|fn:hours-from-time|fn:hours-from-duration|fn:hours-from-dateTime|fn:floor|fn:false|fn:expanded-QName|fn:exists|fn:exactly-one|fn:escape-uri|fn:escape-html-uri|fn:error|fn:ends-with|fn:encode-for-uri|fn:empty|fn:document-uri|fn:doc-available|fn:doc|fn:distinct-values|fn:distinct-nodes|fn:default-collation|fn:deep-equal|fn:days-from-duration|fn:day-from-dateTime|fn:day-from-date|fn:data|fn:current-time|fn:current-dateTime|fn:current-date|fn:count|fn:contains|fn:concat|fn:compare|fn:collection|fn:codepoints-to-string|fn:codepoint-equal|fn:ceiling|fn:boolean|fn:base-uri|fn:avg|fn:adjust-time-to-timezone|fn:adjust-dateTime-to-timezone|fn:adjust-date-to-timezone|fn:abs|feed:unsubscribe|feed:subscription|feed:subscribe|feed:request|feed:item|feed:description|excel:clean|entity:enrich|dom:set-pipelines|dom:set-permissions|dom:set-name|dom:set-evaluation-context|dom:set-domain-scope|dom:set-description|dom:remove-pipeline|dom:remove-permissions|dom:remove|dom:get|dom:evaluation-context|dom:domains|dom:domain-scope|dom:create|dom:configuration-set-restart-user|dom:configuration-set-permissions|dom:configuration-set-evaluation-context|dom:configuration-set-default-domain|dom:configuration-get|dom:configuration-create|dom:collection|dom:add-pipeline|dom:add-permissions|dls:retention-rules|dls:retention-rule-remove|dls:retention-rule-insert|dls:retention-rule|dls:purge|dls:node-expand|dls:link-references|dls:link-expand|dls:documents-query|dls:document-versions-query|dls:document-version-uri|dls:document-version-query|dls:document-version-delete|dls:document-version-as-of|dls:document-version|dls:document-update|dls:document-unmanage|dls:document-set-quality|dls:document-set-property|dls:document-set-properties|dls:document-set-permissions|dls:document-set-collections|dls:document-retention-rules|dls:document-remove-properties|dls:document-remove-permissions|dls:document-remove-collections|dls:document-purge|dls:document-manage|dls:document-is-managed|dls:document-insert-and-manage|dls:document-include-query|dls:document-history|dls:document-get-permissions|dls:document-extract-part|dls:document-delete|dls:document-checkout-status|dls:document-checkout|dls:document-checkin|dls:document-add-properties|dls:document-add-permissions|dls:document-add-collections|dls:break-checkout|dls:author-query|dls:as-of-query|dbk:convert|dbg:wait|dbg:value|dbg:stopped|dbg:stop|dbg:step|dbg:status|dbg:stack|dbg:out|dbg:next|dbg:line|dbg:invoke|dbg:function|dbg:finish|dbg:expr|dbg:eval|dbg:disconnect|dbg:detach|dbg:continue|dbg:connect|dbg:clear|dbg:breakpoints|dbg:break|dbg:attached|dbg:attach|cvt:save-converted-documents|cvt:part-uri|cvt:destination-uri|cvt:basepath|cvt:basename|cts:words|cts:word-query-weight|cts:word-query-text|cts:word-query-options|cts:word-query|cts:word-match|cts:walk|cts:uris|cts:uri-match|cts:train|cts:tokenize|cts:thresholds|cts:stem|cts:similar-query-weight|cts:similar-query-nodes|cts:similar-query|cts:shortest-distance|cts:search|cts:score|cts:reverse-query-weight|cts:reverse-query-nodes|cts:reverse-query|cts:remainder|cts:registered-query-weight|cts:registered-query-options|cts:registered-query-ids|cts:registered-query|cts:register|cts:query|cts:quality|cts:properties-query-query|cts:properties-query|cts:polygon-vertices|cts:polygon|cts:point-longitude|cts:point-latitude|cts:point|cts:or-query-queries|cts:or-query|cts:not-query-weight|cts:not-query-query|cts:not-query|cts:near-query-weight|cts:near-query-queries|cts:near-query-options|cts:near-query-distance|cts:near-query|cts:highlight|cts:geospatial-co-occurrences|cts:frequency|cts:fitness|cts:field-words|cts:field-word-query-weight|cts:field-word-query-text|cts:field-word-query-options|cts:field-word-query-field-name|cts:field-word-query|cts:field-word-match|cts:entity-highlight|cts:element-words|cts:element-word-query-weight|cts:element-word-query-text|cts:element-word-query-options|cts:element-word-query-element-name|cts:element-word-query|cts:element-word-match|cts:element-values|cts:element-value-ranges|cts:element-value-query-weight|cts:element-value-query-text|cts:element-value-query-options|cts:element-value-query-element-name|cts:element-value-query|cts:element-value-match|cts:element-value-geospatial-co-occurrences|cts:element-value-co-occurrences|cts:element-range-query-weight|cts:element-range-query-value|cts:element-range-query-options|cts:element-range-query-operator|cts:element-range-query-element-name|cts:element-range-query|cts:element-query-query|cts:element-query-element-name|cts:element-query|cts:element-pair-geospatial-values|cts:element-pair-geospatial-value-match|cts:element-pair-geospatial-query-weight|cts:element-pair-geospatial-query-region|cts:element-pair-geospatial-query-options|cts:element-pair-geospatial-query-longitude-name|cts:element-pair-geospatial-query-latitude-name|cts:element-pair-geospatial-query-element-name|cts:element-pair-geospatial-query|cts:element-pair-geospatial-boxes|cts:element-geospatial-values|cts:element-geospatial-value-match|cts:element-geospatial-query-weight|cts:element-geospatial-query-region|cts:element-geospatial-query-options|cts:element-geospatial-query-element-name|cts:element-geospatial-query|cts:element-geospatial-boxes|cts:element-child-geospatial-values|cts:element-child-geospatial-value-match|cts:element-child-geospatial-query-weight|cts:element-child-geospatial-query-region|cts:element-child-geospatial-query-options|cts:element-child-geospatial-query-element-name|cts:element-child-geospatial-query-child-name|cts:element-child-geospatial-query|cts:element-child-geospatial-boxes|cts:element-attribute-words|cts:element-attribute-word-query-weight|cts:element-attribute-word-query-text|cts:element-attribute-word-query-options|cts:element-attribute-word-query-element-name|cts:element-attribute-word-query-attribute-name|cts:element-attribute-word-query|cts:element-attribute-word-match|cts:element-attribute-values|cts:element-attribute-value-ranges|cts:element-attribute-value-query-weight|cts:element-attribute-value-query-text|cts:element-attribute-value-query-options|cts:element-attribute-value-query-element-name|cts:element-attribute-value-query-attribute-name|cts:element-attribute-value-query|cts:element-attribute-value-match|cts:element-attribute-value-geospatial-co-occurrences|cts:element-attribute-value-co-occurrences|cts:element-attribute-range-query-weight|cts:element-attribute-range-query-value|cts:element-attribute-range-query-options|cts:element-attribute-range-query-operator|cts:element-attribute-range-query-element-name|cts:element-attribute-range-query-attribute-name|cts:element-attribute-range-query|cts:element-attribute-pair-geospatial-values|cts:element-attribute-pair-geospatial-value-match|cts:element-attribute-pair-geospatial-query-weight|cts:element-attribute-pair-geospatial-query-region|cts:element-attribute-pair-geospatial-query-options|cts:element-attribute-pair-geospatial-query-longitude-name|cts:element-attribute-pair-geospatial-query-latitude-name|cts:element-attribute-pair-geospatial-query-element-name|cts:element-attribute-pair-geospatial-query|cts:element-attribute-pair-geospatial-boxes|cts:document-query-uris|cts:document-query|cts:distance|cts:directory-query-uris|cts:directory-query-depth|cts:directory-query|cts:destination|cts:deregister|cts:contains|cts:confidence|cts:collections|cts:collection-query-uris|cts:collection-query|cts:collection-match|cts:classify|cts:circle-radius|cts:circle-center|cts:circle|cts:box-west|cts:box-south|cts:box-north|cts:box-east|cts:box|cts:bearing|cts:arc-intersection|cts:and-query-queries|cts:and-query-options|cts:and-query|cts:and-not-query-positive-query|cts:and-not-query-negative-query|cts:and-not-query|css:get|css:convert|cpf:success|cpf:failure|cpf:document-set-state|cpf:document-set-processing-status|cpf:document-set-last-updated|cpf:document-set-error|cpf:document-get-state|cpf:document-get-processing-status|cpf:document-get-last-updated|cpf:document-get-error|cpf:check-transition|alert:spawn-matching-actions|alert:rule-user-id-query|alert:rule-set-user-id|alert:rule-set-query|alert:rule-set-options|alert:rule-set-name|alert:rule-set-description|alert:rule-set-action|alert:rule-remove|alert:rule-name-query|alert:rule-insert|alert:rule-id-query|alert:rule-get-user-id|alert:rule-get-query|alert:rule-get-options|alert:rule-get-name|alert:rule-get-id|alert:rule-get-description|alert:rule-get-action|alert:rule-action-query|alert:remove-triggers|alert:make-rule|alert:make-log-action|alert:make-config|alert:make-action|alert:invoke-matching-actions|alert:get-my-rules|alert:get-all-rules|alert:get-actions|alert:find-matching-rules|alert:create-triggers|alert:config-set-uri|alert:config-set-trigger-ids|alert:config-set-options|alert:config-set-name|alert:config-set-description|alert:config-set-cpf-domain-names|alert:config-set-cpf-domain-ids|alert:config-insert|alert:config-get-uri|alert:config-get-trigger-ids|alert:config-get-options|alert:config-get-name|alert:config-get-id|alert:config-get-description|alert:config-get-cpf-domain-names|alert:config-get-cpf-domain-ids|alert:config-get|alert:config-delete|alert:action-set-options|alert:action-set-name|alert:action-set-module-root|alert:action-set-module-db|alert:action-set-module|alert:action-set-description|alert:action-remove|alert:action-insert|alert:action-get-options|alert:action-get-name|alert:action-get-module-root|alert:action-get-module-db|alert:action-get-module|alert:action-get-description|zero-or-one|years-from-duration|year-from-dateTime|year-from-date|upper-case|unordered|true|translate|trace|tokenize|timezone-from-time|timezone-from-dateTime|timezone-from-date|sum|subtract-dateTimes-yielding-yearMonthDuration|subtract-dateTimes-yielding-dayTimeDuration|substring-before|substring-after|substring|subsequence|string-to-codepoints|string-pad|string-length|string-join|string|static-base-uri|starts-with|seconds-from-time|seconds-from-duration|seconds-from-dateTime|round-half-to-even|round|root|reverse|resolve-uri|resolve-QName|replace|remove|QName|prefix-from-QName|position|one-or-more|number|not|normalize-unicode|normalize-space|node-name|node-kind|nilled|namespace-uri-from-QName|namespace-uri-for-prefix|namespace-uri|name|months-from-duration|month-from-dateTime|month-from-date|minutes-from-time|minutes-from-duration|minutes-from-dateTime|min|max|matches|lower-case|local-name-from-QName|local-name|last|lang|iri-to-uri|insert-before|index-of|in-scope-prefixes|implicit-timezone|idref|id|hours-from-time|hours-from-duration|hours-from-dateTime|floor|false|expanded-QName|exists|exactly-one|escape-uri|escape-html-uri|error|ends-with|encode-for-uri|empty|document-uri|doc-available|doc|distinct-values|distinct-nodes|default-collation|deep-equal|days-from-duration|day-from-dateTime|day-from-date|data|current-time|current-dateTime|current-date|count|contains|concat|compare|collection|codepoints-to-string|codepoint-equal|ceiling|boolean|base-uri|avg|adjust-time-to-timezone|adjust-dateTime-to-timezone|adjust-date-to-timezone|abs)\b/], |
|
3 |
+["pln",/^[\w:-]+/],["pln",/^[\t\n\r \xa0]+/]]),["xq","xquery"]); |
... | ... |
@@ -0,0 +1,2 @@ |
1 |
+var a=null; |
|
2 |
+PR.registerLangHandler(PR.createSimpleLexer([["pun",/^[:>?|]+/,a,":|>?"],["dec",/^%(?:YAML|TAG)[^\n\r#]+/,a,"%"],["typ",/^&\S+/,a,"&"],["typ",/^!\S*/,a,"!"],["str",/^"(?:[^"\\]|\\.)*(?:"|$)/,a,'"'],["str",/^'(?:[^']|'')*(?:'|$)/,a,"'"],["com",/^#[^\n\r]*/,a,"#"],["pln",/^\s+/,a," \t\r\n"]],[["dec",/^(?:---|\.\.\.)(?:[\n\r]|$)/],["pun",/^-/],["kwd",/^\w+:[\n\r ]/],["pln",/^\w+/]]),["yaml","yml"]); |
... | ... |
@@ -0,0 +1 @@ |
1 |
+.str{color:#9daa7e}.kwd{color:#d5b57c}.com{color:#726d73}.typ{color:#dd7e5e}.lit{color:#fcf0a4}.pun,.opn,.clo{color:#a78353}.pln{color:#889dbc}.tag{color:#d5b57c}.atn{color:#dd7e5e}.atv{color:#9daa7e}.dec{color:#dd7e5e} |
... | ... |
@@ -0,0 +1 @@ |
1 |
+.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} |
... | ... |
@@ -0,0 +1,28 @@ |
1 |
+var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; |
|
2 |
+(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= |
|
3 |
+[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c< |
|
4 |
+f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&& |
|
5 |
+(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r= |
|
6 |
+{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length, |
|
7 |
+t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b=== |
|
8 |
+"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), |
|
9 |
+l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, |
|
10 |
+q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, |
|
11 |
+q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, |
|
12 |
+"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), |
|
13 |
+a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} |
|
14 |
+for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value", |
|
15 |
+m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m= |
|
16 |
+a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue= |
|
17 |
+j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], |
|
18 |
+"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], |
|
19 |
+H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], |
|
20 |
+J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ |
|
21 |
+I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), |
|
22 |
+["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", |
|
23 |
+/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), |
|
24 |
+["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", |
|
25 |
+hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b= |
|
26 |
+!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m, |
|
27 |
+250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit", |
|
28 |
+PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})(); |
... | ... |
@@ -4,9 +4,9 @@ |
4 | 4 |
<title>Server error</title> |
5 | 5 |
<meta http-equiv="Pragma" content="no-cache"> |
6 | 6 |
<meta http-equiv="Expires" content="-1"> |
7 |
- %= javascript '/js/jquery.js' |
|
8 |
- %= stylesheet '/css/prettify-mojo.css' |
|
9 |
- %= javascript '/js/prettify.js' |
|
7 |
+ %= javascript '/mojo/jquery/jquery.js' |
|
8 |
+ %= stylesheet '/mojo/prettify/prettify-mojo.css' |
|
9 |
+ %= javascript '/mojo/prettify/prettify.js' |
|
10 | 10 |
%= stylesheet begin |
11 | 11 |
a img { border: 0 } |
12 | 12 |
body { |
... | ... |
@@ -39,7 +39,7 @@ |
39 | 39 |
} |
40 | 40 |
.code { |
41 | 41 |
background-color: #1a1a1a; |
42 |
- background: url(<%= url_for '/mojolicious-pinstripe.gif' %>); |
|
42 |
+ background: url(<%= url_for '/mojo/pinstripe.gif' %>); |
|
43 | 43 |
color: #eee; |
44 | 44 |
text-shadow: #333 0 1px 0; |
45 | 45 |
} |
... | ... |
@@ -219,7 +219,7 @@ |
219 | 219 |
</div> |
220 | 220 |
<div id="footer"> |
221 | 221 |
%= link_to 'http://mojolicio.us' => begin |
222 |
- %= image '/mojolicious-black.png', alt => 'Mojolicious logo' |
|
222 |
+ %= image '/mojo/logo-black.png', alt => 'Mojolicious logo' |
|
223 | 223 |
% end |
224 | 224 |
</div> |
225 | 225 |
%= javascript begin |
... | ... |
@@ -4,7 +4,7 @@ |
4 | 4 |
%= stylesheet begin |
5 | 5 |
body { background-color: #caecf6 } |
6 | 6 |
#raptor { |
7 |
- background: url(<%= url_for '/mojolicious-failraptor.png' %>); |
|
7 |
+ background: url(<%= url_for '/mojo/failraptor.png' %>); |
|
8 | 8 |
height: 488px; |
9 | 9 |
left: 50%; |
10 | 10 |
margin-left: -371px; |
... | ... |
@@ -1,4 +1,4 @@ |
1 |
-%= javascript '/js/jquery.js' |
|
1 |
+%= javascript '/mojo/jquery/jquery.js' |
|
2 | 2 |
<div id="mojobar"> |
3 | 3 |
%= stylesheet scoped => 'scoped', begin |
4 | 4 |
#mojobar { |
... | ... |
@@ -56,7 +56,7 @@ |
56 | 56 |
% end |
57 | 57 |
<div id="mojobar-logo"> |
58 | 58 |
%= link_to 'http://mojolicio.us' => begin |
59 |
- %= image '/mojolicious-white.png', alt => 'Mojolicious logo' |
|
59 |
+ %= image '/mojo/logo-white.png', alt => 'Mojolicious logo' |
|
60 | 60 |
% end |
61 | 61 |
</div> |
62 | 62 |
<div id="mojobar-links"> |
... | ... |
@@ -2,8 +2,8 @@ |
2 | 2 |
<html> |
3 | 3 |
<head> |
4 | 4 |
<title>Page not found</title> |
5 |
- %= stylesheet '/css/prettify-mojo.css' |
|
6 |
- %= javascript '/js/prettify.js' |
|
5 |
+ %= stylesheet '/mojo/prettify/prettify-mojo.css' |
|
6 |
+ %= javascript '/mojo/prettify/prettify.js' |
|
7 | 7 |
%= stylesheet begin |
8 | 8 |
body { |
9 | 9 |
background-color: #f5f6f8; |
... | ... |
@@ -117,7 +117,7 @@ |
117 | 117 |
</div> |
118 | 118 |
<div id="footer"> |
119 | 119 |
%= link_to 'http://mojolicio.us' => begin |
120 |
- %= image '/mojolicious-black.png', alt => 'Mojolicious logo' |
|
120 |
+ %= image '/mojo/logo-black.png', alt => 'Mojolicious logo' |
|
121 | 121 |
% end |
122 | 122 |
</div> |
123 | 123 |
</body> |
... | ... |
@@ -10,7 +10,7 @@ |
10 | 10 |
top: 60%; |
11 | 11 |
} |
12 | 12 |
#notfound { |
13 |
- background: url(<%= url_for '/mojolicious-notfound.png' %>); |
|
13 |
+ background: url(<%= url_for '/mojo/notfound.png' %>); |
|
14 | 14 |
height: 62px; |
15 | 15 |
left: 50%; |
16 | 16 |
margin-left: -153px; |
... | ... |
@@ -22,7 +22,7 @@ |
22 | 22 |
% end |
23 | 23 |
<body> |
24 | 24 |
%= link_to url_for->base => begin |
25 |
- %= image '/mojolicious-noraptor.png', alt => 'Bye!', id => 'noraptor' |
|
25 |
+ %= image '/mojo/noraptor.png', alt => 'Bye!', id => 'noraptor' |
|
26 | 26 |
% end |
27 | 27 |
<div id="notfound"></div> |
28 | 28 |
</body> |
... | ... |
@@ -2,8 +2,8 @@ |
2 | 2 |
<html> |
3 | 3 |
<head> |
4 | 4 |
<title><%= $title %></title> |
5 |
- %= stylesheet '/css/prettify-mojo.css' |
|
6 |
- %= javascript '/js/prettify.js' |
|
5 |
+ %= stylesheet '/mojo/prettify/prettify-mojo.css' |
|
6 |
+ %= javascript '/mojo/prettify/prettify.js' |
|
7 | 7 |
%= stylesheet begin |
8 | 8 |
a { color: inherit } |
9 | 9 |
a:hover { color: #2a2a2a } |
... | ... |
@@ -24,7 +24,7 @@ |
24 | 24 |
h1 a, h2 a, h3 a { text-decoration: none } |
25 | 25 |
pre { |
26 | 26 |
background-color: #eee; |
27 |
- background: url(<%= url_for '/mojolicious-pinstripe.gif' %>); |
|
27 |
+ background: url(<%= url_for '/mojo/pinstripe.gif' %>); |
|
28 | 28 |
-moz-border-radius: 5px; |
29 | 29 |
border-radius: 5px; |
30 | 30 |
color: #eee; |
... | ... |
@@ -88,7 +88,7 @@ |
88 | 88 |
</div> |
89 | 89 |
<div id="footer"> |
90 | 90 |
%= link_to 'http://mojolicio.us' => begin |
91 |
- %= image '/mojolicious-black.png', alt => 'Mojolicious logo' |
|
91 |
+ %= image '/mojo/logo-black.png', alt => 'Mojolicious logo' |
|
92 | 92 |
% end |
93 | 93 |
</div> |
94 | 94 |
</body> |
... | ... |
@@ -9,12 +9,14 @@ use Mojo::Base -base; |
9 | 9 |
# Bender: You're better off dead, I'm telling you, dude. |
10 | 10 |
# Fry: Santa Claus is gunning you down!" |
11 | 11 |
use Mojo::IOLoop; |
12 |
+use Mojo::JSON; |
|
13 |
+use Mojo::JSON::Pointer; |
|
12 | 14 |
use Mojo::Server; |
13 | 15 |
use Mojo::UserAgent; |
14 | 16 |
use Mojo::Util qw(decode encode); |
15 | 17 |
use Test::More (); |
16 | 18 |
|
17 |
-has 'tx'; |
|
19 |
+has [qw(message tx)]; |
|
18 | 20 |
has ua => sub { Mojo::UserAgent->new->ioloop(Mojo::IOLoop->singleton) }; |
19 | 21 |
|
20 | 22 |
# Silent or loud tests |
... | ... |
@@ -142,12 +144,6 @@ sub json_content_is { |
142 | 144 |
return $self->_test('is_deeply', $self->tx->res->json, $data, $desc); |
143 | 145 |
} |
144 | 146 |
|
145 |
-sub json_is { |
|
146 |
- my ($self, $p, $data, $desc) = @_; |
|
147 |
- $desc ||= qq{exact match for JSON Pointer "$p"}; |
|
148 |
- return $self->_test('is_deeply', $self->tx->res->json($p), $data, $desc); |
|
149 |
-} |
|
150 |
- |
|
151 | 147 |
sub json_has { |
152 | 148 |
my ($self, $p, $desc) = @_; |
153 | 149 |
$desc ||= qq{has value for JSON Pointer "$p"}; |
... | ... |
@@ -162,28 +158,53 @@ sub json_hasnt { |
162 | 158 |
!Mojo::JSON::Pointer->new->contains($self->tx->res->json, $p), $desc); |
163 | 159 |
} |
164 | 160 |
|
161 |
+sub json_is { |
|
162 |
+ my ($self, $p, $data, $desc) = @_; |
|
163 |
+ $desc ||= qq{exact match for JSON Pointer "$p"}; |
|
164 |
+ return $self->_test('is_deeply', $self->tx->res->json($p), $data, $desc); |
|
165 |
+} |
|
166 |
+ |
|
167 |
+sub json_message_has { |
|
168 |
+ my ($self, $p, $desc) = @_; |
|
169 |
+ $desc ||= qq{has value for JSON Pointer "$p"}; |
|
170 |
+ return $self->_test('ok', $self->_json(contains => $p), $desc); |
|
171 |
+} |
|
172 |
+ |
|
173 |
+sub json_message_hasnt { |
|
174 |
+ my ($self, $p, $desc) = @_; |
|
175 |
+ $desc ||= qq{has no value for JSON Pointer "$p"}; |
|
176 |
+ return $self->_test('ok', !$self->_json(contains => $p), $desc); |
|
177 |
+} |
|
178 |
+ |
|
179 |
+sub json_message_is { |
|
180 |
+ my ($self, $p, $data, $desc) = @_; |
|
181 |
+ $desc ||= qq{exact match for JSON Pointer "$p"}; |
|
182 |
+ return $self->_test('is_deeply', $self->_json(get => $p), $data, $desc); |
|
183 |
+} |
|
184 |
+ |
|
165 | 185 |
sub message_is { |
166 | 186 |
my ($self, $value, $desc) = @_; |
167 |
- $desc ||= 'exact match for message'; |
|
168 |
- return $self->_test('is', $self->_message, $value, $desc); |
|
187 |
+ return $self->_message('is', $value, $desc || 'exact match for message'); |
|
169 | 188 |
} |
170 | 189 |
|
171 | 190 |
sub message_isnt { |
172 | 191 |
my ($self, $value, $desc) = @_; |
173 |
- $desc ||= 'no match for message'; |
|
174 |
- return $self->_test('isnt', $self->_message, $value, $desc); |
|
192 |
+ return $self->_message('isnt', $value, $desc || 'no match for message'); |
|
175 | 193 |
} |
176 | 194 |
|
177 | 195 |
sub message_like { |
178 | 196 |
my ($self, $regex, $desc) = @_; |
179 |
- $desc ||= 'message is similar'; |
|
180 |
- return $self->_test('like', $self->_message, $regex, $desc); |
|
197 |
+ return $self->_message('like', $regex, $desc || 'message is similar'); |
|
198 |
+} |
|
199 |
+ |
|
200 |
+sub message_ok { |
|
201 |
+ my ($self, $desc) = @_; |
|
202 |
+ return $self->_test('ok', !!$self->_wait(1), $desc, 'message received'); |
|
181 | 203 |
} |
182 | 204 |
|
183 | 205 |
sub message_unlike { |
184 | 206 |
my ($self, $regex, $desc) = @_; |
185 |
- $desc ||= 'message is not similar'; |
|
186 |
- return $self->_test('unlike', $self->_message, $regex, $desc); |
|
207 |
+ return $self->_message('unlike', $regex, $desc || 'message is not similar'); |
|
187 | 208 |
} |
188 | 209 |
|
189 | 210 |
sub options_ok { shift->_request_ok(options => @_) } |
... | ... |
@@ -278,7 +299,8 @@ sub websocket_ok { |
278 | 299 |
my $tx = pop; |
279 | 300 |
$self->tx($tx); |
280 | 301 |
$tx->on(finish => sub { $self->{finished} = 1 }); |
281 |
- $tx->on(message => sub { push @{$self->{messages}}, pop }); |
|
302 |
+ $tx->on(binary => sub { push @{$self->{messages}}, [binary => pop] }); |
|
303 |
+ $tx->on(text => sub { push @{$self->{messages}}, [text => pop] }); |
|
282 | 304 |
Mojo::IOLoop->stop; |
283 | 305 |
} |
284 | 306 |
); |
... | ... |
@@ -295,10 +317,28 @@ sub _get_content { |
295 | 317 |
return $charset ? decode($charset, $content) : $content; |
296 | 318 |
} |
297 | 319 |
|
320 |
+sub _json { |
|
321 |
+ my ($self, $method, $p) = @_; |
|
322 |
+ return Mojo::JSON::Pointer->new->$method( |
|
323 |
+ Mojo::JSON->new->decode(@{$self->_wait || []}[1]), $p); |
|
324 |
+} |
|
325 |
+ |
|
298 | 326 |
sub _message { |
299 |
- my $self = shift; |
|
300 |
- Mojo::IOLoop->one_tick while !$self->{finished} && !@{$self->{messages}}; |
|
301 |
- return shift @{$self->{messages}}; |
|
327 |
+ my ($self, $name, $value, $desc) = @_; |
|
328 |
+ local $Test::Builder::Level = $Test::Builder::Level + 1; |
|
329 |
+ my ($type, $msg) = @{$self->_wait || ['']}; |
|
330 |
+ |
|
331 |
+ # Type check |
|
332 |
+ if (ref $value eq 'HASH') { |
|
333 |
+ my $expect = exists $value->{text} ? 'text' : 'binary'; |
|
334 |
+ $value = $value->{$expect}; |
|
335 |
+ $msg = '' unless $type eq $expect; |
|
336 |
+ } |
|
337 |
+ |
|
338 |
+ # Decode text frame if there is no type check |
|
339 |
+ else { $msg = decode 'UTF-8', $msg if $type eq 'text' } |
|
340 |
+ |
|
341 |
+ return $self->_test($name, defined $msg ? $msg : '', $value, $desc); |
|
302 | 342 |
} |
303 | 343 |
|
304 | 344 |
sub _request_ok { |
... | ... |
@@ -326,6 +366,21 @@ sub _text { |
326 | 366 |
return $e->text; |
327 | 367 |
} |
328 | 368 |
|
369 |
+sub _wait { |
|
370 |
+ my ($self, $wait) = @_; |
|
371 |
+ |
|
372 |
+ # DEPRECATED in Rainbow! |
|
373 |
+ my $new = $self->{new} = defined $self->{new} ? $self->{new} : $wait; |
|
374 |
+ warn <<EOF unless $new; |
|
375 |
+Testing WebSocket messages without Test::Mojo->message_ok is DEPRECATED!!! |
|
376 |
+EOF |
|
377 |
+ return $self->message if $new && !$wait; |
|
378 |
+ |
|
379 |
+ # Wait for message |
|
380 |
+ Mojo::IOLoop->one_tick while !$self->{finished} && !@{$self->{messages}}; |
|
381 |
+ return $self->message(shift @{$self->{messages}})->message; |
|
382 |
+} |
|
383 |
+ |
|
329 | 384 |
1; |
330 | 385 |
|
331 | 386 |
=head1 NAME |
... | ... |
@@ -352,6 +407,7 @@ Test::Mojo - Testing Mojo! |
352 | 407 |
# WebSocket |
353 | 408 |
$t->websocket_ok('/echo') |
354 | 409 |
->send_ok('hello') |
410 |
+ ->message_ok |
|
355 | 411 |
->message_is('echo: hello') |
356 | 412 |
->finish_ok; |
357 | 413 |
|
... | ... |
@@ -366,7 +422,20 @@ L<Mojo> and L<Mojolicious> applications. |
366 | 422 |
|
367 | 423 |
L<Test::Mojo> implements the following attributes. |
368 | 424 |
|
369 |
-=head2 C<tx> |
|
425 |
+=head2 message |
|
426 |
+ |
|
427 |
+ my $msg = $t->message; |
|
428 |
+ $t = $t->message([text => $bytes]); |
|
429 |
+ |
|
430 |
+Current WebSocket message. |
|
431 |
+ |
|
432 |
+ # Test custom message |
|
433 |
+ $t->message([binary => $bytes]) |
|
434 |
+ ->json_message_has('/foo/bar') |
|
435 |
+ ->json_message_hasnt('/bar') |
|
436 |
+ ->json_message_is('/foo/baz' => {yada => [1, 2, 3]}); |
|
437 |
+ |
|
438 |
+=head2 tx |
|
370 | 439 |
|
371 | 440 |
my $tx = $t->tx; |
372 | 441 |
$t = $t->tx(Mojo::Transaction::HTTP->new); |
... | ... |
@@ -380,7 +449,7 @@ Current transaction, usually a L<Mojo::Transaction::HTTP> object. |
380 | 449 |
# Test custom transactions |
381 | 450 |
$t->tx($t->tx->previous)->status_is(302)->header_like(Location => qr/foo/); |
382 | 451 |
|
383 |
-=head2 C<ua> |
|
452 |
+=head2 ua |
|
384 | 453 |
|
385 | 454 |
my $ua = $t->ua; |
386 | 455 |
$t = $t->ua(Mojo::UserAgent->new); |
... | ... |
@@ -404,7 +473,7 @@ User agent used for testing, defaults to a L<Mojo::UserAgent> object. |
404 | 473 |
L<Test::Mojo> inherits all methods from L<Mojo::Base> and implements the |
405 | 474 |
following new ones. |
406 | 475 |
|
407 |
-=head2 C<new> |
|
476 |
+=head2 new |
|
408 | 477 |
|
409 | 478 |
my $t = Test::Mojo->new; |
410 | 479 |
my $t = Test::Mojo->new('MyApp'); |
... | ... |
@@ -412,7 +481,7 @@ following new ones. |
412 | 481 |
|
413 | 482 |
Construct a new L<Test::Mojo> object. |
414 | 483 |
|
415 |
-=head2 C<app> |
|
484 |
+=head2 app |
|
416 | 485 |
|
417 | 486 |
my $app = $t->app; |
418 | 487 |
$t = $t->app(MyApp->new); |
... | ... |
@@ -437,63 +506,63 @@ Access application with L<Mojo::UserAgent/"app">. |
437 | 506 |
my $stash; |
438 | 507 |
$t->app->hook(after_dispatch => sub { $stash = shift->stash }); |
439 | 508 |
|
440 |
-=head2 C<content_is> |
|
509 |
+=head2 content_is |
|
441 | 510 |
|
442 | 511 |
$t = $t->content_is('working!'); |
443 | 512 |
$t = $t->content_is('working!', 'right content'); |
444 | 513 |
|
445 | 514 |
Check response content for exact match. |
446 | 515 |
|
447 |
-=head2 C<content_isnt> |
|
516 |
+=head2 content_isnt |
|
448 | 517 |
|
449 | 518 |
$t = $t->content_isnt('working!'); |
450 | 519 |
$t = $t->content_isnt('working!', 'different content'); |
451 | 520 |
|
452 | 521 |
Opposite of C<content_is>. |
453 | 522 |
|
454 |
-=head2 C<content_like> |
|
523 |
+=head2 content_like |
|
455 | 524 |
|
456 | 525 |
$t = $t->content_like(qr/working!/); |
457 | 526 |
$t = $t->content_like(qr/working!/, 'right content'); |
458 | 527 |
|
459 | 528 |
Check response content for similar match. |
460 | 529 |
|
461 |
-=head2 C<content_unlike> |
|
530 |
+=head2 content_unlike |
|
462 | 531 |
|
463 | 532 |
$t = $t->content_unlike(qr/working!/); |
464 | 533 |
$t = $t->content_unlike(qr/working!/, 'different content'); |
465 | 534 |
|
466 | 535 |
Opposite of C<content_like>. |
467 | 536 |
|
468 |
-=head2 C<content_type_is> |
|
537 |
+=head2 content_type_is |
|
469 | 538 |
|
470 | 539 |
$t = $t->content_type_is('text/html'); |
471 | 540 |
$t = $t->content_type_is('text/html', 'right content type'); |
472 | 541 |
|
473 | 542 |
Check response C<Content-Type> header for exact match. |
474 | 543 |
|
475 |
-=head2 C<content_type_isnt> |
|
544 |
+=head2 content_type_isnt |
|
476 | 545 |
|
477 | 546 |
$t = $t->content_type_isnt('text/html'); |
478 | 547 |
$t = $t->content_type_isnt('text/html', 'different content type'); |
479 | 548 |
|
480 | 549 |
Opposite of C<content_type_is>. |
481 | 550 |
|
482 |
-=head2 C<content_type_like> |
|
551 |
+=head2 content_type_like |
|
483 | 552 |
|
484 | 553 |
$t = $t->content_type_like(qr/text/); |
485 | 554 |
$t = $t->content_type_like(qr/text/, 'right content type'); |
486 | 555 |
|
487 | 556 |
Check response C<Content-Type> header for similar match. |
488 | 557 |
|
489 |
-=head2 C<content_type_unlike> |
|
558 |
+=head2 content_type_unlike |
|
490 | 559 |
|
491 | 560 |
$t = $t->content_type_unlike(qr/text/); |
492 | 561 |
$t = $t->content_type_unlike(qr/text/, 'different content type'); |
493 | 562 |
|
494 | 563 |
Opposite of C<content_type_like>. |
495 | 564 |
|
496 |
-=head2 C<delete_ok> |
|
565 |
+=head2 delete_ok |
|
497 | 566 |
|
498 | 567 |
$t = $t->delete_ok('/foo'); |
499 | 568 |
$t = $t->delete_ok('/foo' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -501,7 +570,7 @@ Opposite of C<content_type_like>. |
501 | 570 |
Perform a C<DELETE> request and check for transport errors, takes the same |
502 | 571 |
arguments as L<Mojo::UserAgent/"delete">. |
503 | 572 |
|
504 |
-=head2 C<element_exists> |
|
573 |
+=head2 element_exists |
|
505 | 574 |
|
506 | 575 |
$t = $t->element_exists('div.foo[x=y]'); |
507 | 576 |
$t = $t->element_exists('html head title', 'has a title'); |
... | ... |
@@ -509,21 +578,21 @@ arguments as L<Mojo::UserAgent/"delete">. |
509 | 578 |
Checks for existence of the CSS selectors first matching HTML/XML element with |
510 | 579 |
L<Mojo::DOM>. |
511 | 580 |
|
512 |
-=head2 C<element_exists_not> |
|
581 |
+=head2 element_exists_not |
|
513 | 582 |
|
514 | 583 |
$t = $t->element_exists_not('div.foo[x=y]'); |
515 | 584 |
$t = $t->element_exists_not('html head title', 'has no title'); |
516 | 585 |
|
517 | 586 |
Opposite of C<element_exists>. |
518 | 587 |
|
519 |
-=head2 C<finish_ok> |
|
588 |
+=head2 finish_ok |
|
520 | 589 |
|
521 | 590 |
$t = $t->finish_ok; |
522 | 591 |
$t = $t->finish_ok('finished successfully'); |
523 | 592 |
|
524 | 593 |
Finish C<WebSocket> connection. |
525 | 594 |
|
526 |
-=head2 C<get_ok> |
|
595 |
+=head2 get_ok |
|
527 | 596 |
|
528 | 597 |
$t = $t->get_ok('/foo'); |
529 | 598 |
$t = $t->get_ok('/foo' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -531,7 +600,7 @@ Finish C<WebSocket> connection. |
531 | 600 |
Perform a C<GET> request and check for transport errors, takes the same |
532 | 601 |
arguments as L<Mojo::UserAgent/"get">. |
533 | 602 |
|
534 |
-=head2 C<head_ok> |
|
603 |
+=head2 head_ok |
|
535 | 604 |
|
536 | 605 |
$t = $t->head_ok('/foo'); |
537 | 606 |
$t = $t->head_ok('/foo' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -539,35 +608,35 @@ arguments as L<Mojo::UserAgent/"get">. |
539 | 608 |
Perform a C<HEAD> request and check for transport errors, takes the same |
540 | 609 |
arguments as L<Mojo::UserAgent/"head">. |
541 | 610 |
|
542 |
-=head2 C<header_is> |
|
611 |
+=head2 header_is |
|
543 | 612 |
|
544 | 613 |
$t = $t->header_is(Expect => 'fun'); |
545 | 614 |
$t = $t->header_is(Expect => 'fun', 'right header'); |
546 | 615 |
|
547 | 616 |
Check response header for exact match. |
548 | 617 |
|
549 |
-=head2 C<header_isnt> |
|
618 |
+=head2 header_isnt |
|
550 | 619 |
|
551 | 620 |
$t = $t->header_isnt(Expect => 'fun'); |
552 | 621 |
$t = $t->header_isnt(Expect => 'fun', 'different header'); |
553 | 622 |
|
554 | 623 |
Opposite of C<header_is>. |
555 | 624 |
|
556 |
-=head2 C<header_like> |
|
625 |
+=head2 header_like |
|
557 | 626 |
|
558 | 627 |
$t = $t->header_like(Expect => qr/fun/); |
559 | 628 |
$t = $t->header_like(Expect => qr/fun/, 'right header'); |
560 | 629 |
|
561 | 630 |
Check response header for similar match. |
562 | 631 |
|
563 |
-=head2 C<header_unlike> |
|
632 |
+=head2 header_unlike |
|
564 | 633 |
|
565 | 634 |
$t = $t->header_like(Expect => qr/fun/); |
566 | 635 |
$t = $t->header_like(Expect => qr/fun/, 'different header'); |
567 | 636 |
|
568 | 637 |
Opposite of C<header_like>. |
569 | 638 |
|
570 |
-=head2 C<json_content_is> |
|
639 |
+=head2 json_content_is |
|
571 | 640 |
|
572 | 641 |
$t = $t->json_content_is([1, 2, 3]); |
573 | 642 |
$t = $t->json_content_is([1, 2, 3], 'right content'); |
... | ... |
@@ -575,16 +644,7 @@ Opposite of C<header_like>. |
575 | 644 |
|
576 | 645 |
Check response content for JSON data. |
577 | 646 |
|
578 |
-=head2 C<json_is> |
|
579 |
- |
|
580 |
- $t = $t->json_is('/foo' => {bar => [1, 2, 3]}); |
|
581 |
- $t = $t->json_is('/foo/bar' => [1, 2, 3]); |
|
582 |
- $t = $t->json_is('/foo/bar/1' => 2, 'right value'); |
|
583 |
- |
|
584 |
-Check the value extracted from JSON response using the given JSON Pointer with |
|
585 |
-L<Mojo::JSON::Pointer>. |
|
586 |
- |
|
587 |
-=head2 C<json_has> |
|
647 |
+=head2 json_has |
|
588 | 648 |
|
589 | 649 |
$t = $t->json_has('/foo'); |
590 | 650 |
$t = $t->json_has('/minibar', 'has a minibar'); |
... | ... |
@@ -592,42 +652,97 @@ L<Mojo::JSON::Pointer>. |
592 | 652 |
Check if JSON response contains a value that can be identified using the given |
593 | 653 |
JSON Pointer with L<Mojo::JSON::Pointer>. |
594 | 654 |
|
595 |
-=head2 C<json_hasnt> |
|
655 |
+=head2 json_hasnt |
|
596 | 656 |
|
597 | 657 |
$t = $t->json_hasnt('/foo'); |
598 | 658 |
$t = $t->json_hasnt('/minibar', 'no minibar'); |
599 | 659 |
|
600 | 660 |
Opposite of C<json_has>. |
601 | 661 |
|
602 |
-=head2 C<message_is> |
|
662 |
+=head2 json_is |
|
663 |
+ |
|
664 |
+ $t = $t->json_is('/' => {foo => [1, 2, 3]}); |
|
665 |
+ $t = $t->json_is('/foo' => [1, 2, 3]); |
|
666 |
+ $t = $t->json_is('/foo/1' => 2, 'right value'); |
|
667 |
+ |
|
668 |
+Check the value extracted from JSON response using the given JSON Pointer with |
|
669 |
+L<Mojo::JSON::Pointer>. |
|
670 |
+ |
|
671 |
+=head2 json_message_has |
|
672 |
+ |
|
673 |
+ $t = $t->json_message_has('/foo'); |
|
674 |
+ $t = $t->json_message_has('/minibar', 'has a minibar'); |
|
675 |
+ |
|
676 |
+Check if JSON WebSocket message contains a value that can be identified using |
|
677 |
+the given JSON Pointer with L<Mojo::JSON::Pointer>. |
|
678 |
+ |
|
679 |
+=head2 json_message_hasnt |
|
680 |
+ |
|
681 |
+ $t = $t->json_message_hasnt('/foo'); |
|
682 |
+ $t = $t->json_message_hasnt('/minibar', 'no minibar'); |
|
683 |
+ |
|
684 |
+Opposite of C<json_message_has>. |
|
685 |
+ |
|
686 |
+=head2 json_message_is |
|
603 | 687 |
|
688 |
+ $t = $t->json_message_is('/' => {foo => [1, 2, 3]}); |
|
689 |
+ $t = $t->json_message_is('/foo' => [1, 2, 3]); |
|
690 |
+ $t = $t->json_message_is('/foo/1' => 2, 'right value'); |
|
691 |
+ |
|
692 |
+Check the value extracted from JSON WebSocket message using the given JSON |
|
693 |
+Pointer with L<Mojo::JSON::Pointer>. |
|
694 |
+ |
|
695 |
+=head2 message_is |
|
696 |
+ |
|
697 |
+ $t = $t->message_is({binary => $bytes}); |
|
698 |
+ $t = $t->message_is({text => $bytes}); |
|
604 | 699 |
$t = $t->message_is('working!'); |
605 | 700 |
$t = $t->message_is('working!', 'right message'); |
606 | 701 |
|
607 | 702 |
Check WebSocket message for exact match. |
608 | 703 |
|
609 |
-=head2 C<message_isnt> |
|
704 |
+=head2 message_isnt |
|
610 | 705 |
|
706 |
+ $t = $t->message_isnt({binary => $bytes}); |
|
707 |
+ $t = $t->message_isnt({text => $bytes}); |
|
611 | 708 |
$t = $t->message_isnt('working!'); |
612 | 709 |
$t = $t->message_isnt('working!', 'different message'); |
613 | 710 |
|
614 | 711 |
Opposite of C<message_is>. |
615 | 712 |
|
616 |
-=head2 C<message_like> |
|
713 |
+=head2 message_like |
|
617 | 714 |
|
715 |
+ $t = $t->message_like({binary => qr/$bytes/}); |
|
716 |
+ $t = $t->message_like({text => qr/$bytes/}); |
|
618 | 717 |
$t = $t->message_like(qr/working!/); |
619 | 718 |
$t = $t->message_like(qr/working!/, 'right message'); |
620 | 719 |
|
621 | 720 |
Check WebSocket message for similar match. |
622 | 721 |
|
623 |
-=head2 C<message_unlike> |
|
722 |
+=head2 message_ok |
|
723 |
+ |
|
724 |
+ $t = $t->message_ok; |
|
725 |
+ $t = $t->message_ok('got a message'); |
|
726 |
+ |
|
727 |
+Wait for next WebSocket message to arrive. |
|
728 |
+ |
|
729 |
+ # Wait for message and perform multiple tests on it |
|
730 |
+ $t->websocket_ok('/time') |
|
731 |
+ ->message_ok |
|
732 |
+ ->message_like(qr/\d+/) |
|
733 |
+ ->message_unlike(qr/\w+/) |
|
734 |
+ ->finish_ok; |
|
735 |
+ |
|
736 |
+=head2 message_unlike |
|
624 | 737 |
|
738 |
+ $t = $t->message_unlike({binary => qr/$bytes/}); |
|
739 |
+ $t = $t->message_unlike({text => qr/$bytes/}); |
|
625 | 740 |
$t = $t->message_unlike(qr/working!/); |
626 | 741 |
$t = $t->message_unlike(qr/working!/, 'different message'); |
627 | 742 |
|
628 | 743 |
Opposite of C<message_like>. |
629 | 744 |
|
630 |
-=head2 C<options_ok> |
|
745 |
+=head2 options_ok |
|
631 | 746 |
|
632 | 747 |
$t = $t->options_ok('/foo'); |
633 | 748 |
$t = $t->options_ok('/foo' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -635,7 +750,7 @@ Opposite of C<message_like>. |
635 | 750 |
Perform a C<OPTIONS> request and check for transport errors, takes the same |
636 | 751 |
arguments as L<Mojo::UserAgent/"options">. |
637 | 752 |
|
638 |
-=head2 C<or> |
|
753 |
+=head2 or |
|
639 | 754 |
|
640 | 755 |
$t = $t->or(sub {...}); |
641 | 756 |
|
... | ... |
@@ -645,7 +760,7 @@ Invoke callback if previous test failed. |
645 | 760 |
$t->get_ok('/bad')->or(sub { diag 'Must have been Glen!' }) |
646 | 761 |
->status_is(200)->or(sub { diag $t->tx->res->dom->at('title')->text }); |
647 | 762 |
|
648 |
-=head2 C<patch_ok> |
|
763 |
+=head2 patch_ok |
|
649 | 764 |
|
650 | 765 |
$t = $t->patch_ok('/foo'); |
651 | 766 |
$t = $t->patch_ok('/foo' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -653,7 +768,7 @@ Invoke callback if previous test failed. |
653 | 768 |
Perform a C<PATCH> request and check for transport errors, takes the same |
654 | 769 |
arguments as L<Mojo::UserAgent/"patch">. |
655 | 770 |
|
656 |
-=head2 C<post_ok> |
|
771 |
+=head2 post_ok |
|
657 | 772 |
|
658 | 773 |
$t = $t->post_ok('/foo'); |
659 | 774 |
$t = $t->post_ok('/foo' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -661,7 +776,7 @@ arguments as L<Mojo::UserAgent/"patch">. |
661 | 776 |
Perform a C<POST> request and check for transport errors, takes the same |
662 | 777 |
arguments as L<Mojo::UserAgent/"post">. |
663 | 778 |
|
664 |
-=head2 C<post_form_ok> |
|
779 |
+=head2 post_form_ok |
|
665 | 780 |
|
666 | 781 |
$t = $t->post_form_ok('/foo' => {a => 'b'}); |
667 | 782 |
$t = $t->post_form_ok('/foo' => 'UTF-8' => {a => 'b'} => {DNT => 1}); |
... | ... |
@@ -672,7 +787,7 @@ the same arguments as L<Mojo::UserAgent/"post_form">. |
672 | 787 |
# Test file upload |
673 | 788 |
$t->post_form_ok('/upload' => {foo => {content => 'bar'}})->status_is(200); |
674 | 789 |
|
675 |
-=head2 C<post_json_ok> |
|
790 |
+=head2 post_json_ok |
|
676 | 791 |
|
677 | 792 |
$t = $t->post_json_ok('/foo' => {a => 'b'}); |
678 | 793 |
$t = $t->post_json_ok('/foo' => {a => 'b'} => {DNT => 1}); |
... | ... |
@@ -685,7 +800,7 @@ the same arguments as L<Mojo::UserAgent/"post_json">. |
685 | 800 |
->status_is(200) |
686 | 801 |
->json_content_is({bye => 'world'}); |
687 | 802 |
|
688 |
-=head2 C<put_ok> |
|
803 |
+=head2 put_ok |
|
689 | 804 |
|
690 | 805 |
$t = $t->put_ok('/foo'); |
691 | 806 |
$t = $t->put_ok('/foo' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -693,7 +808,7 @@ the same arguments as L<Mojo::UserAgent/"post_json">. |
693 | 808 |
Perform a C<PUT> request and check for transport errors, takes the same |
694 | 809 |
arguments as L<Mojo::UserAgent/"put">. |
695 | 810 |
|
696 |
-=head2 C<request_ok> |
|
811 |
+=head2 request_ok |
|
697 | 812 |
|
698 | 813 |
$t = $t->request_ok(Mojo::Transaction::HTTP->new); |
699 | 814 |
$t = $t->request_ok(Mojo::Transaction::HTTP->new, 'request successful'); |
... | ... |
@@ -707,37 +822,37 @@ Perform request and check for transport errors. |
707 | 822 |
->status_is(200) |
708 | 823 |
->json_is('/message' => 'User has been replaced.'); |
709 | 824 |
|
710 |
-=head2 C<reset_session> |
|
825 |
+=head2 reset_session |
|
711 | 826 |
|
712 | 827 |
$t = $t->reset_session; |
713 | 828 |
|
714 | 829 |
Reset user agent session. |
715 | 830 |
|
716 |
-=head2 C<send_ok> |
|
831 |
+=head2 send_ok |
|
717 | 832 |
|
718 | 833 |
$t = $t->send_ok({binary => $bytes}); |
719 | 834 |
$t = $t->send_ok({text => $bytes}); |
720 | 835 |
$t = $t->send_ok([$fin, $rsv1, $rsv2, $rsv3, $op, $payload]); |
721 |
- $t = $t->send_ok('hello'); |
|
722 |
- $t = $t->send_ok('hello', 'sent successfully'); |
|
836 |
+ $t = $t->send_ok($chars); |
|
837 |
+ $t = $t->send_ok($chars, 'sent successfully'); |
|
723 | 838 |
|
724 | 839 |
Send message or frame via WebSocket. |
725 | 840 |
|
726 |
-=head2 C<status_is> |
|
841 |
+=head2 status_is |
|
727 | 842 |
|
728 | 843 |
$t = $t->status_is(200); |
729 | 844 |
$t = $t->status_is(200, 'right status'); |
730 | 845 |
|
731 | 846 |
Check response status for exact match. |
732 | 847 |
|
733 |
-=head2 C<status_isnt> |
|
848 |
+=head2 status_isnt |
|
734 | 849 |
|
735 | 850 |
$t = $t->status_isnt(200); |
736 | 851 |
$t = $t->status_isnt(200, 'different status'); |
737 | 852 |
|
738 | 853 |
Opposite of C<status_is>. |
739 | 854 |
|
740 |
-=head2 C<text_is> |
|
855 |
+=head2 text_is |
|
741 | 856 |
|
742 | 857 |
$t = $t->text_is('div.foo[x=y]' => 'Hello!'); |
743 | 858 |
$t = $t->text_is('html head title' => 'Hello!', 'right title'); |
... | ... |
@@ -745,14 +860,14 @@ Opposite of C<status_is>. |
745 | 860 |
Checks text content of the CSS selectors first matching HTML/XML element for |
746 | 861 |
exact match with L<Mojo::DOM>. |
747 | 862 |
|
748 |
-=head2 C<text_isnt> |
|
863 |
+=head2 text_isnt |
|
749 | 864 |
|
750 | 865 |
$t = $t->text_isnt('div.foo[x=y]' => 'Hello!'); |
751 | 866 |
$t = $t->text_isnt('html head title' => 'Hello!', 'different title'); |
752 | 867 |
|
753 | 868 |
Opposite of C<text_is>. |
754 | 869 |
|
755 |
-=head2 C<text_like> |
|
870 |
+=head2 text_like |
|
756 | 871 |
|
757 | 872 |
$t = $t->text_like('div.foo[x=y]' => qr/Hello/); |
758 | 873 |
$t = $t->text_like('html head title' => qr/Hello/, 'right title'); |
... | ... |
@@ -760,14 +875,14 @@ Opposite of C<text_is>. |
760 | 875 |
Checks text content of the CSS selectors first matching HTML/XML element for |
761 | 876 |
similar match with L<Mojo::DOM>. |
762 | 877 |
|
763 |
-=head2 C<text_unlike> |
|
878 |
+=head2 text_unlike |
|
764 | 879 |
|
765 | 880 |
$t = $t->text_unlike('div.foo[x=y]' => qr/Hello/); |
766 | 881 |
$t = $t->text_unlike('html head title' => qr/Hello/, 'different title'); |
767 | 882 |
|
768 | 883 |
Opposite of C<text_like>. |
769 | 884 |
|
770 |
-=head2 C<websocket_ok> |
|
885 |
+=head2 websocket_ok |
|
771 | 886 |
|
772 | 887 |
$t = $t->websocket_ok('/echo'); |
773 | 888 |
$t = $t->websocket_ok('/echo' => {DNT => 1}); |
... | ... |
@@ -4,14 +4,14 @@ use Mojo::Base -strict; |
4 | 4 |
use Mojo::ByteStream 'b'; |
5 | 5 |
use Mojo::Collection 'c'; |
6 | 6 |
use Mojo::DOM; |
7 |
-use Mojo::JSON; |
|
7 |
+use Mojo::JSON 'j'; |
|
8 | 8 |
use Mojo::UserAgent; |
9 | 9 |
use Mojo::Util 'monkey_patch'; |
10 | 10 |
|
11 | 11 |
# Silent oneliners |
12 | 12 |
$ENV{MOJO_LOG_LEVEL} ||= 'fatal'; |
13 | 13 |
|
14 |
-# User agent |
|
14 |
+# Singleton user agent for oneliners |
|
15 | 15 |
my $UA = Mojo::UserAgent->new; |
16 | 16 |
|
17 | 17 |
sub import { |
... | ... |
@@ -19,38 +19,28 @@ sub import { |
19 | 19 |
# Mojolicious::Lite |
20 | 20 |
my $caller = caller; |
21 | 21 |
eval "package $caller; use Mojolicious::Lite;"; |
22 |
+ $UA->app($caller->app); |
|
22 | 23 |
|
23 |
- # Allow redirects |
|
24 | 24 |
$UA->max_redirects(10) unless defined $ENV{MOJO_MAX_REDIRECTS}; |
25 |
- |
|
26 |
- # Detect proxy |
|
27 | 25 |
$UA->detect_proxy unless defined $ENV{MOJO_PROXY}; |
28 | 26 |
|
29 |
- # Application |
|
30 |
- $UA->app($caller->app); |
|
31 |
- |
|
32 |
- # Functions |
|
33 |
- monkey_patch $caller, 'a', |
|
34 |
- sub { $caller->can('any')->(@_) and return $UA->app }; |
|
35 |
- monkey_patch $caller, 'b', \&b; |
|
36 |
- monkey_patch $caller, 'c', \&c; |
|
37 |
- monkey_patch $caller, 'd', sub { _request($UA->build_tx(DELETE => @_)) }; |
|
38 |
- monkey_patch $caller, 'f', sub { _request($UA->build_form_tx(@_)) }; |
|
39 |
- monkey_patch $caller, 'g', sub { _request($UA->build_tx(GET => @_)) }; |
|
40 |
- monkey_patch $caller, 'h', sub { _request($UA->build_tx(HEAD => @_)) }; |
|
41 |
- monkey_patch $caller, 'j', sub { |
|
42 |
- my $d = shift; |
|
43 |
- my $j = Mojo::JSON->new; |
|
44 |
- return $j->encode($d) if ref $d eq 'ARRAY' || ref $d eq 'HASH'; |
|
45 |
- return $j->decode($d); |
|
46 |
- }; |
|
47 |
- monkey_patch $caller, 'n', sub { _request($UA->build_json_tx(@_)) }; |
|
48 |
- monkey_patch $caller, 'o', sub { _request($UA->build_tx(OPTIONS => @_)) }; |
|
49 |
- monkey_patch $caller, 'p', sub { _request($UA->build_tx(POST => @_)) }; |
|
50 |
- monkey_patch $caller, 'r', sub { $UA->app->dumper(@_) }; |
|
51 |
- monkey_patch $caller, 't', sub { _request($UA->build_tx(PATCH => @_)) }; |
|
52 |
- monkey_patch $caller, 'u', sub { _request($UA->build_tx(PUT => @_)) }; |
|
53 |
- monkey_patch $caller, 'x', sub { Mojo::DOM->new(@_) }; |
|
27 |
+ # The ojo DSL |
|
28 |
+ monkey_patch $caller, |
|
29 |
+ a => sub { $caller->can('any')->(@_) and return $UA->app }, |
|
30 |
+ b => \&b, |
|
31 |
+ c => \&c, |
|
32 |
+ d => sub { _request($UA->build_tx(DELETE => @_)) }, |
|
33 |
+ f => sub { _request($UA->build_form_tx(@_)) }, |
|
34 |
+ g => sub { _request($UA->build_tx(GET => @_)) }, |
|
35 |
+ h => sub { _request($UA->build_tx(HEAD => @_)) }, |
|
36 |
+ j => \&j, |
|
37 |
+ n => sub { _request($UA->build_json_tx(@_)) }, |
|
38 |
+ o => sub { _request($UA->build_tx(OPTIONS => @_)) }, |
|
39 |
+ p => sub { _request($UA->build_tx(POST => @_)) }, |
|
40 |
+ r => sub { $UA->app->dumper(@_) }, |
|
41 |
+ t => sub { _request($UA->build_tx(PATCH => @_)) }, |
|
42 |
+ u => sub { _request($UA->build_tx(PUT => @_)) }, |
|
43 |
+ x => sub { Mojo::DOM->new(@_) }; |
|
54 | 44 |
} |
55 | 45 |
|
56 | 46 |
sub _request { |
... | ... |
@@ -88,7 +78,7 @@ C<MOJO_PROXY> environment variable. |
88 | 78 |
|
89 | 79 |
L<ojo> implements the following functions. |
90 | 80 |
|
91 |
-=head2 C<a> |
|
81 |
+=head2 a |
|
92 | 82 |
|
93 | 83 |
my $app = a('/hello' => sub { shift->render(json => {hello => 'world'}) }); |
94 | 84 |
|
... | ... |
@@ -98,7 +88,7 @@ more argument variations. |
98 | 88 |
|
99 | 89 |
$ perl -Mojo -E 'a("/hello" => {text => "Hello Mojo!"})->start' daemon |
100 | 90 |
|
101 |
-=head2 C<b> |
|
91 |
+=head2 b |
|
102 | 92 |
|
103 | 93 |
my $stream = b('lalala'); |
104 | 94 |
|
... | ... |
@@ -106,13 +96,13 @@ Turn string into a L<Mojo::ByteStream> object. |
106 | 96 |
|
107 | 97 |
$ perl -Mojo -E 'b(g("mojolicio.us")->body)->html_unescape->say' |
108 | 98 |
|
109 |
-=head2 C<c> |
|
99 |
+=head2 c |
|
110 | 100 |
|
111 | 101 |
my $collection = c(1, 2, 3); |
112 | 102 |
|
113 | 103 |
Turn list into a L<Mojo::Collection> object. |
114 | 104 |
|
115 |
-=head2 C<d> |
|
105 |
+=head2 d |
|
116 | 106 |
|
117 | 107 |
my $res = d('mojolicio.us'); |
118 | 108 |
my $res = d('http://mojolicio.us' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -120,7 +110,7 @@ Turn list into a L<Mojo::Collection> object. |
120 | 110 |
Perform C<DELETE> request with L<Mojo::UserAgent/"delete"> and return |
121 | 111 |
resulting L<Mojo::Message::Response> object. |
122 | 112 |
|
123 |
-=head2 C<f> |
|
113 |
+=head2 f |
|
124 | 114 |
|
125 | 115 |
my $res = f('http://kraih.com' => {a => 'b'}); |
126 | 116 |
my $res = f('kraih.com' => 'UTF-8' => {a => 'b'} => {DNT => 1}); |
... | ... |
@@ -128,7 +118,7 @@ resulting L<Mojo::Message::Response> object. |
128 | 118 |
Perform C<POST> request with L<Mojo::UserAgent/"post_form"> and return |
129 | 119 |
resulting L<Mojo::Message::Response> object. |
130 | 120 |
|
131 |
-=head2 C<g> |
|
121 |
+=head2 g |
|
132 | 122 |
|
133 | 123 |
my $res = g('mojolicio.us'); |
134 | 124 |
my $res = g('http://mojolicio.us' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -138,7 +128,7 @@ L<Mojo::Message::Response> object. |
138 | 128 |
|
139 | 129 |
$ perl -Mojo -E 'say g("mojolicio.us")->dom("h1, h2, h3")->pluck("text")' |
140 | 130 |
|
141 |
-=head2 C<h> |
|
131 |
+=head2 h |
|
142 | 132 |
|
143 | 133 |
my $res = h('mojolicio.us'); |
144 | 134 |
my $res = h('http://mojolicio.us' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -146,7 +136,7 @@ L<Mojo::Message::Response> object. |
146 | 136 |
Perform C<HEAD> request with L<Mojo::UserAgent/"head"> and return resulting |
147 | 137 |
L<Mojo::Message::Response> object. |
148 | 138 |
|
149 |
-=head2 C<j> |
|
139 |
+=head2 j |
|
150 | 140 |
|
151 | 141 |
my $bytes = j({foo => 'bar'}); |
152 | 142 |
my $array = j($bytes); |
... | ... |
@@ -156,7 +146,7 @@ Encode Perl data structure or decode JSON with L<Mojo::JSON>. |
156 | 146 |
|
157 | 147 |
$ perl -Mojo -E 'b(j({hello => "world!"}))->spurt("hello.json")' |
158 | 148 |
|
159 |
-=head2 C<n> |
|
149 |
+=head2 n |
|
160 | 150 |
|
161 | 151 |
my $res = n('http://kraih.com' => {a => 'b'}); |
162 | 152 |
my $res = n('kraih.com' => {a => 'b'} => {DNT => 1}); |
... | ... |
@@ -164,7 +154,7 @@ Encode Perl data structure or decode JSON with L<Mojo::JSON>. |
164 | 154 |
Perform C<POST> request with L<Mojo::UserAgent/"post_json"> and return |
165 | 155 |
resulting L<Mojo::Message::Response> object. |
166 | 156 |
|
167 |
-=head2 C<o> |
|
157 |
+=head2 o |
|
168 | 158 |
|
169 | 159 |
my $res = o('mojolicio.us'); |
170 | 160 |
my $res = o('http://mojolicio.us' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -172,7 +162,7 @@ resulting L<Mojo::Message::Response> object. |
172 | 162 |
Perform C<OPTIONS> request with L<Mojo::UserAgent/"options"> and return |
173 | 163 |
resulting L<Mojo::Message::Response> object. |
174 | 164 |
|
175 |
-=head2 C<p> |
|
165 |
+=head2 p |
|
176 | 166 |
|
177 | 167 |
my $res = p('mojolicio.us'); |
178 | 168 |
my $res = p('http://mojolicio.us' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -180,7 +170,7 @@ resulting L<Mojo::Message::Response> object. |
180 | 170 |
Perform C<POST> request with L<Mojo::UserAgent/"post"> and return resulting |
181 | 171 |
L<Mojo::Message::Response> object. |
182 | 172 |
|
183 |
-=head2 C<r> |
|
173 |
+=head2 r |
|
184 | 174 |
|
185 | 175 |
my $perl = r({data => 'structure'}); |
186 | 176 |
|
... | ... |
@@ -188,7 +178,7 @@ Dump a Perl data structure with L<Data::Dumper>. |
188 | 178 |
|
189 | 179 |
perl -Mojo -E 'say r(g("mojolicio.us")->headers->to_hash)' |
190 | 180 |
|
191 |
-=head2 C<t> |
|
181 |
+=head2 t |
|
192 | 182 |
|
193 | 183 |
my $res = t('mojolicio.us'); |
194 | 184 |
my $res = t('http://mojolicio.us' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -196,7 +186,7 @@ Dump a Perl data structure with L<Data::Dumper>. |
196 | 186 |
Perform C<PATCH> request with L<Mojo::UserAgent/"patch"> and return resulting |
197 | 187 |
L<Mojo::Message::Response> object. |
198 | 188 |
|
199 |
-=head2 C<u> |
|
189 |
+=head2 u |
|
200 | 190 |
|
201 | 191 |
my $res = u('mojolicio.us'); |
202 | 192 |
my $res = u('http://mojolicio.us' => {DNT => 1} => 'Hi!'); |
... | ... |
@@ -204,7 +194,7 @@ L<Mojo::Message::Response> object. |
204 | 194 |
Perform C<PUT> request with L<Mojo::UserAgent/"put"> and return resulting |
205 | 195 |
L<Mojo::Message::Response> object. |
206 | 196 |
|
207 |
-=head2 C<x> |
|
197 |
+=head2 x |
|
208 | 198 |
|
209 | 199 |
my $dom = x('<div>Hello!</div>'); |
210 | 200 |
|
... | ... |
@@ -15,7 +15,6 @@ GetOptions( |
15 | 15 |
't|test' => sub { $ENV{HYPNOTOAD_TEST} = 1 } |
16 | 16 |
); |
17 | 17 |
|
18 |
-# Usage |
|
19 | 18 |
die <<"EOF" if $help || !(my $app = shift || $ENV{HYPNOTOAD_APP}); |
20 | 19 |
usage: $0 [OPTIONS] [APPLICATION] |
21 | 20 |
|
... | ... |
@@ -7,7 +7,7 @@ use FindBin; |
7 | 7 |
use lib "$FindBin::Bin/../lib"; |
8 | 8 |
|
9 | 9 |
require Mojolicious::Commands; |
10 |
-Mojolicious::Commands->start; |
|
10 |
+Mojolicious::Commands->start_app('Mojo::HelloWorld'); |
|
11 | 11 |
|
12 | 12 |
=head1 NAME |
13 | 13 |
|
... | ... |
@@ -15,7 +15,6 @@ GetOptions( |
15 | 15 |
'w|watch=s' => \my @watch |
16 | 16 |
); |
17 | 17 |
|
18 |
-# Usage |
|
19 | 18 |
die <<"EOF" if $help || !(my $app = shift); |
20 | 19 |
usage: $0 [OPTIONS] [APPLICATION] |
21 | 20 |
|
... | ... |
@@ -16,8 +16,5 @@ Please visit http://mojolicio.us for detailed installation instructions. |
16 | 16 |
|
17 | 17 |
EOF |
18 | 18 |
|
19 |
-# Application |
|
20 |
-$ENV{MOJO_APP} ||= 'Gitprep'; |
|
21 |
- |
|
22 | 19 |
# Start commands |
23 |
-Mojolicious::Commands->start; |
|
20 |
+Mojolicious::Commands->start_app('Gitprep'); |
... | ... |
@@ -64,12 +64,20 @@ |
64 | 64 |
|
65 | 65 |
% layout 'common'; |
66 | 66 |
|
67 |
+ % my $logined = $api->logined; |
|
68 |
+ |
|
67 | 69 |
%= javascript begin |
68 | 70 |
$(document).ready(function () { |
69 | 71 |
var http_rep_url = '<%= url_for("$user/$project.git")->to_abs %>'; |
70 | 72 |
% my $execute_user = getpwuid($>); |
71 | 73 |
% my $rep = $git->rep($user, $project); |
72 |
- var ssh_rep_url = '<%= url_for($rep)->to_abs->scheme('ssh')->userinfo($execute_user)->port('') %>'; |
|
74 |
+ % my $ssh_port = config->{basic}{ssh_port} || ''; |
|
75 |
+ |
|
76 |
+ var logined = <%= $logined ? 'true' : 'false' %>; |
|
77 |
+ var ssh_rep_url = ''; |
|
78 |
+ if (logined) { |
|
79 |
+ ssh_rep_url = '<%= url_for($rep)->to_abs->scheme('ssh')->userinfo($execute_user)->port($ssh_port) %>'; |
|
80 |
+ } |
|
73 | 81 |
|
74 | 82 |
// Click HTTP button |
75 | 83 |
$('#btn_http').on('click', function () { |
... | ... |
@@ -84,7 +92,6 @@ |
84 | 92 |
}); |
85 | 93 |
|
86 | 94 |
// Initialize |
87 |
- var logined = <%= $api->logined ? 'true' : 'false' %>; |
|
88 | 95 |
if (logined) { |
89 | 96 |
$('#btn_ssh').trigger('click'); |
90 | 97 |
} |
... | ... |
@@ -111,7 +118,9 @@ |
111 | 118 |
<div class="input-append" style="margin-top:10px"> |
112 | 119 |
<div class="btn-group" data-toggle="buttons-radio"> |
113 | 120 |
<button class="btn" id="btn_http" style="border-radius:0">HTTP</button> |
114 |
- <button class="btn" id="btn_ssh" style="border-radius:0">SSH</button> |
|
121 |
+ % if ($logined) { |
|
122 |
+ <button class="btn" id="btn_ssh" style="border-radius:0">SSH</button> |
|
123 |
+ % } |
|
115 | 124 |
</div> |
116 | 125 |
<input class="span8" id="rep_url" type="text" style="border-radius:0;"> |
117 | 126 |
</div> |
... | ... |
@@ -144,7 +153,7 @@ |
144 | 153 |
</div> |
145 | 154 |
|
146 | 155 |
% my $url = url_for->to_abs; |
147 |
- % my $ssh_port = config->{ssh_port}; |
|
156 |
+ % my $ssh_port = config->{basic}{ssh_port}; |
|
148 | 157 |
% my $rep_home = app->git->rep_home; |
149 | 158 |
% my $ssh_url = 'ssh://kimoto@' . $url->host |
150 | 159 |
% . ($ssh_port ? ":$ssh_port" : '') . "$rep_home/$user/$project.git"; |