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