Lösa tankar

Detta är lite ostrukturerat. Inte alldeles genomtänkt kanske … men kanske bättre än inget :-)

Låt användaren specificera sina reservnummer

Eftersom reservnummer kan se ut nästan hur som helst så blir det förstås ganska ohanterligt att göra ngt generellt. Men … kanske är det så att enskilda användare vet att man brukar jobba med data där ev reservnummer finns och i så fall vet man kanske också ungefär hur de brukar se ut.

I så fall kanske det hade varit ett alternativ att användaren själv får ange en vilkorssats för att identifiera sina reservnummer, t ex i mitt fall

is.reservnummer <- function(x){
    notNA <- function(x) !is.na(x)
    suppressWarnings(
        substr(x,1,8) %>% as.Date(format = "%Y%m%d") %>% notNA()  & # inleds med datum 
        substr(x, 9, 11) %>% as.numeric() %>% notNA() &
        substr(x, 12, 12) %in% c("A", "X", "T")
    )
}

Jobbar jag ofta med samma typ av data (vilket vi ofta gör) så kan denna funktion skapas i .Rprofile och hanteras som en global option, Pss som t ex:

getOption("error")
## NULL

Men i själva paketet kan också finnas en icke exporterad funktion (blir kanske snurrigt om de har samma namn men jag tänker att det är olika namespace etc; funktionen nedan i paketet, men den ovan i options och/eller en i workspace). Just denna funktion (om skriptet nedan körs direkt i konsolen) ger error eftersom den då får rekursiva anrop till sig själv (jag tänker att det inte sker om den ligger oexporterad i paketet som hjälpfunktion).

is.reservnummer <- function(pin){
    fun <- 
        if (exists("is.reservnummer", .GlobalEnv)) {
            match.fun("is.reservnummer")
        } else if (!is.null(getOption("is.reservnummer"))){
            getOption("is.reservnummer")    
        } else{
            function(pin) logical(length(pin)) # finns ingen specifikation av reservnummerformat så ges FALSE
        }
    fun(pin)
}

… alltså att man kan ha en is.reservnummer i sitt Globala workspace och i så fall anropas den (om man t ex vill skriva över en global option-funktion för ett enskilt projekt eller inte har specat ngn funktion där). Men saknas funktion i workspace så hämtas funktionen istället från options. Finns inte heller detta så är det användarens sätt att säga att hen inte vill jobba med reservnummer (vilket bör gälla åtminstone alla som inte jobbar med sjukvårdsdata i större skala). Då ges bara FALSE.

Skapa pin

T ex format_pin skulle då t ex kunna likna typ:

pin_format <- function (pin){
    
    ...
    
    ## Testa om pin är korrekt nummer
    pin %>%
        basic_pin_test_format_och_textlängd(.) &
        ( test_om_personnummer_samordningsnummer(.) | is.reservnummer(.) )
    ...
}

Anropa funktioner på pin “kontaminerad” med reservnummer

Nu har man i ngn mening angett att även reservnumren (av specificerat format) är att betrakta som pin … men sen är förstås problemet att alla metoder ändå inte bör tillämpas på de element i pin-vektorn där så är olämpligt.

En lösning är då kanske:

pin_birthdate <- function(pin, reservnummer = FALSE){
    ...
    if (!reservnummer) pin[is.reservnummer(pin)] <- NA
    ...
}

… alltså, i normalfallet hanteras funktionen precis som vanligt och då exkluderas reservnumren. Men om man själv vet att just de reservnummer man själv arbetar med har korrekta datum, då väljer man att även inkludera reservnumren i beräkningarna. Just med min version av is.reservnummer ovan skulle jag då köra:

pin_birthdate(pin, TRUE)

… men däremot …

pin_sex(pin)
pin_birthplace(pin)

… eftersom mina reservnummer har födelsedatum men inte födelseort och kön.

Kombinerat med S3

Man kan ju försöka undvika för mkt redundant kod, t ex om alla funktion ändå kompletteras med klasskontroll så kan man ju anropa en generell hjälpfunktion där detta bakas.

initial_pin_check <- function (pin, reservnummer = FALSE){
    pin <- if (is(pin, "pin")) pin else as.pin(pin)
    if (!reservnummer) pin[is.reservnummer(pin)] <- NA
    pin
}
pin_birthdate <- function(pin, ...){
    ...
    pin <- initial_pin_check(pin, ...)
    ...
}