Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 3720cd5e

Von Sven Schöling vor mehr als 6 Jahren hinzugefügt

  • ID 3720cd5e3b013e1b1af311179b383e9f61832baa
  • Vorgänger 8a6fc682
  • Nachfolger 981979b5

modules/fallback: Module entfernt.

In modules/fallback sollten nur module stehen die:

a) für installationcheck gebraucht werden oder
b) nicht per apt installierbar sind

Das gilt für die folgenden Module schon lange nicht mehr:

  • DateTime::Set
  • Email::Address
  • List::MoreUtils
  • List::UtilsBy
  • PBKDF2::Tiny
  • Regexp::IPv6
  • Set::Infinite
  • String::ShellQuote
  • parent

Dabei waren DateTime::Set und Set::Infinite als Anhängigkeiten von
DateTime::Event::Cron reingekommen, das gibt es aber zusammen mit
Set::Crontab immernoch nicht in apt, also ist das weiter im fallback.

List::MoreUtils und List::UtilsBy sind meine ich für Debian 5
reingekommen, die Pakete sind aber seit Ewigkeiten in apt verfügbar.

parent ist seit 5.10.1 ein coremodul.

Die anderen wurden anscheinend einfach so reingeworfen, und hätten da
nie drin sein sollen.

Unterschiede anzeigen:

SL/InstallationCheck.pm
17 17
#   dist_name: name of the package in cpan if it differs from name (ex.: LWP != libwww-perl)
18 18
@required_modules = (
19 19
  { name => "parent",                              url => "http://search.cpan.org/~corion/",    debian => 'libparent-perl' },
20
  { name => "Algorithm::CheckDigits",              url => "http://search.cpan.org/dist/Algorithm-CheckDigits/", debian => 'libalgorithm-checkdigits-perl' },
20
  { name => "Algorithm::CheckDigits",              url => "http://search.cpan.org/~mamawe/",    debian => 'libalgorithm-checkdigits-perl' },
21 21
  { name => "Archive::Zip",    version => '1.16',  url => "http://search.cpan.org/~phred/",     debian => 'libarchive-zip-perl' },
22 22
  { name => "CGI",             version => '3.43',  url => "http://search.cpan.org/~leejo/",     debian => 'libcgi-pm-perl' }, # 4.09 is not core anymore (perl 5.20)
23 23
  { name => "Clone",                               url => "http://search.cpan.org/~rdf/",       debian => 'libclone-perl' },
24 24
  { name => "Config::Std",                         url => "http://search.cpan.org/~dconway/",   debian => 'libconfig-std-perl' },
25
  { name => "Daemon::Generic", version => '0.71',  url => "http://search.cpan.org/~muir/", },
25 26
  { name => "DateTime",                            url => "http://search.cpan.org/~drolsky/",   debian => 'libdatetime-perl' },
27
  { name => "DateTime::Event::Cron", version => '0.08', url => "http://search.cpan.org/~msisk/", },
26 28
  { name => "DateTime::Format::Strptime",          url => "http://search.cpan.org/~drolsky/",   debian => 'libdatetime-format-strptime-perl' },
29
  { name => "DateTime::Set",   version => '0.12',  url => "http://search.cpan.org/~fglock/",    debian => 'libdatetime-set-perl' },
27 30
  { name => "DBI",             version => '1.50',  url => "http://search.cpan.org/~timb/",      debian => 'libdbi-perl' },
28 31
  { name => "DBD::Pg",         version => '1.49',  url => "http://search.cpan.org/~dbdpg/",     debian => 'libdbd-pg-perl' },
29 32
  { name => "Digest::SHA",                         url => "http://search.cpan.org/~mshelor/",   debian => 'libdigest-sha-perl' },
30
  { name => "Email::Address",                      url => "http://search.cpan.org/~rjbs/",      debian => 'libemail-address-perl' },
33
  { name => "Exception::Lite",                     url => "http://search.cpan.org/~elisheva/", },
34
  { name => "Email::Address",  version => '1.888', url => "http://search.cpan.org/~rjbs/",      debian => 'libemail-address-perl' },
31 35
  { name => "Email::MIME",                         url => "http://search.cpan.org/~rjbs/",      debian => 'libemail-mime-perl' },
32 36
  { name => "FCGI",            version => '0.72',  url => "http://search.cpan.org/~mstrout/",   debian => 'libfcgi-perl' },
33 37
  { name => "File::Copy::Recursive",               url => "http://search.cpan.org/~dmuey/",     debian => 'libfile-copy-recursive-perl' },
38
  { name => "File::Flock",   version => '2008.01', url => "http://search.cpan.org/~muir/", },
34 39
  { name => "File::MimeInfo",                      url => "http://search.cpan.org/~michielb/",  debian => 'libfile-mimeinfo-perl' },
35 40
  { name => "GD",                                  url => "http://search.cpan.org/~lds/",       debian => 'libgd-gd2-perl', },
36 41
  { name => 'HTML::Parser',                        url => 'http://search.cpan.org/~gaas/',      debian => 'libhtml-parser-perl', },
37 42
  { name => 'HTML::Restrict',                      url => 'http://search.cpan.org/~oalders/', },
38 43
  { name => "Image::Info",                         url => "http://search.cpan.org/~srezic/",    debian => 'libimage-info-perl' },
39 44
  { name => "JSON",                                url => "http://search.cpan.org/~makamaka",   debian => 'libjson-perl' },
40
  { name => "List::MoreUtils", version => '0.21',  url => "http://search.cpan.org/~vparseval/", debian => 'liblist-moreutils-perl' },
41
  { name => "List::UtilsBy",                       url => "http://search.cpan.org/~pevans/",    debian => 'liblist-utilsby-perl' },
45
  { name => "List::MoreUtils", version => '0.30',  url => "http://search.cpan.org/~vparseval/", debian => 'liblist-moreutils-perl' },
46
  { name => "List::UtilsBy",   version => '0.09',  url => "http://search.cpan.org/~pevans/",    debian => 'liblist-utilsby-perl' },
42 47
  { name => "LWP::Authen::Digest",                 url => "http://search.cpan.org/~gaas/",      debian => 'libwww-perl', dist_name => 'libwww-perl' },
43 48
  { name => "LWP::UserAgent",                      url => "http://search.cpan.org/~gaas/",      debian => 'libwww-perl', dist_name => 'libwww-perl' },
44 49
  { name => "Params::Validate",                    url => "http://search.cpan.org/~drolsky/",   debian => 'libparams-validate-perl' },
45
  { name => "PBKDF2::Tiny",    version => '0.005', url => "http://search.cpan.org/~arodland/", },
50
  { name => "PBKDF2::Tiny",    version => '0.005', url => "http://search.cpan.org/~dagolden/",  debian => 'libpbkdf2-tiny-perl' },
46 51
  { name => "PDF::API2",       version => '2.000', url => "http://search.cpan.org/~areibens/",  debian => 'libpdf-api2-perl' },
52
  { name => "Regexp::IPv6",    version => '0.03',  url => "http://search.cpan.org/~salva/",     debian => 'libregexp-ipv6-perl' },
47 53
  { name => "Rose::Object",                        url => "http://search.cpan.org/~jsiracusa/", debian => 'librose-object-perl' },
48 54
  { name => "Rose::DB",                            url => "http://search.cpan.org/~jsiracusa/", debian => 'librose-db-perl' },
49 55
  { name => "Rose::DB::Object", version => 0.788,  url => "http://search.cpan.org/~jsiracusa/", debian => 'librose-db-object-perl' },
56
  { name => "Set::Infinite",    version => '0.63', url => "http://search.cpan.org/~fglock/", },
57
  { name => "Set::Crontab",     version => '1.03', url => "http://search.cpan.org/~ams/",  },
50 58
  { name => "String::ShellQuote", version => 1.01, url => "http://search.cpan.org/~rosch/",     debian => 'libstring-shellquote-perl' },
51 59
  { name => "Sort::Naturally",                     url => "http://search.cpan.org/~sburke/",    debian => 'libsort-naturally-perl' },
52 60
  # Test::Harness is core, so no Debian packages. Test::Harness 3.00 was first packaged in 5.10.1
modules/fallback/DateTime/Set.pm
1

  
2
package DateTime::Set;
3

  
4
use strict;
5
use Carp;
6
use Params::Validate qw( validate SCALAR BOOLEAN OBJECT CODEREF ARRAYREF );
7
use DateTime 0.12;  # this is for version checking only
8
use DateTime::Duration;
9
use DateTime::Span;
10
use Set::Infinite 0.59;
11
use Set::Infinite::_recurrence;
12

  
13
use vars qw( $VERSION );
14

  
15
use constant INFINITY     =>       100 ** 100 ** 100 ;
16
use constant NEG_INFINITY => -1 * (100 ** 100 ** 100);
17

  
18
BEGIN {
19
    $VERSION = '0.28';
20
}
21

  
22

  
23
sub _fix_datetime {
24
    # internal function -
25
    # (not a class method)
26
    #
27
    # checks that the parameter is an object, and
28
    # also protects the object against mutation
29
    
30
    return $_[0]
31
        unless defined $_[0];      # error
32
    return $_[0]->clone
33
        if ref( $_[0] );           # "immutable" datetime
34
    return DateTime::Infinite::Future->new 
35
        if $_[0] == INFINITY;      # Inf
36
    return DateTime::Infinite::Past->new
37
        if $_[0] == NEG_INFINITY;  # -Inf
38
    return $_[0];                  # error
39
}
40

  
41
sub _fix_return_datetime {
42
    my ( $dt, $dt_arg ) = @_;
43

  
44
    # internal function -
45
    # (not a class method)
46
    #
47
    # checks that the returned datetime has the same
48
    # time zone as the parameter
49

  
50
    # TODO: set locale
51

  
52
    return unless $dt;
53
    return unless $dt_arg;
54
    if ( $dt_arg->can('time_zone_long_name') &&
55
         !( $dt_arg->time_zone_long_name eq 'floating' ) )
56
    {
57
        $dt->set_time_zone( $dt_arg->time_zone );
58
    }
59
    return $dt;
60
}
61

  
62
sub iterate {
63
    # deprecated method - use map() or grep() instead
64
    my ( $self, $callback ) = @_;
65
    my $class = ref( $self );
66
    my $return = $class->empty_set;
67
    $return->{set} = $self->{set}->iterate( 
68
        sub {
69
            my $min = $_[0]->min;
70
            $callback->( $min->clone ) if ref($min);
71
        }
72
    );
73
    $return;
74
}
75

  
76
sub map {
77
    my ( $self, $callback ) = @_;
78
    my $class = ref( $self );
79
    die "The callback parameter to map() must be a subroutine reference"
80
        unless ref( $callback ) eq 'CODE';
81
    my $return = $class->empty_set;
82
    $return->{set} = $self->{set}->iterate( 
83
        sub {
84
            local $_ = $_[0]->min;
85
            next unless ref( $_ );
86
            $_ = $_->clone;
87
            my @list = $callback->();
88
            my $set = Set::Infinite::_recurrence->new();
89
            $set = $set->union( $_ ) for @list;
90
            return $set;
91
        }
92
    );
93
    $return;
94
}
95

  
96
sub grep {
97
    my ( $self, $callback ) = @_;
98
    my $class = ref( $self );
99
    die "The callback parameter to grep() must be a subroutine reference"
100
        unless ref( $callback ) eq 'CODE';
101
    my $return = $class->empty_set;
102
    $return->{set} = $self->{set}->iterate( 
103
        sub {
104
            local $_ = $_[0]->min;
105
            next unless ref( $_ );
106
            $_ = $_->clone;
107
            my $result = $callback->();
108
            return $_ if $result;
109
            return;
110
        }
111
    );
112
    $return;
113
}
114

  
115
sub add { return shift->add_duration( DateTime::Duration->new(@_) ) }
116

  
117
sub subtract { return shift->subtract_duration( DateTime::Duration->new(@_) ) }
118

  
119
sub subtract_duration { return $_[0]->add_duration( $_[1]->inverse ) }
120

  
121
sub add_duration {
122
    my ( $self, $dur ) = @_;
123
    $dur = $dur->clone;  # $dur must be "immutable"
124

  
125
    $self->{set} = $self->{set}->iterate(
126
        sub {
127
            my $min = $_[0]->min;
128
            $min->clone->add_duration( $dur ) if ref($min);
129
        },
130
        backtrack_callback => sub { 
131
            my ( $min, $max ) = ( $_[0]->min, $_[0]->max );
132
            if ( ref($min) )
133
            {
134
                $min = $min->clone;
135
                $min->subtract_duration( $dur );
136
            }
137
            if ( ref($max) )
138
            {
139
                $max = $max->clone;
140
                $max->subtract_duration( $dur );
141
            }
142
            return Set::Infinite::_recurrence->new( $min, $max );
143
        },
144
    );
145
    $self;
146
}
147

  
148
sub set_time_zone {
149
    my ( $self, $tz ) = @_;
150

  
151
    $self->{set} = $self->{set}->iterate(
152
        sub {
153
            my $min = $_[0]->min;
154
            $min->clone->set_time_zone( $tz ) if ref($min);
155
        },
156
        backtrack_callback => sub {
157
            my ( $min, $max ) = ( $_[0]->min, $_[0]->max );
158
            if ( ref($min) )
159
            {
160
                $min = $min->clone;
161
                $min->set_time_zone( $tz );
162
            }
163
            if ( ref($max) )
164
            {
165
                $max = $max->clone;
166
                $max->set_time_zone( $tz );
167
            }
168
            return Set::Infinite::_recurrence->new( $min, $max );
169
        },
170
    );
171
    $self;
172
}
173

  
174
sub set {
175
    my $self = shift;
176
    my %args = validate( @_,
177
                         { locale => { type => SCALAR | OBJECT,
178
                                       default => undef },
179
                         }
180
                       );
181
    $self->{set} = $self->{set}->iterate( 
182
        sub {
183
            my $min = $_[0]->min;
184
            $min->clone->set( %args ) if ref($min);
185
        },
186
    );
187
    $self;
188
}
189

  
190
sub from_recurrence {
191
    my $class = shift;
192

  
193
    my %args = @_;
194
    my %param;
195
    
196
    # Parameter renaming, such that we can use either
197
    #   recurrence => xxx   or   next => xxx, previous => xxx
198
    $param{next} = delete $args{recurrence} || delete $args{next};
199
    $param{previous} = delete $args{previous};
200

  
201
    $param{span} = delete $args{span};
202
    # they might be specifying a span using begin / end
203
    $param{span} = DateTime::Span->new( %args ) if keys %args;
204

  
205
    my $self = {};
206
    
207
    die "Not enough arguments in from_recurrence()"
208
        unless $param{next} || $param{previous}; 
209

  
210
    if ( ! $param{previous} ) 
211
    {
212
        my $data = {};
213
        $param{previous} =
214
                sub {
215
                    _callback_previous ( _fix_datetime( $_[0] ), $param{next}, $data );
216
                }
217
    }
218
    else
219
    {
220
        my $previous = $param{previous};
221
        $param{previous} =
222
                sub {
223
                    $previous->( _fix_datetime( $_[0] ) );
224
                }
225
    }
226

  
227
    if ( ! $param{next} ) 
228
    {
229
        my $data = {};
230
        $param{next} =
231
                sub {
232
                    _callback_next ( _fix_datetime( $_[0] ), $param{previous}, $data );
233
                }
234
    }
235
    else
236
    {
237
        my $next = $param{next};
238
        $param{next} =
239
                sub {
240
                    $next->( _fix_datetime( $_[0] ) );
241
                }
242
    }
243

  
244
    my ( $min, $max );
245
    $max = $param{previous}->( DateTime::Infinite::Future->new );
246
    $min = $param{next}->( DateTime::Infinite::Past->new );
247
    $max = INFINITY if $max->is_infinite;
248
    $min = NEG_INFINITY if $min->is_infinite;
249
        
250
    my $base_set = Set::Infinite::_recurrence->new( $min, $max );
251
    $base_set = $base_set->intersection( $param{span}->{set} )
252
         if $param{span};
253
         
254
    # warn "base set is $base_set\n";
255

  
256
    my $data = {};
257
    $self->{set} = 
258
            $base_set->_recurrence(
259
                $param{next}, 
260
                $param{previous},
261
                $data,
262
        );
263
    bless $self, $class;
264
    
265
    return $self;
266
}
267

  
268
sub from_datetimes {
269
    my $class = shift;
270
    my %args = validate( @_,
271
                         { dates => 
272
                           { type => ARRAYREF,
273
                           },
274
                         }
275
                       );
276
    my $self = {};
277
    $self->{set} = Set::Infinite::_recurrence->new;
278
    # possible optimization: sort datetimes and use "push"
279
    for( @{ $args{dates} } ) 
280
    {
281
        # DateTime::Infinite objects are not welcome here,
282
        # but this is not enforced (it does't hurt)
283

  
284
        carp "The 'dates' argument to from_datetimes() must only contain ".
285
             "datetime objects"
286
            unless UNIVERSAL::can( $_, 'utc_rd_values' );
287

  
288
        $self->{set} = $self->{set}->union( $_->clone );
289
    }
290

  
291
    bless $self, $class;
292
    return $self;
293
}
294

  
295
sub empty_set {
296
    my $class = shift;
297

  
298
    return bless { set => Set::Infinite::_recurrence->new }, $class;
299
}
300

  
301
sub clone { 
302
    my $self = bless { %{ $_[0] } }, ref $_[0];
303
    $self->{set} = $_[0]->{set}->copy;
304
    return $self;
305
}
306

  
307
# default callback that returns the 
308
# "previous" value in a callback recurrence.
309
#
310
# This is used to simulate a 'previous' callback,
311
# when then 'previous' argument in 'from_recurrence' is missing.
312
#
313
sub _callback_previous {
314
    my ($value, $callback_next, $callback_info) = @_; 
315
    my $previous = $value->clone;
316

  
317
    return $value if $value->is_infinite;
318

  
319
    my $freq = $callback_info->{freq};
320
    unless (defined $freq) 
321
    { 
322
        # This is called just once, to setup the recurrence frequency
323
        my $previous = $callback_next->( $value );
324
        my $next =     $callback_next->( $previous );
325
        $freq = 2 * ( $previous - $next );
326
        # save it for future use with this same recurrence
327
        $callback_info->{freq} = $freq;
328
    }
329

  
330
    $previous->add_duration( $freq );  
331
    $previous = $callback_next->( $previous );
332
    if ($previous >= $value) 
333
    {
334
        # This error happens if the event frequency oscilates widely
335
        # (more than 100% of difference from one interval to next)
336
        my @freq = $freq->deltas;
337
        print STDERR "_callback_previous: Delta components are: @freq\n";
338
        warn "_callback_previous: iterator can't find a previous value, got ".
339
            $previous->ymd." after ".$value->ymd;
340
    }
341
    my $previous1;
342
    while (1) 
343
    {
344
        $previous1 = $previous->clone;
345
        $previous = $callback_next->( $previous );
346
        return $previous1 if $previous >= $value;
347
    }
348
}
349

  
350
# default callback that returns the 
351
# "next" value in a callback recurrence.
352
#
353
# This is used to simulate a 'next' callback,
354
# when then 'next' argument in 'from_recurrence' is missing.
355
#
356
sub _callback_next {
357
    my ($value, $callback_previous, $callback_info) = @_; 
358
    my $next = $value->clone;
359

  
360
    return $value if $value->is_infinite;
361

  
362
    my $freq = $callback_info->{freq};
363
    unless (defined $freq) 
364
    { 
365
        # This is called just once, to setup the recurrence frequency
366
        my $next =     $callback_previous->( $value );
367
        my $previous = $callback_previous->( $next );
368
        $freq = 2 * ( $next - $previous );
369
        # save it for future use with this same recurrence
370
        $callback_info->{freq} = $freq;
371
    }
372

  
373
    $next->add_duration( $freq );  
374
    $next = $callback_previous->( $next );
375
    if ($next <= $value) 
376
    {
377
        # This error happens if the event frequency oscilates widely
378
        # (more than 100% of difference from one interval to next)
379
        my @freq = $freq->deltas;
380
        print STDERR "_callback_next: Delta components are: @freq\n";
381
        warn "_callback_next: iterator can't find a previous value, got ".
382
            $next->ymd." before ".$value->ymd;
383
    }
384
    my $next1;
385
    while (1) 
386
    {
387
        $next1 = $next->clone;
388
        $next =  $callback_previous->( $next );
389
        return $next1 if $next >= $value;
390
    }
391
}
392

  
393
sub iterator {
394
    my $self = shift;
395

  
396
    my %args = @_;
397
    my $span;
398
    $span = delete $args{span};
399
    $span = DateTime::Span->new( %args ) if %args;
400

  
401
    return $self->intersection( $span ) if $span;
402
    return $self->clone;
403
}
404

  
405

  
406
# next() gets the next element from an iterator()
407
# next( $dt ) returns the next element after a datetime.
408
sub next {
409
    my $self = shift;
410
    return undef unless ref( $self->{set} );
411

  
412
    if ( @_ ) 
413
    {
414
        if ( $self->{set}->_is_recurrence )
415
        {
416
            return _fix_return_datetime(
417
                       $self->{set}->{param}[0]->( $_[0] ), $_[0] );
418
        }
419
        else 
420
        {
421
            my $span = DateTime::Span->from_datetimes( after => $_[0] );
422
            return _fix_return_datetime(
423
                        $self->intersection( $span )->next, $_[0] );
424
        }
425
    }
426

  
427
    my ($head, $tail) = $self->{set}->first;
428
    $self->{set} = $tail;
429
    return $head->min if defined $head;
430
    return $head;
431
}
432

  
433
# previous() gets the last element from an iterator()
434
# previous( $dt ) returns the previous element before a datetime.
435
sub previous {
436
    my $self = shift;
437
    return undef unless ref( $self->{set} );
438

  
439
    if ( @_ ) 
440
    {
441
        if ( $self->{set}->_is_recurrence ) 
442
        {
443
            return _fix_return_datetime(
444
                      $self->{set}->{param}[1]->( $_[0] ), $_[0] );
445
        }
446
        else 
447
        {
448
            my $span = DateTime::Span->from_datetimes( before => $_[0] );
449
            return _fix_return_datetime(
450
                      $self->intersection( $span )->previous, $_[0] );
451
        }
452
    }
453

  
454
    my ($head, $tail) = $self->{set}->last;
455
    $self->{set} = $tail;
456
    return $head->max if defined $head;
457
    return $head;
458
}
459

  
460
# "current" means less-or-equal to a datetime
461
sub current {
462
    my $self = shift;
463

  
464
    return undef unless ref( $self->{set} );
465

  
466
    if ( $self->{set}->_is_recurrence )
467
    {
468
        my $tmp = $self->next( $_[0] );
469
        return $self->previous( $tmp );
470
    }
471

  
472
    return $_[0] if $self->contains( $_[0] );
473
    $self->previous( $_[0] );
474
}
475

  
476
sub closest {
477
    my $self = shift;
478
    # return $_[0] if $self->contains( $_[0] );
479
    my $dt1 = $self->current( $_[0] );
480
    my $dt2 = $self->next( $_[0] );
481

  
482
    return $dt2 unless defined $dt1;
483
    return $dt1 unless defined $dt2;
484

  
485
    my $delta = $_[0] - $dt1;
486
    return $dt1 if ( $dt2 - $delta ) >= $_[0];
487

  
488
    return $dt2;
489
}
490

  
491
sub as_list {
492
    my $self = shift;
493
    return undef unless ref( $self->{set} );
494

  
495
    my %args = @_;
496
    my $span;
497
    $span = delete $args{span};
498
    $span = DateTime::Span->new( %args ) if %args;
499

  
500
    my $set = $self->clone;
501
    $set = $set->intersection( $span ) if $span;
502

  
503
    return if $set->{set}->is_null;  # nothing = empty
504

  
505
    # Note: removing this line means we may end up in an infinite loop!
506
    ## return undef if $set->{set}->is_too_complex;  # undef = no begin/end
507
 
508
    return undef
509
        if $set->max->is_infinite ||
510
           $set->min->is_infinite;
511

  
512
    my @result;
513
    my $next = $self->min;
514
    if ( $span ) {
515
        my $next1 = $span->min;
516
        $next = $next1 if $next1 && $next1 > $next;
517
        $next = $self->current( $next );
518
    }
519
    my $last = $self->max;
520
    if ( $span ) {
521
        my $last1 = $span->max;
522
        $last = $last1 if $last1 && $last1 < $last;
523
    }
524
    do {
525
        push @result, $next if !$span || $span->contains($next);
526
        $next = $self->next( $next );
527
    }
528
    while $next && $next <= $last;
529
    return @result;
530
}
531

  
532
sub intersection {
533
    my ($set1, $set2) = ( shift, shift );
534
    my $class = ref($set1);
535
    my $tmp = $class->empty_set();
536
    $set2 = $set2->as_set
537
        if $set2->can( 'as_set' );
538
    $set2 = $class->from_datetimes( dates => [ $set2, @_ ] ) 
539
        unless $set2->can( 'union' );
540
    $tmp->{set} = $set1->{set}->intersection( $set2->{set} );
541
    return $tmp;
542
}
543

  
544
sub intersects {
545
    my ($set1, $set2) = ( shift, shift );
546
    my $class = ref($set1);
547
    $set2 = $set2->as_set
548
        if $set2->can( 'as_set' );
549
    unless ( $set2->can( 'union' ) )
550
    {
551
        if ( $set1->{set}->_is_recurrence )
552
        {
553
            for ( $set2, @_ )
554
            {
555
                return 1 if $set1->current( $_ ) == $_;
556
            }
557
            return 0;
558
        }
559
        $set2 = $class->from_datetimes( dates => [ $set2, @_ ] )
560
    }
561
    return $set1->{set}->intersects( $set2->{set} );
562
}
563

  
564
sub contains {
565
    my ($set1, $set2) = ( shift, shift );
566
    my $class = ref($set1);
567
    $set2 = $set2->as_set
568
        if $set2->can( 'as_set' );
569
    unless ( $set2->can( 'union' ) )
570
    {
571
        if ( $set1->{set}->_is_recurrence )
572
        {
573
            for ( $set2, @_ ) 
574
            {
575
                return 0 unless $set1->current( $_ ) == $_;
576
            }
577
            return 1;
578
        }
579
        $set2 = $class->from_datetimes( dates => [ $set2, @_ ] ) 
580
    }
581
    return $set1->{set}->contains( $set2->{set} );
582
}
583

  
584
sub union {
585
    my ($set1, $set2) = ( shift, shift );
586
    my $class = ref($set1);
587
    my $tmp = $class->empty_set();
588
    $set2 = $set2->as_set
589
        if $set2->can( 'as_set' );
590
    $set2 = $class->from_datetimes( dates => [ $set2, @_ ] ) 
591
        unless $set2->can( 'union' );
592
    $tmp->{set} = $set1->{set}->union( $set2->{set} );
593
    bless $tmp, 'DateTime::SpanSet' 
594
        if $set2->isa('DateTime::Span') or $set2->isa('DateTime::SpanSet');
595
    return $tmp;
596
}
597

  
598
sub complement {
599
    my ($set1, $set2) = ( shift, shift );
600
    my $class = ref($set1);
601
    my $tmp = $class->empty_set();
602
    if (defined $set2) 
603
    {
604
        $set2 = $set2->as_set
605
            if $set2->can( 'as_set' );
606
        $set2 = $class->from_datetimes( dates => [ $set2, @_ ] ) 
607
            unless $set2->can( 'union' );
608
        # TODO: "compose complement";
609
        $tmp->{set} = $set1->{set}->complement( $set2->{set} );
610
    }
611
    else 
612
    {
613
        $tmp->{set} = $set1->{set}->complement;
614
        bless $tmp, 'DateTime::SpanSet';
615
    }
616
    return $tmp;
617
}
618

  
619
sub min { 
620
    return _fix_datetime( $_[0]->{set}->min );
621
}
622

  
623
sub max { 
624
    return _fix_datetime( $_[0]->{set}->max );
625
}
626

  
627
# returns a DateTime::Span
628
sub span {
629
  my $set = $_[0]->{set}->span;
630
  my $self = bless { set => $set }, 'DateTime::Span';
631
  return $self;
632
}
633

  
634
sub count {
635
    my ($self) = shift;
636
    return undef unless ref( $self->{set} );
637

  
638
    my %args = @_;
639
    my $span;
640
    $span = delete $args{span};
641
    $span = DateTime::Span->new( %args ) if %args;
642

  
643
    my $set = $self->clone;
644
    $set = $set->intersection( $span ) if $span;
645

  
646
    return $set->{set}->count
647
        unless $set->{set}->is_too_complex;
648

  
649
    return undef
650
        if $set->max->is_infinite ||
651
           $set->min->is_infinite;
652

  
653
    my $count = 0;
654
    my $iter = $set->iterator;
655
    $count++ while $iter->next;
656
    return $count;
657
}
658

  
659
1;
660

  
661
__END__
662

  
663
=head1 NAME
664

  
665
DateTime::Set - Datetime sets and set math
666

  
667
=head1 SYNOPSIS
668

  
669
    use DateTime;
670
    use DateTime::Set;
671

  
672
    $date1 = DateTime->new( year => 2002, month => 3, day => 11 );
673
    $set1 = DateTime::Set->from_datetimes( dates => [ $date1 ] );
674
    #  set1 = 2002-03-11
675

  
676
    $date2 = DateTime->new( year => 2003, month => 4, day => 12 );
677
    $set2 = DateTime::Set->from_datetimes( dates => [ $date1, $date2 ] );
678
    #  set2 = 2002-03-11, and 2003-04-12
679

  
680
    $date3 = DateTime->new( year => 2003, month => 4, day => 1 );
681
    print $set2->next( $date3 )->ymd;      # 2003-04-12
682
    print $set2->previous( $date3 )->ymd;  # 2002-03-11
683
    print $set2->current( $date3 )->ymd;   # 2002-03-11
684
    print $set2->closest( $date3 )->ymd;   # 2003-04-12
685

  
686
    # a 'monthly' recurrence:
687
    $set = DateTime::Set->from_recurrence( 
688
        recurrence => sub {
689
            return $_[0] if $_[0]->is_infinite;
690
            return $_[0]->truncate( to => 'month' )->add( months => 1 )
691
        },
692
        span => $date_span1,    # optional span
693
    );
694

  
695
    $set = $set1->union( $set2 );         # like "OR", "insert", "both"
696
    $set = $set1->complement( $set2 );    # like "delete", "remove"
697
    $set = $set1->intersection( $set2 );  # like "AND", "while"
698
    $set = $set1->complement;             # like "NOT", "negate", "invert"
699

  
700
    if ( $set1->intersects( $set2 ) ) { ...  # like "touches", "interferes"
701
    if ( $set1->contains( $set2 ) ) { ...    # like "is-fully-inside"
702

  
703
    # data extraction 
704
    $date = $set1->min;           # first date of the set
705
    $date = $set1->max;           # last date of the set
706

  
707
    $iter = $set1->iterator;
708
    while ( $dt = $iter->next ) {
709
        print $dt->ymd;
710
    };
711

  
712
=head1 DESCRIPTION
713

  
714
DateTime::Set is a module for datetime sets.  It can be used to handle
715
two different types of sets.
716

  
717
The first is a fixed set of predefined datetime objects.  For example,
718
if we wanted to create a set of datetimes containing the birthdays of
719
people in our family for the current year.
720

  
721
The second type of set that it can handle is one based on a
722
recurrence, such as "every Wednesday", or "noon on the 15th day of
723
every month".  This type of set can have fixed starting and ending
724
datetimes, but neither is required.  So our "every Wednesday set"
725
could be "every Wednesday from the beginning of time until the end of
726
time", or "every Wednesday after 2003-03-05 until the end of time", or
727
"every Wednesday between 2003-03-05 and 2004-01-07".
728

  
729
This module also supports set math operations, so you do things like
730
create a new set from the union or difference of two sets, check
731
whether a datetime is a member of a given set, etc.
732

  
733
This is different from a C<DateTime::Span>, which handles a continuous
734
range as opposed to individual datetime points. There is also a module
735
C<DateTime::SpanSet> to handle sets of spans.
736

  
737
=head1 METHODS
738

  
739
=over 4
740

  
741
=item * from_datetimes
742

  
743
Creates a new set from a list of datetimes.
744

  
745
   $dates = DateTime::Set->from_datetimes( dates => [ $dt1, $dt2, $dt3 ] );
746

  
747
The datetimes can be objects from class C<DateTime>, or from a
748
C<DateTime::Calendar::*> class.
749

  
750
C<DateTime::Infinite::*> objects are not valid set members.
751

  
752
=item * from_recurrence
753

  
754
Creates a new set specified via a "recurrence" callback.
755

  
756
    $months = DateTime::Set->from_recurrence( 
757
        span => $dt_span_this_year,    # optional span
758
        recurrence => sub { 
759
            return $_[0]->truncate( to => 'month' )->add( months => 1 ) 
760
        }, 
761
    );
762

  
763
The C<span> parameter is optional. It must be a C<DateTime::Span> object.
764

  
765
The span can also be specified using C<begin> / C<after> and C<before>
766
/ C<end> parameters, as in the C<DateTime::Span> constructor.  In this
767
case, if there is a C<span> parameter it will be ignored.
768

  
769
    $months = DateTime::Set->from_recurrence(
770
        after => $dt_now,
771
        recurrence => sub {
772
            return $_[0]->truncate( to => 'month' )->add( months => 1 );
773
        },
774
    );
775

  
776
The recurrence function will be passed a single parameter, a datetime
777
object. The parameter can be an object from class C<DateTime>, or from
778
one of the C<DateTime::Calendar::*> classes.  The parameter can also
779
be a C<DateTime::Infinite::Future> or a C<DateTime::Infinite::Past>
780
object.
781

  
782
The recurrence must return the I<next> event after that object.  There
783
is no guarantee as to what the returned object will be set to, only
784
that it will be greater than the object passed to the recurrence.
785

  
786
If there are no more datetimes after the given parameter, then the
787
recurrence function should return C<DateTime::Infinite::Future>.
788

  
789
It is ok to modify the parameter C<$_[0]> inside the recurrence
790
function.  There are no side-effects.
791

  
792
For example, if you wanted a recurrence that generated datetimes in
793
increments of 30 seconds, it would look like this:
794

  
795
  sub every_30_seconds {
796
      my $dt = shift;
797
      if ( $dt->second < 30 ) {
798
          return $dt->truncate( to => 'minute' )->add( seconds => 30 );
799
      } else {
800
          return $dt->truncate( to => 'minute' )->add( minutes => 1 );
801
      }
802
  }
803

  
804
Note that this recurrence takes leap seconds into account.  Consider
805
using C<truncate()> in this manner to avoid complicated arithmetic
806
problems!
807

  
808
It is also possible to create a recurrence by specifying either or both
809
of 'next' and 'previous' callbacks.
810

  
811
The callbacks can return C<DateTime::Infinite::Future> and
812
C<DateTime::Infinite::Past> objects, in order to define I<bounded
813
recurrences>.  In this case, both 'next' and 'previous' callbacks must
814
be defined:
815

  
816
    # "monthly from $dt until forever"
817

  
818
    my $months = DateTime::Set->from_recurrence(
819
        next => sub {
820
            return $dt if $_[0] < $dt;
821
            $_[0]->truncate( to => 'month' );
822
            $_[0]->add( months => 1 );
823
            return $_[0];
824
        },
825
        previous => sub {
826
            my $param = $_[0]->clone;
827
            $_[0]->truncate( to => 'month' );
828
            $_[0]->subtract( months => 1 ) if $_[0] == $param;
829
            return $_[0] if $_[0] >= $dt;
830
            return DateTime::Infinite::Past->new;
831
        },
832
    );
833

  
834
Bounded recurrences are easier to write using C<span> parameters. See above.
835

  
836
See also C<DateTime::Event::Recurrence> and the other
837
C<DateTime::Event::*> factory modules for generating specialized
838
recurrences, such as sunrise and sunset times, and holidays.
839

  
840
=item * empty_set
841

  
842
Creates a new empty set.
843

  
844
    $set = DateTime::Set->empty_set;
845
    print "empty set" unless defined $set->max;
846

  
847
=item * clone
848

  
849
This object method returns a replica of the given object.
850

  
851
C<clone> is useful if you want to apply a transformation to a set,
852
but you want to keep the previous value:
853

  
854
    $set2 = $set1->clone;
855
    $set2->add_duration( year => 1 );  # $set1 is unaltered
856

  
857
=item * add_duration( $duration )
858

  
859
This method adds the specified duration to every element of the set.
860

  
861
    $dt_dur = new DateTime::Duration( year => 1 );
862
    $set->add_duration( $dt_dur );
863

  
864
The original set is modified. If you want to keep the old values use:
865

  
866
    $new_set = $set->clone->add_duration( $dt_dur );
867

  
868
=item * add
869

  
870
This method is syntactic sugar around the C<add_duration()> method.
871

  
872
    $meetings_2004 = $meetings_2003->clone->add( years => 1 );
873

  
874
=item * subtract_duration( $duration_object )
875

  
876
When given a C<DateTime::Duration> object, this method simply calls
877
C<invert()> on that object and passes that new duration to the
878
C<add_duration> method.
879

  
880
=item * subtract( DateTime::Duration->new parameters )
881

  
882
Like C<add()>, this is syntactic sugar for the C<subtract_duration()>
883
method.
884

  
885
=item * set_time_zone( $tz )
886

  
887
This method will attempt to apply the C<set_time_zone> method to every 
888
datetime in the set.
889

  
890
=item * set( locale => .. )
891

  
892
This method can be used to change the C<locale> of a datetime set.
893

  
894
=item * min
895

  
896
=item * max
897

  
898
The first and last C<DateTime> in the set.  These methods may return
899
C<undef> if the set is empty.  It is also possible that these methods
900
may return a C<DateTime::Infinite::Past> or
901
C<DateTime::Infinite::Future> object.
902

  
903
These methods return just a I<copy> of the actual boundary value.
904
If you modify the result, the set will not be modified.
905

  
906
=item * span
907

  
908
Returns the total span of the set, as a C<DateTime::Span> object.
909

  
910
=item * iterator / next / previous
911

  
912
These methods can be used to iterate over the datetimes in a set.
913

  
914
    $iter = $set1->iterator;
915
    while ( $dt = $iter->next ) {
916
        print $dt->ymd;
917
    }
918

  
919
    # iterate backwards
920
    $iter = $set1->iterator;
921
    while ( $dt = $iter->previous ) {
922
        print $dt->ymd;
923
    }
924

  
925
The boundaries of the iterator can be limited by passing it a C<span>
926
parameter.  This should be a C<DateTime::Span> object which delimits
927
the iterator's boundaries.  Optionally, instead of passing an object,
928
you can pass any parameters that would work for one of the
929
C<DateTime::Span> class's constructors, and an object will be created
930
for you.
931

  
932
Obviously, if the span you specify is not restricted both at the start
933
and end, then your iterator may iterate forever, depending on the
934
nature of your set.  User beware!
935

  
936
The C<next()> or C<previous()> method will return C<undef> when there
937
are no more datetimes in the iterator.
938

  
939
=item * as_list
940

  
941
Returns the set elements as a list of C<DateTime> objects.  Just as
942
with the C<iterator()> method, the C<as_list()> method can be limited
943
by a span.
944

  
945
  my @dt = $set->as_list( span => $span );
946

  
947
Applying C<as_list()> to a large recurrence set is a very expensive
948
operation, both in CPU time and in the memory used.  If you I<really>
949
need to extract elements from a large set, you can limit the set with
950
a shorter span:
951

  
952
    my @short_list = $large_set->as_list( span => $short_span );
953

  
954
For I<infinite> sets, C<as_list()> will return C<undef>.  Please note
955
that this is explicitly not an empty list, since an empty list is a
956
valid return value for empty sets!
957

  
958
=item * count
959

  
960
Returns a count of C<DateTime> objects in the set.  Just as with the
961
C<iterator()> method, the C<count()> method can be limited by a span.
962

  
963
  defined( my $n = $set->count) or die "can't count";
964

  
965
  my $n = $set->count( span => $span );
966
  die "can't count" unless defined $n;
967

  
968
Applying C<count()> to a large recurrence set is a very expensive
969
operation, both in CPU time and in the memory used.  If you I<really>
970
need to count elements from a large set, you can limit the set with a
971
shorter span:
972

  
973
    my $count = $large_set->count( span => $short_span );
974

  
975
For I<infinite> sets, C<count()> will return C<undef>.  Please note
976
that this is explicitly not a scalar zero, since a zero count is a
977
valid return value for empty sets!
978

  
979
=item * union
980

  
981
=item * intersection
982

  
983
=item * complement
984

  
985
These set operation methods can accept a C<DateTime> list, a
986
C<DateTime::Set>, a C<DateTime::Span>, or a C<DateTime::SpanSet>
987
object as an argument.
988

  
989
    $set = $set1->union( $set2 );         # like "OR", "insert", "both"
990
    $set = $set1->complement( $set2 );    # like "delete", "remove"
991
    $set = $set1->intersection( $set2 );  # like "AND", "while"
992
    $set = $set1->complement;             # like "NOT", "negate", "invert"
993

  
994
The C<union> of a C<DateTime::Set> with a C<DateTime::Span> or a
995
C<DateTime::SpanSet> object returns a C<DateTime::SpanSet> object.
996

  
997
If C<complement> is called without any arguments, then the result is a
998
C<DateTime::SpanSet> object representing the spans between each of the
999
set's elements.  If complement is given an argument, then the return
1000
value is a C<DateTime::Set> object representing the I<set difference>
1001
between the sets.
1002

  
1003
All other operations will always return a C<DateTime::Set>.
1004

  
1005
=item * intersects
1006

  
1007
=item * contains
1008

  
1009
These set operations result in a boolean value.
1010

  
1011
    if ( $set1->intersects( $set2 ) ) { ...  # like "touches", "interferes"
1012
    if ( $set1->contains( $dt ) ) { ...    # like "is-fully-inside"
1013

  
1014
These methods can accept a C<DateTime> list, a C<DateTime::Set>, a
1015
C<DateTime::Span>, or a C<DateTime::SpanSet> object as an argument.
1016

  
1017
=item * previous
1018

  
1019
=item * next
1020

  
1021
=item * current
1022

  
1023
=item * closest
1024

  
1025
  my $dt = $set->next( $dt );
1026
  my $dt = $set->previous( $dt );
1027
  my $dt = $set->current( $dt );
1028
  my $dt = $set->closest( $dt );
1029

  
1030
These methods are used to find a set member relative to a given
1031
datetime.
1032

  
1033
The C<current()> method returns C<$dt> if $dt is an event, otherwise
1034
it returns the previous event.
1035

  
1036
The C<closest()> method returns C<$dt> if $dt is an event, otherwise
1037
it returns the closest event (previous or next).
1038

  
1039
All of these methods may return C<undef> if there is no matching
1040
datetime in the set.
1041

  
1042
These methods will try to set the returned value to the same time zone
1043
as the argument, unless the argument has a 'floating' time zone.
1044

  
1045
=item * map ( sub { ... } )
1046

  
1047
    # example: remove the hour:minute:second information
1048
    $set = $set2->map( 
1049
        sub {
1050
            return $_->truncate( to => day );
1051
        }
1052
    );
1053

  
1054
    # example: postpone or antecipate events which 
1055
    #          match datetimes within another set
1056
    $set = $set2->map(
1057
        sub {
1058
            return $_->add( days => 1 ) while $holidays->contains( $_ );
1059
        }
1060
    );
1061

  
1062
This method is the "set" version of Perl "map".
1063

  
1064
It evaluates a subroutine for each element of the set (locally setting
1065
"$_" to each datetime) and returns the set composed of the results of
1066
each such evaluation.
1067

  
1068
Like Perl "map", each element of the set may produce zero, one, or
1069
more elements in the returned value.
1070

  
1071
Unlike Perl "map", changing "$_" does not change the original
1072
set. This means that calling map in void context has no effect.
1073

  
1074
The callback subroutine may be called later in the program, due to
1075
lazy evaluation.  So don't count on subroutine side-effects. For
1076
example, a C<print> inside the subroutine may happen later than you
1077
expect.
1078

  
1079
The callback return value is expected to be within the span of the
1080
C<previous> and the C<next> element in the original set.  This is a
1081
limitation of the backtracking algorithm used in the C<Set::Infinite>
1082
library.
1083

  
1084
For example: given the set C<[ 2001, 2010, 2015 ]>, the callback
1085
result for the value C<2010> is expected to be within the span C<[
1086
2001 .. 2015 ]>.
1087

  
1088
=item * grep ( sub { ... } )
1089

  
1090
    # example: filter out any sundays
1091
    $set = $set2->grep( 
1092
        sub {
1093
            return ( $_->day_of_week != 7 );
1094
        }
1095
    );
1096

  
1097
This method is the "set" version of Perl "grep".
1098

  
1099
It evaluates a subroutine for each element of the set (locally setting
1100
"$_" to each datetime) and returns the set consisting of those
1101
elements for which the expression evaluated to true.
1102

  
1103
Unlike Perl "grep", changing "$_" does not change the original
1104
set. This means that calling grep in void context has no effect.
1105

  
1106
Changing "$_" does change the resulting set.
1107

  
1108
The callback subroutine may be called later in the program, due to
1109
lazy evaluation.  So don't count on subroutine side-effects. For
1110
example, a C<print> inside the subroutine may happen later than you
1111
expect.
1112

  
1113
=item * iterate ( sub { ... } )
1114

  
1115
I<deprecated method - please use "map" or "grep" instead.>
1116

  
1117
=back
1118

  
1119
=head1 SUPPORT
1120

  
1121
Support is offered through the C<datetime@perl.org> mailing list.
1122

  
1123
Please report bugs using rt.cpan.org
1124

  
1125
=head1 AUTHOR
1126

  
1127
Flavio Soibelmann Glock <fglock@pucrs.br>
1128

  
1129
The API was developed together with Dave Rolsky and the DateTime
1130
Community.
1131

  
1132
=head1 COPYRIGHT
1133

  
1134
Copyright (c) 2003-2006 Flavio Soibelmann Glock. All rights reserved.
1135
This program is free software; you can distribute it and/or modify it
1136
under the same terms as Perl itself.
1137

  
1138
The full text of the license can be found in the LICENSE file included
1139
with this module.
1140

  
1141
=head1 SEE ALSO
1142

  
1143
Set::Infinite
1144

  
1145
For details on the Perl DateTime Suite project please see
1146
L<http://datetime.perl.org>.
1147

  
1148
=cut
1149

  
modules/fallback/DateTime/Span.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::Span;
6

  
7
use strict;
8

  
9
use DateTime::Set;
10
use DateTime::SpanSet;
11

  
12
use Params::Validate qw( validate SCALAR BOOLEAN OBJECT CODEREF ARRAYREF );
13
use vars qw( $VERSION );
14

  
15
use constant INFINITY     => DateTime::INFINITY;
16
use constant NEG_INFINITY => DateTime::NEG_INFINITY;
17
$VERSION = $DateTime::Set::VERSION;
18

  
19
sub set_time_zone {
20
    my ( $self, $tz ) = @_;
21

  
22
    $self->{set} = $self->{set}->iterate( 
23
        sub {
24
            my %tmp = %{ $_[0]->{list}[0] };
25
            $tmp{a} = $tmp{a}->clone->set_time_zone( $tz ) if ref $tmp{a};
26
            $tmp{b} = $tmp{b}->clone->set_time_zone( $tz ) if ref $tmp{b};
27
            \%tmp;
28
        }
29
    );
30
    return $self;
31
}
32

  
33
# note: the constructor must clone its DateTime parameters, such that
34
# the set elements become immutable
35
sub from_datetimes {
36
    my $class = shift;
37
    my %args = validate( @_,
38
                         { start =>
39
                           { type => OBJECT,
40
                             optional => 1,
41
                           },
42
                           end =>
43
                           { type => OBJECT,
44
                             optional => 1,
45
                           },
46
                           after =>
47
                           { type => OBJECT,
48
                             optional => 1,
49
                           },
50
                           before =>
51
                           { type => OBJECT,
52
                             optional => 1,
53
                           },
54
                         }
55
                       );
56
    my $self = {};
57
    my $set;
58

  
59
    die "No arguments given to DateTime::Span->from_datetimes\n"
60
        unless keys %args;
61

  
62
    if ( exists $args{start} && exists $args{after} ) {
63
        die "Cannot give both start and after arguments to DateTime::Span->from_datetimes\n";
64
    }
65
    if ( exists $args{end} && exists $args{before} ) {
66
        die "Cannot give both end and before arguments to DateTime::Span->from_datetimes\n";
67
    }
68

  
69
    my ( $start, $open_start, $end, $open_end );
70
    ( $start, $open_start ) = ( NEG_INFINITY,  0 );
71
    ( $start, $open_start ) = ( $args{start},  0 ) if exists $args{start};
72
    ( $start, $open_start ) = ( $args{after},  1 ) if exists $args{after};
73
    ( $end,   $open_end   ) = ( INFINITY,      0 );
74
    ( $end,   $open_end   ) = ( $args{end},    0 ) if exists $args{end};
75
    ( $end,   $open_end   ) = ( $args{before}, 1 ) if exists $args{before};
76

  
77
    if ( $start > $end ) {
78
        die "Span cannot start after the end in DateTime::Span->from_datetimes\n";
79
    }
80
    $set = Set::Infinite::_recurrence->new( $start, $end );
81
    if ( $start != $end ) {
82
        # remove start, such that we have ">" instead of ">="
83
        $set = $set->complement( $start ) if $open_start;  
84
        # remove end, such that we have "<" instead of "<="
85
        $set = $set->complement( $end )   if $open_end;    
86
    }
87

  
88
    $self->{set} = $set;
89
    bless $self, $class;
90
    return $self;
91
}
92

  
93
sub from_datetime_and_duration {
94
    my $class = shift;
95
    my %args = @_;
96

  
97
    my $key;
98
    my $dt;
99
    # extract datetime parameters
100
    for ( qw( start end before after ) ) {
101
        if ( exists $args{$_} ) {
102
           $key = $_;
103
           $dt = delete $args{$_};
104
       }
105
    }
106

  
107
    # extract duration parameters
108
    my $dt_duration;
109
    if ( exists $args{duration} ) {
110
        $dt_duration = $args{duration};
111
    }
112
    else {
113
        $dt_duration = DateTime::Duration->new( %args );
114
    }
115
    # warn "Creating span from $key => ".$dt->datetime." and $dt_duration";
116
    my $other_date = $dt->clone->add_duration( $dt_duration );
117
    # warn "Creating span from $key => ".$dt->datetime." and ".$other_date->datetime;
118
    my $other_key;
119
    if ( $dt_duration->is_positive ) {
120
        # check if have to invert keys
121
        $key = 'after' if $key eq 'end';
122
        $key = 'start' if $key eq 'before';
123
        $other_key = 'before';
124
    }
125
    else {
126
        # check if have to invert keys
127
        $other_key = 'end' if $key eq 'after';
128
        $other_key = 'before' if $key eq 'start';
129
        $key = 'start';
130
    }
131
    return $class->new( $key => $dt, $other_key => $other_date ); 
132
}
133

  
134
# This method is intentionally not documented.  It's really only for
135
# use by ::Set and ::SpanSet's as_list() and iterator() methods.
136
sub new {
137
    my $class = shift;
138
    my %args = @_;
139

  
140
    # If we find anything _not_ appropriate for from_datetimes, we
141
    # assume it must be for durations, and call this constructor.
142
    # This way, we don't need to hardcode the DateTime::Duration
143
    # parameters.
144
    foreach ( keys %args )
145
    {
146
        return $class->from_datetime_and_duration(%args)
147
            unless /^(?:before|after|start|end)$/;
148
    }
149

  
150
    return $class->from_datetimes(%args);
151
}
152

  
153
sub clone { 
154
    bless { 
155
        set => $_[0]->{set}->copy,
156
        }, ref $_[0];
157
}
158

  
159
# Set::Infinite methods
160

  
161
sub intersection {
162
    my ($set1, $set2) = @_;
163
    my $class = ref($set1);
164
    my $tmp = {};  # $class->new();
165
    $set2 = $set2->as_spanset
166
        if $set2->can( 'as_spanset' );
167
    $set2 = $set2->as_set
168
        if $set2->can( 'as_set' );
169
    $set2 = DateTime::Set->from_datetimes( dates => [ $set2 ] ) 
170
        unless $set2->can( 'union' );
171
    $tmp->{set} = $set1->{set}->intersection( $set2->{set} );
172

  
173
    # intersection() can generate something more complex than a span.
174
    bless $tmp, 'DateTime::SpanSet';
175

  
176
    return $tmp;
177
}
178

  
179
sub intersects {
180
    my ($set1, $set2) = @_;
181
    my $class = ref($set1);
182
    $set2 = $set2->as_spanset
183
        if $set2->can( 'as_spanset' );
184
    $set2 = $set2->as_set
185
        if $set2->can( 'as_set' );
186
    $set2 = DateTime::Set->from_datetimes( dates => [ $set2 ] ) 
187
        unless $set2->can( 'union' );
188
    return $set1->{set}->intersects( $set2->{set} );
189
}
190

  
191
sub contains {
192
    my ($set1, $set2) = @_;
193
    my $class = ref($set1);
194
    $set2 = $set2->as_spanset
195
        if $set2->can( 'as_spanset' );
196
    $set2 = $set2->as_set
197
        if $set2->can( 'as_set' );
198
    $set2 = DateTime::Set->from_datetimes( dates => [ $set2 ] ) 
199
        unless $set2->can( 'union' );
200
    return $set1->{set}->contains( $set2->{set} );
201
}
202

  
203
sub union {
204
    my ($set1, $set2) = @_;
205
    my $class = ref($set1);
206
    my $tmp = {};   # $class->new();
207
    $set2 = $set2->as_spanset
208
        if $set2->can( 'as_spanset' );
209
    $set2 = $set2->as_set
210
        if $set2->can( 'as_set' );
211
    $set2 = DateTime::Set->from_datetimes( dates => [ $set2 ] ) 
212
        unless $set2->can( 'union' );
213
    $tmp->{set} = $set1->{set}->union( $set2->{set} );
214
 
215
    # union() can generate something more complex than a span.
216
    bless $tmp, 'DateTime::SpanSet';
217

  
218
    # # We have to check it's internal structure to find out.
219
    # if ( $#{ $tmp->{set}->{list} } != 0 ) {
220
    #    bless $tmp, 'Date::SpanSet';
221
    # }
222

  
223
    return $tmp;
224
}
225

  
226
sub complement {
227
    my ($set1, $set2) = @_;
228
    my $class = ref($set1);
229
    my $tmp = {};   # $class->new;
230
    if (defined $set2) {
231
        $set2 = $set2->as_spanset
232
            if $set2->can( 'as_spanset' );
233
        $set2 = $set2->as_set
234
            if $set2->can( 'as_set' );
235
        $set2 = DateTime::Set->from_datetimes( dates => [ $set2 ] ) 
236
            unless $set2->can( 'union' );
237
        $tmp->{set} = $set1->{set}->complement( $set2->{set} );
238
    }
239
    else {
240
        $tmp->{set} = $set1->{set}->complement;
241
    }
242

  
243
    # complement() can generate something more complex than a span.
244
    bless $tmp, 'DateTime::SpanSet';
245

  
246
    # # We have to check it's internal structure to find out.
247
    # if ( $#{ $tmp->{set}->{list} } != 0 ) {
248
    #    bless $tmp, 'Date::SpanSet';
249
    # }
250

  
251
    return $tmp;
... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.

Auch abrufbar als: Unified diff