wenchun / jsdoc-toolkit

Automatically exported from code.google.com/p/jsdoc-toolkit
0 stars 0 forks source link

Add support/plugin for parsing classes defined by the prototype.js library #164

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Classes defined with prototype.js library style don't get recognized by jsdoc:

MyBaseClass = Class.create();
MyBaseClass.prototype =
{
   // class members
   ...
   // this is the constructor, by convention from prototype.js
   initialize : function()
   {
   }

}

Same problem with subclasses:
MyClass = Class.create();
MyClass.prototype = Object.extend( new MyBaseClass(),
{
   // class members
   ...
}
);

I know it is possible to use tags like @class, @constructor and @lends, but
it would be nice if these could be added dynamically using some kind of
code preprocessing/substitution.

Maybe adding a plugin event hook "onSourceLoaded" before the source file
tokenizing would do it, and a specific prototype.js plugin could use regexp
to add the missing tags?

Prototype JS library: http://prototypejs.org/

Original issue reported on code.google.com by PVinc...@googlemail.com on 7 Jul 2008 at 2:00

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
Does anyone have any workarounds?

I'm finding it very difficult to get anything more than the description at the 
top of
the class definition file showing up in the resulting docs.

I've tried pdoc (http://pdoc.org/), but it seems to require that *every* 
docblock is
syntactically correct, and bails out with error immediately it finds any 
exceptions.

Additionally, as it *only* looks at docblocks, and doesn't actually parse the
javascript, it doesn't document where functions/methods are invoked.

Matt

Original comment by mcalth...@gmail.com on 20 Jan 2009 at 1:16

GoogleCodeExporter commented 8 years ago
When you define your prototype classes, you can simply add some tags to 
explicitly
define your classes.

You need to:
- Add @class tag before every Class.create().
- Add @extend in a class comment when creating subclasses.
- Add @lend before the prototype block of the subclass body.

Here is a sample usage:

/**
 * Constructs a new Sample object. (constructor description because in JS there is
 * no difference between class and constructor)
 *
 * @param {String} sampleField sample field value
 *
 * @class The Sample class is a sample class. (class description). The class tag
 * is mandatory because JSDoc doesn't recognize classes defined using Class.create()
 * from prototype.js
 */
com.sample.SampleClass = Class.create( );

/**
 * Static constant.
 * @type {String}
 */
com.sample.SampleClass.A_STATIC_CONSTANT = "Static string constant";

/**
 * Private static constant.
 * @type {String}
 */
com.sample.SampleClass._A_PRIVATE_STATIC_CONSTANT = "Private static string 
constant";

/**
 * Class prototype, doesn't need any special tag.
 */
com.sample.SampleClass.prototype =
{
    /**
     * Sample private field 
     */
    _samplePrivateField : null,

    /**
     * Returns the sample field.
     * @return {String} sample field
     */
    getSampleField : function()
    {
        return this._samplePrivateField;
    },

    /**
     * Returns the sample field.
     * @param {String} sampleField sample field
     */
    setSampleField : function( sampleField )
    {
        this._samplePrivateField = sampleField;
    },

    /**
     * Private method.
     */ 
    _privateMethod : function()
    {
        // ...
    },

    /**
     * Constructs a new Sample object. (constructor description because in JS there is
     * no difference between class and constructor)
     * This description is the same as in the one above the class definition.
     * Only the description from the header will be visible in the public JSDoc.
     * @param {String} sampleField sample field value
     */
    initialize : function( sampleField )
    {
        this._samplePrivateField = sampleField;
    },

    /**
     * Sample method in sample class.
     */
    sampleMethodInClass : function()
    {
        // ...
    }   
};

/**
 * Constructs a new Sample subclass object.
 * @param {String} sampleField sample field value
 *
 * @class The Sample subclass is a sample subclass.
 * We need to explicitly specify the "extends" tag.
 * @extends com.sample.SampleClass
 */
com.sample.SampleSubClass = Class.create( );
com.sample.SampleSubClass.prototype = Object.extend( new 
com.sample.SampleClass(),
/** @lends com.sample.SampleSubClass.prototype */
{
    initialize : function()
    {
        // ...
    },

    /**
     * Sample method in subclass.
     */
    sampleMethodInSubClass : function()
    {
        // ...
    }
});

Original comment by PVinc...@googlemail.com on 21 Jan 2009 at 11:55

GoogleCodeExporter commented 8 years ago
That's a terrific example. I'll probably refer people to it the next time this 
question comes up. You may need 
to add some docs for the namespaces though:

/**
 * @namespace
 * @name com
 */

/**
 * @namespace
 * @name com.sample
 */

Original comment by micmath on 21 Jan 2009 at 10:27

GoogleCodeExporter commented 8 years ago
Wait, what???

Please do not assume that assigning properties to the prototype object directly 
is
how Prototype classes are implemented!  A more correct (and yet more 
problematic)
example is as follows:
(btw, making this up as I go here, so please forgive any typoes)
------------

/**
 * Should be documented as the Fribbit class
 */
var Fribbit = Class.create({
  /** A Fribbit prototype variable */
  chatty: true,

  /** The Fribbit constructor */
  initialize: function() {
  },

  /** A Fribbit instance method */
  doFoo: function() {
  }
});

// Now declare Fribbit's class members
Object.extend(Fribbit, {
  /** A Fribbit class variable */
  cache: {},

  /** A Fribbit class method */
  getCached: function() {
  }
});

// ... Once declared, classes can continue to be enhanced...

// addMethods() may be used to do ad-hoc augmentation.  For example, we can add
// some more prototype members like thus:
Fribbit.addMethods({
  /** Another Fribbit prototype method */
  doBar: function() {
  },

  /** More Fribbit prototype state (still valid, even though it's not a function) */
  stillChatty: true
});

// addMethods may also be used to "mixin" behavior and state defined elsewhere.
// For example, we can add the Wobney mixin as follows.  (And how should this
// be documented???)
Fribbit.addMethods(Wobney);

Original comment by broofa on 10 Feb 2009 at 11:29

GoogleCodeExporter commented 8 years ago
Sorry, forgot to request that we re-open this bug because, frankly, the above
proposed solution and workaround are meaningless to anyone who uses the "proper"
style of class creation in Prototype.

I also forgot to mention that this is not just a stylistic choice for 
programmers. 
By assigning properties directly to the prototype as proposed in comment #3 you
circumvent the [very powerful] support for referencing superclass method
implementations via the $super argument. For example:

-------------
/** Create a subclass of Fribbit */
var SubFribbit = Class.create(Fribbit{
  initialize: function($super) {
    $super(); // Invoke superclass's initialize
  },

  doBar: function($super) {
    $super(); // Invoke superclass implementation of doBar()
  }
});

Original comment by broofa on 10 Feb 2009 at 11:37

GoogleCodeExporter commented 8 years ago
Sorry, for the spam.  Just found this link that gives a more meaningful answer 
to
anyone else who may have this problem:
http://groups.google.com/group/jsdoc-2/browse_thread/thread/c16385c11bb9f943

Original comment by broofa on 10 Feb 2009 at 11:44