Merge branch 'documentation'
This commit is contained in:
commit
cf0a37de7f
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,5 +1,8 @@
|
|||||||
|
.test_info.*
|
||||||
|
lastlog.jsonl
|
||||||
*.bak
|
*.bak
|
||||||
lab
|
lab
|
||||||
.envrc
|
.envrc
|
||||||
*.orig
|
*.orig
|
||||||
*.tdy
|
*.tdy
|
||||||
|
*.ERR
|
||||||
|
@ -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:
|
||||||
|
@ -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 );
|
||||||
|
23
lib/Dancer2/Plugin/JsonApi/Registry.pod
Normal file
23
lib/Dancer2/Plugin/JsonApi/Registry.pod
Normal 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
|
@ -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 ) }
|
||||||
|
64
lib/Dancer2/Plugin/JsonApi/Schema.pod
Normal file
64
lib/Dancer2/Plugin/JsonApi/Schema.pod
Normal 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>.
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
12
xt/worktree-clean.t
Normal 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;
|
Loading…
Reference in New Issue
Block a user