# Snooze 1.0.0-alpha.1
## Differences to pre-alpha snooze
Pretty much everything has been reworked here. Snooze is no longer opinionated on how it should be used and does not focus on creating a RESTful server (though it can still be used to). It has removed most of what was in the pre-alpha version to create a better foundation for a more powerful and modular framework. Mostly this is done in the way of Entities. **More information provided in the README below**.
## Installation
    # install snooze to your local project
    npm install snooze
    
    # install snooze-baselib as a starting place for your project
    npm install snooze-baselib
    
    # optionally install snooze-cli to start
    # your projects using a snooze.json config file
    sudo npm install -g snooze-cli
## Setup
To create a simple one-file snooze application an example is shown below. More advanced setups later in the README. It is recommended that beginners, intermediates, and advanced users use the `snooze-baselib` module unless there are specific reasons not to. The `snooze-baselib` module contains usefule `Entities` and `importProcesses`.

    // main.js
    (function() {
        'use strict';
        
        // Snooze is a global object. Because of node's require caching
        // the snooze object has one instance accross all files.
        var snooze = require('snooze');
        
        // Creates a myApp module and imports the `snooze-baselib` module
        snooze.module('myApp', ['snooze-baselib'])
            // Creates a run function that will be ran when the application starts
            .run(function() {
                console.log('Hello World!');
            })
            // Does some compiling and begins the app by calling all config
            // and run processes.
            .wakeup();
    })();
Outputs

    # running via terminal
    node main.js
    Hello World!
    
#### Modules
Modules are a flexible wrapper or foundation for your project. They can be designed to share a set of functionality to other modules (and are not intended to run alone), or they can be designed to run your application. Modules greatest strength is that it allows sharing functionality easily and in an abstrated, modular way. To create a module use the `snooze.module` method.

    var snooze = require('snooze');
    snooze.module('myApp', []);
    
When creating a module the second param is required. It can be an empty array or an array of modules to import. All module methods that don't return a value returns itself making commands chainable.

    snooze.module('myApp', []).doSomething().doSomethingElse();
    
If the modules is already created you can access it be omitting the array.

    snooze.module('myApp').doSomething();
    
#### Importing Modules
Importing modules lets you import functionality into your application seemlessly. Modules can be written yourself or downloaded using npm. `snooze-baselib` is a highly recommended starting point. Using it as an example, to install it and import it into your project do the following.

```
 npm install snooze-baselib --save
```
```
snooze.module('myApp', ['snooze-baselib']);
```

If the npm module hasn't been required using `require()` snooze will try to do this automatically. If you are trying to import a local module (not from npm) `require()` it manually before you try to import it into another module.

**Note** When a module is constructed the dependant modules will import immediately.

#### run
A run processes may be what you use to run your app. Your module can define multiple run processes that will get called once `wakeup` or `doRuns` is called. It's recommended you should use `wakeup` instead. Run processes allow injected Entities.

    snooze.module('myApp').run(function(MyService) {
        MyService.doSomething();
    });
    
#### config
Config processes are called before run processes. Entities may define a config object. This is up to the writer of the entity to provide as well as document.

    snooze.module('myApp').config(function(MyService) {
        MyService.maxSomethings = 10;
    }).run(function(MyService) {
        MyService.doSomething();
    });
    
Depending on how the Entity is written. Some entities may provide a config and an injectable, just a config, or just an injectable. See the documentation of the Entity for it's possible uses.

#### wakeup
Because I am a pun-master (i'm not), to start your *snooze* application you should *wakeup*. This will go through the `configPreprocessors`, `config` processes, and `run` processes in that order.

    snooze.module('myApp')
        .run(function() {
            console.log('foo');
        });
    
    console.log('bar');
    
    snooze.module('myApp').wakeup();
Outputs

    bar
    foo

#### Entities
A Service in pre-alpha is what is now a *type* of Entity in alpha. An Entity can be created and customized to serve any purpose. Using the **recommended** `snooze-baselib` module in your projects you get the `service`, `value`, and `constant` entities in your project. Other entities can be imported from other modules or created by the developer and shared through imports.

An Entity can be injected into snooze processes or any "injectable function". They can also be injected into Entities that define a function for their `constructor`. Taking the `service` Entity from `snooze-baselib` we can create a Math service for our application.

    // lib/services/Math.js
    (function() {
        'use strict';
        var snooze = require('snooze');
        
        // Constructing a service named Math. The second parameter is the constructor.
        // This function can also contain injectable Entities like services.
        snooze.module('myApp').service('Math', function() {
            return {
                sum: function(num1, num2) {
                    return num1, num2;
                }
            };
        })
        .run(function(Math) {
            console.log(Math.sum(10, 5));
        });
    });
Outputs

    node main.js
    15
**Note** we don't include the dependencies here. When dependencies are defined, snooze will construct a module. When no dependencies are defined you are accessing the module.

Entities come in different shapes and sizes. Lets create a bank app that prevents you from withdrawing more that $500 at a time.

// lib/services/Bank.js
    (function() {
        'use strict';
        var snooze = require('snooze');
        
        snooze.module('myApp').service('Bank', function(maxWithdrawAmount) {
            return {
                withdraw: function(accountBalance, withdrawAmount) {
                    if(withdrawAmount > maxWithdrawAmount) {
                        console.log('Unable to withdraw $' + withdrawAmount + ' as it exceeds the max withdraw amount of $' + maxWithdrawAmount);
                        
                        return accountBalance;
                    } else {
                        return accountBalance - withdrawAmount;
                    }
                }
            };
        })
        .constant('maxWithdrawAmount', 500)
        .run(function(Bank) {
            var myBalance = 1000;
            myBalance = Bank.withdraw(myBalance, 700);
            myBalance = Bank.withdraw(myBalance, 200);
            
            console.log('$' + myBalance);
        });
    });
Output

    node main.js
    Unable to withdraw $700 as it exceeds the max withdraw amount of $500
    $800
    
For more information on `service`, `value`, and `constant`, see the [snooze-baselib README](https://github.com/iamchairs/snooze-baselib).

#### Registering Entities
Each module is responsible for importing it's own entities. You don't need to worry about importing the entities from a module you are importing. The module you are importing (say `snooze-baselib`) will import it's Entity types (`service`, `value`, and `constant`) as well as entities built on these types (like in our `Math` example). To create your own entities on these types and import them use the `registerEntitiesFromPath` method. You can specify the exact path of the file to import or use a [globbing pattern](https://github.com/isaacs/node-glob).

    // main.js
    (function() {
        'use strict';
        var snooze = require('snooze');
        
        snooze.module('myApp', ['snooze-baselib'])
            .registerEntitiesFromPath('lib/services/Math.js')
            // .registerEntitiesFromPath('lib/services/*.js') [all js files in lib/services]
            // .registerEntitiesFromPath('lib/**/*.js') [all js files in lib recursively]
            .run(function(Math) {
                console.log(Math.sum(10, 5));
            })
            .wakeup();
    })();

#### snooze.json (config)

If the root of your app has a snooze.json file in it, snooze will load the contents into the config when it's constructed. Modules can be written to read the config and change the behavior of your application in the configuration or running phases of your application. The only available property in vanila snooze.json is the **silent** property. False be default but set to true and logs and warns will not print to the console.

    {
        "silent": true
    }

## Advanced Modifications
In this section I'll go into creating custom Entities, Config Preprocessors, and Import Processes, and extending snooze.json.

Before you do this consider the following.
* Is this functionality available elsewhere?
* If this functionality exists but doesn't provide exactly what I need should I try contacting the author first?
* How can this affect other modules?
 * Is it modular enough?
 * Is it abstracted?
 * Am I modifying basic functionality accross the app in a potentially harmful way?
   * Did I document this well enough?

In several ways you can change the way snooze and modules work entirely through these features. This flexibility is powerful but can also be harmful. Be careful, be nice.

#### Creating Entities
`Entities` is a loose term for the type of Entity as well as instances of that type. An Entity type is refered to as an `EntityGroup`. And instance of an `EntityGroup` is an `Entity`. An `Entity` also creates and instance of itself when it's injected. So we have `EntityGroup`, `Entity`, and `EntityInstance`. Using `snooze-baselib` again as an example, a `service` is an `EntityGroup`. If we create a `service` called Math, Math is an `Entity`. When Math is injected (in say, a run processes) it injects an instance of Math called an `EntityInstance`.

##### EntityGroups

To create the `service` `EntityGroup` we will do the following.

    // lib/entities/service.js
    (function() {
    	'use strict';
    
    	var snooze = require('snooze');
    
    	var Service = new snooze.EntityGroup();
    	Service.type = 'service';
    
    	module.exports = Service;
    })();

The name, or type, of the Entity should set to the new `EntityGroup` object constructed from `snooze.EntityGroup`. The type should not contain spaces. The reason for this is because when this `EntityGroup` is compiled it's type will become a method on the module.

Before `EntityGroup`

    snooze.module('myApp')
        .service('MyService', function() {}); // Error: undefined is not a function
After `EntityGroup`

    snooze.module('myApp')
        .registerEntityGroupsFromPath('lib/entities/*.js')
        .service('MyService', function() {}); // All good
        
##### Compiling

The `EntityGroup` has a set of methods that take an `Entity` and apply it's config, injection, etc. An `Entity` is constructed in 2 parts. The first being the name of the `Entity`, the second being the `constructor`. The `constructor` in the above examples is the function, but this can be any value you defined as the constructor. In the `snooze-baselib` `constant` `Entity` the constructor is not a function but just whatever value is passed in the second argument **as is**. In any case, we need to create a `compile` method that takes the `constructor` and constructs an instance. Entities compile when `module.EntityManager.compile` or `module.wakeup` is called. They are not compiled when registered because some Entities will be defined with dependencies that don't yet exist. Once `wakeup` is called an `module.isAwake` is set to true, Entites will autocompile individually.

    Service.compile = function(entity, entityManager) {
		entity.instance = entityManager.run(entity.constructor);

		if(entity.instance.$compile) {
			entity.instance.$compile();
		}
	};
	
The service `compile` takes the `constructor` and runs it as an injectable function using `EntityManager`. The returned value is the `EntityInstance`. Additionally, if the newly created instance has a $compile method it will run that after compiling the instance.

##### Registering Dependencies

Once the instance has been compiled we should write the `registerDependencies` method. Not all Entities will have dependencies and the ones that do may not use an injectable function as it's `constructor`. Because of this, it's up to the author of the `Entity` to create a method that will register the Entities dependencies. This step is important, it will prevent circular dependencies and infinite loops.

    Service.registerDependencies = function(entity, entityManager) {
		if(typeof entity.constructor === 'function') {
			entity.dependencies = snooze.Util.getParams(entity.constructor);
		} else {
			throw Error('Services expect function constructors. ' + (typeof entity.constructor) + ' given');
		}
	};
	
##### Injecting

The `EntityGroup` should define what an Entity provides when it's being injected. In the case of a `service` we will return the instance unless $get is defined (in which case that will be returned).

    Service.getInject = function(entity, entityManager) {
		if(entity.instance.$get) {
			return entity.instance.$get;
		}

		return entity.instance;
	};
**Using $get**

    snooze.module('myApp')
        .service('MyService1', function() {
            // Here is the injected value
            return {
                foo: function() {
                    return 'bar';
                }
            };
        })
        .service('MyService2', function() {
            var properties = {
                fooValue: 'bar'
            };
            return {
                properties: properties
                // Here is the injected value
                '$get': {
                    foo: function() {
                        return properties.fooValue
                    }
                }
            };
        })
        .run(function(MyService1, MyService2) {
            console.log(MyService1.foo());
            console.log(MyService2.foo());
        });
Outputs

    bar
    bar
    
##### Configuring

Similar to the `getInject` method but used when injecting into `module.config` processes.
    
    Service.getConfig = function(entity, entityManager) {
		if(entity.instance.$config) {
			return entity.instance.$config;
		}

		return entity.instance;
	};
	
Using to update $get.

    snooze.module('myApp')
        .service('MyService1', function() {
            // Here is the injected value
            return {
                foo: function() {
                    return 'bar';
                }
            };
        })
        .service('MyService2', function() {
            var properties = {
                fooValue: 'bar'
            };
            return {
                properties: properties
                // Here is the injected value
                '$get': {
                    foo: function() {
                        return properties.fooValue
                    }
                }
            };
        })
        .config(function(MyService2) {
            MyService2.properties.fooValue = 'baz';
        })
        .run(function(MyService1, MyService2) {
            console.log(MyService1.foo());
            console.log(MyService2.foo());
        });
Outputs
    
    bar
    baz

#### Post Compile

Entity instances can call a post-compile process. This is useful for managing services that need to do their own level of compiling once it's dependencies are ready. To set the post-compile processes set the `$post` value on the instance return object.

    snooze.module('myApp')
        .service('ServiceManager', function($entityManager) {
            var services = [];

            // This will run after EntityManager.compile has finished compiling all Entities.
            function $post() {
                var srvs = $entityManager.getEntities('service');
                for(var i = 0; i < srvs.length; i++) {
                    services.push(srvs[i].instance);
                }
            };

            function getServices() {
                return services;
            };

            return {
                '$get': {
                    getServices: getServices
                },
                '$post': $post
            };
        });
    
##### Other Properties

**private** - You can set an `Entity` as private. This means it will not be shared to an importing module. (default: false)

    Service.private = false;

**injectable** - You can set any individual `Entity` as injectable or not. If false, the `Entity` cannot be injected into other Entities or run processes. (default: true)

    Service.injectable = true;

**configurable** - You can set any individual `Entity` as configurable or not. If false, the `Entity` cannot be injected into config processes. (default: true)

```
    Service.compile = function(entity, entityManager) {
		entity.instance = entityManager.run(entity.constructor);

		entity.private = entity.$private || entity.private;
		entity.injectable = entity.$injectable || entity.injectable;
		entity.configurable = entity.$configurable || entity.configurable;

		if(entity.instance.$compile) {
			entity.instance.$compile();
		}
	};
```

```
    // This service is only configurable
    snooze.module('myApp')
        .service('routeManager', function() {
            return {
                $injectable: false,
                path: function(url, cb) { ... }
            };
        })
        .config(function(routeManager) {
            routeManager.path('/users', function() { ... });
        });
```

**constant** - You can set an EntityGroup as `constant` (true) to throw an error if the Entity is attempted to be overwritten. (default: false)

    Service.constant = false;

#### Import Processes
Import processes define how to import modules into others. By default, snooze has no import processes. `snooze-baselib` defines processes to import Entities. An import process is a function that returns the import process function. The first function allows manipulation of the existing importProcesses. The second (nested) function gets appended to the array of import processes.

The import processes is given the source (imported) module and the dest (importee) module.

Here is the processes for importing Entities.
```
    // lib/importProcesses/importEntities.js
    (function() {
    	'use strict';
    
    	module.exports = function(processes) {
    		return function(source, dest) {
    			var entities = source.EntityManager.getEntities();
    
    			for(var i = 0; i < entities.length; i++) {
    				var entity = entities[i];
    				dest.log(('+ Entity: ' + entity.getName()).blue);
    				if(dest.EntityManager.entityExists(entity)) {
    					dest.warn('Entity Exists: ' + entity.getName());
    				} else {
    					dest.EntityManager.registerEntity(entity);
    				}
    			}
    		};
    	};
    })();
```
```
snooze.module('myApp')
    .registerImportProcessesFromPath('lib/importProcesses/*.js');
```

#### Config Preprocessors
Config preprocessors is another tool to help you extend snooze.json. `snooze-baselib` defines a preprocessors that allows you to define run modes for your application.
```
    // lib/configPreprocessors/mergeModeConfig.js
    (function() {
    	'use strict';
    
    	module.exports = function(processes) {
    		return function(config, module) {
    			var mode = config.mode;
    			if(mode) {
    				if(config.modes[mode]) {
    					for(var key in config.modes[mode]) {
    						config[key] = config.modes[mode][key];
    					}
    				}
    			}
    
    			console.log(config);
    		};
    	};
    })();
```
```
snooze.module('myApp')
    .registerConfigPreprocessorsFromPath('lib/importProcesses/*.js');
```

#### Extending snooze.json
Unrecognized properties in the snooze.json are passively ignored. Using `configPreprocessors` and writing your Entities to read from the config lets you define custom configurations. The entire configuration is always available when called. One example for extending the snooze.json is if you were creating an HTTP service.

``` 
    // snooze.json
    {
        "mode": "development",
        "modes": {
            "development": {
                "port": 8080
            },
            "production": {
                "port": 80
            }
        }
    }
```
```
    snooze.module('myApp')
            .service('HTTP', function($config) {
                var port = $config.port;
                
                // ...
            });
```

What properties are available in config should be documented.