Giter VIP home page Giter VIP logo

opt's Introduction

opt

{opt} helps you set options.

You can set options using autocomplete, so you easily find the options you need and don’t misspell them. It also includes a mechanism to check option values.

Installation

Install with:

remotes::install_github("moodymudskipper/opt")

How to use

opt is the only object in the package, it behaves like a list, and allows you to set your options as illustrated below.

# set option
opt$cli$cli.ansi(TRUE)
#> options(cli.ansi = TRUE)

# get option
opt$cli$cli.ansi()
#> getOption("cli.ansi")
#> [1] TRUE

# same as base R
getOption("cli.ansi")
#> [1] TRUE

Set options(opt.verbose = FALSE) (or opt$opt$opt.verbose(FALSE) !) to disable the options() / getOptions() messages. {opt} is a bit too slow to be used in packaged code and might not be worth an extra dependency so this message helps you copy and paste the relevant base R call.

Printing the option displays hints to where to find help and where the function is used in its package :

opt$cli$cli.ansi
#> Call `opt$cli$cli.ansi()` to get and `opt$cli$cli.ansi(value)` to set.
#> Try the following topic(s) for help on this option:
#> help("ansi_simplify", "cli")
#> help("ansi_strip", "cli")
#> help("ansi-styles", "cli")
#> help("cli-config", "cli")
#> help("make_ansi_style", "cli")
#> help("style_hyperlink", "cli")
#> This option is used by : `cli::is_ansi_tty()`

The ALL option integrates all package options + all other options found in options(), it’s convenient to find any option with autocomplete, for example here looking for width:

opt is always up to date, because of some magic explained at the end of the README.

If it’s useful to you you might enumerate the available options with names() :

library(opt)
names(opts$callr)
#> [1] "callr.compress_transport" "callr.error"              "callr.traceback" 

ev

ev stands for “environment variable” and is opt’s little sister, it behaves the same but for environment variables.

FIXME: better rename as ENV ?

How to validate option values

If you place in the “/inst” folder of your package an “opt.dcf” file similar to the example below, users of {opt} will have their inputs validated, no need for you to add {opt} as a dependency.

in {opt} itself the “/inst/opt.dcf” file is the following

verbose: if (!is.logical(value) || length(value) != 1 || is.na(value)) stop("The `opt.verbose` option should be boolean.", call. = FALSE)
character_test: stopifnot(is.character(value))
foobar_test: match.arg(value, c("foo", "bar"))

Then when setting options wrongly:

opt$opt$opt.verbose(1)
#> Error: The `opt.verbose` option should be boolean.

opt$opt$opt.character_test(1)
#> Error in opt$opt$opt.character_test(1) : is.character(value) is not TRUE

opt$opt$opt.foobar_test("baz")
#> Error in match.arg(value, c("foo", "bar")) : 
#>   'arg' should be one of “foo”, “bar”

How it works

The code of loaded packages is inspected for calls to getOption() or {rlang}’s local_options(), with_options(), push_options(), peek_options(), peek_option(), where option names are found.

It’s done when {opt}’s namespace is loaded, but also updated anytime you type opt$.

{opts} most likely won’t display options that don’t exist, however it might miss existing options if they are fetched in the package using other functions than the above, or by defining a variable first and calling getOption(var) for instance.

For example the package {diffobj} uses a function gdo() to set options and prevents {opt} to fetch those with static analysis.

Dependencies

{opt} has zero dependencies so it’s safe to have library(opt) in your .RProfile.

opt's People

Contributors

moodymudskipper avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

opt's Issues

config ?

after environment variables, what about {config} files ?
we don't want to import packages so we would suggest {config}, otherwise same idea, we'd have a cfg object

documentation

When printing opt$pkg$theoption :

  • Print in which function it is used
  • In which help file it is mentioned
  • Print a retrieved definition if relevant

The latter can be obtained by :

  • retrieving option documenting topic, it usually contains "option" in the topic name and the option name in the text
  • retrieving arg definition where the option is the default

We can afford to be slow since we're printing at this point, and we're restricted to a single package so it won't be all that long even if we search all the doc.

validate base options

Since those are stable.

It's a manual chore but that's useful. They're documented (at least some/most) in ?options

We need a mechanism for this too.

option validation

I'm not sure about this dcf strategy because it implies :

  • potential duplication of code (if user has checking code in package already)
  • checking code that is not tested and might not be aligned with actual expected values (though it's on the maintainer)
  • opt specific effort, though no dependency

Maybe maintainer should define checking functions for options, and those would be detected ? how though ? strict naming or function/argument ? complex heuristics ?

For instance in {flow} I might have something like :

# checking "flow.svg" option
check_svg_opt <- function(value) stopifnot(is.logical(value))

I can use it in my own package, and {opt} would find it.
Can we think of an heuristic general enough so that a user wouldn't have to think about conventions too hard, just write a check function for any option and we'd pick it up ?

A lot of options are defined as default args so we might pick single argument functions that are called on the relevant arg for those ?

We might also get it from the documentation of those args, if it's formatted like "A boolean. Whether to ..." or "Character, name of the ...", that's a wide net

I still like the idea that the maintainer may help {opt} not do its complex (and unavoidably costly and brittle to an extent) heuristics.

FR: add hyperlink to help

Hi,

I was wondering if it would be possible to add cli in Suggests.

If cli is installed, you could provide hyperlinks to help topics.

For example for readxl.

opt$readxl$readxl.show_progress
Call `opt$readxl$readxl.show_progress()` to get and `opt$readxl$readxl.show_progress(value)` to set.
Try the following topic(s) for help on this option:
help("readxl_progress", "readxl")
This option is used by : `readxl::readxl_progress()`

if cli is installed, help("readxl_progress", "readxl") could be replaced by cli::cli_bullets("{.help readxl::readxl_progress}") which displays a hyperlink in the console (in RStudio) !, otherwise would not changed

For more details on cli hyperlinks https://cli.r-lib.org/reference/links.html

Thanks!

.RProfile, .Renviron, default values

Other things that I often wonder about options and environment values are :

  • What are their default values ?
  • What are the values that we've set in .RProfile or .Renviron ?

For the first question we can use callr, attach the package and fetch the options.
For the second we can parse the files, note that env variables can be set in the RProfile too

Not sure about the api.

  • We could have additional args
  • We could have new objects opt_rprofile, opt_renviron, opt_default, ev_renviron, ev_default
  • We could have opt$.RProfile$, ev$.RProfile$, ev$.Renviron$, right below the ALL element, we'd have a tree with uneven depths it that weird ?

We might set too (we don't set any new variable, we just replace the value where it is, so that should be possible to do it cleanly)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.