| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | # Features / Actions
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 18:04:43 +03:00
										 |  |  | The Feature / Action couple is meta-programming library that helps with: | 
					
						
							|  |  |  | - extending and calling methods (Actions) on object inheritance chains | 
					
						
							|  |  |  | - managing and applying sets of methods (Features) to objects (a-la _mixin_) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | ## Actions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Actions are an extension to the JavaScript object model tailored for | 
					
						
							|  |  |  | a set of specific tasks. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 18:42:38 +03:00
										 |  |  | By design this tool-set promotes a _cooperative_ model and makes it | 
					
						
							|  |  |  | hard to change/modify existing signatures / _contracts_ in _extending_  | 
					
						
							|  |  |  | code. | 
					
						
							| 
									
										
										
										
											2016-08-23 18:04:43 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 02:08:20 +03:00
										 |  |  | #### The problem:
 | 
					
						
							| 
									
										
										
										
											2016-08-24 00:48:40 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```javascript | 
					
						
							|  |  |  | var N = { | 
					
						
							|  |  |  |   times: function(n){ | 
					
						
							|  |  |  |     this.value *= n | 
					
						
							| 
									
										
										
										
											2016-08-24 01:17:27 +03:00
										 |  |  |     return this | 
					
						
							| 
									
										
										
										
											2016-08-24 00:48:40 +03:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var n = Object.create(N) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:17:27 +03:00
										 |  |  | n.value = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:55:46 +03:00
										 |  |  | n | 
					
						
							|  |  |  |   .times(3) | 
					
						
							|  |  |  |   .times(2) | 
					
						
							| 
									
										
										
										
											2016-08-24 01:17:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 00:48:40 +03:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To extend this object we'll need to: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:17:27 +03:00
										 |  |  | ```javascript | 
					
						
							|  |  |  | n.times = function(n){ | 
					
						
							|  |  |  |   console.log(this.value, 'times', n) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var res = N.times.call(this, n) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   console.log('    ->', this.value) | 
					
						
							|  |  |  |   return res | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-08-24 00:48:40 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:17:27 +03:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Note that we are manually calling the _super_ method and manually  | 
					
						
							| 
									
										
										
										
											2016-08-24 02:16:40 +03:00
										 |  |  | returning and re-returning `this` in each implementation of `.times(..)`. | 
					
						
							| 
									
										
										
										
											2016-08-24 01:17:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | Another thing to note here is that the code above, though quite simple is | 
					
						
							|  |  |  | not reusable, i.e.: | 
					
						
							|  |  |  | - we can't simply use the extending method for any other parent unless we | 
					
						
							|  |  |  |   either copy/rewrite it or complicate the code. | 
					
						
							|  |  |  | - we can't use the extending method stand-alone, for example for testing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 02:08:20 +03:00
										 |  |  | #### The solution:
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:17:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```javascript | 
					
						
							|  |  |  | var N = Actions({ | 
					
						
							|  |  |  |   times: [function(n){ | 
					
						
							|  |  |  |     this.value *= n | 
					
						
							|  |  |  |   }] | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 02:16:40 +03:00
										 |  |  | // Now we extend .times(..) | 
					
						
							| 
									
										
										
										
											2016-08-24 01:55:46 +03:00
										 |  |  | var ExtendedN = Actions({ | 
					
						
							| 
									
										
										
										
											2016-08-24 01:17:27 +03:00
										 |  |  |   times: [function(n){ | 
					
						
							|  |  |  |     console.log(this.value, 'times', n) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return function(){ | 
					
						
							|  |  |  |       console.log('    ->', this.value) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }] | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | And both objects can be used in the same way as before: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```javascript | 
					
						
							| 
									
										
										
										
											2016-08-24 02:16:40 +03:00
										 |  |  | // Here we mix the two, but either can be used stand-alone as above... | 
					
						
							| 
									
										
										
										
											2016-08-24 01:55:46 +03:00
										 |  |  | var n = mix(N, ExtendedN)  | 
					
						
							| 
									
										
										
										
											2016-08-24 01:17:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | n.value = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:55:46 +03:00
										 |  |  | n | 
					
						
							|  |  |  |   .times(3) | 
					
						
							|  |  |  |   .times(2) | 
					
						
							| 
									
										
										
										
											2016-08-24 01:17:27 +03:00
										 |  |  | ``` | 
					
						
							| 
									
										
										
										
											2016-08-24 00:48:40 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 02:16:40 +03:00
										 |  |  | Now: | 
					
						
							|  |  |  | - `this` is returned automatically enabling us to chain calls to `.times(..)` | 
					
						
							|  |  |  | - the _super_ method is resolved and called automatically | 
					
						
							|  |  |  | - both `N` and `ExtendedN` are independent of each other and reusable  | 
					
						
							|  |  |  |   in different inheritance chains without any extra work needed. | 
					
						
							|  |  |  | - _and more... (see below)_ | 
					
						
							| 
									
										
										
										
											2016-08-24 01:55:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 00:48:40 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 18:04:43 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 02:16:40 +03:00
										 |  |  | ### What we get:
 | 
					
						
							| 
									
										
										
										
											2016-08-23 18:28:06 +03:00
										 |  |  | - **Call _extended_ actions automatically**   | 
					
						
							|  |  |  |   All actions (methods) in a chain are guaranteed to get called if the  | 
					
						
							|  |  |  |   action is called. | 
					
						
							|  |  |  | - **Thread arguments up the call chain**   | 
					
						
							|  |  |  |   All actions in a chain will get the set of arguments passed to the  | 
					
						
							|  |  |  |   action when called. | 
					
						
							|  |  |  | - **Thread the return value down the call chain**   | 
					
						
							|  |  |  |   The return value will get passed through all the actions in a chain  | 
					
						
							|  |  |  |   before returning to the action caller. | 
					
						
							| 
									
										
										
										
											2016-08-24 02:43:51 +03:00
										 |  |  | - **Return `this` by default** | 
					
						
							| 
									
										
										
										
											2016-08-23 18:42:38 +03:00
										 |  |  | - **Organise and apply actions to objects** | 
					
						
							| 
									
										
										
										
											2016-08-23 18:28:06 +03:00
										 |  |  | - **Unified way to document actions** | 
					
						
							|  |  |  | - **Introspection and inspection API** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 18:42:38 +03:00
										 |  |  | ### Restrictions comparing to native JavaScript:
 | 
					
						
							| 
									
										
										
										
											2016-08-23 18:04:43 +03:00
										 |  |  | - **No method shadowing**   | 
					
						
							|  |  |  |   The _extending_ action can not "shadow" the _extended_ action in a  | 
					
						
							| 
									
										
										
										
											2016-08-23 18:10:59 +03:00
										 |  |  |   non destructive manner (e.g. via a `throw`), all actions in a chain are  | 
					
						
							| 
									
										
										
										
											2016-08-23 18:04:43 +03:00
										 |  |  |   guaranteed to be called, unless a fatal error condition. | 
					
						
							|  |  |  | - **No argument shadowing**   | 
					
						
							|  |  |  |   The _extending_ has access to all the arguments that the user passed | 
					
						
							|  |  |  |   but can not modify or reformat them before the _extended_ action gets | 
					
						
							|  |  |  |   them. | 
					
						
							|  |  |  | - **No return shadowing**   | 
					
						
							|  |  |  |   The _extending_ action can not replace the object returned by the  | 
					
						
							| 
									
										
										
										
											2016-08-23 18:10:59 +03:00
										 |  |  |   _extended_ action, though it can _cooperatively_ update/modify it if  | 
					
						
							| 
									
										
										
										
											2016-08-23 18:04:43 +03:00
										 |  |  |   needed | 
					
						
							| 
									
										
										
										
											2016-08-23 18:28:06 +03:00
										 |  |  | - **Single return point**   | 
					
						
							| 
									
										
										
										
											2016-08-23 18:04:43 +03:00
										 |  |  |   Only the _root_ action can return a value, any other returns by  | 
					
						
							|  |  |  |   _extending_ actions are ignored | 
					
						
							| 
									
										
										
										
											2016-08-24 02:43:51 +03:00
										 |  |  | - **No state transferred via mixin**   | 
					
						
							|  |  |  |   The only two things _inherited_ from the object defining the actions  | 
					
						
							|  |  |  |   via the mixin methods or `mix` function are properties and actions,  | 
					
						
							|  |  |  |   all data, including normal methods is discarded.   | 
					
						
							|  |  |  |   _(this is not final)_ | 
					
						
							| 
									
										
										
										
											2016-08-23 18:10:59 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 00:48:40 +03:00
										 |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | ### The main entities:
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 18:59:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | **Action set** | 
					
						
							| 
									
										
										
										
											2016-08-24 02:54:25 +03:00
										 |  |  | ```javascript | 
					
						
							|  |  |  | var empty_full = new ActionSet() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var minimal = Actions({ | 
					
						
							|  |  |  |   // action and prop definitions... | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var full = Actions(ActionSet(), { | 
					
						
							|  |  |  |   // ... | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var inherited = Actions(full, { | 
					
						
							|  |  |  |   // ... | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2016-08-23 18:59:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | - an object containing a number of actions, | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  | - optionally, directly or indirectly inherited from `MetaActions` | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  |   and/or other action sets, | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  | - the action handlers are bound relative to it (`._action_handlers`) | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **Action** | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 02:43:51 +03:00
										 |  |  | A full example: | 
					
						
							|  |  |  | ```javascript | 
					
						
							|  |  |  |   // ... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   minimal: [function(){ | 
					
						
							|  |  |  |     // ... | 
					
						
							|  |  |  |   }], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   full: ['Short info string', | 
					
						
							|  |  |  |     'Long documentation string, describing the action', | 
					
						
							|  |  |  |     function(){ | 
					
						
							|  |  |  |       // pre code | 
					
						
							|  |  |  |       //    run before the parent action... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return function(res){ | 
					
						
							|  |  |  |         // post code | 
					
						
							|  |  |  |         //     run after the parent action or directly after  | 
					
						
							|  |  |  |         //     the pre-code of this is the root action... | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // ... | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Both documentation strings and the return callback are optional. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The call diagram: | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | ``` | 
					
						
							|  |  |  |                         +  pre  +  pre  +       +  post +  post + | 
					
						
							|  |  |  | Action event handler:   o-------x                       o-------x | 
					
						
							|  |  |  |                                 v                       ^ | 
					
						
							|  |  |  | Actions                         o-------x       o-------x | 
					
						
							|  |  |  |                                         v       ^ | 
					
						
							|  |  |  | Root Action                             o---|---x | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  | - a method, created by `Action(..)`, | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | - calls all the shadowed/overloaded actions in the inheritance  | 
					
						
							| 
									
										
										
										
											2016-08-23 21:49:58 +03:00
										 |  |  |   chain in sequence implicitly,   | 
					
						
							| 
									
										
										
										
											2016-08-23 21:49:36 +03:00
										 |  |  |   **Notes:**    | 
					
						
							|  |  |  |     - there is no way to prevent an action in the chain from | 
					
						
							|  |  |  | 		  running, this is by design, i.e. no way to fully shadow. | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | - actions that do not shadow anything are called root actions. | 
					
						
							|  |  |  | - returns the action set by default (for call chaining), | 
					
						
							| 
									
										
										
										
											2016-08-23 21:49:58 +03:00
										 |  |  | - the base/root action can return any value.   | 
					
						
							| 
									
										
										
										
											2016-08-23 21:49:36 +03:00
										 |  |  |   **Notes:**   | 
					
						
							|  |  |  |     - if undefined is returned, it will be replaced by the  | 
					
						
							|  |  |  | 		  action context/action set. | 
					
						
							|  |  |  |     - there is no distinction between root and other actions | 
					
						
							|  |  |  | 		  other than that root action's return values are not  | 
					
						
							|  |  |  | 		  ignored. | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | - can consist of two parts: the first is called before the  | 
					
						
							|  |  |  |   shadowed action (pre-callback) and the second after (post-callback). | 
					
						
							|  |  |  | - post-callback has access to the return value and can modify it | 
					
						
							|  |  |  |   but not replace it. | 
					
						
							|  |  |  | - can be bound to, a-la an event, calling the handlers when it is  | 
					
						
							|  |  |  |   called,  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **Action (event) handler** | 
					
						
							| 
									
										
										
										
											2016-08-24 02:54:25 +03:00
										 |  |  | ```javascript | 
					
						
							|  |  |  | action_set.on('action_name', function(){ | 
					
						
							|  |  |  |   // post code... | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | action_set.on('action_name.post', function(){ | 
					
						
							|  |  |  |   // post code... | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | action_set.on('action_name.pre', function(){ | 
					
						
							|  |  |  |   // pre code... | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | - a function, | 
					
						
							|  |  |  | - can be bound to run before and/or after the action itself, | 
					
						
							|  |  |  | - is local to an action set it was bound via, | 
					
						
							|  |  |  | - when an action is triggered from an action set, all the pre  | 
					
						
							|  |  |  |   handlers in its inheritance chain will be called before the  | 
					
						
							|  |  |  |   respective actions they are bound to and all the post handlers | 
					
						
							|  |  |  |   are called directly after. | 
					
						
							|  |  |  | - pre handlers are passed the same arguments the original actions | 
					
						
							|  |  |  |   got when it was called. | 
					
						
							|  |  |  | - post action handlers will get the root action result as first  | 
					
						
							|  |  |  |   argument succeeded by the action arguments. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### The action system main protocols:
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 02:08:20 +03:00
										 |  |  | By default `Actions(..)` defines no additional methods. Most of the API | 
					
						
							|  |  |  | methods are defined in `MetaActions` and can be optionally inherited  | 
					
						
							|  |  |  | from an instance of `ActionSet`. In general this includes all | 
					
						
							|  |  |  | `ActionSet / object` level methods while anything accessible from the  | 
					
						
							|  |  |  | _action_ is build-in. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  | 1. Documentation generation and introspection (`MetaActions`) | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   ``` | 
					
						
							|  |  |  |   <action>.toString() | 
					
						
							|  |  |  |       -> code of original action function | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   <action-set>.getDoc() | 
					
						
							|  |  |  |   <action-set>.getDoc(<action-name>[, ..]) | 
					
						
							|  |  |  |       -> dict of action-name, doc | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 18:42:38 +03:00
										 |  |  |   <action-set>.getHandlerDocStr(<action-name>) | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |       -> formated string of action handlers | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   <action-set>.actions | 
					
						
							|  |  |  |       -> list of action names | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   <action-set>.length | 
					
						
							|  |  |  |       -> number of actions | 
					
						
							|  |  |  |   ``` | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  | 2. Event-like callbacks for actions (`MetaActions`, `Action`) | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   ``` | 
					
						
							|  |  |  |   <action-set>.on('action', function(){ ... }) | 
					
						
							|  |  |  |   <action-set>.on('action.post', function(){ ... }) | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   <action-set>.on('action.pre', function(){ ... }) | 
					
						
							|  |  |  |   ``` | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  | 3. A mechanism to define and extend already defined actions | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 	This replaces / complements the standard JavaScript overloading  | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  | 	mechanisms (`Action`, `Actions`) | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 21:49:36 +03:00
										 |  |  |   ```javascript | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   // Actions... | 
					
						
							|  |  |  |   var X = Actions({ | 
					
						
							|  |  |  |     m: [function(){ console.log('m') }] | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  |   var O = Actions(X, { | 
					
						
							|  |  |  |     m: [function(){ | 
					
						
							|  |  |  |       console.log('pre') | 
					
						
							|  |  |  |       return function(res){ | 
					
						
							|  |  |  |         console.log('post') | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  |   ``` | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  |   **Notes:** | 
					
						
							|  |  |  |   - what is done here is similar to calling `O.__proto__.m.call(..)` | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |     but is implicit, and not dependant on the original containing  | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  |     object name/reference (`O`), thus enabling an action to be  | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |     referenced and called from any object and still chain correctly. | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Secondary action protocols:
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  | 1. A mechanism to manually call the pre/post stages of an action | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   Pre phase... | 
					
						
							|  |  |  |   ``` | 
					
						
							|  |  |  |   <action>.pre(<context>) | 
					
						
							|  |  |  |   <action>.pre(<context>, [<arg>, ..]) | 
					
						
							|  |  |  |     -> <call-data> | 
					
						
							|  |  |  |   ``` | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   Post phase... | 
					
						
							|  |  |  |   ``` | 
					
						
							|  |  |  |   <action>.post(<context>, <call-data>) | 
					
						
							|  |  |  |     -> <result> | 
					
						
							|  |  |  |   ``` | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   This is internally used to implement the action call as well as the | 
					
						
							|  |  |  |   chaining callbacks (see below). | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   All action protocol details apply. | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  |   **Notes:** | 
					
						
							|  |  |  |   - there is not reliable way to call the post phase without first | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |     calling the pre phase due to how the pre phase is defined (i.e. | 
					
						
							|  |  |  |     pre phase functions can return post phase functions). | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  | 2. A mechanism to chain/wrap actions or an action and a function. | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 	This enables us to call a callback or another action (inner) between  | 
					
						
							|  |  |  | 	the root action's (outer) pre and post stages. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |   ``` | 
					
						
							|  |  |  |   Outer action                o-------x       o-------x | 
					
						
							|  |  |  |                                       v       ^ | 
					
						
							|  |  |  |   Inner action/callback               o---|---x | 
					
						
							|  |  |  |   ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   A trivial example: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ``` | 
					
						
							|  |  |  |   actionSet.someAction.chainApply(actionsSet,  | 
					
						
							|  |  |  |     function(){ | 
					
						
							|  |  |  |       // this gets run between someAction's pre and post  | 
					
						
							|  |  |  |       // stages... | 
					
						
							|  |  |  |     },  | 
					
						
							|  |  |  |     args) | 
					
						
							|  |  |  |   ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   This is intended to implement protocols where a single action is | 
					
						
							|  |  |  |   intended to act as a hook point (outer) and multiple different  | 
					
						
							|  |  |  |   implementations (inner) within a single action set can be used as | 
					
						
							|  |  |  |   entry points. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ``` | 
					
						
							|  |  |  |   // Protocol root action (outer) definition... | 
					
						
							|  |  |  |   protocolAction: [function(){}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Implementation actions (inner)... | 
					
						
							|  |  |  |   implementationAction1: [function(){ | 
					
						
							|  |  |  |     return this.protocolAction.chainApply(this, function(){ | 
					
						
							|  |  |  |       // ... | 
					
						
							|  |  |  |     }, ..) | 
					
						
							|  |  |  |   }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   implementationAction2: [function(){ | 
					
						
							|  |  |  |     return this.protocolAction.chainApply(this, function(){ | 
					
						
							|  |  |  |       // ... | 
					
						
							|  |  |  |     }, ..) | 
					
						
							|  |  |  |   }] | 
					
						
							|  |  |  |   ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Now calling any of the 'implementation' actions will execute code | 
					
						
							|  |  |  |   in the following order: | 
					
						
							|  |  |  |   1. pre phase of protocol action (outer) | 
					
						
							|  |  |  |   2. implementation action (inner) | 
					
						
							|  |  |  |   3. post phase of protocol action (outer) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  |   **Notes:** | 
					
						
							|  |  |  |   - this will not affect to protocol/signature of the outer action | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |     in any way. | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  |   - both the inner and outer actions will get passed the same  | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |     arguments. | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  |   - another use-case is testing/debugging actions. | 
					
						
							|  |  |  |   - this is effectively the inside-out of normal action overloading. | 
					
						
							|  |  |  |   - there is intentionally no shorthand for this feature, to avoid  | 
					
						
							| 
									
										
										
										
											2016-08-23 17:25:55 +03:00
										 |  |  |     confusion and to discourage the use of this feature unless | 
					
						
							|  |  |  |     really necessary. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 3. `.__call__` action / handler | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	This action if defined is called for every action called. It behaves | 
					
						
							|  |  |  | 	like any other action but with a fixed signature, it always receives  | 
					
						
							|  |  |  | 	the action name as first argument and a list of action arguments as | 
					
						
							|  |  |  | 	the second arguments, and as normal a result on the post phase. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  |   **Notes:** | 
					
						
							|  |  |  | 	- it is not necessary to define the actual action, binding to a | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 		handler will also work. | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  | 	- one should not call actions directly from within a __call__  | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 		handler as that will result in infinite recursion. | 
					
						
							|  |  |  | 		XXX need a way to prevent this... | 
					
						
							| 
									
										
										
										
											2016-08-23 17:31:06 +03:00
										 |  |  | 	- one should use this with extreme care as this will introduce  | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | 		an overhead on all the actions if not done carefully. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 18:04:43 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | ## Features
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 18:04:43 +03:00
										 |  |  | Features is a module that helps build _features_ out of sets of actions | 
					
						
							|  |  |  | and manage sets of features according to external criteria and  | 
					
						
							|  |  |  | feature-feature dependencies. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Goals:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | XXX | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### The main entities:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **Feature** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | XXX | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **FeatureSet (Features)** | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 17:21:35 +03:00
										 |  |  | XXX | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <!-- vim:set ts=4 sw=4 spell : --> |