zebraclass

zebraClass is a createClass extensions that uses its lazy-loading functionality to provide an easy-to-use interface for shared inheritances. Requires createClass.

npm install zebraclass
2 downloads in the last week
4 downloads in the last month

zebraClass

zebraClass Logo
zebraClass is a createClass extensions that uses the lazy-loading functionality to provide an easy-to-use interface for shared inheritance. Requires createClass.

Use case 1: JavaScript Candy

If you are developing an application that has different versions of the same class for different usages but you want the same inheritance chain for both classes you're going to need this if you don't want to uglify your code by creating single files for each class and loading your classes in a zebra way.
Let's assume you're developing an application that allows you to edit and solve puzzles. You're going to create one controller for the Game and one for the Editor. Sounds quite simple- and it is. You're going to create the base class "Controller" and then derive your classes "GameController" and "EditorController" from that class. But let's assume you're going to create different controllers for different kinds of puzzles. So you've got a BaseController and derive both a CrosswordController and a SudokuController from these. Now things got a bit more tricky. One option would be to place the Game and Editor controllers on top of the concrete game controller like this: BaseController -> CrosswordController -> [Game/Editor]CrosswordController
But as soon as things get a bit trickier and you need to hook your concrete controllers inbetween those controllers (chances increase by abstracting your game logic, e.g. BaseController -> FieldController -> GridController -> CrosswordController), you'll need a zebra kind of inheritance:
SharedBaseController -> GameBaseController -> SharedCrosswordController -> GameCrosswordController

You could also do this by moving all of your controllers into a single file and include them zebra-style. But this would be the Java way, not the JavaScript style. In JavaScript you're loading a module and you want it to work. You don't want a thousand 20-lines files making things complicated and less structured. So you're sticking to the JavaScript-way and create both a shared.js and game.js/editor.js using zebraClass to easily manage these inheritances:
index.js:

// Tell zebraClass how to handle the game controller variations
// This will automatically create the class MyPuzzleApp.GameController.
// Even though it is generally possible, you should not add anything to it
// But instead use the classes
// MyPuzzleApp.ControllerBase and MyPuzzleApp.ControllerGame
zebraClass.add( 'MyPuzzleApp.Controller', [ 'Base', 'Game' ] );

require( './base' );
require( './game' );

zebraClass.initialize( 'MyPuzzleApp.Controller' );

base.js:

zebraClass( 'MyPuzzleApp.Controller' );

MyPuzzleApp.ControllerBase.prototype...  // Add your shared code here...



zebraClass( 'MyPuzzleApp.FieldController', 'MyPuzzleApp.Controller' );
...
zebraClass( 'MyPuzzleApp.GridController', 'MyPuzzleApp.FieldController' );
...
zebraClass( 'MyPuzzleApp.CrosswordController', 'MyPuzzleApp.GridController' );
...

game.js:

zebraClass( 'MyPuzzleApp.Controller' );
MyPuzzleApp.ControllerGame.prototype...    // Add your game code here...

zebraClass( 'MyPuzzleApp.FieldController' );
...
zebraClass( 'MyPuzzleApp.GridController' );
...
zebraClass( 'MyPuzzleApp.CrosswordController' );
...

Use case 2: Multichain inheritance

Let's assume we've got the same controllers as above but we'd like to have both the game and the editor available. If we'd be using classic single-chain inheritance, we would not get any farer than the base controller class, since once we have added a game or an editor class, the next layer's base class wouldn't know whether to take the Editor or the Game class. Thus we're going to create two base-versions for both the Editor and Game classes (automatically handled by zebraClass): index.js:

// Tell zebraClass how to handle the game controller variation
zebraClass.add( 'MyPuzzleApp.Controller', [ 'Base', 'Game' ], 'Game[classname][variation]' );

include( './base' );
include( './game' );

zebraClass.initialize( 'MyPuzzleApp.Controller' );


// Tell zebraClass how to handle the editor controller variation
zebraClass.add( 'MyPuzzleApp.Controller', [ 'Base', 'Editor' ], 'Editor[classname][variation]' );

include( './base' );
include( './editor' );

zebraClass.initialize( 'MyPuzzleApp.Controller' );

base.js:

zebraClass( 'MyPuzzleApp.Controller', function(Controller,sClassName,sParentClassName) {

  // Add constructor
  Controller.prototype[sClassName]    = function(...) {
    this[sParentClassName](...);

    ...
  };

} );

zebraClass( 'MyPuzzleApp.FieldController', 'MyPuzzleApp.Controller', function( Controller, sClassName, sParentClassName ) {
  ...
} );

zebraClass( 'MyPuzzleApp.GridController', 'MyPuzzleApp.FieldController', function( Controller, sClassName, sParentClassName ) {
  ...
} );

zebraClass( 'MyPuzzleApp.CrosswordController', 'MyPuzzleApp.GridController', function( Controller, sClassName, sParentClassName ) {
  ...
} );

game.js:

zebraClass( 'MyPuzzleApp.Controller', function(Controller,sClassName,sParentClassName) {

  // Add constructor
  Controller.prototype[sClassName]    = function(...) {
    this[sParentClassName]();

    ...
  };

} );

zebraClass( 'MyPuzzleApp.FieldController', function( Controller, sClassName, sParentClassName ) {
  ...
} );

zebraClass( 'MyPuzzleApp.GridController', function( Controller, sClassName, sParentClassName ) {
  ...
} );

zebraClass( 'MyPuzzleApp.CrosswordController', function( Controller, sClassName, sParentClassName ) {
  ...
} );

Use case 3: Modular inheritance

Let's assume we've got the same controllers that we already used for multichain inheritance. But what we want to do now is adding modular functionality to the classes. Since we like it complicated we're not going to add the modular functionality at the end of the chain, but again for every single class within the inheritance chain: index.js:

// Tell zebraClass how to handle the game controller variation
zebraClass.add( 'MyPuzzleApp.Controller', [ 'Base', 'MyModule', 'Game' ], 'Game[classname][variation]' );

include( './base' );

include( './my-module' );
// Since my-module doesn't add functionality to all classes,
// we have to let zebraClass take care of it.
// If you don't know whether or not a module is going to
// extend all classes, play it save and call this function.
zebraClass.finishVariation( 'MyPuzzleApp.Controller' );

include( './game' );

zebraClass.initialize( 'MyPuzzleApp.Controller' );

...

my-module.js:

// We're going to overwrite FieldController and GridController:

zebraClass( 'MyPuzzleApp.FieldController', function( Controller, sClassName, sParentClassName ) {
  ...
} );

zebraClass( 'MyPuzzleApp.GridController', function( Controller, sClassName, sParentClassName ) {
  ...
} );
npm loves you