A script to check and change a JMP preference

by on Dec.23, 2010 , under JMP & JSL

Marianne Toft asked the JMP scripting group on LinkedIn a question about managing preferences with JSL:

Does anybody know how to read a specific setting from the Preferences? I need to read the status of ‘Use JMP locale settings’ and if 0 then change to 1 and give the user a message to restart JMP.

Several people had helpful suggestions, but unfortunately it’s just not a trivial problem. It’s a surprisingly tricky problem.

Challenges

First, by default Show Preferences() only shows the preferences that you’ve taken to change. You need to use Show Preferences(all) to see the defaults listed, too.

Second, Show Preferences(SomeSpecificPreferenceHere), although a good guess, doesn’t actually work. You’ll just get the usual output for Show Preferences() without an argument.

Lesson: when you supply an argument JMP doesn’t understand, sometimes you get errors, but a lot of the time it’s just ignored, silently. You get no indication that you did something that doesn’t work. The only way you can be sure it was ignored is to try it again without the argument, or with a different argument, and check whether anything changed.

Third, Show Preferences( [all] ) doesn’t return an expression. It returns missing. The information you need is echoed to the Log window, but it’s not returned as a string or an expression or a list or anything else you’d be able to do some work on. So you need to overcome that.

How to solve the basic problem

In JMP 9, you can Get Log(), which returns a list of strings, one for each line of whatever’s in the log. So to work efficiently, you need to Clear Log() first, then Show Preferences(all), then do Get Log().

Well! Now you have a list of strings, and you need to find the item in that list that is relevant, so you need to put a Contains() test inside a For() loop.

It’s a string, so you have to transform it into an expression with Parse() and some other bookkeeping, so that you can probe its argument with Arg().

Then check whether the argument is the desired one, and if not, change it, by editing the expression with Substitute() and then immediately doing Eval() on the result of that.

Now we need to let the user know we did something, and perhaps that they need to restart. So, put up a New Window() with a Text Box() saying that a preference has changed and they need to restart. Include a Button Box() for “OK” that closes the alert window.

So, that’s the gist of the strategy.

Abstract the script

But, why write all this just for this one specific preference? Why not write it to check and if necessary change any preference?

So, start out with a couple globals that set the preference and the desired value.

But wait! Marianne’s example involves a numeric argument, but other preferences have text arguments; consider Use JMP Locale Settings(0) vs. Report Table Style("Plain"). So we need to make sure our script can work properly whether the particular preference takes a numeric or string value.

And while Marianne’s example requires a restart for the changed preference to take effect, most preferences do not. Might as well set a restartNeeded=1 if it’s important, or 0 if it’s not.

In that alert window, we only need to tell them to restart if it’s important, not if it’s not, so let’s add an If Box() around the Text Box() that only shows the instruction if it’s needed.

If the preference was what we wanted in the first place, we should probably echo something to the Log window, just so we know it ran, if nothing else. We need a Write() statement for that.

Which version of JMP?

But wait, there’s more! The Get Log() command didn’t come along until JMP version 9. If you haven’t been able to upgrade yet, then you need to take another strategy to this whole problem.

There might be a better way to do this, but the only way I could find was to Save Log() to a text file, then Load Text File() to a string, then use Substr() and a bunch of arguments with Contains() to chop out the single preference we care about. From there, the script runs about the same way.

And we need to put all this inside a test for JMP Version(), which returns a string, and usually we need to Trim() it and then do an inequality test, e.g. If( Trim( JMP Version() ) > "9", …), where the first argument is the Get Log() strategy described first, and the second argument uses the Save Log() strategy.

What about nested preferences?

Yet another problem! The script so far deals with top-level preferences with simple, single arguments, either numeric or character. But some preferences are trickier, e.g.,

Preferences(
  Fonts(
    English(
      Monospaced Font("Courier", 10)
    )
  )
);

In this case, the Parse() line will need to be more elaborate, and you’ll have to nest more Arg()s around it to dig down to the particular setting value of interest. Conditioning for such a situation is left as an exercise for the reader, primarily because it’s a hassle, it’s not what Marianne needs, and the syntax of the Preferences() command in JMP is arbitrary enough that we can’t really write code today that will be future-proof; we don’t know how deeply nested a given preference might be, nor what kind of arguments it might expect.

Buy now!

Contact me if you’re interested in purchasing this script or commissioning one like it.