line
stmt
bran
cond
sub
pod
time
code
1
package Data::TOON;
2
10
10
1406094
use 5.014;
10
41
3
10
10
56
use strict;
10
67
10
277
4
10
10
51
use warnings;
10
18
10
588
5
6
10
10
5460
use Data::TOON::Encoder;
10
31
10
491
7
10
10
5193
use Data::TOON::Decoder;
10
31
10
545
8
10
10
4449
use Data::TOON::Validator;
10
33
10
3005
9
10
our $VERSION = "0.03";
11
12
=encoding utf-8
13
14
=head1 NAME
15
16
Data::TOON - Complete Perl implementation of TOON (Token-Oriented Object Notation)
17
18
=head1 SYNOPSIS
19
20
use Data::TOON;
21
22
# Basic usage
23
my $data = { name => 'Alice', age => 30, active => 1 };
24
my $toon = Data::TOON->encode($data);
25
print $toon;
26
# Output:
27
# active: true
28
# age: 30
29
# name: Alice
30
31
my $decoded = Data::TOON->decode($toon);
32
33
# Tabular arrays
34
my $users = {
35
users => [
36
{ id => 1, name => 'Alice', role => 'admin' },
37
{ id => 2, name => 'Bob', role => 'user' }
38
]
39
};
40
41
print Data::TOON->encode($users);
42
# Output:
43
# users[2]{id,name,role}:
44
# 1,Alice,admin
45
# 2,Bob,user
46
47
# Alternative delimiters
48
my $encoder = Data::TOON::Encoder->new(delimiter => '|');
49
print $encoder->encode($users);
50
# Or with tabs:
51
my $tab_encoder = Data::TOON::Encoder->new(delimiter => "\t");
52
53
# Root primitives and arrays
54
print Data::TOON->encode(42); # Output: 42
55
print Data::TOON->encode('hello'); # Output: hello
56
print Data::TOON->encode([1, 2, 3]); # Output: [3]: 1,2,3
57
58
=head1 DESCRIPTION
59
60
Data::TOON is a complete Perl implementation of TOON (Token-Oriented Object Notation), a human-friendly,
61
line-oriented data serialization format.
62
63
TOON provides:
64
65
=over 4
66
67
=item * B - Indentation-based, similar to YAML, with minimal quoting
68
69
=item * B - Compact tabular, explicit list, or inline primitive arrays
70
71
=item * B - Support for comma, tab, and pipe delimiters
72
73
=item * B - DoS protection via depth limits and circular reference detection
74
75
=item * B - Automatic number normalization (removes trailing zeros, etc.)
76
77
=item * B - 95%+ coverage of TOON specification v1.0
78
79
=back
80
81
The format is particularly useful for configuration files, data interchange, and human-editable data storage.
82
83
=head1 METHODS
84
85
=head2 encode( $data, %options )
86
87
Encodes a Perl data structure to TOON format string.
88
89
B
90
91
=over 4
92
93
=item C<$data>
94
95
The Perl data structure to encode. Can be:
96
- Hash reference (becomes TOON object)
97
- Array reference (becomes TOON array)
98
- Scalar (becomes root primitive: number, string, boolean, or null)
99
100
=item C<%options>
101
102
Optional encoder configuration:
103
104
=over 4
105
106
=item C
107
108
Number of spaces per indentation level. Default: 2
109
110
Data::TOON->encode($data, indent => 4);
111
112
=item C
113
114
Array element delimiter character:
115
116
=over 4
117
118
=item C<','> (default) - Comma-separated values
119
120
items[2]{id,name}: 1,Alice
121
2,Bob
122
123
=item C<"\t"> - Tab-separated values
124
125
items[2]{idname}:
126
1Alice
127
2Bob
128
129
=item C<'|'> - Pipe-separated values
130
131
items[2|]{id|name}:
132
1|Alice
133
2|Bob
134
135
=back
136
137
=item C
138
139
Enable strict mode validation. Default: 1
140
141
Data::TOON->encode($data, strict => 0);
142
143
=item C
144
145
Maximum nesting depth (prevents DoS). Default: 100
146
147
Data::TOON->encode($data, max_depth => 50);
148
149
=item C
150
151
Array reference of column names to prioritize (appear leftmost in tabular format). Columns not in this list appear after in alphabetical order. Default: empty array (standard alphabetical sort)
152
153
Data::TOON->encode($data, column_priority => ['id', 'name']);
154
# Will output columns as: id, name, ... (other columns alphabetically)
155
156
=back
157
158
=back
159
160
B
161
162
TOON format string. Can encode to:
163
- Object (most common): C pairs
164
- Tabular array: Compact C format
165
- List array: Explicit C format
166
- Root primitive: Single value (42, "hello", true, false, null)
167
- Root array: C<[N]: value,value,...>
168
169
B
170
171
# Simple object
172
my $toon = Data::TOON->encode({ name => 'Alice', age => 30 });
173
# Output:
174
# age: 30
175
# name: Alice
176
177
# Nested object
178
my $toon = Data::TOON->encode({
179
user => {
180
name => 'Alice',
181
age => 30
182
}
183
});
184
# Output:
185
# user:
186
# age: 30
187
# name: Alice
188
189
# Tabular array (uniform objects)
190
my $toon = Data::TOON->encode({
191
users => [
192
{ id => 1, name => 'Alice' },
193
{ id => 2, name => 'Bob' }
194
]
195
});
196
# Output:
197
# users[2]{id,name}:
198
# 1,Alice
199
# 2,Bob
200
201
# Tabular array with column priority
202
my $toon = Data::TOON->encode({
203
users => [
204
{ id => 1, name => 'Alice', role => 'admin' },
205
{ id => 2, name => 'Bob', role => 'user' }
206
]
207
}, column_priority => ['id', 'name']);
208
# Output:
209
# users[2]{id,name,role}:
210
# 1,Alice,admin
211
# 2,Bob,user
212
213
# List array (non-uniform objects)
214
my $toon = Data::TOON->encode({
215
items => [
216
{ id => 1, name => 'Alice', extra => 'data' },
217
{ id => 2, name => 'Bob' }
218
]
219
});
220
# Output:
221
# items[2]:
222
# - extra: data
223
# id: 1
224
# name: Alice
225
# - id: 2
226
# name: Bob
227
228
# Root array
229
my $toon = Data::TOON->encode([1, 2, 3]);
230
# Output: [3]: 1,2,3
231
232
# Root primitive
233
my $toon = Data::TOON->encode(42);
234
# Output: 42
235
236
237
=cut
238
239
sub encode {
240
28
28
1
935488
my ($class, $data, %opts) = @_;
241
28
206
my $encoder = Data::TOON::Encoder->new(%opts);
242
28
100
return $encoder->encode($data);
243
}
244
245
sub decode {
246
47
47
1
921478
my ($class, $toon_text, %opts) = @_;
247
47
328
my $decoder = Data::TOON::Decoder->new(%opts);
248
47
150
return $decoder->decode($toon_text);
249
}
250
251
sub validate {
252
3
3
0
213781
my ($class, $toon_text) = @_;
253
3
20
my $validator = Data::TOON::Validator->new();
254
3
7
return $validator->validate($toon_text);
255
}
256
257
=head1 EXAMPLES AND PATTERNS
258
259
=head2 Configuration File
260
261
TOON is well-suited for configuration files:
262
263
app_name: MyApp
264
version: 1.0.0
265
debug: false
266
database:
267
host: localhost
268
port: 5432
269
user: admin
270
max_connections: 100
271
servers[3]{host,port,role}:
272
web1.example.com,8080,primary
273
web2.example.com,8080,secondary
274
web3.example.com,8080,secondary
275
276
=head2 Data Exchange Format
277
278
For APIs and data interchange where readability matters:
279
280
response:
281
status: success
282
code: 200
283
data[2]:
284
- id: 1001
285
name: Product A
286
price: 29.99
287
in_stock: true
288
- id: 1002
289
name: Product B
290
price: 49.99
291
in_stock: false
292
293
=head2 Handling Nested Structures
294
295
organization:
296
name: Example Corp
297
departments[2]:
298
- name: Engineering
299
teams[2]:
300
- name: Backend
301
members: 5
302
- name: Frontend
303
members: 3
304
- name: Sales
305
teams[1]:
306
- name: Enterprise
307
members: 8
308
309
=head1 TOON FORMAT FEATURES
310
311
=head2 Data Types
312
313
TOON supports JSON data types:
314
315
=over 4
316
317
=item B - Unordered collection of key-value pairs
318
319
user:
320
name: Alice
321
age: 30
322
323
=item B - Ordered collection of values (3 formats available)
324
325
Tabular:
326
users[2]{id,name}: 1,Alice
327
2,Bob
328
329
List:
330
items[2]:
331
- id: 1
332
name: Alice
333
- id: 2
334
name: Bob
335
336
Primitive:
337
tags[3]: red,green,blue
338
339
=item B - UTF-8 text (quoted if needed)
340
341
name: Alice
342
quote: "She said \"Hello\""
343
344
=item B - Integer or float (canonicalized)
345
346
count: 42
347
ratio: 3.14
348
349
=item B - true or false
350
351
active: true
352
deleted: false
353
354
=item B - Null value
355
356
optional_field: null
357
358
=back
359
360
=head2 Delimiters
361
362
Three delimiter options for array values:
363
364
B
365
data[3]: a,b,c
366
367
B
368
data[3]: abc
369
370
B
371
data[3|]: a|b|c
372
373
Use tab or pipe delimiters when values might contain commas.
374
375
=head2 String Escaping
376
377
Standard escape sequences are supported:
378
379
text: "Line 1\nLine 2"
380
path: "C:\\Program Files\\App"
381
json: "Use \" to escape quotes"
382
383
=head2 Root Forms
384
385
Documents can start with different root types:
386
387
# Root object (default)
388
name: Alice
389
age: 30
390
391
# Root primitive
392
42
393
394
# Root array
395
[3]: a,b,c
396
397
=head1 PERFORMANCE CONSIDERATIONS
398
399
=over 4
400
401
=item * Encoding is O(n) in data size
402
=item * Decoding is O(n) in text size
403
=item * Memory usage is proportional to data complexity
404
=item * Large documents (>100MB) may require streaming parser
405
406
=back
407
408
=head1 SECURITY
409
410
Data::TOON includes several security features:
411
412
=over 4
413
414
=item B - Prevents stack overflow from deeply nested structures
415
Default max_depth: 100 levels
416
Configurable via encode/decode options
417
418
=item B - Prevents infinite loops during encoding
419
Automatically detects and rejects circular references
420
421
=item B - Strict parsing rules prevent injection attacks
422
All strings are treated as literal values
423
No code evaluation or command injection possible
424
425
=back
426
427
=head1 COMPATIBILITY
428
429
=over 4
430
431
=item * Perl 5.14 or later
432
=item * No external dependencies
433
=item * Pure Perl implementation (portable)
434
435
=back
436
437
=head1 TOON SPECIFICATION COMPLIANCE
438
439
This implementation achieves 95%+ compliance with TOON Specification v1.0:
440
441
✓ Complete object support
442
✓ Complete array support (all 3 formats)
443
✓ All delimiters (comma, tab, pipe)
444
✓ Root forms (object, array, primitive)
445
✓ String escaping
446
✓ Canonical number form
447
✓ Security measures
448
✓ Full type inference
449
450
See L for complete specification.
451
452
=head1 COMMON ERRORS AND TROUBLESHOOTING
453
454
=head2 "Maximum nesting depth exceeded"
455
456
If you encounter this error, your data is nested more than 100 levels deep:
457
458
# Increase max_depth
459
my $encoded = Data::TOON->encode($data, max_depth => 200);
460
461
=head2 "Circular reference detected"
462
463
Your data structure contains a reference to itself:
464
465
my $obj = { name => 'Alice' };
466
$obj->{self} = $obj; # This creates a circle!
467
468
Solution: Remove the circular reference before encoding.
469
470
=head2 Inconsistent type inference
471
472
If values aren't being parsed as expected, use explicit quoting:
473
474
# Without quotes - might be interpreted as number
475
value: 42
476
477
# With quotes - definitely a string
478
value: "42"
479
480
=head1 SEE ALSO
481
482
=over 4
483
484
=item * L
485
486
=item * L - Data model foundation
487
488
=item * L - Similar indentation-based format
489
490
=back
491
492
=head1 LICENSE
493
494
Copyright (C) ytnobody.
495
496
This library is free software; you can redistribute it and/or modify
497
it under the same terms as Perl itself.
498
499
=head1 AUTHOR
500
501
ytnobody Eytnobody@gmail.comE