livelykernel / contextjs Goto Github PK
View Code? Open in Web Editor NEWContext-oriented Programming (COP) for JavaScript
License: MIT License
Context-oriented Programming (COP) for JavaScript
License: MIT License
Writing import * from ".../cop"
should make the module "cop-aware", so you have proceed
, withLayers
, withoutLayers
and a method to access a layer (layer
?, currently create
) available at module scope.
When a class without accessor methods for a property is refined by a layer with other accessing behavior, the original property value is not preserved when the accessors are used while the layer is active:
it('can provide state for classes', function() {
class Example {
constructor() {
this.a = 0;
}
}
const o1 = new Example(),
o2 = new Example(),
layer1 = new Layer('LtestLayerStateInTwoObjects1');
layer1.refineClass(Example, {
get a() { return this.l1_value },
set a(value) { this.l1_value = value },
});
assert.equal(o1.a, 0, "getter broken");
o1.a = 1;
assert.equal(o1.a, 1, "setter broken");
cop.withLayers([layer1], () => {
o1.a = 20;
o2.a = 30;
assert.equal(o1.a, 20, "layer state in first object broken");
assert.equal(o2.a, 30, "layer state in second object broken");
});
assert.equal(o1.a, 1, "getter broken after layer activation"); // this fails, a is 20
o1.a = 2;
assert.equal(o1.a, 2, "setter broken after layer activation");
});
But it works if not the class is refined, but an object with an own property a instead (same partial accessors in the layer).
Currently, the old cop
object is the default export, while there are also some named exports like the Layer class. Basically, I just exported things in such a way that the changes to the existing unit tests are minimal...
Since the cop object is only the old means of scoping, when ES6 modules were not a thing, we could replace that by lots of named exports which can then be imported like this: import * as cop from '.../Layers'
if that were preferable. It would also allow to only import layerClass, layerObject, or Layer if you need them. What would be a good default export then? Or we keep both ways, having the cop object as a default export, but all individual "global" cop functions primarily as named exports. That would mean, the cop object is only assembled at the end of the module like this export default { layerClass: layerClass, layerObject: layerObject, ... }
.
Given the following classes and layer:
class Base {
m() { return "m" }
}
const L = new Layer('DummyLayer').refineClass(Base, {
m() { return "L," + cop.proceed() }
});
class Child extends Base {
m() { return "Subm" }
}
Because we cannot enumerate the subclasses of a class, the following holds for Child:
const o = new Child();
cop.withLayers([L], () => { assert.equal(o.m(), "Subm", "not wrapped");
But, if another layer refines the subclass method subsequently:
const L2 = new Layer('AnotherOne').refineClass(Child, {
m() { return 'L2,' + cop.proceed() }
});
suddenly, Child#m also behaves differently when L is activated:
cop.withLayers([L], () => o.m()); // 'L,Subm'
cop.withLayers([L, L2], () => o.m()); // 'L2,L,Subm'
It would be consistent, if L did not apply to Child#m at all, because it did not when L2 did not refine it yet.
Thus, the expected behavior is:
cop.withLayers([L], () => o.m()); // 'Subm'
cop.withLayers([L, L2], () => o.m()); // 'L2,Subm'
As standard ECMAScript does not support retrieving all "subclasses" or derived prototypes from a given class/prototype, we cannot keep that functionality.
If we do not want to rely on a non-standard ECMAScript class system, we have to drop support for method names like LayerName$layeredMethodName becoming partial methods automatically. It would be possible to rectify classes/prototypes with these later, or we could write some kind of mixin which does that, but this can be done when the need for it arises in the first place.
The test cases relying on that syntax should be rewritten with the class-in-layer syntax (refineClass/refineObject) or removed if the same test case exists with class-in-layer syntax already.
layers should be able to make methods in their target object layer aware again after they have changed.
As ES6 isn't supported natively, transpilation to ES5 is needed before publishing.
During the refactoring, the code was moved to copv2/Layers.js. Now that it is complete, we should move it back to the package root and rename copv2 to cop.
Karma can control and test on most of the standard browsers out there automatically. But I have only run the tests with Chrome 47 until now. We should define which Browsers we want to support and run the tests for all of them as well. This is related to #4 because Travis could maybe run all browser tests for us.
As Jens I want to write code like this:
layer("Foo").refineClass(whatever, {
stuff() { return "bar" }
}
withLayers([Foo], () => whatever.stuff()
and later change my mind about what Foo should do, so I want to change the code to:
layer("Foo").refineClass(whatever, {
stuff() { return "bla" }
}
reevaluate that (Lively do-it) and expect that withLayers([Foo], () => whatever.stuff()
now returns "bla". That means, that the existing Foo has been changed, and no new "Foo" layer has been created. This is especially important if you activate a layer globally and then change it.
Fill them in before publishing the package after discussing what they should contain - needed to complete #23
Think of a solution so the import statement looks nice in apps using ContetxJS. package.json and bower in combination with an index.js might help.
That "main" file should export functions as indicated in #19, while more implementation details should be importable as they currently are, by importing directly from Layers.js.
Not sure whether this should go here or into the Lively repository...
For demo purposes, we could implement structural layers and an example in the new Lively, like it was in the old one. By the way we can evaluate if the LayereableObjectTrait can or should be refactored into a mixin (like presented as an idiom for ES6 classes).
When #14 is merged, we will have three builds per push/PR, for the node versions 4, 5, and the latest. But all of them run the karma browser tests, which is nonesense. Ideally, we would have those three builds running the tests only for node (using mocha) and either
Currently there are two ways to define partial state or behavior:
cop.layerObject(theLayer, theObject, thePartials)`
and
theLayer.refineObject(theObject, thePartials)`
...and their respective companions layerClass
and refineClass
.
I think the latter reads better. Should we therefore deprecate the other syntax?
Make sure that
We could build a simple test app, which requires ContextJS and should be running properly after invoking npm install or bower install.
Long time ago, you would write cop.createLayer("foo.bar.bla.MyLayer", ...)
with the effect that the Layer object was accessible as foo.bar.bla.MyLayer
. To achieve that, createLayer
parsed the dotted expression and put the layer into the innermost context object. Well, cop.create
still supports that if you provide it with the outermost object: cop.create(foo, "bar.bla.MyLayer")
will currently put MyLayer in foo.bar.bla.
I would like to drop that feature, since you should better write cop.create(foo.bar.bla, 'MyLayer')
instead (or in the future layer(foo.bar.bla, 'MyLayer').refine...
). Or foo.bar.bla.MyLayer = new Layer(...)
if you want to overwrite that property (in constrast to the proposed layer(...)
behavior).
I cannot assign labels, milestones or people to issues here, but would very much like to do so during the seminar. @JensLincke can you grant us the appropriate permissions, please?
Particularly about using https://github.com/lzrski/npm-git-install for the time being if depending directly on the GitHub repository.
Probably the readme should also include some information about the transpilation to justify the above.
k.t.
Possibly with karma --single-run? Don't know if travis can conduct tests which require spawning browsers...
Once we have that layer("LayerName")
"accessor", we would still have to write
let LayerName = layer("LayerName")
to have a variable called LayerName for use with withLayers. Otherwise you would have to write withLayers([layer("LayerName")], ...)
, which is both wordy and typo-prone (if you type withLayers([layer("LayerNaem"], ...)
a new layer would be created).
Some tests still use __lookupGetter__
and the like. Port them to their standard equivalents, just like the Layers.js has already been ported.
The feature implemented for #34 is useful in environments like Lively, but less so in ordinary web applications where methods are seldom or never modified. Since the additional getter call probably adds a performance overhead (which is yet to be measured...), it should be somehow configurable if that technique should be applied or not. In the latter case, the method wrapping should happen as it did before the changes to implement #34.
We could configure this behavior, for example, by adding a configure function or configuration object in the contextjs module.
Probably Jasime or Mocha, optionally with something like Chai assertions... The tests are currently written with LivelyKernel's own testing framework.
Remove the remaining pieces of non-plain-ES6 code. Recommendation: just delete these two files and fix everything that goes red.
and get it running stand alone
To ensure compatibility with node-based environments.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.