rails_jskit 5.0.2 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a15f3760d8c6e81a5ac1c0ffd2344c9201881cf3
4
- data.tar.gz: 38b50b8168b5e20d38023fb5686dde1c08727ffa
3
+ metadata.gz: 240307149b562d4e71edf1aefeafcb18dcffd2f9
4
+ data.tar.gz: 5db7168702b8598eed85b76d16cd4fe7d57cf781
5
5
  SHA512:
6
- metadata.gz: 3d926442464ed5aad88ec72dc60396491dddc28ba3410ea5394560c996b98bec35770a99a9c39ea671f7b3ed6d846feeb1175e2a9c6c7135d73ff78369ae93ee
7
- data.tar.gz: db51a062072c0768ec026976656c3e6ec30bc072442d375a59d3b1e1b9a576ad79092a007f7eae312d75fb6d71012508c9abf8d167826c982f7c7e79c873e4fe
6
+ metadata.gz: e2de89050713116fbaad34b612b5193b810944c758a6fb9b14664da23e251a029e5238e5a12709d2c5a005902aa43714be804eccbd215d81949a9400ebf361ff
7
+ data.tar.gz: 94f6f5ddf9910a6a8632bb10ae9fb93963cc6807b236258f64b62db454105ab4f04dc457d604d079a57a4cae3d520b0f8e6d6b672658f70fc99de2c91339f68e
data/README.md CHANGED
@@ -107,7 +107,7 @@ Documentation
107
107
 
108
108
  ### Application Object
109
109
 
110
- RailsJskit will automatically create a JSkit application object for you, using the configured `app_namespace` for the global variable name _(defaults to "App")_. This global namespace provides you a way to interact with your JSkit application. You can #{link_to "configure", "#configuration"} this setting in your initializer `(config/initializers/rails_jskit.rb)`.
110
+ RailsJskit will automatically create a JSkit application object for you, using the configured `app_namespace` for the global variable name _(defaults to "App")_. This global namespace provides you a way to interact with your JSkit application. You can [configure](#configuration) this setting in your initializer `(config/initializers/rails_jskit.rb)`.
111
111
 
112
112
  #### Dispatcher
113
113
 
@@ -472,7 +472,7 @@ Testing
472
472
 
473
473
  One of the main advantages of RailsJSkit is that it provides a simple structure that's easily tested. There are however, a few things you need to keep in mind while testing JSkit controllers.
474
474
 
475
- When testing, it's important to use the #{link_to "Controller Factories", "#controller-factories"} to create your test subjects. This ensures that you always have a fresh version of the controller that has not been mutated by previous tests. A basic jasmine/mocha style JSkit controller test looks something like this:
475
+ When testing, it's important to use the [Controller Factories](#controller-factories) to create your test subjects. This ensures that you always have a fresh version of the controller that has not been mutated by previous tests. A basic jasmine/mocha style JSkit controller test looks something like this:
476
476
 
477
477
  ```js
478
478
  // spec/javscripts/controllers/posts_controller_spec.js
@@ -6,7 +6,6 @@
6
6
  */
7
7
  var JSkit = (function() {
8
8
  if (!_) throw new Error("JSkit: lodash or underscore is required");
9
- if (!$) throw new Error("JSkit: jQuery or equivalent is required");
10
9
 
11
10
  return {
12
11
  /**
@@ -27,8 +26,8 @@ var JSkit = (function() {
27
26
  * @class Dispatcher
28
27
  */
29
28
  JSkit.Dispatcher = (function() {
30
- var contains = _.contains;
31
- var pluck = _.pluck;
29
+ var any = _.any;
30
+ var each = _.each;
32
31
 
33
32
  /**
34
33
  Get all handler functions for a given dispatcher and event.
@@ -69,7 +68,7 @@ JSkit.Dispatcher = (function() {
69
68
  */
70
69
  function registerHandler(registeredHandlers, eventHandler, method) {
71
70
  method = method || "push";
72
- if (!contains(pluck(registeredHandlers, "handler"), eventHandler.handler)) {
71
+ if (!any(registeredHandlers, eventHandler)) {
73
72
  registeredHandlers[method](eventHandler);
74
73
  }
75
74
  }
@@ -146,7 +145,7 @@ JSkit.Dispatcher = (function() {
146
145
  var eventHhandlers = this.__events__[eventName] || [];
147
146
  var args = _.rest(arguments);
148
147
 
149
- _.each(eventHhandlers, function(eventHandler) {
148
+ each(eventHhandlers, function(eventHandler) {
150
149
  var handler = eventHandler.handler;
151
150
  var context = eventHandler.context;
152
151
  handler.apply(context, args);
@@ -157,301 +156,228 @@ JSkit.Dispatcher = (function() {
157
156
  };
158
157
  })();
159
158
 
160
- /**
161
- * @module JSkit
162
- * @class Controller
163
- */
164
159
  JSkit.Controller = (function() {
160
+ var bind = _.bind;
165
161
  var bindAll = _.bindAll;
162
+ var cloneDeep = _.cloneDeep;
166
163
  var compact = _.compact;
167
164
  var defaults = _.defaults;
168
165
  var each = _.each;
166
+ var extend = _.extend;
169
167
  var first = _.first;
170
168
  var flatten = _.flatten;
171
- var functions = _.functions;
172
- var isFunc = _.isFunction;
169
+ var includes = _.includes;
170
+ var isArray = _.isArray;
171
+ var isFunction = _.isFunction;
173
172
  var isObject = _.isObject;
174
173
  var keys = _.keys;
175
174
  var last = _.last;
176
175
  var map = _.map;
177
- var pairs = _.pairs;
178
176
  var reduce = _.reduce;
179
- var uniq = _.uniq;
180
- var values = _.values;
177
+ var underscore = _.snakeCase;
178
+
179
+ function restrictKeywords(attrs) {
180
+ var keywords = [
181
+ "registerEvents",
182
+ "registerActions",
183
+ "cacheElements",
184
+ "eventNameForAction"
185
+ ];
186
+
187
+ each(keys(attrs), function(keyword) {
188
+ if (includes(keywords, keyword)) {
189
+ throw new Error("JSkit.Controller.create: " + keyword + " is a restricted keyword");
190
+ }
191
+ });
192
+ }
181
193
 
182
- /**
183
- * Take a string and put underscores between names and delimiters
184
- *
185
- * @private
186
- * @method constantize
187
- * @param {String} string
188
- * @return {String}
189
- */
190
- function underscore(string) {
191
- string = string || "";
192
- return string.replace(/([A-Z])/g, " $1").replace(/^\s?/, "").replace(/-|\s/g, "_").toLowerCase();
194
+ function eventNameForAction(controller, action) {
195
+ return compact([
196
+ controller.namespace,
197
+ controller.channel,
198
+ controller.controllerEventName,
199
+ action
200
+ ]).join(controller.eventSeparator);
193
201
  }
194
202
 
195
- /**
196
- * Register the controller's actions to the dispatcher
197
- *
198
- * @private
199
- * @method registerActions
200
- * @param {Controller} controller
201
- */
202
- function registerActions(controller) {
203
- each(controller.actions, function(action) {
204
- each(mapAction(action), function(actionMap) {
205
- ensureActionIsDefined(controller, actionMap);
206
- controller.dispatcher.on(actionEventName(controller, actionMap.name), controller[actionMap.method], controller);
207
- }, controller);
208
- }, controller);
203
+ function registerAllAction(controller) {
204
+ if (!includes(controller.actions, "all")) controller.actions.unshift("all");
209
205
  }
210
206
 
211
- /**
212
- * Take an action string or mapped action and return
213
- * an object containing the action name and method.
214
- *
215
- * @private
216
- * @method mapAction
217
- * @param {String,Object} action/mappedAction
218
- * @return {Array} action/event maps
219
- */
220
- function mapAction(action) {
221
- return isObject(action) ? map(action, createActionMap) : [createActionMap(action, action)];
207
+ function normalizeActions(controller) {
208
+ controller.__actions__ = flatten(map(controller.actions, function(action) {
209
+ return normalizeAction(action);
210
+ }));
222
211
  }
223
212
 
224
- /**
225
- * Create a list of maps of action name/method pairs.
226
- *
227
- * @private
228
- * @method createActionMap
229
- * @param {String} method to map to action
230
- * @param {String} action to map to method
231
- */
232
- function createActionMap(method, action) {
233
- return { name: action, method: method };
213
+ function normalizeAction(action) {
214
+ return isObject(action) ? map(action, createActionObject) : [createActionObject(action, action)];
234
215
  }
235
216
 
236
- /**
237
- * Take a controller and an actionMap and determine if
238
- * the action is defined on the controller. If not, throw
239
- * an error.
240
- *
241
- * @private
242
- * @method ensureActionIsDefined
243
- * @param {Controller} controller
244
- * @param {Object} actionMap
245
- */
246
- function ensureActionIsDefined(controller, actionMap) {
247
- if (!isFunc(controller[actionMap.method])) {
248
- throw new Error(controller.name + ' action "' + actionMap.name + ":" + actionMap.method + '" method is undefined');
217
+ function createActionObject(method, name) {
218
+ return { name: name, method: method };
219
+ }
220
+
221
+ function ensureActionIsDefined(controller, action) {
222
+ if (!isFunction(controller[action.method])) {
223
+ throw new Error(controller.name + ' action "' + action.name + ":" + action.method + '" method is undefined');
249
224
  }
250
225
  }
251
226
 
252
- /**
253
- * Return an event name based on the controller properties
254
- * that make up an event name.
255
- *
256
- * @private
257
- * @method actionEventName
258
- * @param {Controller} controller
259
- * @param {String} action
260
- * @return String
261
- */
262
- function actionEventName(controller, action) {
263
- return compact([
264
- controller.namespace,
265
- controller.channel,
266
- controller.controllerEventName,
267
- action
268
- ]).join(controller.eventSeparator);
227
+ function registerActions(controller) {
228
+ each(controller.__actions__, function(action) {
229
+ ensureActionIsDefined(controller, action);
230
+ controller.dispatcher.on(eventNameForAction(controller, action.name), controller[action.method], controller);
231
+ });
232
+ }
233
+
234
+ function normalizeControllerElements(controller) {
235
+ controller.__elements__ = reduce(controller.elements, function(memo, elements, action) {
236
+ memo[action] = normalizeElements(elements);
237
+ return memo;
238
+ }, {});
239
+ }
240
+
241
+ function normalizeElements(elements) {
242
+ return reduce(elements, function(memo, selector, name) {
243
+ if (_.isArray(selector)) selector = first(selector);
244
+ memo[name] = selector;
245
+ return memo;
246
+ }, {});
247
+ }
248
+
249
+ function normalizeControllerEvents(controller) {
250
+ controller.__events__ = reduce(controller.elements, function(memo, elements, action) {
251
+ memo[action] = normalizeEvents(elements);
252
+ return memo;
253
+ }, {});
254
+ }
255
+
256
+ function normalizeEvents(elements) {
257
+ return reduce(elements, function(memo, selector, name) {
258
+ if (_.isArray(selector)) memo["$" + name] = last(selector);
259
+
260
+ return memo;
261
+ }, {});
262
+ }
263
+
264
+ function isMappedAction(action) {
265
+ return action.name != action.method;
266
+ }
267
+
268
+ function nativeFind(selector) {
269
+ return document.querySelectorAll(selector);
270
+ }
271
+
272
+ function findInDOM(selector) {
273
+ var finder = $ ? $ : nativeFind;
274
+ return finder(selector);
269
275
  }
270
276
 
271
- /**
272
- * Iterate over the given controller's elements object
273
- * and cache a reference to each selected element.
274
- *
275
- * @private
276
- * @method cacheElements
277
- * @param {Controller} controller
278
- * @param {String} action
279
- */
280
277
  function cacheElements(controller, action) {
281
- if (reduceElements(controller.elements, first)[action]) {
282
- each(reduceElements(controller.elements, first)[action], function(selector, name) {
283
- controller["$" + name] = $(selector);
284
- }, controller);
278
+ if (!action) throw new Error("JSkit.Controller.cacheElements: action is undefined");
279
+
280
+ var actionElements = controller.__elements__[action];
281
+
282
+ if (actionElements) {
283
+ each(actionElements, function(selector, name) {
284
+ var element = controller["$" + name] = findInDOM(selector);
285
+
286
+ if (!element.length) {
287
+ throw new Error("JSkit.Controller.cacheElements: " + selector + " is not in the DOM");
288
+ }
289
+ });
285
290
  }
286
291
  }
287
292
 
288
- /**
289
- * Iterate over the given action's events and register
290
- * the event handlers on each element.
291
- *
292
- * @private
293
- * @method registerEvents
294
- * @param {Controller} controller
295
- * @param {String} action
296
- */
297
- function registerEvents(controller, action) {
298
- if (reduceElements(controller.elements, last)[action]) {
299
- each(reduceElements(controller.elements, last)[action], function(eventMap, element) {
300
- each(eventMap, function(method, evnt) {
301
- var handler = controller[method];
302
- var $element = controller["$" + element];
303
- $element.on(evnt, handler);
304
- }, controller);
305
- }, controller);
306
- }
293
+ function decorateCacheElements(controller) {
294
+ controller.cacheElements = function(action) {
295
+ return cacheElements(controller, action);
296
+ };
307
297
  }
308
298
 
309
- /**
310
- * Iterate over the controller's elements
311
- * and register to cache each action's events.
312
- *
313
- * @private
314
- * @method registerElementCaching
315
- * @param {Controller} controller
316
- */
317
- function registerElementCaching(controller) {
318
- each(reduceElements(controller.elements, first), function(elements, action) {
319
- controller.dispatcher.before(actionEventName(controller, action), function() {
320
- cacheElements(controller, action);
321
- }, controller);
322
- }, controller);
299
+ function registerActionEvents(controller, action) {
300
+ each(controller.__events__[action], function(events, element) {
301
+ if (!controller[element]) cacheElements(controller, action);
302
+ registerElementEvents(controller, element, events);
303
+ });
323
304
  }
324
305
 
325
- /**
326
- * Iterate over the controller's events
327
- * and register to handle each action's element events.
328
- *
329
- * @private
330
- * @method registerControllerEvents
331
- * @param {Controller} controller
332
- */
333
- function registerControllerEvents(controller) {
334
- each(reduceElements(controller.elements, last), function(eventMap, action) {
335
- controller.dispatcher.on(actionEventName(controller, action), function() {
336
- registerEvents(controller, action);
337
- }, controller);
338
- }, controller);
306
+ function registerElementEvents(controller, element, events) {
307
+ var eventsBinder = bind(eventsBinderFor(events), controller);
308
+ var on = bind($.prototype.on, controller[element]);
309
+ eventsBinder(on);
339
310
  }
340
311
 
341
- /**
342
- * Reduce the controller's elements object into an object
343
- * that only contains either the elements to cache or the
344
- * events to register to that element.
345
- *
346
- * @private
347
- *
348
- * @method reduceElements
349
- * @param {Object} controller's elements object
350
- * @param {Function} function to grab either head or tail (first, last)
351
- * @return {Object}
352
- */
353
- function reduceElements(elements, accessMethod) {
354
- return reduce(elements, function(memo, value, key) {
355
- memo[key] = {};
356
- each(value, function(v, k) {
357
- memo[key][k] = accessMethod(flatten([v]));
312
+ function eventsBinderFor(events) {
313
+ if(events instanceof Function) {
314
+ return events;
315
+ }
316
+
317
+ return function(on) {
318
+ var controller = this;
319
+ each(events, function(handler, evnt) {
320
+ on(evnt, controller[handler]);
358
321
  });
359
- return memo;
360
- }, {});
322
+ };
323
+ }
324
+
325
+ function decorateRegisterEvents(controller) {
326
+ controller.registerEvents = function(action) {
327
+ return registerActionEvents(controller, action);
328
+ };
329
+ }
330
+
331
+ function registerCacheElementsForActions(controller) {
332
+ each(controller.__actions__, function(action) {
333
+ var eventName = eventNameForAction(controller, action.name);
334
+ controller.dispatcher.before(eventName, function() {
335
+ return cacheElements(controller, action.name);
336
+ })
337
+ });
338
+ }
339
+
340
+ function registerControllerElementEvents(controller) {
341
+ each(controller.__actions__, function(action) {
342
+ registerActionEvents(controller, action.name);
343
+ });
361
344
  }
362
345
 
363
346
  return {
364
- /**
365
- * Factory function to create fresh controller objects
366
- * with the given attributes.
367
- *
368
- * @method create
369
- * @static
370
- * @param {Object} [attrs={}]
371
- *
372
- * @return {Controller}
373
- */
374
347
  create: function(attrs) {
375
- attrs = attrs || {};
376
- if (!attrs.name) throw new Error("Controller.create(name): name is undefined");
377
-
348
+ attrs = extend({}, attrs);
349
+ if (!attrs.name) throw new Error("JSkit.Controller: name is undefined");
350
+ restrictKeywords(attrs);
378
351
  var controller = defaults(attrs, {
379
- /**
380
- * Array of actions to be wired up.
381
- *
382
- * @property actions
383
- * @type Array
384
- * @default []
385
- */
386
352
  actions: [],
387
- /**
388
- * Namespace that controller events are namespaced under.
389
- *
390
- * @property namespace
391
- * @type String
392
- * @default ""
393
- */
394
- namespace: "",
395
- /**
396
- * Channel that controller events use under namespace.
397
- *
398
- * @property channel
399
- * @type String
400
- * @default "controller"
401
- */
402
353
  channel: "controller",
403
- /**
404
- * Underscored name of controller for use in events.
405
- *
406
- * @property controllerEventName
407
- * @type String
408
- * @default "controller"
409
- */
410
354
  controllerEventName: underscore(attrs.name),
411
- /**
412
- * Event dispatcher for registering events.
413
- *
414
- * @property dispatcher
415
- * @type Dispatcher
416
- * @default JSkit.Dispatcher.create()
417
- */
418
355
  dispatcher: JSkit.Dispatcher.create(),
419
- /**
420
- * Object of element names/selectors to
421
- * cache per action.
422
- *
423
- * @property elements
424
- * @type Object
425
- * @default {}
426
- */
427
356
  elements: {},
428
- /**
429
- * Object of events for each action to
430
- * register on given elements.
431
- *
432
- * @property events
433
- * @type Object
434
- * @default {}
435
- */
436
357
  eventSeparator: ":",
437
- /**
438
- * Default implementation that commits no operation
439
- * @method all
440
- */
358
+ namespace: "",
359
+ initialize: function() {},
441
360
  all: function() {},
442
- /**
443
- * Default implementation that commits no operation
444
- * @method initialize
445
- */
446
- initialize: function() {}
361
+ eventNameForAction: function(action) {
362
+ return eventNameForAction(this, action);
363
+ }
447
364
  });
365
+
448
366
  bindAll(controller);
449
- controller.actions.unshift("all");
450
367
 
451
- registerElementCaching(controller);
452
- registerControllerEvents(controller);
368
+ registerAllAction(controller);
369
+ normalizeActions(controller);
453
370
  registerActions(controller);
454
371
 
372
+ normalizeControllerElements(controller);
373
+ normalizeControllerEvents(controller);
374
+
375
+ registerCacheElementsForActions(controller);
376
+ registerControllerElementEvents(controller);
377
+
378
+ decorateCacheElements(controller);
379
+ decorateRegisterEvents(controller);
380
+
455
381
  controller.initialize();
456
382
 
457
383
  return controller;
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_jskit
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.2
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dayton Nolan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-08 00:00:00.000000000 Z
11
+ date: 2015-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -170,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
170
  version: '0'
171
171
  requirements: []
172
172
  rubyforge_project:
173
- rubygems_version: 2.2.2
173
+ rubygems_version: 2.4.5.1
174
174
  signing_key:
175
175
  specification_version: 4
176
176
  summary: Gem that provides Rails integration for jskit