changeset 20834:27b333c88c8e

Overhaul m-files in prefs directory. Update docstrings, re-code to match Matlab behavior, put input validation first, add BIST tests. * addpref.m, getpref.m, ispref.m, preferences.m, rmpref.m, setpref.m: Update docstrings, re-code to match Matlab behavior, put input validation first, add BIST tests. * loadprefs.m, prefsfile.m, saveprefs.m: Update docstring. Remove ## note about testing. * saveprefs.m: Update docstring. Remove ## note about testing. Change function declaration to not return any value. * scripts/prefs/private/prefdir.m: Move file from scripts/prefs to private directory. Match variable names in doc to those in function. * module.mk: Change build system to find prefdir.m in private directory.
author Rik <rik@octave.org>
date Wed, 09 Dec 2015 12:01:31 -0800
parents 9c4c87679985
children 14cd86258b3d
files scripts/prefs/addpref.m scripts/prefs/getpref.m scripts/prefs/ispref.m scripts/prefs/module.mk scripts/prefs/prefdir.m scripts/prefs/preferences.m scripts/prefs/private/loadprefs.m scripts/prefs/private/prefdir.m scripts/prefs/private/prefsfile.m scripts/prefs/private/saveprefs.m scripts/prefs/rmpref.m scripts/prefs/setpref.m
diffstat 12 files changed, 403 insertions(+), 221 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/prefs/addpref.m	Wed Dec 09 14:32:04 2015 -0500
+++ b/scripts/prefs/addpref.m	Wed Dec 09 12:01:31 2015 -0800
@@ -17,18 +17,20 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {} addpref (@var{group}, @var{pref}, @var{val})
-## Add a preference @var{pref} and associated value @var{val} to the named
+## @deftypefn  {Function File} {} addpref ("@var{group}", "@var{pref}", @var{val})
+## @deftypefnx {Function File} {} addpref ("@var{group}", @{"@var{pref1}", "@var{pref2}", @dots{}@}, @{@var{val1}, @var{val2}, @dots{}@})
+## Add the preference @var{pref} and associated value @var{val} to the named
 ## preference group @var{group}.
 ##
-## The named preference group must be a character string.
+## The named preference group must be a string.
+##
+## The preference @var{pref} may be a string or a cell array of strings.  An
+## error will be issued if the preference already exists.
 ##
-## The preference @var{pref} may be a character string or a cell array of
-## character strings.
-##
-## The corresponding value @var{val} may be any value, or, if @var{pref} is a
-## cell array of strings, @var{val} must be a cell array of values with the
-## same size as @var{pref}.
+## The corresponding value @var{val} may be any Octave value, .e.g., double,
+## struct, cell array, object, etc.  Or, if @var{pref} is a cell array of
+## strings then @var{val} must be a cell array of values with the same size as
+## @var{pref}.
 ## @seealso{setpref, getpref, ispref, rmpref}
 ## @end deftypefn
 
@@ -36,43 +38,75 @@
 
 function addpref (group, pref, val)
 
-  if (nargin == 3)
-    if (ischar (group))
-      prefs = loadprefs ();
-      if (ischar (pref))
-        if (isfield (group, pref))
-          error ("addpref: preference %s already exists in group %s", pref, group);
-        else
-          prefs.(group).(pref) = val;
-        endif
-      elseif (iscellstr (pref))
-        if (size_equal (pref, val))
-          for i = 1:numel (pref)
-            if (isfield (group, pref{i}))
-              error ("addpref: preference %s already exists in group %s",
-                     pref{i}, group);
-            else
-              prefs.(group).(pref{i}) = val;
-            endif
-          endfor
-        else
-          error ("addpref: size mismatch for PREF and VAL");
-        endif
-      else
-        error ("addpref: PREF must be a character string or cellstr");
-      endif
-      saveprefs (prefs);
+  if (nargin != 3)
+    print_usage ();
+  endif
+
+  if (! ischar (group))
+    error ("addpref: GROUP must be a string");
+  elseif (! (ischar (pref) || iscellstr (pref)))
+    error ("addpref: PREF must be a string or cellstr");
+  endif
+
+  prefs = loadprefs ();
+
+  if (ischar (pref))
+    if (isfield (prefs, group) && isfield (prefs.(group), pref))
+      error ("addpref: preference %s already exists in group %s", pref, group);
     else
-      error ("addpref: GROUP must be a string");
+      prefs.(group).(pref) = val;
     endif
   else
-    print_usage ();
+    if (! size_equal (pref, val))
+      error ("addpref: size mismatch for PREF and VAL");
+    endif
+    for i = 1:numel (pref)
+      if (isfield (prefs, group) && isfield (prefs.(group), pref{i}))
+        error ("addpref: preference %s already exists in group %s",
+               pref{i}, group);
+      else
+        prefs.(group).(pref{i}) = val{i};
+      endif
+    endfor
   endif
 
+  saveprefs (prefs);
+
 endfunction
 
 
-## Testing these functions will require some care to avoid wiping out
-## existing (or creating unwanted) preferences for the user running the
-## tests.
+%!test
+%! HOME = getenv ("HOME");
+%! unwind_protect
+%!   setenv ("HOME", P_tmpdir ());
+%!
+%!   addpref ("group1", "pref1", [1 2 3]);
+%!   assert (getpref ("group1", "pref1"), [1 2 3]);
+%!
+%!   addpref ("group2", {"prefA", "prefB"}, {"StringA", {"StringB"}});
+%!   assert (getpref ("group2", "prefA"), "StringA");
+%!   assert (getpref ("group2", "prefB"), {"StringB"});
+%!
+%!   fail ('addpref ("group1", "pref1", 4)', ...
+%!         "preference pref1 already exists in group group1");
+%!   fail ('setpref ("group1", {"p1", "p2"}, 1)', ...
+%!         "size mismatch for PREF and VAL");
+%!   fail ('addpref ("group2", {"prefC", "prefA"}, {1, 2})',
+%!         "preference prefA already exists in group group2");
+%!
+%! unwind_protect_cleanup
+%!   unlink (fullfile (P_tmpdir (), ".octave_prefs"));
+%!   if (isempty (HOME))
+%!     unsetenv ("HOME");
+%!   else
+%!     setenv ("HOME", HOME);
+%!   endif
+%! end_unwind_protect
 
+%!error addpref ()
+%!error addpref (1)
+%!error addpref (1,2)
+%!error addpref (1,2,3,4)
+%!error <GROUP must be a string> addpref (1, "pref1", 2)
+%!error <PREF must be a string> addpref ("group1", 1, 2)
+
--- a/scripts/prefs/getpref.m	Wed Dec 09 14:32:04 2015 -0500
+++ b/scripts/prefs/getpref.m	Wed Dec 09 12:01:31 2015 -0800
@@ -17,23 +17,26 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {Function File} {} getpref (@var{group}, @var{pref})
-## @deftypefnx {Function File} {} getpref (@var{group}, @var{pref}, @var{default})
-## @deftypefnx {Function File} {} getpref (@var{group})
+## @deftypefn  {Function File} {@var{val} =} getpref ("@var{group}", "@var{pref}")
+## @deftypefnx {Function File} {@var{val} =} getpref ("@var{group}", "@var{pref}", @var{default})
+## @deftypefnx {Function File} {@{@var{val1}, @var{val2}, @dots{}@} =} getpref ("@var{group}", @{"@var{pref1}", "@var{pref2"}, @dots{}@})
+## @deftypefnx {Function File} {@var{prefstruct} =} getpref ("@var{group}")
+## @deftypefnx {Function File} {@var{prefstruct} =} getpref ()
 ## Return the preference value corresponding to the named preference @var{pref}
 ## in the preference group @var{group}.
 ##
-## The named preference group must be a character string.
+## The named preference group must be a string.
 ##
-## If @var{pref} does not exist in @var{group} and @var{default} is
-## specified, return @var{default}.
+## If @var{pref} does not exist in @var{group} and @var{default} is specified,
+## create the preference with value @var{default} and return @var{default}.
 ##
-## The preference @var{pref} may be a character string or a cell array of
-## character strings.
+## The preference @var{pref} may be a string or cell array of strings.  If it
+## is a cell array of strings then a cell array of preferences is returned.
 ##
-## The corresponding default value @var{default} may be any value, or, if
-## @var{pref} is a cell array of strings, @var{default} must be a cell array
-## of values with the same size as @var{pref}.
+## The corresponding default value @var{default} may be any Octave value,
+## .e.g., double, struct, cell array, object, etc.  Or, if @var{pref} is a cell
+## array of strings then @var{default} must be a cell array of values with the
+## same size as @var{pref}.
 ##
 ## If neither @var{pref} nor @var{default} are specified, return a structure
 ## of preferences for the preference group @var{group}.
@@ -47,54 +50,106 @@
 
 function retval = getpref (group, pref, default)
 
+  if (nargin > 3)
+    print_usage ();
+  endif
+
   if (nargin == 0)
     retval = loadprefs ();
   elseif (nargin == 1)
-    if (ischar (group))
-      prefs = loadprefs ();
-      if (isfield (prefs, group))
-        retval = prefs.(group);
-      else
-        retval = [];
-      endif
+    if (! ischar (group))
+      error ("getpref: GROUP must be a string");
+    endif
+    prefs = loadprefs ();
+    if (isfield (prefs, group))
+      retval = prefs.(group);
     else
-      error ("getpref: GROUP must be a character string");
+      ## FIXME: Is this the right behavior, or should it produce an error?
+      retval = [];
     endif
-  elseif (nargin == 2 || nargin == 3)
+  else
+    if (! (ischar (pref) || iscellstr (pref)))
+      error ("getpref: PREF must be a string or cellstr");
+    endif
+
     grp = getpref (group);
+
     if (ischar (pref))
       if (isfield (grp, pref))
         retval = grp.(pref);
       elseif (nargin == 3)
+        addpref (group, pref, default);
         retval = default;
       else
-        error ("getpref: preference %s does not exist in group %s", pref, group);
+        error ("getpref: preference %s does not exist in group %s",
+               pref, group);
       endif
-    elseif (iscellstr (pref))
-      if (nargin == 2 || size_equal (pref, default))
-        for i = 1:numel (pref)
-          if (isfield (grp, pref{i}))
-            retval.(pref) = grp.(pref{i});
-          elseif (nargin == 3)
-            retval.(pref) = default{i};
-          else
-            error ("getpref: preference %s does not exist in group %s", pref{i}, group);
-          endif
-        endfor
-      else
+    else
+      if (nargin != 2 && ! size_equal (pref, default))
         error ("getpref: size mismatch for PREF and DEFAULT");
       endif
-    else
-      error ("getpref: PREF must be a character string or cellstr");
+
+      for i = 1:numel (pref)
+        if (isfield (grp, pref{i}))
+          retval{i} = grp.(pref{i});
+        elseif (nargin == 3)
+          addpref (group, pref{i}, default{i});
+          retval{i} = default{i};
+        else
+          error ("getpref: preference %s does not exist in group %s",
+                 pref{i}, group);
+        endif
+      endfor
     endif
-  else
-    print_usage ();
   endif
 
 endfunction
 
 
-## Testing these functions will require some care to avoid wiping out
-## existing (or creating unwanted) preferences for the user running the
-## tests.
+%!test
+%! HOME = getenv ("HOME");
+%! unwind_protect
+%!   setenv ("HOME", P_tmpdir ());
+%!   addpref ("group1", "pref1", [1 2 3]);
+%!   addpref ("group2", {"prefA", "prefB"}, {"StringA", {"StringB"}});
+%!
+%!   exp.group1.pref1 = [1 2 3];
+%!   exp.group2.prefA = "StringA";
+%!   exp.group2.prefB = {"StringB"};
+%!   obs = getpref ();
+%!   assert (obs, exp);
+%!
+%!   assert (getpref ("group1"), exp.group1);
+%!   assert (getpref ("group2"), exp.group2);
+%!   assert (getpref ("group3"), []);
+%!
+%!   assert (getpref ("group1", "pref1"), [1 2 3]);
+%!   assert (getpref ("group2", "prefA"), "StringA");
+%!   assert (getpref ("group2", "prefB"), {"StringB"});
+%!   assert (getpref ("group1", "pref2", "New_Value"), "New_Value");
+%!   assert (getpref ("group1", "pref2"), "New_Value");
+%!   fail ('getpref ("group1", "no_such_pref")', ...
+%!         "preference no_such_pref does not exist in group group1");
+%!
+%!   assert (getpref ("group2", {"prefA", "prefB"}), {"StringA", {"StringB"}});
+%!   assert (getpref ("group2", {"prefA", "prefC"}, {1, "StringC"}),
+%!           {"StringA", "StringC"});
+%!   assert (getpref ("group2", "prefC"), "StringC");
+%!   fail ('getpref ("group1", {"p1", "p2"}, 1)', ...
+%!         "size mismatch for PREF and DEFAULT");
+%!   fail ('getpref ("group2", {"prefA", "prefD"})',
+%!         "preference prefD does not exist in group group2");
+%!
+%! unwind_protect_cleanup
+%!   unlink (fullfile (P_tmpdir (), ".octave_prefs"));
+%!   if (isempty (HOME))
+%!     unsetenv ("HOME");
+%!   else
+%!     setenv ("HOME", HOME);
+%!   endif
+%! end_unwind_protect
 
+%!error getpref (1,2,3,4)
+%!error <GROUP must be a string> getpref (1)
+%!error <PREF must be a string> getpref ("group1", 1, 2)
+
--- a/scripts/prefs/ispref.m	Wed Dec 09 14:32:04 2015 -0500
+++ b/scripts/prefs/ispref.m	Wed Dec 09 12:01:31 2015 -0800
@@ -17,15 +17,15 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {Function File} {} ispref (@var{group}, @var{pref})
-## @deftypefnx {Function File} {} ispref (@var{group})
+## @deftypefn  {Function File} {} ispref ("@var{group}", "@var{pref}")
+## @deftypefnx {Function File} {} ispref ("@var{group}", @{"@var{pref1}", "@var{pref2"}, @dots{}@})
+## @deftypefnx {Function File} {} ispref ("@var{group}")
 ## Return true if the named preference @var{pref} exists in the preference
 ## group @var{group}.
 ##
-## The named preference group must be a character string.
+## The named preference group must be a string.
 ##
-## The preference @var{pref} may be a character string or a cell array of
-## character strings.
+## The preference @var{pref} may be a string or a cell array of strings.
 ##
 ## If @var{pref} is not specified, return true if the preference group
 ## @var{group} exists.
@@ -34,30 +34,66 @@
 
 ## Author: jwe
 
-function retval = ispref (group, pref)
+function retval = ispref (group, pref = "")
+
+  if (nargin == 0 || nargin > 2)
+    print_usage ();
+  endif
+
+  if (! ischar (group))
+    error ("ispref: GROUP must be a string");
+  endif
+  if (! (ischar (pref) || iscellstr (pref)))
+    error ("ispref: PREF must be a string or cellstr");
+  endif
 
   if (nargin == 1)
     retval = isfield (loadprefs (), group);
-  elseif (nargin == 2)
+  else
     prefs = loadprefs ();
     if (isfield (prefs, group))
-      grp = prefs.(group);
-      if (ischar (pref) || iscellstr (pref))
-        retval = isfield (grp, pref);
+      retval = isfield (prefs.(group), pref);
+    else
+      if (ischar (pref))
+        retval = false;
       else
-        retval = false;
+        retval = false (size (pref));
       endif
-    else
-      retval = false;
     endif
-  else
-    print_usage ();
   endif
 
 endfunction
 
 
-## Testing these functions will require some care to avoid wiping out
-## existing (or creating unwanted) preferences for the user running the
-## tests.
+%!test
+%! HOME = getenv ("HOME");
+%! unwind_protect
+%!   setenv ("HOME", P_tmpdir ());
+%!   addpref ("group1", "pref1", [1 2 3]);
+%!   addpref ("group2", {"prefA", "prefB"}, {"StringA", {"StringB"}});
+%!
+%!   assert (ispref ("group1"));
+%!   assert (! ispref ("group3"));
+%!
+%!   assert (ispref ("group2", "prefB"));
+%!   assert (! ispref ("group2", "prefC"));
+%!
+%!   assert (ispref ("group2", {"prefB", "prefC"}), [true, false]);
+%!
+%!   assert (ispref ("group3", "prefB"), false);
+%!   assert (ispref ("group3", {"prefB", "prefC"}), [false, false]);
+%!
+%! unwind_protect_cleanup
+%!   unlink (fullfile (P_tmpdir (), ".octave_prefs"));
+%!   if (isempty (HOME))
+%!     unsetenv ("HOME");
+%!   else
+%!     setenv ("HOME", HOME);
+%!   endif
+%! end_unwind_protect
 
+%!error ispref ()
+%!error ispref (1,2,3)
+%!error <GROUP must be a string> ispref (1, "pref1")
+%!error <PREF must be a string> ispref ("group1", 1)
+
--- a/scripts/prefs/module.mk	Wed Dec 09 14:32:04 2015 -0500
+++ b/scripts/prefs/module.mk	Wed Dec 09 12:01:31 2015 -0800
@@ -4,6 +4,7 @@
 
 scripts_prefs_PRIVATE_FCN_FILES = \
   scripts/prefs/private/loadprefs.m \
+  scripts/prefs/private/prefdir.m \
   scripts/prefs/private/prefsfile.m \
   scripts/prefs/private/saveprefs.m
 
@@ -11,7 +12,6 @@
   scripts/prefs/addpref.m \
   scripts/prefs/getpref.m \
   scripts/prefs/ispref.m \
-  scripts/prefs/prefdir.m \
   scripts/prefs/preferences.m \
   scripts/prefs/rmpref.m \
   scripts/prefs/setpref.m
--- a/scripts/prefs/prefdir.m	Wed Dec 09 14:32:04 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-## Copyright (C) 2013-2015 John Donoghue
-##
-## This file is part of Octave.
-##
-## Octave is free software; you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or (at
-## your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING.  If not, see
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn  {Command} {} prefdir
-## @deftypefnx {Command} {@var{dir} =} prefdir
-## Return the directory that contains the preferences for Octave.
-##
-## Examples:
-##
-## Display the preferences directory
-##
-## @example
-## prefdir
-## @end example
-##
-## Change to the preferences folder
-##
-## @example
-## cd (prefdir)
-## @end example
-## @seealso{getpref, setpref, addpref, rmpref, ispref}
-## @end deftypefn
-
-## Author: John Donoghue
-## Version: 0.01
-
-function folder = prefdir ()
-
-  folder = get_home_directory ();
-
-endfunction
-
--- a/scripts/prefs/preferences.m	Wed Dec 09 14:32:04 2015 -0500
+++ b/scripts/prefs/preferences.m	Wed Dec 09 12:01:31 2015 -0800
@@ -22,13 +22,21 @@
 ## @end deftypefn
 
 ## Author: John Donoghue
-## Version: 0.01
 
 function preferences ()
+
   if (isguirunning ())
     __octave_link_show_preferences__ ();
   else
     warning ("preferences: GUI must be running to use preferences dialog");
   endif
+
 endfunction
 
+
+%!test
+%! if (isguirunning ())
+%!   return;
+%! endif
+%! fail ("preferences ()", "warning", "GUI must be running");
+
--- a/scripts/prefs/private/loadprefs.m	Wed Dec 09 14:32:04 2015 -0500
+++ b/scripts/prefs/private/loadprefs.m	Wed Dec 09 12:01:31 2015 -0800
@@ -17,8 +17,8 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {} loadprefs ()
-## Undocumented internal function.
+## @deftypefn {Function File} {@var{prefs} =} loadprefs ()
+## Return a structure containing all user configured preferences.
 ## @end deftypefn
 
 ## Author: jwe
@@ -31,15 +31,10 @@
 
   if (isstruct (s) && S_ISREG (s.mode))
     tmp = load (file);
-    retval= tmp.prefs;
+    retval = tmp.prefs;
   else
     retval = [];
   endif
 
 endfunction
 
-
-## Testing these functions will require some care to avoid wiping out
-## existing (or creating unwanted) preferences for the user running the
-## tests.
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/prefs/private/prefdir.m	Wed Dec 09 12:01:31 2015 -0800
@@ -0,0 +1,47 @@
+## Copyright (C) 2013-2015 John Donoghue
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {Command} {} prefdir
+## @deftypefnx {Command} {@var{dir} =} prefdir
+## Return the directory that holds the preferences for Octave.
+##
+## Examples:
+##
+## Display the preferences directory
+##
+## @example
+## prefdir
+## @end example
+##
+## Change to the preferences folder
+##
+## @example
+## cd (prefdir)
+## @end example
+## @seealso{getpref, setpref, addpref, rmpref, ispref}
+## @end deftypefn
+
+## Author: John Donoghue
+
+function dir = prefdir ()
+
+  dir = get_home_directory ();
+
+endfunction
+
--- a/scripts/prefs/private/prefsfile.m	Wed Dec 09 14:32:04 2015 -0500
+++ b/scripts/prefs/private/prefsfile.m	Wed Dec 09 12:01:31 2015 -0800
@@ -18,7 +18,7 @@
 
 ## -*- texinfo -*-
 ## @deftypefn {Function File} {} prefsfile ()
-## Undocumented internal function.
+## Return the full path and name of the file containing Octave preferences.
 ## @end deftypefn
 
 ## Author: jwe
@@ -29,8 +29,3 @@
 
 endfunction
 
-
-## Testing these functions will require some care to avoid wiping out
-## existing (or creating unwanted) preferences for the user running the
-## tests.
-
--- a/scripts/prefs/private/saveprefs.m	Wed Dec 09 14:32:04 2015 -0500
+++ b/scripts/prefs/private/saveprefs.m	Wed Dec 09 12:01:31 2015 -0800
@@ -17,13 +17,13 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {} saveprefs ()
-## Undocumented internal function.
+## @deftypefn {Function File} {} saveprefs (@var{s})
+## Save user preferences in the structure @var{s} to Octave's preference file.
 ## @end deftypefn
 
 ## Author: jwe
 
-function retval = saveprefs (s)
+function saveprefs (s)
 
   prefs = s;
 
@@ -31,8 +31,3 @@
 
 endfunction
 
-
-## Testing these functions will require some care to avoid wiping out
-## existing (or creating unwanted) preferences for the user running the
-## tests.
-
--- a/scripts/prefs/rmpref.m	Wed Dec 09 14:32:04 2015 -0500
+++ b/scripts/prefs/rmpref.m	Wed Dec 09 12:01:31 2015 -0800
@@ -17,13 +17,14 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {Function File} {} rmpref (@var{group}, @var{pref})
-## @deftypefnx {Function File} {} rmpref (@var{group})
+## @deftypefn  {Function File} {} rmpref ("@var{group}", "@var{pref}")
+## @deftypefnx {Function File} {} rmpref ("@var{group}", @{"@var{pref1}", "@var{pref2}", @dots{}@})
+## @deftypefnx {Function File} {} rmpref ("@var{group}")
 ## Remove the named preference @var{pref} from the preference group @var{group}.
 ##
-## The named preference group must be a character string.
+## The named preference group must be a string.
 ##
-## The preference @var{pref} may be a character string or cell array of strings.
+## The preference @var{pref} may be a string or cell array of strings.
 ##
 ## If @var{pref} is not specified, remove the preference group @var{group}.
 ##
@@ -33,7 +34,7 @@
 
 ## Author: jwe
 
-function retval = rmpref (group, pref)
+function rmpref (group, pref)
 
   if (nargin < 1 || nargin > 2)
     print_usage ();
@@ -44,13 +45,12 @@
   endif
 
   if (nargin == 1)
-    if (ispref (group))
-      prefs = loadprefs ();
-      prefs = rmfield (prefs, group);
-      saveprefs (prefs);
-    else
-      error ("rmpref: group <%s> does not exist", group);
+    if (! ispref (group))
+      error ("rmpref: group %s does not exist", group);
     endif
+    prefs = loadprefs ();
+    prefs = rmfield (prefs, group);
+    saveprefs (prefs);
   else
     valid = ispref (group, pref);
     if (all (valid))
@@ -59,10 +59,12 @@
       saveprefs (prefs);
     else
       if (! ispref (group))
-        error ("rmpref: group <%s> does not exist", group);
+        error ("rmpref: group %s does not exist", group);
+      elseif (ischar (pref))
+        error ("rmpref: preference %s does not exist", pref);
       else
         idx = find (! valid, 1);
-        error ("rmpref: pref <%s> does not exist", (cellstr (pref)){idx} );
+        error ("rmpref: preference %s does not exist", pref{idx});
       endif
     endif
   endif
@@ -70,13 +72,42 @@
 endfunction
 
 
-## Testing these functions will require some care to avoid wiping out
-## existing (or creating unwanted) preferences for the user running the
-## tests.
+%!test
+%! HOME = getenv ("HOME");
+%! unwind_protect
+%!   setenv ("HOME", P_tmpdir ());
+%!   addpref ("group1", "pref1", [1 2 3]);
+%!   addpref ("group2", {"prefA", "prefB", "prefC"}, {"strA", "strB", "strC"});
+%!
+%!   assert (ispref ("group1"));
+%!   rmpref ("group1");
+%!   assert (! ispref ("group1"));
+%!
+%!   assert (ispref ("group2", "prefB"));
+%!   rmpref ("group2", "prefB");
+%!   assert (! ispref ("group2", "prefB"));
+%!
+%!   fail ('rmpref ("group3")', ...
+%!         "group group3 does not exist");
+%!   fail ('rmpref ("group3", "prefA")', ...
+%!         "group group3 does not exist");
+%!   fail ('rmpref ("group2", "prefB")',
+%!         "preference prefB does not exist");
+%!   fail ('rmpref ("group2", {"prefA", "prefB"})',
+%!         "preference prefB does not exist");
+%!
+%! unwind_protect_cleanup
+%!   unlink (fullfile (P_tmpdir (), ".octave_prefs"));
+%!   if (isempty (HOME))
+%!     unsetenv ("HOME");
+%!   else
+%!     setenv ("HOME", HOME);
+%!   endif
+%! end_unwind_protect
 
 ## Test input validation
 %!error rmpref ()
 %!error rmpref (1,2,3)
-%!error rmpref ({"__group1__"})
-%!error rmpref ("__group1__", 1)
+%!error <GROUP must be a string> rmpref (1)
+%!error <PREF must be a string> rmpref ("group1", 1)
 
--- a/scripts/prefs/setpref.m	Wed Dec 09 14:32:04 2015 -0500
+++ b/scripts/prefs/setpref.m	Wed Dec 09 12:01:31 2015 -0800
@@ -17,18 +17,19 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {} setpref (@var{group}, @var{pref}, @var{val})
-## Set a preference @var{pref} to the given @var{val} in the named preference
+## @deftypefn  {Function File} {} setpref ("@var{group}", "@var{pref}", @var{val})
+## @deftypefnx {Function File} {} addpref ("@var{group}", @{"@var{pref1}", "@var{pref2}", @dots{}@}, @{@var{val1}, @var{val2}, @dots{}@})
+## Set the preference @var{pref} to the given @var{val} in the named preference
 ## group @var{group}.
 ##
-## The named preference group must be a character string.
+## The named preference group must be a string.
+##
+## The preference @var{pref} may be a string or a cell array of strings.
 ##
-## The preference @var{pref} may be a character string or a cell array of
-## character strings.
-##
-## The corresponding value @var{val} may be any value, or, if @var{pref} is a
-## cell array of strings, @var{val} must be a cell array of values with the
-## same size as @var{pref}.
+## The corresponding value @var{val} may be any Octave value, .e.g., double,
+## struct, cell array, object, etc.  Or, if @var{pref} is a cell array of
+## strings then @var{val} must be a cell array of values with the same size as
+## @var{pref}.
 ##
 ## If the named preference or group does not exist, it is added.
 ## @seealso{addpref, getpref, ispref, rmpref}
@@ -38,34 +39,67 @@
 
 function setpref (group, pref, val)
 
-  if (nargin == 3)
-    if (ischar (group))
-      prefs = loadprefs ();
-      if (ischar (pref))
-        prefs.(group).(pref) = val;
-      elseif (iscellstr (pref))
-        if (size_equal (pref, val))
-          for i = 1:numel (pref)
-            prefs.(group).(pref{i}) = val;
-          endfor
-        else
-          error ("setpref: size mismatch for PREF and VAL");
-        endif
-      else
-        error ("setpref: PREF must be a character string or cellstr");
-      endif
-      saveprefs (prefs);
-    else
-      error ("setpref: GROUP must be a string");
-    endif
-  else
+  if (nargin != 3)
     print_usage ();
   endif
 
+  if (! ischar (group))
+    error ("setpref: GROUP must be a string");
+  endif
+  if (! (ischar (pref) || iscellstr (pref)))
+    error ("setpref: PREF must be a string or cellstr");
+  endif
+
+  prefs = loadprefs ();
+
+  if (ischar (pref))
+    prefs.(group).(pref) = val;
+  else
+    if (! size_equal (pref, val))
+      error ("setpref: size mismatch for PREF and VAL");
+    endif
+
+    for i = 1:numel (pref)
+      prefs.(group).(pref{i}) = val{i};
+    endfor
+  endif
+
+  saveprefs (prefs);
+
 endfunction
 
 
-## Testing these functions will require some care to avoid wiping out
-## existing (or creating unwanted) preferences for the user running the
-## tests.
+%!test
+%! HOME = getenv ("HOME");
+%! unwind_protect
+%!   setenv ("HOME", P_tmpdir ());
+%!
+%!   setpref ("group1", "pref1", [1 2 3]);
+%!   assert (getpref ("group1", "pref1"), [1 2 3]);
+%!
+%!   setpref ("group2", {"prefA", "prefB"}, {"StringA", {"StringB"}});
+%!   assert (getpref ("group2", "prefA"), "StringA");
+%!   assert (getpref ("group2", "prefB"), {"StringB"});
+%!
+%!   setpref ("group1", {"pref1", "pref2"}, {1, 2});
+%!   assert (getpref ("group1", "pref1"), 1);
+%!   assert (getpref ("group1", "pref2"), 2);
+%!
+%!   fail ('setpref ("group1", {"p1", "p2"}, 1)', ...
+%!         "size mismatch for PREF and VAL");
+%! unwind_protect_cleanup
+%!   unlink (fullfile (P_tmpdir (), ".octave_prefs"));
+%!   if (isempty (HOME))
+%!     unsetenv ("HOME");
+%!   else
+%!     setenv ("HOME", HOME);
+%!   endif
+%! end_unwind_protect
 
+%!error setpref ()
+%!error setpref (1)
+%!error setpref (1,2)
+%!error setpref (1,2,3,4)
+%!error <GROUP must be a string> setpref (1, "pref1", 2)
+%!error <PREF must be a string> setpref ("group1", 1, 2)
+