Michael Friendly
2013-Feb-07 21:49 UTC
[Rd] assignInNamespace to create a setwd() replacement: how to use unlockBinding()?
In my .Rprofile for Windows, I had the following functions defined to mirror a few features I miss from linux: (a) replace setwd() with a version that stashes the current directory so it can be easily restored (b) writes a short version of the current R directory to the Windows title bar: I can always see where I am, with multiple Rgui windows. (c) creates a cd() shorthand for setwd(), but with the difference that cd() acts like cd - under the tcsh shell, returning to the previously stored directory. #### setwd-new.R ###### # .Rprofile functions to set current directory in WindowTitle #=====================# setwd() replacement functions #===================== oldsetwd <- base::setwd utils::assignInNamespace("setwd", function(dir) { .lastdir <<- oldsetwd(dir) utils::setWindowTitle( short.path(base::getwd()) ) .lastdir }, "base") # setwd replacement, allowing cd() to be like 'cd -' on unix (return to last dir) cd <- function(dir) { if(missing(dir)) dir <- .lastdir .lastdir <<- base::setwd(dir) utils::setWindowTitle( short.path(base::getwd()) ) } short.path <- function(dir, len=2) { np <-length(parts <- unlist(strsplit(dir, '/'))) parts <-rev( rev(parts)[1:min(np,len)] ) dots <- ifelse (np>len, '...', '') paste(dots,paste(parts, '/', sep='', collapse='')) } These all worked for all R versions up to R 2.15.0, where it began to break as follows: > source("setwd-new.R") Error in utils::assignInNamespace("setwd", function(dir) { : locked binding of ?setwd? cannot be changed > I understand what the error means, and I think that unlockBinding() somewhere in my code gives a solution, but I don't see where or how. I should also add that in my actual .Rprofile, I source these functions into a local environment & attach so they are always available, but don't clutter up ls() .my.env <- local({ # all my local definitions }) attach(.my.env) -- Michael Friendly Email: friendly AT yorku DOT ca Professor, Psychology Dept. & Chair, Quantitative Methods York University Voice: 416 736-2100 x66249 Fax: 416 736-5814 4700 Keele Street Web: http://www.datavis.ca Toronto, ONT M3J 1P3 CANADA
Uwe Ligges
2013-Feb-08 14:17 UTC
[Rd] assignInNamespace to create a setwd() replacement: how to use unlockBinding()?
On 07.02.2013 22:49, Michael Friendly wrote:> In my .Rprofile for Windows, I had the following functions defined to > mirror a few features > I miss from linux: > > (a) replace setwd() with a version that stashes the current directory so > it can be easily restored > (b) writes a short version of the current R directory to the Windows > title bar: I can always see where I am, > with multiple Rgui windows. > (c) creates a cd() shorthand for setwd(), but with the difference that > cd() acts like cd - under the tcsh shell, > returning to the previously stored directory. > > #### setwd-new.R ###### > # .Rprofile functions to set current directory in WindowTitle > > #=====================> # setwd() replacement functions > #=====================> > oldsetwd <- base::setwd > utils::assignInNamespace("setwd", > function(dir) { > .lastdir <<- oldsetwd(dir) > utils::setWindowTitle( short.path(base::getwd()) ) > .lastdir > }, "base") > > # setwd replacement, allowing cd() to be like 'cd -' on unix (return to > last dir) > cd <- function(dir) { > if(missing(dir)) dir <- .lastdir > .lastdir <<- base::setwd(dir) > utils::setWindowTitle( short.path(base::getwd()) ) > } > > short.path <- function(dir, len=2) { > np <-length(parts <- unlist(strsplit(dir, '/'))) > parts <-rev( rev(parts)[1:min(np,len)] ) > dots <- ifelse (np>len, '...', '') > paste(dots,paste(parts, '/', sep='', collapse='')) > } > > > These all worked for all R versions up to R 2.15.0, where it began to > break as follows: > > > source("setwd-new.R") > Error in utils::assignInNamespace("setwd", function(dir) { : > locked binding of ?setwd? cannot be changed > > > > I understand what the error means, and I think that unlockBinding() > somewhere in my code gives a solution, > but I don't see where or how. > > I should also add that in my actual .Rprofile, I source these functions > into a local environment & attach > so they are always available, but don't clutter up ls() > > .my.env <- local({ > # all my local definitions > }) > attach(.my.env) >Replacing base functionality is bad practice, since some packages may rely on the actual functionality from base. Why not provide such functions in a private package that masks the base functionality for your interactive work only (and keeps base clean to be used by other packages). Finally, you can load that package in your startup code. Best, Uwe Ligges