R/rqudocusectioncountrefclass.R

###
###
###
###   Purpose:   Reference class for section counting
###   started:   2016/02/16 (pvr)
###
### ################################################### ###


#' Reference Class for section counts
#'
#' @description
#' A reference object of reference class \code{SectionCount}
#' represents the numbers in front of a section title.
#'
#' @details
#' The section title number  counts the numbers of different
#' section at any given level up and until a given section
#' title. In a markdown (md) document section levels
#' of titles are denoted by hash (#) signs. Based on the
#' number of hash signs of a given section title, the level of
#' the corresponding section title can be inferred. The more
#' hash signs the lower the level of the section title. Hence
#' one hash means top-level section title, two hashes stand
#' for subsections, three hashes denote subsubsectiones, etc.
#' For a given section title the level determines the corresponding
#' number of the section title. For a top-level section there
#' is just one number, for a subsection there are two numbers
#' separated by a dot (.) and for subsubsections there are
#' three numbers all separated by dots. Each of the numbers
#' that are associated with a given section title count the
#' number of sections for a specific level up
#' and until that given section title.
#'
#' @field vSectionCount   vector with section counts
sectionCount <- setRefClass(Class   = "SectionCount",
                            fields  = list(vSectionCount       = "numeric",
                                           nSectionCount       = "numeric",
                                           nSubSectionCount    = "numeric",
                                           nSubSubsectionCount = "numeric",
                                           sHash               = "character",
                                           sCountSep           = "character",
                                           nNrExtraHash        = "numeric"),
                            methods = list(
                              .lGetDefaults = function(){
                                'default values for given reference object'
                                return(list(nNrSectionLevels = 6L))
                              },
                              initialize = function(){
                                'Initialize count fields and set default for count separator'
                                lRefObjDefaults     <- .self$.lGetDefaults()
                                vSectionCount       <<- vector(mode = "numeric",
                                                               length = lRefObjDefaults$nNrSectionLevels)
                                nSectionCount       <<- 0
                                nSubSectionCount    <<- 0
                                nSubSubsectionCount <<- 0
                                sCountSep           <<- "."
                                nNrExtraHash        <<- 0
                              },
                              setHash = function(psHash){
                                sHash <<- psHash
                              },
                              setNrExtraHash = function(pnNrExtraHash){
                                nNrExtraHash <<- pnNrExtraHash
                              },
                              incrSectionCounts = function(){
                                'Increment section counts based on number of hash signs'
                                # count the number of hash signs in sHash
                                nNrHash <- nchar(sHash)
                                # subtract any number of extra hashes
                                if (nNrExtraHash < nNrHash)
                                  nNrHash <- nNrHash - nNrExtraHash
                                # increment the section count at the appropriate level
                                nNrMaxSectLevel <- length(vSectionCount)
                                if (nNrHash > nNrMaxSectLevel)
                                  stop(" * Current title seams to have ", nNrHash,
                                       " levels. The max. number of levels is: ",
                                       nNrMaxSectLevel)
                                vSectionCount[nNrHash] <<- vSectionCount[nNrHash] + 1
                                # set all counts of lower levels to 0
                                if (nNrHash < nNrMaxSectLevel)
                                  vSectionCount[(nNrHash+1):nNrMaxSectLevel] <<- 0
                              },
                              sGetSectionNumber = function(){
                                'Return section number as string, as soon as a count is zero
                                  we stop pasting together. This assumes counts are 1-based.'
                                sSectionNumberResult <- NULL
                                if (vSectionCount[1] > 0)
                                  sSectionNumberResult <- as.character(vSectionCount[1])
                                ### # loop over remaining vSectionCount
                                for (nSecCountIdx in 2:length(vSectionCount)){
                                  if (vSectionCount[nSecCountIdx] == 0)
                                    break
                                  sSectionNumberResult <- paste(sSectionNumberResult,
                                                                as.character(vSectionCount[nSecCountIdx]),
                                                                sep = sCountSep)
                                }
                                return(sSectionNumberResult)
                              }
                            ))


#' Reference class for automatically enumerating section titles
#'
#' @description
#' The level of a Markdown section headers is indicated using
#' hashes in front of the title. YAML frontmatter allows for
#' to specify section header numbering, but it is not clear
#' how to mix headers with and without numbers in the same
#' document. The \code{SectionEnumerator} reference class allows
#' us to specify section header numbers only for certain titles.
#'
#' @details
#' The main method of a SectionEnumerator reference object
#' is \code{displayNumSection}. This takes as input a string
#' of an unnumbered section, parses that string and computes
#' the section number based on the number of hashes. For some
#' reason, the option \code{number_sections = FALSE} does not
#' work for top level sections, but it only works for subsections.
#' As a work-around, all sections are moved down one level to subsections
#' by ignoring a given number of \code{nNrExtraHash} hash signs.
#' Hence a subsection will be numbered as a section and a subsubsection
#' will be numbered as a subsection etc.
#'
#' @field sUnNumSection       original ununmbered section string
#' @field rcSectionCount      reference object representing section count
#' @field sHash               hashes of caption
#' @field sRemCaption         remaining caption after removing hashes
#' @field sNumCaptionResult   resulting caption string with number
#' @field sSectionSplit       split character between number and title
#' @field nNrExtraHash        number of extra hashes not used for section counts
#' @export SectionEnumerator
#' @exportClass SectionEnumerator
SectionEnumerator <- setRefClass(Class   = "SectionEnumerator",
                                 fields  = list(sUnNumSection     = "character",
                                                rcSectionCount    = "SectionCount",
                                                sHash             = "character",
                                                sRemCaption       = "character",
                                                sNumCaptionResult = "character",
                                                sSectionSplit     = "character",
                                                nNrExtraHash      = "numeric"
                                 ),
                                 methods = list(
                                   initialize = function(){
                                     'Initalisation of object fields'
                                     sUnNumSection     <<- ""
                                     sHash             <<- ""
                                     sRemCaption       <<- ""
                                     sNumCaptionResult <<- ""
                                     sSectionSplit     <<- " "
                                     nNrExtraHash      <<- 0
                                     rcSectionCount    <<- sectionCount$new()
                                   },
                                   setUnNumSection = function(psUnNumSection){
                                     'Setter for unnumbered section string'
                                     sUnNumSection <<- psUnNumSection
                                   },
                                   setNrExtraHash = function(pnNrExtraHash){
                                     nNrExtraHash <<- pnNrExtraHash
                                   },
                                   parseUnNumSection = function(){
                                     'Parse the unnumbered section string and assign the object fields'
                                     vecUnNumCaption <- unlist(strsplit(sUnNumSection,sSectionSplit))
                                     sHash <<- vecUnNumCaption[1]
                                     sRemCaption <<- paste0(vecUnNumCaption[2:length(vecUnNumCaption)],
                                                            collapse = " ")
                                     rcSectionCount$setHash(psHash = sHash)
                                     rcSectionCount$setNrExtraHash(pnNrExtraHash = nNrExtraHash)
                                     rcSectionCount$incrSectionCounts()
                                     sNumCaptionResult <<- paste(sHash,
                                                                 rcSectionCount$sGetSectionNumber(),
                                                                 sRemCaption)

                                   },
                                   displayNumSection = function(psUnNumSection = NULL, pnNrExtraHash = NULL){
                                     'Parsing of unnumbered section string and display the string including the section number'
                                     if (!is.null(pnNrExtraHash))
                                       nNrExtraHash <<- pnNrExtraHash
                                     if (!is.null(psUnNumSection))
                                       sUnNumSection <<- psUnNumSection
                                     .self$parseUnNumSection()
                                     cat(sNumCaptionResult, "\n")
                                   }
                                 ))
pvrqualitasag/rqudocuhelper documentation built on May 26, 2019, 11:34 a.m.