How does namespacing work in coffeescript and rails?
-
24-12-2019 - |
Question
I am looking at this coffeescript code from Gitlab and wondering how it works.
class Issue
constructor: ->
$('.edit-issue.inline-update input[type="submit"]').hide()
$(".issue-box .inline-update").on "change", "select", ->
$(this).submit()
$(".issue-box .inline-update").on "change", "#issue_assignee_id", ->
$(this).submit()
@Issue = Issue
It seems that this is only being used in the issue related views, but it is not being called anywhere in the issues html. Is there something magical going on behind the scenes here? Also what is the significance of the @Issue = Issue
line?
Solution
@Issue = Issue
simply publishes a local variable to the global scope. This has got nothing to with ruby or rails. It's purely a coffee script idiom.
CoffeeScript executes inside a wrapper which is designed to prevent creating variables in the global scope. And in this wrapper, this
(or @
) is the global object.
So this:
class Issue
constructor: ->
@Issue = Issue;
Compiles approximately to this JS:
(function() {
var Issue;
Issue = (function() {
function Issue() {}
return Issue;
})();
this.Issue = Issue;
}.call(window));
In that JS, window
becomes this
, and properties of window become global variables. So from now on, you only need to type Issue
in any other JS file and you will have the issue constructor.
Without the @Issue = Issue
line, the Issue
constructor would never be available outside that code, and no other file could use it.
In other words, it's the same as this:
window.Issue = Issue;
Which I actually prefer most of the time. It's more clear what's going on as window
always means window
, but @
can mean many things depending on where it appears.
OTHER TIPS
Just like in JavaScript, there is no proper namespacing in coffeescript. @Issue = Issue
translates to this.Issue = Issue
. My guess is that this snippet is meant to be concatenated with other files during build, one of them opening an anonymous closure, similar to the one below.
var namespace1 = {subnamespace1: {}};
(function() {
// Several concatenated files
}).call(namespace1.subnamespace1);