JavaScript Libraries in Yosemite

(Please note: I think I found a more palatable way to accomplish what I wanted.  Please also see https://lawlessguy.wordpress.com/2014/10/25/evaluate-external-javascript-files-in-yosemite/ )

I’d like to begin by saying that I didn’t expect this exercise in learning OS/X JavaScript to take me down the path that it did.

I began the exercise by reading Apple’s documentation on JavaScript for Automation at:

https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/index.html

Specifically, I referred to this section of the page:

Screen Shot 2014-10-21 at 6.02.07 PM

(the above snippet is copyrighted by Apple, inc. )

I decided to create a library for my personal use that I will add to over time.  At first, I just wanted to get away from all of the boilerplate code necessary to display a dialog box:

Screen Shot 2014-10-21 at 6.09.15 PM

 

I thought I’d create a function called msg() that would behave like App.displayDialog() above.  Since msg() would need a reference to an initialized Application object, I would create a global one.

I had figured that I would end up adding more global objects over time, so I thought it best to collect them as attributes of one global object “__g”.   Since the Library documentation indicates that any code found outside of a function definition would execute, I would simply place the definition and initialization of the __g object and its attribute app object at the beginning of the code:

Screen Shot 2014-10-21 at 6.14.48 PM

In the msg() function itself, note that I have tried to compensate for the second parameter “y” by checking for the presence of a value other than null.  If y is null, I call displayDialog() only with x.

I also found that displayDialog() is type-aware.  It expects the first parameter to be text.  I check to see if the first parameter to msg() is of type “string”.  If not, I coerce it to string. We will revisit this later in the text.

(edit: It looks like one can shut off this behavior with the app.strictParameterType boolean. I’ll have to tinker with the setting to see what happens. )

Problem #1 – Saving the Library Source File

I initially ran into problems saving “jimslib.scpt”, my library, into ~/Library/Script Libraries … Script Editor didn’t even show it on the detailed “Save” dialog.  I ended up saving the file elsewhere.  I then mv’ed it into ~/Library/Script Libraries and used the “open” command from a Terminal window to load it into the editor.

Problem #2 – Variable Scoping

I created a test script called “libtest.scpt” and used it to load my library.

I entered the lines:

x=Library("jimslib");
x.msg("Hello!");

I then saw a dialog box with the word “Hello” displayed.

I then entered the line:

x.msg(__g);

Upon execution, the Script Editor told me that it couldn’t find variable __g.  I am assuming that while functions are exposed in the object returned by the call to Library(), variables are not globally set in the ecosystem when the outside-the-function code is executed.

Problem #3 – Script Caching

As I tried to work to investigate the behaviors of the library system, it became evident that my driver program libtest.scpt was not picking up the changes I was making to the jimslib.scpt file.  I assume that this is some kind of optimization in the Script Editor program.

I had to close libtest.scpt and re-open it to pick up the changes.

Problem #4 – Weird Type Coercions

If I define a function in JavaScript and display it on the console by referencing the name, I can see the body of the function if I coerce it to a string by appending an empty string (“”).

Screen Shot 2014-10-21 at 6.28.27 PM

If I do the same with a function defined in a library, the displayed value is:

Screen Shot 2014-10-21 at 6.30.26 PM

 

I could have sworn that I received an “object” value back as the body text for one iteration of a function that I was building.  I could be wrong.

The JavaScript loaded via Library() is going through some kind of Just-in-Time compilation.  I like my JS code to remain JavaScript so that I can refer to it as JavaScript.  JIT-compilation is fine for the code that executes, but I want to be able to get back to the function-body definitions.

Here’s my Hack to get a JS Library Working the Way I Want

I found that while I could not translate the body of a function back to text outside of a library, I *could* translate it to text by exposing another function inside the library to do so.  I called this intermediate function body().

Please consider the entire “jimslib” listing below:

Screen Shot 2014-10-21 at 6.37.23 PM

 

Note that what had been global code is now bottled up in a function called allofit().  The function body() coerces allofit to text and then prunes the top line (function allofit() {) and the bottom line (}) from the text.

Body returns what had been my original global library code.  To load this library into the ecosystem, I used this test code which calls eval() to solidify the code into the same scope as the script itself.

Screen Shot 2014-10-21 at 6.43.55 PM

Screen Shot 2014-10-21 at 6.44.32 PM

Screen Shot 2014-10-21 at 6.44.43 PM

Screen Shot 2014-10-21 at 6.44.51 PM

Note that the number 2 and the Object __g were correctly coerced to strings in the above example … something that a direct call to displayDialog() does not do.

Epilogue

I had intended on trying to determine if libraries stages in ~/Library/Script Libraries would be included if I exported a client script as an application.  I had assumed that this would not happen since the loading of the library appears to be a run-time function and not a compile-time function.  I didn’t end up getting that far.

I don’t think anyone should really try to depend on the above hack as there has to be a better way to do this and still be able to leverage the Script Editor environment.

My experiments will continue…

 

Advertisements

About Jim Lawless

I've been programming computers for about 36 years ... 30 of that professionally. I've been a teacher, I've worked as a consultant, and have written articles here and there for publications like Dr. Dobbs Journal, The C/C++ Users Journal, Nuts and Volts, and others.
This entry was posted in Programming and tagged , . Bookmark the permalink.

One Response to JavaScript Libraries in Yosemite

  1. Pingback: Evaluate External JavaScript Files in Yosemite | Jim Lawless' Other Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s