File Coverage

blib/lib/MongoDBx/Tiny.pm
Criterion Covered Total %
statement 84 255 32.9
branch 6 74 8.1
condition 0 47 0.0
subroutine 24 45 53.3
pod 26 29 89.6
total 140 450 31.1


line stmt bran cond sub pod time code
1             package MongoDBx::Tiny;
2              
3 2     2   76351 use 5.006;
  2         8  
  2         74  
4 2     2   10 use strict;
  2         5  
  2         55  
5 2     2   10 use warnings;
  2         8  
  2         110  
6              
7             =head1 NAME
8              
9             MongoDBx::Tiny - Simple Mongo ORM for Perl
10              
11             =head1 VERSION
12              
13             Version 0.03
14              
15             =cut
16              
17             our $VERSION = '0.03';
18              
19             =head1 SYNOPSIS
20              
21             # --------------------
22             package My::Data;
23              
24             use MongoDBx::Tiny;
25              
26             CONNECT_INFO host => 'localhost', port => 27017;
27             DATABASE_NAME 'my_data';
28              
29             # --------------------
30             package My::Data::Foo;
31              
32             use MongoDBx::Tiny::Document;
33              
34             COLLECTION_NAME 'foo';
35              
36             ESSENTIAL qw/code/;
37             FIELD 'code', INT, LENGTH(10), DEFAULT('0'), REQUIRED;
38             FIELD 'name', STR, LENGTH(30), DEFAULT('noname');
39              
40             # --------------------
41             package main;
42              
43             my $tiny = My::Data->new;
44             $tiny->insert(foo => { code => 123, name => "foo_123"}) or die $!;
45             my $foo = $tiny->single(foo => { code => 123});
46             $foo->name('foo_321');
47             $foo->update;
48             $foo->remove;
49              
50             =cut
51              
52 2     2   1595 use MongoDB;
  2         4391655  
  2         87  
53 2     2   23 use Carp qw/carp confess/;
  2         5  
  2         174  
54 2     2   1209 use Data::Dumper;
  2         7321  
  2         137  
55 2     2   1280 use MongoDBx::Tiny::Util;
  2         6  
  2         154  
56 2     2   12 use Params::Validate ();
  2         4  
  2         39  
57 2     2   10 use Scalar::Util qw(blessed);
  2         4  
  2         123  
58              
59              
60             sub import {
61 3     3   42 my $caller = (caller(0))[0];
62             {
63 2     2   10 no strict 'refs';
  2         3  
  2         190  
  3         5  
64 3         5 push @{"${caller}::ISA"}, __PACKAGE__;
  3         36  
65             }
66 3         33 strict->import;
67 3         127 warnings->import;
68 3         397 __PACKAGE__->export_to_level(1, @_);
69             }
70              
71             require Exporter;
72 2     2   12 use base qw/Exporter/;
  2         4  
  2         266  
73             our @EXPORT = qw/CONNECT_INFO DATABASE_NAME LOAD_PLUGIN/;
74             our $_CONNECT_INFO;
75             our $_DATABASE_NAME;
76              
77             =head1 EXPORT
78              
79             A list of functions that can be exported.
80              
81             =head2 CONNECT_INFO
82              
83             CONNECT_INFO host => 'localhost', port => 27017;
84              
85             =head2 DATABASE_NAME
86              
87             DATABASE_NAME 'my_data';
88              
89             =head2 LOAD_PLUGIN
90              
91             LOAD_PLUGIN 'One'; # MongoDBx::Tiny::Plugin::One
92             LOAD_PLUGIN 'Two';
93             LOAD_PLUGIN '+Class::Name';
94              
95             =cut
96              
97             {
98 2     2   12 no warnings qw(once);
  2         2  
  2         1422  
99             *CONNECT_INFO = \&install_connect_info;
100             *DATABASE_NAME = \&install_database_name;
101             *LOAD_PLUGIN = \&install_plugin;
102             }
103              
104 1     1 0 7 sub install_connect_info { util_class_attr('CONNECT_INFO', @_) }
105              
106 1     1 0 4 sub install_database_name { util_class_attr('DATABASE_NAME',@_) }
107              
108             sub install_plugin {
109 1     1 0 6 my $class = (caller(0))[0];
110 1         7 $class->load_plugin(shift)
111             }
112              
113              
114             =head1 SUBROUTINES/METHODS
115              
116             =head2 new
117              
118             my $tiny = My::Data->new();
119              
120             # or you can specify connect_info, database_name.
121             my $tiny = My::Data->new({
122             connect_info => [ host => 'localhost', port => 27017 ],
123             database_name => 'my_data',
124             });
125              
126             =cut
127              
128             sub new {
129 1     1 1 27 my $class = shift;
130 1         2 my $opt = shift;
131 1 50       6 if (ref $opt->{connect_info} eq 'ARRAY') {
132 0         0 $class->install_connect_info($opt->{connect_info});
133             }
134 1 50       5 if ($opt->{database_name} ) {
135 0         0 $class->install_database_name($opt->{database_name});
136             }
137 1         4 my $self = bless{},$class;
138 1         3 eval { $self->connect; };
  1         10  
139              
140 1 50       2320 if ($@) {
141 1         591 Carp::carp $@;
142 1         13 return;
143             }
144              
145 0         0 return $self;
146             }
147              
148             =head2 get_connection
149              
150             returns MongoDB::Connection. you can override how to get connection object.
151              
152             sub get_connection {
153             my $class = shift;
154              
155             return MongoDB::Connection->new(@{$class->CONNECT_INFO}) if !$ENV{PLACK_ENV};
156              
157             my $key = 'some_key';
158             if (in_scope_container() and my $con = scope_container($key)) {
159             return $con;
160             } else {
161             my $con = MongoDB::Connection->new(@{$class->CONNECT_INFO});
162             scope_container($key, $con) if in_scope_container();
163             return $con;
164             }
165             }
166              
167              
168             =cut
169              
170             sub get_connection {
171 1     1 1 3 my $class = shift;
172 1         2 return MongoDB::Connection->new(@{$class->connect_info});
  1         7  
173             }
174              
175             =head2 connect_info, database_name
176              
177             alias to installed value
178              
179             my $connect_info = $tiny->connect_info;
180              
181             my $database_name = $tiny->database_name;
182              
183             =cut
184              
185             sub connect_info {
186 1     1 1 3 my $class = shift; # or self
187 1         7 util_class_attr('CONNECT_INFO',$class);
188             }
189              
190             sub database_name {
191 0     0 1 0 my $class = shift; # or self
192 0         0 util_class_attr('DATABASE_NAME',$class);
193             }
194              
195             =head2 connection, database
196              
197             alias to connection and database object.
198              
199             my $connection = $tiny->connection; # MongoDB::Connection object
200              
201             my $database = $tiny->database; # MongoDB::Database object
202              
203             =cut
204              
205              
206 0     0 1 0 sub connection { shift->{connection} }
207              
208 0     0 1 0 sub database { shift->{database} }
209              
210             =head2 cursor_class, validator_class, gridfs_class
211              
212             override if you want.
213              
214             MongoDBx::Tiny::Cursor
215            
216             MongoDBx::Tiny::Validator
217            
218             MongoDBx::Tiny::GridFS
219              
220             =cut
221              
222 0     0 1 0 sub cursor_class { 'MongoDBx::Tiny::Cursor' }
223              
224 0     0 1 0 sub validator_class { 'MongoDBx::Tiny::Validator' }
225              
226 0     0 1 0 sub gridfs_class { 'MongoDBx::Tiny::GridFS' }
227              
228             =head2 collection
229              
230             returns MongoDB::Collection
231              
232             $collection = $tiny->collection('collection_name')
233              
234             =cut
235              
236             sub collection {
237 0     0 1 0 my $self = shift;
238 0 0       0 my $name = shift or confess q|no collection name|;
239 0   0     0 my $opt = shift || {no_cache => 0};
240 0 0       0 if ($opt->{no_cache}) {
241 0         0 return $self->database->$name();
242             } else {
243 0         0 my $cache = $self->{collection};
244 0 0       0 return $cache->{$name} if $cache->{$name};
245 0         0 return ($self->{collection}->{$name} = $self->database->$name());
246             }
247             }
248              
249             =head2 connect / disconnect
250              
251             just (re)connect & disconnect
252              
253             =cut
254              
255             sub connect {
256 1     1 1 3 my $self = shift;
257 1         7 $self->disconnect;
258              
259 1         9 my $connection = $self->get_connection;
260 0         0 my $db_name = $self->database_name;
261 0         0 my $database = $connection->$db_name();
262 0         0 $self->{connection} = $connection;
263 0         0 $self->{database} = $database;
264 0         0 $self->{gridfs} = undef;
265              
266 0         0 return $self->{connection};
267             }
268              
269             sub disconnect {
270 1     1 1 2 my $self = shift;
271 1         3 for (qw(connection database gridfs collection)) {
272 4         13 delete $self->{$_};
273             }
274 1         3 return 1;
275             }
276              
277              
278             =head2 insert,create
279              
280             $document_object = $tiny->insert('collection_name' => $document);
281              
282             =cut
283              
284             {
285 2     2   18 no warnings qw(once);
  2         3  
  2         3220  
286             *create = \&insert;
287             }
288              
289             sub insert {
290 0     0 1 0 my $self = shift;
291 0 0       0 my $c_name = shift or confess q/no collection name/;
292 0 0       0 my $document = shift or confess q/no document/;
293              
294 0         0 my $opt = shift;
295 0         0 $opt->{state} = 'insert';
296              
297 0         0 my $validator = $self->validate($c_name,$document,$opt);
298              
299 0 0       0 if ($validator->has_error) {
300 0         0 confess "invalid document: \n" . (Dumper $validator->errors);
301             }
302              
303 0         0 my $d_class = $self->document_class($c_name);
304 0 0       0 unless ($opt->{no_trigger}) {
305 0         0 $d_class->call_trigger('before_insert',$self,$document,$opt) ;
306             }
307              
308 0         0 my $collection = $self->collection($c_name);
309 0         0 my $id = $collection->insert($document);
310 0         0 my $object = $self->single($c_name,$id);
311 0 0       0 unless ($opt->{no_trigger}) {
312 0         0 $d_class->call_trigger('after_insert',$object,$opt);
313             }
314 0         0 return $object;
315             }
316              
317             =head2 single
318              
319             returns MongoDBx::Tiny::Document object.
320              
321             $document_object = $tiny->single('collection_name' => $MongoDB_oid_object);
322            
323             $tiny->single('collection_name' => $oid_text);
324            
325             $query = { field => $val };
326             $tiny->single('collection_name' => $query);
327              
328             =cut
329              
330             sub single {
331             #xxx
332             # 4ff19d717bcc56834b000000
333             # tiny->single("sfa"); # return first value
334 0     0 1 0 my $self = shift;
335 0         0 my $c_name = shift;
336              
337 0         0 my $collection = $self->collection($c_name);
338 0         0 my $document;
339 0         0 my $d_class = $self->document_class($c_name);
340              
341 0         0 my $essential = $d_class->essential; #
342              
343 0         0 my ($proto) = shift;
344 0 0       0 unless (ref $proto eq 'HASH') {
345 0         0 $proto = { _id => "$proto" };
346             }
347 0         0 $proto = util_to_oid($proto,'_id',$d_class->field->list('OID'));
348              
349 0         0 my $reserved= $d_class->query_attributes('single');
350 0 0 0     0 if ($reserved && ( my @attr = keys %$reserved)) {
351 0   0     0 $proto->{$_} ||= $reserved->{$_} for @attr;
352             }
353 0         0 $document = $collection->find_one($proto,$essential);
354              
355             # # needed?
356             # elsif (scalar @_ >= 2) {
357             # my %query = @_;
358             # $document = $collection->find_one(\%query,$essential);
359             # }
360 0 0       0 return unless $document;
361 0         0 $self->document_to_object($c_name,$document);
362             }
363              
364             =head2 search
365              
366             returns MongoDBx::Tiny::Cursor object.
367              
368             $query = { field => $val };
369             $cursor = $tiny->search('collection_name' => $query);
370             while (my $object = $cursor->next) {
371             # warn $object->id;
372             }
373            
374             # list context
375             @object = $tiny->search('collection_name' => $query);
376              
377             =cut
378              
379             sub search {
380 0     0 1 0 my $self = shift;
381             # xxx
382 0         0 my $c_name = shift;
383 0         0 my $collection = $self->collection($c_name);
384 0         0 my $d_class = $self->document_class($c_name);
385 0         0 my $essential = $d_class->essential; #
386 0         0 my $query = shift;
387 0         0 my @operation = @_;
388              
389 0         0 $query = util_to_oid($query,'_id',$d_class->field->list('OID'));
390 0         0 my $reserved= $d_class->query_attributes('search');
391 0 0 0     0 if ($reserved && ( my @attr = keys %$reserved)) {
392 0   0     0 $query->{$_} ||= $reserved->{$_} for @attr;
393             }
394              
395 0         0 my $cursor = $collection->find($query)->fields($essential);
396 0 0       0 if (wantarray) {
397 0         0 return map { $self->document_to_object($c_name,$_) } $cursor->all;
  0         0  
398             } else {
399 0         0 eval "require " . $self->cursor_class;
400 0         0 return $self->cursor_class->new(
401             tiny => $self, c_name => $c_name,cursor => $cursor
402             );
403             }
404             }
405              
406             =head2 update
407              
408             $tiny->update('collection_name',$query,$document);
409              
410             =cut
411              
412             sub update {
413 0     0 1 0 my $self = shift;
414             # xxx
415 0   0     0 my $c_name = shift || confess q/no collection name/;;
416 0   0     0 my $query = shift || confess q/no query/;
417 0         0 my $document = shift;
418 0         0 my $opt = shift;
419 0 0       0 return unless $document;
420 0         0 $opt->{state} = 'update';
421              
422 0         0 my $validator = $self->validate(
423             $c_name,$document,$opt
424             );
425            
426 0 0       0 if ($validator->has_error) {
427 0         0 confess "invalid document: \n" . (Dumper $validator->errors);
428             }
429 0         0 my $d_class = $self->document_class($c_name);
430              
431 0         0 my @object; # xxx
432 0 0 0     0 if (!$opt->{no_trigger} and $d_class->trigger('before_update')) {
433 0         0 my $cursor = $self->search($c_name,$query);
434 0         0 while (my $object = $cursor->next) {
435 0         0 push @object,$object;
436 0         0 $object->call_trigger('before_update',$self,$opt);
437             }
438             }
439              
440 0         0 my $collection = $self->collection($c_name);
441 0         0 $collection->update($query,{ '$set' => $document },{ multiple => 1 });
442              
443 0 0 0     0 if (!$opt->{no_trigger} and $d_class->trigger('after_update')) {
444 0         0 for my $object (@object) {
445 0         0 $object->call_trigger('after_update',$self,$opt);
446             }
447             }
448            
449             # tiny->remove('foo',{ code => 111 });
450             }
451              
452             =head2 remove
453              
454              
455             $tiny->remove('collection_name',$query);
456              
457             =cut
458              
459             sub remove {
460 0     0 1 0 my $self = shift;
461             # xxx
462 0   0     0 my $c_name = shift || confess q/no collection name/;;
463 0   0     0 my $query = shift || confess q/no query/;
464 0   0     0 my $opt = shift || {};
465              
466 0         0 my $d_class = $self->document_class($c_name);
467            
468 0         0 my @object; # xxx
469 0 0 0     0 if (!$opt->{no_trigger} and $d_class->trigger('before_remove')) {
470 0         0 my $cursor = $self->search($c_name,$query);
471 0         0 while (my $object = $cursor->next) {
472 0         0 push @object,$object;
473 0         0 $object->call_trigger('before_remove',$object,$opt);
474             }
475             }
476              
477 0         0 my $collection = $self->collection($c_name);
478 0         0 $collection->remove($query);
479              
480 0 0 0     0 if (!$opt->{no_trigger} and $d_class->trigger('after_remove')) {
481 0         0 for my $object (@object) {
482 0         0 $object->call_trigger('after_remove',$object,$opt);
483             }
484             }
485             }
486              
487             =head2 count
488              
489             $count_num = $tiny->count('collection_name',$query);
490              
491             =cut
492              
493             sub count {
494 0     0 1 0 my $self = shift;
495 0         0 my $c_name = shift;
496 0         0 my $collection = $self->collection($c_name);
497 0         0 my $d_class = $self->document_class($c_name);
498 0         0 return $collection->count(shift);
499             }
500              
501             =head2 document_to_object
502              
503             $document_object = $tiny->document_to_object('collection_name',$document);
504              
505             =cut
506              
507             sub document_to_object {
508 0     0 1 0 my $self = shift;
509 0 0       0 my $c_name = shift or confess q/no collecion name/;
510 0 0       0 my $document = shift or confess q/no document/;
511 0 0       0 confess q/no id/ unless $document->{_id};
512              
513 0         0 my $d_class = $self->document_class($c_name);
514              
515 0         0 return $d_class->new($document,$self);
516             }
517              
518             =head2 validate
519              
520             $validator = $tiny->validate('collecion_name',$document,$opt);
521              
522             my $validator = $tiny->validate(
523             'foo',
524             { code => 123, name => "foo_123"},
525             { state => 'insert' }
526             );
527             my $foo1 = $tiny->insert(
528             'foo',
529             $validator->document,
530             { state => 'insert', no_validate => 1 }
531             );
532             # erros: [{ field => 'field1', code => 'errorcode', message => 'message1' },,,]
533             my @erros = $validator->erros;
534            
535             my @fields = $validator->errors('field');
536             my @error_code = $validator->errors('code');
537             my @error_message = $validator->errors('message');
538              
539             =cut
540              
541             sub validate {
542 0     0 1 0 my $self = shift;
543 0 0       0 my $c_name = shift or confess q/no collecion_name/;
544 0 0       0 my $document = shift or confess q/no document/;
545 0         0 my $opt = shift;
546              
547 0         0 Params::Validate::validate_with(
548             params => $opt,
549             spec => {
550             state => 1,# insert,update
551             no_trigger => 0,
552             no_validate => 0,
553             },
554             allow_extra => 1,
555             );
556            
557 0         0 $opt->{tiny} = $self;
558 0         0 eval "require " . $self->validator_class;
559 0         0 my $validator = $self->validator_class->new(
560             $c_name,
561             $document,
562             $self,
563             );
564            
565 0         0 return $validator->check($opt);
566             }
567              
568             =head2 gridfs
569              
570             returns MongoDBx::Tiny::GridFS
571              
572             $gridfs = $tiny->gridfs();
573            
574             $gridfs = $tiny->gridfs({database => $mongo_databse_object });
575            
576             $gridfs = $tiny->gridfs({fields => 'other_filename' });
577              
578             my $gridfs = $tiny->gridfs;
579             $gridfs->put('/tmp/foo.txt', {"filename" => 'foo.txt' });
580             my $foo_txt = $gridfs->get({ filename => 'foo.txt' })->slurp;
581            
582             $gridfs->put('/tmp/bar.txt','bar.txt');
583             my $bar_txt = $gridfs->get('bar.txt')->slurp;
584              
585             =cut
586              
587             sub gridfs {
588 0     0 1 0 my $self = shift;
589 0   0     0 my $opt = shift || {};
590 0         0 my %opt = Params::Validate::validate_with(
591             params => $opt,
592             spec => {
593             database => {optional => 1},
594             fields => {optional => 1, default => 'filename'},
595             }
596             );
597              
598 0   0     0 my $database = $opt{database} || $self->database;
599              
600 0         0 eval "require " . $self->gridfs_class;
601 0 0       0 return $self->{gridfs} if $self->{gridfs};
602 0         0 $self->{gridfs} = $self->gridfs_class->new(
603             $database->get_gridfs,$opt{fields}
604             );
605             }
606              
607              
608             =head2 document_class
609              
610             $document_class_name = $tiny->document_class('collecion_name');
611              
612             =cut
613              
614             sub document_class {
615 0     0 1 0 my $self = shift;
616 0 0       0 my $c_name = shift or confess q/no collection name/;
617 0         0 return util_document_class($c_name,ref $self);
618             }
619              
620             =head2 load_plugin
621              
622             # --------------------
623            
624             package MyDB;
625             use MongoDBx::Tiny;
626            
627             LOAD_PLUGIN('PluginName');
628             LOAD_PLUGIN('+Class::Name');
629            
630             # --------------------
631             package MongoDBx::Tiny::Plugin::PluginName;
632             use strict;
633             use warnings;
634             use utf8;
635            
636             our @EXPORT = qw/function_for_plugin/;
637            
638             sub function_for_plugin {}
639            
640             # --------------------
641            
642             $tiny->function_for_plugin;
643              
644             =cut
645              
646             sub load_plugin {
647 1     1 1 2 my ($proto, $pkg) = @_;
648            
649 1 50       3 my $class = ref $proto ? ref $proto : $proto;
650 1 50       3 $pkg = $pkg =~ s/^\+// ? $pkg : "MongoDBx::Tiny::Plugin::$pkg";
651 1         54 eval "require $pkg ";
652              
653 2     2   15 no strict 'refs';
  2         5  
  2         1061  
654 1         2 for my $method ( @{"${pkg}::EXPORT"} ) {
  1         5  
655 2 50       20 next if $class->can($method);
656 2         15 *{$class . '::' . $method} = $pkg->can($method);
  2         9  
657             }
658             }
659              
660             =head2 process
661              
662             [EXPERIMENTAL]
663              
664             $tiny->process('collecion_name','some',@args);
665              
666             $tiny->process('foo','some',$validator,$arg); # just call Data::Foo::process_some
667            
668             #
669             sub process_foo {
670             my ($class,$tiny,$validator,$arg) = @_;
671             }
672              
673             =cut
674              
675             sub process {
676             # xxx
677 0     0 1   my $self = shift;
678 0 0         my $c_name = shift or confess q/no collecion name/;
679 0 0         my $method = shift or confess q/no process method name/;
680 0           my $d_class = $self->document_class($c_name);
681 0           my $process_method = sprintf "process_%s", $method;
682 0           $d_class->$process_method($self,@_);
683             }
684              
685             =head2 set_indexes
686              
687             [EXPERIMENTAL]
688              
689             $tiny->set_indexes('collection_name');
690              
691             =cut
692              
693             sub set_indexes {
694 0     0 1   my $self = shift;
695 0           my $c_name = shift;
696 0           my $collection = $self->collection($c_name);
697 0           my $d_class = $self->document_class($c_name);
698 0   0       my $indexes = $d_class->indexes || [];
699              
700              
701 0           my $ns = sprintf "%s.%s", $self->database_name,$c_name;
702              
703 0           for my $index (@$indexes) {
704              
705 0           my ($field,$index_opt,$opt) = @$index;
706 0           require Tie::IxHash;
707 0 0         if (ref $field eq 'ARRAY') {
708 0           $field = Tie::IxHash->new(@$field);
709             }
710 0 0         my $index_target = ref $field ? $field : { $field => 1 };
711 0           my ($index_exists) = $self->collection('system.indexes')->find({ns => $ns,key => $index_target})->all;
712            
713 0 0         if (!$index_exists) {
714 0           $collection->ensure_index($index_target,$index_opt);
715             }
716             }
717             }
718              
719             =head2 unset_indexes
720              
721             [EXPERIMENTAL]
722              
723             # drop indexes without "_id";
724             $tiny->unset_indexes('collection_name');
725              
726             =cut
727              
728             sub unset_indexes {
729 0     0 1   my $self = shift;
730 0           my $c_name = shift;
731 0           my $collection = $self->collection($c_name);
732              
733             #> db.system.indexes.find({ns:"my_data.foo",key:{$ne : {"_id":1}}});
734 0           my $ns = sprintf "%s.%s", $self->database_name,$c_name;
735 0           my @index = $self->collection('system.indexes')->find({ns => $ns,key => { '$ne' => {"_id" => 1}}})->all;
736 0           for (@index) {
737 0           $collection->drop_index($_->{key});
738             }
739             }
740              
741 0     0     sub DESTROY {
742             # xxx
743             }
744              
745              
746             1;
747              
748             __END__
749              
750             =head1 SEE ALSO
751              
752             =over
753              
754             =item MongoDBx::Tiny::Document
755              
756             =item MongoDBx::Tiny::Attributes
757              
758             =item MongoDBx::Tiny::Relation
759              
760             =item MongoDBx::Tiny::Util
761              
762             =item MongoDBx::Tiny::Cursor
763              
764             =item MongoDBx::Tiny::Validator
765              
766             =item MongoDBx::Tiny::GridFS
767              
768             =item MongoDBx::Tiny::GridFS::File
769              
770             =item MongoDBx::Tiny::Plugin::SingleByCache
771              
772             =back
773              
774             =head1 SUPPORT
775              
776             L<https://github.com/naoto43/mongodbx-tiny/>
777              
778             =head1 AUTHOR
779              
780             Naoto ISHIKAWA, C<< <toona at seesaa.co.jp> >>
781              
782             =head1 LICENSE AND COPYRIGHT
783              
784             Copyright 2013 Naoto ISHIKAWA.
785              
786             This program is free software; you can redistribute it and/or modify it
787             under the terms of either: the GNU General Public License as published
788             by the Free Software Foundation; or the Artistic License.
789              
790             See http://dev.perl.org/licenses/ for more information.
791              
792              
793             =cut