carpentries / glosario-r

glosario create and retrieve multilingual glossaries.
https://carpentries.github.io/glosario-r
Other
6 stars 5 forks source link

Public Method for Accessing Private Attributes in `text_definition` #13

Open ian-flores opened 3 years ago

ian-flores commented 3 years ago

In R/text_definition.R line 7. I'm currently doing the following:

 entries_list <- purrr::map(entries, ~.x$.__enclos_env__$private$.entries)

@zkamvar suggested in #11 that we add a public method instead of accessing the enclosed environment. This issue is to discuss and track this development.

zkamvar commented 3 years ago

It looks like neither GlossaryEntry or LanguageGlossaryEntry are exported classes, so the distinction between private and public here is a bit moot.

I would suggest to define an active binding to access the entries. This way, you can write purrr::map(entries, "entries") or purrr::map(entries, ~.x$entries). This way, you have access to them, but they are still immutable outside of the object.

zkamvar commented 3 years ago

The same can be done for the LanguageGlossaryEntry if you want to save two bytes for each call: https://github.com/carpentries/glosario-r/blob/fc44a3964a966cce49a30e7a0093f679f82da1d2/R/entry.R#L17-L25

ian-flores commented 3 years ago

I'm a bit lost on where would you add this @zkamvar , if you can show me with a small example I would be grateful.

zkamvar commented 3 years ago

Active bindings are another part of the R6 class that act like publicly available list elements that auto-compute their contents. I realized that I accidentally linked the wrong content :flushed:, so here's the link to the documentation: https://r6.r-lib.org/articles/Introduction.html#active-bindings-1. Thank you for asking for clarification!

With active bindings, you can write gloss$language instead of gloss$language() or gloss$.__enclose_env__$private$.lang.

They are defined in the R6 class with by defining a list to the active argument like so:

LanguageGlossaryEntry <- R6::R6Class("LanguageGlossaryEntry",
  private = list(
    .lang = NA_character_,
    .term = NA_character_,
    .defn = NA_character_
  ),
  # ---------------------- Active bindings can be accessed just like list read-only elements
  active = list(
    language =  function() {
      private$.lang
    },
    term = function() {
      private$.term
    },
    definition = function() {
      private$.defn
    }
  ),
  # -----------------------------------------------
  public = list(
    initialize = function(term, defn, lang = "en") {
      stopifnot(rlang::is_scalar_character(term))
      stopifnot(rlang::is_scalar_character(defn))
      stopifnot(rlang::is_scalar_character(lang))
      private$.term <- term
      private$.defn <- defn
      private$.lang <- lang
    }
    print = function(show_lang = TRUE) {
      def <- private$.defn

      if (show_lang) {
        def <- paste0(def, " (", private$.lang, ")")
      }

      names(def) <- private$.term
      cli::cli_dl(def)

    }
  )
)

For GlossaryEntry, you would do something similar and add:

# <snip>
  private = list(
    .slug = NA_character_,
    .entries = NULL,
    .ref = NULL
  ),
  active = list(
    slug = function() {
      private$.slug
    },
    entries = function() {
      private$.entries
    },
    refrence = function() {
      private$.ref
    }
  ), 
# <snip>

Hope that helps and sorry for the confusion!