Start PDoc integration.
This commit is contained in:
parent
24fb692281
commit
b2597ece0c
36
Rakefile
36
Rakefile
|
@ -10,29 +10,41 @@ PROTOTYPE_TEST_UNIT_DIR = File.join(PROTOTYPE_TEST_DIR, 'unit')
|
|||
PROTOTYPE_TMP_DIR = File.join(PROTOTYPE_TEST_UNIT_DIR, 'tmp')
|
||||
PROTOTYPE_VERSION = '1.6.0.3'
|
||||
|
||||
$:.unshift File.join(PROTOTYPE_ROOT, 'lib')
|
||||
|
||||
task :default => [:dist, :dist_helper, :package, :clean_package_source]
|
||||
|
||||
desc "Builds the distribution."
|
||||
task :dist do
|
||||
$:.unshift File.join(PROTOTYPE_ROOT, 'lib')
|
||||
require 'protodoc'
|
||||
|
||||
Dir.chdir(PROTOTYPE_SRC_DIR) do
|
||||
File.open(File.join(PROTOTYPE_DIST_DIR, 'prototype.js'), 'w+') do |dist|
|
||||
dist << Protodoc::Preprocessor.new('prototype.js')
|
||||
end
|
||||
|
||||
File.open(File.join(PROTOTYPE_DIST_DIR, 'prototype.js'), 'w+') do |dist|
|
||||
source = File.join(PROTOTYPE_SRC_DIR, 'prototype.js')
|
||||
dist << Protodoc::Preprocessor.new(source, :strip_documentation => true)
|
||||
end
|
||||
end
|
||||
|
||||
desc "Builds the documentation."
|
||||
task :doc do
|
||||
require 'protodoc'
|
||||
require 'pdoc'
|
||||
|
||||
Tempfile.open("prototype-doc") do |temp|
|
||||
source = File.join(PROTOTYPE_SRC_DIR, 'prototype.js')
|
||||
temp << Protodoc::Preprocessor.new(source, :strip_documentation => false)
|
||||
temp.flush
|
||||
rm_rf PROTOTYPE_DOC_DIR
|
||||
PDoc::Runner.new(temp.path, :output => PROTOTYPE_DOC_DIR).run
|
||||
end
|
||||
end
|
||||
|
||||
desc "Builds the updating helper."
|
||||
task :dist_helper do
|
||||
$:.unshift File.join(PROTOTYPE_ROOT, 'lib')
|
||||
require 'protodoc'
|
||||
|
||||
Dir.chdir(File.join(PROTOTYPE_ROOT, 'ext', 'update_helper')) do
|
||||
File.open(File.join(PROTOTYPE_DIST_DIR, 'prototype_update_helper.js'), 'w+') do |dist|
|
||||
dist << Protodoc::Preprocessor.new('prototype_update_helper.js')
|
||||
end
|
||||
|
||||
File.open(File.join(PROTOTYPE_DIST_DIR, 'prototype_update_helper.js'), 'w+') do |dist|
|
||||
source = File.join(PROTOTYPE_ROOT, 'ext', 'update_helper', 'prototype_update_helper.js')
|
||||
dist << Protodoc::Preprocessor.new(source)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,27 +8,43 @@ class String
|
|||
def strip_whitespace_at_line_ends
|
||||
lines.map {|line| line.gsub(/\s+$/, '')} * $/
|
||||
end
|
||||
|
||||
def strip_pdoc_comments
|
||||
gsub %r{\s*/\*\*.*?\*\*/}m, "\n"
|
||||
end
|
||||
end
|
||||
|
||||
module Protodoc
|
||||
module Environment
|
||||
def include(*filenames)
|
||||
filenames.map {|filename| Preprocessor.new(filename).to_s}.join("\n")
|
||||
filenames.map do |filename|
|
||||
Preprocessor.new(expand_path(filename), @options).result
|
||||
end.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
class Preprocessor
|
||||
include Environment
|
||||
|
||||
def initialize(filename)
|
||||
def initialize(filename, options = { })
|
||||
filename = File.join(filename.split('/'))
|
||||
@filename = File.expand_path(filename)
|
||||
@template = ERB.new(IO.read(@filename), nil, '%')
|
||||
@options = options
|
||||
end
|
||||
|
||||
def to_s
|
||||
@template.result(binding).strip_whitespace_at_line_ends
|
||||
def expand_path(filename)
|
||||
File.join(File.dirname(@filename), filename)
|
||||
end
|
||||
|
||||
def result
|
||||
result = @template.result(binding)
|
||||
result = result.strip_whitespace_at_line_ends
|
||||
result = result.strip_pdoc_comments if @options[:strip_documentation]
|
||||
result
|
||||
end
|
||||
|
||||
alias_method :to_s, :result
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
/** section: lang, alias of: Array.from
|
||||
* $A(iterable) -> Array
|
||||
*
|
||||
* Accepts an array-like collection (anything with numeric indices) and returns
|
||||
* its equivalent as an actual Array object.
|
||||
* This method is a convenience alias of [[Array.from]], but is the preferred way
|
||||
* of casting to an Array.
|
||||
**/
|
||||
function $A(iterable) {
|
||||
if (!iterable) return [];
|
||||
if (iterable.toArray) return iterable.toArray();
|
||||
|
@ -21,6 +29,14 @@ if (Prototype.Browser.WebKit) {
|
|||
};
|
||||
}
|
||||
|
||||
/** section: lang
|
||||
* $w(string) -> Array
|
||||
* - string (String): A string with zero or more spaces.
|
||||
*
|
||||
* Splits a string into an array, treating all whitespace as delimiters.
|
||||
*
|
||||
* Equivalent to Ruby's `%w{foo bar}` or Perl's `qw(foo bar)`.
|
||||
**/
|
||||
function $w(string) {
|
||||
if (!Object.isString(string)) return [];
|
||||
string = string.strip();
|
||||
|
@ -29,6 +45,9 @@ function $w(string) {
|
|||
|
||||
Array.from = $A;
|
||||
|
||||
/** section: lang
|
||||
* Array
|
||||
**/
|
||||
(function() {
|
||||
var arrayProto = Array.prototype,
|
||||
slice = arrayProto.slice,
|
||||
|
@ -40,25 +59,49 @@ Array.from = $A;
|
|||
}
|
||||
if (!_each) _each = each;
|
||||
|
||||
/**
|
||||
* Array#clear() -> Array
|
||||
* Empties an array.
|
||||
**/
|
||||
function clear() {
|
||||
this.length = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#first() -> ?
|
||||
* Returns the array's first item.
|
||||
**/
|
||||
function first() {
|
||||
return this[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#last() -> ?
|
||||
* Returns the array's last item.
|
||||
**/
|
||||
function last() {
|
||||
return this[this.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#compact() -> Array
|
||||
* Trims the array of `null`, `undefined`, or other "falsy" values.
|
||||
**/
|
||||
function compact() {
|
||||
return this.select(function(value) {
|
||||
return value != null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#flatten() -> Array
|
||||
* Returns a “flat” (one-dimensional) version of the array.
|
||||
*
|
||||
* Nested arrays are recursively injected “inline”. This can prove very
|
||||
* useful when handling the results of a recursive collection algorithm,
|
||||
* for instance.
|
||||
**/
|
||||
function flatten() {
|
||||
return this.inject([], function(array, value) {
|
||||
if (Object.isArray(value))
|
||||
|
@ -68,6 +111,13 @@ Array.from = $A;
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#without(value...) -> Array
|
||||
* - value (?): A value to exclude.
|
||||
*
|
||||
* Produces a new version of the array that does not contain any of the
|
||||
* specified values.
|
||||
**/
|
||||
function without() {
|
||||
var values = slice.call(arguments, 0);
|
||||
return this.select(function(value) {
|
||||
|
@ -75,14 +125,34 @@ Array.from = $A;
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#reverse([inline = false]) -> Array
|
||||
* - inline (Boolean): Whether to modify the array in place. If `false`,
|
||||
* clones the original array first.
|
||||
*
|
||||
* Returns the reversed version of the array.
|
||||
**/
|
||||
function reverse(inline) {
|
||||
return (inline !== false ? this : this.toArray())._reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#reduce() -> Array
|
||||
* Reduces arrays: one-element arrays are turned into their unique item,
|
||||
* while multiple-element arrays are returned untouched.
|
||||
**/
|
||||
function reduce() {
|
||||
return this.length > 1 ? this : this[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#uniq([sorted = false]) -> Array
|
||||
* - sorted (Boolean): Whether the array has already been sorted. If `true`,
|
||||
* a less-costly algorithm will be used.
|
||||
*
|
||||
* Produces a duplicate-free version of an array. If no duplicates are
|
||||
* found, the original array is returned.
|
||||
**/
|
||||
function uniq(sorted) {
|
||||
return this.inject([], function(array, value, index) {
|
||||
if (0 == index || (sorted ? array.last() != value : !array.include(value)))
|
||||
|
@ -91,24 +161,53 @@ Array.from = $A;
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#intersect(array) -> Array
|
||||
* - array (Array): A collection of values.
|
||||
*
|
||||
* Returns an array containing every item that is shared between the two
|
||||
* given arrays.
|
||||
**/
|
||||
function intersect(array) {
|
||||
return this.uniq().findAll(function(item) {
|
||||
return array.detect(function(value) { return item === value });
|
||||
});
|
||||
}
|
||||
|
||||
/** alias of: Array#toArray
|
||||
* Array#clone() -> Array
|
||||
*
|
||||
* Returns a duplicate of the array, leaving the original array intact.
|
||||
**/
|
||||
function clone() {
|
||||
return slice.call(this, 0);
|
||||
}
|
||||
|
||||
/** related to: Enumerable#size
|
||||
* Array#size() -> Number
|
||||
* Returns the size of the array.
|
||||
*
|
||||
* This is just a local optimization of the mixed-in [[Enumerable#size]]
|
||||
* which avoids array cloning and uses the array’s native length property.
|
||||
**/
|
||||
function size() {
|
||||
return this.length;
|
||||
}
|
||||
|
||||
/** related to: Object.inspect
|
||||
* Array#inspect() -> String
|
||||
*
|
||||
* Returns the debug-oriented string representation of an array.
|
||||
**/
|
||||
function inspect() {
|
||||
return '[' + this.map(Object.inspect).join(', ') + ']';
|
||||
}
|
||||
|
||||
/** related to: Object.toJSON
|
||||
* Array#toJSON() -> String
|
||||
*
|
||||
* Returns a JSON string representation of the array.
|
||||
**/
|
||||
function toJSON() {
|
||||
var results = [];
|
||||
this.each(function(object) {
|
||||
|
@ -118,6 +217,15 @@ Array.from = $A;
|
|||
return '[' + results.join(', ') + ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#indexOf(item[, offset = 0]) -> Number
|
||||
* - item (?): A value that may or may not be in the array.
|
||||
* - offset (Number): The number of initial items to skip before beginning the
|
||||
* search.
|
||||
*
|
||||
* Returns the position of the first occurrence of `item` within the array — or
|
||||
* `-1` if `item` doesn’t exist in the array.
|
||||
**/
|
||||
function indexOf(item, i) {
|
||||
i || (i = 0);
|
||||
var length = this.length;
|
||||
|
@ -127,12 +235,26 @@ Array.from = $A;
|
|||
return -1;
|
||||
}
|
||||
|
||||
/** related to: Array#indexOf
|
||||
* Array#lastIndexOf(item[, offset]) -> Number
|
||||
* - item (?): A value that may or may not be in the array.
|
||||
* - offset (Number): The number of items at the end to skip before beginning
|
||||
* the search.
|
||||
*
|
||||
* Returns the position of the last occurrence of `item` within the array — or
|
||||
* `-1` if `item` doesn’t exist in the array.
|
||||
**/
|
||||
function lastIndexOf(item, i) {
|
||||
i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
|
||||
var n = this.slice(0, i).reverse().indexOf(item);
|
||||
return (n < 0) ? n : i - n - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Array#concat(args...) -> Array
|
||||
*
|
||||
* TODO: Array#concat
|
||||
**/
|
||||
function concat() {
|
||||
var array = slice.call(this, 0), item;
|
||||
for (var i = 0, length = arguments.length; i < length; i++) {
|
||||
|
|
|
@ -1,5 +1,35 @@
|
|||
/* Based on Alex Arnell's inheritance implementation. */
|
||||
|
||||
/** section: lang
|
||||
* Class
|
||||
**/
|
||||
var Class = (function() {
|
||||
/**
|
||||
* Class.create([superclass][, methods...]) -> Class
|
||||
* - superclass (Class): The optional superclass to inherit methods from.
|
||||
* - methods (Object): An object whose properties will be "mixed-in" to the
|
||||
* new class. Any number of mixins can be added; later mixins take
|
||||
* precedence.
|
||||
*
|
||||
* Creates a class.
|
||||
*
|
||||
* Class.create returns a function that, when called, will fire its own
|
||||
* `initialize` method.
|
||||
*
|
||||
* `Class.create` accepts two kinds of arguments. If the first argument is
|
||||
* a `Class`, it's treated as the new class's superclass, and all its
|
||||
* methods are inherited. Otherwise, any arguments passed are treated as
|
||||
* objects, and their methods are copied over as instance methods of the new
|
||||
* class. Later arguments take precedence over earlier arguments.
|
||||
*
|
||||
* If a subclass overrides an instance method declared in a superclass, the
|
||||
* subclass's method can still access the original method. To do so, declare
|
||||
* the subclass's method as normal, but insert `$super` as the first
|
||||
* argument. This makes `$super` available as a method for use within the
|
||||
* function.
|
||||
*
|
||||
* To extend a class after it has been defined, use [[Class#addMethods]].
|
||||
**/
|
||||
function create() {
|
||||
var parent = null, properties = $A(arguments);
|
||||
if (Object.isFunction(properties[0]))
|
||||
|
@ -30,6 +60,23 @@ var Class = (function() {
|
|||
return klass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class#addMethods(methods) -> Class
|
||||
* - methods (Object): The methods to add to the class.
|
||||
*
|
||||
* Adds methods to an existing class.
|
||||
*
|
||||
* `Class#addMethods` is a method available on classes that have been
|
||||
* defined with `Class.create`. It can be used to add new instance methods
|
||||
* to that class, or overwrite existing methods, after the class has been
|
||||
* defined.
|
||||
*
|
||||
* New methods propagate down the inheritance chain. If the class has
|
||||
* subclasses, those subclasses will receive the new methods — even in the
|
||||
* context of `$super` calls. The new methods also propagate to instances of
|
||||
* the class and of all its subclasses, even those that have already been
|
||||
* instantiated.
|
||||
**/
|
||||
function addMethods(source) {
|
||||
var ancestor = this.superclass && this.superclass.prototype;
|
||||
var properties = Object.keys(source);
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
/** section: lang
|
||||
* Date
|
||||
**/
|
||||
|
||||
/**
|
||||
* Date#toJSON -> String
|
||||
*
|
||||
* TODO: Date#toJSON
|
||||
**/
|
||||
Date.prototype.toJSON = function() {
|
||||
return '"' + this.getUTCFullYear() + '-' +
|
||||
(this.getUTCMonth() + 1).toPaddedString(2) + '-' +
|
||||
|
|
|
@ -1,6 +1,19 @@
|
|||
/** section: lang
|
||||
* mixin Enumerable
|
||||
**/
|
||||
|
||||
var $break = { };
|
||||
|
||||
var Enumerable = (function() {
|
||||
/**
|
||||
* Enumerable#each(iterator[, context]) -> Enumerable
|
||||
* - iterator (Function): A `Function` that expects an item in the
|
||||
* collection as the first argument and a numerical index as the second.
|
||||
* - context (Object): The scope in which to call `iterator`. Affects what
|
||||
* the keyword `this` means inside `iterator`.
|
||||
*
|
||||
* Calls `iterator` for each item in the collection.
|
||||
**/
|
||||
function each(iterator, context) {
|
||||
var index = 0;
|
||||
try {
|
||||
|
@ -13,6 +26,12 @@ var Enumerable = (function() {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#eachSlice(number[, iterator = Prototype.K[, context]]) -> Enumerable
|
||||
*
|
||||
* TODO: Enumerable#eachSlice
|
||||
* http://prototypejs.org/api/enumerable#method-eachslice
|
||||
**/
|
||||
function eachSlice(number, iterator, context) {
|
||||
var index = -number, slices = [], array = this.toArray();
|
||||
if (number < 1) return array;
|
||||
|
@ -21,6 +40,12 @@ var Enumerable = (function() {
|
|||
return slices.collect(iterator, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#all([iterator = Prototype.K[, context]]) -> Boolean
|
||||
*
|
||||
* Determines whether all the elements are boolean-equivalent to `true`,
|
||||
* either directly or through computation by the provided iterator.
|
||||
**/
|
||||
function all(iterator, context) {
|
||||
iterator = iterator || Prototype.K;
|
||||
var result = true;
|
||||
|
@ -31,6 +56,12 @@ var Enumerable = (function() {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#any([iterator = Prototype.K[, context]]) -> Boolean
|
||||
*
|
||||
* Determines whether at least one element is boolean-equivalent to `true`,
|
||||
* either directly or through computation by the provided iterator.
|
||||
**/
|
||||
function any(iterator, context) {
|
||||
iterator = iterator || Prototype.K;
|
||||
var result = false;
|
||||
|
@ -41,6 +72,12 @@ var Enumerable = (function() {
|
|||
return result;
|
||||
}
|
||||
|
||||
/** alias of: Enumerable#map
|
||||
* Enumerable#collect([iterator = Prototype.K[, context]]) -> Array
|
||||
*
|
||||
* Returns the results of applying the iterator to each element.
|
||||
* Aliased as [[Enumerable#map]].
|
||||
**/
|
||||
function collect(iterator, context) {
|
||||
iterator = iterator || Prototype.K;
|
||||
var results = [];
|
||||
|
@ -50,6 +87,12 @@ var Enumerable = (function() {
|
|||
return results;
|
||||
}
|
||||
|
||||
/** alias of: Enumerable#find
|
||||
* Enumerable#detect(iterator[, context]) -> firstElement | undefined
|
||||
*
|
||||
* Finds the first element for which the iterator returns a “truthy” value.
|
||||
* Aliased by the [[Enumerable#find]] method.
|
||||
**/
|
||||
function detect(iterator, context) {
|
||||
var result;
|
||||
this.each(function(value, index) {
|
||||
|
@ -61,6 +104,12 @@ var Enumerable = (function() {
|
|||
return result;
|
||||
}
|
||||
|
||||
/** alias of: select
|
||||
* Enumerable#findAll(iterator[, context]) -> Array
|
||||
*
|
||||
* Returns all the elements for which the iterator returned “truthy” value.
|
||||
* Aliased as [[Enumerable#select]].
|
||||
**/
|
||||
function findAll(iterator, context) {
|
||||
var results = [];
|
||||
this.each(function(value, index) {
|
||||
|
@ -70,6 +119,12 @@ var Enumerable = (function() {
|
|||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#grep(regex[, iterator = Prototype.K[, context]]) -> Array
|
||||
*
|
||||
* Returns all the elements that match the filter. If an iterator is provided,
|
||||
* it is used to produce the returned value for each selected element.
|
||||
**/
|
||||
function grep(filter, iterator, context) {
|
||||
iterator = iterator || Prototype.K;
|
||||
var results = [];
|
||||
|
@ -84,6 +139,12 @@ var Enumerable = (function() {
|
|||
return results;
|
||||
}
|
||||
|
||||
/** alias of: Enumerable#member
|
||||
* Enumerable#include(object) -> Boolean
|
||||
*
|
||||
* Determines whether a given object is in the Enumerable or not,
|
||||
* based on the `==` comparison operator. Aliased as [[Enumerable#member]].
|
||||
**/
|
||||
function include(object) {
|
||||
if (Object.isFunction(this.indexOf))
|
||||
if (this.indexOf(object) != -1) return true;
|
||||
|
@ -98,6 +159,12 @@ var Enumerable = (function() {
|
|||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#inGroupsOf(size[, filler = null]) -> [group...]
|
||||
*
|
||||
* Groups items in fixed-size chunks, using a specific value to fill up
|
||||
* the last chunk if necessary.
|
||||
**/
|
||||
function inGroupsOf(number, fillWith) {
|
||||
fillWith = Object.isUndefined(fillWith) ? null : fillWith;
|
||||
return this.eachSlice(number, function(slice) {
|
||||
|
@ -106,6 +173,13 @@ var Enumerable = (function() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#inject(accumulator, iterator[, context]) -> accumulatedValue
|
||||
*
|
||||
* Incrementally builds a result value based on the successive results
|
||||
* of the iterator.
|
||||
* This can be used for array construction, numerical sums/averages, etc.
|
||||
**/
|
||||
function inject(memo, iterator, context) {
|
||||
this.each(function(value, index) {
|
||||
memo = iterator.call(context, memo, value, index);
|
||||
|
@ -113,6 +187,12 @@ var Enumerable = (function() {
|
|||
return memo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#invoke(methodName[, arg...]) -> Array
|
||||
*
|
||||
* Invokes the same method, with the same arguments, for all items in a collection.
|
||||
* Returns the results of the method calls.
|
||||
**/
|
||||
function invoke(method) {
|
||||
var args = $A(arguments).slice(1);
|
||||
return this.map(function(value) {
|
||||
|
@ -120,6 +200,14 @@ var Enumerable = (function() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#max([iterator = Prototype.K[, context]]) -> maxValue
|
||||
*
|
||||
* Returns the maximum element (or element-based computation), or undefined if
|
||||
* the enumeration is empty.
|
||||
* Elements are either compared directly, or by first applying the iterator
|
||||
* and comparing returned values.
|
||||
**/
|
||||
function max(iterator, context) {
|
||||
iterator = iterator || Prototype.K;
|
||||
var result;
|
||||
|
@ -131,6 +219,14 @@ var Enumerable = (function() {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#min([iterator = Prototype.K[, context]]) -> minValue
|
||||
*
|
||||
* Returns the minimum element (or element-based computation), or undefined if
|
||||
* the enumeration is empty.
|
||||
* Elements are either compared directly, or by first applying the iterator
|
||||
* and comparing returned values.
|
||||
**/
|
||||
function min(iterator, context) {
|
||||
iterator = iterator || Prototype.K;
|
||||
var result;
|
||||
|
@ -142,6 +238,14 @@ var Enumerable = (function() {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#partition([iterator = Prototype.K[, context]]) -> [TrueArray, FalseArray]
|
||||
*
|
||||
* Partitions the elements in two groups: those regarded as true, and those
|
||||
* considered false.
|
||||
* By default, regular JavaScript boolean equivalence is used, but an iterator
|
||||
* can be provided, that computes a boolean representation of the elements.
|
||||
**/
|
||||
function partition(iterator, context) {
|
||||
iterator = iterator || Prototype.K;
|
||||
var trues = [], falses = [];
|
||||
|
@ -152,6 +256,12 @@ var Enumerable = (function() {
|
|||
return [trues, falses];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#pluck(propertyName) -> Array
|
||||
*
|
||||
* Optimization for a common use-case of collect: fetching the same property
|
||||
* for all the elements. Returns the property values.
|
||||
**/
|
||||
function pluck(property) {
|
||||
var results = [];
|
||||
this.each(function(value) {
|
||||
|
@ -160,6 +270,11 @@ var Enumerable = (function() {
|
|||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#reject(iterator[, context]) -> Array
|
||||
*
|
||||
* Returns all the elements for which the iterator returned a “falsy” value.
|
||||
**/
|
||||
function reject(iterator, context) {
|
||||
var results = [];
|
||||
this.each(function(value, index) {
|
||||
|
@ -169,6 +284,12 @@ var Enumerable = (function() {
|
|||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#sortBy(iterator[, context]) -> Array
|
||||
*
|
||||
* Provides a custom-sorted view of the elements based on the criteria computed,
|
||||
* for each element, by the iterator.
|
||||
**/
|
||||
function sortBy(iterator, context) {
|
||||
return this.map(function(value, index) {
|
||||
return {
|
||||
|
@ -181,10 +302,24 @@ var Enumerable = (function() {
|
|||
}).pluck('value');
|
||||
}
|
||||
|
||||
/** alias of: Enumerable#entries
|
||||
* Enumerable#toArray() -> Array
|
||||
*
|
||||
* Returns an Array representation of the enumeration.
|
||||
* Aliased as [[Enumerable#entries]].
|
||||
**/
|
||||
function toArray() {
|
||||
return this.map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#zip(sequence...[, iterator = Prototype.K]) -> Array
|
||||
*
|
||||
* Zips together (think of the zip on a pair of trousers) 2+ sequences,
|
||||
* providing an array of tuples.
|
||||
* Each tuple contains one value per original sequence.
|
||||
* Tuples can be converted to something else by applying the optional iterator on them.
|
||||
**/
|
||||
function zip() {
|
||||
var iterator = Prototype.K, args = $A(arguments);
|
||||
if (Object.isFunction(args.last()))
|
||||
|
@ -196,10 +331,20 @@ var Enumerable = (function() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerable#size() -> Number
|
||||
*
|
||||
* Returns the size of the enumeration.
|
||||
**/
|
||||
function size() {
|
||||
return this.toArray().length;
|
||||
}
|
||||
|
||||
/** related to: Object.inspect
|
||||
* Enumerable#inspect() -> String
|
||||
*
|
||||
* TODO: Enumerable#inspect
|
||||
**/
|
||||
function inspect() {
|
||||
return '#<Enumerable:' + this.toArray().inspect() + '>';
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/** section: lang
|
||||
* Function
|
||||
**/
|
||||
Object.extend(Function.prototype, (function() {
|
||||
var slice = Array.prototype.slice;
|
||||
|
||||
|
@ -12,6 +15,13 @@ Object.extend(Function.prototype, (function() {
|
|||
return update(array, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function#argumentNames() -> Array
|
||||
*
|
||||
* Reads the argument names as stated in the function definition and returns
|
||||
* the values as an array of strings (or an empty array if the function is
|
||||
* defined without parameters).
|
||||
**/
|
||||
function argumentNames() {
|
||||
var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
|
||||
.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
|
||||
|
@ -19,6 +29,13 @@ Object.extend(Function.prototype, (function() {
|
|||
return names.length == 1 && !names[0] ? [] : names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function#bind(object[, args...]) -> Function
|
||||
* - object (Object): The object to bind to.
|
||||
*
|
||||
* Wraps the function in another, locking its execution scope to an object
|
||||
* specified by `object`.
|
||||
**/
|
||||
function bind(context) {
|
||||
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
|
||||
var __method = this, args = slice.call(arguments, 1);
|
||||
|
@ -28,6 +45,14 @@ Object.extend(Function.prototype, (function() {
|
|||
}
|
||||
}
|
||||
|
||||
/** related to: Function#bind
|
||||
* Function#bindAsEventListener(object[, args...]) -> Function
|
||||
* - object (Object): The object to bind to.
|
||||
*
|
||||
* An event-specific variant of [[Function#bind]] which ensures the function
|
||||
* will recieve the current event object as the first argument when
|
||||
* executing.
|
||||
**/
|
||||
function bindAsEventListener(context) {
|
||||
var __method = this, args = slice.call(arguments, 1);
|
||||
return function(event) {
|
||||
|
@ -36,6 +61,15 @@ Object.extend(Function.prototype, (function() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function#curry(args...) -> Function
|
||||
* Partially applies the function, returning a function with one or more
|
||||
* arguments already “filled in.”
|
||||
*
|
||||
* Function#curry works just like [[Function#bind]] without the initial
|
||||
* scope argument. Use the latter if you need to partially apply a function
|
||||
* _and_ modify its execution scope at the same time.
|
||||
**/
|
||||
function curry() {
|
||||
if (!arguments.length) return this;
|
||||
var __method = this, args = slice.call(arguments, 0);
|
||||
|
@ -45,6 +79,19 @@ Object.extend(Function.prototype, (function() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function#delay(seconds[, args...]) -> Number
|
||||
* - seconds (Number): How long to wait before calling the function.
|
||||
*
|
||||
* Schedules the function to run after the specified amount of time, passing
|
||||
* any arguments given.
|
||||
*
|
||||
* Behaves much like `window.setTimeout`. Returns an integer ID that can be
|
||||
* used to clear the timeout with `window.clearTimeout` before it runs.
|
||||
*
|
||||
* To schedule a function to run as soon as the interpreter is idle, use
|
||||
* [[Function#defer]].
|
||||
**/
|
||||
function delay(timeout) {
|
||||
var __method = this, args = slice.call(arguments, 1);
|
||||
timeout = timeout * 1000
|
||||
|
@ -53,11 +100,33 @@ Object.extend(Function.prototype, (function() {
|
|||
}, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function#defer(args...) -> Number
|
||||
* Schedules the function to run as soon as the interpreter is idle.
|
||||
*
|
||||
* A “deferred” function will not run immediately; rather, it will run as soon
|
||||
* as the interpreter’s call stack is empty.
|
||||
*
|
||||
* Behaves much like `window.setTimeout` with a delay set to `0`. Returns an
|
||||
* ID that can be used to clear the timeout with `window.clearTimeout` before
|
||||
* it runs.
|
||||
**/
|
||||
function defer() {
|
||||
var args = update([0.01], arguments);
|
||||
return this.delay.apply(this, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function#wrap(wrapperFunction) -> Function
|
||||
* - wrapperFunction (Function): The function to act as a wrapper.
|
||||
*
|
||||
* Returns a function “wrapped” around the original function.
|
||||
*
|
||||
* `Function#wrap` distills the essence of aspect-oriented programming into
|
||||
* a single method, letting you easily build on existing functions by
|
||||
* specifying before and after behavior, transforming the return value, or
|
||||
* even preventing the original function from being called.
|
||||
**/
|
||||
function wrap(wrapper) {
|
||||
var __method = this;
|
||||
return function() {
|
||||
|
@ -66,6 +135,13 @@ Object.extend(Function.prototype, (function() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function#methodize() -> Function
|
||||
* Wraps the function inside another function that, at call time, pushes
|
||||
* `this` to the original function as the first argument.
|
||||
*
|
||||
* Used to define both a generic method and an instance method.
|
||||
**/
|
||||
function methodize() {
|
||||
if (this._methodized) return this._methodized;
|
||||
var __method = this;
|
||||
|
|
|
@ -1,8 +1,23 @@
|
|||
/** section: lang
|
||||
* $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).
|
||||
**/
|
||||
function $H(object) {
|
||||
return new Hash(object);
|
||||
};
|
||||
|
||||
/** section: lang
|
||||
* class Hash
|
||||
**/
|
||||
var Hash = Class.create(Enumerable, (function() {
|
||||
/**
|
||||
* new Hash([object])
|
||||
*
|
||||
* TODO: new Hash
|
||||
**/
|
||||
function initialize(object) {
|
||||
this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
|
||||
}
|
||||
|
@ -16,34 +31,69 @@ var Hash = Class.create(Enumerable, (function() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#set(key, value) -> value
|
||||
*
|
||||
* Sets the hash’s `key` property to value and returns value.
|
||||
**/
|
||||
function set(key, value) {
|
||||
return this._object[key] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#get(key) -> value
|
||||
*
|
||||
* Returns the value of the hash’s `key` property.
|
||||
**/
|
||||
function get(key) {
|
||||
// simulating poorly supported hasOwnProperty
|
||||
if (this._object[key] !== Object.prototype[key])
|
||||
return this._object[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#unset(key) -> value
|
||||
*
|
||||
* Deletes the hash’s `key` property and returns its value.
|
||||
**/
|
||||
function unset(key) {
|
||||
var value = this._object[key];
|
||||
delete this._object[key];
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#toObject() -> Object
|
||||
*
|
||||
* Returns a cloned, vanilla object.
|
||||
**/
|
||||
function toObject() {
|
||||
return Object.clone(this._object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#keys() -> [String...]
|
||||
*
|
||||
* Provides an Array of keys (that is, property names) for the hash.
|
||||
**/
|
||||
function keys() {
|
||||
return this.pluck('key');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#values() -> Array
|
||||
*
|
||||
* Collect the values of a hash and returns them in an array.
|
||||
**/
|
||||
function values() {
|
||||
return this.pluck('value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#index(value) -> String
|
||||
*
|
||||
* TODO: Hash#index
|
||||
**/
|
||||
function index(value) {
|
||||
var match = this.detect(function(pair) {
|
||||
return pair.value === value;
|
||||
|
@ -51,10 +101,23 @@ var Hash = Class.create(Enumerable, (function() {
|
|||
return match && match.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#merge(object) -> Hash
|
||||
*
|
||||
* Merges `object` to hash and returns the result of that merge.
|
||||
* Prior to v1.6.0: This was destructive (object's values were added to hash).
|
||||
* Since v1.6.0: This is no longer destructive (hash is cloned before the operation).
|
||||
**/
|
||||
function merge(object) {
|
||||
return this.clone().update(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#update(object) -> Hash
|
||||
*
|
||||
* Updates hash with the key/value pairs of `object`.
|
||||
* The original hash will be modified.
|
||||
**/
|
||||
function update(object) {
|
||||
return new Hash(object).inject(this, function(result, pair) {
|
||||
result.set(pair.key, pair.value);
|
||||
|
@ -62,11 +125,21 @@ var Hash = Class.create(Enumerable, (function() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#toQueryPair(key, value) -> String
|
||||
*
|
||||
* TODO: Hash#toQueryPair
|
||||
**/
|
||||
function toQueryPair(key, value) {
|
||||
if (Object.isUndefined(value)) return key;
|
||||
return key + '=' + encodeURIComponent(String.interpret(value));
|
||||
}
|
||||
|
||||
/** related to: String#toQueryParams
|
||||
* Hash#toQueryString() -> String
|
||||
*
|
||||
* Turns a hash into its URL-encoded query string representation.
|
||||
**/
|
||||
function toQueryString() {
|
||||
return this.inject([], function(results, pair) {
|
||||
var key = encodeURIComponent(pair.key), values = pair.value;
|
||||
|
@ -79,16 +152,31 @@ var Hash = Class.create(Enumerable, (function() {
|
|||
}).join('&');
|
||||
}
|
||||
|
||||
/** related to: Object.inspect
|
||||
* Hash#inspect() -> String
|
||||
*
|
||||
* Returns the debug-oriented string representation of the hash.
|
||||
**/
|
||||
function inspect() {
|
||||
return '#<Hash:{' + this.map(function(pair) {
|
||||
return pair.map(Object.inspect).join(': ');
|
||||
}).join(', ') + '}>';
|
||||
}
|
||||
|
||||
/** related to: Object.toJSON
|
||||
* Hash#toJSON() -> String
|
||||
*
|
||||
* Returns a JSON string.
|
||||
**/
|
||||
function toJSON() {
|
||||
return Object.toJSON(this.toObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash#clone() -> newHash
|
||||
*
|
||||
* Returns a clone of hash.
|
||||
**/
|
||||
function clone() {
|
||||
return new Hash(this);
|
||||
}
|
||||
|
|
|
@ -1,38 +1,91 @@
|
|||
/** section: lang
|
||||
* Number
|
||||
**/
|
||||
Object.extend(Number.prototype, (function() {
|
||||
/**
|
||||
* Number#toColorPart() -> String
|
||||
*
|
||||
* Produces a 2-digit hexadecimal representation of the number
|
||||
* (which is therefore assumed to be in the [0..255] range).
|
||||
* Useful for composing CSS color strings.
|
||||
**/
|
||||
function toColorPart() {
|
||||
return this.toPaddedString(2, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number#succ() -> Number
|
||||
*
|
||||
* Returns the successor of the current Number, as defined by current + 1.
|
||||
* Used to make numbers compatible with ObjectRange.
|
||||
**/
|
||||
function succ() {
|
||||
return this + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number#times(iterator) -> Number
|
||||
*
|
||||
* Encapsulates a regular [0..n[ loop, Ruby-style.
|
||||
**/
|
||||
function times(iterator, context) {
|
||||
$R(0, this, true).each(iterator, context);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number#toPaddedString(length[, radix]) -> String
|
||||
*
|
||||
* Converts the number into a string padded with 0s so that the string’s length
|
||||
* is at least equal to `length`.
|
||||
* Takes an optional `radix` argument which specifies the base to use for conversion.
|
||||
**/
|
||||
function toPaddedString(length, radix) {
|
||||
var string = this.toString(radix || 10);
|
||||
return '0'.times(length - string.length) + string;
|
||||
}
|
||||
|
||||
/** related to: Object.toJSON
|
||||
* Number#toJSON() -> String
|
||||
*
|
||||
* Returns a JSON string.
|
||||
**/
|
||||
function toJSON() {
|
||||
return isFinite(this) ? this.toString() : 'null';
|
||||
}
|
||||
|
||||
/**
|
||||
* Number#abs() -> Number
|
||||
*
|
||||
* Returns the absolute value of the number.
|
||||
**/
|
||||
function abs() {
|
||||
return Math.abs(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number#round() -> Number
|
||||
*
|
||||
* Rounds the number to the nearest integer.
|
||||
**/
|
||||
function round() {
|
||||
return Math.round(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number#ceil() -> Number
|
||||
*
|
||||
* Returns the smallest integer greater than or equal to the number.
|
||||
**/
|
||||
function ceil() {
|
||||
return Math.ceil(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number#floor() -> Number
|
||||
*
|
||||
* Returns the largest integer less than or equal to the number.
|
||||
**/
|
||||
function floor() {
|
||||
return Math.floor(this);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/** section: lang
|
||||
* Object
|
||||
**/
|
||||
(function() {
|
||||
|
||||
function getClass(object) {
|
||||
|
@ -5,12 +8,36 @@
|
|||
.match(/^\[object\s(.*)\]$/)[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.extend(destination, source) -> Object
|
||||
* - destination (Object): The object to receive the new properties.
|
||||
* - source (Object): The object whose properties will be duplicated.
|
||||
*
|
||||
* Copies all properties from the source to the destination object. Returns
|
||||
* the destination object.
|
||||
**/
|
||||
function extend(destination, source) {
|
||||
for (var property in source)
|
||||
destination[property] = source[property];
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.inspect(object) -> String
|
||||
* - object (Object): The item to be inspected.
|
||||
*
|
||||
* Returns the debug-oriented string representation of the object.
|
||||
*
|
||||
* `undefined` and `null` are represented as such.
|
||||
*
|
||||
* Other types are checked for a `inspect` method. If there is one, it is
|
||||
* used; otherwise, it reverts to the `toString` method.
|
||||
*
|
||||
* Prototype provides `inspect` methods for many types, both built-in and
|
||||
* library-defined — among them `String`, `Array`, `Enumerable` and `Hash`.
|
||||
* These attempt to provide useful string representations (from a
|
||||
* developer’s standpoint) for their respective types.
|
||||
**/
|
||||
function inspect(object) {
|
||||
try {
|
||||
if (isUndefined(object)) return 'undefined';
|
||||
|
@ -22,6 +49,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.toJSON(object) -> String
|
||||
* - object (Object): The object to be serialized.
|
||||
*
|
||||
* Returns a JSON string.
|
||||
*
|
||||
* `undefined` and `function` types have no JSON representation. `boolean`
|
||||
* and `null` are coerced to strings.
|
||||
*
|
||||
* For other types, `Object.toJSON` looks for a `toJSON` method on `object`.
|
||||
* If there is one, it is used; otherwise the object is treated like a
|
||||
* generic `Object`.
|
||||
**/
|
||||
function toJSON(object) {
|
||||
var type = typeof object;
|
||||
switch (type) {
|
||||
|
@ -45,14 +85,53 @@
|
|||
return '{' + results.join(', ') + '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.toQueryString(object) -> String
|
||||
* object (Object): The object whose property/value pairs will be converted.
|
||||
*
|
||||
* Turns an object into its URL-encoded query string representation.
|
||||
*
|
||||
* This is a form of serialization, and is mostly useful to provide complex
|
||||
* parameter sets for stuff such as objects in the Ajax namespace (e.g.
|
||||
* [[Ajax.Request]]).
|
||||
*
|
||||
* Undefined-value pairs will be serialized as if empty-valued. Array-valued
|
||||
* pairs will get serialized with one name/value pair per array element. All
|
||||
* values get URI-encoded using JavaScript’s native `encodeURIComponent`
|
||||
* function.
|
||||
*
|
||||
* The order of pairs in the serialized form is not guaranteed (and mostly
|
||||
* irrelevant anyway) — except for array-based parts, which are serialized
|
||||
* in array order.
|
||||
**/
|
||||
function toQueryString(object) {
|
||||
return $H(object).toQueryString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.toHTML(object) -> String
|
||||
* - object (Object): The object to convert to HTML.
|
||||
*
|
||||
* Converts the object to its HTML representation.
|
||||
*
|
||||
* Returns the return value of `object`’s `toHTML` method if it exists; else
|
||||
* runs `object` through [[String.interpret]].
|
||||
**/
|
||||
function toHTML(object) {
|
||||
return object && object.toHTML ? object.toHTML() : String.interpret(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.keys(object) -> Array
|
||||
* - object (Object): The object to pull keys from.
|
||||
*
|
||||
* Returns an array of the object's property names.
|
||||
*
|
||||
* Note that the order of the resulting array is browser-dependent — it
|
||||
* relies on the `for…in` loop, for which the ECMAScript spec does not
|
||||
* prescribe an enumeration order. Sort the resulting array if you wish to
|
||||
* normalize the order of the object keys.
|
||||
**/
|
||||
function keys(object) {
|
||||
var results = [];
|
||||
for (var property in object)
|
||||
|
@ -60,6 +139,19 @@
|
|||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.values(object) -> Array
|
||||
* - object (Object): The object to pull values from.
|
||||
*
|
||||
* Returns an array of the object's values.
|
||||
*
|
||||
* Note that the order of the resulting array is browser-dependent — it
|
||||
* relies on the `for…in` loop, for which the ECMAScript spec does not
|
||||
* prescribe an enumeration order.
|
||||
*
|
||||
* Also, remember that while property _names_ are unique, property _values_
|
||||
* have no such constraint.
|
||||
**/
|
||||
function values(object) {
|
||||
var results = [];
|
||||
for (var property in object)
|
||||
|
@ -67,34 +159,89 @@
|
|||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.clone(object) -> Object
|
||||
* - object (Object): The object to clone.
|
||||
*
|
||||
* Duplicates the passed object.
|
||||
*
|
||||
* Copies all the original's key/value pairs onto an empty object.
|
||||
*
|
||||
* Do note that this is a _shallow_ copy, not a _deep_ copy. Nested objects
|
||||
* will retain their references.
|
||||
**/
|
||||
function clone(object) {
|
||||
return extend({ }, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.isElement(object) -> Boolean
|
||||
* - object (Object): The object to test.
|
||||
*
|
||||
* Returns `true` if `object` is a DOM node of type 1; `false` otherwise.
|
||||
**/
|
||||
function isElement(object) {
|
||||
return !!(object && object.nodeType == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.isArray(object) -> Boolean
|
||||
* - object (Object): The object to test.
|
||||
*
|
||||
* Returns `true` if `object` is an array; false otherwise.
|
||||
**/
|
||||
function isArray(object) {
|
||||
return getClass(object) === "Array";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Object.isHash(object) -> Boolean
|
||||
* - object (Object): The object to test.
|
||||
*
|
||||
* Returns `true` if `object` is an instance of the [[Hash]] class; `false`
|
||||
* otherwise.
|
||||
**/
|
||||
function isHash(object) {
|
||||
return object instanceof Hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.isFunction(object) -> Boolean
|
||||
* - object (Object): The object to test.
|
||||
*
|
||||
* Returns `true` if `object` is of type `function`; `false` otherwise.
|
||||
**/
|
||||
function isFunction(object) {
|
||||
return typeof object === "function";
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.isString(object) -> Boolean
|
||||
* - object (Object): The object to test.
|
||||
*
|
||||
* Returns `true` if `object` is of type `string`; `false` otherwise.
|
||||
**/
|
||||
function isString(object) {
|
||||
return getClass(object) === "String";
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.isNumber(object) -> Boolean
|
||||
* - object (Object): The object to test.
|
||||
*
|
||||
* Returns `true` if `object` is of type `number`; `false` otherwise.
|
||||
**/
|
||||
function isNumber(object) {
|
||||
return getClass(object) === "Number";
|
||||
}
|
||||
|
||||
/**
|
||||
* Object.isUndefined(object) -> Boolean
|
||||
* - object (Object): The object to test.
|
||||
*
|
||||
* Returns `true` if `object` is of type `string`; `false` otherwise.
|
||||
**/
|
||||
function isUndefined(object) {
|
||||
return typeof object === "undefined";
|
||||
}
|
||||
|
|
|
@ -1,4 +1,26 @@
|
|||
/** section: lang
|
||||
* class PeriodicalExecuter
|
||||
**/
|
||||
var PeriodicalExecuter = Class.create({
|
||||
/**
|
||||
* new PeriodicalExecuter(callback, frequency)
|
||||
* - callback (Function): the function to be executed at each interval.
|
||||
* - 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.
|
||||
**/
|
||||
initialize: function(callback, frequency) {
|
||||
this.callback = callback;
|
||||
this.frequency = frequency;
|
||||
|
@ -15,6 +37,11 @@ var PeriodicalExecuter = Class.create({
|
|||
this.callback(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* PeriodicalExecuter#stop() -> undefined
|
||||
*
|
||||
* Stops the periodical executer (there will be no further triggers).
|
||||
**/
|
||||
stop: function() {
|
||||
if (!this.timer) return;
|
||||
clearInterval(this.timer);
|
||||
|
|
|
@ -1,8 +1,24 @@
|
|||
/** section: lang
|
||||
* class ObjectRange
|
||||
**/
|
||||
|
||||
/**
|
||||
* $R(start, end[, exclusive = false]) -> ObjectRange
|
||||
*
|
||||
* Creates a new ObjectRange object.
|
||||
* This method is a convenience wrapper around the ObjectRange constructor,
|
||||
* but $R is the preferred alias.
|
||||
**/
|
||||
function $R(start, end, exclusive) {
|
||||
return new ObjectRange(start, end, exclusive);
|
||||
}
|
||||
|
||||
var ObjectRange = Class.create(Enumerable, (function() {
|
||||
/**
|
||||
* new ObjectRange(start, end[, exclusive = false])
|
||||
*
|
||||
* TODO: new ObjectRange
|
||||
**/
|
||||
function initialize(start, end, exclusive) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
|
@ -17,6 +33,11 @@ var ObjectRange = Class.create(Enumerable, (function() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ObjectRange#include(value) -> Boolean
|
||||
*
|
||||
* Determines whether the value is included in the range.
|
||||
**/
|
||||
function include(value) {
|
||||
if (value < this.start)
|
||||
return false;
|
||||
|
|
|
@ -1,5 +1,23 @@
|
|||
/** section: lang
|
||||
* RegExp
|
||||
**/
|
||||
|
||||
/** alias of: RegExp#test
|
||||
* RegExp#match(str) -> Boolean
|
||||
*
|
||||
* Return true if string matches the regular expression, false otherwise.
|
||||
**/
|
||||
RegExp.prototype.match = RegExp.prototype.test;
|
||||
|
||||
/**
|
||||
* RegExp.escape(str) -> String
|
||||
* - str (String): A string intended to be used in a `RegExp` constructor.
|
||||
*
|
||||
* Escapes any characters in the string that have special meaning in a
|
||||
* regular expression.
|
||||
*
|
||||
* Use before passing a string into the `RegExp` constructor.
|
||||
**/
|
||||
RegExp.escape = function(str) {
|
||||
return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
|
||||
};
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
/** section: lang
|
||||
* String
|
||||
**/
|
||||
Object.extend(String, {
|
||||
/**
|
||||
* String.interpret(value) -> String
|
||||
*
|
||||
* TODO: String.interpret
|
||||
**/
|
||||
interpret: function(value) {
|
||||
return value == null ? '' : String(value);
|
||||
},
|
||||
|
@ -20,6 +28,13 @@ Object.extend(String.prototype, (function() {
|
|||
return function(match) { return template.evaluate(match) };
|
||||
}
|
||||
|
||||
/**
|
||||
* String#gsub(pattern, replacement) -> String
|
||||
*
|
||||
* Returns the string with every occurence of a given pattern replaced by either
|
||||
* a regular string, the returned value of a function or a [[Template]] string.
|
||||
* The pattern can be a string or a regular expression.
|
||||
**/
|
||||
function gsub(pattern, replacement) {
|
||||
var result = '', source = this, match;
|
||||
replacement = prepareReplacement(replacement);
|
||||
|
@ -36,6 +51,13 @@ Object.extend(String.prototype, (function() {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* String#sub(pattern, replacement[, count = 1]) -> String
|
||||
*
|
||||
* Returns a string with the first count occurrences of pattern replaced by either
|
||||
* a regular string, the returned value of a function or a [[Template]] string.
|
||||
* The pattern can be a string or a regular expression.
|
||||
**/
|
||||
function sub(pattern, replacement, count) {
|
||||
replacement = prepareReplacement(replacement);
|
||||
count = Object.isUndefined(count) ? 1 : count;
|
||||
|
@ -46,11 +68,24 @@ Object.extend(String.prototype, (function() {
|
|||
});
|
||||
}
|
||||
|
||||
/** related to: String#gsub
|
||||
* String#scan(pattern, iterator) -> String
|
||||
*
|
||||
* Allows iterating over every occurrence of the given pattern (which can be a
|
||||
* string or a regular expression).
|
||||
* Returns the original string.
|
||||
**/
|
||||
function scan(pattern, iterator) {
|
||||
this.gsub(pattern, iterator);
|
||||
return String(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* String#truncate([length = 30[, suffix = '...']]) -> String
|
||||
*
|
||||
* Truncates a string to given `length` and appends `suffix` to it (indicating
|
||||
* that it is only an excerpt).
|
||||
**/
|
||||
function truncate(length, truncation) {
|
||||
length = length || 30;
|
||||
truncation = Object.isUndefined(truncation) ? '...' : truncation;
|
||||
|
@ -58,18 +93,39 @@ Object.extend(String.prototype, (function() {
|
|||
this.slice(0, length - truncation.length) + truncation : String(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* String#strip() -> String
|
||||
*
|
||||
* Strips all leading and trailing whitespace from a string.
|
||||
**/
|
||||
function strip() {
|
||||
return this.replace(/^\s+/, '').replace(/\s+$/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* String#stripTags() -> String
|
||||
*
|
||||
* Strips a string of any HTML tag.
|
||||
**/
|
||||
function stripTags() {
|
||||
return this.replace(/<\/?[^>]+>/gi, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* String#stripScripts() -> String
|
||||
*
|
||||
* Strips a string of anything that looks like an HTML script block.
|
||||
**/
|
||||
function stripScripts() {
|
||||
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
|
||||
}
|
||||
|
||||
/**
|
||||
* String#extractScripts() -> Array
|
||||
*
|
||||
* Exctracts the content of any script block present in the string and returns
|
||||
* them as an array of strings.
|
||||
**/
|
||||
function extractScripts() {
|
||||
var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
|
||||
var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
|
||||
|
@ -78,15 +134,31 @@ Object.extend(String.prototype, (function() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* String#evalScripts() -> Array
|
||||
*
|
||||
* Evaluates the content of any script block present in the string.
|
||||
* Returns an array containing the value returned by each script.
|
||||
**/
|
||||
function evalScripts() {
|
||||
return this.extractScripts().map(function(script) { return eval(script) });
|
||||
}
|
||||
|
||||
/**
|
||||
* String#escapeHTML() -> String
|
||||
*
|
||||
* Converts HTML special characters to their entity equivalents.
|
||||
**/
|
||||
function escapeHTML() {
|
||||
escapeHTML.text.data = this;
|
||||
return escapeHTML.div.innerHTML;
|
||||
}
|
||||
|
||||
/** related to: String#escapeHTML
|
||||
* String#unescapeHTML() -> String
|
||||
*
|
||||
* Strips tags and converts the entity forms of special HTML characters to their normal form.
|
||||
**/
|
||||
function unescapeHTML() {
|
||||
var div = new Element('div');
|
||||
div.innerHTML = this.stripTags();
|
||||
|
@ -95,6 +167,11 @@ Object.extend(String.prototype, (function() {
|
|||
div.childNodes[0].nodeValue) : '';
|
||||
}
|
||||
|
||||
/** alias of: String#parseQuery, related to: Hash#toQueryString
|
||||
* String#toQueryParams([separator = '&']) -> Object
|
||||
*
|
||||
* Parses a URI-like query string and returns an object composed of parameter/value pairs.
|
||||
**/
|
||||
function toQueryParams(separator) {
|
||||
var match = this.strip().match(/([^?#]*)(#.*)?$/);
|
||||
if (!match) return { };
|
||||
|
@ -115,19 +192,42 @@ Object.extend(String.prototype, (function() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* String#toArray() -> Array
|
||||
*
|
||||
* Splits the string character-by-character and returns an array with the result.
|
||||
**/
|
||||
function toArray() {
|
||||
return this.split('');
|
||||
}
|
||||
|
||||
/**
|
||||
* String#succ() -> String
|
||||
*
|
||||
* Used internally by ObjectRange.
|
||||
* Converts the last character of the string to the following character in the
|
||||
* Unicode alphabet.
|
||||
**/
|
||||
function succ() {
|
||||
return this.slice(0, this.length - 1) +
|
||||
String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* String#times(count) -> String
|
||||
*
|
||||
* Concatenates the string `count` times.
|
||||
**/
|
||||
function times(count) {
|
||||
return count < 1 ? '' : new Array(count + 1).join(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* String#camelize() -> String
|
||||
*
|
||||
* Converts a string separated by dashes into a camelCase equivalent.
|
||||
* For instance, 'foo-bar' would be converted to 'fooBar'.
|
||||
**/
|
||||
function camelize() {
|
||||
var parts = this.split('-'), len = parts.length;
|
||||
if (len == 1) return parts[0];
|
||||
|
@ -142,18 +242,39 @@ Object.extend(String.prototype, (function() {
|
|||
return camelized;
|
||||
}
|
||||
|
||||
/**
|
||||
* String#capitalize() -> String
|
||||
*
|
||||
* Capitalizes the first letter of a string and downcases all the others.
|
||||
**/
|
||||
function capitalize() {
|
||||
return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* String#underscore() -> String
|
||||
*
|
||||
* Converts a camelized string into a series of words separated by an underscore ("_").
|
||||
**/
|
||||
function underscore() {
|
||||
return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* String#dasherize() -> String
|
||||
*
|
||||
* Replaces every instance of the underscore character ("_") by a dash ("-").
|
||||
**/
|
||||
function dasherize() {
|
||||
return this.gsub(/_/,'-');
|
||||
}
|
||||
|
||||
/** related to: Object.inspect
|
||||
* String#inspect([useDoubleQuotes = false]) -> String
|
||||
*
|
||||
* Returns a debug-oriented version of the string (i.e. wrapped in single or
|
||||
* double quotes, with backslashes and quotes escaped).
|
||||
**/
|
||||
function inspect(useDoubleQuotes) {
|
||||
var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
|
||||
var character = String.specialChar[match[0]];
|
||||
|
@ -163,14 +284,31 @@ Object.extend(String.prototype, (function() {
|
|||
return "'" + escapedString.replace(/'/g, '\\\'') + "'";
|
||||
}
|
||||
|
||||
/** related to: Object.toJSON
|
||||
* String#toJSON() -> String
|
||||
*
|
||||
* Returns a JSON string.
|
||||
**/
|
||||
function toJSON() {
|
||||
return this.inspect(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* String#unfilterJSON([filter = Prototype.JSONFilter]) -> String
|
||||
*
|
||||
* Strips comment delimiters around Ajax JSON or JavaScript responses.
|
||||
* This security method is called internally.
|
||||
**/
|
||||
function unfilterJSON(filter) {
|
||||
return this.sub(filter || Prototype.JSONFilter, '#{1}');
|
||||
}
|
||||
|
||||
/**
|
||||
* String#isJSON() -> Boolean
|
||||
*
|
||||
* Check if the string is valid JSON by the use of regular expressions.
|
||||
* This security method is called internally.
|
||||
**/
|
||||
function isJSON() {
|
||||
var str = this;
|
||||
if (str.blank()) return false;
|
||||
|
@ -178,6 +316,13 @@ Object.extend(String.prototype, (function() {
|
|||
return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* String#evalJSON([sanitize = false]) -> object
|
||||
*
|
||||
* Evaluates the JSON in the string and returns the resulting object.
|
||||
* If the optional sanitize parameter is set to true, the string is checked for
|
||||
* possible malicious attempts and eval is not called if one is detected.
|
||||
**/
|
||||
function evalJSON(sanitize) {
|
||||
var json = this.unfilterJSON();
|
||||
try {
|
||||
|
@ -186,27 +331,57 @@ Object.extend(String.prototype, (function() {
|
|||
throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
|
||||
}
|
||||
|
||||
/**
|
||||
* String#include(substring) -> Boolean
|
||||
*
|
||||
* Check if the string contains a substring.
|
||||
**/
|
||||
function include(pattern) {
|
||||
return this.indexOf(pattern) > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* String#startsWith(substring) -> Boolean
|
||||
*
|
||||
* Checks if the string starts with substring.
|
||||
**/
|
||||
function startsWith(pattern) {
|
||||
return this.indexOf(pattern) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* String#endsWith(substring) -> Boolean
|
||||
*
|
||||
* Checks if the string ends with substring.
|
||||
**/
|
||||
function endsWith(pattern) {
|
||||
var d = this.length - pattern.length;
|
||||
return d >= 0 && this.lastIndexOf(pattern) === d;
|
||||
}
|
||||
|
||||
/**
|
||||
* String#empty() -> Boolean
|
||||
*
|
||||
* Checks if the string is empty.
|
||||
**/
|
||||
function empty() {
|
||||
return this == '';
|
||||
}
|
||||
|
||||
/**
|
||||
* String#blank() -> Boolean
|
||||
*
|
||||
* Check if the string is 'blank', meaning either empty or containing only whitespace.
|
||||
**/
|
||||
function blank() {
|
||||
return /^\s*$/.test(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* String#interpolate(object[, pattern]) -> String
|
||||
*
|
||||
* Treats the string as a Template and fills it with object’s properties.
|
||||
**/
|
||||
function interpolate(object, pattern) {
|
||||
return new Template(this, pattern).evaluate(object);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,23 @@
|
|||
/** section: lang
|
||||
* class Template
|
||||
**/
|
||||
var Template = Class.create({
|
||||
/**
|
||||
* new Template(template[, pattern = Template.Pattern])
|
||||
*
|
||||
* TODO: new Template
|
||||
**/
|
||||
initialize: function(template, pattern) {
|
||||
this.template = template.toString();
|
||||
this.pattern = pattern || Template.Pattern;
|
||||
},
|
||||
|
||||
/**
|
||||
* Template#evaluate(object) -> String
|
||||
*
|
||||
* Applies the template to given `object`’s data, producing a formatted string
|
||||
* with symbols replaced by corresponding object’s properties.
|
||||
**/
|
||||
evaluate: function(object) {
|
||||
if (Object.isFunction(object.toTemplateReplacements))
|
||||
object = object.toTemplateReplacements();
|
||||
|
|
|
@ -35,6 +35,21 @@ if (Prototype.Browser.MobileSafari)
|
|||
|
||||
var Abstract = { };
|
||||
|
||||
/**
|
||||
* == lang ==
|
||||
* Language extensions.
|
||||
**/
|
||||
|
||||
/** section: lang
|
||||
* Try
|
||||
**/
|
||||
|
||||
/**
|
||||
* Try.these(function...) -> ?
|
||||
* - function (Function): A function that may throw an exception.
|
||||
* Accepts an arbitrary number of functions and returns the result of the
|
||||
* first one that doesn't throw an error.
|
||||
**/
|
||||
var Try = {
|
||||
these: function() {
|
||||
var returnValue;
|
||||
|
|
Loading…
Reference in New Issue