# NAME

File::Serialize - DWIM file serialization/deserialization

# VERSION

version 1.5.0

# SYNOPSIS

```perl
use File::Serialize { pretty => 1 };

my $data = { foo => 'bar' };

serialize_file '/path/to/file.json' => $data;

...;

$data_copy = deserialize_file '/path/to/file.json';
```

# DESCRIPTION

_File::Serialize_ provides a common, simple interface to
file serialization -- you provide the file path, the data to serialized, and
the module takes care of the rest. Even the serialization format, unless
specified
explicitly as part of the options, is detected from the file extension.

# IMPORT

_File::Serialize_ imports the three functions
`serialize_file`, `deserialize_file` and `transerialize_file` into the current namespace.
A default set of options can be set for both by passing a hashref as
an argument to the 'use' statement.

```perl
use File::Serialize { pretty => 1 };
```

# SUPPORTED SERIALIZERS

File::Serialize will pick the serializer to use based on
the extension of the filename or the explicitly given `format`.
If several serializers are registered for the format,
the available serializer with the highest precedence number will
be used.

- YAML

    [File::Serialize::Serialize::YAML::XS](https://metacpan.org/pod/File::Serialize::Serialize::YAML::XS)

    [File::Serialize::Serialize::YAML::Tiny](https://metacpan.org/pod/File::Serialize::Serialize::YAML::Tiny)

- JSON

    [File::Serialize::Serializer::JSON::MaybeXS](https://metacpan.org/pod/File::Serialize::Serializer::JSON::MaybeXS)

- TOML

    [File::Serialize::Serializer::TOML](https://metacpan.org/pod/File::Serialize::Serializer::TOML)

- XML

    [File::Serialize::Serializer::XML::Simple](https://metacpan.org/pod/File::Serialize::Serializer::XML::Simple)

- jsony

    [File::Serialize::Serializer::JSONY](https://metacpan.org/pod/File::Serialize::Serializer::JSONY)

- Markdown

    [File::Serialize::Serializer::Markdown](https://metacpan.org/pod/File::Serialize::Serializer::Markdown)

# OPTIONS

_File::Serialize_ recognizes a set of options that, if applicable,
will be passed to the serializer.

- format => $serializer

    Explicitly provides the serializer to use.

    ```perl
    my $data = deserialize_file $path, { format => 'json' };
    ```

- add\_extension => $boolean

    If true, the canonical extension of the serializing format will be
    appended to the file. Requires the parameter `format` to be given as well.

    ```perl
    # will create 'foo.yml', 'foo.json' and 'foo.toml'
    serialize_file 'foo', $data, { format => $_, add_extension => 1 }
        for qw/ yaml json toml /;
    ```

- pretty => $boolean

    The serialization will be formatted for human consumption.

- canonical => $boolean

    Serializes the data using its canonical representation.

- utf8 => $boolean

    If set to a `true` value, file will be read/written out using [Path::Tiny](https://metacpan.org/pod/Path::Tiny)'s `slurp_utf8` and `spew_utf8`
    method ( which sets a `binmode` of `:encoding(UTF-8)`). Otherwise,
    [Path::Tiny](https://metacpan.org/pod/Path::Tiny)'s `slurp` and `spew` methods are used.

    Defaults to being `true` because, after all, this is the twenty-first century.

- allow\_nonref => $boolean

    If set to true, allow to serialize non-ref data.

    Defaults to `true`.

# FUNCTIONS

## serialize\_file $path, $data, $options

```perl
my $data = { foo => 'bar' };

serialize_file '/path/to/file.json' => $data;
```

If the `$path` is '`-`', the serialized data will be printed
to STDOUT. If it a scalar ref, the serialized data will be assigned
to that variable.

```perl
serialize_file \my $serialized => $data;

print $serialized;
```

## deserialize\_file $path, $options

```perl
my $data = deserialize_file '/path/to/file.json';
```

If the `$path` is '`-`', the serialized data will be read from
STDIN. If it a scalar ref, the serialized data will be read
from that variable.

```perl
my $json = '{"foo":1}';
my $data = deserialize_file \$json;
```

## transerialize\_file $input, @transformation\_chain

`transerialize_file` is a convenient wrapper that allows you to
deserialize a file, apply any number of transformations to its
content and re-serialize the result.

`$input` can be a filename, a [Path::Tiny](https://metacpan.org/pod/Path::Tiny) object or the raw data
structure to be worked on.

```perl
transerialize_file 'foo.json' => 'foo.yaml';

# equivalent to
serialize_file 'foo.yaml' => deserialize_file 'foo.json'
```

Each element of the `@transformation_chain` can be

- $coderef

    A transformation step. The current data is available both via `$_` and
    as the first argument to the sub,
    and the transformed data is going to be whatever the sub returns.

    ```perl
    my $data = {
        tshirt => { price => 18 },
        hoodie => { price => 50 },
    };

    transerialize_file $data => sub {
        my %inventory = %$_;

        +{ %inventory{ grep { $inventory{$_}{price} <= 20 } keys %inventory } }

    } => 'inexpensive.json';

    # chaining transforms
    transerialize_file $data
        => sub {
            my %inventory = %$_;
            +{ map { $_ => $inventory{$_}{price} } keys %inventory } }
        => sub {
            my %inventory = %$_;
            +{ %inventory{ grep { $inventory{$_} <= 20 } keys %inventory } }
        } => 'inexpensive.json';

    # same as above, but with Perl 5.20 signatures and List::Util pair*
    # helpers
    transerialize_file $data
        => sub($inventory) { +{ pairmap  { $a => $b->{price} } %$inventory } }
        => sub($inventory) { +{ pairgrep { $b <= 20 }          %$inventory } }
        => 'inexpensive.json';
    ```

    If you prefer to have your transform functions modify the structure in-place
    in `$_` and don't want to have to explicitly return it, you can set
    the global variable `$File::Serialize::implicit_transform` to `true`.
    WARNING: this changes the behavior of ALL transforms.

- \\%destinations

    A hashref of destination file with their options. The current state of the data will
    be serialized to those destination. If no options need to be passed, the
    value can be `undef`.

    ```perl
    transerialize_file $data => {
        'beginning.json' => { pretty => 1 },
        'beginning.yml'  => undef
    } => sub { ... } => {
        'end.json' => { pretty => 1 },
        'end.yml'  => undef
    };
    ```

- \[ \\@subchain1, \\@subchain2, ... \]

    Run the subchains given in `@branches` on the current data. Must be the last
    step of the chain.

    ```perl
    my @data = 1..10;

    transerialize_file \@data
        => { 'all.json' => undef }
        => [
           [ sub { [ grep { $_ % 2 } @$_ ] }     => 'odd.json'  ],
           [ sub { [ grep { not $_ % 2 } @$_ ] } => 'even.json' ],
        ];
    ```

- ( $filename, $options )

    Has to be the final step(s) of the chain. Just like the arguments
    of `serialize_file`. `$filename` can be a string or a [Path::Tiny](https://metacpan.org/pod/Path::Tiny) object.
    `$options` is optional.

- \\$result

    Has to be the final step of the chain. Will assign the transformed data
    to `$result` instead of serializing to a file.

# ADDING A SERIALIZER

Serializers are added by creating a `File::Serialize::Serializer::*` class that
implement the [File::Serialize::Serializer](https://metacpan.org/pod/File::Serialize::Serializer) role. See the documentation for the
role for more details.

# AUTHOR

Yanick Champoux <yanick@cpan.org> [![endorse](http://api.coderwall.com/yanick/endorsecount.png)](http://coderwall.com/yanick)

# COPYRIGHT AND LICENSE

This software is copyright (c) 2021, 2019, 2017, 2016, 2015 by Yanick Champoux.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.