Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Want to convert your script to one that uses a nameSpace? here's a template

1519142037

Edited 1560348036
GiGs
Pro
Sheet Author
API Scripter
The wiki tells us  here that it's a good idea to namespace our functions. This process baffled me for the longest time. If you're in the same boat, here's a template and some instructions to make it easy to convert your own scripts to a nameSpace version. Credits: this is adapted from The Aaron's many scripts that use the technique. If I've missed any pitfalls, I'm sure more experienced scripters can offer advice. But this process has worked flawlessly for me quite a few times now. Step 1: create a new script, and paste this into it: var myNameSpace = myNameSpace || (function() { 'use strict'; var version = '1.0',     handleInput = function(msg) {     // copy the body of your on(chat:message) event to this function      },     myFunctionName = function(args){     // for each function, copy this function and swap myFunctionName for function name, and put any arguments in args.      // then paste the body of your function into the body of this one.     },      registerEventHandlers = function() {      on('chat:message', handleInput);     // if you have any other on events, you can enter that here and create a function above, like handleInput, to intercept it.         }; return {      RegisterEventHandlers: registerEventHandlers     }; }()); on("ready",function(){     'use strict';     myNameSpace.RegisterEventHandlers(); }); 2) pick a namespace for your function, and do a global replace, swapping "myNameSpace" for your chosen namespace. 3) create any event handlers you need under the registerEventHandlers function. If your script responds to chat, you can skip this step, it's already set up. 4) copy the body of the on(chat:message) event into the handleInput function.          Repeat for any other other events 5) if you have any functions, make a copy of myFunctionName for each   swap "myFunctionName" for the name of your function, copy the body of old your function to the body if this new function.  if needed, add any args in the title line of the function. That should be it. Test and and see what happens
1519142647
The Aaron
Pro
API Scripter
Nice!  This is my take on what's called The Revealing Module Pattern .  I'm a big fan of encapsulation, and this lets you have it.  You could technically rewrite it to expose nothing outside the namespace, but that's probably not necessary.  
Maybe some dumb questions, but what makes a good namespace? How long should it be? How unique does it have to be?
1519185798

Edited 1519185824
The Aaron
Pro
API Scripter
A good namespace is something unique and descriptive. Length doesn’t matter, but there can only be 52 one letter ones so collision is pretty likely. :)  A few descriptive words put together is usually enough.  It must be completely unique within the API sandbox where it’s running. If you only have one script, it doesn’t matter, but you couldn’t have two scripts at the same time that both used Roller.  In actuality, you don’t need a Nsmespace if you don’t plan to expose functionality to other scripts. You can wrap your script in an anonymous function and achieve the same safe encapsulation: (function() { 'use strict'; var version = '1.0', handleInput = function(msg) { // copy the body of your on(chat:message) event to this function }, myFunctionName = function(args){ // for each function, copy this function and swap myFunctionName for function name, and put any arguments in args. // then paste the body of your function into the body of this one. }, registerEventHandlers = function() { on('chat:message', handleInput); // if you have any other on events, you can enter that here and create a function above, like handleInput, to intercept it.     }; on(‘ready’, registerEventHandlers ); }());
1519202763
Jakob
Sheet Author
API Scripter
Actually, I think it's a good idea to use a variable for your script though, and define your IIFE via const  — these things together give you a good error message when you accidentally include the same script twice.
1519226963
The Aaron
Pro
API Scripter
I usually have my scripts output a message to the API console with the name and version, which helps with tracking that down, but that's a good point regardless.
1519248777
GiGs
Pro
Sheet Author
API Scripter
The Aaron said: Nice!  This is my take on what's called The Revealing Module Pattern .  I'm a big fan of encapsulation, and this lets you have it.  You could technically rewrite it to expose nothing outside the namespace, but that's probably not necessary.   How would you rewrite it to expose nothing outside? Funnily enough, just today i had a frustrating error caused by running two scripts, each of which had a function with the same name, and script A was calling the function from Script B which I didn't realise could happen.
1519255531
The Aaron
Pro
API Scripter
Take a look at my longer post with code a few pages up. :)
1519255927
GiGs
Pro
Sheet Author
API Scripter
Did you mean posts, rather than pages? That snippet without a namespace? I would like to use a Namespace. i thought the whole point of using namespaces was to avoid exposing functions and variables to other scripts?
1519256128
The Aaron
Pro
API Scripter
Yup, a few posts up (was thinking of screen pages up =D). If you wanted to put existing code inside something, you can just put it in an IIFE, an Immediately Invoked Function Expression: (function(){ // Some un-namespaced script code }()); What you're really doing is just putting them in a new scope so they don't pollute the global scope.
1519256377
The Aaron
Pro
API Scripter
In my case, the intent of the namespace is to encapsulate the functionality of a script so that it isn't conflicting with other things.  The object returned at the end of The Revealing Module Pattern is the interface you expose to the outside world.   Usually there's nothing you need to expose (most of my scripts expose two functions that don't really need to be exposed), but sometimes you want to provide functionality to other scripts.  For example, GroupInitiative will tell other scripts when it has changed the turn order, via the Observer Pattern, Bump uses that information to replace a token's turn with the right token instance, TurnMarker1 uses it to rehighlight the current turn, in case it changed, etc.  TokenMod exposes an Observer Pattern function to let other scripts know when it changes a token.
1519256736
GiGs
Pro
Sheet Author
API Scripter
I don't really understand namespaces. Here's what happened, and I'd like to avoid, while keeping namespaces. Is this possible? I have a script for NPCgen, and a script PCgen. Both had a function inside them called getNextid. I was having trouble with the getNextID script, and was working on the version inside the PCGen script, and triggering the PCgen script in the campaign to test my changes. After much pulling of hair, I realised my edits weren't working because the PCGen namespaced script was ignoring its own getNextID function and running the one inside NPCGen. Now, the PCGen script is the first big script i designed, and uses a different construction of the namespace, where I had to explicitly preface each of its functions with PCGen (i.e. call the script with PCGen.getNextid() ) and I hadn't noticed I'd left the PCGen off. But I'd have realised that a lot quicker, except that it was able to find the getNextID script in NPCGen without using its namespace.  The behaviour I'd like to see: * When calling a function inside its own namespace, just use the function name (eg "getNextID()") * when calling a function inside another namespace, call it by using the namespace as a prefix. (eg "mynamespace.getNextID()"). What am I missing in how to construct this?
1519259081
The Aaron
Pro
API Scripter
Well... that's kind of a long question. =D What we've been calling Namespaces here and elsewhere really isn't a Namespace.  Javascript does not have Namespaces.  C++, C#, Java, etc all have Namespaces and they behave like you want.  They are a Named scope under which you find some symbol.  When you are inside the Namespace, you can leave it off as you are inside that scope--that scope is searched for a symbol first before moving outward to a wider scope for name resolution. Javascript doesn't have Namespaces, i.e. named scopes.  It has Global Scope and Function Scope, and (with let and const) Block Scope. Global Scope is just that, global.  If you do nothing else, symbols you define are in the Global Scope.  It is the last scope searched for name resolution.  Function Scope is all the things between the starting { and close } of a function.  If you're in a Function Scope and use a symbol, the Function's scope will be searched first, followed by the Global Scope.  The first place where a symbol is found is where the name will be resolved.  Finally, you have Block Scope, which is anything between { and } (or implied { and } in the case of a single statement following some control structure like if) which isn't a Function Scope.  Complicating things slightly is that var defined variables are always hoisted to the Function Scope outside of any block they happen to be in, where as let and const defined variables are restricted to their Block Scope. // global scope var foo = 1; function bar(){ // function scope var foo = 2; for(let i = 0; i<3;++i){ // block scope let baz = 3; } } In Javascript, we simulate Namespaces with several techniques.  The one you illustrated in the first post, the Revealing Module Pattern is actually a closure which returns an object aliasing functions inside the closure.  A closure is a Function Scope which remains in existence after the function has executed.  Things created in a function have that function's Function Scope even if they are passed outside the function.  This is a massively confusing topic, so no worries if this sounds bat shit crazy, it is! let Foo = (function(){ var Qux = 3; var SomeFunc = function(){ return ++Qux; }; return { func: SomeFunc }; }()); log(Foo.func()); // 4 log(Foo.func()); // 5 In the above, the IIFE returns an object which has the property func which is assigned (by reference) the function SomeFunc().  SomeFunc is defined inside the IIFE, so Qux is in it's Function Scope, the Closure where it is defined.  that returned object is assigned to the variable Foo (by reference).  When Foo.func() is called, it increments Qux and returns the value.  The next execution does the same thing.  The Qux that is being incremented is the one inside the Closure.  The IIFE has long since finished executing, but it's Closure persists and can only be accessed by SomeFunc(). The benefit of the Revealing Module Pattern is that you only reveal the things you want to from it.  You can be certain that no one is going to increment Qux or other than by calling your revealed SomeFunc() function.  This frees you up to use a different implementation without worrying that someone is depending on some private details.  Inside the functions of your Closure, you can freely refer to the other parts of your Closure without any prefacing. Another way people simulate Namespaces is by creating objects that contain things.  This is what you're doing with your explicit prefacing.  You might explicitly construct an object with properties (I do this in earlier scripts like TurnMarker1 and Mystara Calendar), or you might create an object and assign to properties on the fly: var MyObj = { doThing: function(){ }, doOtherThing: function(){ } }; MyObj.doThing(); MyObj.doOtherThing(); Or var MyObj = {}; MyObj.doThing = function(){ }; MyObj.doOtherThing = function(){ }; MyObj.doThing(); MyObj.doOtherThing(); This is very easy, but also doesn't give you any encapsulation.  You also must refer to the "Namespace" every time you reference something else in your "Namespace". Still another thing you can do is use the ES6 Class syntax.  I've not fully embraced this yet, so I'll not bother with an example right now. Hopefully that clears things up a bit?
1519267041
GiGs
Pro
Sheet Author
API Scripter
It might clear things up once I reread it a few times in the morning, hehe. This bit I think resolved my main concern: It is the last scope searched for name resolution. Function Scope is all the things between the starting { and close } of a function. If you're in a Function Scope and use a symbol, the Function's scope will be searched first, followed by the Global Scope. The first place where a symbol is found is where the name will be resolved. if I'd used the same script construction for both scripts, my conflict wouldnt have happened, because the local getNextID would have been found first and used. I will say, this construction (which I've seen before when I've been trying to grasp this stuff) really makes my brain hurt! let Foo = (function(){ var Qux = 3; var SomeFunc = function(){ return ++Qux; }; return { func: SomeFunc }; }()); Thanks for taking the time to explain. Your willingness to help and teach people is real treasure for this place. 
1519268710
The Aaron
Pro
API Scripter
No worries, I’m happy to help!  :). Closures are quite arcane but also powerful. It took me a long time to understand and feel comfortable with them. 
1519272557
Kirsty
Pro
Sheet Author
Thank you, Aaron, for taking the time to type that up. It made a lot of things click into place for me!
1519273035
The Aaron
Pro
API Scripter
Sweet!  =D  No problem.