H. S. Teoh:

OK, here's a draft of the article:

        http://wiki.dlang.org/User:Quickfur/Component_programming_with_ranges


Most of the code below is not tested. So my suggestions may contain bugs or mistakes.


A bit improved chunkBy could go in Phobos.

---------------

For our purposes, though, we can't just do this in a loop, because it has to interface with the other components, which do not have a matching structure to a loop over dates.<

It's just because D doesn't yet have a yield designed like C#. "yield" for coroutines is a very nice kind of glue.

---------------

auto datesInYear(int year) {
    return Date(year, 1, 1)
        .recurrence!((a,n) => a[n-1] + dur!"days"(1))
        .until!(a => a.year > year);
}


===>


auto datesInYear(in uint year) pure /*nothrow*/
in {
    assert(year > 1900);
} body {
    return Date(year, 1, 1)
           .recurrence!((a, n) => a[n - 1] + dur!"days"(1))
           .until!(d => d.year > year);
}


I suggest to align the dots vertically like that. And generally _all_ variables/arguments that don't need to mutate should be const or immutable (or enum), unless holes in Phobos or in the type system or other factors prevent you to do it.

---------------

return chunkBy!"a.month()"(dates);

===>

return dates.chunkBy!q{ a.month };

---------------

byWeek() is not so simple. Most of its code is boilerplate code. Perhaps using a "yield" it becomes simpler.

---------------

string spaces(size_t n) {
    return repeat(' ').take(n).array.to!string;
}

===>

string spaces(in size_t n) pure nothrow {
    return std.array.replicate(" ", n);
}


Currently in programs that import both std.range and std.array you have to qualify the module for replicate.

In Python this is just:

' ' * n

---------------

auto buf = appender!string();

Perhaps this suffices:

appender!string buf;

---------------

string[] days = map!((Date d) => " %2d".format(d.day))(r.front)
                .array;

(not tested) ==>

const days = r.front.map!(d => " %2d".format(d.day)).array;

Or:

const string[] days = r
                      .front
                      .map!(d => " %2d".format(d.day))
                      .array;

---------------

If you put the days inside buf, do you really need to turn days into an array with array()?

string[] days = map!((Date d) => " %2d".format(d.day))(r.front)
                .array;
assert(days.length <= 7 - startDay);
days.copy(buf);


Isn't this enough?

auto days = r.front.map!(d => " %2d".format(d.day));

---------------

If not already present this array should go in std.datetime or core.time:

    static immutable string[] monthNames = [
        "January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
    ];

---------------

return to!string(spaces(before) ~ name ~ spaces(after));

==> (untested)

return text(before.spaces, name, after.spaces);

Or maybe even just (untested):

return before.spaces ~ name ~ after.spaces;

---------------

auto formatMonth(Range)(Range monthDays)
    if (isInputRange!Range && is(ElementType!Range == Date))
{
    assert(!monthDays.empty);
    assert(monthDays.front.day == 1);

    return chain(
        [ monthTitle(monthDays.front.month) ],
        monthDays.byWeek().formatWeek());
}

===> (untested)

auto formatMonth(R)(R monthDays)
    if (isInputRange!R && is(ElementType!R == Date))
in {
    assert(!monthDays.empty);
    assert(monthDays.front.day == 1);
} body {
    return [monthDays.front.month.monthTitle]
           .chain(monthDays.byWeek.formatWeek);
}


Generally I suggest to use pre- and post conditions.

---------------

return months.map!((month) => month.formatMonth());

===> (untested)

return months.map!formatMonth;

---------------

.map!((r) =>

===>

.map!(r =>

---------------

int year = to!int(args[1]);

===>

int year = args[1].to!int;

---------------

On Rosettacode there is a shorter calendar:
http://rosettacode.org/wiki/Calendar#D

If you want we can put, as second D entry, your calendar code (without unittests) in that page too.

Bye,
bearophile

Reply via email to