Jump to content

Module:Mooc/IndexParser

From Wikiversity
 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

[edit source]

parseIndexOverview(indexPlain, rootPath)

[edit source]

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)

[edit source]

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

[edit source]

splitLines(text)

[edit source]

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)

[edit source]

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)

[edit source]

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)

[edit source]

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)

[edit source]

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)

[edit source]

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)

[edit source]

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)

[edit source]

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("Module: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;