Google Closure Compiler: Declaring properties in externs - properties

I've just been trying to work out how to do this, and didn't find much on google, so I'll document what I found here.
I needed to define a JS class in an external library and also define some properties and method on it. I could do methods and the class, but was hitting a wall with properties.
So how is it done?

OK, let's imagine I've got an external JS class called 'Bob'.
My closure externs for this would be:
/** #constructor */ var Bob = function() {};
If I had a method (flyAway(speed)) I would add:
Bob.prototype.flyAway = function(speed) {};
And if I had a property (currentSpeed) I would add:
Bob.prototype.currentSpeed;
(the last one, I was doing (stupidly in hindsight) Bob.currentSpeed;)

Related

Kotlin variables that are not in scope?

On https://github.com/mozilla/rust-android-gradle/blob/8183f9e927336011c7c09d75efd4f5f411940db1/plugin/src/main/kotlin/com/nishtahir/CargoBuildTask.kt#L19 we have this kotlin code:
open class CargoBuildTask : DefaultTask() {
var toolchain: Toolchain? = null
#Suppress("unused")
#TaskAction
fun build() = with(project) {
extensions[CargoExtension::class].apply {
I'm very confused as from where does extensions come from, as well as project. They aren't local variables, they aren't in a scope or something. What are they?
Inheritance is the answer to project.
CargoBuildTask : DefaultTask()
Do you see how CargoBuildTask inherits properties of DefaultTask?
Thus project is a property from DefaultTask. However, extensions is a property from project which is of Type Project.
Read this documentation on DefaultTask and you will have more understanding.
Kotlin's with is the answer to extensions.
In short, with with you can invoke methods without explicitly stating its subject. (Read more here)
For example, these two code snippets mean the exact same thing:
with("string") {
substring(3) //invoke method without subject
}
"string".substring(3) //Same as above
Here is the method from org.gradle.api.Project
ExtensionContainer getExtensions();
Now, If you are wondering how Java's getExtensions() turned into Kotlin's extensions, read this. Basically states that traditional Getters and Setters in Java are interpreted as Properties in Kotlin.
PS: If you are unsure of what Inheritance is in OOP/Kotlin, read this.
The projectcomes from the DefaultTask() inherited in the current class. Inheritance is used here which is a very basic concept. Read more about Kotlin's inheritance here.
The extensions comes from project using with which is one of the scope functions.
Read more about with here.
.
For example. Suppose you've a Data class.
data class PersonModel(val name: String, var age: Int)
And you create a model of it as
val personModel = PersonModel("Adam", 30)
Now, if you pass it to a with function as a reciever, you can access 'personModel`'s properties directly in the with's scope as:
with(personModel) {
//name is the property of personModel
val nameWas = name
//Declared var and can be editable.
age = 31
}
with works with functions as well where you can pass a function as a reciever to it and it returns the returned value of the function.
These scope functions (let, run, with, apply, also) are extremely useful in production environment.

Swift class properties not initialized when constructed by Objective C code

I'm attempting to create a class in Swift 3 to implement a Cordova plugin. I have this building and running, but the application crashes whenever any properties of the class are accessed. I've tried two ways of initializing the class:
#objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
var players = [UUID:DSFPlayerHandler] ();
...
}
and
#objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
var players :[UUID:DSFPlayerHandler];
override init () {
players = [:];
}
...
}
However, when my players property is used, the result is a EXC_BAD_ACCESS exception, with an address that looks like a null pointer dereference.
The object is being created by Objective C code, which is a language I have no familiarity with at all, but I think this is the line that creates it:
obj = [[NSClassFromString(className)alloc] initWithWebViewEngine:_webViewEngine];
The CDVPlugin class contains a comment stating that initWithWebViewEngine should not be overridden (and indeed I do not seem to be able to override this method, because while it is declared in the CDVPlugin.m file, it isn't mentioned in CDVPlugin.h, so the Swift compiler doesn't seem to know about it), but rather initialization code should be placed in a method called pluginInitialize instead. However, if I do that I get a compiler error ("Class DSFMediaCentre has no initializers").
Furthermore, if I put my init() method back in and set it to call pluginInitialize(), like this:
override init () {
super.init(); // necessary otherwise next line is an error
pluginInitialize();
}
override func pluginInitialize() {
players = [:];
}
the error then changes to "Property 'self.players' not initialized at super.init call".
How do I make this class initialize correctly?
You have a mismatch between the strict initialization system required by the language and the procedure used by the framework you're working with.
Swift demands that a) properties be initialized as part of object construction, and b) that construction be chained to the type's supertype. But the CDVPlugin type is doing the construction on your behalf; you don't have the ability to customize it. (This makes more sense in ObjC, because it doesn't have the same compile-time restrictions as Swift.)
The situation is similar to unpacking an object from a nib file. In that case too, because it's the nib loading system that's constructing your object, you don't have the ability to customize the initializer. Your type will always be constructed by init(coder:). In a certain sense, your initialization point moves further down, to awakeFromNib(), and among other things, that forces outlets to other objects in the archive to be declared as optional, usually implicitly unwrapped.
The same solution should avail you here. You should consider pluginInitialize() to be your initialization point. The language then requires that properties be optional, since they are not filled at its initialization point. Therefore, make the property an IUO:
#objc(DSFMediaCentre)
class DSFMediaCentre : CDVPlugin
{
var players :[UUID:DSFPlayerHandler]!
override func pluginInitialize() {
players = [:];
}
}
and all should be well.
The other solution is to use lazy keyword
lazy var players :[UUID:DSFPlayerHandler] = [:]
So, you don't need to initialize players in initializer but still make sure players always non-nulable

Add methods to an assigned closure with GroovyDSL

Geb uses a static field called content to define the contents of a page or module. The value of the content field is a closure.
class GebishOrgHomePage extends Page {
static content = {
manualsMenu {
module MenuModule, $("#header-content ul li", 0)
}
links { $('.link-list li a') }
}
}
Intellij already has support for this content dsl, however it does not support the module and moduleList methods. This causes limited auto-complete support when working with modules.
To fix this I'd like to write a GroovyDSL script that adds the missing method definitions to the content closure and its nested closures. However, I've no idea how to add methods to a closure that is not passed to a method, since enclosingCall requires a concrete method name.
And the other thing is that those methods must have a generic return type like this:
<T extends Module> T module(Class<T> m) {
// return an instance of T
}
If you use the latest snapshot then module() calls will be understood by your IDE. This is down to moving module() to Navigator exactly for what you are after - autocompletion and strong typing.
Have a look at the current version of section 6.4 of the Book of Geb. The moduleList() will be gone in a future release and that section explains what to use instead. The module() method taking a map argument to initialise module properties will also go, you now initialise the module yourself and pass the instance to module() and there is an example of doing this in 6.4. Thanks to all that you will get autocompletion around module defintions and usage in IntelliJ.

Chain up to 'Gtk.Box.new' not supported

I'm new to Vala and so far I think it's pretty cool but I'm having trouble understanding inheritance. I read here that I should use base() to call the parents constructor. Alright, cool, seems understandable but It din't work for me. I kept getting the error on the title. Here is my snippet to show:
public class MyBox : Gtk.Box {
public MyBox(Gtk.Orientation orientation, int spacing) {
// I have to this
this.set_orientation(orientation);
this.set_spacing(spacing);
// I want to do this:
base(orientation, spacing);
//workaround is this:
Object(orientation: orientation, spacing: spacing);
}
}
Please help me understand why Object(....) works but not base(...)
Shouldn't it be the same thing?
This is due to implementation of the C code. When Vala generates a constructor, it generates two C functions a _new function that allocates memory and calls the _construct and a _construct function that initialises the object. When you case the base constructor using base(), it needs a matching _construct function to call. Not all the classes written in C have this; in the VAPI file, you will find has_construct_function = false for some constructors. If this is the case, no chain-up can be done. The base GObject can set properties from arguments, so this becomes the only way to set defaults in the base class.

Using dojo.require() without dojo.declare()

I'm quite confused from Dojo's documentation. How can I use dojo.require() without actually using dojo.declare()? The reason I don't want to use dojo.declare() is that it exposes declared class as global variable.
Right now my code looks like this:
HTML file:
dojo.require('module.test');
Module/test.js:
dojo.provide('module.test');
function test() {
return 'found me';
}
I just can't get Dojo to return test() method anywhere. What's the correct pattern for using dojo.require() without declaring?
I think you are confusing dojo.provide/dojo.require with dojo.declare. They are completely different concepts.
Things that relate to modules
dojo.provide defines a module.
dojo.require requires that a module be defined before running any code later.
Things that relate to JavaScript classes
dojo.declare is something completely different. It declares a Dojo-style class.
You can have multiple classes in a module, or several modules making up one class. In general, modules !== classes and they are completely unrelated concepts.
dojo.provide defines the code module so that the loader will see it and creates an object from the global namespace by that name. From that point, you can anchor code directly to that global variable, e.g.
Module/test.js:
dojo.provide('module.test');
module.test.myFunc = function() {
return 'found me';
}
There are various patterns you can use, such as creating a closure and hiding "private" function implementations, exposing them via the global reference you created in dojo.provide:
dojo.provide('module.test');
function(){
// closure to keep top-level definitions out of the global scope
var myString = 'found me';
function privateHelper() {
return myString;
}
module.test.myFunc = function() {
return privateHelper();
}
}();
Note that the above simply puts methods directly on an object. Now, there's also dojo.declare, which is often used with dojo.provide to create an object with prototypes and mixins so that you can create instances with the 'new' keyword with some inheritance, even simulating multiple inheritance vai mixins. This sort of OO abstraction is often overused. It does approximate the patterns required by languages like Java, so some folks are used to declaring objects for everything.
Note that as of Dojo 1.5, dojo.declare returns an object and does not necessarily need to declare anything in the global scope.
Here's a pattern I sometimes use (this would be the contents of test.js):
(function() {
var thisModule = dojo.provide("module.test");
dojo.mixin(thisModule, {
test: function() {
return "found me";
}
});
})();
Now you can reference module.test.test() in your HTML page.