R/plugin.R

#' @title Application Plugin
#'
#' @description
#' Plugins provide additional functionality to an [`App`]. These are the main
#' mechanisms through which additional functionality is added, as opposed to
#' using inheritance of the [`App`] object itself.
#'
#' The Plugin interface is as follows:
#' * `plugin$name` - should return a string that identifies this plugin
#' * `plugin$on_attach` - is a function that is given the app as a first
#'                        argument and attaches the main functionality
#'                        of the app.
#' * `plugin$on_detach` - is a function that is given the app as a first
#'                        argument and removes the main functionality of the
#'                        application. By default, it removes all handles,
#'                        routers, and statics with metadata `plugin == name`.
#' * `plugin$requires` - should return a list of plugin names that are
#'                       required for this plugin to attach.
#' * Any other methods are made available through the plugin instance. They
#'   can operate on the app method itself through `self$app`.
#'
#' @param app (App) instance
#' @param ... (arg)s passed to the underlying methods
#'
#' @export
Plugin <- R6Class(

  classname = "Plugin",
  inherit = Configurable,

  public = list(

    #' @description Establishes initial configuration for the Plugin.
    #' @param name     (str) name of the plugin
    #' @param requires (chr) additional plugin names that are required
    initialize = function(name, requires = NULL) {

      private$.name <-
        assert_string(name)
      private$.requires <-
        assert_character(requires, min.len = 1L, null.ok = TRUE)

    },

    #' @description `on_attach(app, ...)` should attach all the handlers,
    #' routers, and static paths necessary for this plugin. To make them easier
    #' to detach, add `plugin == self$name` to the metadata of the handlers.
    on_attach = function(app, ...) {

      private$.app <- app

    },

    #' @description (optional) should detach all the handlers, routers,
    #' and static paths for the plugin. By default it does this by just removing
    #' all the elements that have the plugin indicated via metadata.
    on_detach = function(app, ...) {

      app$handle_remove(plugin == !!self$name)
      app$router_remove(plugin == !!self$name, attach = "request")
      app$router_remove(plugin == !!self$name, attach = "header")
      app$router_remove(plugin == !!self$name, attach = "message")
      app$static_remove(plugin == !!self$name)

    }

  ),

  active = list(

    #' @field name name of the plugin
    name = function() private$.name,

    #' @field requires name(s) of plugins that are required by this plugin
    requires = function() private$.requires,

    #' @field app attached app instance
    app = function() private$.app,

    #' @field fire fire object attached to app instance
    fire = function() private$.app$fire

  ),

  private = list(

    # Name of the plugin
    .name = NULL,

    # Application attached
    .app = NULL,

    # Required plugins
    .requires = NULL

  )

)
tjpalanca/webtools documentation built on Dec. 23, 2021, 11 a.m.