Under Rails3.1.1/Coffeescript - not always getting the function safety wrapper - ruby-on-rails

I have recently started using coffeescript with Rails and I am finding that sometimes the generated javascript does not get the function safety wrapper.
Here is a sample project demonstrating it.
For example, this CS code, in index.js.coffee:
class Foo
afunc: ->
alert("afunc")
Correctly becomes:
(function() {
var Foo;
Foo = (function() {
function Foo() {}
Foo.prototype.afunc = function() {
return alert("afunc");
};
return Foo;
})();
}).call(this);
But this code, from other.js.coffee:
class App.Func
ouch: ->
alert("ouch")
becomes this un-wrapped version
App.Func = (function() {
function Func() {}
Func.prototype.ouch = function() {
return alert("ouch");
};
return Func;
})();
It seems to be due to the "App." prefix - which I can see affects naming/scope - but why is coffeescript compiling it differently...
App is defined in setup.js.coffee, like this:
window.App =
Models: {}
Which also does not get wrapped, unless I add a class into that file too.
I am sure it must be my misunderstanding - so thanks in advance for the pointers to the manual :).
EDIT:
I created this question as I thought it might be behind some issues I was having with my backbone/coffeescript app, but it seems that it was not. As the class is linked to a public/global thing "App", it seems to work wrapped or not. Still would be useful to know why its happening - is it by design?

The "function safety wrapper" feature you are using works to prevent local variables from being set on the global namespace. Since setting an object property (App.Func) doesn't affect the global namespace, the declaration is not wrapped in a function.

Related

How do I run some code only once in Dart?

I wonder if there's a language sugar/SDK utility function in Dart that allows to protect a certain code from running more than once?
E.g.
void onUserLogin() {
...
runOnce(() {
handleInitialMessage();
});
...
}
I know I can add a global or class static boolean flag to check but it would be accessible in other functions of the same scope with a risk of accidental mixup in the future.
In C++ I could e.g. use a local static bool for this.
There is no built-in functionality to prevent code from running more than once. You need some kind of external state to know whether it actually did run.
You can't just remember whether the function itself has been seen before, because you use a function expression ("lambda") here, and every evaluation of that creates a new function object which is not even equal to other function objects created by the same expression.
So, you need something to represent the location of the call.
I guess you could hack up something using stack traces. I will not recommend that (very expensive for very little advantage).
So, I'd recommend something like:
class RunOnce {
bool _hasRun = false;
void call(void Function() function) {
if (_hasRun) return;
// Set after calling if you don't want a throw to count as a run.
_hasRun = true;
function();
}
}
...
static final _runOnce = RunOnce();
void onUserLogin() {
_runOnce(handleInitialMessage);
}
It's still just a static global that can be accidentally reused.

Fable F# to Javascript: Parameterless functions being given a parameter when referenced

I am having difficulty referring to parameterless functions in Fable.
With this example:
let f1 () =
1
let someRefTof1 = f1
I'd expect the generated js to look something like this:
function f1() {
return 1;
}
var someRefTof1 = f1;
but what I actually get is:
function f1() {
return 1;
}
var someRefTof1 = exports.someRefTof1 = function someRefTof1(arg00_) {
return f1(arg00_);
};
I'm unclear on the purpose of arg00_ or how to avoid it being generated?
(As a bit of background, I am struggling to call a function in an external js library which expects a function to be passed as a parameter)
Edit:
Background
The above is what i believe to be a minimal, verifiable, reproduction of my question but, after comments, I thought it may be useful to provide a touch more context on why this is causing issues. What I am actually trying to do is use angularjs from Fable.
So my example looks more like this:
let app = AngularFable.NgFable.angular.``module``("app",[||])
type TestCtrl() =
member this.Val1() = "boom";
app?controller("test", TestCtrl)
which gets compiled to:
var app = exports.app = angular.module("app", []);
var TestCtrl = exports.TestCtrl = function () {
function TestCtrl() {
_classCallCheck(this, TestCtrl);
}
TestCtrl.prototype.Val1 = function Val1() {
return "boom";
};
return TestCtrl;
}();
_fableCore.Util.setInterfaces(TestCtrl.prototype, [], "App.TestCtrl");
app.controller("test", function (unitVar) {
return new TestCtrl();
});
with unitVar being the problematic parameter introduced in this example. When I use this in my html with something like:
<div ng-app="app">
<div ng-controller="test as vm">
{{vm.Val1()}}
</div>
</div>
I run into an unknown provider error whereas if I simply change the compiled javascript to remove the unitVar parameter from the last line like this:
app.controller("test", function () {
return new TestCtrl();
});
then my example works as expected.
I'd really like to know if there is a way to avoid having the Fable compiler generate this parameter. I'm 99% sure this reduces to the same problem as in my original question but I've included this additional context to better explain why this is an issue
Thank you very much for your question and detailed explanations. There're two things here that are a bit tricky and are caused by optimisations both of the F# compiler and Fable.
In the AST provided by the F# compiler, methods (functions that are members of a type or module) are compiled as usual methods as in C#. This is for optimization.
However, when you create an anonymous lambda or make a reference to a method, the F# compiler will keep F# semantics, that is, all functions have a single argument (as John Palmer says, unit is an argument too) and can be curried.
Ok, this info is just to make clear why the F# compiler/Fable represent methods and lambdas differently. Let's go with the issue of argumentless functions: the obvious solution would be of course to remove the F# compiler generated argument for functions accepting unit (as it's already done for methods). In fact, I also had problems with libraries like Mocha because of this.
I did try to remove the unit argument at the beginning but I got fails in some scenarios because of this. TBH, I don't remember now exactly which tests were failing but because of the expectation that there'll be always an argument, in some cases function composition or inlining was failing when the unit argument was removed.
Other attempts to modify the semantics of F# functions in the JS runtime have always failed because they don't cover all scenarios. However, we can be more lenient with delegates (System.Func<>) as it's usually safe to assume these ones should behave more like functions in languages like C# or F#. I can try to remove the unit argument just for delegates and see what happens :)
For more info about sending F# functions to JS code you can check the documentation.
UPDATE: Scratch all that, please try fable-compiler#0.6.12 and fable-core#0.6.8. This version eliminates unit arguments, the solution was actually simpler than I thought and (hopefully) shouldn't create issues with existing projects. (The explanation about methods and lambdas compiled differently still applies.)

BackboneJS view keeps returning not defined

I can't seem to initialize my view. I tried looking around to see if this was asked before, but none of the solutions were working for me. My backbonejs view is below:
class FRView extends Backbone.View
el: $ 'fr_view'
initialize: ->
console.log("created")
render: ->
console.log("here")
I'm attemtpting to intialize it inside of a partial using the code below:
:javascript
var curr_view = new FRView()
but I keep getting the following error:
Uncaught ReferenceError: FRView is not defined
I've also tried
:javascript
var curr_view = new Backbone.View.FRView()
Which lead to the following error:
Uncaught TypeError: Backbone.View.FRView is not a constructor
From chrome sources browser I can see that the FRView file is loaded. I've also tried wrapping it in document onload but that didn't help. Any idea what might be causing this issue?
I see two bugs, one you know about and one that you'll find out about soon.
The first problem (the one you know about) is caused by CoffeeScript's scoping system:
Lexical Scoping and Variable Safety
[...]
Although suppressed within this documentation for clarity, all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })();
So your FRView ends up looking more or less like this in JavaScript:
(function() {
var FRView = ...
})();
and that means that FRView is only visible inside your CoffeeScript file.
The easiest solution is to put the class in the global scope:
class #FRView extends Backbone.View
or equivalently:
class window.FRView extends Backbone.View
Another common solution is to define a global namespace for your app and then put your class in that namespace:
class YourNameSpace.FRView extends Backbone.View
and say new YourNameSpace.FRView when instantiating it.
The other problem is that your el looks a bit confused:
el: $ 'fr_view'
There are two problems here:
That will be looking for an <fr_view> element in your HTML and you probably don't have such a thing. I'd guess that you really have something like <div id="fr_view"> or maybe <div class="fr_view">, in that case you'd want to say:
el: '#fr_view' # If you're using an id attribute.
el: '.fr_view' # If you're using a CSS class.
$ 'fr_view' will be executed when the JavaScript is loaded and the element might not exist at that time. The solution to this problem is to use just the select for el as above. There's no need to use a jQuery object for el, Backbone will do that for you when the view is instantiated.
As 'mu is too short' pointed out, the issue rooted from namespace/declaration issues. After googling around about namespace I skimmed through this and fixed the issue by changing my backbonejs view to:
class Portal.Views.FRView extends Backbone.View
el: $ '#FRView'
initialize: ->
console.log("created")
render: ->
console.log("here")
and instantiated it using:
:javascript
var frview = new Portal.Views.FRView();

Using mirrors, how can I get a reference to a class's method?

Say I have an instance of a class Foo, and I want to grab a list of all of its methods that are annotated a certain way. I want to have a reference to the method itself, so I'm not looking to use reflection to invoke the method each time, just to grab a reference to it the first time.
In other words, I want to do the reflection equivalent of this:
class Foo {
a() {print("a");}
}
void main() {
var f = new Foo();
var x = f.a; // Need reflective way of doing this
x(); // prints "a"
}
I have tried using InstanceMirror#getField, but methods are not considered fields so that didn't work. Any ideas?
As far as I understand reflection in Dart, there's no way to get the actual method as you wish to. (I'll very happily delete this answer if someone comes along and shows how to do that.)
The best I can come up with to ameliorate some of what you probably don't like about using reflection to invoke the method is this:
import 'dart:mirrors';
class Foo {
a() {print("a");}
}
void main() {
var f = new Foo();
final fMirror = reflect(f);
final aSym = new Symbol('a');
final x = () => fMirror.invoke(aSym, []);
x(); // prints "a"
}
Again, I know that's not quite what you're looking for, but I believe it's as close as you can get.
Side note: getField invokes the getter and returns the result -- it's actually fine if the getter is implemented as a method. It doesn't work for you here, but for a different reason than you thought.
What you're trying to get would be described as the "closurized" version of the method. That is, you want to get the method as a function, where the receiver is implicit in the function invocation. There isn't a way to get that from the mirror. You could get a methodMirror as
reflect(foo).type.methods[const Symbol("a")]
but you can't invoke the result.

Free standing function in coffeescript in Rails 3.2.8

I've recently started using coffeescript in my rails projects pretty heavily.
I'm curious how you make a free standing function. So if I do:
foo = ->
alert("hello world")
That compiles to
(function() {
var foo;
foo = function() {
return alert("hello world");
};
}).call(this);
How do I make it compile to
var foo;
foo = function(){
return alert("hello world");
}
I want to be able to call use link_to_function "foo"
There are actually several ways you can accomplish this (one way already given in the comments).
Compile without the closure wrapper
This will expose all functions to the outer scope. This may be an option if you are using a lighterweight framework where you can control of the build process. I'm not sure you would be able to within the context of the asset pipeline but works great in the context of a small sinatra app.
coffee -b myfile.coffee
Attach to a global object
If you know you are targeting a specific runtime, like the browser you can use the global window object.
window.foo = -> alert("hello world")
This is the same effect as the solution in the comments since the target is a Rails environment. But using # which is sugar for this. will attach it to whatever the scope of this is at the moment. Assuming the function is not being defined in a callback or an internal object with a bound context, it would likely be the window object.
#foo = -> alert("hello world")
Better would be to create your own namespace and attach that way:
Mine ||= {}
Mine.foo = -> alert("hello world")
#Mine = Mine
CoffeeScript classes
Or use CoffeeScript's class syntax to do the same by attaching to the prototype itself:
class #Mine
#foo: -> alert("hello world") # called as Mine.foo() (notice the # declaration)
In our rails applications we typically have an asset that defines the namespace, aka a file at app/assets/javascripts titled mine.coffee:
window.Mine ||= {}
and then in other files we can require that namespace:
#= require mine
class Mine.MyOtherThing
#foo: -> alert("hello world")

Resources