Descriptions of all the classes/namespaces in the "Language" section.

This commit is contained in:
Andrew Dupont 2009-03-06 15:41:11 -06:00
parent 2895be3587
commit 8c2af9bd66
10 changed files with 270 additions and 21 deletions

View File

@ -1,4 +1,4 @@
/** section: Language, alias of: Array.from
/** section: Language, alias of: Array.from, related to: Array
* $A(iterable) -> Array
*
* Accepts an array-like collection (anything with numeric indices) and returns
@ -29,7 +29,7 @@ if (Prototype.Browser.WebKit) {
};
}
/** section: Language
/** section: Language, related to: Array
* $w(string) -> Array
* - string (String): A string with zero or more spaces.
*
@ -43,11 +43,94 @@ function $w(string) {
return string ? string.split(/\s+/) : [];
}
/** alias of: $A
* Array.from(iterable) -> Array
**/
Array.from = $A;
/** section: Language
* class Array
*
* Prototype extends all native JavaScript arrays with quite a few powerful
* methods.
*
* This is done in two ways:
*
* * It mixes in the [[Enumerable]] module, which brings a ton of methods in
* already.
* * It adds quite a few extra methods, which are documented in this section.
*
* With Prototype, arrays become much, much more than the trivial objects we
* used to manipulate, limiting ourselves to using their `length` property and
* their `[]` indexing operator. They become very powerful objects that
* greatly simplify the code for 99% of the common use cases involving them.
*
* <h4>Why you should stop using forin to iterate</h4>
*
* Many JavaScript authors have been misled into using the `for…in` JavaScript
* construct to loop over array elements. This kind of code just wont work
* with Prototype.
*
* The ECMA 262 standard, which defines ECMAScript 3rd edition, supposedly
* implemented by all major browsers including MSIE, defines ten methods
* on Array (§15.4.4), including nice methods like `concat`, `join`, `pop`, and
* `push`.
*
* This same standard explicitely defines that the `for…in` construct (§12.6.4)
* exists to enumerate the properties of the object appearing on the right side
* of the `in` keyword. Only properties specifically marked as _non-enumerable_
* are ignored by such a loop. By default, the `prototype` and `length`
* properties are so marked, which prevents you from enumerating over array
* methods when using forin. This comfort led developers to use `for…in` as a
* shortcut for indexing loops, when it is not its actual purpose.
*
* However, Prototype has no way to mark the methods it adds to
* `Array.prototype` as non-enumerable. Therefore, using `for…in` on arrays
* when using Prototype will enumerate all extended methods as well, such as
* those coming from the [[Enumerable]] module, and those Prototype puts in the
* Array namespace (listed further below).
*
* <h4>What you should use instead</h4>
*
* You can revert to vanilla loops:
*
* for (var index = 0; index < myArray.length; ++index) {
* var item = myArray[index];
* // Your code working on item here...
* }
*
* Or you can use iterators, such as [[Array#each]]:
*
* myArray.each(function(item) {
* // Your code working on item here...
* });
*
*
* The inability to use `for...in` on arrays is not much of a burden: as youll
* see, most of what you used to loop over arrays for can be concisely done
* using the new methods provided by Array or the mixed-in [[Enumerable]]
* module. So manual loops should be fairly rare.
*
*
* <h4>A note on performance</h4>
*
* Should you have a very large array, using iterators with lexical closures
* (anonymous functions that you pass to the iterators and that get invoked at
* every loop iteration) in methods like [[Array#each]] _or_ relying on
* repetitive array construction (such as uniq), may yield unsatisfactory
* performance. In such cases, youre better off writing manual indexing loops,
* but take care then to cache the length property and use the prefix `++`
* operator:
*
* // Custom loop with cached length property: maximum full-loop
* // performance on very large arrays!
* for (var index = 0, len = myArray.length; index < len; ++index) {
* var item = myArray[index];
* // Your code working on item here...
* }
*
**/
(function() {
var arrayProto = Array.prototype,
slice = arrayProto.slice,

View File

@ -1,12 +1,13 @@
/** section: Language
* class Date
*
* Extensions to the built-in `Date` object.
**/
/**
* Date#toJSON -> String
* Date#toJSON() -> String
*
* Produces a string representation of the date in ISO 8601 format.
*
**/
Date.prototype.toJSON = function() {
return '"' + this.getUTCFullYear() + '-' +

View File

@ -1,9 +1,11 @@
/** section: Language
/** section: Language, related to: Hash
* $H([object]) -> Hash
*
* Creates a Hash (which is synonymous to map or associative array for our purposes).
* A convenience wrapper around the Hash constructor, with a safeguard that lets you pass
* an existing Hash object and get it back untouched (instead of uselessly cloning it).
* Creates a `Hash`.
*
* `$H` is a convenience wrapper around the Hash constructor, with a safeguard
* that lets you pass an existing Hash object and get it back untouched
* (instead of uselessly cloning it).
**/
function $H(object) {
return new Hash(object);
@ -11,6 +13,24 @@ function $H(object) {
/** section: Language
* class Hash
*
* A set of key/value pairs.
*
* `Hash` can be thought of as an associative array, binding unique keys to
* values (which are not necessarily unique), though it can not guarantee
* consistent order its elements when iterating. Because of the nature of
* JavaScript, every object is in fact a hash; but `Hash` adds a number of
* methods that let you enumerate keys and values, iterate over key/value
* pairs, merge two hashes together, and much more.
*
* <h4>Creating a hash</h4>
*
* There are two ways to construct a Hash instance: the first is regular
* JavaScript object instantiation with the `new` keyword, and the second is
* using the [[$H]] function. There is one difference between them: if a `Hash`
* is passed to `$H`, it will be returned as-is, wherease the same hash passed
* to `new Hash` will be _cloned_ instead.
*
**/
var Hash = Class.create(Enumerable, (function() {
/**
@ -35,7 +55,7 @@ var Hash = Class.create(Enumerable, (function() {
/**
* Hash#set(key, value) -> value
*
* Sets the hashs `key` property to value and returns value.
* Sets the hashs `key` property to `value` and returns `value`.
**/
function set(key, value) {
return this._object[key] = value;

View File

@ -1,5 +1,16 @@
/** section: Language
* class Number
*
* Extensions to the built-in `Number` object.
*
* Prototype extends native JavaScript numbers in order to provide:
*
* * [[ObjectRange]] compatibility, through [[Number#succ]].
* * Ruby-like numerical loops with [[Number#times]].
* * Simple utility methods such as [[Number#toColorPart]] and
* [[Number#toPaddedString]].
* * Instance-method aliases of many functions in the `Math` namespace.
*
**/
Object.extend(Number.prototype, (function() {
/**

View File

@ -1,5 +1,12 @@
/** section: Language
* class Object
*
* Extensions to the built-in `Object` object.
*
* Because it is dangerous and invasive to augment `Object.prototype` (i.e.,
* add instance methods to objects), all these methods are static methods that
* take an `Object` as their first parameter.
*
**/
(function() {

View File

@ -1,5 +1,15 @@
/** section: Language
* class PeriodicalExecuter
*
* A class that oversees the calling of a particular function periodically.
*
* `PeriodicalExecuter` shields you from multiple parallel executions of the
* `callback` function, should it take longer than the given interval to
* execute.
*
* This is especially useful if you use one to interact with the user at
* given intervals (e.g. use a prompt or confirm call): this will avoid
* multiple message boxes all waiting to be actioned.
**/
var PeriodicalExecuter = Class.create({
/**
@ -8,18 +18,7 @@ var PeriodicalExecuter = Class.create({
* - frequency (Number): the amount of time, in sections, to wait in between
* callbacks.
*
* Creates an object that oversees the calling of a particular function via
* `window.setInterval`.
*
* The only notable advantage provided by `PeriodicalExecuter` is that it
* shields you against multiple parallel executions of the `callback`
* function, should it take longer than the given interval to execute (it
* maintains an internal running flag, which is shielded against
* exceptions in the callback function).
*
* This is especially useful if you use one to interact with the user at
* given intervals (e.g. use a prompt or confirm call): this will avoid
* multiple message boxes all waiting to be actioned.
* Creates an `PeriodicalExecuter`.
**/
initialize: function(callback, frequency) {
this.callback = callback;

View File

@ -1,5 +1,21 @@
/** section: Language
* class ObjectRange
*
* Ranges represent an interval of values. The value type just needs to be
* "compatible" that is, to implement a `succ` method letting us step from
* one value to the next (its successor).
*
* Prototype provides such a method for [[Number]] and [[String]], but you
* are (of course) welcome to implement useful semantics in your own objects,
* in order to enable ranges based on them.
*
* `ObjectRange` mixes in [[Enumerable]], which makes ranges very versatile.
* It takes care, however, to override the default code for `include`, to
* achieve better efficiency.
*
* While `ObjectRange` does provide a constructor, the preferred way to obtain
* a range is to use the [[$R]] utility function, which is strictly equivalent
* (only way more concise to use).
**/
/** section: Language

View File

@ -1,5 +1,7 @@
/** section: Language
* class RegExp
*
* Extensions to the built-in `RegExp` object.
**/
/** alias of: RegExp#test

View File

@ -1,5 +1,13 @@
/** section: Language
* class String
*
* Extensions to the built-in `String` class.
*
* Prototype enhances the `String` object with a series of useful methods for
* ranging from the trivial to the complex. Tired of stripping trailing
* whitespace? Try [[String#strip]]. Want to replace `replace`? Have a look at
* [[String#sub]] and [[String#gsub]]. Need to parse a query string? We have
* [[String#toQueryParams]].
**/
Object.extend(String, {
/**

View File

@ -1,5 +1,107 @@
/** section: Language
* class Template
*
* A class for sophisticated string interpolation.
*
* Any time you have a group of similar objects and you need to produce
* formatted output for these objects, maybe inside a loop, you typically
* resort to concatenating string literals with the object's fields. There's
* nothing wrong with this approach, except that it is hard to visualize the
* output immediately just by glancing at the concatenation expression. The
* `Template` class provides a much nicer and clearer way of achieving this
* formatting.
*
* <h4>Straightforward templates</h4>
*
* The Template class uses a basic formatting syntax, similar to what is used
* in Ruby. The templates are created from strings that have embedded symbols
* in the form (e.g., `#{fieldName}`) that will be replaced by actual values
* when the template is applied (evaluated) to an object.
*
*
* // the template (our formatting expression)
* var myTemplate = new Template(
* 'The TV show #{title} was created by #{author}.');
*
* // our data to be formatted by the template
* var show = {
* title: 'The Simpsons',
* author: 'Matt Groening',
* network: 'FOX'
* };
*
* // let's format our data
* myTemplate.evaluate(show);
* // -> "The TV show The Simpsons was created by Matt Groening."
*
* <h4>Templates are meant to be reused</h4>
*
* As the example illustrates, `Template` objects are not tied to specific
* data. The data is bound to the template only during the evaluation of the
* template, without affecting the template itself. The next example shows the
* same template being used with a handful of distinct objects.
*
*
* // creating a few similar objects
* var conversion1 = { from: 'meters', to: 'feet', factor: 3.28 };
* var conversion2 = { from: 'kilojoules', to: 'BTUs', factor: 0.9478 };
* var conversion3 = { from: 'megabytes', to: 'gigabytes', factor: 1024 };
*
* // the template
* var templ = new Template(
* 'Multiply by #{factor} to convert from #{from} to #{to}.');
*
* // let's format each object
* [conversion1, conversion2, conversion3].each( function(conv){
* templ.evaluate(conv);
* });
* // -> Multiply by 3.28 to convert from meters to feet.
* // -> Multiply by 0.9478 to convert from kilojoules to BTUs.
* // -> Multiply by 1024 to convert from megabytes to gigabytes.
*
* <h4>Escape sequence</h4>
*
* There's always the chance that one day you'll need to have a literal in your
* template that looks like a symbol, but is not supposed to be replaced. For
* these situations there's an escape character: the backslash (`\`).
*
* // NOTE: you're seeing two backslashes here because the backslash
* // is also an escape character in JavaScript strings, so a literal
* // backslash is represented by two backslashes.
* var t = new Template(
* 'in #{lang} we also use the \\#{variable} syntax for templates.');
* var data = { lang:'Ruby', variable: '(not used)' };
* t.evaluate(data);
* // -> in Ruby we also use the #{variable} syntax for templates.
*
*
*
* <h4>Custom syntaxes</h4>
*
* The default syntax of the template strings will probably be enough for most
* scenarios. In the rare occasion where the default Ruby-like syntax is
* inadequate, there's a provision for customization. `Template`'s
* constructor accepts an optional second argument that is a regular expression
* object to match the replaceable symbols in the template string. Let's put
* together a template that uses a syntax similar to the ubiquitous `<%= %>`
* constructs:
*
* // matches symbols like '<%= field %>'
* var syntax = /(^|.|\r|\n)(\<%=\s*(\w+)\s*%\>)/;
*
* var t = new Template(
* '<div>Name: <b><%= name %></b>, Age: <b><%=age%></b></div>', syntax);
* t.evaluate( {name: 'John Smith', age: 26} );
* // -> <div>Name: <b>John Smith</b>, Age: <b>26</b></div>
*
* There are important constraints to any custom syntax. Any syntax must
* provide at least three groupings in the regular expression. The first
* grouping is to capture what comes before the symbol, to detect the backslash
* escape character (no, you cannot use a different character). The second
* grouping captures the entire symbol and will be completely replaced upon
* evaluation. Lastly, the third required grouping captures the name of the
* field inside the symbol.
*
**/
var Template = Class.create({
/**