Skip to content

Commit c7e424f

Browse files
authored
Merge pull request #3 from json-structure/perl-sdk
feat(perl): Add complete Perl SDK implementation
2 parents 2b8537c + 4361aab commit c7e424f

25 files changed

Lines changed: 10514 additions & 0 deletions

.github/workflows/perl.yml

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
name: Perl SDK
2+
3+
on:
4+
push:
5+
branches: [master, main]
6+
paths:
7+
- 'perl/**'
8+
- 'meta/**'
9+
- 'test-assets/**'
10+
- '.github/workflows/perl.yml'
11+
tags:
12+
- 'v[0-9]+.[0-9]+.[0-9]+'
13+
pull_request:
14+
branches: [master, main]
15+
paths:
16+
- 'perl/**'
17+
- 'meta/**'
18+
- 'test-assets/**'
19+
- '.github/workflows/perl.yml'
20+
21+
jobs:
22+
test:
23+
name: Test Perl ${{ matrix.perl-version }} (${{ matrix.json-backend }}) on ${{ matrix.os }}
24+
runs-on: ${{ matrix.os }}
25+
strategy:
26+
fail-fast: false
27+
matrix:
28+
os: [ubuntu-latest, macos-latest, windows-latest]
29+
perl-version: ['5.20', '5.26', '5.32', '5.38']
30+
json-backend: ['JSON::PP', 'Cpanel::JSON::XS']
31+
exclude:
32+
# Windows perl setup can be slow, test fewer versions
33+
- os: windows-latest
34+
perl-version: '5.20'
35+
- os: windows-latest
36+
perl-version: '5.26'
37+
# XS modules can be tricky on Windows, test only with PP
38+
- os: windows-latest
39+
json-backend: 'Cpanel::JSON::XS'
40+
41+
steps:
42+
- uses: actions/checkout@v4
43+
with:
44+
submodules: recursive
45+
46+
- name: Set up Perl ${{ matrix.perl-version }}
47+
uses: shogo82148/actions-setup-perl@v1
48+
with:
49+
perl-version: ${{ matrix.perl-version }}
50+
51+
- name: Install dependencies
52+
working-directory: perl
53+
run: |
54+
cpanm --installdeps --notest .
55+
56+
- name: Install JSON backend (${{ matrix.json-backend }})
57+
if: matrix.json-backend != 'JSON::PP'
58+
run: |
59+
cpanm --notest ${{ matrix.json-backend }}
60+
61+
- name: Run tests
62+
working-directory: perl
63+
run: |
64+
prove -l -v t/
65+
66+
- name: Run tests with coverage
67+
if: matrix.perl-version == '5.38' && matrix.os == 'ubuntu-latest'
68+
working-directory: perl
69+
run: |
70+
cpanm --notest Devel::Cover Devel::Cover::Report::Clover
71+
perl Makefile.PL
72+
HARNESS_PERL_SWITCHES=-MDevel::Cover prove -l t/
73+
cover -report text
74+
75+
lint:
76+
name: Perl Critic
77+
runs-on: ubuntu-latest
78+
79+
steps:
80+
- uses: actions/checkout@v4
81+
with:
82+
submodules: recursive
83+
84+
- name: Set up Perl
85+
uses: shogo82148/actions-setup-perl@v1
86+
with:
87+
perl-version: '5.38'
88+
89+
- name: Install Perl::Critic
90+
run: cpanm --notest Perl::Critic
91+
92+
- name: Run Perl::Critic (gentle)
93+
working-directory: perl
94+
run: |
95+
perlcritic --gentle lib/ || true
96+
continue-on-error: true
97+
98+
build:
99+
name: Build distribution
100+
runs-on: ubuntu-latest
101+
needs: test
102+
103+
steps:
104+
- uses: actions/checkout@v4
105+
with:
106+
submodules: recursive
107+
108+
- name: Set up Perl
109+
uses: shogo82148/actions-setup-perl@v1
110+
with:
111+
perl-version: '5.38'
112+
113+
- name: Install build dependencies
114+
working-directory: perl
115+
run: |
116+
cpanm --notest ExtUtils::MakeMaker Module::Build
117+
cpanm --installdeps --notest .
118+
119+
- name: Build distribution
120+
working-directory: perl
121+
run: |
122+
perl Makefile.PL
123+
make
124+
make manifest
125+
make dist
126+
127+
- name: Verify distribution
128+
working-directory: perl
129+
run: |
130+
# Find the tarball
131+
TARBALL=$(ls JSON-Structure-*.tar.gz 2>/dev/null | head -1)
132+
if [ -n "$TARBALL" ]; then
133+
echo "Built: $TARBALL"
134+
tar -tzf "$TARBALL" | head -20
135+
else
136+
echo "No tarball found, creating with make dist"
137+
make dist
138+
fi
139+
140+
- name: Upload build artifacts
141+
uses: actions/upload-artifact@v4
142+
with:
143+
name: perl-distribution
144+
path: perl/JSON-Structure-*.tar.gz
145+
146+
# CPAN publishing is typically done manually or via PAUSE
147+
# This job prepares the distribution for upload
148+
prepare-cpan:
149+
name: Prepare for CPAN
150+
runs-on: ubuntu-latest
151+
needs: build
152+
if: startsWith(github.ref, 'refs/tags/v')
153+
154+
steps:
155+
- uses: actions/checkout@v4
156+
with:
157+
submodules: recursive
158+
159+
- name: Set up Perl
160+
uses: shogo82148/actions-setup-perl@v1
161+
with:
162+
perl-version: '5.38'
163+
164+
- name: Install dependencies
165+
run: |
166+
cpanm --notest ExtUtils::MakeMaker Test::More Test::Deep
167+
168+
- name: Extract version from tag
169+
id: version
170+
run: |
171+
VERSION=${GITHUB_REF#refs/tags/v}
172+
echo "version=$VERSION" >> $GITHUB_OUTPUT
173+
174+
- name: Update version in modules
175+
working-directory: perl
176+
run: |
177+
VERSION=${{ steps.version.outputs.version }}
178+
# Update version in all .pm files
179+
find lib -name '*.pm' -exec sed -i "s/VERSION = '0.01'/VERSION = '$VERSION'/" {} \;
180+
181+
- name: Build final distribution
182+
working-directory: perl
183+
run: |
184+
perl Makefile.PL
185+
make
186+
make manifest
187+
make dist
188+
189+
- name: Upload CPAN-ready distribution
190+
uses: actions/upload-artifact@v4
191+
with:
192+
name: cpan-distribution
193+
path: perl/JSON-Structure-*.tar.gz
194+
195+
- name: Create release notes
196+
run: |
197+
echo "## Perl SDK v${{ steps.version.outputs.version }}" > release-notes.md
198+
echo "" >> release-notes.md
199+
echo "### Installation" >> release-notes.md
200+
echo "" >> release-notes.md
201+
echo "From CPAN (when available):" >> release-notes.md
202+
echo '```bash' >> release-notes.md
203+
echo "cpanm JSON::Structure" >> release-notes.md
204+
echo '```' >> release-notes.md
205+
echo "" >> release-notes.md
206+
echo "From this release:" >> release-notes.md
207+
echo '```bash' >> release-notes.md
208+
echo "cpanm JSON-Structure-${{ steps.version.outputs.version }}.tar.gz" >> release-notes.md
209+
echo '```' >> release-notes.md
210+
211+
- name: Upload release notes
212+
uses: actions/upload-artifact@v4
213+
with:
214+
name: release-notes
215+
path: release-notes.md
216+
217+
# Publish to CPAN via PAUSE
218+
# Requires PAUSE_USERNAME and PAUSE_PASSWORD secrets to be set
219+
publish-cpan:
220+
name: Publish to CPAN
221+
runs-on: ubuntu-latest
222+
needs: prepare-cpan
223+
if: startsWith(github.ref, 'refs/tags/v')
224+
environment: cpan # Use a protected environment for secrets
225+
226+
steps:
227+
- name: Download distribution
228+
uses: actions/download-artifact@v4
229+
with:
230+
name: cpan-distribution
231+
232+
- name: Set up Perl
233+
uses: shogo82148/actions-setup-perl@v1
234+
with:
235+
perl-version: '5.38'
236+
237+
- name: Install CPAN::Uploader
238+
run: cpanm --notest CPAN::Uploader
239+
240+
- name: Upload to CPAN
241+
env:
242+
CPAN_USERNAME: ${{ secrets.PAUSE_USERNAME }}
243+
CPAN_PASSWORD: ${{ secrets.PAUSE_PASSWORD }}
244+
run: |
245+
if [ -z "$CPAN_USERNAME" ] || [ -z "$CPAN_PASSWORD" ]; then
246+
echo "::warning::PAUSE credentials not configured. Skipping CPAN upload."
247+
echo "To enable CPAN publishing, set PAUSE_USERNAME and PAUSE_PASSWORD secrets."
248+
exit 0
249+
fi
250+
TARBALL=$(ls JSON-Structure-*.tar.gz | head -1)
251+
if [ -z "$TARBALL" ]; then
252+
echo "Error: No distribution tarball found"
253+
exit 1
254+
fi
255+
echo "Uploading $TARBALL to CPAN..."
256+
cpan-upload -u "$CPAN_USERNAME" -p "$CPAN_PASSWORD" "$TARBALL"
257+
echo "Successfully uploaded to CPAN!"

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ that can be validated and mapped to programming language types.
1515
| [TypeScript/JavaScript](./typescript/) | `json-structure` | ✅ Available |
1616
| [Go](./go/) | `github.com/json-structure/sdk/go` | ✅ Available |
1717
| [Rust](./rust/) | `json-structure` | ✅ Available |
18+
| [Perl](./perl/) | `JSON::Structure` | ✅ Available |
1819
| [C](./c/) | `json-structure` | ✅ Available |
1920

2021
## Features
@@ -204,6 +205,40 @@ func main() {
204205
}
205206
```
206207

208+
### Perl
209+
210+
```bash
211+
cpanm JSON::Structure
212+
```
213+
214+
```perl
215+
use JSON::Structure::SchemaValidator;
216+
use JSON::Structure::InstanceValidator;
217+
use JSON::MaybeXS;
218+
219+
# Define a schema
220+
my $schema = decode_json(q|{
221+
"$schema": "https://json-structure.org/meta/core/v0/#",
222+
"name": "Person",
223+
"type": "object",
224+
"properties": {
225+
"name": {"type": "string"},
226+
"age": {"type": "int32"}
227+
}
228+
}|);
229+
230+
# Validate the schema
231+
my $schema_validator = JSON::Structure::SchemaValidator->new();
232+
my $schema_result = $schema_validator->validate($schema);
233+
print "Schema valid: ", ($schema_result->is_valid ? "true" : "false"), "\n";
234+
235+
# Validate an instance
236+
my $instance = decode_json('{"name": "Alice", "age": 30}');
237+
my $instance_validator = JSON::Structure::InstanceValidator->new(schema => $schema);
238+
my $instance_result = $instance_validator->validate($instance);
239+
print "Instance valid: ", ($instance_result->is_valid ? "true" : "false"), "\n";
240+
```
241+
207242
### Rust
208243

209244
```bash

perl/.gitignore

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Perl build artifacts
2+
MYMETA.*
3+
Makefile
4+
blib/
5+
pm_to_blib
6+
*.o
7+
*.bs
8+
9+
# Distribution files
10+
JSON-Structure-*
11+
MANIFEST
12+
MANIFEST.bak
13+
14+
# Coverage
15+
cover_db/
16+
*.gcov
17+
*.gcda
18+
*.gcno
19+
20+
# IDE
21+
.idea/
22+
*.swp
23+
*.swo
24+
*~
25+
26+
# Allow lib directory (override parent .gitignore)
27+
!lib/
28+
!bin/
29+
30+
local

0 commit comments

Comments
 (0)