File Coverage

blib/lib/Data/Hash/Patch/Smart.pm
Criterion Covered Total %
statement 15 15 100.0
branch 1 2 50.0
condition n/a
subroutine 5 5 100.0
pod 1 1 100.0
total 22 23 95.6


line stmt bran cond sub pod time code
1             package Data::Hash::Patch::Smart;
2              
3 15     15   2124115 use strict;
  15         31  
  15         650  
4 15     15   113 use warnings;
  15         42  
  15         1040  
5              
6 15     15   107 use Exporter 'import';
  15         64  
  15         693  
7 15     15   9416 use Data::Hash::Patch::Smart::Engine ();
  15         76  
  15         2643  
8              
9             our @EXPORT_OK = qw(patch);
10              
11             =head1 NAME
12              
13             Data::Hash::Patch::Smart - Apply structural, wildcard, and array-aware patches to Perl data structures
14              
15             =head1 VERSION
16              
17             Version 0.01
18              
19             =cut
20              
21             our $VERSION = '0.01';
22              
23             =head1 SYNOPSIS
24              
25             use Data::Hash::Patch::Smart qw(patch);
26              
27             my $data = {
28             users => {
29             alice => { role => 'user' },
30             bob => { role => 'admin' },
31             }
32             };
33              
34             my $changes = [
35             { op => 'change', path => '/users/alice/role', to => 'admin' },
36             { op => 'add', path => '/users/bob/tags/0', value => 'active' },
37             { op => 'remove', path => '/users/*/deprecated' },
38             ];
39              
40             my $patched = patch($data, $changes, strict => 1);
41              
42             =head1 DESCRIPTION
43              
44             C applies structured patches to nested Perl
45             data structures. It is the companion to C and
46             supports:
47              
48             =over 4
49              
50             =item *
51              
52             Hash and array navigation via JSON-Pointer-like paths
53              
54             =item *
55              
56             Index arrays (ordered semantics)
57              
58             =item *
59              
60             Unordered arrays (push/remove semantics)
61              
62             =item *
63              
64             Structural wildcards (C)
65              
66             =item *
67              
68             C mode for auto-creating intermediate containers
69              
70             =item *
71              
72             C mode for validating paths
73              
74             =item *
75              
76             Cycle-safe wildcard traversal
77              
78             =back
79              
80             The goal is to provide a predictable, expressive patch engine suitable
81             for configuration management, data migrations, and diff/patch
82             round-tripping.
83              
84             =head1 PATCH OPERATIONS
85              
86             Each change is a hashref with:
87              
88             =over 4
89              
90             =item C
91              
92             One of C, C, C.
93              
94             =item C
95              
96             Slash-separated path segments.
97             Numeric segments index arrays.
98              
99             =item C / C / C
100              
101             Payload for the operation.
102              
103             =back
104              
105             =head2 Unordered array wildcard
106              
107             A leaf C<*> applies unordered semantics:
108              
109             { op => 'add', path => '/items/*', value => 'x' }
110             { op => 'remove', path => '/items/*', from => 'x' }
111              
112             =head2 Structural wildcard
113              
114             A C<*> in the parent path matches all children:
115              
116             /users/*/role
117             /servers/*/ports/*
118              
119             =head1 ERROR HANDLING
120              
121             =head2 Strict mode
122              
123             Strict mode enforces:
124              
125             =over 4
126              
127             =item *
128              
129             Missing hash keys
130              
131             =item *
132              
133             Out-of-bounds array indices
134              
135             =item *
136              
137             Invalid array indices
138              
139             =item *
140              
141             Unsupported operations
142              
143             =back
144              
145             Wildcard segments do B trigger strict errors when no matches exist.
146              
147             =head1 CYCLE DETECTION
148              
149             Wildcard traversal detects cycles and throws an exception in strict mode.
150              
151             =head1 FUNCTIONS
152              
153             =head2 patch( $data, \@changes, %opts )
154              
155             Applies a list of changes to a data structure and returns a deep clone
156             with the modifications applied.
157              
158             =head3 Options
159              
160             =over 4
161              
162             =item C 1>
163              
164             Die on invalid paths, missing keys,
165             or out-of-bounds array indices.
166              
167             =item C 1>
168              
169             Auto-create intermediate hashes and arrays when walking a path.
170              
171             =item C 'unordered'>
172              
173             Enables unordered array semantics for leaf C<*> paths.
174              
175             =back
176              
177             =cut
178              
179             sub patch {
180 27     27 1 2846720 my ($data, $changes, %opts) = @_;
181              
182 27 50       158 die 'patch() expects an arrayref of changes' unless ref($changes) eq 'ARRAY';
183              
184 27         158 return Data::Hash::Patch::Smart::Engine::patch($data, $changes, %opts);
185             }
186              
187             =head1 AUTHOR
188              
189             Nigel Horne, C<< >>
190              
191             =head1 BUGS
192              
193             =head1 SEE ALSO
194              
195             L
196              
197             =head1 REPOSITORY
198              
199             L
200              
201             =head1 SUPPORT
202              
203             This module is provided as-is without any warranty.
204              
205             Please report any bugs or feature requests to C,
206             or through the web interface at
207             L.
208             I will be notified, and then you'll
209             automatically be notified of progress on your bug as I make changes.
210              
211             You can find documentation for this module with the perldoc command.
212              
213             perldoc Data::Hash::Patch::Smart
214              
215             You can also look for information at:
216              
217             =over 4
218              
219             =item * MetaCPAN
220              
221             L
222              
223             =item * RT: CPAN's request tracker
224              
225             L
226              
227             =item * CPAN Testers' Matrix
228              
229             L
230              
231             =item * CPAN Testers Dependencies
232              
233             L
234              
235             =back
236              
237             =head1 LICENCE AND COPYRIGHT
238              
239             Copyright 2026 Nigel Horne.
240              
241             Usage is subject to licence terms.
242              
243             The licence terms of this software are as follows:
244              
245             =over 4
246              
247             =item * Personal single user, single computer use: GPL2
248              
249             =item * All other users (including Commercial, Charity, Educational, Government)
250             must apply in writing for a licence for use from Nigel Horne at the
251             above e-mail.
252              
253             =back
254              
255             =cut
256              
257             1;