Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

3.days.ago implementation in Perl6

Tags:

raku

I want to implement a time calculation like 3.days.ago and 2.months.from_now. Is is possible to extend method to Int, or operator overriding can do this?

1.day.ago      # equivalent to yesterday
1.day.from_now # equivalent to tomorrow
like image 969
Mako Avatar asked Mar 14 '17 03:03

Mako


3 Answers

To get exactly what you are asking for:

use MONKEY-TYPING;
augment class Int {

    my class Date::Offset {
        has Pair $.offset is required;

        method ago () {
            Date.today.earlier( |$!offset )
        }

        method from-now () {
            Date.today.later( |$!offset )
        }
    }

    method days () {
        Date::Offset.new( offset => days => self );
    }
    method months () {
        Date::Offset.new( offset => months => self );
    }
}

say 1.days.ago;      # 2017-03-13
say Date.today;      # 2017-03-14
say 1.days.from-now; # 2017-03-15

say 1.months.ago;    # 2017-02-14

Now that I've shown you how, please don't. You may end up affecting code that you didn't intend to, in a way that is very hard to troubleshoot.
(There are legitimate reasons to do something like that, but I don't think this is one of them)

If you want to mess with how basic operations happen, do it lexically.

{
    sub postfix:« .days.ago » ( Int:D $offset ) {
        Date.today.earlier( days => $offset )
    }

    sub postfix:« .days.from-now » ( Int:D $offset ) {
        Date.today.later( days => $offset )
    }

    sub postfix:« .months.ago » ( Int:D $offset ) {
        Date.today.earlier( months => $offset )
    }

    sub postfix:« .months.from-now » ( Int:D $offset ) {
        Date.today.later( months => $offset )
    }

    say 1.days.ago;      # 2017-03-13
    say Date.today;      # 2017-03-14
    say 1.days.from-now; # 2017-03-15

    say 1.months.ago;    # 2017-02-14

}

say 1.days.ago; # error
like image 109
Brad Gilbert Avatar answered Oct 20 '22 06:10

Brad Gilbert


The basic way to extend an existing class, is to augment it:

use MONKEY-TYPING;
augment class Int {
    method day() { "day" }
}
say 42.day

From there you can have the "day" method create an object that can handle the "ago" and "from_now" methods.

Mind you, it appears though you would need to think a bit about your API: in the first line, 1.day appears to refer to today, whereas in the second line only the "from_now" seems to have that functionality.

Please note that at the moment, subclasses don't know about superclasses being augmented: this is a known issue. The only way around that at the moment is to re-compose the subclasses you need after augmenting their superclass:

use MONKEY-TYPING;
augment class Cool {  # Int is a subclass of Cool
    method day() { "day" }
}
BEGIN Int.^compose; # make sure Int knows about ".day"
say 42.day
like image 44
Elizabeth Mattijsen Avatar answered Oct 20 '22 07:10

Elizabeth Mattijsen


It might be fun to use MONKEY-TYPING, but if you really just want to calculate dates, then please just use the built-in Date object:

put Date.today;                 # 2017-03-23
put Date.today.earlier(day=>3); # 2017-03-20
put Date.today.later(month=>3); # 2017-06-23

(I know about trying clever syntax, but am glad to have been talked out of it).

like image 40
Christopher Bottoms Avatar answered Oct 20 '22 07:10

Christopher Bottoms