Skip to content

Commit

Permalink
Initial implementation of Cucumber messages for Perl (#1670)
Browse files Browse the repository at this point in the history
* Initial commit for Perl implementation of cucumber messages

* Add messages-perl to the build and release infrastructure

* Add README.md and update CHANGELOG.md

[skip ci]

* Add documentation to Cucumber::Messages

Since Cucumber::Messages has been appointed the "main module", its
documentation will be shown on the "homepage" of the dist on
metacpan.org. So, try to provide the minimal set of generally expected
documentation sections for a Perl dist.

* Enable author tests when running `make test`

* Set up synchronization of shared build infrastructure

* Reduce chances of unversioned files included in the dist

The `GatherDir` (default) plugin doesn't know about versioned or unversioned
files. `Git::GatherDir` does and only includes versioned files, unless
explicitly instructed differently (both about in- as well as exclusion).

* After review, add Cucumber Ltd to the list of copyright holders

* Complete documentation of Cucumber::Messages::Message

Co-authored-by: Erik Huelsmann <[email protected]>
Co-authored-by: Aslak Hellesøy <[email protected]>
  • Loading branch information
3 people authored Sep 1, 2021
1 parent 1aa6431 commit 48bc4a3
Show file tree
Hide file tree
Showing 21 changed files with 5,859 additions and 2 deletions.
15 changes: 15 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,17 @@ jobs:
cd gherkin/perl
make
messages-perl:
executor: docker-cucumber-build
steps:
- attach_workspace:
at: '~/cucumber'
- run:
name: messages/perl
command: |
cd messages/perl
make
### Python

tag-expressions-python:
Expand Down Expand Up @@ -1133,6 +1144,10 @@ workflows:
requires:
- prepare-parallel

- messages-perl:
requires:
- prepare-parallel

## Python

- tag-expressions-python:
Expand Down
4 changes: 4 additions & 0 deletions messages/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

* Initial Perl implementation
([#1670](https://github.com/cucumber/common/pull/1670) [ehuelsmann])

### Changed

### Deprecated
Expand Down Expand Up @@ -620,6 +623,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
[brasmusson]: https://github.com/brasmusson
[charlierudolph]: https://github.com/charlierudolph
[david1995]: https://github.com/david1995
[ehuelsmann]: https://github.com/ehuelsmann
[luke-hill]: https://github.com/luke-hill
[mpkorstanje]: https://github.com/mpkorstanje
[mvz]: https://github.com/mvz
Expand Down
4 changes: 2 additions & 2 deletions messages/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
LANGUAGES ?= jsonschema javascript go java ruby python
LANGUAGES ?= jsonschema javascript go java ruby python perl

include default.mk
include default.mk
53 changes: 53 additions & 0 deletions messages/jsonschema/scripts/codegen.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,59 @@ def array_type_for(type_name)
end
end

class Perl < Codegen
def initialize(paths, template_file_name: 'perl.pm.erb')
template = File.read("#{TEMPLATES_DIRECTORY}/#{template_file_name}")
enum_template = File.read("#{TEMPLATES_DIRECTORY}/perl.enum.pm.erb")

language_type_by_schema_type = {
'integer' => 'number',
'string' => 'string',
'boolean' => 'boolean',
}

super(paths, template, enum_template, language_type_by_schema_type)
end

def array_type_for(type_name)
"[]#{type_name}"
end

def default_value(parent_type_name, property_name, property)
if property['type'] == 'string'
if property['enum']
"#{property_name.upcase}_#{enum_constant(property['enum'][0])}"
else
"''"
end
elsif property['type'] == 'boolean'
"''" # an empty string renders evaluates to false
elsif property['$ref']
type = type_for(parent_type_name, nil, property)
"#{type}->new()"
else
super(parent_type_name, property_name, property)
end
end

def property_type_from_ref(ref)
"Cucumber::Messages::#{class_name(ref)}"
end

def property_type_from_enum(enum)
''
end

def format_description(raw_description)
return '' if raw_description.nil?

raw_description
.split("\n")
.map { |description_line| "#{description_line}" }
.join("\n")
end
end

class Ruby < Codegen
def initialize(paths, template_file_name: 'ruby.rb.erb')
template = File.read("#{TEMPLATES_DIRECTORY}/#{template_file_name}")
Expand Down
Empty file.
146 changes: 146 additions & 0 deletions messages/jsonschema/scripts/templates/perl.pm.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package Cucumber::Messages;

# DO NOT CHANGE THIS FILE!!

# The code was auto-generated by this script:
# https://github.com/cucumber/common/blob/main/messages/jsonschema/scripts/codegen.rb

=head1 NAME

Cucumber::Messages - Library of classes to encapsulate Cucumber messages

=head1 SYNOPSIS

use Cucumber::Messages;

my $loc = Cucumber::Messages::Location->new(
line => 12, column => 26
);
my $loc_json = $loc->to_json;

my $envelope = Cucumber::Messages::Envelope->from_json($serialized_envelope);

=head1 DESCRIPTION

L<Cucumber messages|https://github.com/cucumber/common/tree/main/messages>
define the central protocol in the Cucumber ecosystem by which the various
components communicate. Messages are serialized to NDJSON.

This library provides both serialization/deserialization to/from NDJSON as
well as the in-memory representation of the messages for Perl applications.

Each serialized message should be wrapped in a C<Cucumber::Messages::Envelope>
and can thereby be deserialized by calling the C<from_json> class message
with the serialized representation as its argument, like shown in the SYNOPSIS.

=cut

use strict;
use warnings;

use Cucumber::Messages::Message;

=head1 MESSAGE CLASSES

=cut

<%- @schemas.sort.each do |key, schema| %>

package Cucumber::Messages::<%= class_name(key) %> {

=head2 Cucumber::Messages::<%= class_name(key) %>

=head3 DESCRIPTION

Represents the <%= class_name(key) %> message in Cucumber's
L<message protocol|https://github.com/cucumber/common/tree/main/messages#readme>.

<%= format_description(schema['description']) %>

=head3 ATTRIBUTES

=cut

use Moo;
extends 'Cucumber::Messages::Message';

use Scalar::Util qw( blessed );

my %types = (
<%- schema['properties'].each do |property_name, property| -%>
<%= underscore(property_name) %> => '<%= type_for(class_name(key), property_name, property) %>',
<%- end -%>
);

# This is a work-around for the fact that Moo doesn't have introspection
# and Perl doesn't have boolean values...
sub _types {
return \%types;
}


<%- schema['properties'].each do |property_name, property| -%>

=head4 <%= underscore(property_name) %>

<%- if property['description'] -%>
<%= format_description(property['description']) %>
<%- end -%>

<% if property['enum'] -%>

Available constants for valid values of this field:

=over

<%- property['enum'].to_a.each_with_index do |value, index| -%>
=item * <%= property_name.upcase %>_<%= enum_constant(value) %>

<%- end -%>
=back

<% end -%>
=cut

<% if property['enum'] -%>

use constant
<%- property['enum'].to_a.each_with_index do |value, index| -%>
<%= property_name.upcase %>_<%= enum_constant(value) %> => '<%= value %>',
<%- end -%>
;

<% end -%>
has <%= underscore(property_name) %> =>
(is => 'ro',
<%- if (schema['required'] || []).index(property_name) -%>
required => 1,
<%- if default_value(class_name(key), property_name, property) -%>
default => sub { <%= default_value(class_name(key), property_name, property) %> },
<%- end -%>
<%- end -%>
);

<%- end %>
}<%- end -%>


1;

__END__

=head1 LICENSE

Please see the included LICENSE for the canonical version. In summary:

The MIT License (MIT)

Copyright (c) 2021 Erik Huelsmann
Copyright (c) 2021 Cucumber Ltd

This work is loosely derived from prior work of the same library for Ruby,
called C<cucumber-messages>.

=cut


3 changes: 3 additions & 0 deletions messages/perl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
perl5/
.*
*~
1 change: 1 addition & 0 deletions messages/perl/.rsync
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
../../.templates/perl/ .
Loading

0 comments on commit 48bc4a3

Please sign in to comment.