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