Merge branch 'documentation'

This commit is contained in:
Yanick Champoux 2023-11-15 09:42:04 -05:00
commit cf0a37de7f
10 changed files with 202 additions and 67 deletions

3
.gitignore vendored
View File

@ -1,5 +1,8 @@
.test_info.*
lastlog.jsonl
*.bak *.bak
lab lab
.envrc .envrc
*.orig *.orig
*.tdy *.tdy
*.ERR

View File

@ -7,9 +7,9 @@ vars:
TARGET_BRANCH: main TARGET_BRANCH: main
tasks: tasks:
pretty: tidy:
cmds: cmds:
- git diff-ls --diff-filter=ACMR {{.TARGET_BRANCH}} | grep -e '\.pm$\|\.t$' | xargs -IX perltidy -b X - git diff-ls --diff-filter=ACMR {{.TARGET_BRANCH}} | grep -e '\.pm$\|\.t$|\.pod$' | xargs -IX perltidy -b X
default: default:
cmds: cmds:

View File

@ -9,18 +9,6 @@ use Moo;
use experimental qw/ signatures /; use experimental qw/ signatures /;
=head1 DESCRIPTION
The registry for the different types of data managed by the plugin.
=head1 METHODS
=head2 serialize($type,$data,$extra_data={})
Returns the serialized form of C<$data>.
=cut
sub serialize ( $self, $type, $data, $extra_data = {} ) { sub serialize ( $self, $type, $data, $extra_data = {} ) {
return $self->type($type)->serialize( $data, $extra_data ); return $self->type($type)->serialize( $data, $extra_data );
} }
@ -32,12 +20,6 @@ has types => (
has app => ( is => 'ro', ); has app => ( is => 'ro', );
=head2 add_type($type, $definition = {})
Adds a data type to the registry.
=cut
sub add_type ( $self, $type, $definition = {} ) { sub add_type ( $self, $type, $definition = {} ) {
$self->{types}{$type} = Dancer2::Plugin::JsonApi::Schema->new( $self->{types}{$type} = Dancer2::Plugin::JsonApi::Schema->new(
registry => $self, registry => $self,
@ -46,13 +28,6 @@ sub add_type ( $self, $type, $definition = {} ) {
); );
} }
=head2 type($type)
Returns the type's C<Dancer2::Plugin::JsonApi::Schema>. Throws an
error if the type does not exist.
=cut
sub type ( $self, $type ) { sub type ( $self, $type ) {
return $self->types->{$type} //= return $self->types->{$type} //=
Dancer2::Plugin::JsonApi::Schema->new( type => $type ); Dancer2::Plugin::JsonApi::Schema->new( type => $type );

View File

@ -0,0 +1,23 @@
=head1 DESCRIPTION
The registry for the different types of data managed by the plugin.
=head1 METHODS
=head2 add_type($type, $definition = {})
Adds a data type to the registry.
=head2 type($type)
Returns the type's C<Dancer2::Plugin::JsonApi::Schema>. Throws an
error if the type does not exist.
=cut
=head2 serialize($type,$data,$extra_data={})
Returns the serialized form of C<$data>.
=cut

View File

@ -9,26 +9,13 @@ use List::AllUtils qw/ pairmap pairgrep /;
use Set::Object qw/set/; use Set::Object qw/set/;
=head1 ATTRIBUTES has registry => ( is => 'ro' );
=head2 type
The JSON:API object type. Required.
=cut
has type => ( has type => (
required => 1, required => 1,
is => 'ro', is => 'ro',
); );
=head2 id
Key to use as a reference to the object. Defaults to C<id>. Can be a string,
or a function that will be passed the original data object.
=cut
has id => ( has id => (
is => 'ro', is => 'ro',
default => 'id' default => 'id'
@ -39,17 +26,8 @@ has top_level_links => ( is => 'ro' );
has top_level_meta => ( is => 'ro' ); has top_level_meta => ( is => 'ro' );
has relationships => ( is => 'ro', default => sub { +{} } ); has relationships => ( is => 'ro', default => sub { +{} } );
has registry => ( is => 'ro' );
has allowed_attributes => ( is => 'ro' ); has allowed_attributes => ( is => 'ro' );
has before_serialize => ( is => 'ro' );
=head1 METHODS
=head2 top_level_serialize($data,$extra_data = {})
Serializes C<$data> as a top-level
JSON:API object.
=cut
sub serialize ( $self, $data, $extra_data = {} ) { sub serialize ( $self, $data, $extra_data = {} ) {
@ -84,12 +62,6 @@ sub dedupe_included {
return grep { not $seen{ $_->{type} }{ $_->{id} }++ } @_; return grep { not $seen{ $_->{type} }{ $_->{id} }++ } @_;
} }
=head2 serialize_data($data,$extra_data)
Serializes the inner C<$data>.
=cut
has attributes => ( has attributes => (
is => 'ro', is => 'ro',
default => sub { default => sub {
@ -104,8 +76,6 @@ has attributes => (
} }
); );
has before_serialize => ( is => 'ro' );
sub serialize_data ( $self, $data, $extra_data = {}, $included = undef ) { sub serialize_data ( $self, $data, $extra_data = {}, $included = undef ) {
return [ map { $self->serialize_data( $_, $extra_data, $included ) } return [ map { $self->serialize_data( $_, $extra_data, $included ) }

View File

@ -0,0 +1,64 @@
=head1 DESCRIPTION
Defines a type of object to serialize/deserialize from/to the
JSON:API format.
=head1 ATTRIBUTES
=head2 registry
L<Dancer2::Plugin::JsonApi::Registry> to use to find the definition of
other object types.
=head2 before_serialize
Accepts a function, which will be called on the original C<$data> to serialize
to groom it.
before_serialize => sub($data,$xtra) {
# lowercase all keys
return +{ pairmap { lc($a) => $b } %$data }
}
=head2 type
The JSON:API object type. Read-only, required.
=head2 id
Key to use as a reference to the object. Can be a string,
or a function that will be passed the original data object.
Read-only, defaults to the string C<id>.
=head2 links
Links to include as part of the object.
=head2 top_level_links
Links to include to the serialized top level, if the top level object
is of the type defined by this class.
=head2 top_level_meta
Meta information to include to the serialized top level, if the top level object
is of the type defined by this class.
=head2 relationships
Relationships for the object type.
=head2 allowed_attributes
List of attributes that can be serialized/deserialized.
=head1 METHODS
=head2 top_level_serialize($data,$extra_data = {})
Serializes C<$data> as a top-level JSON:API object.
=head2 serialize_data($data,$extra_data)
Serializes the inner C<$data>.

View File

@ -1,5 +1,53 @@
use 5.38.0; use 5.38.0;
=head1 DESCRIPTION
Serializer for JSON:API. Takes in a data structure, munge it to conforms to the JSON:API format (potentially based on a provided registry of JSON:API schemas),
and encode it as JSON.
Note that using Dancer2::Plugin::JsonApi in an app will automatically
set C<Dancer2::Serializer::JsonApi> as its serializer if it's not already defined.
=head1 SYNOPSIS
As part of a Dancer2 App:
# in config.yaml
serializer: JsonApi
As a standalone module:
use Dancer2::Serializer::JsonApi;
use Dancer2::Plugin::JsonApi::Registry;
my $registry = Dancer2::Plugin::JsonApi::Registry->new;
$registry->add_type( 'spaceship' => {
relationships => {
crew => { type => 'person' }
}
} );
$registry->add_type( 'person' );
my $serializer = Dancer2::Serializer::JsonApi->new(
registry => $registry
);
my $serialized = $serializer->serialize([
'spaceship', {
id => 1,
name => 'Unrequited Retribution',
crew => [
{ id => 2, name => 'One-eye Flanagan', species => 'human' },
{ id => 3, name => 'Flabgor', species => 'Moisterian' },
]
}
]);
=cut
package Dancer2::Serializer::JsonApi; package Dancer2::Serializer::JsonApi;
use Dancer2::Plugin::JsonApi::Registry; use Dancer2::Plugin::JsonApi::Registry;
@ -7,20 +55,49 @@ use Dancer2::Serializer::JSON;
use Moo; use Moo;
=head1 ATTRIBUTES
=head2 content_type
Returns the content type used by the serializer, which is C<application/vnd.api+json>;
=cut
has content_type => ( is => 'ro', default => 'application/vnd.api+json' ); has content_type => ( is => 'ro', default => 'application/vnd.api+json' );
with 'Dancer2::Core::Role::Serializer'; with 'Dancer2::Core::Role::Serializer';
=head2 registry
The L<Dancer2::Plugin::JsonApi::Registry> to use.
=cut
has registry => ( has registry => (
is => 'rw', is => 'rw',
default => sub { Dancer2::Plugin::JsonApi::Registry->new } default => sub { Dancer2::Plugin::JsonApi::Registry->new }
); );
=head2 json_serializer
The underlying JSON serializer. Defaults to L<Dancer2::Serializer::JSON>.
=cut
has json_serializer => ( has json_serializer => (
is => 'ro', is => 'ro',
default => sub { Dancer2::Serializer::JSON->new } default => sub { Dancer2::Serializer::JSON->new }
); );
=head1 METHODS
=head2 $self->serialize( [ $type, $data, $xtra ])
Serializes the C<$data> using the C<$type> from the registry.
The returned value will be a JSON string.
=cut
sub serialize { sub serialize {
my ( $self, $data ) = @_; my ( $self, $data ) = @_;
@ -28,6 +105,14 @@ sub serialize {
$self->registry->serialize(@$data) ); $self->registry->serialize(@$data) );
} }
=head2 $self->deserialize( $json_string )
Takes in the serialized C<$json_string> and recreate data out of it.
UNIMPLENTED
=cut
sub deserialize { ... } sub deserialize { ... }
1; 1;

View File

@ -1,3 +1,6 @@
# verifies that at least one test file has been modified
# (the goal being that one test has been added or altered)
use 5.38.0; use 5.38.0;
use Test2::V0; use Test2::V0;
@ -10,13 +13,11 @@ my $git = Git::Wrapper->new('.');
my $on_target = grep { "* $target_branch" eq $_ } $git->branch; my $on_target = grep { "* $target_branch" eq $_ } $git->branch;
if ($on_target) { skip_all "already on target branch" if $on_target;
pass "nothing to check here";
} skip_all "manually disabled" if $ENV{NO_NEW_TEST};
else {
my @diff = $git->diff($target_branch); ok test_file_modified( $git->diff($target_branch) ), "added to a test file";
ok test_file_modified(@diff), "added to a test file";
}
sub test_file_modified (@diff) { sub test_file_modified (@diff) {
my $in_test_file = 0; my $in_test_file = 0;

View File

@ -17,7 +17,9 @@ if ($on_target) {
else { else {
my @files = my @files =
$git->diff( { name_only => 1, diff_filter => 'ACMR' }, $target_branch ); $git->diff( { name_only => 1, diff_filter => 'ACMR' }, $target_branch );
ok Test::PerlTidy::is_file_tidy($_), $_ for @files; ok Test::PerlTidy::is_file_tidy($_), $_
for grep { /\.(pl|pm|pod|t)$/ } @files;
} }
done_testing; done_testing;

12
xt/worktree-clean.t Normal file
View File

@ -0,0 +1,12 @@
use Test2::V0;
use Git::Wrapper;
my $git = Git::Wrapper->new('.');
my $status = $git->status;
# note: 'yath' might create .test_info and lastlog.jsonl files
ok !$status->is_dirty => "worktree is clean";
done_testing;