How to best use global service classes in Aurelia - aurelia

I have some services which are used by many classes in my application. As an example this could be a LoggerService which logs messages to an internal store and prints them to the console.
This service could look something like this:
export class LoggerService {
let _logs = [];
addLog(msg) {
this._logs.push(msg);
console.log(this._logs.length + ': ' + msg);
}
}
I guess the usual way in Aurelia would be to use this class with dependency injection which works just fine since it uses a singleton per default. An example usage could then look something like this:
import {autoinject, Aurelia} from 'aurelia-framework';
import {LoggerService} from 'LoggerService';
#autoinject
export class SomeViewModel {
let _loggerService;
constructor(loggerService) {
this._loggerService = loggerService
}
somethingChanged() {
this._loggerService.addLog('Something changed...');
}
}
Basically this approach works just fine but it feels a little "clumsy" at a larger scale and I hope that it could be simplified:
Using dependency injection requires a lot of boilerplate code in each "using class" which unnecessarily "bloats" them (import statement, a dedicated class member which needs to be assigned in the constructor etc.).
I'm used to having such classes inside a dedicated namespace which lives in the window object. This allows me convenient debugging since I can call code like MyNamespace.LoggerService.addLog('blahblah'); directly from the command line. How do I accomplish this best with Aurelia?
Is there an more straight forward way which would also give me a better debug experience from the command line?

Honest answer? If you follow ES6 modular code conventions, not really. You will always be importing modules if and when you require them. There are things that you can do, which I'll go over in this answer.
You don't actually need to use Aurelia's dependency injection if you don't want to. However, that means that you'll have to handle the lifecycle of the object yourself. Because your object is a class, you'll have to call "new" on it when you import it. However, you can write your logging module differently, and instead of exporting a class, you can export a function, like so:
let _logs = [];
export var LoggerService = {
addLog: function (msg) {
_logs.push(msg);
console.log(_logs.length + ': ' + msg);
}
}
That way, all you have to do is import LoggerService and call LoggerService.addLog inside of your Aurelia view without having to inject it. This is a more functional approach than the class instantiation approach, which can work very well.
import {LoggerService} from 'LoggerService';
export class SomeViewModel {
constructor() {
}
somethingChanged() {
LoggerService.addLog('Something changed...');
}
}
Another thing you can do (I wouldn't recommend this) is simply make this a window variable. This would mean that you wouldn't have to import modules. This violates module principles, though, and things get messy really quickly. Modules exist for a reason, and although import statements do add lines of code, the benefits are worth the extra space.
For your use case, I would use the function-based approach above, and I would check a "development" flag somewhere so that you can expose properties on the window object so that you can access them through the console. (You wouldn't want this available in a production environment, as people could easily mess up your application.) Something like
if (developmentFlag) { window.loggerService = LoggerService; }
This may be the best approach until we're able to run the import statement in the console REPL.

Related

Exception when I change to other scene in KorGE

com.soywiz.korinject.AsyncInjector$NotMappedException: Class 'class ChooseCampaign (Kotlin reflection is not available)' doesn't have constructors RequestContext(initialClazz=class ChooseCampaign (Kotlin reflection is not available))
Above exception was threw when I compiled current code. And I dont know how fix it and what does it means.
My code:
textButton {
position(0, 128)
text = "Play"
onClick {
println("Play")
launchImmediately {
sceneContainer.changeTo<ChooseCampaign>()
}
}
}
How it fix?
When using Scenes in KorGE, you are using the korinject dependency injector indirectly.
And that injector requires manual mapping. If you are using Modules, you can configure those mappings at the Module.init method.
Check this sample: https://github.com/korlibs/korge-samples/blob/1771b7ca7f4440e1a368ff4b441e97bf62e08b8d/sample-scenes/src/commonMain/kotlin/main.kt#L15-L23
In your case, once you get the Injector instance, you can map a scene like this:
mapPrototype { ChooseCampaign(get()) }
You have to put as many get() as parameters your ChooseCampaign constructor has.
In the case you are not using modules, the place to put the mapping is different, and you need to get the Injector instance.
In your suspend fun main() = Korge { block, you have the Stage singleton injected. This is the root view that has a reference to the Views singleton.
So there you can just access the injector like this: this.views.injector
You can then map your scenes whenever you like, though I suggest you do to it at the beginning of the application.

Catching up with 'require' for a metamodel class

I have defined own metamodel class to create a special kind of classes. Now, I would like these classes to automatically register themselves with a special kind of manager. Basically, this would like like this (would only compose be called each time when class' module is being loaded):
use MyManager;
class MyHOW is Metamodel::ClassHOW {
method compose ( Mu \type ) {
self.add_parent( type, MyParentClass );
callsame;
registerMyClass( type );
}
}
Then I have something like:
use v6;
use MyClass;
myclass Foo { ... }
in a module. Then there is a manager object which scans repositories/file system and requires modules with names matching to a certain pattern. Afterwards, it needs to know what myclasses are defined in each module. It could scan the symbol table of the loaded module. But this won't work if the loaded file contains multiple modules or no modules at all – like in the example above.
So far, it looks like the INIT phaser would provide the solution, but I'm struggling to find how to get the body block of a class from within the composer method.
When doing meta-programming, the meta-object's methods are invoked during compilation, as declarations are parsed. Therefore, the compose method is called immediately after the parsing of a myclass foo { } declaration. The result of the module's compilation is then saved, and nothing in the meta-object will be processed again when the module is loaded.
There's no supported way that I'm aware of to inject a load-time callback into the module where a type is being declared. However, it's possible to install the symbols into a separate package - used as a registry - and then find them there.
For example, given I have a lib/MyClass.pm6 that looks like this:
package MyRegistry { }
class MyParentClass { }
class MyHOW is Metamodel::ClassHOW {
method compose ( Mu \type ) {
MyRegistry::{self.name(type)} = type;
self.add_parent( type, MyParentClass );
callsame;
}
}
my package EXPORTHOW {
package DECLARE {
constant myclass = MyHOW;
}
}
And I write some files mods/A.pm6 and mods/B.pm6 like this:
use MyClass;
myclass A { }
And this:
use MyClass;
myclass B { }
Then when I require them in a script like this, and dump the keys in MyRegistry, they'll both be registered there:
use MyClass;
for dir('mods', test => /pm6$/) {
require $_;
}
dd MyRegistry.WHO.values;
Thus giving a predictable way to find them all.
Note that for a technique like this to work, you really need to have them stored into a Stash, since the loader knows how to symbol-merge those, whereas other types touched in different ways during the compilation of different modules will result in load-time conflicts.
You are left with the slight challenge of making sure to install everything under a sufficiently unique key; the type name as I used here is probably not unique enough in general. Probably I'd just generate something sufficiently random that the chance of a collision is hugely unlikely.

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.

Typescript error when using interface from module as field within class

I am working on providing a type definition file for fabric.js. The general structure is shown in the following sample:
declare module fabric {
export interface Canvas {
selectionBorderColor: string;
selectionColor: string;
...
}
var Canvas: {
new (): Canvas;
}
}
This pattern allows me to use fabric.Canvas in a 'interface-like' way, so that variables are associated with the fabric.Canvas interface. At the same time it allows me to call "static members" (such as the constructor of fabric.Canvas).
But this leads to a problem when using a field of interface 'fabric.Canvas' within a class. The following sample shows such an case:
This problem only occurs when placing the interface within a module, otherwise everything works fine.
Any solutions for this problem?
There is some type confusion because you have an interface and a field with the same name - I know this is common in the lib.d.ts file, but I don't think it is a good practice when writing new TypeScript code. It seems to be something of a necessity for defining existing code.
If you rename var Canvas to var MyCanvas (or anything else) your code works.
I tend to prefix my interfaces with an I, for example ICanvas - but this isn't a TypeScript convention (yet).
declare module fabric {
export class Canvas {
selectionBorderColor: string;
selectionColor: string;
}
}
class MyClass {
canvas: fabric.Canvas;
}

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.