<commit_before>Plan
====

Plan is a data validation library for PHP. It's planed to be used for
validating data from external sources.

It has three core design goals:

1. Speed;
2. Simplicity and Lightweight;
3. Full validation features support;

It consist in just one file separated in three _namespaces_. To start, just
have to download it and require it in your code.

Concepts
--------

Defining schemas is the first step to validate an input data. An schema is a
tree of _validators_ that can be manually defined or created based on literals
and arrays.

With the schema defined, a plan must be make to validate data. This is made
through the `\plan\Schema` class. This object, when called like a function,
will validate the data and return the modified (or not) data. If any error
occurs and exception will be thrown.

    <?php
    
    use plan\Schema as plan; // Alias it to make it nicer.
    use plan\InvalidList;    // A list of `Invalid` exceptions will be
                             // always forced by `Schema`.
    
    $plan = new plan($schema);
    
    try {
        $data = $plan($input);
    } catch (InvalidList $list) {
        foreach ($list as $error) {
            var_dump($error->getMessage());
        }
    }

Schema information will be always be trusted, therefore will not be validate.
Contrary input data will be never be trusted.

### Literals

Scalars are treated as literals that are matched using the identity operator:

    $plan = new plan('Hello World');
    $plan('Hello World'); // returns 'Hello World'
    
    $plan = new plan(42);
    
    try {
        $plan(10);
    } catch (InvalidList $e) {
        // $e->getMessage() will be
        // Multiple invalid: ["\"10\" is not \"42\""]
    }

### Arrays

Plan will distinguish between indexed and associative arrays. If an array has
all indexes numeric and sequential will be considerer a sequence. If not will
be considerer a dictionary.

#### Sequences

A sequence will be treated as a list of possible valid values. Will require
that the input data is sequence that contains one or more elements of the
schema. Elements can be repeated.

    $plan = new plan([1, 'one']);
    $plan([1]);
    $plan([1, 'one', 1, 1, 'one', 1]);

An empty array will be a sequence that accept any value.

    $plan = new plan([]);
    $plan(['anything', 123, true);

#### Dictionaries

A dictionary will be used to validate structures. Each key in data will be
checked with the _validator_ of the same key in the schema. By default, keys
are not required; but any additional key will throw an exception.

    $plan = new plan(array('name' => 'John', 'age'  => 42));
    $plan(array('age' => 42));
    
    try {
        $plan(array('age' => 42, 'sex' => 'male');
    } catch (InvalidList $e) {
        // Multiple invalid: ["Extra key sex not allowed"]
    }

Validators
----------

All core _validators_ live in `\plan\assert` _namespace_.

### `type`

Will validate the type of data. The data type will be not casted.

    $plan = new plan(assert\type('int'));
    $plan(123);
    
    try {
        $plan('123');
    } catch (InvalidList $e) {
        // Multiple invalid: ["123 not int"]
    }

Aliases of this _validator_ are: `bool`, `int`, `float`, `str`.

### `scalar`

Wrapper around `is_scalar` function.

### `instance`

Wrapper around `instanceof` type operator.

### `literal`

See [Literals](#literals).

### `seq`

See [Sequences](#sequences).

This is normally accepted as "a list of something (or something else)".

*   A list of email? `new plan([assert\email()])`.
*   A list of people, but some of them are in text and some as a dictionary?

        $plan = new plan([assert\str(), array(
            'name'  => assert\str(),
            'email' => assert\email(),
        )]);
        $plan([
            array('name' => 'Kevin', 'email' => '<EMAIL>'),
            array('name' => 'Jane', 'email' => '<EMAIL>'),
            '<NAME> <<EMAIL>>',
        ]);

### `dict`

See [Dictionaries](#dictionaries).

Because, by default keys are not required and extra keys throw exceptions,
the _validator_ `dict` accept two more parameters to change this behavior.

    $required = true; // Will require ALL keys
    $extra    = true; // Accept extra keys
    
    $dict = array('name' => 'John', 'age' => 42);
    $plan = new plan(assert\dict($dict, $required, $extra);
    $plan(array(
        'name' => 'John',
        'age'  => 42,
        'sex'  => 'male', // This could be whatever
                          // as it would not be validated
    ));

### `any`

Accept any of the given list of _validators_, as a valid value. This is useful
when you only need one choice a of set of values. If you need any quantity
of choices use a [sequence](#sequence) instead.
<commit_msg>Add doc of required parameters of dict<commit_after>Plan
====

Plan is a data validation library for PHP. It's planed to be used for
validating data from external sources.

It has three core design goals:

1. Speed;
2. Simplicity and Lightweight;
3. Full validation features support;

It consist in just one file separated in three _namespaces_. To start, just
have to download it and require it in your code.

Concepts
--------

Defining schemas is the first step to validate an input data. An schema is a
tree of _validators_ that can be manually defined or created based on literals
and arrays.

With the schema defined, a plan must be make to validate data. This is made
through the `\plan\Schema` class. This object, when called like a function,
will validate the data and return the modified (or not) data. If any error
occurs and exception will be thrown.

    <?php
    
    use plan\Schema as plan; // Alias it to make it nicer.
    use plan\InvalidList;    // A list of `Invalid` exceptions will be
                             // always forced by `Schema`.
    
    $plan = new plan($schema);
    
    try {
        $data = $plan($input);
    } catch (InvalidList $list) {
        foreach ($list as $error) {
            var_dump($error->getMessage());
        }
    }

Schema information will be always be trusted, therefore will not be validate.
Contrary input data will be never be trusted.

### Literals

Scalars are treated as literals that are matched using the identity operator:

    $plan = new plan('Hello World');
    $plan('Hello World'); // returns 'Hello World'
    
    $plan = new plan(42);
    
    try {
        $plan(10);
    } catch (InvalidList $e) {
        // $e->getMessage() will be
        // Multiple invalid: ["\"10\" is not \"42\""]
    }

### Arrays

Plan will distinguish between indexed and associative arrays. If an array has
all indexes numeric and sequential will be considerer a sequence. If not will
be considerer a dictionary.

#### Sequences

A sequence will be treated as a list of possible valid values. Will require
that the input data is sequence that contains one or more elements of the
schema. Elements can be repeated.

    $plan = new plan([1, 'one']);
    $plan([1]);
    $plan([1, 'one', 1, 1, 'one', 1]);

An empty array will be a sequence that accept any value.

    $plan = new plan([]);
    $plan(['anything', 123, true);

#### Dictionaries

A dictionary will be used to validate structures. Each key in data will be
checked with the _validator_ of the same key in the schema. By default, keys
are not required; but any additional key will throw an exception.

    $plan = new plan(array('name' => 'John', 'age'  => 42));
    $plan(array('age' => 42));
    
    try {
        $plan(array('age' => 42, 'sex' => 'male');
    } catch (InvalidList $e) {
        // Multiple invalid: ["Extra key sex not allowed"]
    }

Validators
----------

All core _validators_ live in `\plan\assert` _namespace_.

### `type`

Will validate the type of data. The data type will be not casted.

    $plan = new plan(assert\type('int'));
    $plan(123);
    
    try {
        $plan('123');
    } catch (InvalidList $e) {
        // Multiple invalid: ["123 not int"]
    }

Aliases of this _validator_ are: `bool`, `int`, `float`, `str`.

### `scalar`

Wrapper around `is_scalar` function.

### `instance`

Wrapper around `instanceof` type operator.

### `literal`

See [Literals](#literals).

### `seq`

See [Sequences](#sequences).

This is normally accepted as "a list of something (or something else)".

*   A list of email? `new plan([assert\email()])`.
*   A list of people, but some of them are in text and some as a dictionary?

        $plan = new plan([assert\str(), array(
            'name'  => assert\str(),
            'email' => assert\email(),
        )]);
        $plan([
            array('name' => 'Kevin', 'email' => '<EMAIL>'),
            array('name' => 'Jane', 'email' => '<EMAIL>'),
            '<NAME> <<EMAIL>>',
        ]);

### `dict`

See [Dictionaries](#dictionaries).

Because, by default keys are not required and extra keys throw exceptions,
the _validator_ `dict` accept two more parameters to change this behavior.

    $required = true; // Will require ALL keys
    $extra    = true; // Accept extra keys
    
    $dict = array('name' => 'John', 'age' => 42);
    $plan = new plan(assert\dict($dict, $required, $extra));
    $plan(array(
        'name' => 'John',
        'age'  => 42,
        'sex'  => 'male', // This could be whatever
                          // as it would not be validated
    ));

The parameter `required` could be an array of required keys:

    $plan = new plan(assert\dict($dict, ['age']));
    $plan(array('name' => 'John', 'age' => 42));
    
    try {
        $plan(array('name' => 'John'));
    } catch (InvalidList $e) {
        // Multiple invalid: ["Required key age not provided"]
    }

### `any`

Accept any of the given list of _validators_, as a valid value. This is useful
when you only need one choice a of set of values. If you need any quantity
of choices use a [sequence](#sequence) instead.

{'fraction_non_alphanumeric': 0.1252274105518496, 'fraction_numerical': 0.008085708510208208, 'mean_word_length': 2.7185268695978957, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 52, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6450028', 'n_tokens_mistral': 2929, 'n_tokens_neox': 2820, 'n_words': 1249}