Modulo:Mooc/IndexParser

 This module is part of the MOOC interface.

The index parser is a central script of the MOOC module. It parses the MOOC index and creates a Lua object holding the single MOOC items along with their meta data stored in the index.

Instance functions modifica

parseIndexOverview(indexPlain, rootPath) modifica

Parses the MOOC index and extracts the MOOC root item in order to display an overview page.

Parameters:

  1. String indexPlain: MOOC index content
  2. String rootPath: title of the MOOC index page

Returns:

  • Table table t with
    • Mooc/Data/Item t.item: MOOC root item

parseIndex(indexPlain, itemPath, rootPath) modifica

Parses the MOOC index and extracts the MOOC item you are searching for (aka. target item).

Parameters:

  1. String indexPlain: MOOC index content
  2. String itemPath: path of the target item
  3. String rootPath: title of the MOOC index page

Returns:

  • Table table t with
    • Mooc/Data/Item t.navigation: MOOC root item
    • Mooc/Data/Item t.item: target item itself (may be nil if the item was not found)
    • Mooc/Data/Item t.parent: direct parent of the target item
    • Mooc/Data/Item t.previous: item preceding the target item (may be nil if first item in its context)
    • Mooc/Data/Item t.next: item following the target item (may be nil if last item in its context)

Local functions modifica

splitLines(text) modifica

Splits a text into its single lines.

Parameters:

  1. String stringValue: String that will be splitted up into single lines

Returns:

  • Table<String> table containing the single lines

splitPath(itemPath) modifica

Splits an item path into its single parts.

Parameters:

  1. String itemPath: item path with its single parts separated by /

Returns:

  1. String item name (last part of the path)
  2. Table<String>table containing the single parts

getLevel(itemHeaderLine) modifica

Calculates the level of an item according to the number of heading symbols = in it's header line.

 Q: This is a copy of Mooc/Data/Item.getLevel, why don't we use it?

Parameters:

  1. String itemHeaderLine: header line of the item

Returns:

  • int item's level if the line is an item header
  • int zero otherwise

isItem(header, itemName, itemType) modifica

Checks if a header represents a certain item you search for.

Parameters:

  1. Mooc/Data/Item.Header header: header of an item
  2. String itemName: name of the item searched for
  3. String itemType: type of the item searched for

Returns:

  • true if the header is the item searched for
  • false otherwise

loadParam(textLines, iParamStart) modifica

Loads a parameter (aka. meta data entry) from the index.

Parameters:

  1. Table<String> textLines: MOOC index lines
  2. int iParamStart: index of the (first) line the parameter declaration occupies

Returns:

  • Table table t with
    • String t.name: parameter key
    • String t.value: parameter value
    • int t.iEnd: last line the parameter declaration occupies
  • nil if the line did not contain a parameter (or is malformed)

loadParams(textLines, iItemStart) modifica

Loads all parameters of an item.

Parameters:

  1. Table<String> textLines: MOOC index lines
  2. int iItemStart: index of the (first) line the item occupies

Returns:

  1. Table<String, String> table containing the parameter values loaded from the index, accessible using the parameter key
  2. int index of the last line the item occupies

extractItem(textLines, iItemStart, parent, maxLevel, section) modifica

Extracts a MOOC item from the index including its meta data and all children up to the maximum level defined.

Parameters:

  1. Table<String> textLines: MOOC index lines
  2. int iItemStart: index of the (first) line the item occupies
  3. Mooc/Data/Item parent: parental MOOC item
  4. int maxLevel: maximum item level that will be extracted, children at deeper level will be ignored
  5. int section: section number of the previous item

Returns:

  1. Mooc/Data/Item item object extracted from the index
  2. int index of the last line the item occupies
  3. int highest section number in use

extractIndex(baseItem, searchPath, searchLevel) modifica

Extract the item objects related to a certain MOOC item you are searching for (aka. target item).

Parameters:

  1. Mooc/Data/Item baseItem: any parental item of the target item
  2. String searchPath: path of the target item
  3. int searchLevel: current item level searching at

Returns:

  • Table table t with
    • Mooc/Data/Item t.item: target item itself (may be nil if the item was not found)
    • Mooc/Data/Item t.parent: direct parent of the target item
    • Mooc/Data/Item t.previous: item preceding the target item (may be nil if first item in its context)
    • Mooc/Data/Item t.next: item following the target item (may be nil if last item in its context)

local Item = require("Modulo:Mooc/Data/Item");

local moocIndex = {}

local function splitLines(stringValue)
  local lines = {}
  for s in stringValue:gmatch("[^\r?\n]+") do
    table.insert(lines, s);
  end
  return lines;
end

local function splitPath(path)
  local name;
  local pathParts = {}
  for s in path:gmatch("[^/]+") do
    table.insert(pathParts, s);
  end
  
  if #pathParts > 1 then
    -- name is last path part
    name = pathParts[#pathParts];
  else
    -- name is full path for root item
    name = path;
  end
  
  return name, pathParts;
end

local function getLevel(itemHeader)
  local leading = string.len(string.match(itemHeader, "^=*"));
  local trailing = string.len(string.match(itemHeader, "=*$"));
  return math.min(leading, trailing);
end

local function isItem(header, itemName, itemType)
  if header:getName() == itemName then
    if itemType == nil or itemType:isType(header:getTypeIdentifier()) then
      return true;
    end
  end
  return false;
end

local function loadParam(textLines, iParamStart)
  local line = textLines[iParamStart];  
  if line ~= nil and string.sub(line, 1, 1) == "*" then
    local iSeparator = string.find(line, "=", 2, true);
    if iSeparator ~= nil then
      local paramLines = nil;
      local paramName = string.sub(line, 2, iSeparator - 1);
      
      local i = iParamStart;
      local paramValue = string.sub(line, iSeparator + 1);
      local numLines = #textLines;
      repeat
        if i > iParamStart then
          if paramLines == nil then
            paramLines = {}
            if string.len(paramValue) > 0 then
              table.insert(paramLines, paramValue);
            end
          end
          table.insert(paramLines, line);
        end
        i = i + 1;
        line = textLines[i];
      until i > numLines or string.sub(line, 1, 1) == "*" or getLevel(line) > 0;
      
      if paramLines ~= nil then
        paramValue = table.concat(paramLines, '\n');
      end
      
      return {
        name = paramName,
        value = paramValue,
        iEnd = i
      }
    end
  else
    return nil;
  end
end

local function loadParams(textLines, iItemStart)
  local params = {}
  local iParamStart = iItemStart + 1;
  local numLines = #textLines;
  
  local param;
  repeat
    param = loadParam(textLines, iParamStart);
    if param ~= nil then
      params[param.name] = param.value;
      iParamStart = param.iEnd;
    end
  until param == nil or iParamStart > numLines;
  
  return params, iParamStart;
end

local function extractItem(textLines, iItemStart, parent, maxLevel, section)
  local section = section + 1;
  local header = Item.parseHeader(textLines[iItemStart], parent);
  header:setSection(section);
  local item = Item(header);
  local params;
  
  local nextMaxLevel = 0;
  if maxLevel > 0 then
    nextMaxLevel = math.max(1, maxLevel - 1);
  end
  
  -- load parameters
  local i;
  params, i = loadParams(textLines, iItemStart);
  item:setParams(params);
  
  local itemLevel = item:getLevel();
  local child;
  local numLines = #textLines;
  if maxLevel == 0 or maxLevel > 1 then
    -- extract direct children
    while i <= numLines do
      local level = getLevel(textLines[i]);
      if level > itemLevel then
        -- add child
        child, i, section = extractItem(textLines, i, item, nextMaxLevel, section);
        item:addChild(child);
      else
        -- no child
        break;
      end
    end
  else
    -- skip all children
    while i <= numLines do
      local level = getLevel(textLines[i]);
      if level > 0 then
        if level <= itemLevel then
          break;
        end
      	section = section + 1;
      end
      i = i + 1;
    end
  end
  
  return item, i, section;
end

local function extractIndex(baseItem, searchPath, searchLevel)
  local targetLevel = #searchPath;
  local index = nil;
  
  if searchLevel == targetLevel then
    -- current item is target item
    local index = {}
    index["item"] = baseItem;
    return index;
  end
  
  if baseItem:getChildren() ~= nil then
    -- search at next level
    local previous = nil;
    for _,child in ipairs(baseItem:getChildren()) do
      if isItem(child, searchPath[searchLevel + 1]) then
        -- child is part of search path
        index = extractIndex(child, searchPath, searchLevel + 1);
      elseif searchLevel == targetLevel - 1 then
        -- child may be next or previous item
        if index == nil then
          -- child may be previous item
          previous = child;
        else
          -- child is next item
          index["next"] = child;
          break;
        end
      end
    end
    
    if searchLevel == targetLevel - 1 and index ~= nil and searchLevel > 0 then
      -- current item is parental item
      index["parent"] = baseItem;
      index["previous"] = previous;
    end
  end
  
  return index;
end

function moocIndex.parseIndexOverview(indexPlain, rootPath)
	local textLines = splitLines(indexPlain);
	local rootItem = Item(Item.Header("MOOC", 'mooc', nil, rootPath, 0));
	rootItem:setParams({});
		
	-- extract all index item down to target level
	local i = 1;
	local section = 0;
	local item;
	local numLines = #textLines;
	while i <= numLines do
  		local level = getLevel(textLines[i]);
		if level > 0 then
			item, i, section = extractItem(textLines, i, rootItem, 2, section);
			rootItem:addChild(item);
		else
			-- skip initial lines
			i = i + 1;
		end
	end

	local index = {}
	index['item'] = rootItem;
	
	return index;
end

function moocIndex.parseIndex(indexPlain, itemPath, rootPath)
  local textLines = splitLines(indexPlain);
  local itemName, itemPath = splitPath(itemPath);
  local targetLevel = #itemPath;
  local rootItem = Item(Item.Header("MOOC", 'mooc', nil, rootPath, 0));
  
  -- extract all index item down to target level
  local i = 1;
  local section = 0;
  local item;
  local numLines = #textLines;
  while i <= numLines do
    local level = getLevel(textLines[i]);
    if level > 0 then
      item, i, section = extractItem(textLines, i, rootItem, targetLevel + 1, section);
      rootItem:addChild(item);
    else
      -- skip initial lines
      i = i + 1;
    end
  end
  
  -- find target item
  local index = extractIndex(rootItem, itemPath, 0);
  if index ~= nil then
  	index["navigation"] = rootItem;
  end

  return index;
end

return moocIndex;