/src/lang/hash.js

https://github.com/jwheare/prototype · JavaScript · 223 lines · 96 code · 19 blank · 108 comment · 9 complexity · 079228eca30f26d32e4151b831cef02f MD5 · raw file

  1. /** section: Language, related to: Hash
  2. * $H([object]) -> Hash
  3. *
  4. * Creates a `Hash`.
  5. *
  6. * `$H` is a convenience wrapper around the Hash constructor, with a safeguard
  7. * that lets you pass an existing Hash object and get it back untouched
  8. * (instead of uselessly cloning it).
  9. **/
  10. function $H(object) {
  11. return new Hash(object);
  12. };
  13. /** section: Language
  14. * class Hash
  15. *
  16. * A set of key/value pairs.
  17. *
  18. * `Hash` can be thought of as an associative array, binding unique keys to
  19. * values (which are not necessarily unique), though it can not guarantee
  20. * consistent order its elements when iterating. Because of the nature of
  21. * JavaScript, every object is in fact a hash; but `Hash` adds a number of
  22. * methods that let you enumerate keys and values, iterate over key/value
  23. * pairs, merge two hashes together, and much more.
  24. *
  25. * <h4>Creating a hash</h4>
  26. *
  27. * There are two ways to construct a Hash instance: the first is regular
  28. * JavaScript object instantiation with the `new` keyword, and the second is
  29. * using the [[$H]] function. There is one difference between them: if a `Hash`
  30. * is passed to `$H`, it will be returned as-is, wherease the same hash passed
  31. * to `new Hash` will be _cloned_ instead.
  32. *
  33. **/
  34. var Hash = Class.create(Enumerable, (function() {
  35. /**
  36. * new Hash([object])
  37. *
  38. * Creates a new `Hash`. If `object` is given, the new hash will be populated
  39. * with all the object's properties. See [[$H]].
  40. **/
  41. function initialize(object) {
  42. this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
  43. }
  44. function _each(iterator) {
  45. for (var key in this._object) {
  46. var value = this._object[key], pair = [key, value];
  47. pair.key = key;
  48. pair.value = value;
  49. iterator(pair);
  50. }
  51. }
  52. /**
  53. * Hash#set(key, value) -> value
  54. *
  55. * Sets the hash’s `key` property to `value` and returns `value`.
  56. **/
  57. function set(key, value) {
  58. return this._object[key] = value;
  59. }
  60. /**
  61. * Hash#get(key) -> value
  62. *
  63. * Returns the value of the hash’s `key` property.
  64. **/
  65. function get(key) {
  66. // simulating poorly supported hasOwnProperty
  67. if (this._object[key] !== Object.prototype[key])
  68. return this._object[key];
  69. }
  70. /**
  71. * Hash#unset(key) -> value
  72. *
  73. * Deletes the hash’s `key` property and returns its value.
  74. **/
  75. function unset(key) {
  76. var value = this._object[key];
  77. delete this._object[key];
  78. return value;
  79. }
  80. /**
  81. * Hash#toObject() -> Object
  82. *
  83. * Returns a cloned, vanilla object.
  84. **/
  85. function toObject() {
  86. return Object.clone(this._object);
  87. }
  88. /**
  89. * Hash#keys() -> [String...]
  90. *
  91. * Provides an Array of keys (that is, property names) for the hash.
  92. **/
  93. function keys() {
  94. return this.pluck('key');
  95. }
  96. /**
  97. * Hash#values() -> Array
  98. *
  99. * Collect the values of a hash and returns them in an array.
  100. **/
  101. function values() {
  102. return this.pluck('value');
  103. }
  104. /**
  105. * Hash#index(value) -> String
  106. *
  107. * Returns the first key in the hash whose value matches `value`.
  108. * Returns `false` if there is no such key.
  109. **/
  110. function index(value) {
  111. var match = this.detect(function(pair) {
  112. return pair.value === value;
  113. });
  114. return match && match.key;
  115. }
  116. /**
  117. * Hash#merge(object) -> Hash
  118. *
  119. * Returns a new hash with `object`'s key/value pairs merged in.
  120. * To modify the original hash in place, use [[Hash#update]].
  121. *
  122. **/
  123. function merge(object) {
  124. return this.clone().update(object);
  125. }
  126. /**
  127. * Hash#update(object) -> Hash
  128. *
  129. * Updates hash with the key/value pairs of `object`.
  130. * The original hash will be modified. To return a new hash instead, use
  131. * [[Hash#merge]].
  132. **/
  133. function update(object) {
  134. return new Hash(object).inject(this, function(result, pair) {
  135. result.set(pair.key, pair.value);
  136. return result;
  137. });
  138. }
  139. // Private. No PDoc necessary.
  140. function toQueryPair(key, value) {
  141. if (Object.isUndefined(value)) return key;
  142. return key + '=' + encodeURIComponent(String.interpret(value));
  143. }
  144. /** related to: String#toQueryParams
  145. * Hash#toQueryString() -> String
  146. *
  147. * Turns a hash into its URL-encoded query string representation.
  148. **/
  149. function toQueryString() {
  150. return this.inject([], function(results, pair) {
  151. var key = encodeURIComponent(pair.key), values = pair.value;
  152. if (values && typeof values == 'object') {
  153. if (Object.isArray(values))
  154. return results.concat(values.map(toQueryPair.curry(key)));
  155. } else results.push(toQueryPair(key, values));
  156. return results;
  157. }).join('&');
  158. }
  159. /** related to: Object.inspect
  160. * Hash#inspect() -> String
  161. *
  162. * Returns the debug-oriented string representation of the hash.
  163. **/
  164. function inspect() {
  165. return '#<Hash:{' + this.map(function(pair) {
  166. return pair.map(Object.inspect).join(': ');
  167. }).join(', ') + '}>';
  168. }
  169. /** related to: Object.toJSON
  170. * Hash#toJSON() -> String
  171. *
  172. * Returns a JSON string.
  173. **/
  174. function toJSON() {
  175. return Object.toJSON(this.toObject());
  176. }
  177. /**
  178. * Hash#clone() -> Hash
  179. *
  180. * Returns a clone of hash.
  181. **/
  182. function clone() {
  183. return new Hash(this);
  184. }
  185. return {
  186. initialize: initialize,
  187. _each: _each,
  188. set: set,
  189. get: get,
  190. unset: unset,
  191. toObject: toObject,
  192. toTemplateReplacements: toObject,
  193. keys: keys,
  194. values: values,
  195. index: index,
  196. merge: merge,
  197. update: update,
  198. toQueryString: toQueryString,
  199. inspect: inspect,
  200. toJSON: toJSON,
  201. clone: clone
  202. };
  203. })());
  204. Hash.from = $H;