JavaScript
// Copyright (c) 2007 Art & Logic, Inc. All Rights Reserved.
// $Id: $
// Above: [sf02], [sf03]
// a note on the stuff inside the square brackets:
// Each of the codes inside brackets is a reference to the rule(s) in the
// Style Guide that's being illustrated, as follows:
// [sf##] - StyleGuide/SourceFiles
// [cas##] - StyleGuide/ClassesAndStructures
// [nr##] - StyleGuide/NamingRules
// [cg##] - StyleGuide/Commenting
// [fmt##] - StyleGuide/Formatting
// Throughout: [fmt01]; all indentation done with space characters (0x20),
// three spaces per logical tab stop.
// [nr21] C/C++ guard to prevent recursive inclusion of header files
// !!! Javascript - no preprocessor syntax !!!
// [sf05]
// !!! Javascript - no specific include syntax !!!
// [nr25] the 'q' prefix indicates that we are controlling conditional
// !!! Javascript - no precompilation macros !!!
// [sf07], only one class declared/defined in this source file.
// [cg02], comments useful to programmers who will use (but not necessarily
// maintain) this class are separated out into the header file, not in the
// implementation file.
/**
* ARosetta
* Simple, but meaningless class to demonstrate Art+Logic programming
* style conventions as they are applied to the various programming languages
* we use. In several places, you're asked to imagine a block of useful code
* to avoid distracting you from the issues of formatting (etc) that are being
* demonstrated.
*
* As you've already seen above, the thing about to be shown in this file is
* called out in comments using the A+L-style markup '!!!'
*/
// [nr11], [nr18] class names prefixed with "A"
// !!! Javascript - Objects are declared using the Constructor function syntax !!!
// [cas01] public member functions/methods listed first
// !!! Javascript - Should be listed after Constructor function for clarity !!!
// [nr08] new non-class types (enumerations, data structures, etc) are
// named with MixedCase and no special prefix
// !!! Javascript - No such syntax beyond functions !!!
/**
* Construct and initialize the Rosetta object.
* \param fileName The file to use as our data source
*/
function ARosetta(fileName)
{
// [cas01] Protected member functions declared after public
// !!! Javascript - Privileged functions are declared in JS using
// 'this' keyword to assign function to member !!!
// protected:
/**
* [nr03] parameters passed to functions are named using lowerCamelCase
*/
this.Test = function(firstVal, secondVal)
{
var retval = true;
// [fmt07] -- if/else formatting
if (firstVal < secondVal)
{
// [cg06] -- use '$$$' as a marker to indicate a request that the
// following block of code be reviewed before a change is considered
// complete
// $$$ before
// this->Process(secondVal);
// $$$ after
// Shouldn't this be processing the first value in this case?
this.Process(firstVal);
// $$$ end
}
else if (secondVal > kSomeConstant)
{
this.Process(secondVal);
}
else
{
// [fmt18] -- use curly braces even in cases where the language doesn't
// require it to prevent maintenance errors.
retval = false;
}
}
// [cas01] Private member function declared after protected
// !!! Javascript - Private members functions are private to the constructor function through Closures !!!
// private:
/**
* Useful function to process something or other.
*/
function Process(val)
{
// [cg05] -- use '!!!' as a marker to indicate a section of code that
// requires attention
// !!!... removing old hardcoded value
// fProcessResult = 131;
// ...!!!
var result = val;
while (--val)
{
result *= val;
}
fProcessResult = result;
}
/**
* Demonstrating the formatting of a switch statement.
*/
function Decide(midiEventType)
{
// [fmt11] -- switch/case formatting.
switch (midiEventType)
{
// comments precede the case
case kNoteOn:
this.NoteOn(now);
if (duration > 0)
{
this.NoteOff(now + duration);
}
break;
case kNoteOff:
this.NoteOff(now);
break;
case kPolyAfter:
after = channelValue;
// [fmt35] include, but comment out the break when falling through intentionally.
// break;
case kChannelAfter:
this.AfterTouch(after);
break;
// [fmt36] no need to include a commented out break when falling through an empty case
case kPitchbend:
// blank line...
// [fmt12] -- switch statements should always have a default case.
default:
ASSERT(false);
this.LogError("Unsupported event type!");
break;
}
}
// [cas02] member variables declared in the same order: public
// (avoid in most languages), protected, private.
// !!! Javascript - Public member variables must be declared OUTSIDE of constructor function !!!
// protected:
// !!! Javascript - Use this keyword with identifier to declare variable !!!
// private:
// [nr04], [nr19] Member variables are prefixed with a lowercase 'f', followed
// by an uppercase letter.
// [fmt28] -- when declaring pointer variables, attach the '*' to the
// typename, not the variable name.
// !!! Javascript - no pointer syntax !!!
var fInputFile = new (fFilename);
// !!! Javascript - To declare a member variable, you should always assign a value or null !!!
var fProcessResult = 0;
}
// !!! Javascript - Public methods associated with the ARosetta object prototype !!! //
/**
* [nr07] Member functions are named using CamelCase, with a leading upper case
* letter.
*/
ARosetta.prototype.MemberFunctionWithMultipleWords = function()
{
var ok = true;
// [fmt08] -- formatting of a for() loop.
for (var i = 0; i < kSomeConstant; ++i)
{
for (var j = 0; j < kSomeOtherConstant; ++j)
{
// [fmt02] -- preprocessor directives go in column zero.
// !!! Javascript - No preprocessor syntax !!!
// [nr07] -- Calls to member functions of the current object are
// made through an explicit this-> pointer.
// !!! Javascript - no pointer syntax, everything is by reference e.g this.member
ok = this.Test(i, j);
if (!ok)
{
alert("Fatal error testing: " + i + ", " + j );
// goto CleanUp;
// !!! Javascript - no labels, use break !!!
break;
}
}
}
// [fmt19]
if (ok)
{
return true;
}
else
{
return false;
}
// [fmt02] -- labels used as the target of a goto are placed in column zero.
// CleanUp:
// cleanup code here...
// !!! Javascript - no labels
}
/**
* !!! Here's how we handle very long lines (i.e., longer than 79
* characters)
*/
ARosetta.prototype.LongLineWrapping = function()
{
// [fmt03] -- source lines should be less than 80 characters long.
// [fmt04] -- break lines at the most logical point
// 1 2 3 4 5 6 7
//34567890123456789012345678901234567890123456789012345678901234567890123456789
var retval = FunctionWithManyArguments(longArgumentName1, longArgumentName2,
longArgumentName3, longArgumentName4);
// alternative format #1
retval = FunctionWithManyArguments(longArgumentName1,
longArgumentName2,
longArgumentName3,
longArgumentName4);
// alternative format #2
retval = FunctionWithManyArguments(
longArgumentName1,
longArgumentName2,
longArgumentName3,
longArgumentName4);
// [fmt05] -- prefer to break after a comma
retval = anObject.SomeUsefulFunction(x.LeftMargin() + x.RightMargin(),
x.TopMargin() + x.BottomMargin() - 1);
// [fmt05] -- if that's not possible, break after an operator
retval = anObject.SomeUsefulFunction(x.LeftMargin() + x.RightMargin() +
anObject.HorizontalPadding(), x.TopMargin() + x.BottomMargin() - 1);
return retval;
}
/**
* !!! Loop formatting
*/
ARosetta.prototype.Loops = function()
{
// [fmt08] -- for() loop; note the pre-incremented form of the loop control
for (var i = 0; i < kSomeConstant; ++i)
{
// loop code here...
}
var someBoolean = true;
// [fmt09]
while (someBoolean)
{
// useful code...
}
// [fmt09] -- while loop with an empty body makes the emptiness explicit
while (this.SomeFuncReturningBool())
{
// intentionally empty...
}
// [fmt10] -- do/while loop.
// [fmt18] -- exception to the bracing rule saying that braces should
// always be on a line by themselves
do
{
// loop code here..
} while (someBoolean);
}
}