restructured fahrplanparser.getRowContents and added some tests

This commit is contained in:
Johannes Loher 2017-01-11 14:42:04 +01:00
parent f7b67f6d09
commit 8c8d587c54
2 changed files with 84 additions and 17 deletions

View file

@ -1,4 +1,4 @@
import std.array: array, replace; import std.array : array, replace;
import std.datetime : Clock; import std.datetime : Clock;
import std.format : format; import std.format : format;
import std.getopt : defaultGetoptPrinter, getopt; import std.getopt : defaultGetoptPrinter, getopt;
@ -16,10 +16,12 @@ void main(string[] args)
string fileName; string fileName;
string busStop = "Universität Regensburg"; string busStop = "Universität Regensburg";
string substitutionFileName = "replacement.txt"; string substitutionFileName = "replacement.txt";
auto helpInformation = getopt(args, auto helpInformation = getopt(args,
"file|f", "The file that the data is written to.", &fileName, "file|f", "The file that the data is written to.", &fileName,
"stop|s", "The bus stop for which to fetch data.", &busStop, "stop|s", "The bus stop for which to fetch data.", &busStop,
"replacement-file|r", "The file that contais the direction name replacement info.", &substitutionFileName); "replacement-file|r", "The file that contais the direction name replacement info.", &substitutionFileName);
if (helpInformation.helpWanted) if (helpInformation.helpWanted)
{ {
defaultGetoptPrinter("Some information about the program.", helpInformation.options); defaultGetoptPrinter("Some information about the program.", helpInformation.options);
@ -43,7 +45,8 @@ void main(string[] args)
if (fileName !is null) if (fileName !is null)
{ {
auto outfile = File(fileName, "w"); auto outfile = File(fileName, "w");
scope(exit) outfile.close; scope (exit)
outfile.close;
outfile.writeln(output); outfile.writeln(output);
} }
else else

View file

@ -6,24 +6,37 @@ import std.conv : to;
import std.datetime : dur, TimeOfDay; import std.datetime : dur, TimeOfDay;
import std.regex : ctRegex, matchAll; import std.regex : ctRegex, matchAll;
import std.string : strip; import std.string : strip;
import std.typecons : tuple; import std.typecons : tuple, Tuple;
import kxml.xml : readDocument, XmlNode; import kxml.xml : readDocument, XmlNode;
import substitution; import substitution;
private:
enum ScheduleHeadings
{
date,
departure,
line,
direction,
platform
}
public: public:
auto parsedFahrplan(in string data) auto parsedFahrplan(in string data)
{ {
// dfmt off
return data.readDocument return data.readDocument
.parseXPath(`//table[@id="departureMonitor"]/tbody/tr`)[1 .. $] .parseXPath(`//table[@id="departureMonitor"]/tbody/tr`)[1 .. $]
.getRowContents .getRowContents
.filter!(row => !row.empty) .filter!(row => !row.empty)
.map!(a => ["departure" : a[0].parseTime[0].to!string[0 .. $ - 3], .map!(a => ["departure" : a[0].parseTime[0].to!string[0 .. $ - 3],
"delay" : a[0].parseTime[1].total!"minutes".to!string, "delay" : a[0].parseTime[1].total!"minutes".to!string,
"line" : a[1], "line" : a[1],
"direction" : a[2].substitute]); "direction" : a[2].substitute]);
// dfmt on
} }
private: private:
@ -54,7 +67,7 @@ auto parseTime(in string input) @safe
matches.front["minutes"].to!int); matches.front["minutes"].to!int);
auto timeDiff = actualTime - expectedTime; auto timeDiff = actualTime - expectedTime;
if(timeDiff < dur!"minutes"(0)) if (timeDiff < dur!"minutes"(0))
timeDiff = dur!"hours"(24) + timeDiff; timeDiff = dur!"hours"(24) + timeDiff;
return tuple(expectedTime, timeDiff); return tuple(expectedTime, timeDiff);
@ -65,6 +78,7 @@ auto parseTime(in string input) @safe
@safe unittest @safe unittest
{ {
import std.exception : assertThrown; import std.exception : assertThrown;
assertThrown(parseTime("")); assertThrown(parseTime(""));
assertThrown(parseTime("lkeqf")); assertThrown(parseTime("lkeqf"));
assertThrown(parseTime(":")); assertThrown(parseTime(":"));
@ -83,14 +97,64 @@ auto parseTime(in string input) @safe
assert("17:53 (planmäßig 17:51 Uhr)".parseTime == tuple(TimeOfDay(17, 51), dur!"minutes"(2))); assert("17:53 (planmäßig 17:51 Uhr)".parseTime == tuple(TimeOfDay(17, 51), dur!"minutes"(2)));
assert("00:00 23:59".parseTime == tuple(TimeOfDay(23,59), dur!"minutes"(1))); assert("00:00 23:59".parseTime == tuple(TimeOfDay(23, 59), dur!"minutes"(1)));
} }
auto getRowContents(XmlNode[] rows) auto getRowContents(XmlNode[] rows)
{ {
return rows.map!(row => row.parseXPath("//td")[1 .. $ - 1].map!((column) { return rows.map!(x => getRowContent(x));
auto link = column.parseXPath("//a"); }
if (!link.empty)
return link.front.getCData.replace("...", ""); auto getRowContent(XmlNode row)
return column.getCData;})); {
return row.parseXPath("//td")[ScheduleHeadings.departure .. ScheduleHeadings.direction + 1].map!(
cell => stripLinks(cell));
}
auto stripLinks(XmlNode cell)
{
auto links = cell.parseXPath("//a");
if (links.empty)
{
return cell.getCData;
}
else
{
return links.front.getCData.replace("...", "");
}
}
@system unittest
{
auto foo = new XmlNode("foo");
assert(foo.stripLinks == "");
auto link = new XmlNode("a");
link.setCData("test");
foo.addChild(link);
assert(foo.stripLinks == "test");
link.setCData("test2...");
assert(foo.stripLinks == "test2");
auto bar = new XmlNode("bar");
bar.setCData("test3");
assert(bar.stripLinks == "test3");
bar.addChild(link);
assert(bar.stripLinks == "test2");
auto baz = new XmlNode("baz");
auto subNode = new XmlNode("subNode");
baz.addChild(subNode);
assert(baz.stripLinks == "");
baz.addChild(link);
assert(baz.stripLinks == "test2");
baz.addCData("test4");
assert(baz.stripLinks == "test2");
baz.removeChild(link);
assert(baz.stripLinks == "test4");
} }