8a258f1fb98cf55e2990bf5cd64c886c8a17f3bb
[kivitendo-erp.git] / modules / fallback / DateTime / SpanSet.pm
1 # Copyright (c) 2003 Flavio Soibelmann Glock. All rights reserved.
2 # This program is free software; you can redistribute it and/or
3 # modify it under the same terms as Perl itself.
4
5 package DateTime::SpanSet;
6
7 use strict;
8
9 use DateTime::Set;
10 use DateTime::Infinite;
11
12 use Carp;
13 use Params::Validate qw( validate SCALAR BOOLEAN OBJECT CODEREF ARRAYREF );
14 use vars qw( $VERSION );
15
16 use constant INFINITY     =>       100 ** 100 ** 100 ;
17 use constant NEG_INFINITY => -1 * (100 ** 100 ** 100);
18 $VERSION = $DateTime::Set::VERSION;
19
20 sub iterate {
21     my ( $self, $callback ) = @_;
22     my $class = ref( $self );
23     my $return = $class->empty_set;
24     $return->{set} = $self->{set}->iterate(
25         sub {
26             my $span = bless { set => $_[0] }, 'DateTime::Span';
27             $callback->( $span->clone );
28             $span = $span->{set} 
29                 if UNIVERSAL::can( $span, 'union' );
30             return $span;
31         }
32     );
33     $return;
34 }
35
36 sub map {
37     my ( $self, $callback ) = @_;
38     my $class = ref( $self );
39     die "The callback parameter to map() must be a subroutine reference"
40         unless ref( $callback ) eq 'CODE';
41     my $return = $class->empty_set;
42     $return->{set} = $self->{set}->iterate( 
43         sub {
44             local $_ = bless { set => $_[0]->clone }, 'DateTime::Span';
45             my @list = $callback->();
46             my $set = $class->empty_set;
47             $set = $set->union( $_ ) for @list;
48             return $set->{set};
49         }
50     );
51     $return;
52 }
53
54 sub grep {
55     my ( $self, $callback ) = @_;
56     my $class = ref( $self );
57     die "The callback parameter to grep() must be a subroutine reference"
58         unless ref( $callback ) eq 'CODE';
59     my $return = $class->empty_set;
60     $return->{set} = $self->{set}->iterate( 
61         sub {
62             local $_ = bless { set => $_[0]->clone }, 'DateTime::Span';
63             my $result = $callback->();
64             return $_ if $result;
65             return;
66         }
67     );
68     $return;
69 }
70
71 sub set_time_zone {
72     my ( $self, $tz ) = @_;
73
74     # TODO - use iterate() instead 
75
76     my $result = $self->{set}->iterate( 
77         sub {
78             my %tmp = %{ $_[0]->{list}[0] };
79             $tmp{a} = $tmp{a}->clone->set_time_zone( $tz ) if ref $tmp{a};
80             $tmp{b} = $tmp{b}->clone->set_time_zone( $tz ) if ref $tmp{b};
81             \%tmp;
82         },
83         backtrack_callback => sub {
84             my ( $min, $max ) = ( $_[0]->min, $_[0]->max );
85             if ( ref($min) )
86             {
87                 $min = $min->clone;
88                 $min->set_time_zone( 'floating' );
89             }
90             if ( ref($max) )
91             {
92                 $max = $max->clone;
93                 $max->set_time_zone( 'floating' ); 
94             }
95             return Set::Infinite::_recurrence->new( $min, $max );
96         },
97     );
98
99     ### this code enables 'subroutine method' behaviour
100     $self->{set} = $result;
101     return $self;
102 }
103
104 sub from_spans {
105     my $class = shift;
106     my %args = validate( @_,
107                          { spans =>
108                            { type => ARRAYREF,
109                              optional => 1,
110                            },
111                          }
112                        );
113     my $self = {};
114     my $set = Set::Infinite::_recurrence->new();
115     $set = $set->union( $_->{set} ) for @{ $args{spans} };
116     $self->{set} = $set;
117     bless $self, $class;
118     return $self;
119 }
120
121 sub from_set_and_duration {
122     # set => $dt_set, days => 1
123     my $class = shift;
124     my %args = @_;
125     my $set = delete $args{set} || 
126         carp "from_set_and_duration needs a 'set' parameter";
127
128     $set = $set->as_set
129         if UNIVERSAL::can( $set, 'as_set' );
130     unless ( UNIVERSAL::can( $set, 'union' ) ) {
131         carp "'set' must be a set" };
132
133     my $duration = delete $args{duration} ||
134                    new DateTime::Duration( %args );
135     my $end_set = $set->clone->add_duration( $duration );
136     return $class->from_sets( start_set => $set, 
137                               end_set =>   $end_set );
138 }
139
140 sub from_sets {
141     my $class = shift;
142     my %args = validate( @_,
143                          { start_set =>
144                            { # can => 'union',
145                              optional => 0,
146                            },
147                            end_set =>
148                            { # can => 'union',
149                              optional => 0,
150                            },
151                          }
152                        );
153     my $start_set = delete $args{start_set};
154     my $end_set   = delete $args{end_set};
155
156     $start_set = $start_set->as_set
157         if UNIVERSAL::can( $start_set, 'as_set' );
158     $end_set = $end_set->as_set
159         if UNIVERSAL::can( $end_set, 'as_set' );
160
161     unless ( UNIVERSAL::can( $start_set, 'union' ) ) {
162         carp "'start_set' must be a set" };
163     unless ( UNIVERSAL::can( $end_set, 'union' ) ) {
164         carp "'end_set' must be a set" };
165
166     my $self;
167     $self->{set} = $start_set->{set}->until( 
168                    $end_set->{set} );
169     bless $self, $class;
170     return $self;
171 }
172
173 sub start_set {
174     if ( exists $_[0]->{set}{method} &&
175          $_[0]->{set}{method} eq 'until' )
176     {
177         return bless { set => $_[0]->{set}{parent}[0] }, 'DateTime::Set';
178     }
179     my $return = DateTime::Set->empty_set;
180     $return->{set} = $_[0]->{set}->start_set;
181     $return;
182 }
183
184 sub end_set {
185     if ( exists $_[0]->{set}{method} &&
186          $_[0]->{set}{method} eq 'until' )
187     {
188         return bless { set => $_[0]->{set}{parent}[1] }, 'DateTime::Set';
189     }
190     my $return = DateTime::Set->empty_set;
191     $return->{set} = $_[0]->{set}->end_set;
192     $return;
193 }
194
195 sub empty_set {
196     my $class = shift;
197
198     return bless { set => Set::Infinite::_recurrence->new }, $class;
199 }
200
201 sub clone { 
202     bless { 
203         set => $_[0]->{set}->copy,
204         }, ref $_[0];
205 }
206
207
208 sub iterator {
209     my $self = shift;
210
211     my %args = @_;
212     my $span;
213     $span = delete $args{span};
214     $span = DateTime::Span->new( %args ) if %args;
215
216     return $self->intersection( $span ) if $span;
217     return $self->clone;
218 }
219
220
221 # next() gets the next element from an iterator()
222 sub next {
223     my ($self) = shift;
224
225     # TODO: this is fixing an error from elsewhere
226     # - find out what's going on! (with "sunset.pl")
227     return undef unless ref $self->{set};
228
229     if ( @_ )
230     {
231         my $max;
232         $max = $_[0]->max if UNIVERSAL::can( $_[0], 'union' );
233         $max = $_[0] if ! defined $max;
234
235         return undef if ! ref( $max ) && $max == INFINITY;
236
237         my $span = DateTime::Span->from_datetimes( start => $max );
238         my $iterator = $self->intersection( $span );
239         my $return = $iterator->next;
240
241         return $return if ! defined $return;
242         return $return if ! $return->intersects( $max );
243
244         return $iterator->next;
245     }
246
247     my ($head, $tail) = $self->{set}->first;
248     $self->{set} = $tail;
249     return $head unless ref $head;
250     my $return = {
251         set => $head,
252     };
253     bless $return, 'DateTime::Span';
254     return $return;
255 }
256
257 # previous() gets the last element from an iterator()
258 sub previous {
259     my ($self) = shift;
260
261     return undef unless ref $self->{set};
262
263     if ( @_ )
264     {
265         my $min;
266         $min = $_[0]->min if UNIVERSAL::can( $_[0], 'union' );
267         $min = $_[0] if ! defined $min;
268
269         return undef if ! ref( $min ) && $min == INFINITY;
270
271         my $span = DateTime::Span->from_datetimes( end => $min );
272         my $iterator = $self->intersection( $span );
273         my $return = $iterator->previous;
274
275         return $return if ! defined $return;
276         return $return if ! $return->intersects( $min );
277
278         return $iterator->previous;
279     }
280
281     my ($head, $tail) = $self->{set}->last;
282     $self->{set} = $tail;
283     return $head unless ref $head;
284     my $return = {
285         set => $head,
286     };
287     bless $return, 'DateTime::Span';
288     return $return;
289 }
290
291 # "current" means less-or-equal to a DateTime
292 sub current {
293     my $self = shift;
294
295     my $previous;
296     my $next;
297     {
298         my $min;
299         $min = $_[0]->min if UNIVERSAL::can( $_[0], 'union' );
300         $min = $_[0] if ! defined $min;
301         return undef if ! ref( $min ) && $min == INFINITY;
302         my $span = DateTime::Span->from_datetimes( end => $min );
303         my $iterator = $self->intersection( $span );
304         $previous = $iterator->previous;
305         $span = DateTime::Span->from_datetimes( start => $min );
306         $iterator = $self->intersection( $span );
307         $next = $iterator->next;
308     }
309     return $previous unless defined $next;
310
311     my $dt1 = defined $previous
312         ? $next->union( $previous )
313         : $next;
314
315     my $return = $dt1->intersected_spans( $_[0] );
316
317     $return = $previous
318         if !defined $return->max;
319
320     bless $return, 'DateTime::SpanSet'
321         if defined $return;
322     return $return;
323 }
324
325 sub closest {
326     my $self = shift;
327     my $dt = shift;
328
329     my $dt1 = $self->current( $dt );
330     my $dt2 = $self->next( $dt );
331     bless $dt2, 'DateTime::SpanSet' 
332         if defined $dt2;
333
334     return $dt2 unless defined $dt1;
335     return $dt1 unless defined $dt2;
336
337     $dt = DateTime::Set->from_datetimes( dates => [ $dt ] )
338         unless UNIVERSAL::can( $dt, 'union' );
339
340     return $dt1 if $dt1->contains( $dt );
341
342     my $delta = $dt->min - $dt1->max;
343     return $dt1 if ( $dt2->min - $delta ) >= $dt->max;
344
345     return $dt2;
346 }
347
348 sub as_list {
349     my $self = shift;
350     return undef unless ref( $self->{set} );
351
352     my %args = @_;
353     my $span;
354     $span = delete $args{span};
355     $span = DateTime::Span->new( %args ) if %args;
356
357     my $set = $self->clone;
358     $set = $set->intersection( $span ) if $span;
359
360     # Note: removing this line means we may end up in an infinite loop!
361     return undef if $set->{set}->is_too_complex;  # undef = no begin/end
362
363     # return if $set->{set}->is_null;  # nothing = empty
364     my @result;
365     # we should extract _copies_ of the set elements,
366     # such that the user can't modify the set indirectly
367
368     my $iter = $set->iterator;
369     while ( my $dt = $iter->next )
370     {
371         push @result, $dt
372             if ref( $dt );   # we don't want to return INFINITY value
373     };
374
375     return @result;
376 }
377
378 # Set::Infinite methods
379
380 sub intersection {
381     my ($set1, $set2) = ( shift, shift );
382     my $class = ref($set1);
383     my $tmp = $class->empty_set();
384     $set2 = $set2->as_spanset
385         if $set2->can( 'as_spanset' );
386     $set2 = $set2->as_set
387         if $set2->can( 'as_set' );
388     $set2 = DateTime::Set->from_datetimes( dates => [ $set2, @_ ] ) 
389         unless $set2->can( 'union' );
390     $tmp->{set} = $set1->{set}->intersection( $set2->{set} );
391     return $tmp;
392 }
393
394 sub intersected_spans {
395     my ($set1, $set2) = ( shift, shift );
396     my $class = ref($set1);
397     my $tmp = $class->empty_set();
398     $set2 = $set2->as_spanset
399         if $set2->can( 'as_spanset' );
400     $set2 = $set2->as_set
401         if $set2->can( 'as_set' );
402     $set2 = DateTime::Set->from_datetimes( dates => [ $set2, @_ ] )
403         unless $set2->can( 'union' );
404     $tmp->{set} = $set1->{set}->intersected_spans( $set2->{set} );
405     return $tmp;
406 }
407
408 sub intersects {
409     my ($set1, $set2) = ( shift, shift );
410     
411     unless ( $set2->can( 'union' ) )
412     {
413         for ( $set2, @_ )
414         {
415             return 1 if $set1->contains( $_ );
416         }
417         return 0;
418     }
419     
420     my $class = ref($set1);
421     $set2 = $set2->as_spanset
422         if $set2->can( 'as_spanset' );
423     $set2 = $set2->as_set
424         if $set2->can( 'as_set' );
425     $set2 = DateTime::Set->from_datetimes( dates => [ $set2, @_ ] ) 
426         unless $set2->can( 'union' );
427     return $set1->{set}->intersects( $set2->{set} );
428 }
429
430 sub contains {
431     my ($set1, $set2) = ( shift, shift );
432     
433     unless ( $set2->can( 'union' ) )
434     {
435         if ( exists $set1->{set}{method} &&
436              $set1->{set}{method} eq 'until' )
437         {
438             my $start_set = $set1->start_set;
439             my $end_set =   $set1->end_set;
440
441             for ( $set2, @_ )
442             {
443                 my $start = $start_set->next( $set2 );
444                 my $end =   $end_set->next( $set2 );
445
446                 goto ABORT unless defined $start && defined $end;
447             
448                 return 0 if $start < $end;
449             }
450             return 1;
451
452             ABORT: ;
453             # don't know 
454         }
455     }
456     
457     my $class = ref($set1);
458     $set2 = $set2->as_spanset
459         if $set2->can( 'as_spanset' );
460     $set2 = $set2->as_set
461         if $set2->can( 'as_set' );
462     $set2 = DateTime::Set->from_datetimes( dates => [ $set2, @_ ] ) 
463         unless $set2->can( 'union' );
464     return $set1->{set}->contains( $set2->{set} );
465 }
466
467 sub union {
468     my ($set1, $set2) = ( shift, shift );
469     my $class = ref($set1);
470     my $tmp = $class->empty_set();
471     $set2 = $set2->as_spanset
472         if $set2->can( 'as_spanset' );
473     $set2 = $set2->as_set
474         if $set2->can( 'as_set' );
475     $set2 = DateTime::Set->from_datetimes( dates => [ $set2, @_ ] ) 
476         unless $set2->can( 'union' );
477     $tmp->{set} = $set1->{set}->union( $set2->{set} );
478     return $tmp;
479 }
480
481 sub complement {
482     my ($set1, $set2) = ( shift, shift );
483     my $class = ref($set1);
484     my $tmp = $class->empty_set();
485     if (defined $set2) {
486         $set2 = $set2->as_spanset
487             if $set2->can( 'as_spanset' );
488         $set2 = $set2->as_set
489             if $set2->can( 'as_set' );
490         $set2 = DateTime::Set->from_datetimes( dates => [ $set2, @_ ] ) 
491             unless $set2->can( 'union' );
492         $tmp->{set} = $set1->{set}->complement( $set2->{set} );
493     }
494     else {
495         $tmp->{set} = $set1->{set}->complement;
496     }
497     return $tmp;
498 }
499
500 sub min {
501     return DateTime::Set::_fix_datetime( $_[0]->{set}->min );
502 }
503
504 sub max { 
505     return DateTime::Set::_fix_datetime( $_[0]->{set}->max );
506 }
507
508 # returns a DateTime::Span
509 sub span { 
510     my $set = $_[0]->{set}->span;
511     my $self = bless { set => $set }, 'DateTime::Span';
512     return $self;
513 }
514
515 # returns a DateTime::Duration
516 sub duration { 
517     my $dur; 
518
519     return DateTime::Duration->new( seconds => 0 ) 
520         if $_[0]->{set}->is_empty;
521
522     local $@;
523     eval { 
524         local $SIG{__DIE__};   # don't want to trap this (rt ticket 5434)
525         $dur = $_[0]->{set}->size 
526     };
527
528     return $dur if defined $dur && ref( $dur );
529     return DateTime::Infinite::Future->new -
530            DateTime::Infinite::Past->new;
531     # return INFINITY;
532 }
533 *size = \&duration;
534
535 1;
536
537 __END__
538
539 =head1 NAME
540
541 DateTime::SpanSet - set of DateTime spans
542
543 =head1 SYNOPSIS
544
545     $spanset = DateTime::SpanSet->from_spans( spans => [ $dt_span, $dt_span ] );
546
547     $set = $spanset->union( $set2 );         # like "OR", "insert", "both"
548     $set = $spanset->complement( $set2 );    # like "delete", "remove"
549     $set = $spanset->intersection( $set2 );  # like "AND", "while"
550     $set = $spanset->complement;             # like "NOT", "negate", "invert"
551
552     if ( $spanset->intersects( $set2 ) ) { ...  # like "touches", "interferes"
553     if ( $spanset->contains( $set2 ) ) { ...    # like "is-fully-inside"
554
555     # data extraction 
556     $date = $spanset->min;           # first date of the set
557     $date = $spanset->max;           # last date of the set
558
559     $iter = $spanset->iterator;
560     while ( $dt = $iter->next ) {
561         # $dt is a DateTime::Span
562         print $dt->start->ymd;   # first date of span
563         print $dt->end->ymd;     # last date of span
564     };
565
566 =head1 DESCRIPTION
567
568 C<DateTime::SpanSet> is a class that represents sets of datetime
569 spans.  An example would be a recurring meeting that occurs from
570 13:00-15:00 every Friday.
571
572 This is different from a C<DateTime::Set>, which is made of individual
573 datetime points as opposed to ranges.
574
575 =head1 METHODS
576
577 =over 4
578
579 =item * from_spans
580
581 Creates a new span set from one or more C<DateTime::Span> objects.
582
583    $spanset = DateTime::SpanSet->from_spans( spans => [ $dt_span ] );
584
585 =item * from_set_and_duration
586
587 Creates a new span set from one or more C<DateTime::Set> objects and a
588 duration.
589
590 The duration can be a C<DateTime::Duration> object, or the parameters
591 to create a new C<DateTime::Duration> object, such as "days",
592 "months", etc.
593
594    $spanset =
595        DateTime::SpanSet->from_set_and_duration
596            ( set => $dt_set, days => 1 );
597
598 =item * from_sets
599
600 Creates a new span set from two C<DateTime::Set> objects.
601
602 One set defines the I<starting dates>, and the other defines the I<end
603 dates>.
604
605    $spanset =
606        DateTime::SpanSet->from_sets
607            ( start_set => $dt_set1, end_set => $dt_set2 );
608
609 The spans have the starting date C<closed>, and the end date C<open>,
610 like in C<[$dt1, $dt2)>.
611
612 If an end date comes without a starting date before it, then it
613 defines a span like C<(-inf, $dt)>.
614
615 If a starting date comes without an end date after it, then it defines
616 a span like C<[$dt, inf)>.
617
618 =item * empty_set
619
620 Creates a new empty set.
621
622 =item * clone
623
624 This object method returns a replica of the given object.
625
626 =item * set_time_zone( $tz )
627
628 This method accepts either a time zone object or a string that can be
629 passed as the "name" parameter to C<< DateTime::TimeZone->new() >>.
630 If the new time zone's offset is different from the old time zone,
631 then the I<local> time is adjusted accordingly.
632
633 If the old time zone was a floating time zone, then no adjustments to
634 the local time are made, except to account for leap seconds.  If the
635 new time zone is floating, then the I<UTC> time is adjusted in order
636 to leave the local time untouched.
637
638 =item * min
639
640 =item * max
641
642 First or last dates in the set.  These methods may return C<undef> if
643 the set is empty.  It is also possible that these methods may return a
644 scalar containing infinity or negative infinity.
645
646 =item * duration
647
648 The total size of the set, as a C<DateTime::Duration> object.
649
650 The duration may be infinite.
651
652 Also available as C<size()>.
653
654 =item * span
655
656 The total span of the set, as a C<DateTime::Span> object.
657
658 =item * next 
659
660   my $span = $set->next( $dt );
661
662 This method is used to find the next span in the set,
663 after a given datetime or span.
664
665 The return value is a C<DateTime::Span>, or C<undef> if there is no matching
666 span in the set.
667
668 =item * previous 
669
670   my $span = $set->previous( $dt );
671
672 This method is used to find the previous span in the set,
673 before a given datetime or span.
674
675 The return value is a C<DateTime::Span>, or C<undef> if there is no matching
676 span in the set.
677
678
679 =item * current 
680
681   my $span = $set->current( $dt );
682
683 This method is used to find the "current" span in the set,
684 that intersects a given datetime or span. If no current span
685 is found, then the "previous" span is returned.
686
687 The return value is a C<DateTime::SpanSet>, or C<undef> if there is no
688 matching span in the set.
689
690 If a span parameter is given, it may happen that "current" returns
691 more than one span.
692
693 See also: C<intersected_spans()> method.
694
695 =item * closest 
696
697   my $span = $set->closest( $dt );
698
699 This method is used to find the "closest" span in the set, given a
700 datetime or span.
701
702 The return value is a C<DateTime::SpanSet>, or C<undef> if the set is
703 empty.
704
705 If a span parameter is given, it may happen that "closest" returns
706 more than one span.
707
708 =item * as_list
709
710 Returns a list of C<DateTime::Span> objects.
711
712   my @dt_span = $set->as_list( span => $span );
713
714 Just as with the C<iterator()> method, the C<as_list()> method can be
715 limited by a span.
716
717 Applying C<as_list()> to a large recurring spanset is a very expensive
718 operation, both in CPU time and in the memory used.
719
720 For this reason, when C<as_list()> operates on large recurrence sets,
721 it will return at most approximately 200 spans. For larger sets, and
722 for I<infinite> sets, C<as_list()> will return C<undef>.
723
724 Please note that this is explicitly not an empty list, since an empty
725 list is a valid return value for empty sets!
726
727 If you I<really> need to extract spans from a large set, you can:
728
729 - limit the set with a shorter span:
730
731     my @short_list = $large_set->as_list( span => $short_span );
732
733 - use an iterator:
734
735     my @large_list;
736     my $iter = $large_set->iterator;
737     push @large_list, $dt while $dt = $iter->next;
738
739 =item * union
740
741 =item * intersection
742
743 =item * complement
744
745 Set operations may be performed not only with C<DateTime::SpanSet>
746 objects, but also with C<DateTime>, C<DateTime::Set> and
747 C<DateTime::Span> objects.  These set operations always return a
748 C<DateTime::SpanSet> object.
749
750     $set = $spanset->union( $set2 );         # like "OR", "insert", "both"
751     $set = $spanset->complement( $set2 );    # like "delete", "remove"
752     $set = $spanset->intersection( $set2 );  # like "AND", "while"
753     $set = $spanset->complement;             # like "NOT", "negate", "invert"
754
755 =item * intersected_spans
756
757 This method can accept a C<DateTime> list, a C<DateTime::Set>, a
758 C<DateTime::Span>, or a C<DateTime::SpanSet> object as an argument.
759
760     $set = $set1->intersected_spans( $set2 );
761
762 The method always returns a C<DateTime::SpanSet> object, containing
763 all spans that are intersected by the given set.
764
765 Unlike the C<intersection> method, the spans are not modified.  See
766 diagram below:
767
768                set1   [....]   [....]   [....]   [....]
769                set2      [................]
770
771        intersection      [.]   [....]   [.]
772
773   intersected_spans   [....]   [....]   [....]
774
775 =item * intersects
776
777 =item * contains
778
779 These set functions return a boolean value.
780
781     if ( $spanset->intersects( $set2 ) ) { ...  # like "touches", "interferes"
782     if ( $spanset->contains( $dt ) ) { ...    # like "is-fully-inside"
783
784 These methods can accept a C<DateTime>, C<DateTime::Set>,
785 C<DateTime::Span>, or C<DateTime::SpanSet> object as an argument.
786
787 =item * iterator / next / previous
788
789 This method can be used to iterate over the spans in a set.
790
791     $iter = $spanset->iterator;
792     while ( $dt = $iter->next ) {
793         # $dt is a DateTime::Span
794         print $dt->min->ymd;   # first date of span
795         print $dt->max->ymd;   # last date of span
796     }
797
798 The boundaries of the iterator can be limited by passing it a C<span>
799 parameter.  This should be a C<DateTime::Span> object which delimits
800 the iterator's boundaries.  Optionally, instead of passing an object,
801 you can pass any parameters that would work for one of the
802 C<DateTime::Span> class's constructors, and an object will be created
803 for you.
804
805 Obviously, if the span you specify does is not restricted both at the
806 start and end, then your iterator may iterate forever, depending on
807 the nature of your set.  User beware!
808
809 The C<next()> or C<previous()> methods will return C<undef> when there
810 are no more spans in the iterator.
811
812 =item * start_set
813
814 =item * end_set
815
816 These methods do the inverse of the C<from_sets> method:
817
818 C<start_set> retrieves a DateTime::Set with the start datetime of each
819 span.
820
821 C<end_set> retrieves a DateTime::Set with the end datetime of each
822 span.
823
824 =item * map ( sub { ... } )
825
826     # example: enlarge the spans
827     $set = $set2->map( 
828         sub {
829             my $start = $_->start;
830             my $end = $_->end;
831             return DateTime::Span->from_datetimes(
832                 start => $start,
833                 before => $end,
834             );
835         }
836     );
837
838 This method is the "set" version of Perl "map".
839
840 It evaluates a subroutine for each element of the set (locally setting
841 "$_" to each DateTime::Span) and returns the set composed of the
842 results of each such evaluation.
843
844 Like Perl "map", each element of the set may produce zero, one, or
845 more elements in the returned value.
846
847 Unlike Perl "map", changing "$_" does not change the original
848 set. This means that calling map in void context has no effect.
849
850 The callback subroutine may not be called immediately.  Don't count on
851 subroutine side-effects. For example, a C<print> inside the subroutine
852 may happen later than you expect.
853
854 The callback return value is expected to be within the span of the
855 C<previous> and the C<next> element in the original set.
856
857 For example: given the set C<[ 2001, 2010, 2015 ]>, the callback
858 result for the value C<2010> is expected to be within the span C<[
859 2001 .. 2015 ]>.
860
861 =item * grep ( sub { ... } )
862
863     # example: filter out all spans happening today
864     my $today = DateTime->today;
865     $set = $set2->grep( 
866         sub {
867             return ( ! $_->contains( $today ) );
868         }
869     );
870
871 This method is the "set" version of Perl "grep".
872
873 It evaluates a subroutine for each element of the set (locally setting
874 "$_" to each DateTime::Span) and returns the set consisting of those
875 elements for which the expression evaluated to true.
876
877 Unlike Perl "grep", changing "$_" does not change the original
878 set. This means that calling grep in void context has no effect.
879
880 Changing "$_" does change the resulting set.
881
882 The callback subroutine may not be called immediately.  Don't count on
883 subroutine side-effects. For example, a C<print> inside the subroutine
884 may happen later than you expect.
885
886 =item * iterate
887
888 I<Internal method - use "map" or "grep" instead.>
889
890 This function apply a callback subroutine to all elements of a set and
891 returns the resulting set.
892
893 The parameter C<$_[0]> to the callback subroutine is a
894 C<DateTime::Span> object.
895
896 If the callback returns C<undef>, the datetime is removed from the
897 set:
898
899     sub remove_sundays {
900         $_[0] unless $_[0]->start->day_of_week == 7;
901     }
902
903 The callback return value is expected to be within the span of the
904 C<previous> and the C<next> element in the original set.
905
906 For example: given the set C<[ 2001, 2010, 2015 ]>, the callback
907 result for the value C<2010> is expected to be within the span C<[
908 2001 .. 2015 ]>.
909
910 The callback subroutine may not be called immediately.  Don't count on
911 subroutine side-effects. For example, a C<print> inside the subroutine
912 may happen later than you expect.
913
914 =back
915
916 =head1 SUPPORT
917
918 Support is offered through the C<datetime@perl.org> mailing list.
919
920 Please report bugs using rt.cpan.org
921
922 =head1 AUTHOR
923
924 Flavio Soibelmann Glock <fglock@pucrs.br>
925
926 The API was developed together with Dave Rolsky and the DateTime Community.
927
928 =head1 COPYRIGHT
929
930 Copyright (c) 2003 Flavio Soibelmann Glock. All rights reserved.
931 This program is free software; you can distribute it and/or
932 modify it under the same terms as Perl itself.
933
934 The full text of the license can be found in the LICENSE file
935 included with this module.
936
937 =head1 SEE ALSO
938
939 Set::Infinite
940
941 For details on the Perl DateTime Suite project please see
942 L<http://datetime.perl.org>.
943
944 =cut
945