zvictor/ArgueJS — pull request #15 by johmoh (2013-05-17 22:22:53+00:00)
Title: New version of ArgueJS

(copy from https://github.com/zvictor/ArgueJS/issues/14):

Hello,

I made a fork. It is just for early birds and to get response. In the end, I want - with hopefully permission of the maintainer of this project - integrate the code in this repository. Here it is:

https://github.com/johmoh/ArgueJS.git

The module name is "arguejs2" and it is a complete rewrite. The original version is untouched. This version is not highly tested at the moment. But I have a good feeling, that everything works fine. Why the changes... It solves the following feature requests, enhancement requests, bugs and general discussions:

bugs:
- Parameter Ordering (https://github.com/zvictor/ArgueJS/issues/13)

enhancements:
- Is it possible to have an optional parameter that you supply as undefined? (https://github.com/zvictor/ArgueJS/issues/12)

feature requests:
- feature request: lazy evaluation of default parameters (https://github.com/zvictor/ArgueJS/issues/8)
- I do not find it, but some asked for support of variadic functions - it's supported

general solutions:
- How to pass null/undefined as a param? (https://github.com/zvictor/ArgueJS/issues/6)
- General solution for passing undefined/null as value
- General solution for specifying that an parameter can be "anytype"
- General solution for specifying undefined/null as default for an optional parameter
- Ease of extensibility - new options... Yesterday the code also solved "feature request: possibility to specify a validation function for an argument" (https://github.com/zvictor/ArgueJS/issues/9) and "feature request: possibility define a normalization function for an argument" (https://github.com/zvictor/ArgueJS/issues/10) but I removed these options because of some good arguments some people here had. If there is a more clear way to do something like that, I will include that.

**concept**

The function signature is now defined as array containing objects. These objects specify parameters:

[{...}, {...}, ...]

Each object has the following structure:

{name: typespec}

typespec can be...

* A type (String, Boolean, MyClass, ...) - for mandatory parameters.
* An array containing 1 value - the type. That marks the parameter as optional.
* An array containing 2 values - the type (first value) and a default value (second value). That marks the parameter as optional.
* An object with the properties (key:value)-pairs:
* (type:typespec) - This property is mandatory. Typespec must be a type (parameter is mandatory) or an array containing one value - the type (parameter is optional).
* (defaultValue:ValueOrObjectOrFunction) - This property is optional. If you define it, than the parameter gets marked as mandatory. Of course you can specify undefined or null as default value. You can also specify a function for a non-function parameter. In that case the function gets called if the default value is needed (and only in that case). If the type of the parameter is "Function" then this function is not called. In that case, the function is the default value itself. In a variadic function the default value must be an array for the tail parameter.
* (allowUndefined:true|false) - This property is optional (default is false). It is forbidden to specify a default value as undefined, if undefined is not allowed. That means: If you want your parameter to accept undefined or you want to specify a default value as undefined, than you must allow undefined by writing: allowUndefined:true. That parameter is forbidden for the tail parameter in a variadic function.
* (allowNull:true|false) - The same rules as allowUndefined.
* (parenthesizeTail:true|false) - This property is optional (default is false) and only allowed for the tail parameter in a variadic function. The parameter answers the following question: If your tail contains only 1 value and that value is an array should I include that value in a new array or should I return that value (= it is already an array) as it is. The reason for that parameter is simple: If you want to call a variadic function and you already have an array of arguments then you simply can pass the array as the tail argument. Example:

````
formatText() {
var _args = arguejs2.getArguments([{formatString:String}, {replacements:arguejs2.[TAIL]}];
// use _args.replacements to format the _args.formatString
}
````
If parenthesizeTail:true then you can call formatText with...
````
var replacements = [...];
var formattedText = formatText(formatString, replacements[0], replacements[1], ...);
````
...or with...

````
var replacements = [...];
var formattedText = formatText(formatString, replacements);
````

Defining "anytype" or the tail parameter in a variadic function: ArgueJS2 introduces two types for that: ArgueJS2.ANYTYPE and ArgueJS2.TAIL. So you specify a parameter of anytype that is optional with ````{myParameter: [arguejs2.ANYTYPE]}```` or ````{myParameter: {type:. [arguejs2.ANYTYPE]}}````. It's the same for the tail parameter of a variadic function. Just replace "ANYTYPE" with "TAIL" in the example.

What does ANYTYPE mean? - It means any type except undefined or null. That means, if you want to specify a parameter to be any type or undefined or null then you have to specify that with allowUndefined:true and allowNull:true:

````
{myParameter: {type: arguejs2.ANYTYPE, allowUndefined:true, allowNull:true}}
````

There is a example directory in the repository containing an example file to get started.

Yo, that's it for here and now.
Feedback is welcome.