FunctionalPerl
view release on metacpan or search on metacpan
examples/hiring-without-whiteboards view on Meta::CPAN
}
}
*is_heading = is_heading_of(sub($s) {1});
*is_AlsoSee = is_heading_of(sub($s) { $s =~ /also *see/i });
sub is_hr($s) {
$s =~ /^---\s*$/
}
sub is_empty($s) {
$s =~ /^\s*$/
}
sub parse_country($str) {
$USfromCode{$str} // NonUSCountry($str)
}
sub parse_location($str) {
if ($str =~ /^remote$/i) {
$Remote
} else {
my @s = split /\s*,\s*/, $str;
if (@s == 1) {
parse_country($s[0])
} elsif (@s == 2) {
my ($city, $country) = @s;
City($city, parse_country($country))
} elsif (@s == 3) {
my ($city, $state, $country) = @s;
if ($country eq "USA") {
my $s = parse_country($state);
if ($s->is_USA) {
City($city, $s)
} else {
die "presumed state '$state' is not a state in the USA";
}
} else {
die
"don't know how to deal with presumed state '$state' in country '$country': don't know that country";
}
} else {
die "more than two commas in: '$str'"
}
}
}
sub parse_line($line) {
my $s = $line;
$s =~ s/^-\s*// or die "line is not an item";
my ($name, $url, $rest) = $s =~ /^\[(.*?)\] *\((.*?)\)\s*(.*)$/
or die "missing link formatting in: '$s'";
my @p = split /\s*\|\s*/, $rest;
@p == 2 or @p == 3 or die "rest does not contain 2 or 3 parts: '$rest'";
my (undef, $locations, $maybe_process) = @p;
Company(
$name, $url,
# /, ; and & used inconsistently:
list(map { parse_location $_ } split m%\s*[/;&]\s*%, $locations),
$maybe_process
)
}
TEST {
parse_line
"- [Accredible](https://www.accredible.com/careers) | Cambridge, UK / San Francisco, CA / Remote | Take home project, then a pair-programming and discussion onsite / Skype round."
}
Company(
"Accredible",
"https://www.accredible.com/careers",
list(
City('Cambridge', NonUSCountry('UK')),
City('San Francisco', USPSCode('California', 'CA', 1)),
Remote()
),
"Take home project, then a pair-programming and discussion onsite / Skype round."
);
# XX move?; name?
sub FP::Abstract::Sequence::drop_over ($l, $pred) {
$l->drop_while(complement $pred)->drop_while($pred)
}
sub datalines () {
xfile_lines_chomp("$file", "UTF-8")->drop_over(\&is_hr)
->take_while(complement \&is_AlsoSee)->filter(complement \&is_empty)
}
sub companies () {
# Simply ignore the grouping headings.
datalines->filter(complement \&is_heading)->map (\&parse_line)
}
sub parse_heading($str) {
my ($from, $to) = $str =~ /^#+\s+(\w)\s*-\s*(\w|\\?#)\s*$/
or die "not a heading: '$str'";
$to =~ s/^\\//;
InclusiveRange($from, $to)
}
sub grouped_companies_from($datalines) {
# Capture the groupings as well, as the original file is badly
# grouping them, so to keep a diff minimal we first have to
# maintain the wrong grouping before re-grouping automatically.
if ($datalines->is_null) {
null
} else {
my ($heading, $r) = $datalines->first_and_rest;
if (is_heading($heading)) {
my ($groupitems, $r)
= $r->take_while_and_rest(complement \&is_heading);
cons(
Group(parse_heading($heading), $groupitems->map(\&parse_line)),
grouped_companies_from $r)
} else {
die "expecting a header, got: '$heading'";
}
( run in 0.977 second using v1.01-cache-2.11-cpan-71847e10f99 )