Git Product home page Git Product logo

ringa's People

Contributors

corragon avatar macnificent avatar naomimathews avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ringa's Issues

Executors: add `eachIn` to iterate over items to trigger `dynamic`

Target Code:

import {eachIn, dispatch} from 'ringa';

controller.addListener('test', [
  Executor1,
  eachIn('items', 'item', Executor2),
  Executor3
]);
  1. Run Executor1 and wait
  2. For each item in items run Executor2 (one at a time) and wait
  3. Run Executor3 and wait

Note: this requires that the CommandThread executors are dynamically computed while the thread is running!

Alternate Syntax:

import {eachParallel, dispatch} from 'ringa';

controller.addListener('test', [
  Executor1,
  eachIn(items => items.map(items => Executor2)),
  Executor3
]);

Executors: add 'eachInParallel' to mimic 'eachIn' but with parallel behavior

Target Code:

import {eachParallel, dispatch} from 'ringa';

controller.addListener('test', [
  Executor1,
  eachInParallel('items', 'item', Executor2),
  Executor3
]);
  1. Run Executor1 and wait
  2. For each item in items run Executor2 (all in parallel) and pass 'item' as an injector to each and wait
  3. Run Executor3 and wait

Alternate Syntax:

import {eachParallel, dispatch} from 'ringa';

controller.addListener('test', [
  Executor1,
  eachInParallel(items => items.map(items => Executor2)),
  Executor3
]);

Model: add shorthand for properties

Code right now:

export default class MyModel extends Model {
  constructor(id) {
    super(id);

    this.show = false;
    this.overlay = false;
  }

  set show(value) {
    if (this._show === value) {
      return;
    }

    this._show = value;

    this.notify('show');
  }

  get show() {
    return this._show;
  }

  set overlay(value) {
    if (this._overlay === value) {
      return;
    }

    this._overlay = value;

    this.notify('overlay');
  }

  get overlay() {
    return this._overlay;
  }
}

To simplify, target code should be:

export default class MyModel extends Model {
  constructor(id) {
    super(id);

    @property
    this.show = false;
    @property
    this.overlay = false;
  }
}

Command and FunctionExecutor tests emit console.errors

PASS tests/Command.test.js
โ— Console

console.error src/util/executors.js:82
  Ringa Injection Error!:
  	Executor: Controller1_CommandComplexArgs1
  	Missing: c
  	Required: $ringaEvent, $target, $controller, $thread, testObject, a, b, c
  	Available: $controller, $customEvent, $detail, $lastEvent, $lastPromiseError, $lastPromiseResult, $ringaEvent, $target, $thread, done, fail
  	If you are minifying JS, make sure you add the original, unmangled property name to the UglifyJSPlugin mangle exceptions.
  	Dispatched from: unknown stack.
console.error src/util/executors.js:82
  Ringa Injection Error!:
  	Executor: Controller1_CommandComplexArgs1
  	Missing: testObject
  	Required: $ringaEvent, $target, $controller, $thread, testObject, a, b, c
  	Available: $controller, $customEvent, $detail, $lastEvent, $lastPromiseError, $lastPromiseResult, $ringaEvent, $target, $thread, done, fail
  	If you are minifying JS, make sure you add the original, unmangled property name to the UglifyJSPlugin mangle exceptions.
  	Dispatched from: unknown stack.

PASS tests/FunctionExecutor.test.js
โ— Console

console.error node_modules/core-js/modules/es6.promise.js:117
  Unhandled promise rejection someError

RingaEvent: add cancel()

Ringa events right now have:

  • event.done()
  • event.fail()

They should also have event.cancel(). All AbstractCommands should have a _cancel() method as well so that commands can roll back their most recent operation if someone calls _cancel() on the event.

Documentation: write install / build shell script

Write a shell script that does the following:

  • Install ringa
  • Install react-ringa
  • Install ringa-example-server
  • Install ringa-example-react
  • Verify that mongodb is installed

For each, it should run npm install. Then it should pretty-print nice little options on how to start everything up and get the example running on your machine.

Promise: build CommandPromiseWrapper

Target code:

controller.addListener('someEvent', [
    new Promise((resolve, reject) => {
        resolve({result: []});
    })
]);

CommandFactory should automatically determine that a promise has been added (using the .then check recommended by most frameworks), and wrap it in a CommandPromiseWrapper. When CommandPromiseWrapper::_execute is called it should wait for the promise to be resolved before continuing to the next command in the CommandThread (e.g. by calling CommandAbstract::done()).

Middleware: architect and develop

Target Code (UP FOR DISCUSSION):

function preLogger(/* injections */, done /* optional */) {
  console.log('Starting event: ', ringaEvent.type);
  done();
}
function postLogger(/* injections */, done /* optional */) {
  console.log('Finished event: ', ringaEvent.type);
  done();
}

controller.addPreMiddleware(preLogger);
controller.addPostMiddleware(postLogger);

Add support for 'capture' phase

We need to add support for the capture phase of events and of course unit tests to verify it works as expected.

Target code:

controller.addListener([...], true); // true for capture phase

Executors: add 'dynamic' executor generation

Target Code:

import {dynamic, dispatch} from 'ringa';

function buildCommands(items) {
  return items.map(item => Executor2);
}

controller.addListener('test', [
  Executor1,
  dynamic(buildCommands),
  Executor3
]);

dispatch('test', {
  items: ['item1', 'item2', 'item3']
});

Controller: add `initialize` function

Right now, the Controller constructor requires that a DOM node be passed when it is created.

We need to change that so that the DOM node can be set later and when it is set, initialize is called.

Controller: add ability to switch event bus

Controllers need to internally cache all their events and when you switch to a new event bus (or DOM node) they need to detach all the original listeners and reattach them to the new bus.

Executor: add no wait operator [[]]

Target Code:

controller.addListener([
  ...
  Executor1,
  [[Executor2]],
  Executor3,
  ...
]);

Executor1 should run, Executor2 should be started, but then Executor3 should be run immediately without waiting for Executor2 to finish.

buildArgumentsFromRingaEvent error behavior

buildArgumentsFromRingaEvent will console.error() and throw Error when it encounters an issue with injections. We need a way to silence these errors if they are expected, similar to contoller.options.consoleLogFails = false;

Comments: get comment style consistent

There are a lot of files that need to follow the standardized format for commenting. Controller.js is a good example of where I want to go, especially with section headings, but a ton of files are missing detailed comments.

Injections: callbacks should have option to be memoized

Example code:

export default class FormBaseController extends Controller {
  constructor() {
    super();

    this.injections.formModel = () => {
      this.modelWatcher.find(FormBaseModel);
    };
  }
}

Note that in this case every single time an injection runs, the injector will recompute (find) the FormBaseModel - which might be costly. In some cases this might be required, but I think that we should have a rule that if the injection callback returns a value, then that value that is returned is memoized (cached) for next time the injection is evaluated rather than calling the callback all over again.

Target Code:

export default class FormBaseController extends Controller {
  constructor() {
    super();

    // Our callback will only be called once, and then after that it will reuse the returned value.
    this.injections.formModel = () => this.modelWatcher.find(FormBaseModel);
  }
}

However, if the injection property (formModel in this case) is ever overwritten with a new function or a new value, then the memoized value needs to be discarded so we will have to watch for changes to the injection value (in this case formModel)

Executor: architect and develop parallels [...[]...]

Target Code:

controller.addListener('type', [
  Executor1,
  [Executor2, Executor3],
  Executor4
]);
  1. Run Executor1 and wait
  2. Run Executor2 and Executor3 simultaneously and wait
  3. Run Executor4

Combined with no wait operator ([[]]):

controller.addListener('type', [
  Executor1,
  [[Executor2, Executor3]],
  Executor4
]);
  1. Run Executor1 and wait
  2. Run Executor2 and Executor3 simultaneously and DO NOT WAIT
  3. Run Executor4

Controller: add support for event->executor caching

We should have a caching mechanism for a Controller to keep track of all its event to thread factories so that it can be attached, detached, or switch between event buses without ruining flow and without having to call initialize again.

Executors: add Ringa.inject() wrapper

Target Code:

import {inject} from 'ringa';

controller.addListener('test', [
  Executor1,
  inject(Executor2, {
    property1: 'some value'
  }),
  Executor2
]);

When Executor2's is executed the following occurs:

CommandAbstract and CommandFunctionWrapper: the injection Object is merged into the standard injections for the execute() method.

CommandEventWrapper: the injection Object becomes the details for the event.

Note: we may want to consider allowing Executor2 to be its own chain, but I think that will make complexity go through the roof right now.

Ring.event: architect and develop [2]

Target code:

import {dispatch} from 'ring';

controller.addListener('someEvent', [
  dispatch(SOME_EVENT_TYPE, {
    details: 'this is a details object that gets added to the event'} /*optional*/,
    someDomNode /*optional*/)
]);

...

controller.addListener(SOME_EVENT_TYPE, [...]);

Executors: add 'interval' executor

Target code:

controller.addListener('myEvent', [
  interval(conditionCallback, executor, milliseconds)
]);

This will check conditionCallback and as long as it returns true, it would run executor every milliseconds. Once conditionCallback returns false, then it continues to the next executor.

This should allow for the ability to create primitive animations!

Model: create 'model' shortcut

Pain Code:

import {Model} from 'ringa';

export default class PopupLoadingModel extends Model {
  constructor() {
    super();

    this.addProperty('loading', false);
  }
}

Target Code:

import {model, property} from 'ringa';

export default model('PopupLoadingModel', [
  property('loading', false)
]);

OR

import {model, property} from 'ringa';

model('PopupLoadingModel', property('loading', false));

Executor: add sleep operator [millis]

Target Code:

controller.addListener(type, [
  Executor1,
  Executor2,
  50,
  Executor3
]);

Executor1 should run, then Executor2, then it should wait 50 milliseconds, then Executor3 should run.

Controller: add support for a single event type to trigger multiple threads (ordered by priority)

Controller: add support for a single event type to trigger multiple threads (ordered by priority) within the same Controller.

Note that this is primarily useful when one controller extends another or when you want two threads to run in parallel in response to a single event.

We should probably consider doing a clone of the event between the two threads - but this is going to get super complicated.

RingaObject: add name property

Rules:

id: must be unique applicationwide. By default, will be the class name combined with a count for the number of instances of that class.

name: does not have to be unique, but must be unique for all models attached to a controller for injection.

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.