Code Monkey home page Code Monkey logo

contextjs's People

Contributors

athomschke avatar fbornhofen avatar j4yk avatar jenslincke avatar levjj avatar rksm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

contextjs's Issues

Refined accessors in the class also modify the original property

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).

Review Layers.js module exports

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, ... }.

Refining a subclass method also applies layers for the super class method

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'

Remove support for layer-in-class syntax

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.

Test with other browsers than Chrome

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.

Rename create to layer and let it return existing layers if the name exists

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.

Make cop importable as import "contextjs"

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.

Add structural layering to Lively4 Morphs (or arbitrary DOM elements)

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).

Optimize Travis build matrix

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

  • one additional build that tests all browsers (using karma), or
  • multiple additional builds that each run tests for exactly one browser

Deprecate layerClass, layerObject functions

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?

Create publish-ready package.json and bower.json files

Make sure that

  • the license is right (include a LICENSE or COPYING file by the way)
  • the contact info is up-to-date
  • the dependencies are accurate
  • the entry-points (main files, probably) are defined correctly
  • the version number should probably start at 2.0.0 (1.x being the Lively-tied non-ES6 ContextJS)

We could build a simple test app, which requires ContextJS and should be running properly after invoking npm install or bower install.

Drop the "deep injection" feature of cop.layer(...)

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).

How to avoid layer name repetition?

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).

Consider making "persistent layering of methods" optional

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.

Prepare a release

Before we can do this, #9 and #22 should be resolved.

We have to decide whether we should delete currently obsolete files like Flatten.js etc (and only keep them in a branch).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.