Skip to content

Commit

Permalink
Merge pull request #65 from sanctuary-js/dc-create
Browse files Browse the repository at this point in the history
update $.create to take a record rather than positional arguments
  • Loading branch information
davidchambers committed May 9, 2016
2 parents 08a30be + 2425267 commit 42616aa
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 109 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,18 @@ const env = $.env.concat([Integer, NonZeroInteger]);
The next step is to define a `def` function for the environment:

```javascript
const def = $.create(true, env);
const def = $.create({checkTypes: true, env: env});
```

The first argument to `$.create` determines whether type checking is enabled.
The `checkTypes` option determines whether type checking is enabled.
This allows one to only pay the performance cost of run-time type checking
during development. For example:

```javascript
const def = $.create(process.env.NODE_ENV === 'development', env);
const def = $.create({
checkTypes: process.env.NODE_ENV === 'development',
env: env,
});
```

`def` is a function for defining functions. For example:
Expand Down
172 changes: 86 additions & 86 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@
// TypeClass :: (String, (a -> Boolean)) -> TypeClass
$.TypeClass = function(name, test) {
return {
'@@type': 'sanctuary-def/TypeClass',
name: name,
_test: test,
toString: always(stripNamespace(name))
Expand Down Expand Up @@ -444,7 +445,7 @@
};

// RecordType :: {Type} -> Type
$.RecordType = function(fields) {
var RecordType = $.RecordType = function(fields) {
var names = keys(fields);

// invalidMappings :: [String]
Expand Down Expand Up @@ -472,7 +473,7 @@
for (var idx = 0; idx < names.length; idx += 1) {
var name = names[idx];
s += f(idx === 0 ? ' ' : ', ');
s += f(name + ' :: ') + kv(name)(String(fields[name]));
s += f(name + ' :: ') + kv(name)(showType(fields[name]));
if (idx === names.length - 1) s += f(' ');
}
return s + f('}');
Expand Down Expand Up @@ -549,8 +550,17 @@
return UnaryType(name, $$typeEq(name), _1);
};

// $.env :: [Type]
$.env = [
// applyParameterizedTypes :: [Type] -> [Type]
var applyParameterizedTypes = function(types) {
return map(types, function(x) {
return typeof x === 'function' ?
x.apply(null, map(range(0, x.length), K(Unknown))) :
x;
});
};

// defaultEnv :: [Type]
var defaultEnv = $.env = applyParameterizedTypes([
$.Array = type1('Array', id),
$.Boolean = type0('Boolean'),
$.Date = type0('Date'),
Expand All @@ -563,7 +573,7 @@
$.StrMap = StrMap,
$.String = type0('String'),
$.Undefined = type0('Undefined')
];
]);

// Any :: Type
$.Any = NullaryType(
Expand Down Expand Up @@ -677,6 +687,9 @@
// Type :: Type
var Type = type0('sanctuary-def/Type');

// TypeClass :: Type
var TypeClass = type0('sanctuary-def/TypeClass');

// arity :: (Number, Function) -> Function
var arity = function(n, f) {
return (
Expand Down Expand Up @@ -1035,23 +1048,27 @@
value, // :: Any
index // :: Integer
) {
var f = _satisfactoryTypes(env, name, constraints, expTypes, index);
return f(typeVarMap, expTypes[index], [value], [], []);
};

// applyParameterizedTypes :: [Type] -> [Type]
var applyParameterizedTypes = function(_env) {
return map(_env, function(x) {
return typeof x === 'function' ?
x.apply(null, map(range(0, x.length), K(Unknown))) :
x;
});
var result = expTypes[index].validate(value);
return result.isLeft ?
Left(invalidValue(name,
constraints,
expTypes,
Info(env,
[result.value.value],
result.value.typePath,
result.value.propPath,
index))) :
result.chain(function(value) {
var f = _satisfactoryTypes(env, name, constraints, expTypes, index);
return f(typeVarMap, expTypes[index], [value], [], []);
});
};

// test :: ([Type], Type, Any) -> Boolean
var test = $.test = function(_env, t, x) {
var env = applyParameterizedTypes(_env);
return satisfactoryTypes(env, 'name', {}, [t], {}, x, 0).isRight;
var f = _satisfactoryTypes(env, 'name', {}, [t], 0);
return f({}, t, [x], [], []).isRight;
};

// filterTypesByValues :: ([Type], [Any]) -> [Type]
Expand All @@ -1063,19 +1080,7 @@
});
};

// ordinals :: [String]
var ordinals = [
'first',
'second',
'third',
'fourth',
'fifth',
'sixth',
'seventh',
'eighth',
'ninth'
];

// invalidArgumentsLength :: (String, Integer, Integer) -> Error
var invalidArgumentsLength = function(name, expectedLength, actualLength) {
return new TypeError(
LEFT_SINGLE_QUOTATION_MARK + name + RIGHT_SINGLE_QUOTATION_MARK +
Expand All @@ -1084,14 +1089,6 @@
);
};

var invalidArgument = function(name, types, value, index) {
return new TypeError(
LEFT_SINGLE_QUOTATION_MARK + name + RIGHT_SINGLE_QUOTATION_MARK +
' expected a value of type ' + map(types, showTypeQuoted).join(' or ') +
' as its ' + ordinals[index] + ' argument; received ' + show(value)
);
};

// constraintsRepr :: StrMap [TypeClass] -> String
var constraintsRepr = function(constraints) {
var reprs = chain(toPairs(constraints), function(pair) {
Expand Down Expand Up @@ -1350,10 +1347,29 @@
])));
};

// create :: (Boolean, [Type]) -> Function
$.create = function(checkTypes, _env) {
// assertRight :: Either a b -> Undefined !
var assertRight = function(either) {
if (either.isLeft) throw either.value;
};

// Options :: Type
var Options = RecordType({checkTypes: $.Boolean, env: $.Array($.Any)});

// create :: Options -> Function
$.create = function(opts) {
assertRight(satisfactoryTypes(defaultEnv,
'create',
{},
[Options, $.Function],
{},
opts,
0));

// checkTypes :: Boolean
var checkTypes = opts.checkTypes;

// env :: [Type]
var env = applyParameterizedTypes(_env);
var env = applyParameterizedTypes(opts.env);

// curry :: ... -> Function
var curry = function(
Expand All @@ -1366,7 +1382,6 @@
impl // :: Function
) {
return arity(_indexes.length, function() {
var either, result;
if (checkTypes) {
var delta = _indexes.length - arguments.length;
if (delta < 0) {
Expand All @@ -1388,26 +1403,15 @@

var value = arguments[idx];
if (checkTypes) {
result = expTypes[index].validate(value);
if (result.isLeft) {
throw invalidValue(name,
constraints,
expTypes,
Info(env,
[result.value.value],
result.value.typePath,
result.value.propPath,
index));
}
either = satisfactoryTypes(env,
name,
constraints,
expTypes,
typeVarMap,
value,
index);
if (either.isLeft) throw either.value;
typeVarMap = either.value.typeVarMap;
var result = satisfactoryTypes(env,
name,
constraints,
expTypes,
typeVarMap,
value,
index);
assertRight(result);
typeVarMap = result.value.typeVarMap;
}
values[index] = value;
} else {
Expand All @@ -1417,25 +1421,13 @@
if (isEmpty(indexes)) {
var returnValue = impl.apply(this, values);
if (checkTypes) {
result = last(expTypes).validate(returnValue);
if (result.isLeft) {
throw invalidValue(name,
constraints,
expTypes,
Info(env,
[result.value.value],
result.value.typePath,
result.value.propPath,
_indexes.length));
}
either = satisfactoryTypes(env,
name,
constraints,
expTypes,
typeVarMap,
returnValue,
expTypes.length - 1);
if (either.isLeft) throw either.value;
assertRight(satisfactoryTypes(env,
name,
constraints,
expTypes,
typeVarMap,
returnValue,
expTypes.length - 1));
}
return returnValue;
} else {
Expand All @@ -1456,11 +1448,19 @@
throw invalidArgumentsLength('def', def.length, arguments.length);
}

var types = [$.String, $.Object, $.Array(Type), $.Function];
for (var idx = 0; idx < types.length; idx += 1) {
if (!types[idx]._test(arguments[idx])) {
throw invalidArgument('def', [types[idx]], arguments[idx], idx);
}
var types = [$.String,
StrMap($.Array(TypeClass)),
$.Array(Type),
$.Function,
$.Function];
for (var idx = 0; idx < types.length - 1; idx += 1) {
assertRight(satisfactoryTypes(defaultEnv,
'def',
{},
types,
{},
arguments[idx],
idx));
}
}

Expand Down
Loading

0 comments on commit 42616aa

Please sign in to comment.