[med-svn] [r-cran-registry] 01/02: Imported Upstream version 0.3-1

Alba Crespi albac-guest at moszumanska.debian.org
Sun Apr 10 21:21:19 UTC 2016


This is an automated email from the git hooks/post-receive script.

albac-guest pushed a commit to branch master
in repository r-cran-registry.

commit 485baacccadf9333d6ef768180f59192ae3d8b13
Author: Alba Crespi <crespialba+debian at gmail.com>
Date:   Sun Apr 10 21:42:22 2016 +0100

    Imported Upstream version 0.3-1
---
 DESCRIPTION            |   14 +
 MD5                    |   21 +
 NAMESPACE              |   13 +
 R/accessors.R          |   22 +
 R/converters.R         |   25 +
 R/matchfuns.R          |   20 +
 R/printsummary.R       |   32 ++
 R/registry.R           |  501 +++++++++++++++++
 R/utils.R              |    2 +
 build/vignette.rds     |  Bin 0 -> 193 bytes
 demo/00Index           |    2 +
 demo/registry.R        |   67 +++
 inst/doc/registry.R    |  207 +++++++
 inst/doc/registry.Rnw  |  313 +++++++++++
 inst/doc/registry.pdf  |  Bin 0 -> 152573 bytes
 man/matchfuns.Rd       |   65 +++
 man/registry.Rd        |   53 ++
 man/regobj.Rd          |  146 +++++
 tests/registry.R       |    2 +
 vignettes/abbrvnat.bst | 1432 ++++++++++++++++++++++++++++++++++++++++++++++++
 vignettes/registry.Rnw |  313 +++++++++++
 vignettes/registry.bib |   33 ++
 22 files changed, 3283 insertions(+)

diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100755
index 0000000..2f3e5a3
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,14 @@
+Package: registry
+Type: Package
+Title: Infrastructure for R Package Registries
+Version: 0.3
+Author: David Meyer
+Maintainer: David Meyer <David.Meyer at R-project.org>
+Description: Provides a generic infrastructure for creating and using registries.
+Depends: R (>= 2.6.0)
+Imports: utils
+License: GPL-2
+NeedsCompilation: no
+Packaged: 2015-07-07 16:27:02 UTC; david
+Repository: CRAN
+Date/Publication: 2015-07-08 17:11:04
diff --git a/MD5 b/MD5
new file mode 100644
index 0000000..fd237b7
--- /dev/null
+++ b/MD5
@@ -0,0 +1,21 @@
+2615feeba9ddba58a04e6678f0476ae5 *DESCRIPTION
+5d602abc58c4875294dc11f72158774d *NAMESPACE
+b3074b376232f3c1fd80571ba446996f *R/accessors.R
+bb342556b9b96cfa5283fce894700b0d *R/converters.R
+bc616cbb85bd434ba34d927e64f630be *R/matchfuns.R
+880b67c5a7ad7d534dbafe347219223b *R/printsummary.R
+8b1af8764497f1347e5ff3754692652e *R/registry.R
+21bb06f605604d73919a8d3cb816f44c *R/utils.R
+d906ffbab1a29b3f48d69c99bb6fed45 *build/vignette.rds
+8eb52e1e2fe74ae94a8aa3113511b94f *demo/00Index
+aef06553ca79a1d87d69ae93ea9ffcd8 *demo/registry.R
+7d44eb1b5a93ff5de790427a3b8c2301 *inst/doc/registry.R
+03889df16f04b2e9156693baf5e9e694 *inst/doc/registry.Rnw
+f15f4b44a36b80e44016450e74d2ae81 *inst/doc/registry.pdf
+d75af01cf06a4c33ade70aea44df055d *man/matchfuns.Rd
+3ba25d05aadad18ae969da1ed416f2b6 *man/registry.Rd
+5648e6108e71120477b77b0150624873 *man/regobj.Rd
+2c77c272d1d8f1c5bb781bb9ec6edf44 *tests/registry.R
+ee1b5ad6f2633c9d108cc96775448248 *vignettes/abbrvnat.bst
+03889df16f04b2e9156693baf5e9e694 *vignettes/registry.Rnw
+a2cad786f79804c8744a9e008c1651c0 *vignettes/registry.bib
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100755
index 0000000..b32ead7
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,13 @@
+importFrom("utils", "formatUL")
+
+export("registry")
+exportPattern("match_.*")
+
+S3method("[", "registry")
+S3method("[[", "registry")
+S3method("length", "registry")
+S3method("as.data.frame", "registry")
+S3method("print", "registry")
+S3method("summary", "registry")
+S3method("print", "registry_field")
+S3method("print", "registry_entry")
diff --git a/R/accessors.R b/R/accessors.R
new file mode 100755
index 0000000..b1cbd51
--- /dev/null
+++ b/R/accessors.R
@@ -0,0 +1,22 @@
+"[[.registry" <-
+function(x, ...)
+{
+    if (missing(..1))
+        x$get_entry()
+    else
+        x$get_entry(...)
+}
+
+"[.registry" <-
+function(x, ...)
+{
+    if (missing(..1))
+        x$get_entries()
+    else
+        x$get_entries(...)
+}
+
+length.registry <-
+function(x)
+    x$n_of_entries()
+
diff --git a/R/converters.R b/R/converters.R
new file mode 100755
index 0000000..e4d422c
--- /dev/null
+++ b/R/converters.R
@@ -0,0 +1,25 @@
+as.data.frame.registry <-
+function(x, ...)
+{
+    .one_line <- function(entry) {
+        entry <- lapply(.labels(entry), function(i) i[[1]])
+        data.frame(unclass(entry), ...)
+    }
+
+    ret <- do.call(rbind, lapply(x$get_entries(), .one_line))
+    row.names(ret) <- NULL
+    ret
+}
+
+.labels <-
+function(x)
+{
+    ## transform function entries
+    x[sapply(x, inherits, "function")] <- "<<function>>"
+
+    ## transform objects
+    obj <- sapply(x, is.object)
+    x[obj] <- paste("<<", sapply(x, class)[obj], ">>", sep = "")
+
+    x
+}
diff --git a/R/matchfuns.R b/R/matchfuns.R
new file mode 100755
index 0000000..699cf3f
--- /dev/null
+++ b/R/matchfuns.R
@@ -0,0 +1,20 @@
+## user-specifiable lookup-functions
+match_ignorecase <-
+function(lookup, entry, ...)
+    tolower(lookup) %in% tolower(entry)
+
+match_exact <-
+function(lookup, entry, ...)
+    lookup %in% entry
+
+match_partial <-
+function(lookup, entry, ...)
+    !is.na(pmatch(lookup, entry, ...))
+
+match_partial_ignorecase <-
+function(lookup, entry, ...)
+    !is.na(pmatch(tolower(lookup), tolower(entry), ...))
+
+match_regexp <-
+function(lookup, entry, ...)
+    length(grep(lookup, entry, ...)) > 0
diff --git a/R/printsummary.R b/R/printsummary.R
new file mode 100755
index 0000000..5d50683
--- /dev/null
+++ b/R/printsummary.R
@@ -0,0 +1,32 @@
+print.registry <-
+function(x, ...)
+{
+    l <- x$n_of_entries()
+    if (l < 1)
+        writeLines(gettext("An object of class 'registry' with no entry."))
+    else if (l == 1)
+        writeLines(gettext("An object of class 'registry' with one entry."))
+    else
+        writeLines(gettextf("An object of class 'registry' with %d entries.", l))
+    invisible(x)
+}
+
+print.registry_field <-
+function(x, ...) ## remove index function
+{
+    writeLines(formatUL(x[-7], label = names(x[-7]), ...))
+    invisible(x)
+}
+
+print.registry_entry <-
+function(x, ...)
+{
+    x <- lapply(.labels(x), paste, collapse = ", ")
+    writeLines(formatUL(x, label = names(x)))
+    invisible(x)
+}
+
+summary.registry <-
+function(object, ...)
+    as.data.frame(object, ...)
+
diff --git a/R/registry.R b/R/registry.R
new file mode 100755
index 0000000..0fb9d34
--- /dev/null
+++ b/R/registry.R
@@ -0,0 +1,501 @@
+###################################
+### generic registry infrastructure
+
+### IDEA: use lexical scope with nested functions to create an
+### S3-"object" that exposes the data structure only through accessor functions.
+
+## creating function
+registry <-
+    function(entry_class = NULL, registry_class = NULL,
+             validity_FUN = NULL, stop_if_missing = FALSE)
+{
+### ATTRIBUTES
+    ## repository
+    DATA <- META <- list()
+
+    ## permissions
+    PERMISSIONS <- c(set_entries = TRUE, modify_entries = TRUE,
+                     delete_entries = TRUE, set_fields = TRUE)
+    SEALED_FIELDS <- SEALED_ENTRIES <- character(0)
+
+
+### METHODS (PRIVATE)
+    ## helper functions
+    .field_exists <-
+    function(name)
+        name %in% .get_field_names()
+
+    .make_field <-
+    function(type = NA, alternatives = NA, default = NA,
+             is_mandatory = FALSE, is_modifiable = TRUE, is_key = FALSE,
+             validity_FUN = NULL, index_FUN = match_ignorecase,
+             index_FUN_args = NULL
+             )
+        structure(list(type = type,
+                       alternatives = alternatives,
+                       default = default,
+                       is_mandatory = is_mandatory,
+                       is_modifiable = is_modifiable,
+                       is_key = is_key,
+                       validity_FUN = validity_FUN,
+                       index_FUN = index_FUN,
+                       index_FUN_args = index_FUN_args
+                       ),
+                  class = "registry_field")
+
+
+    .make_entry <- function(l)
+    {
+        ## get index fields
+        index_fields <- .get_index_fields()
+
+        ## sort
+        l <- l[c(index_fields, setdiff(.get_field_names(), index_fields))]
+
+        ## return object (possibly inheriting from entry_class)
+        structure(l, class = c(entry_class, "registry_entry"))
+    }
+
+    .get_index_fields <-
+    function()
+        names(META)[sapply(META, function(i) i$is_key)]
+
+    .get_mandatory_fields <-
+    function()
+        names(META)[sapply(META, function(i) i$is_mandatory)]
+
+    .get_field_defaults <-
+    function()
+        lapply(META, function(i) i$default)
+
+    .get_entry_indices <-
+    function(key, stop_missing = stop_if_missing, FUN = NULL, ARGS = NULL) {
+        ## get index fields
+        index_fields <- .get_index_fields()
+        l <- length(key)
+        n <- names(key)
+        if (l != length(index_fields))
+            index_fields <- if (is.null(n))
+                index_fields[1:l]
+            else
+                intersect(n, index_fields)
+
+        ## returns the index of the first match
+        index <- seq_along(DATA)
+        for (index_field in seq_along(index_fields)) {
+            if (length(index) < 1)
+                break
+
+            if (is.null(FUN)) {
+                FUN <- .get_field(index_fields[index_field])$index_FUN
+                ARGS <- .get_field(index_fields[index_field])$index_FUN_args
+            }
+            index <-
+                index[sapply(DATA[index],
+                        function(i) do.call(FUN,
+                                       c(list(key[index_field],
+                                              i[[ index_fields[index_field] ]]),
+                                         ARGS))
+                             )]
+        }
+
+        ## nothing found
+        if (length(index) < 1) {
+            if (stop_missing)
+                stop("Entry not in registry.", call. = FALSE)
+            else
+                return(NULL)
+        }
+
+        ## return
+        index
+    }
+
+    .get_first_entry_index <-
+    function(key, stop_missing = stop_if_missing)
+        .get_entry_indices(key, stop_missing)[1]
+
+    .check_value <-
+    function(field_name, field, value)
+    {
+        ## Note we do not check NA entries because this may by set automatically
+        if (is.object(value) || !is.function(value) && !is.na(value[1])) {
+            ## check class / list of alternatives, if any
+            if (!any(is.na(field$type))) {
+                ## check class
+                if (!inherits(value, field$type)) {
+                    stop(paste("Field", dQuote(field_name),
+                               "does not inherit from:",
+                               paste(field$type, collapse = ", ")),
+                         call. = FALSE)
+                }
+
+                ## check list of alternatives
+                if (!any(is.na(field$alternatives))) {
+                    if(!any(unlist(lapply(field$alternatives,
+                                          identical, value))))
+                        stop(paste("Possible values for", dQuote(field_name),
+                                   "are:", paste(field$alternatives,
+                                                 collapse = ", ")),
+                             call. = FALSE)
+                }
+            }
+
+            ## apply validity function, if any
+            if (!is.null(field$validity_FUN))
+                do.call(field$validity_FUN, list(value))
+        }
+    }
+
+    .check_for_unknown_fields <-
+    function(n)
+    {
+        ## check for fields not in repository
+        missing <- !.field_exists(n)
+        if (any(missing))
+            stop(paste("Field(s) not in repository:",
+                       paste(n[missing], collapse = ", ")), call. = FALSE)
+    }
+
+### METHODS (PUBLIC)
+    ## field accessors
+    .get_field <-
+    function(name)
+    {
+        if (!.field_exists(name))
+            stop(paste("Field", dQuote(name), "not in registry."),
+                 call. = FALSE)
+
+        META[[name]]
+    }
+
+    .get_fields <-
+    function()
+        META
+
+    .get_field_names <-
+    function()
+        names(META)
+
+    .set_field <-
+    function(name,
+             type = NA, alternatives = NA, default = NA,
+             is_mandatory = NULL, is_modifiable = TRUE, is_key = FALSE,
+             validity_FUN = NULL, index_FUN = match_ignorecase, ...
+             )
+    {
+        ## check permissions
+        if (!PERMISSIONS["set_fields"])
+            stop("Setting of fields not allowed.", call. = FALSE)
+
+        ## check for double entries
+        if (.field_exists(name))
+            stop(paste("Field", dQuote(name), "already in registry."),
+                 call. = FALSE)
+
+        ## possibly, infer type from argment
+        if (!is.na(type) && !(is.character(type)))
+            type <- class(type)
+
+        ## check mandatory fields
+        if (is.null(is_mandatory))
+            is_mandatory <- is_key
+        if (is_mandatory && !is.na(default))
+            stop("Mandatory fields should have no default.", call. = FALSE)
+        if (is_key && !is_mandatory)
+            stop("Key fields must be mandatory.", call. = FALSE)
+
+        ## create field entry
+        field <- .make_field(type = type,
+                             alternatives = alternatives,
+                             default = default,
+                             is_mandatory = is_mandatory,
+                             is_modifiable = is_modifiable,
+                             is_key = is_key,
+                             validity_FUN = validity_FUN,
+                             index_FUN = index_FUN,
+                             index_FUN_args = list(...)
+                             )
+
+        ## check validity of default
+        .check_value("default", field, default)
+
+        ## check validity of alternatives
+        if (!any(is.na(alternatives)))
+            for (i in alternatives)
+                .check_value("alternatives", field, i)
+
+        ## add field to meta data
+        META <<- c(META, list(field))
+        names(META)[length(META)] <<- name
+
+        ## add (missing) fields to data entries
+        DATA <<- lapply(DATA, `[[<-`, name, default)
+    }
+
+    .has_entry <-
+    function(key)
+        length(.get_entry_indices(key)) > 0
+
+    .n_of_entries <-
+    function()
+        length(DATA)
+
+    ## entry accessors
+    .set_entry <-
+    function(...)
+    {
+        ## check permissions
+        if (!PERMISSIONS["set_entries"])
+            stop("Setting of entries not allowed.", call. = FALSE)
+
+        ## parameter handling
+        l <- list(...)
+        n <- names(l)
+        index_fields <- .get_index_fields()
+        fields <- .get_field_names()
+
+        if (is.null(n)) {
+            if (length(l) == length(fields)) {
+                n <- fields
+                names(l) <- n
+            } else
+                stop("Need either named arguments, or complete entry.")
+        }
+
+
+        .check_for_unknown_fields(n)
+
+        ## check if there is at least one index field
+        if (length(index_fields) < 1)
+            stop("Need at least one index field before adding entries.",
+                 call. = FALSE)
+
+        ## check for mandatory fields
+        mandatory_fields <- .get_mandatory_fields()
+        missing_mandatory_fields <- !mandatory_fields %in% n
+        if (any(missing_mandatory_fields))
+            stop(paste("The following fields are mandatory, but missing:",
+                       paste(mandatory_fields[missing_mandatory_fields],
+                             collapse = ", ")), call. = FALSE)
+
+        ## check for double entries
+        if (length(.get_entry_indices(l[index_fields],
+                                      stop_missing = FALSE,
+                                      FUN = match_exact)) > 0)
+                stop(paste("Entry already in registry."), call. = FALSE)
+
+        ## check defaults and set values, if needed
+        field_defaults    <- .get_field_defaults()
+        default_fields    <- names(field_defaults)
+        missing_fields    <- setdiff(default_fields, n)
+        l[missing_fields] <- field_defaults[missing_fields]
+
+        ## check field types, and apply field check function, if any.
+        for (f in n)
+            .check_value(f, .get_field(f), l[[f]])
+
+
+        ## apply entry check function
+        if (!is.null(validity_FUN))
+            do.call(validity_FUN, list(l))
+
+        ## add entry
+        entry <- list(.make_entry(l))
+        names(entry) <-
+            paste(lapply(entry[[1]][seq_along(index_fields)], `[[`, 1),
+                  collapse = "_")
+        DATA <<- c(DATA, entry)
+    }
+
+    .get_entries <-
+    function(...)
+    {
+        key <- list(...)
+        if (length(key) > 0) {
+            ind <- .get_entry_indices(key)
+            if (length(ind) > 0)
+                DATA[ind]
+            else
+                NULL
+        } else DATA
+    }
+
+    .grep_entries <-
+    function(pattern, ...)
+    {
+        pattern_in_entry <-
+            function(x) any(sapply(x, function(i) is.character(i)
+                                   && length(grep(pattern, i, ...) > 0)))
+        ind <- sapply(DATA, pattern_in_entry)
+        if (any(ind))
+            DATA[ind]
+        else
+            NULL
+    }
+
+    .get_first_entry <-
+    function(...)
+        .get_entries(...)[[1]]
+
+    .get_entry_names <-
+    function()
+    {
+        if (length(DATA) < 1)
+            character(0)
+        else
+            names(DATA)
+    }
+
+    .delete_entry <-
+    function(...)
+    {
+        key <- list(...)
+
+        ## check permissions
+        if (!PERMISSIONS["delete_entries"])
+            stop("Deletion of entries not allowed.", call. = FALSE)
+
+        ## fetch entry index (this also checks if the entry exists)
+        entry_index <- .get_entry_indices(key)
+
+        ## check if it is unique
+        if (length(entry_index) != 1)
+            stop("Key specification must be unique.", call. = FALSE)
+
+        ## check sealed entries
+        if (entry_index %in% SEALED_ENTRIES)
+            stop(paste("Deletion of entry not allowed."), call. = FALSE)
+
+        ## delete it
+        DATA[entry_index] <<- NULL
+    }
+
+
+    .modify_entry <-
+    function(...)
+    {
+        ## check permissions
+        if (!PERMISSIONS["modify_entries"])
+            stop("Modifying of entries not allowed.", call. = FALSE)
+
+        ## parameter handling
+        l <- list(...)
+        n <- names(l)
+
+        .check_for_unknown_fields(n)
+
+        ## determine entry key
+        key  <- l[.get_index_fields()]
+
+        ## fetch entry index (this also checks if the entry exists)
+        entry_index <- .get_entry_indices(key)
+
+        ## check if it is unique
+        if (length(entry_index) != 1)
+            stop("Key specification must be unique!", call. = FALSE)
+
+        ## fetch entry
+        entry <- DATA[[entry_index]]
+
+        for(field in setdiff(n, .get_index_fields())) {
+            ## check if field is modifiable
+            field_entry <- .get_field(field)
+            if (!field_entry$is_modifiable)
+                stop(paste("Field", dQuote(field), "is not modifiable."),
+                     call. = FALSE)
+
+            ## check if entry and field are sealed
+            if ((entry_index %in% SEALED_ENTRIES) &&
+                (field %in% SEALED_FIELDS))
+                stop(paste("Modification of field", dQuote(field),
+                           "in this entry not allowed."), call. = FALSE)
+
+            ## check new value
+            value <- l[[field]]
+            .check_value(field, field_entry, value)
+
+            ## modify entry locally
+            entry[[field]] <- value
+        }
+
+        ## apply entry check function
+        if (!is.null(validity_FUN))
+            do.call(validity_FUN, list(entry))
+
+        ## modify entry in registry
+        DATA[entry_index] <<- list(entry)
+    }
+
+    ## get all entries for one field
+    .get_field_entries <-
+    function(field, unlist = TRUE)
+    {
+        if (!.field_exists(field))
+            stop(paste("Field", dQuote(field), "not in registry."),
+                 call. = FALSE)
+
+        ret <- lapply(DATA, `[[`, field)
+        if (unlist)
+            unlist(ret)
+        else
+            ret
+    }
+
+    ## permission getters/setters
+    .get_permissions <-
+    function()
+        PERMISSIONS
+
+    .restrict_permissions <-
+    function(set_entries = TRUE, modify_entries = TRUE,
+             delete_entries = TRUE, set_fields = TRUE)
+    {
+        PERMISSIONS["set_entries"] <<-
+            PERMISSIONS["set_entries"] && set_entries
+        PERMISSIONS["modify_entries"] <<-
+            PERMISSIONS["modify_entries"] && modify_entries
+        PERMISSIONS["delete_entries"] <<-
+            PERMISSIONS["delete_entries"] && delete_entries
+        PERMISSIONS["set_fields"] <<-
+            PERMISSIONS["set_fields"] && set_fields
+    }
+
+    .seal_entries <-
+    function()
+    {
+        SEALED_ENTRIES <<- seq_along(DATA)
+        SEALED_FIELDS <<- .get_field_names()
+    }
+
+    .get_sealed_field_names <-
+    function()
+        SEALED_FIELDS
+
+### CONSTRUCTOR
+    ## return class
+    structure(list(get_field = .FUNCall(.get_field),
+                   get_fields = .FUNCall(.get_fields),
+                   get_field_names = .FUNCall(.get_field_names),
+                   set_field = .FUNCall(.set_field),
+
+                   has_entry = .FUNCall(.has_entry),
+                   get_entry = .FUNCall(.get_first_entry),
+                   get_entries = .FUNCall(.get_entries),
+                   get_entry_names = .FUNCall(.get_entry_names),
+                   grep_entries = .FUNCall(.grep_entries),
+                   set_entry = .FUNCall(.set_entry),
+                   modify_entry = .FUNCall(.modify_entry),
+                   delete_entry = .FUNCall(.delete_entry),
+                   n_of_entries = .FUNCall(.n_of_entries),
+
+                   get_field_entries = .FUNCall(.get_field_entries),
+
+                   get_permissions = .FUNCall(.get_permissions),
+                   restrict_permissions = .FUNCall(.restrict_permissions),
+                   seal_entries = .FUNCall(.seal_entries),
+                   get_sealed_field_names = .FUNCall(.get_sealed_field_names)
+                   ),
+              class = c(registry_class, "registry"))
+}
+
diff --git a/R/utils.R b/R/utils.R
new file mode 100755
index 0000000..603d8ee
--- /dev/null
+++ b/R/utils.R
@@ -0,0 +1,2 @@
+## This should be in base R!
+.FUNCall <- function(f) function(...) f(...)
diff --git a/build/vignette.rds b/build/vignette.rds
new file mode 100644
index 0000000..e4c1648
Binary files /dev/null and b/build/vignette.rds differ
diff --git a/demo/00Index b/demo/00Index
new file mode 100755
index 0000000..55c7719
--- /dev/null
+++ b/demo/00Index
@@ -0,0 +1,2 @@
+registry	Demo for the registry package
+
diff --git a/demo/registry.R b/demo/registry.R
new file mode 100755
index 0000000..c4d2b9f
--- /dev/null
+++ b/demo/registry.R
@@ -0,0 +1,67 @@
+##########################
+### registry test instances
+
+library(registry)
+
+.my_check_fun <- function(x) if (x$Z == 999 && x$New2 == 999) stop("No evil allowed!")
+
+## create registry
+R <- registry(entry_class = "simple.list",
+              validity_FUN = .my_check_fun)
+R
+
+## set fields
+R$set_field("names", type = "character", is_key = TRUE)
+R$set_field("X", type = TRUE, is_mandatory = TRUE)
+R$set_field("Y", type = "character")
+R$set_field("Z", default = 123)
+R$get_fields()
+
+## add entries
+R$set_entry(names = c("test", "bar"), X = TRUE, Y = "bla")
+R$set_entry(names = "test2", X = FALSE, Y = "foo", Z = 99)
+R$set_entry(names = "test3", X = FALSE, Y = "bar", Z = "chars")
+R$get_entry("test")
+R[["test2"]]
+R[["test3"]]
+R[["bar"]]
+
+## add new field
+R$set_field("New")
+R$get_field("New")
+
+## change entries
+R$modify_entry(names = "test", New = 123)
+R$modify_entry(names = "test2", New = "test")
+
+## field check function (checks for strict positive values)
+R$set_field("New2", type = "numeric", validity_FUN = function(x) stopifnot(x > 0))
+R$set_entry(names = "test5", X = TRUE, New2 = 2)
+
+## add field with fixed alternatives
+R$set_field("New3", type = "character", alternatives = c("A", "B"))
+R$get_field("New")
+R$set_entry(names = "test6", X = TRUE, New3 = "A")
+
+## print/summary = as.data.frame
+R
+summary(R)
+
+## seal entries
+R$seal_entries()
+R$set_field("New4")
+R$set_entry(names = "test7", X = TRUE, Y = "bla")
+R$delete_entry("test7")
+R$modify_entry(names = "test", New4 = "test")
+
+## error cases:
+TRY <- function(...) stopifnot(inherits(try(..., silent = TRUE), "try-error"))
+TRY(R$set_field("bla", type = "character", default = 123))
+TRY(R$set_entry("err1", Y = "bla"))
+TRY(R$set_entry("err2", X = "bla"))
+TRY(R$set_entry("err3", X = TRUE, New2 = -2))
+TRY(R$set_entry("err4", X = TRUE, Z = 999, New2 = 999))
+TRY(R$set_entry("err5", X = TRUE, New3 = "C"))
+TRY(R$modify_entry("Bla", "New", 123))
+TRY(R$modify_entry("X", "Bla", 123))
+TRY(R$modify_entry("test","X",TRUE))
diff --git a/inst/doc/registry.R b/inst/doc/registry.R
new file mode 100644
index 0000000..a2d7424
--- /dev/null
+++ b/inst/doc/registry.R
@@ -0,0 +1,207 @@
+### R code from vignette source 'registry.Rnw'
+### Encoding: UTF-8
+
+###################################################
+### code chunk number 1: registry.Rnw:56-58
+###################################################
+options(width = 80)
+library("registry")
+
+
+###################################################
+### code chunk number 2: registry.Rnw:122-125
+###################################################
+library(registry)
+R <- registry()
+print(R)
+
+
+###################################################
+### code chunk number 3: registry.Rnw:141-142
+###################################################
+checkAge <- function(x) stopifnot(is.na(x) || x > 0 && x < 100)
+
+
+###################################################
+### code chunk number 4: registry.Rnw:147-148
+###################################################
+checkPhone <- function(x) stopifnot(!is.na(x$mobile) || !is.na(x$home))
+
+
+###################################################
+### code chunk number 5: registry.Rnw:153-155
+###################################################
+R <- registry(registry_class = "Addressbook", entry_class = "Address",
+              validity_FUN = checkPhone)
+
+
+###################################################
+### code chunk number 6: registry.Rnw:158-164
+###################################################
+print.Addressbook <-
+function(x, ...) {
+    writeLines(sprintf("An address book with %i entries.\n", length(x)))
+    invisible(x)
+}
+print(R)
+
+
+###################################################
+### code chunk number 7: registry.Rnw:170-172
+###################################################
+R$set_field("last", type = "character", is_key = TRUE, index_FUN = match_partial_ignorecase)
+R$set_field("first", type = "character", is_key = TRUE, index_FUN = match_partial_ignorecase)
+
+
+###################################################
+### code chunk number 8: registry.Rnw:175-176
+###################################################
+R$set_field("address", type = "character")
+
+
+###################################################
+### code chunk number 9: registry.Rnw:181-183
+###################################################
+R$set_field("mobile", type = "character")
+R$set_field("home", type = "character")
+
+
+###################################################
+### code chunk number 10: registry.Rnw:187-188
+###################################################
+R$set_field("age", type = "integer", validity_FUN = checkAge)
+
+
+###################################################
+### code chunk number 11: registry.Rnw:192-195
+###################################################
+R$set_field("type", type = "character",
+            alternatives = c("Business", "Private"),
+            default = "Business")
+
+
+###################################################
+### code chunk number 12: registry.Rnw:198-199
+###################################################
+R$get_field("type")
+
+
+###################################################
+### code chunk number 13: registry.Rnw:206-210
+###################################################
+R$set_entry(last = "Smith", first = "Mary", address = "Vienna",
+            home = "734 43 34", type = "Private", age = 44L)
+R$set_entry(last = "Smith", first = "Peter", address = "New York",
+            mobile = "878 78 87")
+
+
+###################################################
+### code chunk number 14: registry.Rnw:213-215
+###################################################
+R$set_entry("Myers", "John", "Washington", "52 32 34", "898 89 99",
+            33L, "Business")
+
+
+###################################################
+### code chunk number 15: registry.Rnw:218-223
+###################################################
+TRY <- function(expr) tryCatch(expr, error = print)
+TRY(R$set_entry(last = "Smith", first = "Mary"))
+TRY(R$set_entry(last = "Miller", first = "Henry"))
+TRY(R$set_entry(last = "Miller", first = "Henry", age = 12.5))
+TRY(R$set_entry(last = "Miller", first = "Henry", age = 999L))
+
+
+###################################################
+### code chunk number 16: registry.Rnw:226-227
+###################################################
+R$get_entry(last = "Smith", first = "mar")
+
+
+###################################################
+### code chunk number 17: registry.Rnw:231-234
+###################################################
+print.Address <- function(x) with(x,
+    writeLines(sprintf("%s %s, %s; home: %s, mobile: %s; age: %i (%s)", first, last, address, home, mobile, age, type)))
+R$get_entry(last = "Smith", first = "mar")
+
+
+###################################################
+### code chunk number 18: registry.Rnw:241-242
+###################################################
+R[["Myers"]]
+
+
+###################################################
+### code chunk number 19: registry.Rnw:246-248
+###################################################
+R$set_entry(last = "Frears", first = c("Joe", "Jonathan"),
+            address = "Washington", home = "721 42 34")
+
+
+###################################################
+### code chunk number 20: registry.Rnw:251-252
+###################################################
+identical(R[["Frears", "Jonathan"]], R[["Frears", "Joe"]])
+
+
+###################################################
+### code chunk number 21: registry.Rnw:258-259
+###################################################
+R$get_entries("Smith")
+
+
+###################################################
+### code chunk number 22: registry.Rnw:262-263
+###################################################
+R$grep_entries("Priv")
+
+
+###################################################
+### code chunk number 23: registry.Rnw:266-268 (eval = FALSE)
+###################################################
+## R$get_entries()
+## R[]
+
+
+###################################################
+### code chunk number 24: registry.Rnw:271-272
+###################################################
+summary(R)
+
+
+###################################################
+### code chunk number 25: registry.Rnw:276-279
+###################################################
+R[["Smith", "Peter"]]
+R$modify_entry(last = "Smith", first = "Peter", age = 22L)
+R[["Smith", "Peter"]]
+
+
+###################################################
+### code chunk number 26: registry.Rnw:282-284
+###################################################
+R$delete_entry(last = "Smith", first = "Peter")
+R[["Smith", "Peter"]]
+
+
+###################################################
+### code chunk number 27: registry.Rnw:294-299
+###################################################
+R$seal_entries()
+TRY(R$delete_entry("Smith", "Mary"))
+R$set_entry(last = "Slater", first = "Christian", address = "Boston",
+            mobile = "766 23 88")
+R[["Slater"]]
+
+
+###################################################
+### code chunk number 28: registry.Rnw:302-307
+###################################################
+R$get_permissions()
+R$restrict_permissions(delete_entries = FALSE)
+TRY(R$delete_entry("Slater"))
+R$modify_entry(last = "Slater", first = "Christian", age = 44L)
+R[["Slater"]]
+
+
diff --git a/inst/doc/registry.Rnw b/inst/doc/registry.Rnw
new file mode 100755
index 0000000..aa04475
--- /dev/null
+++ b/inst/doc/registry.Rnw
@@ -0,0 +1,313 @@
+\documentclass[a4paper]{article}
+\usepackage[round,longnamesfirst]{natbib}
+\usepackage{graphicx,keyval,thumbpdf,a4wide,makeidx,color,colordvi}
+\usepackage{amsfonts,hyperref}
+\usepackage[utf8]{inputenc}
+\DeclareUnicodeCharacter{201C}{"}
+\DeclareUnicodeCharacter{201D}{"}
+
+\newcommand\R{\textsf{R}}
+\newcommand{\pkg}[1]{{\normalfont\fontseries{b}\selectfont #1}}
+\newcommand{\sQuote}[1]{`{#1}'}
+\newcommand{\dQuote}[1]{``{#1}''}
+\newcommand{\file}[1]{\sQuote{\textsf{#1}}}
+\newcommand{\data}[1]{\texttt{#1}}
+\newcommand{\var}[1]{\textit{#1}}
+\newcommand{\class}[1]{\textsf{#1}}
+\newcommand{\proglang}[1]{\textsf{#1}}
+%% \code without `-' ligatures
+\def\nohyphenation{\hyphenchar\font=-1 \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font=`-}
+{\catcode`\-=\active%
+  \global\def\code{\bgroup%
+    \catcode`\-=\active \let-\codedash%
+    \Rd at code}}
+\def\codedash{-\discretionary{}{}{}}
+\def\Rd at code#1{\texttt{\nohyphenation#1}\egroup}
+\newcommand{\codefun}[1]{\code{#1()}}
+\newcommand{\codefunind}[1]{\codefun{#1}\index{\texttt{#1}}}
+\newcommand{\codeind}[1]{\code{#1}\index{\texttt{#1}}}
+
+\SweaveOpts{strip.white=true}
+
+\definecolor{Blue}{rgb}{0,0,0.8}
+\definecolor{Red}{rgb}{0.7,0,0}
+
+\date{2009-02-17}
+\title{A Generic Registry Infrastructure for \R}
+\author{David Meyer}
+%\VignetteIndexEntry{Registry}
+%\VignetteDepends{registry}
+%\VignetteKeywords{registry}
+%\VignettePackage{registry}
+
+\makeindex{}
+
+\sloppy{}
+
+\begin{document}
+\maketitle
+
+% \begin{abstract}
+% This document introduces a generic registry infrastructure for \R,
+% provided by the \pkg{registry} package.
+% \end{abstract}
+
+<<echo=FALSE>>=
+options(width = 80)
+library("registry")
+@ %
+
+\section{Introduction}
+\label{sec:introduction}
+
+More and more, \R~packages are offering dynamic functionality,
+allowing users to extend a \dQuote{repository} of initial features or
+data. For example, the \pkg{proxy} package \citep{registry:meyer+buchta:2008}
+provides an enhanced
+\codefun{dist} function for computing dissimilarity matrices,
+allowing to choose among several proximity
+measures stored in a registry. Each entry is composed of a small
+workhorse function and some meta data including, e.g., a character vector
+of aliases, literature references, the formula in plain text,
+a function to coerce
+between similarity and distance, and a type categorization
+(binary, metric, etc.). Users can add new proximity measures to the
+registry at run-time and immediately use them without recreating the
+package, specifying one of the aliases defined in the meta data.
+Similarly, the \pkg{relations} \citep{registry:hornik+meyer:2008}
+and \pkg{CLUE} \citep{registry:hornik:2005,registry:hornik:2007}
+packages use simple
+registries internally to link some meta data to available functions,
+used by the high-level consensus ranking and cluster ensemble
+functions, respectively.
+
+Such a registry, whether exposed to the user or not, is conceptually a
+small in-memory data base where entries with a common field structure are
+stored and retrieved and whose fields can be of mixed type.
+At first sight, a data frame seems to be the
+data structure of choice for an appropriate implementation.
+Unfortunately, data frames are inconvenient to use
+with factors, functions, or other recursive types such as lists
+due to automatic coercions taking place behind the scenes. In fact, a
+simpler, record-like structure such as a list with named components
+(\dQuote{fields}) appears more practical. Also,
+features known from \dQuote{real} data bases such as compound keys,
+validity checking of new entries, and use of access rights are not
+available by default and need to be \dQuote{reinvented} every time
+they are needed.
+
+The \pkg{registry} package provides a simple mechanism for defining
+and manipulating user-extensible registry objects. A typical
+use case in the context of an \R~package could include the following steps:
+
+\begin{enumerate}
+\item Create one or more registry objects inside the package's namespace.
+\item Insert entries to the registry.
+\item Possibly, \dQuote{seal} the entries and set access rights.
+\item Possibly, export the registry object to the user level.
+\item Browse and retrieve entries from the registry.
+\end{enumerate}
+
+In the following, we explain these steps in more detail:
+first, how a registry can be set up; second, how entries
+can be added, modified and retrieved; and third, how a registry can be
+sealed and restricted through the definition of access rights.
+
+\section{Creating Registries}
+
+A registry basically is a container (implemented in \R~as an
+environment), along with some access functions. A new object of class
+\code{registry} can simply be created using the \codefun{registry} function:
+<<>>=
+library(registry)
+R <- registry()
+print(R)
+@
+Optional parameters include the specification of an (additional) class
+for the created registry object and the individual entries,
+as well as the specification of some validity function checking new
+entries to be added to the registry.
+
+In the following, we will use the example of a simple address book,
+whose entries include first and last name, address, age, home/cell
+phone number, and a business/private classification.
+Last and first name build the search key. Age is an
+optional integer in the range of 1 and
+99. Additionally, at least one phone number should be added to the registry.
+
+We start by creating two simple validity functions. The first one, to
+be specified at field level later on, checks a given age:
+<<>>=
+checkAge <- function(x) stopifnot(is.na(x) || x > 0 && x < 100)
+@
+The second one, specified at registry level,
+checks whether a given registry entry (list of named components)
+contains at least one phone number:
+<<>>=
+checkPhone <- function(x) stopifnot(!is.na(x$mobile) || !is.na(x$home))
+@
+Next, we create a registry of class \code{Addressbook} (inheriting
+from \code{registry}), containing entries of class \code{Address} and
+using the above validity function.
+<<>>=
+R <- registry(registry_class = "Addressbook", entry_class = "Address",
+              validity_FUN = checkPhone)
+@
+The additional class for the registry allows, e.g., user-defined printing:
+<<>>=
+print.Addressbook <-
+function(x, ...) {
+    writeLines(sprintf("An address book with %i entries.\n", length(x)))
+    invisible(x)
+}
+print(R)
+@
+
+At this stage, we are ready to set up the field information. First and last
+names are mandatory character fields, uniquely identifying an entry
+(key fields). Lookups should work with partial completion, ignoring case:
+<<>>=
+R$set_field("last", type = "character", is_key = TRUE, index_FUN = match_partial_ignorecase)
+R$set_field("first", type = "character", is_key = TRUE, index_FUN = match_partial_ignorecase)
+@
+The address is also character, but optional:
+<<>>=
+R$set_field("address", type = "character")
+@
+At least one phone number (character) is required. This can be
+achieved by making them optional, and using the validity
+function specified at the registry level to check whether one of them is empty:
+<<>>=
+R$set_field("mobile", type = "character")
+R$set_field("home", type = "character")
+@
+The age field is an optional integer with a defined range, checked by
+the field-level validity function:
+<<>>=
+R$set_field("age", type = "integer", validity_FUN = checkAge)
+@
+Finally, the business/private category is defined by specifying the
+possible alternatives (\code{Business} is set as default):
+<<>>=
+R$set_field("type", type = "character",
+            alternatives = c("Business", "Private"),
+            default = "Business")
+@
+The setup for a field can be retrieved using \codefun{get\_field}:
+<<>>=
+R$get_field("type")
+@
+\codefun{get\_fields} returns the complete list.
+
+\section{Using Registries}
+
+We now can start adding entries to the registry:
+<<>>=
+R$set_entry(last = "Smith", first = "Mary", address = "Vienna",
+            home = "734 43 34", type = "Private", age = 44L)
+R$set_entry(last = "Smith", first = "Peter", address = "New York",
+            mobile = "878 78 87")
+@
+If all field values are specified, the field names can be omitted:
+<<>>=
+R$set_entry("Myers", "John", "Washington", "52 32 34", "898 89 99",
+            33L, "Business")
+@
+Duplicate or invalid entries are not accepted:
+<<>>=
+TRY <- function(expr) tryCatch(expr, error = print)
+TRY(R$set_entry(last = "Smith", first = "Mary"))
+TRY(R$set_entry(last = "Miller", first = "Henry"))
+TRY(R$set_entry(last = "Miller", first = "Henry", age = 12.5))
+TRY(R$set_entry(last = "Miller", first = "Henry", age = 999L))
+@
+A single entry can be retrieved using \codefun{get\_entry}:
+<<>>=
+R$get_entry(last = "Smith", first = "mar")
+@
+Since returned entries inherit from \code{Address}, we can provide a
+user-defined print method:
+<<>>=
+print.Address <- function(x) with(x,
+    writeLines(sprintf("%s %s, %s; home: %s, mobile: %s; age: %i (%s)", first, last, address, home, mobile, age, type)))
+R$get_entry(last = "Smith", first = "mar")
+@
+Note that even though
+the first name of Mary Smith is incompletely specified and in
+lower case, the lookup is still successful
+because of the partial matching indexing function. The \code{[[} operator
+can be used as an alternative to \codefun{get\_entry}:
+<<>>=
+R[["Myers"]]
+@
+For Myers, the last name uniquely identifies the entry, so
+the first name can be omitted. Key values can have alternative values:
+<<>>=
+R$set_entry(last = "Frears", first = c("Joe", "Jonathan"),
+            address = "Washington", home = "721 42 34")
+@
+Either of them can be used for retrieval:
+<<>>=
+identical(R[["Frears", "Jonathan"]], R[["Frears", "Joe"]])
+@
+Unsuccessful lookups result in a
+return of \code{NULL}. Multiple  entries can be retrieved
+using the \codefun{get\_entries} accessing function. They are returned
+in a list whose component names are generated from the key values:
+<<>>=
+R$get_entries("Smith")
+@
+Full-text search in all information is provided by \codefun{grep\_entries}:
+<<>>=
+R$grep_entries("Priv")
+@
+A list of all entries can be obtained using either of:
+<<eval=FALSE>>=
+R$get_entries()
+R[]
+@
+The summary method for registry objects returns a data frame:
+<<>>=
+summary(R)
+@
+Entries can also be modified using \codefun{modify\_entry}, specifying
+key and new field values:
+<<>>=
+R[["Smith", "Peter"]]
+R$modify_entry(last = "Smith", first = "Peter", age = 22L)
+R[["Smith", "Peter"]]
+@
+Finally, entries can be removed using \codefun{delete\_entry}:
+<<>>=
+R$delete_entry(last = "Smith", first = "Peter")
+R[["Smith", "Peter"]]
+@
+
+\section{Sealing Registries and Setting Access Rights}
+
+Occasionally, developers might want to protect a registry that ships
+with some package to prevent accidental deletions or
+alterations. For this, \pkg{registry} offers two mechanisms: first, a
+registry object can be \dQuote{sealed} to prevent modifications of
+\emph{existing} data:
+<<>>=
+R$seal_entries()
+TRY(R$delete_entry("Smith", "Mary"))
+R$set_entry(last = "Slater", first = "Christian", address = "Boston",
+            mobile = "766 23 88")
+R[["Slater"]]
+@
+Second, the access permissions for registries can be restricted:
+<<>>=
+R$get_permissions()
+R$restrict_permissions(delete_entries = FALSE)
+TRY(R$delete_entry("Slater"))
+R$modify_entry(last = "Slater", first = "Christian", age = 44L)
+R[["Slater"]]
+@
+
+\bibliographystyle{abbrvnat}
+\bibliography{registry}
+
+\end{document}
diff --git a/inst/doc/registry.pdf b/inst/doc/registry.pdf
new file mode 100755
index 0000000..66a2958
Binary files /dev/null and b/inst/doc/registry.pdf differ
diff --git a/man/matchfuns.Rd b/man/matchfuns.Rd
new file mode 100755
index 0000000..6b33566
--- /dev/null
+++ b/man/matchfuns.Rd
@@ -0,0 +1,65 @@
+\name{matchfuns}
+\alias{matchfuns}
+\alias{match_ignorecase}
+\alias{match_exact}
+\alias{match_partial}
+\alias{match_partial_ignorecase}
+\alias{match_regexp}
+\title{Matching functions}
+\description{
+  Functions used for lookups of search keys.
+}
+\usage{
+match_ignorecase(lookup, entry, \dots)
+match_exact(lookup, entry, \dots)
+match_partial(lookup, entry, \dots)
+match_partial_ignorecase(lookup, entry, \dots)
+match_regexp(lookup, entry, \dots)
+}
+\arguments{
+  \item{lookup}{Search value to look up (for some key field).}
+  \item{entry}{Vector of key values where \code{lookup} is sought.}
+  \item{\dots}{For \code{match_ignorecase} and \code{match_exact}:
+    currently not used. For \code{match_partial} and
+    \code{match_partial_ignorecase}: additional arguments passed to
+    \code{\link[base]{pmatch}}. For \code{match_regexp}: additional
+    arguments passed to \code{\link[base]{grep}}.}
+}
+\details{
+  These are matching functions to be specified for key fields,
+  controlling how search values are looked up in the registry.
+}
+\author{David Meyer \email{David.Meyer at R-project.org}}
+
+\seealso{\code{\link{regobj}}}
+
+\examples{
+## use exact matching
+R <- registry(stop_if_missing = FALSE)
+R$set_field("Key", type = "character", is_key = TRUE, index_FUN = match_exact)
+R$set_field("Value", type = "numeric")
+R$set_entry("the key", 1)
+
+R[["the key"]]
+R[["the"]]
+
+## use partial matching
+R <- registry()
+R$set_field("Key", type = "character", is_key = TRUE, index_FUN = match_partial)
+R$set_field("Value", type = "numeric")
+R$set_entry("the key", 1)
+
+R[["the"]]
+
+## use regular expressions
+R <- registry()
+R$set_field("Key", type = "character", is_key = TRUE, index_FUN = match_regexp)
+R$set_field("Value", type = "numeric")
+R$set_entry("the key", 1)
+R$set_entry("key", 2)
+
+R[["k.*"]]
+R["k.*"]
+
+}
+\keyword{data}
\ No newline at end of file
diff --git a/man/registry.Rd b/man/registry.Rd
new file mode 100755
index 0000000..6145b6d
--- /dev/null
+++ b/man/registry.Rd
@@ -0,0 +1,53 @@
+\name{registry}
+\alias{registry}
+\title{Registry creator}
+\description{
+  Function to create a registry object.
+}
+\usage{
+registry(entry_class = NULL, registry_class = NULL,
+         validity_FUN = NULL, stop_if_missing = FALSE)
+}
+
+\arguments{
+  \item{entry_class}{character string indicating a class the
+   returned registry object will additionally inherit from
+    (optional). Used for dispatching user-specified print and summary methods.}
+  \item{registry_class}{character string indicating a class the
+    registry entries will additionally inherit from (optional).
+    Used for dispatching user-specified print and summary methods.}
+  \item{validity_FUN}{a function accepting a new registry entry as argument for
+    checking its validity and possibly aborting with an error
+    message. The entry will be provided by the calling function as a
+    list with named components (fields).}
+  \item{stop_if_missing}{logical indicating whether the registry lookup
+    functions should abort or just return \code{NULL} in case of no
+    match.}
+}
+\details{
+  This is a generating function that will return a registry object whose
+  components are accessor functions for the contained data. These are
+  documented separately (\code{\link{regobj}}).
+}
+\author{David Meyer \email{David.Meyer at R-project.org}}
+
+\seealso{\code{\link{regobj}}}
+
+\examples{
+R <- registry()
+
+R$set_field("X", type = TRUE)
+R$set_field("Y", type = "character")
+R$set_field("index", type = "character", is_key = TRUE,
+            index_FUN = match_partial_ignorecase)
+R$set_field("index2", type = "integer", is_key = TRUE)
+
+R$set_entry(X = TRUE, Y = "bla", index = "test", index2 = 1L)
+R$set_entry(X = FALSE, Y = "foo", index = c("test", "bar"), index2 = 2L)
+
+R$get_entries("test")
+R[["test", 1]]
+R["test"]
+R[["test"]]
+}
+\keyword{data}
\ No newline at end of file
diff --git a/man/regobj.Rd b/man/regobj.Rd
new file mode 100755
index 0000000..fd2cbb3
--- /dev/null
+++ b/man/regobj.Rd
@@ -0,0 +1,146 @@
+\name{regobj}
+\alias{regobj}
+\alias{summary.registry}
+\alias{print.registry}
+\alias{[.registry}
+\alias{[[.registry}
+
+%- Also NEED an '\alias' for EACH other topic documented here.
+\title{Registry object}
+\description{
+  Registry object.
+}
+\usage{
+\special{regobj$get_field(name)}
+\special{regobj$get_fields()}
+\special{regobj$get_field_names()}
+\special{regobj$set_field(name,
+                 type = NA, alternatives = NA, default = NA,
+                 is_mandatory = FALSE, is_modifiable = TRUE,
+                 is_key = FALSE, validity_FUN = NULL,
+                 index_FUN = match_ignorecase, \dots)}
+
+\special{regobj$has_entry(key)}
+\special{regobj$get_entry(\dots)}
+\special{regobj$get_entries(\dots)}
+\special{regobj$grep_entries(pattern, \dots)}
+\special{regobj$get_entry_names()}
+\special{regobj$set_entry(\dots)}
+\special{regobj$modify_entry(\dots)}
+\special{regobj$delete_entry(\dots)}
+\special{regobj$n_of_entries(name)}
+\special{regobj$get_field_entries(field, unlist = TRUE)}
+
+\special{regobj$get_permissions()}
+\special{regobj$restrict_permissions(set_entries = TRUE,
+         modify_entries = TRUE, delete_entries = TRUE, set_fields = TRUE)}
+\special{regobj$seal_entries()}
+\special{regobj$get_sealed_field_names()}
+
+
+\method{print}{registry}(x, \dots)
+\method{summary}{registry}(object, \dots)
+
+\method{[[}{registry}(x, \dots)
+\method{[}{registry}(x, \dots)
+}
+%- maybe also 'usage' for other objects documented here.
+\arguments{
+  \item{name}{character string representing the name of an
+    entry (case-insensitive).}
+  \item{pattern}{regular expression to be matched to all fields of class
+    \code{"character"} in all entries.}
+  \item{type}{character vector specifying accepted classes
+    for this field. If \code{NA} (default), any class will be accepted.
+    If \code{type} is not a character vector, the
+    class will be inferred from the argument given.}
+  \item{alternatives}{vector of alternatives accepted for this field.}
+  \item{default}{optional default value for the field.}
+  \item{is_mandatory}{logical specifying whether new entries are required
+    to have a value for this field.}
+  \item{is_modifiable}{logical specifying whether entries can be changed
+    with respect to that field.}
+  \item{is_key}{logical indicating whether the field is (part of) an
+    index.}
+  \item{validity_FUN}{optional function or character string with the name of a
+    function that checks the validity of a field entry. Such a function
+    gets the value to be investigated as argument, and should stop with an
+    error message if the value is not correct.}
+  \item{index_FUN}{vectorized predicate function matching an
+    index value to a vector (of existing field entries). See \link{matchfuns}.}
+  \item{x, object}{a registry object.}
+  \item{\dots}{for \code{regobj$set_entry} and \code{regobj$modify_entry}:
+    named list of fields to be modified in or added to the registry,
+    including the index field(s) (see details).
+    For \code{grep_entries}: additional parameters passed to
+    \code{\link[base]{grep}}.
+    For \code{set_field}: additional parameters passed to the specified
+    match function.
+    For \code{get_entry}, \code{get_entries}
+    and the indexing functions: key values for the entry (entries)
+    to be looked up.}
+}
+\details{
+  \code{regobj} represents a registry object returned by
+  \code{\link{registry}} whose elements can be processed using
+    the following accessor functions:
+  
+  \code{get_field_names()} returns a character
+  vector with all field names. \code{get_field()} returns the information
+  for a specific field as a list with components named as described
+  above. \code{get_fields()} returns a list with all field
+  entries. \code{set_field()} is used to create new fields in the
+  repository (the default value will be set in all
+  entries).
+
+  \code{get_entry_names()} returns a character vector with (the first
+  alias of) all entries. \code{entry_exists()} is a predicate checking
+  if an entry with the specified alias exists in the
+  registry. \code{get_entry()} returns the first specified entry
+  if at least one exists (and, by
+  default, gives an error if it does not). \code{get_entries()} is used to
+  query more than one entry matching the index
+  (named argument list) exactly. \code{grep_entries()} returns those entries
+  where the regular expression in \code{pattern} matches \emph{any}
+  character field in an entry. By default, all values are
+  returned. \code{delete_entry} removes an existing entry from the
+  registry.
+  
+  \code{set_entry}, \code{delete_entry} and \code{modify_entry}
+  require a named list
+  of arguments used as field entries.
+  At least the index fields are required.
+
+  \code{set_entry}
+  will check for all other mandatory fields. If specified in the field
+  meta data, each field entry and the entry as a whole is checked for
+  validity. Note that it is possible to specify a vector of values for
+  an index field, treated as alternative keys for this entry.
+
+  It is possible to \emph{restrict} permissions (for setting, getting, deleting
+  and modifying entries) using \code{restrict_permissions}. Further, a
+  user can \emph{seal} the current registry state (fields, entries) so
+  that \emph{existing} structure and information becomes
+  immutable. Additional fields and entries can be changed according to the
+  permissions set. Permissions and sealing are useful for exported
+  registry objects to control the users' capabilities of
+  modifying/extending them.
+}
+\author{David Meyer \email{David.Meyer at R-project.org}}
+
+\seealso{\code{\link{dist}}, \link{matchfuns}}
+\examples{
+regobj <- registry()
+regobj$set_field("X", type = TRUE)
+regobj$set_field("Y", type = "character")
+regobj$set_field("index", type = "character", is_key = TRUE,
+            index_FUN = match_partial_ignorecase)
+regobj$set_field("index2", type = "integer", is_key = TRUE)
+regobj$set_entry(X = TRUE, Y = "bla", index = "test", index2 = 1L)
+regobj$set_entry(X = FALSE, Y = "foo", index = c("test", "bar"), index2 = 2L)
+regobj$get_entries("test")
+regobj[["test", 1]]
+regobj["test"]
+regobj[["test"]]
+}
+\keyword{data}% __ONLY ONE__ keyword per line
diff --git a/tests/registry.R b/tests/registry.R
new file mode 100755
index 0000000..265f3f5
--- /dev/null
+++ b/tests/registry.R
@@ -0,0 +1,2 @@
+library(registry)
+demo("registry")
diff --git a/vignettes/abbrvnat.bst b/vignettes/abbrvnat.bst
new file mode 100755
index 0000000..2068b0f
--- /dev/null
+++ b/vignettes/abbrvnat.bst
@@ -0,0 +1,1432 @@
+%% File: `abbrvnat.bst'
+%% A modification of `abbrv.bst' for use with natbib package 
+%%
+%% Copyright 1993-2005 Patrick W Daly
+%% Max-Planck-Institut f\"ur Sonnensystemforschung
+%% Max-Planck-Str. 2
+%% D-37191 Katlenburg-Lindau
+%% Germany
+%% E-mail: daly at mps.mpg.de
+%%
+%% This program can be redistributed and/or modified under the terms
+%% of the LaTeX Project Public License Distributed from CTAN
+%% archives in directory macros/latex/base/lppl.txt; either
+%% version 1 of the License, or any later version.
+%%
+ % Version and source file information:
+ % \ProvidesFile{natbst.mbs}[2005/01/07 1.8 (PWD)]
+ %
+ % BibTeX `plainnat' family
+ %   version 0.99b for BibTeX versions 0.99a or later,
+ %   for LaTeX versions 2.09 and 2e.
+ %
+ % For use with the `natbib.sty' package; emulates the corresponding
+ %   member of the `plain' family, but with author-year citations.
+ %
+ % With version 6.0 of `natbib.sty', it may also be used for numerical
+ %   citations, while retaining the commands \citeauthor, \citefullauthor,
+ %   and \citeyear to print the corresponding information.
+ %
+ % For version 7.0 of `natbib.sty', the KEY field replaces missing
+ %   authors/editors, and the date is left blank in \bibitem.
+ %
+ % Includes field EID for the sequence/citation number of electronic journals
+ %  which is used instead of page numbers.
+ %
+ % Includes fields ISBN and ISSN.
+ %
+ % Includes field URL for Internet addresses.
+ %
+ % Includes field DOI for Digital Object Idenfifiers.
+ %
+ % Works best with the url.sty package of Donald Arseneau.
+ %
+ % Works with identical authors and year are further sorted by
+ %   citation key, to preserve any natural sequence.
+ %
+ENTRY
+  { address
+    author
+    booktitle
+    chapter
+    doi
+    eid
+    edition
+    editor
+    howpublished
+    institution
+    isbn
+    issn
+    journal
+    key
+    month
+    note
+    number
+    organization
+    pages
+    publisher
+    school
+    series
+    title
+    type
+    url
+    volume
+    year
+  }
+  {}
+  { label extra.label sort.label short.list }
+
+INTEGERS { output.state before.all mid.sentence after.sentence after.block }
+
+FUNCTION {init.state.consts}
+{ #0 'before.all :=
+  #1 'mid.sentence :=
+  #2 'after.sentence :=
+  #3 'after.block :=
+}
+
+STRINGS { s t }
+
+FUNCTION {output.nonnull}
+{ 's :=
+  output.state mid.sentence =
+    { ", " * write$ }
+    { output.state after.block =
+        { add.period$ write$
+          newline$
+          "\newblock " write$
+        }
+        { output.state before.all =
+            'write$
+            { add.period$ " " * write$ }
+          if$
+        }
+      if$
+      mid.sentence 'output.state :=
+    }
+  if$
+  s
+}
+
+FUNCTION {output}
+{ duplicate$ empty$
+    'pop$
+    'output.nonnull
+  if$
+}
+
+FUNCTION {output.check}
+{ 't :=
+  duplicate$ empty$
+    { pop$ "empty " t * " in " * cite$ * warning$ }
+    'output.nonnull
+  if$
+}
+
+FUNCTION {fin.entry}
+{ add.period$
+  write$
+  newline$
+}
+
+FUNCTION {new.block}
+{ output.state before.all =
+    'skip$
+    { after.block 'output.state := }
+  if$
+}
+
+FUNCTION {new.sentence}
+{ output.state after.block =
+    'skip$
+    { output.state before.all =
+        'skip$
+        { after.sentence 'output.state := }
+      if$
+    }
+  if$
+}
+
+FUNCTION {not}
+{   { #0 }
+    { #1 }
+  if$
+}
+
+FUNCTION {and}
+{   'skip$
+    { pop$ #0 }
+  if$
+}
+
+FUNCTION {or}
+{   { pop$ #1 }
+    'skip$
+  if$
+}
+
+FUNCTION {new.block.checka}
+{ empty$
+    'skip$
+    'new.block
+  if$
+}
+
+FUNCTION {new.block.checkb}
+{ empty$
+  swap$ empty$
+  and
+    'skip$
+    'new.block
+  if$
+}
+
+FUNCTION {new.sentence.checka}
+{ empty$
+    'skip$
+    'new.sentence
+  if$
+}
+
+FUNCTION {new.sentence.checkb}
+{ empty$
+  swap$ empty$
+  and
+    'skip$
+    'new.sentence
+  if$
+}
+
+FUNCTION {field.or.null}
+{ duplicate$ empty$
+    { pop$ "" }
+    'skip$
+  if$
+}
+
+FUNCTION {emphasize}
+{ duplicate$ empty$
+    { pop$ "" }
+    { "\emph{" swap$ * "}" * }
+  if$
+}
+
+INTEGERS { nameptr namesleft numnames }
+
+FUNCTION {format.names}
+{ 's :=
+  #1 'nameptr :=
+  s num.names$ 'numnames :=
+  numnames 'namesleft :=
+    { namesleft #0 > }
+    { s nameptr "{f.~}{vv~}{ll}{, jj}" format.name$ 't :=
+      nameptr #1 >
+        { namesleft #1 >
+            { ", " * t * }
+            { numnames #2 >
+                { "," * }
+                'skip$
+              if$
+              t "others" =
+                { " et~al." * }
+                { " and " * t * }
+              if$
+            }
+          if$
+        }
+        't
+      if$
+      nameptr #1 + 'nameptr :=
+      namesleft #1 - 'namesleft :=
+    }
+  while$
+}
+
+FUNCTION {format.key}
+{ empty$
+    { key field.or.null }
+    { "" }
+  if$
+}
+
+FUNCTION {format.authors}
+{ author empty$
+    { "" }
+    { author format.names }
+  if$
+}
+
+FUNCTION {format.editors}
+{ editor empty$
+    { "" }
+    { editor format.names
+      editor num.names$ #1 >
+        { ", editors" * }
+        { ", editor" * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.isbn}
+{ isbn empty$
+    { "" }
+    { new.block "ISBN " isbn * }
+  if$
+}
+
+FUNCTION {format.issn}
+{ issn empty$
+    { "" }
+    { new.block "ISSN " issn * }
+  if$
+}
+
+FUNCTION {format.url}
+{ url empty$
+    { "" }
+    { new.block "URL \url{" url * "}" * }
+  if$
+}
+
+FUNCTION {format.doi}
+{ doi empty$
+    { "" }
+    { new.block "\doi{" doi * "}" * }
+  if$
+}
+
+FUNCTION {format.title}
+{ title empty$
+    { "" }
+    { title "t" change.case$ }
+  if$
+}
+
+FUNCTION {format.full.names}
+{'s :=
+  #1 'nameptr :=
+  s num.names$ 'numnames :=
+  numnames 'namesleft :=
+    { namesleft #0 > }
+    { s nameptr
+      "{vv~}{ll}" format.name$ 't :=
+      nameptr #1 >
+        {
+          namesleft #1 >
+            { ", " * t * }
+            {
+              numnames #2 >
+                { "," * }
+                'skip$
+              if$
+              t "others" =
+                { " et~al." * }
+                { " and " * t * }
+              if$
+            }
+          if$
+        }
+        't
+      if$
+      nameptr #1 + 'nameptr :=
+      namesleft #1 - 'namesleft :=
+    }
+  while$
+}
+
+FUNCTION {author.editor.full}
+{ author empty$
+    { editor empty$
+        { "" }
+        { editor format.full.names }
+      if$
+    }
+    { author format.full.names }
+  if$
+}
+
+FUNCTION {author.full}
+{ author empty$
+    { "" }
+    { author format.full.names }
+  if$
+}
+
+FUNCTION {editor.full}
+{ editor empty$
+    { "" }
+    { editor format.full.names }
+  if$
+}
+
+FUNCTION {make.full.names}
+{ type$ "book" =
+  type$ "inbook" =
+  or
+    'author.editor.full
+    { type$ "proceedings" =
+        'editor.full
+        'author.full
+      if$
+    }
+  if$
+}
+
+FUNCTION {output.bibitem}
+{ newline$
+  "\bibitem[" write$
+  label write$
+  ")" make.full.names duplicate$ short.list =
+     { pop$ }
+     { * }
+   if$
+  "]{" * write$
+  cite$ write$
+  "}" write$
+  newline$
+  ""
+  before.all 'output.state :=
+}
+
+FUNCTION {n.dashify}
+{ 't :=
+  ""
+    { t empty$ not }
+    { t #1 #1 substring$ "-" =
+        { t #1 #2 substring$ "--" = not
+            { "--" *
+              t #2 global.max$ substring$ 't :=
+            }
+            {   { t #1 #1 substring$ "-" = }
+                { "-" *
+                  t #2 global.max$ substring$ 't :=
+                }
+              while$
+            }
+          if$
+        }
+        { t #1 #1 substring$ *
+          t #2 global.max$ substring$ 't :=
+        }
+      if$
+    }
+  while$
+}
+
+FUNCTION {format.date}
+{ year duplicate$ empty$
+    { "empty year in " cite$ * warning$
+       pop$ "" }
+    'skip$
+  if$
+  month empty$
+    'skip$
+    { month
+      " " * swap$ *
+    }
+  if$
+  extra.label *
+}
+
+FUNCTION {format.btitle}
+{ title emphasize
+}
+
+FUNCTION {tie.or.space.connect}
+{ duplicate$ text.length$ #3 <
+    { "~" }
+    { " " }
+  if$
+  swap$ * *
+}
+
+FUNCTION {either.or.check}
+{ empty$
+    'pop$
+    { "can't use both " swap$ * " fields in " * cite$ * warning$ }
+  if$
+}
+
+FUNCTION {format.bvolume}
+{ volume empty$
+    { "" }
+    { "volume" volume tie.or.space.connect
+      series empty$
+        'skip$
+        { " of " * series emphasize * }
+      if$
+      "volume and number" number either.or.check
+    }
+  if$
+}
+
+FUNCTION {format.number.series}
+{ volume empty$
+    { number empty$
+        { series field.or.null }
+        { output.state mid.sentence =
+            { "number" }
+            { "Number" }
+          if$
+          number tie.or.space.connect
+          series empty$
+            { "there's a number but no series in " cite$ * warning$ }
+            { " in " * series * }
+          if$
+        }
+      if$
+    }
+    { "" }
+  if$
+}
+
+FUNCTION {format.edition}
+{ edition empty$
+    { "" }
+    { output.state mid.sentence =
+        { edition "l" change.case$ " edition" * }
+        { edition "t" change.case$ " edition" * }
+      if$
+    }
+  if$
+}
+
+INTEGERS { multiresult }
+
+FUNCTION {multi.page.check}
+{ 't :=
+  #0 'multiresult :=
+    { multiresult not
+      t empty$ not
+      and
+    }
+    { t #1 #1 substring$
+      duplicate$ "-" =
+      swap$ duplicate$ "," =
+      swap$ "+" =
+      or or
+        { #1 'multiresult := }
+        { t #2 global.max$ substring$ 't := }
+      if$
+    }
+  while$
+  multiresult
+}
+
+FUNCTION {format.pages}
+{ pages empty$
+    { "" }
+    { pages multi.page.check
+        { "pages" pages n.dashify tie.or.space.connect }
+        { "page" pages tie.or.space.connect }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.eid}
+{ eid empty$
+    { "" }
+    { "art." eid tie.or.space.connect }
+  if$
+}
+
+FUNCTION {format.vol.num.pages}
+{ volume field.or.null
+  number empty$
+    'skip$
+    { "\penalty0 (" number * ")" * *
+      volume empty$
+        { "there's a number but no volume in " cite$ * warning$ }
+        'skip$
+      if$
+    }
+  if$
+  pages empty$
+    'skip$
+    { duplicate$ empty$
+        { pop$ format.pages }
+        { ":\penalty0 " * pages n.dashify * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.vol.num.eid}
+{ volume field.or.null
+  number empty$
+    'skip$
+    { "\penalty0 (" number * ")" * *
+      volume empty$
+        { "there's a number but no volume in " cite$ * warning$ }
+        'skip$
+      if$
+    }
+  if$
+  eid empty$
+    'skip$
+    { duplicate$ empty$
+        { pop$ format.eid }
+        { ":\penalty0 " * eid * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.chapter.pages}
+{ chapter empty$
+    'format.pages
+    { type empty$
+        { "chapter" }
+        { type "l" change.case$ }
+      if$
+      chapter tie.or.space.connect
+      pages empty$
+        'skip$
+        { ", " * format.pages * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.in.ed.booktitle}
+{ booktitle empty$
+    { "" }
+    { editor empty$
+        { "In " booktitle emphasize * }
+        { "In " format.editors * ", " * booktitle emphasize * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {empty.misc.check}
+{ author empty$ title empty$ howpublished empty$
+  month empty$ year empty$ note empty$
+  and and and and and
+  key empty$ not and
+    { "all relevant fields are empty in " cite$ * warning$ }
+    'skip$
+  if$
+}
+
+FUNCTION {format.thesis.type}
+{ type empty$
+    'skip$
+    { pop$
+      type "t" change.case$
+    }
+  if$
+}
+
+FUNCTION {format.tr.number}
+{ type empty$
+    { "Technical Report" }
+    'type
+  if$
+  number empty$
+    { "t" change.case$ }
+    { number tie.or.space.connect }
+  if$
+}
+
+FUNCTION {format.article.crossref}
+{ key empty$
+    { journal empty$
+        { "need key or journal for " cite$ * " to crossref " * crossref *
+          warning$
+          ""
+        }
+        { "In \emph{" journal * "}" * }
+      if$
+    }
+    { "In " key * }
+  if$
+  " \citep{" * crossref * "}" *
+}
+
+FUNCTION {format.book.crossref}
+{ volume empty$
+    { "empty volume in " cite$ * "'s crossref of " * crossref * warning$
+      "In "
+    }
+    { "Volume" volume tie.or.space.connect
+      " of " *
+    }
+  if$
+  editor empty$
+  editor field.or.null author field.or.null =
+  or
+    { key empty$
+        { series empty$
+            { "need editor, key, or series for " cite$ * " to crossref " *
+              crossref * warning$
+              "" *
+            }
+            { "\emph{" * series * "}" * }
+          if$
+        }
+        { key * }
+      if$
+    }
+    'skip$
+  if$
+  ", \citet{" * crossref * "}" *
+}
+
+FUNCTION {format.incoll.inproc.crossref}
+{ editor empty$
+  editor field.or.null author field.or.null =
+  or
+    { key empty$
+        { booktitle empty$
+            { "need editor, key, or booktitle for " cite$ * " to crossref " *
+              crossref * warning$
+              ""
+            }
+            { "In \emph{" booktitle * "}" * }
+          if$
+        }
+        { "In " key * }
+      if$
+    }
+    { "In " }
+  if$
+  " \citet{" * crossref * "}" *
+}
+
+FUNCTION {article}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  new.block
+  format.title "title" output.check
+  new.block
+  crossref missing$
+    { journal emphasize "journal" output.check
+      eid empty$
+        { format.vol.num.pages output }
+        { format.vol.num.eid output }
+      if$
+      format.date "year" output.check
+    }
+    { format.article.crossref output.nonnull
+      eid empty$
+        { format.pages output }
+        { format.eid output }
+      if$
+    }
+  if$
+  format.issn output
+  format.doi output
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {book}
+{ output.bibitem
+  author empty$
+    { format.editors "author and editor" output.check
+      editor format.key output
+    }
+    { format.authors output.nonnull
+      crossref missing$
+        { "author and editor" editor either.or.check }
+        'skip$
+      if$
+    }
+  if$
+  new.block
+  format.btitle "title" output.check
+  crossref missing$
+    { format.bvolume output
+      new.block
+      format.number.series output
+      new.sentence
+      publisher "publisher" output.check
+      address output
+    }
+    { new.block
+      format.book.crossref output.nonnull
+    }
+  if$
+  format.edition output
+  format.date "year" output.check
+  format.isbn output
+  format.doi output
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {booklet}
+{ output.bibitem
+  format.authors output
+  author format.key output
+  new.block
+  format.title "title" output.check
+  howpublished address new.block.checkb
+  howpublished output
+  address output
+  format.date output
+  format.isbn output
+  format.doi output
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {inbook}
+{ output.bibitem
+  author empty$
+    { format.editors "author and editor" output.check
+      editor format.key output
+    }
+    { format.authors output.nonnull
+      crossref missing$
+        { "author and editor" editor either.or.check }
+        'skip$
+      if$
+    }
+  if$
+  new.block
+  format.btitle "title" output.check
+  crossref missing$
+    { format.bvolume output
+      format.chapter.pages "chapter and pages" output.check
+      new.block
+      format.number.series output
+      new.sentence
+      publisher "publisher" output.check
+      address output
+    }
+    { format.chapter.pages "chapter and pages" output.check
+      new.block
+      format.book.crossref output.nonnull
+    }
+  if$
+  format.edition output
+  format.date "year" output.check
+  format.isbn output
+  format.doi output
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {incollection}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  new.block
+  format.title "title" output.check
+  new.block
+  crossref missing$
+    { format.in.ed.booktitle "booktitle" output.check
+      format.bvolume output
+      format.number.series output
+      format.chapter.pages output
+      new.sentence
+      publisher "publisher" output.check
+      address output
+      format.edition output
+      format.date "year" output.check
+    }
+    { format.incoll.inproc.crossref output.nonnull
+      format.chapter.pages output
+    }
+  if$
+  format.isbn output
+  format.doi output
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {inproceedings}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  new.block
+  format.title "title" output.check
+  new.block
+  crossref missing$
+    { format.in.ed.booktitle "booktitle" output.check
+      format.bvolume output
+      format.number.series output
+      format.pages output
+      address empty$
+        { organization publisher new.sentence.checkb
+          organization output
+          publisher output
+          format.date "year" output.check
+        }
+        { address output.nonnull
+          format.date "year" output.check
+          new.sentence
+          organization output
+          publisher output
+        }
+      if$
+    }
+    { format.incoll.inproc.crossref output.nonnull
+      format.pages output
+    }
+  if$
+  format.isbn output
+  format.doi output
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {conference} { inproceedings }
+
+FUNCTION {manual}
+{ output.bibitem
+  format.authors output
+  author format.key output
+  new.block
+  format.btitle "title" output.check
+  organization address new.block.checkb
+  organization output
+  address output
+  format.edition output
+  format.date output
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {mastersthesis}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  new.block
+  format.title "title" output.check
+  new.block
+  "Master's thesis" format.thesis.type output.nonnull
+  school "school" output.check
+  address output
+  format.date "year" output.check
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {misc}
+{ output.bibitem
+  format.authors output
+  author format.key output
+  title howpublished new.block.checkb
+  format.title output
+  howpublished new.block.checka
+  howpublished output
+  format.date output
+  format.issn output
+  format.url output
+  new.block
+  note output
+  fin.entry
+  empty.misc.check
+}
+
+FUNCTION {phdthesis}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  new.block
+  format.btitle "title" output.check
+  new.block
+  "PhD thesis" format.thesis.type output.nonnull
+  school "school" output.check
+  address output
+  format.date "year" output.check
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {proceedings}
+{ output.bibitem
+  format.editors output
+  editor format.key output
+  new.block
+  format.btitle "title" output.check
+  format.bvolume output
+  format.number.series output
+  address output
+  format.date "year" output.check
+  new.sentence
+  organization output
+  publisher output
+  format.isbn output
+  format.doi output
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {techreport}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  new.block
+  format.title "title" output.check
+  new.block
+  format.tr.number output.nonnull
+  institution "institution" output.check
+  address output
+  format.date "year" output.check
+  format.url output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {unpublished}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  new.block
+  format.title "title" output.check
+  format.url output
+  new.block
+  note "note" output.check
+  format.date output
+  fin.entry
+}
+
+FUNCTION {default.type} { misc }
+
+
+MACRO {jan} {"Jan."}
+
+MACRO {feb} {"Feb."}
+
+MACRO {mar} {"Mar."}
+
+MACRO {apr} {"Apr."}
+
+MACRO {may} {"May"}
+
+MACRO {jun} {"June"}
+
+MACRO {jul} {"July"}
+
+MACRO {aug} {"Aug."}
+
+MACRO {sep} {"Sept."}
+
+MACRO {oct} {"Oct."}
+
+MACRO {nov} {"Nov."}
+
+MACRO {dec} {"Dec."}
+
+
+
+MACRO {acmcs} {"ACM Comput. Surv."}
+
+MACRO {acta} {"Acta Inf."}
+
+MACRO {cacm} {"Commun. ACM"}
+
+MACRO {ibmjrd} {"IBM J. Res. Dev."}
+
+MACRO {ibmsj} {"IBM Syst.~J."}
+
+MACRO {ieeese} {"IEEE Trans. Softw. Eng."}
+
+MACRO {ieeetc} {"IEEE Trans. Comput."}
+
+MACRO {ieeetcad}
+ {"IEEE Trans. Comput.-Aided Design Integrated Circuits"}
+
+MACRO {ipl} {"Inf. Process. Lett."}
+
+MACRO {jacm} {"J.~ACM"}
+
+MACRO {jcss} {"J.~Comput. Syst. Sci."}
+
+MACRO {scp} {"Sci. Comput. Programming"}
+
+MACRO {sicomp} {"SIAM J. Comput."}
+
+MACRO {tocs} {"ACM Trans. Comput. Syst."}
+
+MACRO {tods} {"ACM Trans. Database Syst."}
+
+MACRO {tog} {"ACM Trans. Gr."}
+
+MACRO {toms} {"ACM Trans. Math. Softw."}
+
+MACRO {toois} {"ACM Trans. Office Inf. Syst."}
+
+MACRO {toplas} {"ACM Trans. Prog. Lang. Syst."}
+
+MACRO {tcs} {"Theoretical Comput. Sci."}
+
+
+READ
+
+FUNCTION {sortify}
+{ purify$
+  "l" change.case$
+}
+
+INTEGERS { len }
+
+FUNCTION {chop.word}
+{ 's :=
+  'len :=
+  s #1 len substring$ =
+    { s len #1 + global.max$ substring$ }
+    's
+  if$
+}
+
+FUNCTION {format.lab.names}
+{ 's :=
+  s #1 "{vv~}{ll}" format.name$
+  s num.names$ duplicate$
+  #2 >
+    { pop$ " et~al." * }
+    { #2 <
+        'skip$
+        { s #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" =
+            { " et~al." * }
+            { " and " * s #2 "{vv~}{ll}" format.name$ * }
+          if$
+        }
+      if$
+    }
+  if$
+}
+
+FUNCTION {author.key.label}
+{ author empty$
+    { key empty$
+        { cite$ #1 #3 substring$ }
+        'key
+      if$
+    }
+    { author format.lab.names }
+  if$
+}
+
+FUNCTION {author.editor.key.label}
+{ author empty$
+    { editor empty$
+        { key empty$
+            { cite$ #1 #3 substring$ }
+            'key
+          if$
+        }
+        { editor format.lab.names }
+      if$
+    }
+    { author format.lab.names }
+  if$
+}
+
+FUNCTION {author.key.organization.label}
+{ author empty$
+    { key empty$
+        { organization empty$
+            { cite$ #1 #3 substring$ }
+            { "The " #4 organization chop.word #3 text.prefix$ }
+          if$
+        }
+        'key
+      if$
+    }
+    { author format.lab.names }
+  if$
+}
+
+FUNCTION {editor.key.organization.label}
+{ editor empty$
+    { key empty$
+        { organization empty$
+            { cite$ #1 #3 substring$ }
+            { "The " #4 organization chop.word #3 text.prefix$ }
+          if$
+        }
+        'key
+      if$
+    }
+    { editor format.lab.names }
+  if$
+}
+
+FUNCTION {calc.short.authors}
+{ type$ "book" =
+  type$ "inbook" =
+  or
+    'author.editor.key.label
+    { type$ "proceedings" =
+        'editor.key.organization.label
+        { type$ "manual" =
+            'author.key.organization.label
+            'author.key.label
+          if$
+        }
+      if$
+    }
+  if$
+  'short.list :=
+}
+
+FUNCTION {calc.label}
+{ calc.short.authors
+  short.list
+  "("
+  *
+  year duplicate$ empty$
+  short.list key field.or.null = or
+     { pop$ "" }
+     'skip$
+  if$
+  *
+  'label :=
+}
+
+FUNCTION {sort.format.names}
+{ 's :=
+  #1 'nameptr :=
+  ""
+  s num.names$ 'numnames :=
+  numnames 'namesleft :=
+    { namesleft #0 > }
+    {
+      s nameptr "{vv{ } }{ll{ }}{  f{ }}{  jj{ }}" format.name$ 't :=
+      nameptr #1 >
+        {
+          "   "  *
+          namesleft #1 = t "others" = and
+            { "zzzzz" * }
+            { numnames #2 > nameptr #2 = and
+                { "zz" * year field.or.null * "   " * }
+                'skip$
+              if$
+              t sortify *
+            }
+          if$
+        }
+        { t sortify * }
+      if$
+      nameptr #1 + 'nameptr :=
+      namesleft #1 - 'namesleft :=
+    }
+  while$
+}
+
+FUNCTION {sort.format.title}
+{ 't :=
+  "A " #2
+    "An " #3
+      "The " #4 t chop.word
+    chop.word
+  chop.word
+  sortify
+  #1 global.max$ substring$
+}
+
+FUNCTION {author.sort}
+{ author empty$
+    { key empty$
+        { "to sort, need author or key in " cite$ * warning$
+          ""
+        }
+        { key sortify }
+      if$
+    }
+    { author sort.format.names }
+  if$
+}
+
+FUNCTION {author.editor.sort}
+{ author empty$
+    { editor empty$
+        { key empty$
+            { "to sort, need author, editor, or key in " cite$ * warning$
+              ""
+            }
+            { key sortify }
+          if$
+        }
+        { editor sort.format.names }
+      if$
+    }
+    { author sort.format.names }
+  if$
+}
+
+FUNCTION {author.organization.sort}
+{ author empty$
+    { organization empty$
+        { key empty$
+            { "to sort, need author, organization, or key in " cite$ * warning$
+              ""
+            }
+            { key sortify }
+          if$
+        }
+        { "The " #4 organization chop.word sortify }
+      if$
+    }
+    { author sort.format.names }
+  if$
+}
+
+FUNCTION {editor.organization.sort}
+{ editor empty$
+    { organization empty$
+        { key empty$
+            { "to sort, need editor, organization, or key in " cite$ * warning$
+              ""
+            }
+            { key sortify }
+          if$
+        }
+        { "The " #4 organization chop.word sortify }
+      if$
+    }
+    { editor sort.format.names }
+  if$
+}
+
+
+FUNCTION {presort}
+{ calc.label
+  label sortify
+  "    "
+  *
+  type$ "book" =
+  type$ "inbook" =
+  or
+    'author.editor.sort
+    { type$ "proceedings" =
+        'editor.organization.sort
+        { type$ "manual" =
+            'author.organization.sort
+            'author.sort
+          if$
+        }
+      if$
+    }
+  if$
+  "    "
+  *
+  cite$
+  *
+  #1 entry.max$ substring$
+  'sort.label :=
+  sort.label *
+  #1 entry.max$ substring$
+  'sort.key$ :=
+}
+
+ITERATE {presort}
+
+SORT
+
+STRINGS { longest.label last.label next.extra }
+
+INTEGERS { longest.label.width last.extra.num number.label }
+
+FUNCTION {initialize.longest.label}
+{ "" 'longest.label :=
+  #0 int.to.chr$ 'last.label :=
+  "" 'next.extra :=
+  #0 'longest.label.width :=
+  #0 'last.extra.num :=
+  #0 'number.label :=
+}
+
+FUNCTION {forward.pass}
+{ last.label label =
+    { last.extra.num #1 + 'last.extra.num :=
+      last.extra.num int.to.chr$ 'extra.label :=
+    }
+    { "a" chr.to.int$ 'last.extra.num :=
+      "" 'extra.label :=
+      label 'last.label :=
+    }
+  if$
+  number.label #1 + 'number.label :=
+}
+
+FUNCTION {reverse.pass}
+{ next.extra "b" =
+    { "a" 'extra.label := }
+    'skip$
+  if$
+  extra.label 'next.extra :=
+  extra.label
+  duplicate$ empty$
+    'skip$
+    { "{\natexlab{" swap$ * "}}" * }
+  if$
+  'extra.label :=
+  label extra.label * 'label :=
+}
+
+EXECUTE {initialize.longest.label}
+
+ITERATE {forward.pass}
+
+REVERSE {reverse.pass}
+
+FUNCTION {bib.sort.order}
+{ sort.label  'sort.key$ :=
+}
+
+ITERATE {bib.sort.order}
+
+SORT
+
+FUNCTION {begin.bib}
+{   preamble$ empty$
+    'skip$
+    { preamble$ write$ newline$ }
+  if$
+  "\begin{thebibliography}{" number.label int.to.str$ * "}" *
+  write$ newline$
+  "\providecommand{\natexlab}[1]{#1}"
+  write$ newline$
+  "\providecommand{\url}[1]{\texttt{#1}}"
+  write$ newline$
+  "\expandafter\ifx\csname urlstyle\endcsname\relax"
+  write$ newline$
+  "  \providecommand{\doi}[1]{doi: #1}\else"
+  write$ newline$
+  "  \providecommand{\doi}{doi: \begingroup \urlstyle{rm}\Url}\fi"
+  write$ newline$
+}
+
+EXECUTE {begin.bib}
+
+EXECUTE {init.state.consts}
+
+ITERATE {call.type$}
+
+FUNCTION {end.bib}
+{ newline$
+  "\end{thebibliography}" write$ newline$
+}
+
+EXECUTE {end.bib}
diff --git a/vignettes/registry.Rnw b/vignettes/registry.Rnw
new file mode 100755
index 0000000..aa04475
--- /dev/null
+++ b/vignettes/registry.Rnw
@@ -0,0 +1,313 @@
+\documentclass[a4paper]{article}
+\usepackage[round,longnamesfirst]{natbib}
+\usepackage{graphicx,keyval,thumbpdf,a4wide,makeidx,color,colordvi}
+\usepackage{amsfonts,hyperref}
+\usepackage[utf8]{inputenc}
+\DeclareUnicodeCharacter{201C}{"}
+\DeclareUnicodeCharacter{201D}{"}
+
+\newcommand\R{\textsf{R}}
+\newcommand{\pkg}[1]{{\normalfont\fontseries{b}\selectfont #1}}
+\newcommand{\sQuote}[1]{`{#1}'}
+\newcommand{\dQuote}[1]{``{#1}''}
+\newcommand{\file}[1]{\sQuote{\textsf{#1}}}
+\newcommand{\data}[1]{\texttt{#1}}
+\newcommand{\var}[1]{\textit{#1}}
+\newcommand{\class}[1]{\textsf{#1}}
+\newcommand{\proglang}[1]{\textsf{#1}}
+%% \code without `-' ligatures
+\def\nohyphenation{\hyphenchar\font=-1 \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font=`-}
+{\catcode`\-=\active%
+  \global\def\code{\bgroup%
+    \catcode`\-=\active \let-\codedash%
+    \Rd at code}}
+\def\codedash{-\discretionary{}{}{}}
+\def\Rd at code#1{\texttt{\nohyphenation#1}\egroup}
+\newcommand{\codefun}[1]{\code{#1()}}
+\newcommand{\codefunind}[1]{\codefun{#1}\index{\texttt{#1}}}
+\newcommand{\codeind}[1]{\code{#1}\index{\texttt{#1}}}
+
+\SweaveOpts{strip.white=true}
+
+\definecolor{Blue}{rgb}{0,0,0.8}
+\definecolor{Red}{rgb}{0.7,0,0}
+
+\date{2009-02-17}
+\title{A Generic Registry Infrastructure for \R}
+\author{David Meyer}
+%\VignetteIndexEntry{Registry}
+%\VignetteDepends{registry}
+%\VignetteKeywords{registry}
+%\VignettePackage{registry}
+
+\makeindex{}
+
+\sloppy{}
+
+\begin{document}
+\maketitle
+
+% \begin{abstract}
+% This document introduces a generic registry infrastructure for \R,
+% provided by the \pkg{registry} package.
+% \end{abstract}
+
+<<echo=FALSE>>=
+options(width = 80)
+library("registry")
+@ %
+
+\section{Introduction}
+\label{sec:introduction}
+
+More and more, \R~packages are offering dynamic functionality,
+allowing users to extend a \dQuote{repository} of initial features or
+data. For example, the \pkg{proxy} package \citep{registry:meyer+buchta:2008}
+provides an enhanced
+\codefun{dist} function for computing dissimilarity matrices,
+allowing to choose among several proximity
+measures stored in a registry. Each entry is composed of a small
+workhorse function and some meta data including, e.g., a character vector
+of aliases, literature references, the formula in plain text,
+a function to coerce
+between similarity and distance, and a type categorization
+(binary, metric, etc.). Users can add new proximity measures to the
+registry at run-time and immediately use them without recreating the
+package, specifying one of the aliases defined in the meta data.
+Similarly, the \pkg{relations} \citep{registry:hornik+meyer:2008}
+and \pkg{CLUE} \citep{registry:hornik:2005,registry:hornik:2007}
+packages use simple
+registries internally to link some meta data to available functions,
+used by the high-level consensus ranking and cluster ensemble
+functions, respectively.
+
+Such a registry, whether exposed to the user or not, is conceptually a
+small in-memory data base where entries with a common field structure are
+stored and retrieved and whose fields can be of mixed type.
+At first sight, a data frame seems to be the
+data structure of choice for an appropriate implementation.
+Unfortunately, data frames are inconvenient to use
+with factors, functions, or other recursive types such as lists
+due to automatic coercions taking place behind the scenes. In fact, a
+simpler, record-like structure such as a list with named components
+(\dQuote{fields}) appears more practical. Also,
+features known from \dQuote{real} data bases such as compound keys,
+validity checking of new entries, and use of access rights are not
+available by default and need to be \dQuote{reinvented} every time
+they are needed.
+
+The \pkg{registry} package provides a simple mechanism for defining
+and manipulating user-extensible registry objects. A typical
+use case in the context of an \R~package could include the following steps:
+
+\begin{enumerate}
+\item Create one or more registry objects inside the package's namespace.
+\item Insert entries to the registry.
+\item Possibly, \dQuote{seal} the entries and set access rights.
+\item Possibly, export the registry object to the user level.
+\item Browse and retrieve entries from the registry.
+\end{enumerate}
+
+In the following, we explain these steps in more detail:
+first, how a registry can be set up; second, how entries
+can be added, modified and retrieved; and third, how a registry can be
+sealed and restricted through the definition of access rights.
+
+\section{Creating Registries}
+
+A registry basically is a container (implemented in \R~as an
+environment), along with some access functions. A new object of class
+\code{registry} can simply be created using the \codefun{registry} function:
+<<>>=
+library(registry)
+R <- registry()
+print(R)
+@
+Optional parameters include the specification of an (additional) class
+for the created registry object and the individual entries,
+as well as the specification of some validity function checking new
+entries to be added to the registry.
+
+In the following, we will use the example of a simple address book,
+whose entries include first and last name, address, age, home/cell
+phone number, and a business/private classification.
+Last and first name build the search key. Age is an
+optional integer in the range of 1 and
+99. Additionally, at least one phone number should be added to the registry.
+
+We start by creating two simple validity functions. The first one, to
+be specified at field level later on, checks a given age:
+<<>>=
+checkAge <- function(x) stopifnot(is.na(x) || x > 0 && x < 100)
+@
+The second one, specified at registry level,
+checks whether a given registry entry (list of named components)
+contains at least one phone number:
+<<>>=
+checkPhone <- function(x) stopifnot(!is.na(x$mobile) || !is.na(x$home))
+@
+Next, we create a registry of class \code{Addressbook} (inheriting
+from \code{registry}), containing entries of class \code{Address} and
+using the above validity function.
+<<>>=
+R <- registry(registry_class = "Addressbook", entry_class = "Address",
+              validity_FUN = checkPhone)
+@
+The additional class for the registry allows, e.g., user-defined printing:
+<<>>=
+print.Addressbook <-
+function(x, ...) {
+    writeLines(sprintf("An address book with %i entries.\n", length(x)))
+    invisible(x)
+}
+print(R)
+@
+
+At this stage, we are ready to set up the field information. First and last
+names are mandatory character fields, uniquely identifying an entry
+(key fields). Lookups should work with partial completion, ignoring case:
+<<>>=
+R$set_field("last", type = "character", is_key = TRUE, index_FUN = match_partial_ignorecase)
+R$set_field("first", type = "character", is_key = TRUE, index_FUN = match_partial_ignorecase)
+@
+The address is also character, but optional:
+<<>>=
+R$set_field("address", type = "character")
+@
+At least one phone number (character) is required. This can be
+achieved by making them optional, and using the validity
+function specified at the registry level to check whether one of them is empty:
+<<>>=
+R$set_field("mobile", type = "character")
+R$set_field("home", type = "character")
+@
+The age field is an optional integer with a defined range, checked by
+the field-level validity function:
+<<>>=
+R$set_field("age", type = "integer", validity_FUN = checkAge)
+@
+Finally, the business/private category is defined by specifying the
+possible alternatives (\code{Business} is set as default):
+<<>>=
+R$set_field("type", type = "character",
+            alternatives = c("Business", "Private"),
+            default = "Business")
+@
+The setup for a field can be retrieved using \codefun{get\_field}:
+<<>>=
+R$get_field("type")
+@
+\codefun{get\_fields} returns the complete list.
+
+\section{Using Registries}
+
+We now can start adding entries to the registry:
+<<>>=
+R$set_entry(last = "Smith", first = "Mary", address = "Vienna",
+            home = "734 43 34", type = "Private", age = 44L)
+R$set_entry(last = "Smith", first = "Peter", address = "New York",
+            mobile = "878 78 87")
+@
+If all field values are specified, the field names can be omitted:
+<<>>=
+R$set_entry("Myers", "John", "Washington", "52 32 34", "898 89 99",
+            33L, "Business")
+@
+Duplicate or invalid entries are not accepted:
+<<>>=
+TRY <- function(expr) tryCatch(expr, error = print)
+TRY(R$set_entry(last = "Smith", first = "Mary"))
+TRY(R$set_entry(last = "Miller", first = "Henry"))
+TRY(R$set_entry(last = "Miller", first = "Henry", age = 12.5))
+TRY(R$set_entry(last = "Miller", first = "Henry", age = 999L))
+@
+A single entry can be retrieved using \codefun{get\_entry}:
+<<>>=
+R$get_entry(last = "Smith", first = "mar")
+@
+Since returned entries inherit from \code{Address}, we can provide a
+user-defined print method:
+<<>>=
+print.Address <- function(x) with(x,
+    writeLines(sprintf("%s %s, %s; home: %s, mobile: %s; age: %i (%s)", first, last, address, home, mobile, age, type)))
+R$get_entry(last = "Smith", first = "mar")
+@
+Note that even though
+the first name of Mary Smith is incompletely specified and in
+lower case, the lookup is still successful
+because of the partial matching indexing function. The \code{[[} operator
+can be used as an alternative to \codefun{get\_entry}:
+<<>>=
+R[["Myers"]]
+@
+For Myers, the last name uniquely identifies the entry, so
+the first name can be omitted. Key values can have alternative values:
+<<>>=
+R$set_entry(last = "Frears", first = c("Joe", "Jonathan"),
+            address = "Washington", home = "721 42 34")
+@
+Either of them can be used for retrieval:
+<<>>=
+identical(R[["Frears", "Jonathan"]], R[["Frears", "Joe"]])
+@
+Unsuccessful lookups result in a
+return of \code{NULL}. Multiple  entries can be retrieved
+using the \codefun{get\_entries} accessing function. They are returned
+in a list whose component names are generated from the key values:
+<<>>=
+R$get_entries("Smith")
+@
+Full-text search in all information is provided by \codefun{grep\_entries}:
+<<>>=
+R$grep_entries("Priv")
+@
+A list of all entries can be obtained using either of:
+<<eval=FALSE>>=
+R$get_entries()
+R[]
+@
+The summary method for registry objects returns a data frame:
+<<>>=
+summary(R)
+@
+Entries can also be modified using \codefun{modify\_entry}, specifying
+key and new field values:
+<<>>=
+R[["Smith", "Peter"]]
+R$modify_entry(last = "Smith", first = "Peter", age = 22L)
+R[["Smith", "Peter"]]
+@
+Finally, entries can be removed using \codefun{delete\_entry}:
+<<>>=
+R$delete_entry(last = "Smith", first = "Peter")
+R[["Smith", "Peter"]]
+@
+
+\section{Sealing Registries and Setting Access Rights}
+
+Occasionally, developers might want to protect a registry that ships
+with some package to prevent accidental deletions or
+alterations. For this, \pkg{registry} offers two mechanisms: first, a
+registry object can be \dQuote{sealed} to prevent modifications of
+\emph{existing} data:
+<<>>=
+R$seal_entries()
+TRY(R$delete_entry("Smith", "Mary"))
+R$set_entry(last = "Slater", first = "Christian", address = "Boston",
+            mobile = "766 23 88")
+R[["Slater"]]
+@
+Second, the access permissions for registries can be restricted:
+<<>>=
+R$get_permissions()
+R$restrict_permissions(delete_entries = FALSE)
+TRY(R$delete_entry("Slater"))
+R$modify_entry(last = "Slater", first = "Christian", age = 44L)
+R[["Slater"]]
+@
+
+\bibliographystyle{abbrvnat}
+\bibliography{registry}
+
+\end{document}
diff --git a/vignettes/registry.bib b/vignettes/registry.bib
new file mode 100755
index 0000000..03d2f0a
--- /dev/null
+++ b/vignettes/registry.bib
@@ -0,0 +1,33 @@
+ at Manual{registry:meyer+buchta:2008,
+  title	       = {proxy: Distance and Similarity Measures},
+  author       = {David Meyer and Christian Buchta},
+  year	       = 2008,
+  note	       = {R package version 0.4-1}
+}
+
+ at Manual{registry:hornik:2007,
+  title	       = {clue: Cluster ensembles},
+  author       = {Kurt Hornik},
+  year	       = 2007,
+  note	       = {R package version 0.3-20.},
+  url	       = {http://CRAN.R-project.org/}
+}
+
+ at Article{registry:hornik:2005,
+  title	       = {A {CLUE} for {CLUster Ensembles}},
+  author       = {Kurt Hornik},
+  year	       = 2005,
+  journal      = {Journal of Statistical Software},
+  volume       = 14,
+  number       = 12,
+  url	       = {http://www.jstatsoft.org/v14/i12/},
+  month	       = {September}
+}
+
+ at Manual{registry:hornik+meyer:2008,
+  title	       = {relations: Data Structures and Algorithms for
+                  Relations},
+  author       = {Kurt Hornik and David Meyer},
+  year	       = 2008,
+  note	       = {R package version 0.5}
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-registry.git



More information about the debian-med-commit mailing list