Skip Alien-Ditaa
[gitmo/Moose.git] / t / examples / example_Moose_POOP.t
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use Test::More;
7
8 use Test::Requires {
9     'DBM::Deep' => '1.0003', # skip all if not installed
10     'DateTime::Format::MySQL' => '0.01',
11 };
12
13 use Test::Fatal;
14
15 BEGIN {
16     # in case there are leftovers
17     unlink('newswriter.db') if -e 'newswriter.db';
18 }
19
20 END {
21     unlink('newswriter.db') if -e 'newswriter.db';
22 }
23
24
25 =pod
26
27 This example creates a very basic Object Database which
28 links in the instances created with a backend store
29 (a DBM::Deep hash). It is by no means to be taken seriously
30 as a real-world ODB, but is a proof of concept of the flexibility
31 of the ::Instance protocol.
32
33 =cut
34
35 BEGIN {
36
37     package MooseX::POOP::Meta::Instance;
38     use Moose;
39
40     use DBM::Deep;
41
42     extends 'Moose::Meta::Instance';
43
44     {
45         my %INSTANCE_COUNTERS;
46
47         my $db = DBM::Deep->new({
48             file      => "newswriter.db",
49             autobless => 1,
50             locking   => 1,
51         });
52
53         sub _reload_db {
54             #use Data::Dumper;
55             #warn Dumper $db;
56             $db = undef;
57             $db = DBM::Deep->new({
58                 file      => "newswriter.db",
59                 autobless => 1,
60                 locking   => 1,
61             });
62         }
63
64         sub create_instance {
65             my $self  = shift;
66             my $class = $self->associated_metaclass->name;
67             my $oid   = ++$INSTANCE_COUNTERS{$class};
68
69             $db->{$class}->[($oid - 1)] = {};
70
71             bless {
72                 oid      => $oid,
73                 instance => $db->{$class}->[($oid - 1)]
74             }, $class;
75         }
76
77         sub find_instance {
78             my ($self, $oid) = @_;
79             my $instance = $db->{$self->associated_metaclass->name}->[($oid - 1)];
80
81             bless {
82                 oid      => $oid,
83                 instance => $instance,
84             }, $self->associated_metaclass->name;
85         }
86
87         sub clone_instance {
88             my ($self, $instance) = @_;
89
90             my $class = $self->{meta}->name;
91             my $oid   = ++$INSTANCE_COUNTERS{$class};
92
93             my $clone = tied($instance)->clone;
94
95             bless {
96                 oid      => $oid,
97                 instance => $clone,
98             }, $class;
99         }
100     }
101
102     sub get_instance_oid {
103         my ($self, $instance) = @_;
104         $instance->{oid};
105     }
106
107     sub get_slot_value {
108         my ($self, $instance, $slot_name) = @_;
109         return $instance->{instance}->{$slot_name};
110     }
111
112     sub set_slot_value {
113         my ($self, $instance, $slot_name, $value) = @_;
114         $instance->{instance}->{$slot_name} = $value;
115     }
116
117     sub is_slot_initialized {
118         my ($self, $instance, $slot_name, $value) = @_;
119         exists $instance->{instance}->{$slot_name} ? 1 : 0;
120     }
121
122     sub weaken_slot_value {
123         confess "Not sure how well DBM::Deep plays with weak refs, Rob says 'Write a test'";
124     }
125
126     sub inline_slot_access {
127         my ($self, $instance, $slot_name) = @_;
128         sprintf "%s->{instance}->{%s}", $instance, $slot_name;
129     }
130
131     package MooseX::POOP::Meta::Class;
132     use Moose;
133
134     extends 'Moose::Meta::Class';
135
136     override '_construct_instance' => sub {
137         my $class = shift;
138         my $params = @_ == 1 ? $_[0] : {@_};
139         return $class->get_meta_instance->find_instance($params->{oid})
140             if $params->{oid};
141         super();
142     };
143
144 }
145 {
146     package MooseX::POOP::Object;
147     use metaclass 'MooseX::POOP::Meta::Class' => (
148         instance_metaclass => 'MooseX::POOP::Meta::Instance'
149     );
150     use Moose;
151
152     sub oid {
153         my $self = shift;
154         $self->meta
155              ->get_meta_instance
156              ->get_instance_oid($self);
157     }
158
159 }
160 {
161     package Newswriter::Author;
162     use Moose;
163
164     extends 'MooseX::POOP::Object';
165
166     has 'first_name' => (is => 'rw', isa => 'Str');
167     has 'last_name'  => (is => 'rw', isa => 'Str');
168
169     package Newswriter::Article;
170     use Moose;
171     use Moose::Util::TypeConstraints;
172
173     use DateTime::Format::MySQL;
174
175     extends 'MooseX::POOP::Object';
176
177     subtype 'Headline'
178         => as 'Str'
179         => where { length($_) < 100 };
180
181     subtype 'Summary'
182         => as 'Str'
183         => where { length($_) < 255 };
184
185     subtype 'DateTimeFormatString'
186         => as 'Str'
187         => where { DateTime::Format::MySQL->parse_datetime($_) };
188
189     enum 'Status' => qw(draft posted pending archive);
190
191     has 'headline' => (is => 'rw', isa => 'Headline');
192     has 'summary'  => (is => 'rw', isa => 'Summary');
193     has 'article'  => (is => 'rw', isa => 'Str');
194
195     has 'start_date' => (is => 'rw', isa => 'DateTimeFormatString');
196     has 'end_date'   => (is => 'rw', isa => 'DateTimeFormatString');
197
198     has 'author' => (is => 'rw', isa => 'Newswriter::Author');
199
200     has 'status' => (is => 'rw', isa => 'Status');
201
202     around 'start_date', 'end_date' => sub {
203         my $c    = shift;
204         my $self = shift;
205         $c->($self, DateTime::Format::MySQL->format_datetime($_[0])) if @_;
206         DateTime::Format::MySQL->parse_datetime($c->($self) || return undef);
207     };
208 }
209
210 { # check the meta stuff first
211     isa_ok(MooseX::POOP::Object->meta, 'MooseX::POOP::Meta::Class');
212     isa_ok(MooseX::POOP::Object->meta, 'Moose::Meta::Class');
213     isa_ok(MooseX::POOP::Object->meta, 'Class::MOP::Class');
214
215     is(MooseX::POOP::Object->meta->instance_metaclass,
216       'MooseX::POOP::Meta::Instance',
217       '... got the right instance metaclass name');
218
219     isa_ok(MooseX::POOP::Object->meta->get_meta_instance, 'MooseX::POOP::Meta::Instance');
220
221     my $base = MooseX::POOP::Object->new;
222     isa_ok($base, 'MooseX::POOP::Object');
223     isa_ok($base, 'Moose::Object');
224
225     isa_ok($base->meta, 'MooseX::POOP::Meta::Class');
226     isa_ok($base->meta, 'Moose::Meta::Class');
227     isa_ok($base->meta, 'Class::MOP::Class');
228
229     is($base->meta->instance_metaclass,
230       'MooseX::POOP::Meta::Instance',
231       '... got the right instance metaclass name');
232
233     isa_ok($base->meta->get_meta_instance, 'MooseX::POOP::Meta::Instance');
234 }
235
236 my $article_oid;
237 my $article_ref;
238 {
239     my $article;
240     is( exception {
241         $article = Newswriter::Article->new(
242             headline => 'Home Office Redecorated',
243             summary  => 'The home office was recently redecorated to match the new company colors',
244             article  => '...',
245
246             author => Newswriter::Author->new(
247                 first_name => 'Truman',
248                 last_name  => 'Capote'
249             ),
250
251             status => 'pending'
252         );
253     }, undef, '... created my article successfully' );
254     isa_ok($article, 'Newswriter::Article');
255     isa_ok($article, 'MooseX::POOP::Object');
256
257     is( exception {
258         $article->start_date(DateTime->new(year => 2006, month => 6, day => 10));
259         $article->end_date(DateTime->new(year => 2006, month => 6, day => 17));
260     }, undef, '... add the article date-time stuff' );
261
262     ## check some meta stuff
263
264     isa_ok($article->meta, 'MooseX::POOP::Meta::Class');
265     isa_ok($article->meta, 'Moose::Meta::Class');
266     isa_ok($article->meta, 'Class::MOP::Class');
267
268     is($article->meta->instance_metaclass,
269       'MooseX::POOP::Meta::Instance',
270       '... got the right instance metaclass name');
271
272     isa_ok($article->meta->get_meta_instance, 'MooseX::POOP::Meta::Instance');
273
274     ok($article->oid, '... got a oid for the article');
275
276     $article_oid = $article->oid;
277     $article_ref = "$article";
278
279     is($article->headline,
280        'Home Office Redecorated',
281        '... got the right headline');
282     is($article->summary,
283        'The home office was recently redecorated to match the new company colors',
284        '... got the right summary');
285     is($article->article, '...', '... got the right article');
286
287     isa_ok($article->start_date, 'DateTime');
288     isa_ok($article->end_date,   'DateTime');
289
290     isa_ok($article->author, 'Newswriter::Author');
291     is($article->author->first_name, 'Truman', '... got the right author first name');
292     is($article->author->last_name, 'Capote', '... got the right author last name');
293
294     is($article->status, 'pending', '... got the right status');
295 }
296
297 MooseX::POOP::Meta::Instance->_reload_db();
298
299 my $article2_oid;
300 my $article2_ref;
301 {
302     my $article2;
303     is( exception {
304         $article2 = Newswriter::Article->new(
305             headline => 'Company wins Lottery',
306             summary  => 'An email was received today that informed the company we have won the lottery',
307             article  => 'WoW',
308
309             author => Newswriter::Author->new(
310                 first_name => 'Katie',
311                 last_name  => 'Couric'
312             ),
313
314             status => 'posted'
315         );
316     }, undef, '... created my article successfully' );
317     isa_ok($article2, 'Newswriter::Article');
318     isa_ok($article2, 'MooseX::POOP::Object');
319
320     $article2_oid = $article2->oid;
321     $article2_ref = "$article2";
322
323     is($article2->headline,
324        'Company wins Lottery',
325        '... got the right headline');
326     is($article2->summary,
327        'An email was received today that informed the company we have won the lottery',
328        '... got the right summary');
329     is($article2->article, 'WoW', '... got the right article');
330
331     ok(!$article2->start_date, '... these two dates are unassigned');
332     ok(!$article2->end_date,   '... these two dates are unassigned');
333
334     isa_ok($article2->author, 'Newswriter::Author');
335     is($article2->author->first_name, 'Katie', '... got the right author first name');
336     is($article2->author->last_name, 'Couric', '... got the right author last name');
337
338     is($article2->status, 'posted', '... got the right status');
339
340     ## orig-article
341
342     my $article;
343     is( exception {
344         $article = Newswriter::Article->new(oid => $article_oid);
345     }, undef, '... (re)-created my article successfully' );
346     isa_ok($article, 'Newswriter::Article');
347     isa_ok($article, 'MooseX::POOP::Object');
348
349     is($article->oid, $article_oid, '... got a oid for the article');
350     isnt($article_ref, "$article", '... got a new article instance');
351
352     is($article->headline,
353        'Home Office Redecorated',
354        '... got the right headline');
355     is($article->summary,
356        'The home office was recently redecorated to match the new company colors',
357        '... got the right summary');
358     is($article->article, '...', '... got the right article');
359
360     isa_ok($article->start_date, 'DateTime');
361     isa_ok($article->end_date,   'DateTime');
362
363     isa_ok($article->author, 'Newswriter::Author');
364     is($article->author->first_name, 'Truman', '... got the right author first name');
365     is($article->author->last_name, 'Capote', '... got the right author last name');
366
367     is( exception {
368         $article->author->first_name('Dan');
369         $article->author->last_name('Rather');
370     }, undef, '... changed the value ok' );
371
372     is($article->author->first_name, 'Dan', '... got the changed author first name');
373     is($article->author->last_name, 'Rather', '... got the changed author last name');
374
375     is($article->status, 'pending', '... got the right status');
376 }
377
378 MooseX::POOP::Meta::Instance->_reload_db();
379
380 {
381     my $article;
382     is( exception {
383         $article = Newswriter::Article->new(oid => $article_oid);
384     }, undef, '... (re)-created my article successfully' );
385     isa_ok($article, 'Newswriter::Article');
386     isa_ok($article, 'MooseX::POOP::Object');
387
388     is($article->oid, $article_oid, '... got a oid for the article');
389     isnt($article_ref, "$article", '... got a new article instance');
390
391     is($article->headline,
392        'Home Office Redecorated',
393        '... got the right headline');
394     is($article->summary,
395        'The home office was recently redecorated to match the new company colors',
396        '... got the right summary');
397     is($article->article, '...', '... got the right article');
398
399     isa_ok($article->start_date, 'DateTime');
400     isa_ok($article->end_date,   'DateTime');
401
402     isa_ok($article->author, 'Newswriter::Author');
403     is($article->author->first_name, 'Dan', '... got the changed author first name');
404     is($article->author->last_name, 'Rather', '... got the changed author last name');
405
406     is($article->status, 'pending', '... got the right status');
407
408     my $article2;
409     is( exception {
410         $article2 = Newswriter::Article->new(oid => $article2_oid);
411     }, undef, '... (re)-created my article successfully' );
412     isa_ok($article2, 'Newswriter::Article');
413     isa_ok($article2, 'MooseX::POOP::Object');
414
415     is($article2->oid, $article2_oid, '... got a oid for the article');
416     isnt($article2_ref, "$article2", '... got a new article instance');
417
418     is($article2->headline,
419        'Company wins Lottery',
420        '... got the right headline');
421     is($article2->summary,
422        'An email was received today that informed the company we have won the lottery',
423        '... got the right summary');
424     is($article2->article, 'WoW', '... got the right article');
425
426     ok(!$article2->start_date, '... these two dates are unassigned');
427     ok(!$article2->end_date,   '... these two dates are unassigned');
428
429     isa_ok($article2->author, 'Newswriter::Author');
430     is($article2->author->first_name, 'Katie', '... got the right author first name');
431     is($article2->author->last_name, 'Couric', '... got the right author last name');
432
433     is($article2->status, 'posted', '... got the right status');
434
435 }
436
437 done_testing;