1
0
Fork 0
Classical object-oriented framework for JavaScript [unmaintained] https://gnu.org/software/easejs
 
 
 
 
 
 
Go to file
Mike Gerwitz b4fe08292f
'this' now properly binds to the private member object of the instance for getters/setters
Getters/setters did not get much attention during the initial development of
ease.js, simply because there was such a strong focus on pre-ES5
compatibility---ease.js was created for a project that strongly required it.
Given that, getters/setters were not used, since those are ES5 features. As
such, I find that two things have happened:

  1. There was little incentive to provide a proper implementation; even though
     I noticed the issues during the initial development, they were left
     unresolved and were then forgotten about as the project lay dormant for a
     while.
  2. The project was dormant because it was working as intended (sure, there
     are still things on the TODO-list feature-wise). Since getters/setters were
     unused in the project for which ease.js was created, the bug was never
     found and so never addressed.

That said, I now am using getters/setters in a project with ease.js and noticed
a very odd bug that could not be explained by that project's implementation.
Sure enough, it was an ease.js issue and this commit resolves it.

Now, there is more to be said about this commit. Mainly, it should be noted that
MemberBuilder.buildGetterSetter, when compared with its method counterpart
(buildMethod) is incomplete---it does not properly address overrides, the
abstract keyword, proxies or the possibility of method hiding. This is certainly
something that I will get to, but I want to get this fix out as soon as I can.
Since overriding ES5 getters/setters (rather than explicit methods) is more
likely to be a rarity, and since a partial fix is better than no fix, this will
likely be tagged immediately and a further fix will follow in the (hopefully
near) future.

(This is an interesting example of how glaring bugs manage to slip through the
cracks, even when the developer is initially aware of them.)
2013-01-19 22:38:35 -05:00
doc Added README to scripts/ directory 2012-05-11 20:53:02 -04:00
lib 'this' now properly binds to the private member object of the instance for getters/setters 2013-01-19 22:38:35 -05:00
test 'this' now properly binds to the private member object of the instance for getters/setters 2013-01-19 22:38:35 -05:00
tools Added GNU GPL v3+ license header and copyright notice to all scripts and Makefiles 2012-05-11 19:11:12 -04:00
.gitignore Ignoring webroot 2011-12-15 19:20:56 -05:00
COPYING Split COPYING into two separate files: COPYING and COPYING.LGPL 2012-06-13 22:27:48 -04:00
COPYING.LGPL Split COPYING into two separate files: COPYING and COPYING.LGPL 2012-06-13 22:27:48 -04:00
Makefile Added GNU GPL v3+ license header and copyright notice to all scripts and Makefiles 2012-05-11 19:11:12 -04:00
README.hacking Added beginning of README.hacking 2011-09-02 22:24:16 -04:00
README.md Updated README.md to remove npm unavailibility mention 2011-12-22 23:36:15 -05:00
README.todo Resolved majority of Closure Compiler warnings (VERBOSE) 2011-12-13 21:19:14 -05:00
index.js Created version module to provide additional version information 2011-12-23 18:31:11 -05:00
package.json Updated version in documentation and package.json to v0.1.0 2011-12-23 00:09:11 -05:00

README.md

ease.js

ease.js is a collection of CommonJS modules intended to "ease" the transition into JavaScript from other Object-Oriented languages. It provides an intuitive means of achieving classical inheritance and has planned support traits/mixins.

Current support includes:

  • Simple and intuitive class definitions
  • Classical inheritance
  • Abstract classes and methods
  • Interfaces
  • Visibility (public, protected and private members)
  • Static and constant members

While the current focus of the project is Object-Oriented design, it is likely that ease.js will expand to other paradigms in the future.

This project is under active development. Please see the manual for more information.

Full Documentation

Full documentation is available at the following URL:

http://easejs.org/manual/ (Multiple Pages)

http://easejs.org/manual.html (Single Page)

Bug Reports / Feature Requests

Please direct bug reports and feature requests to the bug tracker located at http://easejs.org/bugs/

Why ease.js?

There are already a number of libraries/frameworks that permit basic classical Object-Oriented development, so why ease.js? While many of the existing solutions certainly provide viable solutions, they are largely incomplete. Until the appearance of ECMAScript 5, many of the features enjoyed by classical OO developers were elusive to JavaScript. The aim of this project is to provide an intuitive framework in a CommonJS format which also addresses ES5 issues and is an all-inclusive solution to OO techniques.

ECMAScript reserves certain keywords that hint at classical OO in future versions, but said features are uncertain. ease.js will satisfy the classical OO itch until the time where ECMAScript itself includes it, at which time ease.js will still be useful for providing a transition in order to support older browsers. ease.js may also be useful in the future to augment the feature set of whatever native ECMAScript implementation is decided upon.

Why Classical OOP in JavaScript?

ease.js was created (historically) for a number of reasons:

  • To "ease" Object-Oriented developers into JavaScript by providing a familiar environment.
  • To provide the maintenance and development benefits of classical OOP.
  • To provide features missing from the language, such as proper encapsulation through private/protected members, interfaces, traits, intuitive inheritance, etc.
  • To encapsulate the hacks commonly used to perform the above tasks.

Many JS purists believe that classical Object-Oriented programming should be left out of the language and one should stick strictly to prototypal development. While the two are related (both Object-Oriented), they can be applied to different problem domains in order to achieve results that are more natural or intuitive to developers. ease.js works seamlessly with existing prototypes, allowing the developer to choose whether or not they want to use "classes".

How to Use

Please note that, as the project is under active development, the API may change until the first release.

ease.js uses the CommonJS module format. In the examples below, Node.js is used.

Defining Classes

The constructor is provided as the __construct() method (influenced by PHP).

    var Class = require( 'easejs' ).Class;

    // anonymous class definition
    var Dog = Class(
    {
        'private _name': '',

        'public __construct': function( name )
        {
            this._name = name;
        },

        'public bark': function()
        {
            console.log( 'Woof!' );
        },

        'public getName': function()
        {
            return this._name;
        }
    });

The above creates an anonymous class and stores it in the variable Dog. You have the option of naming class in order to provide more useful error messages and toString() output:

    var Dog = Class( 'Dog',
    {
        // ...
    });

Extending Classes

Classes may inherit from one-another. If the supertype was created using Class.extend(), a convenience extend() method has been added to it. Classes that were not created via Class.extend() can still be extended by passing it as the first argument to Class.extend().

Multiple inheritance is not supported. ease.js is very generous with the options it provides to developers as alternatives, so pick whichever flavor your are most comfortable with: interfaces, traits or mixins. Multiple inheritance will not be added in the future due to problems which have been addressed by interfaces and traits.

Note that traits and mixins are not yet available. They are planned features and will be available in the future.

    var SubFoo = Foo.extend(
    {
        'public anotherMethod': function()
        {
        },
    });

    // if Foo was not created via Class.extend(), this option may be used (has
    // the same effect as above, even if Foo was created using Class.extend())
    var SubFoo = Class.extend( Foo,
    {
        'public anotherMethod': function()
        {
        },
    });

Abstract Classes

Abstract classes require that their subtypes implement certain methods. They cannot be instantiated. Classes are considered to be abstract if they contain one or more abstract methods and are declared using AbstractClass rather than Class. If a class contains abstract methods but is not declared abstract, an error will result. Similarily, if a class is declared to be abstract and contains no abstract methods, an error will be thrown.

    var AbstractClass = require( 'easejs' ).AbstractClass;

    var AbstractFoo = AbstractClass(
    {
        // a function may be provided if you wish the subtypes to implement a
        // certain number of arguments
        'abstract public fooBar': [ 'arg' ],

        // alternatively, you needn't supply implementation details
        'abstract public fooBar2': [],
    });

If the abstract method provides implementation details (as shown by fooBar(), subtypes must implement at least that many arguments or an exception will be thrown. This ensures consistency between supertypes and their subtypes.

Abstract classes can be extended from just as an other class. In order for its subtype to be instantiated, it must provide concrete implementations of each abstract method. If any methods are left as abstract, then the subtype too will be considered abstract and must be declared as such.

    // can be instantiated because concrete methods are supplied for both
    // abstract methods
    var ConcreteFoo = Class.extend( AbstractFoo,
    {
        'public fooBar': function( arg )
        {
        },

        'public fooBar2': function()
        {
        },
    });

    // cannot be instantiated because one abstract method remains
    var StillAbstractFoo = AbstractClass.extend( AbstractFoo,
    {
        'public fooBar': function( arg )
        {
        },
    });

Interfaces

Interfaces can be declared in a very similar manner to classes. All members of an interface are implicitly abstract.

    var MyType = Interface(
    {
        'public foo': []
    });

To implement an interface, use the implement() class method:

    var ConcreteType = Class.implement( MyType ).extend(
    {
        'public foo': function() {}
    });

Note that, if a concrete implementation for each method is not provided, the implementing type must be declared abstract.

Use of Reserved Words

Though JavaScript doesn't currently implement classes, interfaces, etc, it does reserve the keywords. In an effort to ensure that ease.js will not clash, the following precautions are taken:

  • Class is used with a capital 'C'
  • Interface is used with a capital 'I'
  • Reserved keywords are quoted when used (e.g. in property strings)