acts_as_dashboard 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +54 -0
  5. data/Rakefile +23 -0
  6. data/VERSION +1 -0
  7. data/acts_as_dashboard.gemspec +166 -0
  8. data/generators/dashboard/USAGE +23 -0
  9. data/generators/dashboard/dashboard_generator.rb +105 -0
  10. data/generators/dashboard/templates/controller.erb +39 -0
  11. data/generators/dashboard/templates/dashboard.css +66 -0
  12. data/generators/dashboard/templates/dashboard.js +305 -0
  13. data/generators/dashboard/templates/jqplot-0.9.7/jquery.jqplot.min.js +14 -0
  14. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.barRenderer.js +404 -0
  15. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.barRenderer.min.js +14 -0
  16. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasAxisLabelRenderer.js +200 -0
  17. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasAxisLabelRenderer.min.js +14 -0
  18. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasAxisTickRenderer.js +232 -0
  19. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasAxisTickRenderer.min.js +14 -0
  20. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasTextRenderer.js +408 -0
  21. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.canvasTextRenderer.min.js +14 -0
  22. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.categoryAxisRenderer.js +238 -0
  23. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.categoryAxisRenderer.min.js +14 -0
  24. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.cursor.js +812 -0
  25. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.cursor.min.js +14 -0
  26. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.dateAxisRenderer.js +313 -0
  27. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.dateAxisRenderer.min.js +14 -0
  28. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.dragable.js +203 -0
  29. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.dragable.min.js +14 -0
  30. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.highlighter.js +359 -0
  31. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.highlighter.min.js +14 -0
  32. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.logAxisRenderer.js +434 -0
  33. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.logAxisRenderer.min.js +14 -0
  34. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.mekkoAxisRenderer.js +595 -0
  35. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.mekkoAxisRenderer.min.js +14 -0
  36. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.mekkoRenderer.js +308 -0
  37. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.mekkoRenderer.min.js +14 -0
  38. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.ohlcRenderer.js +343 -0
  39. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.ohlcRenderer.min.js +14 -0
  40. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.pieRenderer.js +333 -0
  41. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.pieRenderer.min.js +14 -0
  42. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.pointLabels.js +307 -0
  43. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.pointLabels.js.orig +273 -0
  44. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.pointLabels.min.js +14 -0
  45. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.trendline.js +208 -0
  46. data/generators/dashboard/templates/jqplot-0.9.7/plugins/jqplot.trendline.min.js +14 -0
  47. data/generators/dashboard/templates/jquery.jqplot.min.css +1 -0
  48. data/generators/dashboard/templates/js.class-2.1.4/CHANGELOG +269 -0
  49. data/generators/dashboard/templates/js.class-2.1.4/MIT-LICENSE +30 -0
  50. data/generators/dashboard/templates/js.class-2.1.4/README +30 -0
  51. data/generators/dashboard/templates/js.class-2.1.4/min/command.js +1 -0
  52. data/generators/dashboard/templates/js.class-2.1.4/min/comparable.js +1 -0
  53. data/generators/dashboard/templates/js.class-2.1.4/min/constant_scope.js +1 -0
  54. data/generators/dashboard/templates/js.class-2.1.4/min/core.js +1 -0
  55. data/generators/dashboard/templates/js.class-2.1.4/min/decorator.js +1 -0
  56. data/generators/dashboard/templates/js.class-2.1.4/min/enumerable.js +1 -0
  57. data/generators/dashboard/templates/js.class-2.1.4/min/forwardable.js +1 -0
  58. data/generators/dashboard/templates/js.class-2.1.4/min/hash.js +1 -0
  59. data/generators/dashboard/templates/js.class-2.1.4/min/linked_list.js +1 -0
  60. data/generators/dashboard/templates/js.class-2.1.4/min/loader.js +1 -0
  61. data/generators/dashboard/templates/js.class-2.1.4/min/method_chain.js +1 -0
  62. data/generators/dashboard/templates/js.class-2.1.4/min/observable.js +1 -0
  63. data/generators/dashboard/templates/js.class-2.1.4/min/package.js +1 -0
  64. data/generators/dashboard/templates/js.class-2.1.4/min/proxy.js +1 -0
  65. data/generators/dashboard/templates/js.class-2.1.4/min/ruby.js +1 -0
  66. data/generators/dashboard/templates/js.class-2.1.4/min/set.js +1 -0
  67. data/generators/dashboard/templates/js.class-2.1.4/min/stack_trace.js +1 -0
  68. data/generators/dashboard/templates/js.class-2.1.4/min/state.js +1 -0
  69. data/generators/dashboard/templates/js.class-2.1.4/min/stdlib.js +16 -0
  70. data/generators/dashboard/templates/js.class-2.1.4/src/command.js +93 -0
  71. data/generators/dashboard/templates/js.class-2.1.4/src/comparable.js +37 -0
  72. data/generators/dashboard/templates/js.class-2.1.4/src/constant_scope.js +48 -0
  73. data/generators/dashboard/templates/js.class-2.1.4/src/core.js +1060 -0
  74. data/generators/dashboard/templates/js.class-2.1.4/src/decorator.js +50 -0
  75. data/generators/dashboard/templates/js.class-2.1.4/src/enumerable.js +505 -0
  76. data/generators/dashboard/templates/js.class-2.1.4/src/forwardable.js +22 -0
  77. data/generators/dashboard/templates/js.class-2.1.4/src/hash.js +334 -0
  78. data/generators/dashboard/templates/js.class-2.1.4/src/linked_list.js +114 -0
  79. data/generators/dashboard/templates/js.class-2.1.4/src/loader.js +458 -0
  80. data/generators/dashboard/templates/js.class-2.1.4/src/method_chain.js +172 -0
  81. data/generators/dashboard/templates/js.class-2.1.4/src/observable.js +55 -0
  82. data/generators/dashboard/templates/js.class-2.1.4/src/package.js +377 -0
  83. data/generators/dashboard/templates/js.class-2.1.4/src/proxy.js +58 -0
  84. data/generators/dashboard/templates/js.class-2.1.4/src/ruby.js +44 -0
  85. data/generators/dashboard/templates/js.class-2.1.4/src/set.js +332 -0
  86. data/generators/dashboard/templates/js.class-2.1.4/src/stack_trace.js +151 -0
  87. data/generators/dashboard/templates/js.class-2.1.4/src/state.js +95 -0
  88. data/generators/dashboard/templates/js.class-2.1.4/src/stdlib.js +2517 -0
  89. data/generators/dashboard/templates/show.html.erb +67 -0
  90. data/lib/acts_as_dashboard/app/views/dashboards/show.html.erb +67 -0
  91. data/lib/acts_as_dashboard/class_methods.rb +58 -0
  92. data/lib/acts_as_dashboard/config.rb +25 -0
  93. data/lib/acts_as_dashboard/instance_methods.rb +32 -0
  94. data/lib/acts_as_dashboard/line_graph_widget.rb +68 -0
  95. data/lib/acts_as_dashboard/public/javascripts/dashboard.js +305 -0
  96. data/lib/acts_as_dashboard/public/stylesheets/dashboard.css +66 -0
  97. data/lib/acts_as_dashboard/short_messages_widget.rb +25 -0
  98. data/lib/acts_as_dashboard/widget.rb +55 -0
  99. data/lib/acts_as_dashboard.rb +17 -0
  100. data/spec/acts_as_dashboard/class_method_specs.rb +188 -0
  101. data/spec/acts_as_dashboard/config_spec.rb +57 -0
  102. data/spec/acts_as_dashboard/instance_methods_spec.rb +134 -0
  103. data/spec/acts_as_dashboard/line_graph_widget_spec.rb +165 -0
  104. data/spec/acts_as_dashboard/short_messages_widget_spec.rb +69 -0
  105. data/spec/acts_as_dashboard/widget_spec.rb +6 -0
  106. data/spec/acts_as_dashboard_spec.rb +15 -0
  107. data/spec/shared/widget_behaviours.rb +171 -0
  108. data/spec/spec.opts +1 -0
  109. data/spec/spec_helper.rb +10 -0
  110. data/tasks/install.rake +8 -0
  111. data/tasks/install_javascript.rake +7 -0
  112. data/tasks/install_stylesheets.rake +7 -0
  113. metadata +209 -0
@@ -0,0 +1,1060 @@
1
+ /**
2
+ * JS.Class: Ruby-style JavaScript
3
+ * Copyright (c) 2007-2010 James Coglan
4
+ *
5
+ * http://jsclass.jcoglan.com
6
+ * http://github.com/jcoglan/js.class
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ *
26
+ * Parts of this software are derived from the following open-source projects:
27
+ *
28
+ * - The Prototype framework, (c) 2005-2010 Sam Stephenson
29
+ * - Alex Arnell's Inheritance library, (c) 2006, Alex Arnell
30
+ * - Base, (c) 2006-9, Dean Edwards
31
+ */
32
+
33
+ /**
34
+ * == core ==
35
+ **/
36
+
37
+ /** section: core
38
+ * JS
39
+ *
40
+ * The `JS` object is used as a namespace by the rest of the JS.Class framework, and hosts
41
+ * various utility methods used throughout. None of these methods should be taken as being
42
+ * public API, they are all 'plumbing' and may be removed or changed at any time.
43
+ **/
44
+ this.JS = this.JS || {};
45
+
46
+ /**
47
+ * JS.extend(target, extensions) -> Object
48
+ * - target (Object): object to be extended
49
+ * - extensions (Object): object containing key/value pairs to add to target
50
+ *
51
+ * Adds the properties of the second argument to the first, and returns the first. Will not
52
+ * needlessly overwrite fields with identical values; if an object has inherited a property
53
+ * we should not add the property to the object itself.
54
+ **/
55
+ JS.extend = function(target, extensions) {
56
+ extensions = extensions || {};
57
+ for (var prop in extensions) {
58
+ if (target[prop] === extensions[prop]) continue;
59
+ target[prop] = extensions[prop];
60
+ }
61
+ return target;
62
+ };
63
+
64
+ JS.extend(JS, {
65
+
66
+ /**
67
+ * JS.makeFunction() -> Function
68
+ *
69
+ * Returns a function for use as a constructor. These functions are used as the basis for
70
+ * classes. The constructor calls the object's `initialize()` method if it exists.
71
+ **/
72
+ makeFunction: function() {
73
+ return function() {
74
+ return this.initialize
75
+ ? (this.initialize.apply(this, arguments) || this)
76
+ : this;
77
+ };
78
+ },
79
+
80
+ /**
81
+ * JS.makeBridge(klass) -> Object
82
+ * - klass (JS.Class): class from which you want to inherit
83
+ *
84
+ * Takes a class and returns an instance of it, without calling the class's constructor.
85
+ * Used for forging prototype links between objects using JavaScript's inheritance model.
86
+ **/
87
+ makeBridge: function(klass) {
88
+ var bridge = function() {};
89
+ bridge.prototype = klass.prototype;
90
+ return new bridge;
91
+ },
92
+
93
+ /**
94
+ * JS.bind(object, func) -> Function
95
+ * - object (Object): object to bind the function to
96
+ * - func (Function): function that the bound function should call
97
+ *
98
+ * Takes a function and an object, and returns a new function that calls the original
99
+ * function with `this` set to refer to the `object`. Used to implement `JS.Kernel#method`,
100
+ * amongst other things.
101
+ **/
102
+ bind: function() {
103
+ var args = JS.array(arguments),
104
+ method = args.shift(),
105
+ object = args.shift() || null;
106
+
107
+ return function() {
108
+ return method.apply(object, args.concat(JS.array(arguments)));
109
+ };
110
+ },
111
+
112
+ /**
113
+ * JS.callsSuper(func) -> Boolean
114
+ * - func (Function): function to test for super() calls
115
+ *
116
+ * Takes a function and returns `true` iff the function makes a call to `callSuper()`.
117
+ * Result is cached on the function itself since functions are immutable and decompiling
118
+ * them is expensive. We use this to determine whether to wrap the function when it's
119
+ * added to a class; wrapping impedes performance and should be avoided where possible.
120
+ **/
121
+ callsSuper: function(func) {
122
+ return func.SUPER === undefined
123
+ ? func.SUPER = /\bcallSuper\b/.test(func.toString())
124
+ : func.SUPER;
125
+ },
126
+
127
+ /**
128
+ * JS.mask(func) -> Function
129
+ * - func (Function): function to obfuscate
130
+ *
131
+ * Disguises a function so that we cannot tell if it uses `callSuper()`. Sometimes we don't
132
+ * want such functions to be wrapped by the inheritance system. Modifies the function's
133
+ * `toString()` method and returns the function.
134
+ **/
135
+ mask: function(func) {
136
+ var string = func.toString().replace(/callSuper/g, 'super');
137
+ func.toString = function() { return string };
138
+ return func;
139
+ },
140
+
141
+ /**
142
+ * JS.array(iterable) -> Array
143
+ * - iterable (Object): object you want to cast to an array
144
+ *
145
+ * Takes any iterable object (something with a `length` property) and returns a native
146
+ * JavaScript `Array` containing the same elements.
147
+ **/
148
+ array: function(iterable) {
149
+ if (!iterable) return [];
150
+ if (iterable.toArray) return iterable.toArray();
151
+
152
+ var length = iterable.length,
153
+ results = [];
154
+
155
+ while (length--) results[length] = iterable[length];
156
+ return results;
157
+ },
158
+
159
+ /**
160
+ * JS.indexOf(haystack, needle) -> Number
161
+ * - haystack (Array): array to search
162
+ * - needle (Object): object to search for
163
+ *
164
+ * Returns the index of the `needle` in the `haystack`, which is typically an `Array` or an
165
+ * array-like object. Returns -1 if no matching element is found. We need this as older
166
+ * IE versions don't implement `Array#indexOf`.
167
+ **/
168
+ indexOf: function(haystack, needle) {
169
+ for (var i = 0, n = haystack.length; i < n; i++) {
170
+ if (haystack[i] === needle) return i;
171
+ }
172
+ return -1;
173
+ },
174
+
175
+ /**
176
+ * JS.isFn(object) -> Boolean
177
+ * - object (Object): object to test
178
+ *
179
+ * Returns `true` iff the argument is a `Function`.
180
+ **/
181
+ isFn: function(object) {
182
+ return object instanceof Function;
183
+ },
184
+
185
+ /**
186
+ * JS.isType(object, type) -> Boolean
187
+ * - object (Object): object whose type we wish to check
188
+ * - type (JS.Module): type to match against
189
+ *
190
+ * Returns `true` iff `object` is of the given `type`.
191
+ **/
192
+ isType: function(object, type) {
193
+ if (!object || !type) return false;
194
+ return (type instanceof Function && object instanceof type) ||
195
+ (typeof type === 'string' && typeof object === type) ||
196
+ (object.isA && object.isA(type));
197
+ },
198
+
199
+ /**
200
+ * JS.ignore(key, object) -> Boolean
201
+ * - key (String): name of field being added to an object
202
+ * - object (Object): value of the given field
203
+ *
204
+ * Used to determine whether a key-value pair should be added to a class or module. Pairs
205
+ * may be ignored if they have some special function, like `include` or `extend`.
206
+ **/
207
+ ignore: function(key, object) {
208
+ return /^(include|extend)$/.test(key) && typeof object === 'object';
209
+ }
210
+ });
211
+
212
+
213
+ /** section: core
214
+ * class JS.Module
215
+ * includes JS.Kernel
216
+ *
217
+ * `Module` is the core class in JS.Class. A module is simply an object that stores methods,
218
+ * and is responsible for handling method lookups, inheritance relationships and the like.
219
+ * All of Ruby's inheritance semantics are handled using modules in JS.Class.
220
+ *
221
+ * The basic object/module/class model in Ruby is expressed in the diagram at
222
+ * http://ruby-doc.org/core/classes/Class.html -- `Class` inherits from `Module`, which
223
+ * inherits from `Object` (as do all custom classes). `Kernel` is a `Module` which is mixed
224
+ * into `Object` to provide methods common to all objects.
225
+ *
226
+ * In JS.Class, there is no `Object` class, but we do have `Module`, `Class` and `Kernel`.
227
+ * All top-level (parentless) classes include the `JS.Kernel` module, so all classes in effect
228
+ * inherit from `Kernel`. All classes are instances of `JS.Class`, and all modules instances
229
+ * of `JS.Module`. `Module` is a top-level class, from which `Class` inherits.
230
+ *
231
+ * The following diagram shows this relationship; vertical lines indicate parent/child
232
+ * class relationships, horizontal lines indicate module inclusions. (`C`) means a class,
233
+ * (`M`) a module.
234
+ *
235
+ *
236
+ * ============== ============== =================== ==============
237
+ * | M | Kernel |----->| C | Module | | C | ParentClass |<-----| M | Kernel |
238
+ * ============== ============== =================== ==============
239
+ * ^ ^
240
+ * | |
241
+ * | |
242
+ * ============= ==================
243
+ * | C | Class | | C | ChildClass |
244
+ * ============= ==================
245
+ *
246
+ *
247
+ * All objects have a metamodule attached to them; this handles storage of singleton
248
+ * methods as metaclasses do in Ruby. This is handled by mixing the object's class into
249
+ * the object's metamodule.
250
+ *
251
+ *
252
+ * class
253
+ * =================
254
+ * | C | SomeClass |------------------------------------------------
255
+ * ================= |
256
+ * | |
257
+ * V |
258
+ * ==================== ================================= |
259
+ * | <SomeClass:0xb7> |<>----| M | <Module:<SomeClass:0xb7>> |<-----
260
+ * ==================== =================================
261
+ * instance metamodule
262
+ *
263
+ *
264
+ * Similarly, inheritance of class methods is handled by mixing the parent class's
265
+ * metamodule into the child class's metamodule, like so:
266
+ *
267
+ *
268
+ * =================== ============================
269
+ * | C | ParentClass |<>----| M | <Module:ParentClass> |------
270
+ * =================== ============================ |
271
+ * ^ |
272
+ * | |
273
+ * | |
274
+ * =================== =========================== |
275
+ * | C | ChildClass |<>----| M | <Module:ChildClass> |<------
276
+ * =================== ===========================
277
+ *
278
+ *
279
+ * The parent-child relationships are also implemented using module inclusion, with some
280
+ * extra checks and optimisations. Also, bear in mind that although `Class` appears to be a
281
+ * subclass of `Module`, this particular parent-child relationship is faked using manual
282
+ * delegation; every class has a hidden module attached to it that handles all the method
283
+ * storage and lookup responsibilities.
284
+ **/
285
+ JS.Module = JS.makeFunction();
286
+ JS.extend(JS.Module.prototype, {
287
+ END_WITHOUT_DOT: /([^\.])$/,
288
+
289
+ /**
290
+ * new JS.Module(name, methods, options)
291
+ * - name (String): the name of the module, used for debugging
292
+ * - methods (Object): list of methods for the class
293
+ * - options (Object): configuration options
294
+ *
295
+ * The `name` argument is optional and may be omitted; `name` is not used to assign
296
+ * the class to a variable, it is only uses as metadata. The `options` object is used
297
+ * to specify the target object that the module is storing methods for.
298
+ *
299
+ * var Runnable = new JS.Module('Runnable', {
300
+ * run: function(args) {
301
+ * // ...
302
+ * }
303
+ * });
304
+ **/
305
+ initialize: function(name, methods, options) {
306
+ this.__mod__ = this; // Mirror property found in Class. Think of this as toModule()
307
+ this.__inc__ = []; // List of modules included in this module
308
+ this.__fns__ = {}; // Object storing methods belonging to this module
309
+ this.__dep__ = []; // List modules and classes that depend on this module
310
+ this.__mct__ = {}; // Cache table for method call lookups
311
+
312
+ if (typeof name === 'string') {
313
+ this.__nom__ = this.displayName = name;
314
+ } else {
315
+ this.__nom__ = this.displayName = '';
316
+ options = methods;
317
+ methods = name;
318
+ }
319
+
320
+ options = options || {};
321
+
322
+ // Object to resolve methods onto
323
+ this.__res__ = options._resolve || null;
324
+
325
+ if (methods) this.include(methods, false);
326
+
327
+ if (JS.Module.__chainq__) JS.Module.__chainq__.push(this);
328
+ },
329
+
330
+ /**
331
+ * JS.Module#setName(name) -> undefined
332
+ * - name (String): the name for the module
333
+ *
334
+ * Sets the `displayName` of the module to the given value. Should be the fully-qualified
335
+ * name, including names of the containing modules.
336
+ **/
337
+ setName: function(name) {
338
+ this.__nom__ = this.displayName = name || '';
339
+ for (var key in this.__mod__.__fns__)
340
+ this.__name__(key);
341
+ if (name && this.__meta__) this.__meta__.setName(name + '.');
342
+ },
343
+
344
+ /**
345
+ * JS.Module#__name__(name) -> undefined
346
+ * - name (String): the name of the method to assign a `displayName` to
347
+ *
348
+ * Assigns the `displayName` property to the named method using Ruby conventions for naming
349
+ * instance and singleton methods. If the named field points to another `Module`, the name
350
+ * change is applied recursively.
351
+ **/
352
+ __name__: function(name) {
353
+ if (!this.__nom__) return;
354
+ var object = this.__mod__.__fns__[name] || {};
355
+ name = this.__nom__.replace(this.END_WITHOUT_DOT, '$1#') + name;
356
+ if (JS.isFn(object.setName)) return object.setName(name);
357
+ if (JS.isFn(object)) object.displayName = name;
358
+ },
359
+
360
+ /**
361
+ * JS.Module#define(name, func[, resolve = true[, options = {}]]) -> undefined
362
+ * - name (String): the name of the method
363
+ * - func (Function): a function implementing the method
364
+ * - resolve (Boolean): sets whether to refresh method tables afterward
365
+ * - options (Object): execution options
366
+ *
367
+ * Adds an instance method to the module with the given `name`. The `options` parameter is
368
+ * for internal use to make sure callbacks fire on the correct objects, e.g. a class
369
+ * uses a hidden module to store its methods, but callbacks should fire on the class,
370
+ * not the module.
371
+ **/
372
+ define: function(name, func, resolve, options) {
373
+ var notify = (options || {})._notify || this;
374
+ this.__fns__[name] = func;
375
+ this.__name__(name);
376
+ if (JS.Module._notify && notify && JS.isFn(func))
377
+ JS.Module._notify(name, notify);
378
+ if (resolve !== false) this.resolve();
379
+ },
380
+
381
+ /**
382
+ * JS.Module#instanceMethod(name) -> Function
383
+ * - name (String): the name of the method
384
+ *
385
+ * Returns the named instance method from the module as an unbound function.
386
+ **/
387
+ instanceMethod: function(name) {
388
+ var method = this.lookup(name).pop();
389
+ return JS.isFn(method) ? method : null;
390
+ },
391
+
392
+ /**
393
+ * JS.Module#instanceMethods([includeSuper = true[, results]]) -> Array
394
+ * - includeSuper (Boolean): whether to include ancestor methods
395
+ * - results (Array): list of found method names (internal use)
396
+ *
397
+ * Returns an array of all the method names from the module. Pass `false` to ignore methods
398
+ * inherited from ancestors.
399
+ **/
400
+ instanceMethods: function(includeSuper, results) {
401
+ var self = this.__mod__,
402
+ results = results || [],
403
+ ancestors = self.ancestors(),
404
+ n = ancestors.length,
405
+ name;
406
+
407
+ for (name in self.__fns__) {
408
+ if (self.__fns__.hasOwnProperty(name) &&
409
+ JS.isFn(self.__fns__[name]) &&
410
+ JS.indexOf(results, name) === -1)
411
+ results.push(name);
412
+ }
413
+ if (includeSuper === false) return results;
414
+
415
+ while (n--) ancestors[n].instanceMethods(false, results);
416
+ return results;
417
+ },
418
+
419
+ /**
420
+ * JS.Module#include(module[, resolve = true[, options = {}]]) -> undefined
421
+ * - module (JS.Module): the module to mix in
422
+ * - resolve (Boolean): sets whether to refresh method tables afterward
423
+ * - options (Object): flags to control execution
424
+ *
425
+ * Mixes `module` into the receiver or, if `module` is plain old object (rather than a
426
+ * `JS.Module`) adds methods directly into the receiver. The `options` and `resolve` arguments
427
+ * are mostly for internal use; `options` specifies objects that callbacks should fire on,
428
+ * and `resolve` tells the module whether to resolve methods onto its target after adding
429
+ * the methods.
430
+ **/
431
+ include: function(module, resolve, options) {
432
+ resolve = (resolve !== false);
433
+ if (!module) return resolve ? this.resolve() : this.uncache();
434
+ options = options || {};
435
+
436
+ if (module.__mod__) module = module.__mod__;
437
+
438
+ var inc = module.include,
439
+ ext = module.extend,
440
+ includer = options._included || this,
441
+ modules, method, i, n;
442
+
443
+ if (module.__inc__ && module.__fns__) {
444
+ // module is a Module instance: make links and fire callbacks
445
+
446
+ this.__inc__.push(module);
447
+ module.__dep__.push(this);
448
+ if (options._extended) module.extended && module.extended(options._extended);
449
+ else module.included && module.included(includer);
450
+
451
+ } else {
452
+ // module is a normal object: add methods directly to this module
453
+
454
+ if (options._recall) {
455
+ // Second call: add all the methods
456
+ for (method in module) {
457
+ if (JS.ignore(method, module[method])) continue;
458
+ this.define(method, module[method], false, {_notify: includer || options._extended || this});
459
+ }
460
+ } else {
461
+ // First call: handle include and extend blocks
462
+
463
+ // Handle inclusions
464
+ if (typeof inc === 'object' || JS.isType(inc, JS.Module)) {
465
+ modules = [].concat(inc);
466
+ for (i = 0, n = modules.length; i < n; i++)
467
+ includer.include(modules[i], resolve, options);
468
+ }
469
+
470
+ // Handle extensions
471
+ if (typeof ext === 'object' || JS.isType(ext, JS.Module)) {
472
+ modules = [].concat(ext);
473
+ for (i = 0, n = modules.length; i < n; i++)
474
+ includer.extend(modules[i], false);
475
+ includer.extend();
476
+ }
477
+
478
+ // Make a second call to include(). This allows mixins to modify the
479
+ // include() method and affect the addition of methods to this module
480
+ options._recall = true;
481
+ return includer.include(module, resolve, options);
482
+ }
483
+ }
484
+ resolve ? this.resolve() : this.uncache();
485
+ },
486
+
487
+ /**
488
+ * JS.Module#includes(module) -> Boolean
489
+ * - module (JS.Module): a module to check for inclusion
490
+ *
491
+ * Returns `true` iff the receiver includes (i.e. inherits from) the given `module`, or
492
+ * if the receiver and given `module` are the same object. Recurses over the receiver's
493
+ * inheritance tree, could get expensive.
494
+ **/
495
+ includes: function(module) {
496
+ var self = this.__mod__,
497
+ i = self.__inc__.length;
498
+
499
+ if (Object === module || self === module || self.__res__ === module.prototype)
500
+ return true;
501
+
502
+ while (i--) {
503
+ if (self.__inc__[i].includes(module))
504
+ return true;
505
+ }
506
+ return false;
507
+ },
508
+
509
+ /**
510
+ * JS.Module#match(object) -> Boolean
511
+ * - object (Object): object to type-check
512
+ *
513
+ * Returns `true` if the receiver is in the inheritance chain of `object`.
514
+ **/
515
+ match: function(object) {
516
+ return object.isA && object.isA(this);
517
+ },
518
+
519
+ /**
520
+ * JS.Module#ancestors([results]) -> Array
521
+ * - results (Array): list of found ancestors (internal use)
522
+ *
523
+ * Returns an array of the module's ancestor modules/classes, with the most distant
524
+ * first and the receiver last. This is the opposite order to that given by Ruby, but
525
+ * this order makes it easier to eliminate duplicates and preserve Ruby's inheritance
526
+ * semantics with respect to the diamond problem. The `results` parameter is for internal
527
+ * use; we recurse over the tree passing the same array around rather than generating
528
+ * lots of arrays and concatenating.
529
+ **/
530
+ ancestors: function(results) {
531
+ var self = this.__mod__,
532
+ cachable = (results === undefined),
533
+ klass = (self.__res__||{}).klass,
534
+ result = (klass && self.__res__ === klass.prototype) ? klass : self,
535
+ i, n;
536
+
537
+ if (cachable && self.__anc__) return self.__anc__.slice();
538
+ results = results || [];
539
+
540
+ // Recurse over inclusions first
541
+ for (i = 0, n = self.__inc__.length; i < n; i++)
542
+ self.__inc__[i].ancestors(results);
543
+
544
+ // If this module is not already in the list, add it
545
+ if (JS.indexOf(results, result) === -1) results.push(result);
546
+
547
+ if (cachable) self.__anc__ = results.slice();
548
+ return results;
549
+ },
550
+
551
+ /**
552
+ * JS.Module#lookup(name) -> Array
553
+ * - name (String): the name of the method to search for
554
+ *
555
+ * Returns an array of all the methods in the module's inheritance tree with the given
556
+ * `name`. Methods are returned in the same order as the modules in `JS.Module#ancestors`,
557
+ * so the last method in the list will be called first, the penultimate on the first
558
+ * `callSuper()`, and so on back through the list.
559
+ **/
560
+ lookup: function(name) {
561
+ var self = this.__mod__,
562
+ cache = self.__mct__;
563
+
564
+ if (cache[name]) return cache[name].slice();
565
+
566
+ var ancestors = self.ancestors(),
567
+ results = [],
568
+ i, n, method;
569
+
570
+ for (i = 0, n = ancestors.length; i < n; i++) {
571
+ method = ancestors[i].__mod__.__fns__[name];
572
+ if (method) results.push(method);
573
+ }
574
+ cache[name] = results.slice();
575
+ return results;
576
+ },
577
+
578
+ /**
579
+ * JS.Module#make(name, func) -> Function
580
+ * - name (String): the name of the method being produced
581
+ * - func (Function): a function implementing the method
582
+ *
583
+ * Returns a version of the function ready to be added to a prototype object. Functions
584
+ * that use `callSuper()` must be wrapped to support that behaviour, other functions can
585
+ * be used raw.
586
+ **/
587
+ make: function(name, func) {
588
+ if (!JS.isFn(func) || !JS.callsSuper(func)) return func;
589
+ var module = this;
590
+ return function() {
591
+ return module.chain(this, name, arguments);
592
+ };
593
+ },
594
+
595
+ /**
596
+ * JS.Module#chain(self, name, args) -> Object
597
+ * - self (Object): the receiver of the call
598
+ * - name (String): the name of the method being called
599
+ * - args (Array): list of arguments to begin the call
600
+ *
601
+ * Performs calls to functions that use `callSuper()`. Ancestor methods are looked up
602
+ * dynamically at call-time; this allows `callSuper()` to be late-bound as in Ruby at the
603
+ * cost of a little performance. Arguments to the call are stored so they can be passed
604
+ * up the call stack automatically without the developer needing to pass them by hand.
605
+ **/
606
+ chain: JS.mask( function(self, name, args) {
607
+ var callees = this.lookup(name), // List of method implementations
608
+ stackIndex = callees.length - 1, // Current position in the call stack
609
+ currentSuper = self.callSuper, // Current super method attached to the receiver
610
+ params = JS.array(args), // Copy of argument list
611
+ result;
612
+
613
+ // Set up the callSuper() method
614
+ self.callSuper = function() {
615
+
616
+ // Overwrite arguments specified explicitly
617
+ var i = arguments.length;
618
+ while (i--) params[i] = arguments[i];
619
+
620
+ // Step up the stack, call and step back down
621
+ stackIndex -= 1;
622
+ var returnValue = callees[stackIndex].apply(self, params);
623
+ stackIndex += 1;
624
+
625
+ return returnValue;
626
+ };
627
+
628
+ // Call the last method in the stack
629
+ result = callees.pop().apply(self, params);
630
+
631
+ // Remove or reassign callSuper() method
632
+ currentSuper ? self.callSuper = currentSuper : delete self.callSuper;
633
+
634
+ return result;
635
+ } ),
636
+
637
+ /**
638
+ * JS.Module#resolve([target = this]) -> undefined
639
+ * - target (Object): the object to reflect methods onto
640
+ *
641
+ * Copies methods from the module onto the `target` object, wrapping methods where
642
+ * necessary. The target will typically be a native JavaScript prototype object used
643
+ * to represent a class. Recurses over this module's ancestors to make sure all applicable
644
+ * methods exist.
645
+ **/
646
+ resolve: function(target) {
647
+ var self = this.__mod__,
648
+ target = target || self,
649
+ resolved = target.__res__, i, n, key, made;
650
+
651
+ // Resolve all dependent modules if the target is this module
652
+ if (target === self) {
653
+ self.uncache(false);
654
+ i = self.__dep__.length;
655
+ while (i--) self.__dep__[i].resolve();
656
+ }
657
+
658
+ if (!resolved) return;
659
+
660
+ // Recurse over this module's ancestors
661
+ for (i = 0, n = self.__inc__.length; i < n; i++)
662
+ self.__inc__[i].resolve(target);
663
+
664
+ // Wrap and copy methods to the target
665
+ for (key in self.__fns__) {
666
+ made = target.make(key, self.__fns__[key]);
667
+ if (resolved[key] !== made) resolved[key] = made;
668
+ }
669
+ },
670
+
671
+ /**
672
+ * JS.Module#uncache([recursive = true]) -> undefined
673
+ * - recursive (Boolean): whether to clear the cache of all dependent modules
674
+ *
675
+ * Clears the ancestor and method table cahces for the module. This is used to invalidate
676
+ * caches when modules are modified, to avoid some of the bugs that exist in Ruby.
677
+ **/
678
+ uncache: function(recursive) {
679
+ var self = this.__mod__,
680
+ i = self.__dep__.length;
681
+
682
+ self.__anc__ = null;
683
+ self.__mct__ = {};
684
+ if (recursive === false) return;
685
+ while (i--) self.__dep__[i].uncache();
686
+ }
687
+ });
688
+
689
+
690
+ /** section: core
691
+ * class JS.Class < JS.Module
692
+ *
693
+ * `Class` is a subclass of `JS.Module`; classes not only store methods but also spawn
694
+ * new objects. In addition, classes have an extra type of inheritance on top of mixins,
695
+ * in that each class can have a single parent class from which it will inherit both
696
+ * instance and singleton methods.
697
+ *
698
+ * Refer to `JS.Module` for details of how inheritance is implemented in JS.Class. Though
699
+ * `Class` is supposed to appear to be a subclass of `Module`, this relationship is
700
+ * implemented by letting each `Class` hold a reference to an anonymous `Module` and
701
+ * using manual delegation where necessary.
702
+ **/
703
+ JS.Class = JS.makeFunction();
704
+ JS.extend(JS.Class.prototype = JS.makeBridge(JS.Module), {
705
+
706
+ /**
707
+ * new JS.Class(name, parent, methods)
708
+ * - name (String): the name of the class, used for debugging
709
+ * - parent (JS.Class): the parent class to inherit from
710
+ * - methods (Object): list of methods for the class
711
+ *
712
+ * The `name` and `parent` arguments are both optional and may be omitted. `name`
713
+ * is not used to assign the class to a variable, it is only uses as metadata.
714
+ * The default parent class is `Object`, and all classes include the JS.Kernel
715
+ * module.
716
+ **/
717
+ initialize: function(name, parent, methods) {
718
+ if (typeof name === 'string') {
719
+ this.__nom__ = this.displayName = name;
720
+ } else {
721
+ this.__nom__ = this.displayName = '';
722
+ methods = parent;
723
+ parent = name;
724
+ }
725
+ var klass = JS.extend(JS.makeFunction(), this);
726
+ klass.klass = klass.constructor = this.klass;
727
+
728
+ if (!JS.isFn(parent)) {
729
+ methods = parent;
730
+ parent = Object;
731
+ }
732
+
733
+ // Set up parent-child relationship, then add methods. Setting up a parent
734
+ // class in JavaScript wipes the existing prototype object.
735
+ klass.inherit(parent);
736
+ klass.include(methods, false);
737
+ klass.resolve();
738
+
739
+ // Fire inherited() callback on ancestors
740
+ do {
741
+ parent.inherited && parent.inherited(klass);
742
+ } while (parent = parent.superclass);
743
+
744
+ return klass;
745
+ },
746
+
747
+ /**
748
+ * JS.Class#inherit(klass) -> undefined
749
+ * - klass (JS.Class): the class to inherit from
750
+ *
751
+ * Sets up the parent-child relationship to the parent class. This is a destructive action
752
+ * in that the existing prototype will be discarded; always call this before adding any
753
+ * methods to the class.
754
+ **/
755
+ inherit: function(klass) {
756
+ this.superclass = klass;
757
+
758
+ // Mix the parent's metamodule into this class's metamodule
759
+ if (this.__eigen__ && klass.__eigen__) this.extend(klass.__eigen__(), true);
760
+
761
+ this.subclasses = [];
762
+ (klass.subclasses || []).push(this);
763
+
764
+ // Bootstrap JavaScript's prototypal inheritance model
765
+ var p = this.prototype = JS.makeBridge(klass);
766
+ p.klass = p.constructor = this;
767
+
768
+ // Set up a module to store methods and delegate calls to
769
+ // -- Class does not really subclass Module, instead each
770
+ // Class has a Module that it delegates to
771
+ this.__mod__ = new JS.Module(this.__nom__, {}, {_resolve: this.prototype});
772
+ this.include(JS.Kernel, false);
773
+
774
+ if (klass !== Object) this.include(klass.__mod__ || new JS.Module(klass.prototype,
775
+ {_resolve: klass.prototype}), false);
776
+ },
777
+
778
+ /**
779
+ * JS.Class#include(module[, resolve = true[, options = {}]]) -> undefined
780
+ * - module (JS.Module): the module to mix in
781
+ * - resolve (Boolean): sets whether to refresh method tables afterward
782
+ * - options (Object): flags to control execution
783
+ *
784
+ * Mixes a `module` into the class if it's a `JS.Module` instance, or adds instance
785
+ * methods to the class itself if given a plain old object. Overrides `JS.Module#include`
786
+ * to make sure callbacks fire on the class rather than its delegating module.
787
+ **/
788
+ include: function(module, resolve, options) {
789
+ if (!module) return;
790
+
791
+ var mod = this.__mod__,
792
+ options = options || {};
793
+
794
+ options._included = this;
795
+ return mod.include(module, resolve, options);
796
+ },
797
+
798
+ /**
799
+ * JS.Class#define(name, func[, resolve = true[, options = {}]]) -> undefined
800
+ * - name (String): the name of the method
801
+ * - func (Function): a function to implement the method
802
+ * - resolve (Boolean): sets whether to refresh method tables afterward
803
+ * - options (Object): options for internal use
804
+ *
805
+ * Adds an instance method to the class with the given `name`. The `options` parameter is
806
+ * for internal use to make sure callbacks fire on the correct objects, e.g. a class
807
+ * uses a hidden module to store its methods, but callbacks should fire on the class,
808
+ * not the module.
809
+ **/
810
+ define: function(name, func, resolve, options) {
811
+ var module = this.__mod__;
812
+ options = options || {};
813
+ options._notify = this;
814
+ module.define(name, func, resolve, options);
815
+ }
816
+ });
817
+
818
+
819
+ // This file bootstraps the framework by redefining Module and Class using their
820
+ // own prototypes and mixing in methods from Kernel, making these classes appear
821
+ // to be instances of themselves.
822
+
823
+ JS.Module = new JS.Class('Module', JS.Module.prototype);
824
+ JS.Class = new JS.Class('Class', JS.Module, JS.Class.prototype);
825
+ JS.Module.klass = JS.Module.constructor =
826
+ JS.Class.klass = JS.Class.constructor = JS.Class;
827
+
828
+ JS.extend(JS.Module, {
829
+ _observers: [],
830
+
831
+ __chainq__: [],
832
+
833
+ methodAdded: function(block, context) {
834
+ this._observers.push([block, context]);
835
+ },
836
+
837
+ _notify: function(name, object) {
838
+ var obs = this._observers, i = obs.length;
839
+ while (i--) obs[i][0].call(obs[i][1] || null, name, object);
840
+ }
841
+ });
842
+
843
+
844
+ /** section: core
845
+ * mixin JS.Kernel
846
+ *
847
+ * `Kernel` is the base module; all classes include the `Kernel`, so its methods become
848
+ * available to all objects instantiated by JS.Class. As in Ruby, the core `Object`
849
+ * methods are implemented here rather than in the base `Object` class. JS.Class does
850
+ * not in fact have an `Object` class and does not modify the builtin JavaScript `Object`
851
+ * class either.
852
+ **/
853
+ JS.Kernel = JS.extend(new JS.Module('Kernel', {
854
+ /**
855
+ * JS.Kernel#__eigen__() -> JS.Module
856
+ *
857
+ * Returns the object's metamodule, analogous to calling `(class << self; self; end)`
858
+ * in Ruby. Ruby's metaclasses are `Class`es, not just `Module`s, but so far I've not found
859
+ * a compelling reason to enforce this. You cannot instantiate or subclass metaclasses
860
+ * in Ruby, they only really exist to store methods so a module will suffice.
861
+ **/
862
+ __eigen__: function() {
863
+ if (this.__meta__) return this.__meta__;
864
+
865
+ var me = this.__nom__,
866
+ klass = this.klass.__nom__,
867
+ name = me || (klass ? '#<' + klass + '>' : ''),
868
+ module = this.__meta__ = new JS.Module(name ? name + '.' : '', {}, {_resolve: this});
869
+
870
+ module.include(this.klass.__mod__, false);
871
+ return module;
872
+ },
873
+
874
+ /**
875
+ * JS.Kernel#equals(object) -> Boolean
876
+ * - object (Object): object to compare to the receiver
877
+ *
878
+ * Returns `true` iff `object` is the same object as the receiver. Override to provide a
879
+ * more meaningful comparison for use in sets, hashtables etc.
880
+ **/
881
+ equals: function(object) {
882
+ return this === object;
883
+ },
884
+
885
+ /**
886
+ * JS.Kernel#extend(module[, resolve = true]) -> undefined
887
+ * - module (JS.Module): module with which to extend the object
888
+ * - resolve (Boolean): whether to refresh method tables afterward
889
+ *
890
+ * Extends the object using the methods from `module`. If `module` is an instance of
891
+ * `JS.Module`, it becomes part of the object's inheritance chain and any methods added
892
+ * directly to the object will take precedence. Pass `false` as a second argument
893
+ * to prevent the method resolution process from firing.
894
+ **/
895
+ extend: function(module, resolve) {
896
+ return this.__eigen__().include(module, resolve, {_extended: this});
897
+ },
898
+
899
+ /**
900
+ * JS.Kernel#hash() -> String
901
+ *
902
+ * Returns a hexadecimal hashcode for the object for use in hashtables. By default,
903
+ * this is a random number guaranteed to be unique to the object. If you override
904
+ * this method, make sure that `a.equals(b)` implies `a.hash() === b.hash()`.
905
+ **/
906
+ hash: function() {
907
+ return this.__hashcode__ = this.__hashcode__ || JS.Kernel.getHashCode();
908
+ },
909
+
910
+ /**
911
+ * JS.Kernel#isA(type) -> Boolean
912
+ * - type (JS.Module): module or class to check the object's type against
913
+ *
914
+ * Returns `true` iff the object is an instance of `type` or one of its
915
+ * subclasses, or if the object's class includes the module `type`.
916
+ **/
917
+ isA: function(moduleOrClass) {
918
+ return this.__eigen__().includes(moduleOrClass);
919
+ },
920
+
921
+ /**
922
+ * JS.Kernel#method(name) -> Function
923
+ * - name (String): the name of the required method
924
+ *
925
+ * Returns the named method from the object as a bound function.
926
+ **/
927
+ method: function(name) {
928
+ var self = this,
929
+ cache = self.__mcache__ = self.__mcache__ || {};
930
+
931
+ if ((cache[name] || {}).fn === self[name]) return cache[name].bd;
932
+ return (cache[name] = {fn: self[name], bd: JS.bind(self[name], self)}).bd;
933
+ },
934
+
935
+ /**
936
+ * JS.Kernel#methods() -> Array
937
+ *
938
+ * Returns a list of all the method names defined on the object.
939
+ **/
940
+ methods: function() {
941
+ return this.__eigen__().instanceMethods(true);
942
+ },
943
+
944
+ /**
945
+ * JS.Kernel#tap(block[, context]) -> this
946
+ * - block (Function): block of code to execute
947
+ * - context (Object): sets the binding of `this` within `block`
948
+ *
949
+ * Executes the given function passing the object as a parameter, and returns the
950
+ * object rather than the result of the function. Designed to 'tap into' a method
951
+ * chain to inspect intermediate values. From the Ruby docs:
952
+ *
953
+ * list .tap(function(x) { console.log("original: ", x) })
954
+ * .toArray() .tap(function(x) { console.log("array: ", x) })
955
+ * .select(condition) .tap(function(x) { console.log("evens: ", x) })
956
+ * .map(square) .tap(function(x) { console.log("squares: ", x) })
957
+ **/
958
+ tap: function(block, context) {
959
+ block.call(context || null, this);
960
+ return this;
961
+ }
962
+ }),
963
+
964
+ {
965
+ __hashIndex__: 0,
966
+
967
+ getHashCode: function() {
968
+ this.__hashIndex__ += 1;
969
+ return (Math.floor(new Date().getTime() / 1000) + this.__hashIndex__).toString(16);
970
+ }
971
+ });
972
+
973
+ JS.Module.include(JS.Kernel);
974
+ JS.extend(JS.Module, JS.Kernel.__fns__);
975
+ JS.Class.include(JS.Kernel);
976
+ JS.extend(JS.Class, JS.Kernel.__fns__);
977
+
978
+
979
+ /** section: core
980
+ * class JS.Interface
981
+ *
982
+ * `Interface` is a class used to encapsulate sets of methods and check whether objects
983
+ * implement them. Think of interfaces as a means of duck-typing rather than as they are
984
+ * used in Java.
985
+ **/
986
+ JS.Interface = new JS.Class({
987
+ /**
988
+ * new JS.Interface(methods)
989
+ * - methods (Array): a list of method names
990
+ *
991
+ * An `Interface` is instantiated using a list of method names; these methods are the
992
+ * API the interface can be used to check for.
993
+ *
994
+ * var HistoryInterface = new JS.Interface([
995
+ * 'getInitialState',
996
+ * 'changeState'
997
+ * ]);
998
+ **/
999
+ initialize: function(methods) {
1000
+ this.test = function(object, returnName) {
1001
+ var n = methods.length;
1002
+ while (n--) {
1003
+ if (!JS.isFn(object[methods[n]]))
1004
+ return returnName ? methods[n] : false;
1005
+ }
1006
+ return true;
1007
+ };
1008
+ },
1009
+
1010
+ /**
1011
+ * JS.Interface#test(object[, returnName = false]) -> Boolean | String
1012
+ * - object (Object): object whose API we wish to check
1013
+ * - returnName (Boolean): if true, return the first name found to be missing
1014
+ *
1015
+ * Checks whether `object` implements the interface, returning `true` or `false`. If
1016
+ * the second argument is `true`, returns the name of the first method found to be
1017
+ * missing from the object's API.
1018
+ **/
1019
+
1020
+ extend: {
1021
+ /**
1022
+ * JS.Interface.ensure(object, iface1[, iface2]) -> undefined
1023
+ * - object (Object): object whose API we wish to check
1024
+ * - iface (JS.Interface): interface the object should implement
1025
+ *
1026
+ * Throws an `Error` unless `object` implements the required interface(s).
1027
+ **/
1028
+ ensure: function() {
1029
+ var args = JS.array(arguments), object = args.shift(), face, result;
1030
+ while (face = args.shift()) {
1031
+ result = face.test(object, true);
1032
+ if (result !== true) throw new Error('object does not implement ' + result + '()');
1033
+ }
1034
+ }
1035
+ }
1036
+ });
1037
+
1038
+
1039
+ /** section: core
1040
+ * class JS.Singleton
1041
+ *
1042
+ * `Singleton` is a class used to construct custom objects with all the inheritance features
1043
+ * of `JS.Class`, the methods from `JS.Kernel`, etc. It constructs an anonymous class from the
1044
+ * objects you provide and returns an instance of this class.
1045
+ **/
1046
+ JS.Singleton = new JS.Class({
1047
+ /**
1048
+ * new JS.Singleton(name, parent, methods)
1049
+ * - name (String): the name of the singleton, used for debugging
1050
+ * - parent (JS.Class): the parent class to inherit from
1051
+ * - methods (Object): list of methods for the singleton
1052
+ *
1053
+ * `Singleton`s are instantiated the same way as instances of `JS.Class`, the only difference
1054
+ * being that `Singleton` returns an instance of the newly created class, rather than the
1055
+ * class itself.
1056
+ **/
1057
+ initialize: function(name, parent, methods) {
1058
+ return new (new JS.Class(name, parent, methods));
1059
+ }
1060
+ });