Closed GoogleCodeExporter closed 9 years ago
The behavior you are describing is "as expected." When you are using the @name
tag the doc comment is no longer
related to the code that surrounds it. If you later document something called
"this.options" the "this" bit is no longer
related to the class you documented previously. To solve this you would have to
provide a @name for the members as
well, for example @name MyClass#options. The reason prop, on the other hand, is
correctly associated with the
method setProp is because you didn't use @name to document setProp. This is
explained somewhat more here:
http://code.google.com/p/jsdoc-toolkit/wiki/TagName
Of course this solution of using all @name tags everywhere is only taking you
further from where you really want to
be, which is where you don't have to use any @name tags anywhere, so read on...
Firstly, I want to address your statement that using @name tags is problematic.
I understand but let me tell you that I
have personal experience with A Very Large JavaScript Library (AVLJSL) and it
is 100% documented with @name tags.
This has not proven to be the problem you suggest, in fact we find it gives us
very welcome control over exactly what
will appear in our documentation.
But OK, you wish to take advantage of JsDoc's imperfect code parser, forcing it
to try to guess the names of your
symbols for you. That's allowed, but if you want to make JsDoc Toolkit do the
work, you must write your code in a
way that it understands. It's not that it's stupid, it just doesn't get the
advantage of being able to run the code you're
documenting so it must try to guess what WOULD be defined IF your code WERE
run, in other words "static analysis,"
which is a much harder job. But that's OK too.
Here's how you could rewrite that same code so that JsDoc Toolkit can see more
clearly what the names are:
{{{
(function() {
/**
* @constructor
* @param {Object} options Some options.
*/
MyClass = function(options) {
/**
* This instance's options
* @type Object
*/
this.options = options;
}
/**
* Set a property.
* @param {String} val Value for the property.
*/
MyClass.prototype.setProp = function(val) {
/**
* Some property
* @type String
*/
this.prop = val;
};
/**
* @constructor
* @param {Object} options Some options.
*/
MyOtherClass = function(options) {
/**
* This instance's options
* @type Object
*/
this.options = options;
}
})();
}}}
So unfortunately it boils down to either you provide the @name or you make it
obvious to JsDoc Toolkit what that
name will be. Hope that helps, I can't fix it any better than that I'm afraid.
Original comment by micmath
on 12 Sep 2009 at 5:34
Thanks so much for your clear explanation (and your great library). You make
very
good points about the @name tag. I think the main issue is that I have
constitutional
difficulties doing anything manually that I think a computer should do for me,
even
when the latter takes me more time :).
I wanted to follow up, just to make sure that there isn't a hidden bug here
that you
would want to address. The reason I was using the @name tag to begin with is
that the
way I was initially setting up the code did not allow jsdoc-toolkit to
recognize the
symbols at all, as shown in the following example:
(function() {
// this class is identified properly.
/**
* @constructor
* @param {Object} options Some options.
*/
MyClass1 = function(options) {
/**
* This instance's options
* @type Object
*/
this.options = options;
};
// this class is ignored.
/**
* @constructor
* @param {Object} options Some options.
*/
function MyClass2(options) {
/**
* This instance's options
* @type Object
*/
this.options = options;
};
// this class is ignored.
/**
* @constructor
* @param {Object} options Some options.
*/
var MyClass3 = function(options) {
/**
* This instance's options
* @type Object
*/
this.options = options;
};
})();
While I understand that due to the variety of ways prototypes can be defined in
Javascript, jsdoc-toolkit can't be expected to recognize all of these symbols,
I was
surprised that MyClass2 and MyClass3 were totally ignored inside an anonymous
function, though they work perfectly well outside, even though I explicitly
used the
@constructor tag.
If this is also expected behavior, please ignore. Thanks for your help with
this -
the syntax you suggested works great.
Original comment by nick.rab...@gmail.com
on 12 Sep 2009 at 8:29
I don't mind discussing this topic, it is one I'm fairly interested in after
all, but bear with me as it's slightly hard to
explain. I'll *try* to be brief...
Firstly, keep in mind that writing this:
function MyClass2(options) {/* ... */}
is, for the purposes of this discussion, practically equivalent to writing this:
var MyClass2 = function(options) {/* ... */}
and if you write it that way it should be clear what the difference between the
following two lines of code is:
MyClass1 = function(options) {/* ... */}
var MyClass2 = function(options) {/* ... */}
The answer of course is that while MyClass1 is visible globally, MyClass2 is
only visible in it's current scope (that's
what the var keyword does after all). As you know, in JavaScript symbol
visibility is limited by the enclosing function,
so if you declare a symbol with the var keyword inside an enclosing function,
that name visibility is limited to that
function, which is effectively what you've done with MyClass2 and MyClass3.
Once the Big Anonymous Wrapper
Function (BAWF) ends, so too do those names, which is why JsDoc Toolkit doesn't
automatically include those symbols
in your documentation: as near as it can tell those symbols have no name that
can be accessed from outside the BAWF
(technically they are inner functions of the BAWF, so their names are like
"anonymous"-MyClass2, if anonymous had a
name, which of course it doesn't). You can help explain things to JsDoc Toolkit
by providing an explicit global @name
for those symbols, but that gets us back to where we started again, doesn't it?
I understand the source of the confusion is that in your real code, somewhere
later on, you give those inner functions
more outerish names like so:
/*global name*/ window.MyClass2 = /*inner name*/ MyClass2;
and that makes it all work for you when you run the code, but poor JsDoc
Toolkit doesn't (can't) know what that line
will accomplish because it never tries to run your code and simply from looking
it can't tell if that line will ever be
reached, or if it is reached if the value of MyClass2 has changed recently or
not... etc, etc. In contrast, JsDoc Toolkit
can safely tell that this will result in a global MyClass symbol:
MyClass1 = function(options) {/* ... */}
And that is why it can and does document the name of MyClass1, while MyClass2
and MyClass3 appear to be missed.
Actually it isn't missing them at all, it just doesn't know what to call them.
BTW, I perfectly understand your wish to let JsDoc Toolkit find the names for
you. I'd estimate that probably 70% of the
code in the JsDoc Toolkit application is devoted to that one single task, so I
hope you can get it to work for you.
Original comment by micmath
on 13 Sep 2009 at 7:45
Thanks again, this is a great explanation. I withdraw all bug reports, and
depart a
more informed programmer (and documenter). I should note, though I consider
this a
good thing, that including the var statement earlier seems to get my desired
effect
(local symbol that can later be made global) and my desired documentation
(symbol
recognized as global) - so my current solution, which seems to be working
great, is:
(function() {
// declare local vars
var MyClass1;
// recognized by jsdoc-toolkit as desired
/**
* @constructor
* @param {Object} options Some options.
*/
MyClass1 = function(options) {
/**
* This instance's options
* @type Object
*/
this.options = options;
};
// push local var global
window.MyClass1 = MyClass1;
})();
I can't quite decide whether the little dance required to get the right
documentation
improves my code, by pushing me to explicitly define my scopes, or results in
the
tail wagging the dog a little, in which case I should rely more on @name tags -
for
example, the above code would be more compact as
var MyClass1 = window.MyClass1 = function() { ...etc... };
but that would need the @name work discussed above. I'll think about it -
either way,
thank you for a very informative discussion.
Original comment by nick.rab...@gmail.com
on 13 Sep 2009 at 6:09
Ha! You've found yet another way that JsDoc Toolkit is easily confused by names
and used it to your advantage this time. I must
say: that's quite a nifty solution! I hope you don't mind if I add it to the
FAQ (with credit to you of course).
function() {
var MyClass1;
/**
* Plainly a function-scoped variable but poor JsDoc Toolkit can't see that.
* @constructor
* @param {Object} options Some options.
*/
MyClass1 = function(options) {
}
// make the world right again
window.MyClass1 = MyClass1
}
Well played, sir!
Original comment by micmath
on 13 Sep 2009 at 9:09
Glad you like it, and glad you got something out of this exchange as well. :)
Original comment by nick.rab...@gmail.com
on 13 Sep 2009 at 9:27
Original issue reported on code.google.com by
nick.rab...@gmail.com
on 10 Sep 2009 at 11:52