From 29716aa141f00bc8cbf7b3ce04a0ff278a594390 Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Tue, 14 Nov 2023 11:45:06 -0500 Subject: [PATCH] documentation --- Taskfile.yaml | 4 +- lib/Dancer2/Plugin/JsonApi/Registry.pm | 25 -------- lib/Dancer2/Plugin/JsonApi/Registry.pod | 23 +++++++ lib/Dancer2/Plugin/JsonApi/Schema.pm | 34 +--------- lib/Dancer2/Plugin/JsonApi/Schema.pod | 64 +++++++++++++++++++ lib/Dancer2/Serializer/JsonApi.pm | 85 +++++++++++++++++++++++++ xt/added-test.t | 15 +++-- 7 files changed, 184 insertions(+), 66 deletions(-) create mode 100644 lib/Dancer2/Plugin/JsonApi/Registry.pod create mode 100644 lib/Dancer2/Plugin/JsonApi/Schema.pod diff --git a/Taskfile.yaml b/Taskfile.yaml index 257d731..783a03c 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -7,9 +7,9 @@ vars: TARGET_BRANCH: main tasks: - pretty: + tidy: 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: cmds: diff --git a/lib/Dancer2/Plugin/JsonApi/Registry.pm b/lib/Dancer2/Plugin/JsonApi/Registry.pm index b1a1c6a..d170dd5 100644 --- a/lib/Dancer2/Plugin/JsonApi/Registry.pm +++ b/lib/Dancer2/Plugin/JsonApi/Registry.pm @@ -9,18 +9,6 @@ use Moo; 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 = {} ) { return $self->type($type)->serialize( $data, $extra_data ); } @@ -32,12 +20,6 @@ has types => ( has app => ( is => 'ro', ); -=head2 add_type($type, $definition = {}) - -Adds a data type to the registry. - -=cut - sub add_type ( $self, $type, $definition = {} ) { $self->{types}{$type} = Dancer2::Plugin::JsonApi::Schema->new( registry => $self, @@ -46,13 +28,6 @@ sub add_type ( $self, $type, $definition = {} ) { ); } -=head2 type($type) - -Returns the type's C. Throws an -error if the type does not exist. - -=cut - sub type ( $self, $type ) { return $self->types->{$type} //= Dancer2::Plugin::JsonApi::Schema->new( type => $type ); diff --git a/lib/Dancer2/Plugin/JsonApi/Registry.pod b/lib/Dancer2/Plugin/JsonApi/Registry.pod new file mode 100644 index 0000000..e18b346 --- /dev/null +++ b/lib/Dancer2/Plugin/JsonApi/Registry.pod @@ -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. Throws an +error if the type does not exist. + +=cut + +=head2 serialize($type,$data,$extra_data={}) + +Returns the serialized form of C<$data>. + +=cut diff --git a/lib/Dancer2/Plugin/JsonApi/Schema.pm b/lib/Dancer2/Plugin/JsonApi/Schema.pm index 1ae6c40..c9d4538 100644 --- a/lib/Dancer2/Plugin/JsonApi/Schema.pm +++ b/lib/Dancer2/Plugin/JsonApi/Schema.pm @@ -9,26 +9,13 @@ use List::AllUtils qw/ pairmap pairgrep /; use Set::Object qw/set/; -=head1 ATTRIBUTES - -=head2 type - -The JSON:API object type. Required. - -=cut +has registry => ( is => 'ro' ); has type => ( required => 1, is => 'ro', ); -=head2 id - -Key to use as a reference to the object. Defaults to C. Can be a string, - or a function that will be passed the original data object. - -=cut - has id => ( is => 'ro', default => 'id' @@ -39,17 +26,8 @@ has top_level_links => ( is => 'ro' ); has top_level_meta => ( is => 'ro' ); has relationships => ( is => 'ro', default => sub { +{} } ); -has registry => ( is => 'ro' ); has allowed_attributes => ( is => 'ro' ); - -=head1 METHODS - -=head2 top_level_serialize($data,$extra_data = {}) - -Serializes C<$data> as a top-level -JSON:API object. - -=cut +has before_serialize => ( is => 'ro' ); sub serialize ( $self, $data, $extra_data = {} ) { @@ -84,12 +62,6 @@ sub dedupe_included { return grep { not $seen{ $_->{type} }{ $_->{id} }++ } @_; } -=head2 serialize_data($data,$extra_data) - -Serializes the inner C<$data>. - -=cut - has attributes => ( is => 'ro', default => sub { @@ -104,8 +76,6 @@ has attributes => ( } ); -has before_serialize => ( is => 'ro' ); - sub serialize_data ( $self, $data, $extra_data = {}, $included = undef ) { return [ map { $self->serialize_data( $_, $extra_data, $included ) } diff --git a/lib/Dancer2/Plugin/JsonApi/Schema.pod b/lib/Dancer2/Plugin/JsonApi/Schema.pod new file mode 100644 index 0000000..52ca1cf --- /dev/null +++ b/lib/Dancer2/Plugin/JsonApi/Schema.pod @@ -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 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. + +=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>. diff --git a/lib/Dancer2/Serializer/JsonApi.pm b/lib/Dancer2/Serializer/JsonApi.pm index 074b7cd..3bdf91e 100644 --- a/lib/Dancer2/Serializer/JsonApi.pm +++ b/lib/Dancer2/Serializer/JsonApi.pm @@ -1,5 +1,53 @@ 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 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; use Dancer2::Plugin::JsonApi::Registry; @@ -7,20 +55,49 @@ use Dancer2::Serializer::JSON; use Moo; +=head1 ATTRIBUTES + +=head2 content_type + +Returns the content type used by the serializer, which is C; + +=cut + has content_type => ( is => 'ro', default => 'application/vnd.api+json' ); with 'Dancer2::Core::Role::Serializer'; +=head2 registry + +The L to use. + +=cut + has registry => ( is => 'rw', default => sub { Dancer2::Plugin::JsonApi::Registry->new } ); +=head2 json_serializer + +The underlying JSON serializer. Defaults to L. + +=cut + has json_serializer => ( is => 'ro', 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 { my ( $self, $data ) = @_; @@ -28,6 +105,14 @@ sub serialize { $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 { ... } 1; diff --git a/xt/added-test.t b/xt/added-test.t index ce2edca..b118594 100644 --- a/xt/added-test.t +++ b/xt/added-test.t @@ -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 Test2::V0; @@ -10,13 +13,11 @@ my $git = Git::Wrapper->new('.'); my $on_target = grep { "* $target_branch" eq $_ } $git->branch; -if ($on_target) { - pass "nothing to check here"; -} -else { - my @diff = $git->diff($target_branch); - ok test_file_modified(@diff), "added to a test file"; -} +skip_all "already on target branch" if $on_target; + +skip_all "manually disabled" if $ENV{NO_NEW_TEST}; + +ok test_file_modified( $git->diff($target_branch) ), "added to a test file"; sub test_file_modified (@diff) { my $in_test_file = 0;