prototype/src/lang/hash.js

261 lines
7.2 KiB
JavaScript
Raw Normal View History

/** section: Language, related to: Hash
2008-12-14 04:36:59 +00:00
* $H([object]) -> Hash
*
* Creates a `Hash`. This is purely a convenience wrapper around the Hash
* constructor, it does not do anything other than pass any argument it's
* given into the Hash constructor and return the result.
2008-12-14 04:36:59 +00:00
**/
2007-10-13 10:55:52 +00:00
function $H(object) {
return new Hash(object);
2007-01-18 22:24:27 +00:00
};
2009-03-05 19:56:01 +00:00
/** section: Language
2008-12-14 04:36:59 +00:00
* class Hash
* includes Enumerable
*
* 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>
*
* You can create a Hash either via `new Hash()` or the convenience alias
* `$H()`; there is **no** difference between them. In either case, you may
* optionally pass in an object to seed the `Hash`. If you pass in a `Hash`,
* it will be cloned.
*
2008-12-14 04:36:59 +00:00
**/
2007-10-13 10:55:52 +00:00
var Hash = Class.create(Enumerable, (function() {
2008-12-14 04:36:59 +00:00
/**
* new Hash([object])
*
2009-02-24 02:21:02 +00:00
* Creates a new `Hash`. If `object` is given, the new hash will be populated
* with all the object's properties. See [[$H]].
2008-12-14 04:36:59 +00:00
**/
2008-09-28 17:41:53 +00:00
function initialize(object) {
this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
}
2009-09-10 13:55:12 +00:00
// Docs for #each even though technically it's implemented by Enumerable
/**
* Hash#each(iterator[, context]) -> Hash
* - iterator (Function): A function that expects each item in the `Hash`
* as the first argument and a numerical index as the second.
* - context (Object): The scope in which to call `iterator`. Determines what
* `this` means inside `iterator`.
*
* Iterates over the name/value pairs in the hash.
*
* This is actually just the [[Enumerable#each #each]] method from the
* mixed-in [[Enumerable]] module. It is documented here to describe the
* structure of the elements passed to the iterator and the order of
* iteration.
*
* The iterator's first argument (the "item") is an object with two
* properties:
*
* - `key`: the key name as a `String`
* - `value`: the corresponding value (which may be `undefined`)
*
* The order of iteration is implementation-dependent, as it relies on
* the order of the native `for..in` loop. Although most modern
* implementations exhibit *ordered* behavior, this is not standardized and
* may not always be the case, and so cannot be relied upon.
*
* ### Example
*
* var h = $H({version: 1.6, author: 'The Core Team'});
*
* h.each(function(pair) {
* alert(pair.key + ' = "' + pair.value + '"');
* });
* // Alerts 'version = "1.6"' and 'author = "The Core Team"'
* // -or-
* // Alerts 'author = "The Core Team"' and 'version = "1.6"'
**/
// Our _internal_ each
2008-09-28 17:41:53 +00:00
function _each(iterator) {
for (var key in this._object) {
var value = this._object[key], pair = [key, value];
pair.key = key;
pair.value = value;
iterator(pair);
}
}
2008-12-14 04:36:59 +00:00
/**
* Hash#set(key, value) -> value
*
* Sets the hash's `key` property to `value` and returns `value`.
2008-12-14 04:36:59 +00:00
**/
2008-09-28 17:41:53 +00:00
function set(key, value) {
return this._object[key] = value;
}
2008-12-14 04:36:59 +00:00
/**
* Hash#get(key) -> value
*
* Returns the value of the hash's `key` property.
2008-12-14 04:36:59 +00:00
**/
2008-09-28 17:41:53 +00:00
function get(key) {
// simulating poorly supported hasOwnProperty
if (this._object[key] !== Object.prototype[key])
return this._object[key];
}
2008-12-14 04:36:59 +00:00
/**
* Hash#unset(key) -> value
*
* Deletes the hash's `key` property and returns its value.
2008-12-14 04:36:59 +00:00
**/
2008-09-28 17:41:53 +00:00
function unset(key) {
var value = this._object[key];
delete this._object[key];
return value;
}
2008-12-14 04:36:59 +00:00
/**
* Hash#toObject() -> Object
*
* Returns a cloned, vanilla object.
**/
2008-09-28 17:41:53 +00:00
function toObject() {
return Object.clone(this._object);
}
2008-12-14 04:36:59 +00:00
/**
* Hash#keys() -> [String...]
*
2008-12-14 04:36:59 +00:00
* Provides an Array of keys (that is, property names) for the hash.
**/
2008-09-28 17:41:53 +00:00
function keys() {
return this.pluck('key');
}
2008-12-14 04:36:59 +00:00
/**
* Hash#values() -> Array
*
* Collect the values of a hash and returns them in an array.
**/
2008-09-28 17:41:53 +00:00
function values() {
return this.pluck('value');
}
2008-12-14 04:36:59 +00:00
/**
* Hash#index(value) -> String
*
2009-02-24 02:21:02 +00:00
* Returns the first key in the hash whose value matches `value`.
* Returns `false` if there is no such key.
2008-12-14 04:36:59 +00:00
**/
2008-09-28 17:41:53 +00:00
function index(value) {
var match = this.detect(function(pair) {
return pair.value === value;
2008-09-28 17:41:53 +00:00
});
return match && match.key;
}
2008-12-14 04:36:59 +00:00
/**
* Hash#merge(object) -> Hash
*
2009-02-24 02:21:02 +00:00
* Returns a new hash with `object`'s key/value pairs merged in.
* To modify the original hash in place, use [[Hash#update]].
*
2008-12-14 04:36:59 +00:00
**/
2008-09-28 17:41:53 +00:00
function merge(object) {
return this.clone().update(object);
}
2008-12-14 04:36:59 +00:00
/**
* Hash#update(object) -> Hash
*
* Updates hash with the key/value pairs of `object`.
2009-02-24 02:21:02 +00:00
* The original hash will be modified. To return a new hash instead, use
* [[Hash#merge]].
2008-12-14 04:36:59 +00:00
**/
2008-09-28 17:41:53 +00:00
function update(object) {
return new Hash(object).inject(this, function(result, pair) {
result.set(pair.key, pair.value);
return result;
});
}
2009-02-24 02:21:02 +00:00
// Private. No PDoc necessary.
2007-10-13 10:55:52 +00:00
function toQueryPair(key, value) {
if (Object.isUndefined(value)) return key;
return key + '=' + encodeURIComponent(String.interpret(value));
2007-01-18 22:24:27 +00:00
}
2008-12-14 04:36:59 +00:00
/** related to: String#toQueryParams
* Hash#toQueryString() -> String
*
2008-12-14 04:36:59 +00:00
* Turns a hash into its URL-encoded query string representation.
**/
2008-09-28 17:41:53 +00:00
function toQueryString() {
return this.inject([], function(results, pair) {
var key = encodeURIComponent(pair.key), values = pair.value;
2008-09-28 17:41:53 +00:00
if (values && typeof values == 'object') {
if (Object.isArray(values))
return results.concat(values.map(toQueryPair.curry(key)));
} else results.push(toQueryPair(key, values));
return results;
}).join('&');
}
2008-09-28 17:41:53 +00:00
2008-12-14 04:36:59 +00:00
/** related to: Object.inspect
* Hash#inspect() -> String
*
* Returns the debug-oriented string representation of the Hash.
2008-12-14 04:36:59 +00:00
**/
2008-09-28 17:41:53 +00:00
function inspect() {
return '#<Hash:{' + this.map(function(pair) {
return pair.map(Object.inspect).join(': ');
}).join(', ') + '}>';
}
2008-12-14 04:36:59 +00:00
/** related to: Object.toJSON
* Hash#toJSON() -> String
*
2008-12-14 04:36:59 +00:00
* Returns a JSON string.
**/
2008-09-28 17:41:53 +00:00
function toJSON() {
return Object.toJSON(this.toObject());
}
2008-12-14 04:36:59 +00:00
/**
2009-02-24 02:21:02 +00:00
* Hash#clone() -> Hash
2008-12-14 04:36:59 +00:00
*
* Returns a clone of this Hash.
2008-12-14 04:36:59 +00:00
**/
2008-09-28 17:41:53 +00:00
function clone() {
return new Hash(this);
}
2008-09-28 17:41:53 +00:00
return {
initialize: initialize,
_each: _each,
set: set,
get: get,
unset: unset,
toObject: toObject,
toTemplateReplacements: toObject,
keys: keys,
values: values,
index: index,
merge: merge,
update: update,
toQueryString: toQueryString,
inspect: inspect,
toJSON: toJSON,
clone: clone
};
2007-10-13 10:55:52 +00:00
})());
Hash.from = $H;