First public release.
Package skeleton.
Reading and writing delimited text files (CSV/TSV) and Excel workbooks, remembering the delimiter, decimal mark, encoding, line endings, byte order mark, missing-value text and sheet names needed to write the blinded copy back in the same shape.
Column type detection, by values rather than by storage class, with every
threshold a named constant in R/detect.R.
Seed handling that always puts .Random.seed back as it found it, and one
blinding function per detected type.
blind_data() and blind_file(), the leak check that runs before anything is
written, and the blind_summary object printed after every run.
keep_real, the fifth option: the names of columns to copy over unblinded,
with their real values, for a column that carries nothing sensitive and that
code has to use as it is, such as a treatment arm or a study visit. A kept
column stays lined up with its own rows and keeps its real name even under
blind_names, which is why it cannot be combined with rows. Being the one
way to make the package disclose real data, it is reported rather than assumed
safe: the leak check excuses those columns and names them, so the verdict reads
Leak check: passed, except 2 columns kept real: arm, visit instead of a bare
passed, and each kept column's own line reads REAL VALUES KEPT, not blinded. Naming a column the data does not have is an error before anything is
written.
SPSS (.sav, .zsav), Stata (.dta), .rds and Parquet files, keeping value
labels, variable labels and display formats, and the class of the data frame
stored in an .rds. Parquet needs the suggested arrow package. An SPSS code
declared user-missing is now treated as the code it is, not as a missing value.
run_app(), a Shiny app on 127.0.0.1 with the five options, the summary and
a Copy button. The Keep real box lists the uploaded file's columns to
choose from, read from the file's header alone so that a large file is not read
twice. Then a preview of the first ten blinded rows (one sheet at a time
for a workbook) and a download button. Uploads of up to 1 GB are allowed, the
browser's copy of the upload is deleted as soon as the app has its own, and
that copy goes when the session ends. Also an RStudio addin, Blind a data
file, that opens the app.
A command line wrapper, inst/scripts/datablinder, with the five options plus
--output, --help and --version; --keep-real takes a comma separated
list of column names. The summary goes to standard output and
anything that went wrong to standard error, with an exit status of 1 if the
file could not be blinded or the leak check failed.
install_cli(), which puts that command where the shell can find it on
macOS, Linux and Windows: it copies the script to a directory that is on the
PATH where it can, writes the .cmd shim Windows needs, and says plainly
whether the shell will find the command and what to add to the PATH if it
will not. It needs no sudo and never edits a shell configuration file. It is
the only function here that writes a file outliving the session, so it asks
first: it prints the directory and waits for y, and any other answer writes
nothing, not even the directory. Where there is nobody to ask, in a script or
Rscript -e, it is an error rather than a silent write to a home directory. A
dir inside tempdir() needs no permission, since the session takes it away
again.
A README that leads with the one promise the package makes, shows the three
ways to run it, and says plainly in a Limits section what the blinded copy
does not give you: no formal privacy guarantee, a structure that stays visible
on purpose, no meaning in any analysis of the copy, since columns are blinded
independently, and whole columns shared as they are if keep_real names them. It credits FakeDataR for the ideas borrowed from it.
R CMD check runs clean.
Help pages that stand on their own, for anyone who never sees the README:
?datablinder gives the promise, the four functions, the five options and the
limits; ?blind_data and ?blind_file both carry the list of what happens to
each kind of column; and ?blind_summary describes the summary object, what
to look for in it before sharing a file, and format() for getting its lines
as a character vector.