Skip to main content
K.Daube
Community Expert
Community Expert
June 9, 2018
Answered

"Namespacing" scripts

  • June 9, 2018
  • 4 replies
  • 1171 views

Dear all,

In post Resources for learning framecript Rick says:

6) FrameScript functions are local to each script and not shared in the global FrameMaker session like ExtendScript's functions are. (Yes, I do namespace my ExtendScript scripts to avoid this, but it is not necessary with FrameScript.)

How is namespacing done?

  • Prefixing global variable names with an abbreviation of the script name?
  • ???

Awaiting some enlightenment ...

Klaus

This topic has been closed for replies.
Correct answer frameexpert

I will initially write something like this without namespacing:

main ();

function main () {

   

    // This is the main function.

    // From here I call other functions.

   

    processDoc (app.ActiveDoc);

}

function processDoc (doc) {

   

    // Call some other function from here.

    processTables (doc);

}

function processTables (doc) {

   

    // Do something here.

}

And I use a Python script to convert it to this:

// Make an object specific to this script.

var CP_ABC = CP_ABC || {};

// Add the functions to the object.

CP_ABC.main = function () {

   

    // This is the CP_ABC.main function.

    // From here I call other functions.

   

    CP_ABC.processDoc (app.ActiveDoc);

};

CP_ABC.processDoc = function (doc) {

   

    // Call some other function from here.

    CP_ABC.processTables (doc);

};

CP_ABC.processTables = function (doc) {

   

    // Do something here.

};

// Call the functions using the object "namespace".

CP_ABC.main ();

I got this idea out of this book:

https://www.amazon.com/JavaScript-Patterns-Better-Applications-Coding/dp/0596806752/ref=sr_1_3?ie=UTF8&qid=1528559325&sr…

Rick

4 replies

Inspiring
May 1, 2019

I find namespacing a bit unnecessary for most scripts. I just wrap each script in an anonymous function which is immediately called.

(function () {

     // your script here

})();

This keeps everything declared in your script within the scope of this function, but without the need for any prefixes.

Ian Proudfoot
Legend
June 11, 2018

I've been silently following this thread and I fully support the concepts defined by Rick. The first time I ever wrote an ExtendScript application was the S1000D support hat was built into FrameMaker. It's a reasonably large application with some complex scriptUI dialogs. I was unaware of the visible footprint I was leaving in the global FrameMaker session space. Towards the end of that development I read the excellent book "JavaScript: The Good Parts" by Douglas Crockford. (https://www.amazon.co.uk/JavaScript-Good-Parts-ebook/dp/B0026OR2ZY ) It showed me what I had done wrong and how to fix it. It was too late at that stage to retrofit these improvements into the S1000D application, so many of its functions and objects remain exposed. I offered to fix it for Adobe, but it wasn't seen as a priority.

You may ask does it matter? I would argue strongly that it certainly does. It's never a good idea to have global variables and objects open to accidental or even malicious abuse. I even managed to accidentally name a variable the same as one of the S1000D variables and had the most confusing time trying to debug it all .

I have to disagree with Jang that a simple prefix is adequate. It can prevent errors, but sill leaves a whole heap of detritus in the global space. Let's all be good ExtendScript citizens and keep FrameMaker tidy!

frameexpert
Community Expert
Community Expert
June 11, 2018

Hi Ian, Thanks for your honesty and humility in admitting your mistake. I sent out dozens of client scripts without the namespacing technique before I discovered problems, so you are not alone. I also strongly recommend Crockford's book as it really increased my understanding of JavaScript. Thanks for your feedback! -Rick

www.frameexpert.com
frameexpert
Community Expert
frameexpertCommunity ExpertCorrect answer
Community Expert
June 9, 2018

I will initially write something like this without namespacing:

main ();

function main () {

   

    // This is the main function.

    // From here I call other functions.

   

    processDoc (app.ActiveDoc);

}

function processDoc (doc) {

   

    // Call some other function from here.

    processTables (doc);

}

function processTables (doc) {

   

    // Do something here.

}

And I use a Python script to convert it to this:

// Make an object specific to this script.

var CP_ABC = CP_ABC || {};

// Add the functions to the object.

CP_ABC.main = function () {

   

    // This is the CP_ABC.main function.

    // From here I call other functions.

   

    CP_ABC.processDoc (app.ActiveDoc);

};

CP_ABC.processDoc = function (doc) {

   

    // Call some other function from here.

    CP_ABC.processTables (doc);

};

CP_ABC.processTables = function (doc) {

   

    // Do something here.

};

// Call the functions using the object "namespace".

CP_ABC.main ();

I got this idea out of this book:

https://www.amazon.com/JavaScript-Patterns-Better-Applications-Coding/dp/0596806752/ref=sr_1_3?ie=UTF8&qid=1528559325&sr…

Rick

www.frameexpert.com
frameexpert
Community Expert
Community Expert
June 10, 2018

So the object itself is global--in this example, CP_ABC--but all of its functions are "hidden" inside of the object. This is important for me because I may have a dozen scripts with a processDoc function and when the scripts are installed, there can only be one processDoc function in the global space. Namespacing through objects solves the problem.

A nice side effect is that you can use this object to store "global" variables, which you normally want to avoid. For example, I will sometimes do this:

// Make a global object for this script.

var CP_ABC = CP_ABC || {};

// Set a version value for this script.

CP_ABC.version = "1.0.1, June 9, 2018";

// Set a constant for points units.

CP_ABC.PT = 65536;

...

CP_ABC.makeAFrame = function (page, doc) {

    ...

    // Set the anchored frame width to 2 inches (144 points).

    aframe.Width = 144 * CP_ABC.PT;

    ...

};

Line 6 is convenient because there may be multiple places in the script where I want to use the PT value for setting offsets and dimensions. It is easy for me to remember the current global object name plus dot PT.

Line 4 is convenient because, while I may only use the version value in one place in the script, it is easier to change the value up at the top of a large script instead of hunting for it when it needs to be changed.

www.frameexpert.com
K.Daube
Community Expert
K.DaubeCommunity ExpertAuthor
Community Expert
June 10, 2018

Rick, Thank you very much for this extensive explanation.

BRW: I own the mentioned book as e-book - but did not study it yet to that level...

Klaus

4everJang
Legend
June 9, 2018

I prepend all of my functions with SiD_ (Smart Information Design) so that there is no conflict with scripts from others.