[LON-CAPA-dev] Navmaps usage note
Jeremy Bowers
lon-capa-dev@mail.lon-capa.org
Wed, 16 Jul 2003 15:52:59 -0500
Apache::lonnavmaps::navmaps has been used by most people like this:
-------
my $navmap = [construct navmap];
my $it = $navmap->getIterator(...);
my $depth = 1;
$it->next(); #discard MAP_BEGIN
my $curRes = $it->next();
while ($depth > 0) {
if ($curRes == $it->BEGIN_MAP()) { $depth++; }
if ($curRes == $it->END_MAP()) { $depth--; }
[your code here]
} continue {
$curRes = $it->next();
}
-------
However, I recommend that unless you intend to actually *do* something
with BEGIN_BRANCH or END_BRANCH tokens, or really intend to do something
special when BEGIN_MAP or END_MAP goes by, that you use something like
this instead:
-------
my $navmap = [construct navmap];
my $mapOfInterest = [get a Resource object that is some map]
my $filter = sub { shift->is_problem() };
my @resources = $navmap->retrieveResource($mapOfInterest, $filter, 1);
for my $res (@resources) {
[your logic here]
}
-------
It's safer because there's less bookkeeping you have to do yourself, and
it's less typing.
retrieveResources returns an array populated with
Apache::lonnavmaps::Resource objects from the course.
The first parameter is which map you want to get the resources from,
either as a URL of the map, or as a Resource object. It defaults to the
top-level map of the course.
The second is a filter function which takes in the current Resource
object, and should return true if you want it in the list, or false if
you don't want it.
The third is whether the function should recurse down any maps it may
encounter in the given map.
So, for example
my @resources = $navmap->retrieveResources();
gets all the resources from the course, except the top-level map itself
which is not included (but is easily added by hand to the array).
my @resources = $navmap->retrieveResources(undef, sub {
shift->is_problem() }, 1);
will return a list of all problems in the course.
More documentation in the lonnavmaps.pm perldoc.
If you *do* care about the structure, particularly branching, you can't
do this, because it throws branching information away. If you care about
where maps begin and end, you can do this (which is now used in
grades.pm in getSymbMap):
------
my @sequences = $navmap->retrieveResources(undef, sub { shift->is_map();
}, 1);
for my $sequence ($navmap->getById('0.0'), @sequences) {
my @resources = $navmap->retrieveResources($sequence);
[logic here]
}
------
so you'll always know what map you're in. Depends on what you're doing.
Just a note because I think this is a lot easier in the %75 or so of the
cases where it turns out you don't really care about a lot of the
nitty-gritty details of how maps work. I will be adding something like
this to the navmaps perldoc. Probably won't affect anyone before 1.0
since we don't want to break working code without good reason. (I
actually feel safer with getSymbMap the way it is now, or I wouldn't
have changed it for 1.0; some of what it was doing made me a little
nervous.)
I'd also appreciate it if people using the nav maps do this in the
future if they don't really need full course structure information,
because for 1.1 I hope to fix the iterator code to work correctly (you
should *not* need to track $depth by hand, and it's the #1 source of
bugs during development right now for people using navmaps; I for one
keep writing "$depth++" for both of the 'ifs'), and the fewer people
using it directly and the more people using retrieveResources, the less
punishment I'll get having to re-write the client code when I make that
change.