Merge lp:~noskcaj/ubuntu/vivid/libtree-perl/1.05 into lp:ubuntu/vivid/libtree-perl
- Vivid (15.04)
- 1.05
- Merge into vivid
Proposed by
Jackson Doak
Status: | Needs review |
---|---|
Proposed branch: | lp:~noskcaj/ubuntu/vivid/libtree-perl/1.05 |
Merge into: | lp:ubuntu/vivid/libtree-perl |
Diff against target: |
3109 lines (+1496/-1112) 27 files modified
Build.PL (+38/-34) Changelog.ini (+70/-0) Changes (+50/-17) MANIFEST (+10/-7) META.json (+72/-0) META.yml (+47/-0) Makefile.PL (+43/-0) README (+49/-0) debian/changelog (+6/-0) lib/Tree.pm (+142/-101) lib/Tree/Binary.pm (+0/-330) lib/Tree/Binary2.pm (+330/-0) lib/Tree/Fast.pm (+547/-543) t/Tree/001_root_node.t (+7/-3) t/Tree/003_child_node.t (+2/-1) t/Tree/004_multiple_children.t (+2/-1) t/Tree/005_multilevel_tree.t (+2/-1) t/Tree/010_errors_addchild.t (+2/-1) t/Tree/011_errors_removechild.t (+2/-1) t/Tree/016_events.t (+2/-1) t/Tree_Binary/000_binary_trees.t (+3/-2) t/Tree_Binary/001_mirror.t (+1/-1) t/Tree_Binary/002_clone.t (+4/-4) t/lib/Tests.pm (+61/-0) t/pod.t (+2/-2) t/pod_coverage.t (+2/-2) t/tests.pm (+0/-60) |
To merge this branch: | bzr merge lp:~noskcaj/ubuntu/vivid/libtree-perl/1.05 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Holbach (community) | Approve | ||
Review via email: mp+244658@code.launchpad.net |
Commit message
Description of the change
New upstream release. Package might be better RMed though
To post a comment you must log in.
Unmerged revisions
- 4. By Jackson Doak
-
New upstream release.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'Build.PL' |
2 | --- Build.PL 2008-01-17 12:56:58 +0000 |
3 | +++ Build.PL 2014-12-12 23:08:52 +0000 |
4 | @@ -2,39 +2,43 @@ |
5 | |
6 | use 5.6.0; |
7 | |
8 | -use strict; |
9 | use warnings; |
10 | |
11 | -eval "use Tree::Binary;"; |
12 | -unless ($@) { |
13 | - if ( (my $version = Tree::Binary->VERSION) <= 0.07 ) { |
14 | - my $tree_binary_msg = "You currently have Tree::Binary version $version installed.\nThis distribution will install an incompatible Tree::Binary module on top of it.\nDo you wish for me to continue?"; |
15 | - |
16 | - if ( !Module::Build->y_n( $tree_binary_msg, 'n' ) ) { |
17 | - exit; |
18 | - } |
19 | - } |
20 | -} |
21 | - |
22 | -my $build = Module::Build->new( |
23 | - module_name => 'Tree', |
24 | - license => 'perl', |
25 | - requires => { |
26 | - 'perl' => '5.6.0', |
27 | - 'Scalar::Util' => '1.10', |
28 | - }, |
29 | - build_requires => { |
30 | - 'Scalar::Util' => '1.10', |
31 | - 'Test::Deep' => '0.088', |
32 | - 'Test::Exception' => '0.15', |
33 | - 'Test::More' => '0.47', |
34 | - 'Test::Warn' => '0.08', |
35 | - }, |
36 | - create_makefile_pl => 'traditional', |
37 | - recursive_test_files => 1, |
38 | - add_to_cleanup => [ |
39 | - 'META.yml', '*.bak', '*.gz', 'Makefile.PL', |
40 | - ], |
41 | -); |
42 | - |
43 | -$build->create_build_script; |
44 | + |
45 | +Module::Build -> new |
46 | +( |
47 | + dist_abstract => 'An N-ary tree', |
48 | + module_name => 'Tree', |
49 | + license => 'artistic_2', |
50 | + requires => |
51 | + { |
52 | + perl => '5.6.0', |
53 | + Scalar::Util => 1.10, |
54 | + }, |
55 | + configure_requires => |
56 | + { |
57 | + Module::Build => 0.40, |
58 | + }, |
59 | + build_requires => |
60 | + { |
61 | + base => 0, |
62 | + constant => 0, |
63 | + Data::Dumper => 2.136, |
64 | + Exporter => 5.66, |
65 | + overload => 0, |
66 | + Scalar::Util => 1.10, |
67 | + strict => 0, |
68 | + Test::Deep => 0.088, |
69 | + Test::Exception => 0.15, |
70 | +# Test::Pod => 1.45, # Make it optional. See t/pod.t |
71 | +# Test::Pod::Coverage => 1.08, # Make it optional. See t/pod.t |
72 | + Test::More => 0.47, |
73 | + Test::Warn => 0.08, |
74 | + warnings => 0, |
75 | + }, |
76 | + recursive_test_files => 1, |
77 | + add_to_cleanup => |
78 | + [ |
79 | + 'META.yml', '*.bak', '*.gz', 'Makefile.PL', |
80 | + ], |
81 | +) -> create_build_script; |
82 | |
83 | === added file 'Changelog.ini' |
84 | --- Changelog.ini 1970-01-01 00:00:00 +0000 |
85 | +++ Changelog.ini 2014-12-12 23:08:52 +0000 |
86 | @@ -0,0 +1,70 @@ |
87 | +[Module] |
88 | +Name=Tree |
89 | +Changelog.Creator=Module::Metadata::Changes V 2.05 |
90 | +Changelog.Parser=Config::IniFiles V 2.78 |
91 | + |
92 | +[V 1.05] |
93 | +Date=2013-06-05T08:34:00 |
94 | +Comments= <<EOT |
95 | +- No code changes. |
96 | +- For pre-reqs base, constant and overload, which ship with Perl, set the version # to 0. |
97 | +Requested by Andreas Mock. Actually, I should have done this with version 1.04. |
98 | +- Rename CHANGES to Changes as per CPAN::Changes::Spec. |
99 | +EOT |
100 | + |
101 | +[V 1.04] |
102 | +Date=2012-11-08T12:38:00 |
103 | +Comments= <<EOT |
104 | +- No code changes. |
105 | +- For pre-reqs such as strict, warnings, etc, which ship with Perl, set the version # to 0. |
106 | +Reported as RT#80663 by Father Chrysostomos for Tree::DAG_Node. |
107 | +- Add README. |
108 | +EOT |
109 | + |
110 | +[V 1.03] |
111 | +Date=2012-11-02T09:34:00 |
112 | +Comments= <<EOT |
113 | +- Rename Tree::Binary to Tree::Binary2 so it no longer clashes with the Tree::Binary shipped in the |
114 | +Tree-Binary distro. MetaCPAN was getting confused, and automatically redirected links to this |
115 | +module's Tree:Binary to the other one. |
116 | +EOT |
117 | + |
118 | +[V 1.02] |
119 | +Date=2012-10-04T12:10:00 |
120 | +Comments= <<EOT |
121 | +- Ron Savage is now co-maint. |
122 | +- Patch Tree::Fast's value() to accept a defained value so the node's value can be set with |
123 | +$n -> value($new_value). |
124 | +- Patch Tree::Fast's meta() to accept a hashref so metadata can be set with $n -> meta({key => value}), |
125 | +as well as by directly accessing the internal hashref '_meta'. |
126 | +- Patch t/Tree/001_root_node.t to test the above. |
127 | +- Rename Changes to CHANGES. |
128 | +- Use ini.report.pl (shipped with Module::Metadata::Changes) to add Changelog.ini to the distro. |
129 | +- Reformat the dates in this file. |
130 | +- Change lib/Tree/Fast.pm to Unix line endings. |
131 | +- Clean up the POD. |
132 | +- Re-work Makefile.PL rather than have Build.PL generate it. |
133 | +- Update pre-reqs in Build.PL and Makefile.PL. |
134 | +- Move t/tests.pm to t/lib/Tests.pm. |
135 | +EOT |
136 | + |
137 | +[V 1.01] |
138 | +Date=2007-10-18T12:00:00 |
139 | +Comments= <<EOT |
140 | +- Fixed Changes file |
141 | +- Right distro name. |
142 | +- 1.00 release noted |
143 | +- Cleaned up 5.6.0 -> 5.006 |
144 | +- Fix for RT# 16889 (clone broken for Tree::Binary) |
145 | +- Patch submitted by HDP |
146 | +- Fix for other miscellenous bugs |
147 | +- Patch submitted by HDP |
148 | +EOT |
149 | + |
150 | +[V 1.00] |
151 | +Date=2005-11-08T12:00:00 |
152 | +Comments=- Initial release |
153 | + |
154 | +[V 0.99] |
155 | +Date=2005-10-24T10:30:00 |
156 | +Comments=- Initial revision |
157 | |
158 | === modified file 'Changes' |
159 | --- Changes 2008-01-17 12:56:58 +0000 |
160 | +++ Changes 2014-12-12 23:08:52 +0000 |
161 | @@ -1,17 +1,50 @@ |
162 | -Revision history for Perl distribution Tree |
163 | - |
164 | -1.01 Oct 18, 2007 |
165 | - - Fixed Changes file |
166 | - - Right distro name. |
167 | - - 1.00 release noted |
168 | - - Cleaned up 5.6.0 -> 5.006 |
169 | - - Fix for RT# 16889 (clone broken for Tree::Binary) |
170 | - - Patch submitted by HDP |
171 | - - Fix for other miscellenous bugs |
172 | - - Patch submitted by HDP |
173 | - |
174 | -1.00 Nov 08, 2005 |
175 | - - Initial release |
176 | - |
177 | -0.99_01 Mon 24 Oct 2005 10:30:00 |
178 | - - Initial revision |
179 | +Revision history for Perl distribution Tree. |
180 | + |
181 | +1.05 Wed Jun 5 08:34:00 2013 |
182 | + - No code changes. |
183 | + - For pre-reqs base, constant and overload, which ship with Perl, set the version # to 0. |
184 | + Requested by Andreas Mock. Actually, I should have done this with version 1.04. |
185 | + - Rename CHANGES to Changes as per CPAN::Changes::Spec. |
186 | + |
187 | +1.04 Thu Nov 8 12:38:00 2012 |
188 | + - No code changes. |
189 | + - For pre-reqs such as strict, warnings, etc, which ship with Perl, set the version # to 0. |
190 | + Reported as RT#80663 by Father Chrysostomos for Tree::DAG_Node. |
191 | + - Add README. |
192 | + |
193 | +1.03 Fri Nov 2 09:34:00 2012 |
194 | + - Rename Tree::Binary to Tree::Binary2 so it no longer clashes with the Tree::Binary shipped in the |
195 | + Tree-Binary distro. MetaCPAN was getting confused, and automatically redirected links to this |
196 | + module's Tree:Binary to the other one. |
197 | + |
198 | +1.02 Thu Oct 4 12:10:00 2012 |
199 | + - Ron Savage is now co-maint. |
200 | + - Patch Tree::Fast's value() to accept a defained value so the node's value can be set with |
201 | + $n -> value($new_value). |
202 | + - Patch Tree::Fast's meta() to accept a hashref so metadata can be set with $n -> meta({key => value}), |
203 | + as well as by directly accessing the internal hashref '_meta'. |
204 | + - Patch t/Tree/001_root_node.t to test the above. |
205 | + - Rename Changes to CHANGES. |
206 | + - Use ini.report.pl (shipped with Module::Metadata::Changes) to add Changelog.ini to the distro. |
207 | + - Reformat the dates in this file. |
208 | + - Change lib/Tree/Fast.pm to Unix line endings. |
209 | + - Clean up the POD. |
210 | + - Re-work Makefile.PL rather than have Build.PL generate it. |
211 | + - Update pre-reqs in Build.PL and Makefile.PL. |
212 | + - Move t/tests.pm to t/lib/Tests.pm. |
213 | + |
214 | +1.01 Thu Oct 18 12:00:00 2007 |
215 | + - Fixed Changes file |
216 | + - Right distro name. |
217 | + - 1.00 release noted |
218 | + - Cleaned up 5.6.0 -> 5.006 |
219 | + - Fix for RT# 16889 (clone broken for Tree::Binary) |
220 | + - Patch submitted by HDP |
221 | + - Fix for other miscellenous bugs |
222 | + - Patch submitted by HDP |
223 | + |
224 | +1.00 Tue Nov 08 12:00:00 2005 |
225 | + - Initial release |
226 | + |
227 | +0.99 Mon Oct 24 10:30:00 2005 |
228 | + - Initial revision |
229 | |
230 | === modified file 'MANIFEST' |
231 | --- MANIFEST 2008-01-17 12:56:58 +0000 |
232 | +++ MANIFEST 2014-12-12 23:08:52 +0000 |
233 | @@ -1,10 +1,17 @@ |
234 | Build.PL |
235 | +Changelog.ini |
236 | Changes |
237 | +lib/Tree.pm |
238 | +lib/Tree/Binary2.pm |
239 | +lib/Tree/Fast.pm |
240 | Makefile.PL |
241 | MANIFEST This list of files |
242 | -lib/Tree.pm |
243 | -lib/Tree/Binary.pm |
244 | -lib/Tree/Fast.pm |
245 | +META.json |
246 | +META.yml |
247 | +README |
248 | +t/lib/Tests.pm |
249 | +t/pod.t |
250 | +t/pod_coverage.t |
251 | t/Tree/000_interface.t |
252 | t/Tree/001_root_node.t |
253 | t/Tree/002_null_object.t |
254 | @@ -26,7 +33,3 @@ |
255 | t/Tree_Binary/001_mirror.t |
256 | t/Tree_Binary/002_clone.t |
257 | t/Tree_Fast/001_clone.t |
258 | -t/pod.t |
259 | -t/pod_coverage.t |
260 | -t/tests.pm |
261 | -META.yml |
262 | |
263 | === added file 'META.json' |
264 | --- META.json 1970-01-01 00:00:00 +0000 |
265 | +++ META.json 2014-12-12 23:08:52 +0000 |
266 | @@ -0,0 +1,72 @@ |
267 | +{ |
268 | + "abstract" : "An N-ary tree", |
269 | + "author" : [ |
270 | + "Rob Kinyon E<lt>rob.kinyon@iinteractive.comE<gt>", |
271 | + "Stevan Little E<lt>stevan.little@iinteractive.comE<gt>", |
272 | + "Co-maintenance since V 1.02 is by Ron Savage <rsavage@cpan.org>." |
273 | + ], |
274 | + "dynamic_config" : 1, |
275 | + "generated_by" : "Module::Build version 0.4005, CPAN::Meta::Converter version 2.120921", |
276 | + "license" : [ |
277 | + "artistic_2" |
278 | + ], |
279 | + "meta-spec" : { |
280 | + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", |
281 | + "version" : "2" |
282 | + }, |
283 | + "name" : "Tree", |
284 | + "prereqs" : { |
285 | + "build" : { |
286 | + "requires" : { |
287 | + "Data::Dumper" : "2.136", |
288 | + "Exporter" : "5.66", |
289 | + "Scalar::Util" : "1.1", |
290 | + "Test::Deep" : "0.088", |
291 | + "Test::Exception" : "0.15", |
292 | + "Test::More" : "0.47", |
293 | + "Test::Warn" : "0.08", |
294 | + "base" : "0", |
295 | + "constant" : "0", |
296 | + "overload" : "0", |
297 | + "strict" : "0", |
298 | + "warnings" : "0" |
299 | + } |
300 | + }, |
301 | + "configure" : { |
302 | + "requires" : { |
303 | + "Module::Build" : "0.4" |
304 | + } |
305 | + }, |
306 | + "runtime" : { |
307 | + "requires" : { |
308 | + "Scalar::Util" : "1.1", |
309 | + "perl" : "v5.6.0" |
310 | + } |
311 | + } |
312 | + }, |
313 | + "provides" : { |
314 | + "Tree" : { |
315 | + "file" : "lib/Tree.pm", |
316 | + "version" : "1.05" |
317 | + }, |
318 | + "Tree::Binary2" : { |
319 | + "file" : "lib/Tree/Binary2.pm", |
320 | + "version" : "1.05" |
321 | + }, |
322 | + "Tree::Fast" : { |
323 | + "file" : "lib/Tree/Fast.pm", |
324 | + "version" : "1.05" |
325 | + }, |
326 | + "Tree::Null" : { |
327 | + "file" : "lib/Tree/Fast.pm", |
328 | + "version" : 0 |
329 | + } |
330 | + }, |
331 | + "release_status" : "stable", |
332 | + "resources" : { |
333 | + "license" : [ |
334 | + "http://www.perlfoundation.org/artistic_license_2_0" |
335 | + ] |
336 | + }, |
337 | + "version" : "1.05" |
338 | +} |
339 | |
340 | === added file 'META.yml' |
341 | --- META.yml 1970-01-01 00:00:00 +0000 |
342 | +++ META.yml 2014-12-12 23:08:52 +0000 |
343 | @@ -0,0 +1,47 @@ |
344 | +--- |
345 | +abstract: 'An N-ary tree' |
346 | +author: |
347 | + - 'Rob Kinyon E<lt>rob.kinyon@iinteractive.comE<gt>' |
348 | + - 'Stevan Little E<lt>stevan.little@iinteractive.comE<gt>' |
349 | + - 'Co-maintenance since V 1.02 is by Ron Savage <rsavage@cpan.org>.' |
350 | +build_requires: |
351 | + Data::Dumper: 2.136 |
352 | + Exporter: 5.66 |
353 | + Scalar::Util: 1.1 |
354 | + Test::Deep: 0.088 |
355 | + Test::Exception: 0.15 |
356 | + Test::More: 0.47 |
357 | + Test::Warn: 0.08 |
358 | + base: 0 |
359 | + constant: 0 |
360 | + overload: 0 |
361 | + strict: 0 |
362 | + warnings: 0 |
363 | +configure_requires: |
364 | + Module::Build: 0.4 |
365 | +dynamic_config: 1 |
366 | +generated_by: 'Module::Build version 0.4005, CPAN::Meta::Converter version 2.120921' |
367 | +license: artistic_2 |
368 | +meta-spec: |
369 | + url: http://module-build.sourceforge.net/META-spec-v1.4.html |
370 | + version: 1.4 |
371 | +name: Tree |
372 | +provides: |
373 | + Tree: |
374 | + file: lib/Tree.pm |
375 | + version: 1.05 |
376 | + Tree::Binary2: |
377 | + file: lib/Tree/Binary2.pm |
378 | + version: 1.05 |
379 | + Tree::Fast: |
380 | + file: lib/Tree/Fast.pm |
381 | + version: 1.05 |
382 | + Tree::Null: |
383 | + file: lib/Tree/Fast.pm |
384 | + version: 0 |
385 | +requires: |
386 | + Scalar::Util: 1.1 |
387 | + perl: v5.6.0 |
388 | +resources: |
389 | + license: http://www.perlfoundation.org/artistic_license_2_0 |
390 | +version: 1.05 |
391 | |
392 | === added file 'Makefile.PL' |
393 | --- Makefile.PL 1970-01-01 00:00:00 +0000 |
394 | +++ Makefile.PL 2014-12-12 23:08:52 +0000 |
395 | @@ -0,0 +1,43 @@ |
396 | +use warnings; |
397 | + |
398 | +require 5.006000; |
399 | + |
400 | +use ExtUtils::MakeMaker; |
401 | + |
402 | +# ---------------------- |
403 | + |
404 | +WriteMakefile |
405 | +( |
406 | + ($] ge '5.005') ? |
407 | + ( |
408 | + AUTHOR => 'Rob Kinyin (rkinyon@cpan.org)', |
409 | + ABSTRACT => 'Persist multiple trees in a single db table, preserving child order', |
410 | + ) : (), |
411 | + NAME => 'Tree', |
412 | + LICENSE => 'artistic_2', |
413 | + VERSION_FROM => 'lib/Tree.pm', |
414 | + PREREQ_PM => |
415 | + { |
416 | + base => 0, |
417 | + constant => 0, |
418 | + Data::Dumper => 2.136, |
419 | + Exporter => 5.66, |
420 | + overload => 0, |
421 | + Scalar::Util => 1.10, |
422 | + strict => 0, |
423 | + Test::Deep => 0.088, |
424 | + Test::Exception => 0.15, |
425 | +# Test::Pod => 1.45, # Make it optional. See t/pod.t |
426 | +# Test::Pod::Coverage => 1.08, # Make it optional. See t/pod.t |
427 | + Test::More => 0.47, |
428 | + Test::Warn => 0.08, |
429 | + warnings => 0, |
430 | + }, |
431 | + INSTALLDIRS => 'site', |
432 | + EXE_FILES => [], |
433 | + PL_FILES => {}, |
434 | + test => |
435 | + { |
436 | + TESTS => 't/*.t t/Tree_Binary/*.t t/Tree/*.t t/Tree_Fast/*.t', |
437 | + }, |
438 | +); |
439 | |
440 | === added file 'README' |
441 | --- README 1970-01-01 00:00:00 +0000 |
442 | +++ README 2014-12-12 23:08:52 +0000 |
443 | @@ -0,0 +1,49 @@ |
444 | +README file for Tree. |
445 | + |
446 | +See also: CHANGES and Changelog.ini. |
447 | + |
448 | +Warning: WinZip 8.1 and 9.0 both contain an 'accidental' bug which stops |
449 | +them recognizing POSIX-style directory structures in valid tar files. |
450 | +You are better off using a reliable tool such as InfoZip: |
451 | +ftp://ftp.info-zip.org/pub/infozip/ |
452 | + |
453 | +1 Installing from a Unix-like distro |
454 | +------------------------------------ |
455 | +shell>gunzip Tree-1.03.tgz |
456 | +shell>tar mxvf Tree-1.03.tar |
457 | + |
458 | +On Unix-like systems, assuming you have installed Module::Build V 0.25+: |
459 | + |
460 | +shell>perl Build.PL |
461 | +shell>./Build |
462 | +shell>./Build test |
463 | +shell>./Build install |
464 | + |
465 | +On MS Windows-like systems, assuming you have installed Module::Build V 0.25+: |
466 | + |
467 | +shell>perl Build.PL |
468 | +shell>perl Build |
469 | +shell>perl Build test |
470 | +shell>perl Build install |
471 | + |
472 | +Alternately, without Module::Build, you do this: |
473 | + |
474 | +Note: 'make' on MS Windows-like systems may be called 'nmake' or 'dmake'. |
475 | + |
476 | +shell>perl Makefile.PL |
477 | +shell>make |
478 | +shell>make test |
479 | +shell>su (for Unix-like systems) |
480 | +shell>make install |
481 | +shell>exit (for Unix-like systems) |
482 | + |
483 | +On all systems: |
484 | + |
485 | +Run Tree.pm through your favourite pod2html translator. |
486 | + |
487 | +2 Installing from an ActiveState distro |
488 | +--------------------------------------- |
489 | +shell>unzip Tree-1.03.zip |
490 | +shell>ppm install --location=. Tree |
491 | +shell>del Tree-1.03.ppd |
492 | +shell>del PPM-Tree-1.03.tar.gz |
493 | |
494 | === modified file 'debian/changelog' |
495 | --- debian/changelog 2010-02-09 20:55:43 +0000 |
496 | +++ debian/changelog 2014-12-12 23:08:52 +0000 |
497 | @@ -1,3 +1,9 @@ |
498 | +libtree-perl (1.05-0ubuntu1) vivid; urgency=medium |
499 | + |
500 | + * New upstream release. |
501 | + |
502 | + -- Jackson Doak <noskcaj@ubuntu.com> Sat, 13 Dec 2014 08:10:01 +1100 |
503 | + |
504 | libtree-perl (1.01-0ubuntu2) lucid; urgency=low |
505 | |
506 | * debian/control: |
507 | |
508 | === modified file 'lib/Tree.pm' |
509 | --- lib/Tree.pm 2008-01-17 12:56:58 +0000 |
510 | +++ lib/Tree.pm 2014-12-12 23:08:52 +0000 |
511 | @@ -5,7 +5,7 @@ |
512 | use strict; |
513 | use warnings FATAL => 'all'; |
514 | |
515 | -our $VERSION = '1.01'; |
516 | +our $VERSION = '1.05'; |
517 | |
518 | use Scalar::Util qw( blessed refaddr weaken ); |
519 | |
520 | @@ -32,9 +32,9 @@ |
521 | }, |
522 | ); |
523 | |
524 | -sub QUIET { return $error_handlers{ 'quiet' } } |
525 | -sub WARN { return $error_handlers{ 'warn' } } |
526 | -sub DIE { return $error_handlers{ 'die' } } |
527 | +sub QUIET { return $error_handlers{ 'quiet' } } |
528 | +sub WARN { return $error_handlers{ 'warn' } } |
529 | +sub DIE { return $error_handlers{ 'die' } } |
530 | |
531 | # The default error handler is quiet |
532 | my $ERROR_HANDLER = $error_handlers{ 'quiet' }; |
533 | @@ -381,7 +381,7 @@ |
534 | |
535 | =head1 NAME |
536 | |
537 | -Tree - an N-ary tree |
538 | +Tree - An N-ary tree |
539 | |
540 | =head1 SYNOPSIS |
541 | |
542 | @@ -419,6 +419,9 @@ |
543 | value => sub { ... }, |
544 | }); |
545 | |
546 | + my $old_default_error_handler = $tree->error_handler(Tree->DIE); |
547 | + my $old_object_error_handler = $tree->error_handler($tree->DIE); |
548 | + |
549 | =head1 DESCRIPTION |
550 | |
551 | This is meant to be a full-featured N-ary tree representation with |
552 | @@ -428,39 +431,35 @@ |
553 | |
554 | =head1 METHODS |
555 | |
556 | -=head2 Constructor |
557 | - |
558 | -=over 4 |
559 | - |
560 | -=item B<new([$value])> |
561 | - |
562 | -This will return a Tree object. It will accept one parameter which, if passed, |
563 | -will become the value (accessible by C<value()>). All other parameters will be |
564 | +=head2 Constructors |
565 | + |
566 | +=head2 new([$value]) |
567 | + |
568 | +Here, [] indicate an optional parameter. |
569 | + |
570 | +This will return a C<Tree> object. It will accept one parameter which, if passed, |
571 | +will become the I<value> (accessible by C<value()>). All other parameters will be |
572 | ignored. |
573 | |
574 | -If you call C<$tree-E<gt>new([$value])>, it will instead call C<clone()>, then set |
575 | -the value of the clone to $value. |
576 | +If you call C<< $tree->new([$value]) >>, it will instead call C<clone()>, then set |
577 | +the I<value> of the clone to $value. |
578 | |
579 | -=item B<clone()> |
580 | +=head2 clone() |
581 | |
582 | This will return a clone of C<$tree>. The clone will be a root tree, but all |
583 | children will be cloned. |
584 | |
585 | -If you call L<Tree-E<gt>clone([$value])>, it will instead call C<new()>. |
586 | +If you call C<< Tree->clone([$value]) >>, it will instead call C<new($value)>. |
587 | |
588 | B<NOTE:> the value is merely a shallow copy. This means that all references |
589 | will be kept. |
590 | |
591 | -=back |
592 | - |
593 | =head2 Behaviors |
594 | |
595 | -=over 4 |
596 | - |
597 | -=item B<add_child([$options], @nodes)> |
598 | +=head2 add_child([$options], @nodes) |
599 | |
600 | This will add all the C<@nodes> as children of C<$tree>. $options is a optional |
601 | -unblessed hashref that specifies options for add_child(). The optional |
602 | +unblessed hashref that specifies options for C<add_child()>. The optional |
603 | parameters are: |
604 | |
605 | =over 4 |
606 | @@ -469,11 +468,17 @@ |
607 | |
608 | This specifies the index to add C<@nodes> at. If specified, this will be passed |
609 | into splice(). The only exceptions are if this is 0, it will act as an |
610 | -unshift(). If it is unset or undefined, it will act as a push(). |
611 | +unshift(). If it is unset or undefined, it will act as a push(). Lastly, if it is out of range |
612 | +(too negative or too big [beyond the number of children]) the child is not added, and an error msg |
613 | +will be available in L</last_error()>. |
614 | |
615 | =back |
616 | |
617 | -=item B<remove_child([$options], @nodes)> |
618 | +add_child() resets last_error() upon entry. |
619 | + |
620 | +=head2 remove_child([$options], @nodes) |
621 | + |
622 | +Here, [] indicate an optional parameter. |
623 | |
624 | This will remove all the C<@nodes> from the children of C<$tree>. You can either |
625 | pass in the actual child object you wish to remove, the index of the child you |
626 | @@ -482,16 +487,23 @@ |
627 | $options is a optional unblessed hashref that specifies parameters for |
628 | remove_child(). Currently, no parameters are used. |
629 | |
630 | -=item B<mirror()> |
631 | +remove_child() resets last_error() upon entry. |
632 | + |
633 | +=head2 mirror() |
634 | |
635 | This will modify the tree such that it is a mirror of what it was before. This |
636 | means that the order of all children is reversed. |
637 | |
638 | B<NOTE>: This is a destructive action. It I<will> modify the tree's internal |
639 | structure. If you wish to get a mirror, yet keep the original tree intact, use |
640 | -C<my $mirror = $tree-E<gt>clone-E<gt>mirror;> |
641 | - |
642 | -=item B<traverse( [$order] )> |
643 | +C<< my $mirror = $tree->clone->mirror >>. |
644 | + |
645 | +mirror() does not reset last_error() because it (mirror() ) is implemented in L<Tree::Fast>, |
646 | +which has no error handling. |
647 | + |
648 | +=head2 traverse([$order]) |
649 | + |
650 | +Here, [] indicate an optional parameter. |
651 | |
652 | This will return a list of the nodes in the given traversal order. The default |
653 | traversal order is pre-order. |
654 | @@ -500,65 +512,63 @@ |
655 | |
656 | =over 4 |
657 | |
658 | -=item * Pre-order (aka Prefix traversal) |
659 | +=item * Pre-order |
660 | |
661 | This will return the node, then the first sub tree in pre-order traversal, |
662 | then the next sub tree, etc. |
663 | |
664 | -Use C<$tree-E<gt>PRE_ORDER> as the C<$order>. |
665 | +Use C<< $tree->PRE_ORDER >> as the C<$order>. |
666 | |
667 | -=item * Post-order (aka Prefix traversal) |
668 | +=item * Post-order |
669 | |
670 | This will return the each sub-tree in post-order traversal, then the node. |
671 | |
672 | -Use C<$tree-E<gt>POST_ORDER> as the C<$order>. |
673 | +Use C<< $tree->POST_ORDER >> as the C<$order>. |
674 | |
675 | -=item * Level-order (aka Prefix traversal) |
676 | +=item * Level-order |
677 | |
678 | This will return the node, then the all children of the node, then all |
679 | grandchildren of the node, etc. |
680 | |
681 | -Use C<$tree-E<gt>LEVEL_ORDER> as the C<$order>. |
682 | - |
683 | -=back |
684 | - |
685 | -=back |
686 | - |
687 | -All behaviors will reset last_error(). |
688 | +Use C<< $tree->LEVEL_ORDER >> as the C<$order>. |
689 | + |
690 | +=back |
691 | + |
692 | +traverse() does not reset last_error() because it (traverse() ) is implemented in L<Tree::Fast>, |
693 | +which has no error handling. |
694 | |
695 | =head2 State Queries |
696 | |
697 | -=over 4 |
698 | - |
699 | -=item * B<is_root()> |
700 | - |
701 | -This will return true is C<$tree> has no parent and false otherwise. |
702 | - |
703 | -=item * B<is_leaf()> |
704 | - |
705 | -This will return true is C<$tree> has no children and false otherwise. |
706 | - |
707 | -=item * B<has_child(@nodes)> |
708 | - |
709 | -This will return true is C<$tree> has each of the C<@nodes> as a child. |
710 | +=head2 is_root() |
711 | + |
712 | +This will return true if C<$tree> has no parent and false otherwise. |
713 | + |
714 | +=head2 is_leaf() |
715 | + |
716 | +This will return true if C<$tree> has no children and false otherwise. |
717 | + |
718 | +=head2 has_child(@nodes) |
719 | + |
720 | +This will return true if C<$tree> has each of the C<@nodes> as a child. |
721 | Otherwise, it will return false. |
722 | |
723 | -=item * B<get_index_for(@nodes)> |
724 | - |
725 | -This will return the index into the children list for each of the C<@nodes> |
726 | +The test to see if a node is in the tree uses refaddr() from L<Scalar::Util>, not the I<value> of the node. |
727 | +This means C<@nodes> must be an array of C<Tree> objects. |
728 | + |
729 | +=head2 get_index_for(@nodes) |
730 | + |
731 | +This will return the index into the children list of C<$tree> for each of the C<@nodes> |
732 | passed in. |
733 | |
734 | -=back |
735 | - |
736 | =head2 Accessors |
737 | |
738 | -=over 4 |
739 | - |
740 | -=item * B<parent()> |
741 | +=head2 parent() |
742 | |
743 | This will return the parent of C<$tree>. |
744 | |
745 | -=item * B<children( [ $idx, [$idx, ..] ] )> |
746 | +=head2 children( [ $idx, [$idx, ..] ] ) |
747 | + |
748 | +Here, [] indicate optional parameters. |
749 | |
750 | This will return the children of C<$tree>. If called in list context, it will |
751 | return all the children. If called in scalar context, it will return the |
752 | @@ -568,22 +578,22 @@ |
753 | children in the order you asked for them. This is very much like an |
754 | arrayslice. |
755 | |
756 | -=item * B<root()> |
757 | +=head2 root() |
758 | |
759 | This will return the root node of the tree that C<$tree> is in. The root of |
760 | the root node is itself. |
761 | |
762 | -=item * B<height()> |
763 | +=head2 height() |
764 | |
765 | This will return the height of C<$tree>. A leaf has a height of 1. A parent |
766 | has a height of its tallest child, plus 1. |
767 | |
768 | -=item * B<width()> |
769 | +=head2 width() |
770 | |
771 | This will return the width of C<$tree>. A leaf has a width of 1. A parent has |
772 | a width equal to the sum of all the widths of its children. |
773 | |
774 | -=item * B<depth()> |
775 | +=head2 depth() |
776 | |
777 | This will return the depth of C<$tree>. A root has a depth of 0. A child has |
778 | the depth of its parent, plus 1. |
779 | @@ -591,21 +601,25 @@ |
780 | This is the distance from the root. It's useful for things like |
781 | pretty-printing the tree. |
782 | |
783 | -=item * B<size()> |
784 | +=head2 size() |
785 | |
786 | This will return the number of nodes within C<$tree>. A leaf has a size of 1. |
787 | A parent has a size equal to the 1 plus the sum of all the sizes of its |
788 | children. |
789 | |
790 | -=item * B<value()> |
791 | +=head2 value() |
792 | |
793 | This will return the value stored in the node. |
794 | |
795 | -=item * B<set_value([$value])> |
796 | - |
797 | -This will set the value stored in the node to $value, then return $self. |
798 | - |
799 | -=item * B<meta()> |
800 | +=head2 set_value([$value]) |
801 | + |
802 | +Here, [] indicate an optional parameter. |
803 | + |
804 | +This will set the I<value> stored in the node to $value, then return $self. |
805 | + |
806 | +If C<$value> is not provided, undef is used. |
807 | + |
808 | +=head2 meta() |
809 | |
810 | This will return a hashref that can be used to store whatever metadata the |
811 | client wishes to store. For example, L<Tree::Persist::DB> uses this to store |
812 | @@ -616,8 +630,6 @@ |
813 | this, using a unique key for each persistence layer associated with that tree. |
814 | This will help prevent clobbering of metadata. |
815 | |
816 | -=back |
817 | - |
818 | =head1 ERROR HANDLING |
819 | |
820 | Describe what the default error handlers do and what a custom error handler is |
821 | @@ -625,9 +637,7 @@ |
822 | |
823 | =head2 Error-related methods |
824 | |
825 | -=over 4 |
826 | - |
827 | -=item * B<error_handler( [ $handler ] )> |
828 | +=head2 error_handler( [ $handler ] ) |
829 | |
830 | This will return the current error handler for the tree. If a value is passed |
831 | in, then it will be used to set the error handler for the tree. |
832 | @@ -635,19 +645,17 @@ |
833 | If called as a class method, this will instead work with the default error |
834 | handler. |
835 | |
836 | -=item * B<error( $error, [ arg1 [, arg2 ...] ] )> |
837 | +=head2 error( $error, [ arg1 [, arg2 ...] ] ) |
838 | |
839 | Call this when you wish to report an error using the currently defined |
840 | error_handler for the tree. The only guaranteed parameter is an error string |
841 | describing the issue. There may be other arguments, and you may certainly |
842 | provide other arguments in your subclass to be passed to your custom handler. |
843 | |
844 | -=item * B<last_error()> |
845 | +=head2 last_error() |
846 | |
847 | If an error occurred during the last behavior, this will return the error |
848 | -string. It is reset only when a behavior is called. |
849 | - |
850 | -=back |
851 | +string. It is reset only by add_child() and remove_child(). |
852 | |
853 | =head2 Default error handlers |
854 | |
855 | @@ -656,7 +664,7 @@ |
856 | =item QUIET |
857 | |
858 | Use this error handler if you want to have quiet error-handling. The |
859 | -last_error method will retrieve the error from the last operation, if there |
860 | +L</last_error()> method will retrieve the error from the last operation, if there |
861 | was one. If an error occurs, the operation will return undefined. |
862 | |
863 | =item WARN |
864 | @@ -667,7 +675,7 @@ |
865 | |
866 | =head1 EVENT HANDLING |
867 | |
868 | -Forest provides for basic event handling. You may choose to register one or |
869 | +Tree provides for basic event handling. You may choose to register one or |
870 | more callbacks to be called when the appropriate event occurs. The events |
871 | are: |
872 | |
873 | @@ -675,14 +683,14 @@ |
874 | |
875 | =item * add_child |
876 | |
877 | -This event will trigger as the last step in an L<add_child()> call. |
878 | +This event will trigger as the last step in an L</add_child([$options], @nodes)> call. |
879 | |
880 | The parameters will be C<( $self, @args )> where C<@args> is the arguments |
881 | passed into the add_child() call. |
882 | |
883 | =item * remove_child |
884 | |
885 | -This event will trigger as the last step in an L<remove_child()> call. |
886 | +This event will trigger as the last step in an L</remove_child([$options], @nodes)> call. |
887 | |
888 | The parameters will be C<( $self, @args )> where C<@args> is the arguments |
889 | passed into the remove_child() call. |
890 | @@ -699,14 +707,12 @@ |
891 | |
892 | =head2 Event handling methods |
893 | |
894 | -=over 4 |
895 | - |
896 | -=item * B<add_event_handler( $type => $callback [, $type => $callback, ... ])> |
897 | +=head2 add_event_handler( {$type => $callback [, $type => $callback, ... ]} ) |
898 | |
899 | You may choose to add event handlers for any known type. Callbacks must be |
900 | references to subroutines. They will be called in the order they are defined. |
901 | |
902 | -=item * B<event( $type, $actor, @args )> |
903 | +=head2 event( $type, $actor, @args ) |
904 | |
905 | This will trigger an event of type C<$type>. All event handlers registered on |
906 | C<$tree> will be called with parameters of C<($actor, @args)>. Then, the |
907 | @@ -716,14 +722,12 @@ |
908 | This allows you specify an event handler on the root and be guaranteed that it |
909 | will fire every time the appropriate event occurs anywhere in the tree. |
910 | |
911 | -=back |
912 | - |
913 | =head1 NULL TREE |
914 | |
915 | If you call C<$self-E<gt>parent> on a root node, it will return a Tree::Null |
916 | object. This is an implementation of the Null Object pattern optimized for |
917 | usage with L<Tree>. It will evaluate as false in every case (using |
918 | -L<overload>) and all methods called on it will return a Tree::Null object. |
919 | +I<overload>) and all methods called on it will return a Tree::Null object. |
920 | |
921 | =head2 Notes |
922 | |
923 | @@ -754,11 +758,13 @@ |
924 | |
925 | Please q.v. L<Forest> for more info on this topic. |
926 | |
927 | -=head1 WHAT'S NOT HERE |
928 | - |
929 | -=over 4 |
930 | - |
931 | -=item * The Visitor pattern |
932 | +=head1 FAQ |
933 | + |
934 | +=head2 Which is the best tree processing module? |
935 | + |
936 | +L<Tree::DAG_Node>. More details: L</SEE ALSO>. |
937 | + |
938 | +=head2 How do I implement the visitor pattern? |
939 | |
940 | I have deliberately chosen to not implement the Visitor pattern as described |
941 | by Gamma et al. Given a sufficiently powerful C<traverse()> and Perl's |
942 | @@ -787,10 +793,42 @@ |
943 | } |
944 | } |
945 | |
946 | +=head2 Should I implement the visitor pattern? |
947 | + |
948 | +No. You're better off using the L<Tree::DAG_Node/walk_down($options)> method. |
949 | + |
950 | +=head1 SEE ALSO |
951 | + |
952 | +=over 4 |
953 | + |
954 | +=item o L<Tree::Binary> |
955 | + |
956 | +Lightweight. |
957 | + |
958 | +=item o L<Tree::DAG_Node> |
959 | + |
960 | +Lightweight, and with a long list of methods. |
961 | + |
962 | +=item o L<Tree::DAG_Node::Persist> |
963 | + |
964 | +Lightweight. |
965 | + |
966 | +=item o L<Tree::Persist> |
967 | + |
968 | +Lightweight. |
969 | + |
970 | +=item o L<Forest> |
971 | + |
972 | +Uses L<Moose>. |
973 | + |
974 | =back |
975 | |
976 | +C<Tree> itself is also lightweight. |
977 | + |
978 | =head1 CODE COVERAGE |
979 | |
980 | +These statistics are as of V 1.01. |
981 | + |
982 | We use L<Devel::Cover> to test the code coverage of our tests. Below is the |
983 | L<Devel::Cover> report on this module's test suite. |
984 | |
985 | @@ -824,6 +862,9 @@ |
986 | |
987 | Thanks to Infinity Interactive for generously donating our time. |
988 | |
989 | +Co-maintenance since V 1.02 is by Ron Savage <rsavage@cpan.org>. |
990 | +Uses of 'I' in previous versions is not me, but will be hereafter. |
991 | + |
992 | =head1 COPYRIGHT AND LICENSE |
993 | |
994 | Copyright 2004, 2005 by Infinity Interactive, Inc. |
995 | @@ -831,6 +872,6 @@ |
996 | L<http://www.iinteractive.com> |
997 | |
998 | This library is free software; you can redistribute it and/or modify it under |
999 | -the same terms as Perl itself. |
1000 | +the same terms as Perl itself. |
1001 | |
1002 | =cut |
1003 | |
1004 | === removed file 'lib/Tree/Binary.pm' |
1005 | --- lib/Tree/Binary.pm 2008-01-17 12:56:58 +0000 |
1006 | +++ lib/Tree/Binary.pm 1970-01-01 00:00:00 +0000 |
1007 | @@ -1,330 +0,0 @@ |
1008 | -package Tree::Binary; |
1009 | - |
1010 | -use 5.006; |
1011 | - |
1012 | -use strict; |
1013 | -use warnings FATAL => 'all'; |
1014 | - |
1015 | -use Scalar::Util qw( blessed ); |
1016 | - |
1017 | -use base qw( Tree ); |
1018 | - |
1019 | -our $VERSION = '1.01'; |
1020 | - |
1021 | -sub _init { |
1022 | - my $self = shift; |
1023 | - $self->SUPER::_init( @_ ); |
1024 | - |
1025 | - # Make this class a complete binary tree, |
1026 | - # filling in with Tree::Null as appropriate. |
1027 | - $self->{_children}->[$_] = $self->_null |
1028 | - for 0 .. 1; |
1029 | - |
1030 | - return $self; |
1031 | -} |
1032 | - |
1033 | -sub left { |
1034 | - my $self = shift; |
1035 | - return $self->_set_get_child( 0, @_ ); |
1036 | -} |
1037 | - |
1038 | -sub right { |
1039 | - my $self = shift; |
1040 | - return $self->_set_get_child( 1, @_ ); |
1041 | -} |
1042 | - |
1043 | -sub _set_get_child { |
1044 | - my $self = shift; |
1045 | - my $index = shift; |
1046 | - |
1047 | - if ( @_ ) { |
1048 | - my $node = shift; |
1049 | - $node = $self->_null unless $node; |
1050 | - |
1051 | - my $old = $self->children->[$index]; |
1052 | - $self->children->[$index] = $node; |
1053 | - |
1054 | - if ( $node ) { |
1055 | - $node->_set_parent( $self ); |
1056 | - $node->_set_root( $self->root ); |
1057 | - $node->_fix_depth; |
1058 | - } |
1059 | - |
1060 | - if ( $old ) { |
1061 | - $old->_set_parent( $old->_null ); |
1062 | - $old->_set_root( $old->_null ); |
1063 | - $old->_fix_depth; |
1064 | - } |
1065 | - |
1066 | - $self->_fix_height; |
1067 | - $self->_fix_width; |
1068 | - |
1069 | - return $self; |
1070 | - } |
1071 | - else { |
1072 | - return $self->children->[$index]; |
1073 | - } |
1074 | -} |
1075 | - |
1076 | -sub _clone_children { |
1077 | - my ($self, $clone) = @_; |
1078 | - |
1079 | - @{ $clone->{_children} } = (); |
1080 | - $clone->add_child({}, map { $_->clone } @{ $self->{_children} }); |
1081 | -} |
1082 | - |
1083 | -sub children { |
1084 | - my $self = shift; |
1085 | - if ( @_ ) { |
1086 | - my @idx = @_; |
1087 | - return @{$self->{_children}}[@idx]; |
1088 | - } |
1089 | - else { |
1090 | - if ( caller->isa( __PACKAGE__ ) || $self->isa( scalar(caller) ) ) { |
1091 | - return wantarray ? @{$self->{_children}} : $self->{_children}; |
1092 | - } |
1093 | - else { |
1094 | - return grep { $_ } @{$self->{_children}}; |
1095 | - } |
1096 | - } |
1097 | -} |
1098 | - |
1099 | -use constant IN_ORDER => 4; |
1100 | - |
1101 | -# One of the things we have to do in a traversal is to remove all of the |
1102 | -# Tree::Null elements that are appended to the tree to make this a complete |
1103 | -# binary tree. The user isn't going to expect them, because they're an |
1104 | -# internal nicety. |
1105 | - |
1106 | -sub traverse { |
1107 | - my $self = shift; |
1108 | - my $order = shift; |
1109 | - $order = $self->PRE_ORDER unless $order; |
1110 | - |
1111 | - if ( wantarray ) { |
1112 | - if ( $order == $self->IN_ORDER ) { |
1113 | - return grep { $_ } ( |
1114 | - $self->left->traverse( $order ), |
1115 | - $self, |
1116 | - $self->right->traverse( $order ), |
1117 | - ); |
1118 | - } |
1119 | - else { |
1120 | - return grep { $_ } $self->SUPER::traverse( $order ); |
1121 | - } |
1122 | - } |
1123 | - else { |
1124 | - my $closure; |
1125 | - |
1126 | - if ( $order eq $self->IN_ORDER ) { |
1127 | - my @list = $self->traverse( $order ); |
1128 | - |
1129 | - $closure = sub { |
1130 | - return unless @list; |
1131 | - return shift @list; |
1132 | - }; |
1133 | - } |
1134 | - elsif ( $order eq $self->PRE_ORDER ) { |
1135 | - my $next_node = $self; |
1136 | - my @stack = ( $self ); |
1137 | - my @next_meth = ( 0 ); |
1138 | - |
1139 | - my @meths = qw( left right ); |
1140 | - $closure = sub { |
1141 | - my $node = $next_node; |
1142 | - return unless $node; |
1143 | - $next_node = undef; |
1144 | - |
1145 | - while ( @stack && !$next_node ) { |
1146 | - while ( @next_meth && $next_meth[0] == 2 ) { |
1147 | - shift @stack; |
1148 | - shift @next_meth; |
1149 | - } |
1150 | - |
1151 | - if ( @stack ) { |
1152 | - my $meth = $meths[ $next_meth[0]++ ]; |
1153 | - $next_node = $stack[0]->$meth; |
1154 | - next unless $next_node; |
1155 | - unshift @stack, $next_node; |
1156 | - unshift @next_meth, 0; |
1157 | - } |
1158 | - } |
1159 | - |
1160 | - return $node; |
1161 | - }; |
1162 | - } |
1163 | - elsif ( $order eq $self->POST_ORDER ) { |
1164 | - my @list = $self->traverse( $order ); |
1165 | - |
1166 | - $closure = sub { |
1167 | - return unless @list; |
1168 | - return shift @list; |
1169 | - }; |
1170 | - #my @stack = ( $self ); |
1171 | - #my @next_idx = ( 0 ); |
1172 | - #while ( @{ $stack[0]->{_children} } ) { |
1173 | - # unshift @stack, $stack[0]->{_children}[0]; |
1174 | - # unshift @next_idx, 0; |
1175 | - #} |
1176 | - # |
1177 | - #$closure = sub { |
1178 | - # my $node = $stack[0] || return; |
1179 | - # |
1180 | - # shift @stack; shift @next_idx; |
1181 | - # $next_idx[0]++; |
1182 | - # |
1183 | - # while ( @stack && exists $stack[0]->{_children}[ $next_idx[0] ] ) { |
1184 | - # unshift @stack, $stack[0]->{_children}[ $next_idx[0] ]; |
1185 | - # unshift @next_idx, 0; |
1186 | - # } |
1187 | - # |
1188 | - # return $node; |
1189 | - #}; |
1190 | - } |
1191 | - elsif ( $order eq $self->LEVEL_ORDER ) { |
1192 | - my @nodes = ($self); |
1193 | - $closure = sub { |
1194 | - my $node = shift @nodes; |
1195 | - return unless $node; |
1196 | - push @nodes, grep { $_ } @{$node->{_children}}; |
1197 | - return $node; |
1198 | - }; |
1199 | - } |
1200 | - else { |
1201 | - return $self->error( "traverse(): '$order' is an illegal traversal order" ); |
1202 | - } |
1203 | - |
1204 | - return $closure; |
1205 | - } |
1206 | -} |
1207 | - |
1208 | -1; |
1209 | -__END__ |
1210 | - |
1211 | -=head1 NAME |
1212 | - |
1213 | -Tree::Binary - An implementation of a binary tree |
1214 | - |
1215 | -=head1 SYNOPSIS |
1216 | - |
1217 | - my $tree = Tree::Binary->new( 'root' ); |
1218 | - |
1219 | - my $left = Tree::Binary->new( 'left' ); |
1220 | - $tree->left( $left ); |
1221 | - |
1222 | - my $right = Tree::Binary->new( 'left' ); |
1223 | - $tree->right( $right ); |
1224 | - |
1225 | - my $right_child = $tree->right; |
1226 | - |
1227 | - $tree->right( undef ); # Unset the right child. |
1228 | - |
1229 | - my @nodes = $tree->traverse( $tree->POST_ORDER ); |
1230 | - |
1231 | - my $traversal = $tree->traverse( $tree->IN_ORDER ); |
1232 | - while ( my $node = $traversal->() ) { |
1233 | - # Do something with $node here |
1234 | - } |
1235 | - |
1236 | -=head1 DESCRIPTION |
1237 | - |
1238 | -This is an implementation of a binary tree. This class inherits from L<Tree>, |
1239 | -which is an N-ary tree implemenation. Because of this, this class actually |
1240 | -provides an implementation of a complete binary tree vs. a sparse binary tree. |
1241 | -The empty nodes are instances of Tree::Null, which is described in L<Tree>. |
1242 | -This should have no effect on your usage of this class. |
1243 | - |
1244 | -=head1 METHODS |
1245 | - |
1246 | -In addition to the methods provided by L<Tree>, the following items are |
1247 | -provided or overriden. |
1248 | - |
1249 | -=over 4 |
1250 | - |
1251 | -=item * C<left([$child])> / C<right([$child])> |
1252 | - |
1253 | -These access the left and right children, respectively. They are mutators, |
1254 | -which means that their behavior changes depending on if you pass in a value. |
1255 | - |
1256 | -If you do not pass in any parameters, then it will act as a getter for the |
1257 | -specific child, return the child (if set) or undef (if not). |
1258 | - |
1259 | -If you pass in a child, it will act as a setter for the specific child, |
1260 | -setting the child to the passed-in value and returning the $tree. (Thus, this |
1261 | -method chains.) |
1262 | - |
1263 | -If you wish to unset the child, do C<$treeE<gt>left( undef );> |
1264 | - |
1265 | -=item * C<children()> |
1266 | - |
1267 | -This will return the children of the tree. |
1268 | - |
1269 | -B<NOTE:> There will be two children, always. Tree::Binary implements a |
1270 | -complete binary tree, filling in missing children with Tree::Null objects. |
1271 | -(Please see L<Tree::Fast> for more information on Tree::Null.) |
1272 | - |
1273 | -=item * B<traverse( [$order] )> |
1274 | - |
1275 | -When called in list context (C<my @traversal = $tree-E<gt>traverse()>), this will |
1276 | -return a list of the nodes in the given traversal order. When called in scalar |
1277 | -context (C<my $traversal = $tree-E<gt>traverse()>), this will return a closure |
1278 | -that will, over successive calls, iterate over the nodes in the given |
1279 | -traversal order. When finished it will return false. |
1280 | - |
1281 | -The default traversal order is pre-order. |
1282 | - |
1283 | -In addition to the traversal orders provided by L<Tree>, Tree::Binary provides |
1284 | -in-order traversals. |
1285 | - |
1286 | -=over 4 |
1287 | - |
1288 | -=item * In-order |
1289 | - |
1290 | -This will return the result of an in-order traversal on the left node (if |
1291 | -any), then the node, then the result of an in-order traversal on the right |
1292 | -node (if any). |
1293 | - |
1294 | -=back |
1295 | - |
1296 | -=back |
1297 | - |
1298 | -B<NOTE:> You have access to all the methods provided by L<Tree>, but it is not |
1299 | -recommended that you use many of them, unless you know what you're doing. This |
1300 | -list includes C<add_child()> and C<remove_child()>. |
1301 | - |
1302 | -=head1 TODO |
1303 | - |
1304 | -=over 4 |
1305 | - |
1306 | -=item * Make in-order closure traversal work iteratively |
1307 | - |
1308 | -=item * Make post-order closure traversal work iteratively |
1309 | - |
1310 | -=back |
1311 | - |
1312 | -=head1 CODE COVERAGE |
1313 | - |
1314 | -Please see the relevant sections of L<Tree>. |
1315 | - |
1316 | -=head1 SUPPORT |
1317 | - |
1318 | -Please see the relevant sections of L<Tree>. |
1319 | - |
1320 | -=head1 AUTHORS |
1321 | - |
1322 | -Rob Kinyon E<lt>rob.kinyon@iinteractive.comE<gt> |
1323 | - |
1324 | -Stevan Little E<lt>stevan.little@iinteractive.comE<gt> |
1325 | - |
1326 | -Thanks to Infinity Interactive for generously donating our time. |
1327 | - |
1328 | -=head1 COPYRIGHT AND LICENSE |
1329 | - |
1330 | -Copyright 2004, 2005 by Infinity Interactive, Inc. |
1331 | - |
1332 | -L<http://www.iinteractive.com> |
1333 | - |
1334 | -This library is free software; you can redistribute it and/or modify it under |
1335 | -the same terms as Perl itself. |
1336 | - |
1337 | -=cut |
1338 | |
1339 | === added file 'lib/Tree/Binary2.pm' |
1340 | --- lib/Tree/Binary2.pm 1970-01-01 00:00:00 +0000 |
1341 | +++ lib/Tree/Binary2.pm 2014-12-12 23:08:52 +0000 |
1342 | @@ -0,0 +1,330 @@ |
1343 | +package Tree::Binary2; |
1344 | + |
1345 | +use 5.006; |
1346 | + |
1347 | +use strict; |
1348 | +use warnings FATAL => 'all'; |
1349 | + |
1350 | +use Scalar::Util qw( blessed ); |
1351 | + |
1352 | +use base qw( Tree ); |
1353 | + |
1354 | +our $VERSION = '1.05'; |
1355 | + |
1356 | +sub _init { |
1357 | + my $self = shift; |
1358 | + $self->SUPER::_init( @_ ); |
1359 | + |
1360 | + # Make this class a complete binary tree, |
1361 | + # filling in with Tree::Null as appropriate. |
1362 | + $self->{_children}->[$_] = $self->_null |
1363 | + for 0 .. 1; |
1364 | + |
1365 | + return $self; |
1366 | +} |
1367 | + |
1368 | +sub left { |
1369 | + my $self = shift; |
1370 | + return $self->_set_get_child( 0, @_ ); |
1371 | +} |
1372 | + |
1373 | +sub right { |
1374 | + my $self = shift; |
1375 | + return $self->_set_get_child( 1, @_ ); |
1376 | +} |
1377 | + |
1378 | +sub _set_get_child { |
1379 | + my $self = shift; |
1380 | + my $index = shift; |
1381 | + |
1382 | + if ( @_ ) { |
1383 | + my $node = shift; |
1384 | + $node = $self->_null unless $node; |
1385 | + |
1386 | + my $old = $self->children->[$index]; |
1387 | + $self->children->[$index] = $node; |
1388 | + |
1389 | + if ( $node ) { |
1390 | + $node->_set_parent( $self ); |
1391 | + $node->_set_root( $self->root ); |
1392 | + $node->_fix_depth; |
1393 | + } |
1394 | + |
1395 | + if ( $old ) { |
1396 | + $old->_set_parent( $old->_null ); |
1397 | + $old->_set_root( $old->_null ); |
1398 | + $old->_fix_depth; |
1399 | + } |
1400 | + |
1401 | + $self->_fix_height; |
1402 | + $self->_fix_width; |
1403 | + |
1404 | + return $self; |
1405 | + } |
1406 | + else { |
1407 | + return $self->children->[$index]; |
1408 | + } |
1409 | +} |
1410 | + |
1411 | +sub _clone_children { |
1412 | + my ($self, $clone) = @_; |
1413 | + |
1414 | + @{ $clone->{_children} } = (); |
1415 | + $clone->add_child({}, map { $_->clone } @{ $self->{_children} }); |
1416 | +} |
1417 | + |
1418 | +sub children { |
1419 | + my $self = shift; |
1420 | + if ( @_ ) { |
1421 | + my @idx = @_; |
1422 | + return @{$self->{_children}}[@idx]; |
1423 | + } |
1424 | + else { |
1425 | + if ( caller->isa( __PACKAGE__ ) || $self->isa( scalar(caller) ) ) { |
1426 | + return wantarray ? @{$self->{_children}} : $self->{_children}; |
1427 | + } |
1428 | + else { |
1429 | + return grep { $_ } @{$self->{_children}}; |
1430 | + } |
1431 | + } |
1432 | +} |
1433 | + |
1434 | +use constant IN_ORDER => 4; |
1435 | + |
1436 | +# One of the things we have to do in a traversal is to remove all of the |
1437 | +# Tree::Null elements that are appended to the tree to make this a complete |
1438 | +# binary tree. The user isn't going to expect them, because they're an |
1439 | +# internal nicety. |
1440 | + |
1441 | +sub traverse { |
1442 | + my $self = shift; |
1443 | + my $order = shift; |
1444 | + $order = $self->PRE_ORDER unless $order; |
1445 | + |
1446 | + if ( wantarray ) { |
1447 | + if ( $order == $self->IN_ORDER ) { |
1448 | + return grep { $_ } ( |
1449 | + $self->left->traverse( $order ), |
1450 | + $self, |
1451 | + $self->right->traverse( $order ), |
1452 | + ); |
1453 | + } |
1454 | + else { |
1455 | + return grep { $_ } $self->SUPER::traverse( $order ); |
1456 | + } |
1457 | + } |
1458 | + else { |
1459 | + my $closure; |
1460 | + |
1461 | + if ( $order eq $self->IN_ORDER ) { |
1462 | + my @list = $self->traverse( $order ); |
1463 | + |
1464 | + $closure = sub { |
1465 | + return unless @list; |
1466 | + return shift @list; |
1467 | + }; |
1468 | + } |
1469 | + elsif ( $order eq $self->PRE_ORDER ) { |
1470 | + my $next_node = $self; |
1471 | + my @stack = ( $self ); |
1472 | + my @next_meth = ( 0 ); |
1473 | + |
1474 | + my @meths = qw( left right ); |
1475 | + $closure = sub { |
1476 | + my $node = $next_node; |
1477 | + return unless $node; |
1478 | + $next_node = undef; |
1479 | + |
1480 | + while ( @stack && !$next_node ) { |
1481 | + while ( @next_meth && $next_meth[0] == 2 ) { |
1482 | + shift @stack; |
1483 | + shift @next_meth; |
1484 | + } |
1485 | + |
1486 | + if ( @stack ) { |
1487 | + my $meth = $meths[ $next_meth[0]++ ]; |
1488 | + $next_node = $stack[0]->$meth; |
1489 | + next unless $next_node; |
1490 | + unshift @stack, $next_node; |
1491 | + unshift @next_meth, 0; |
1492 | + } |
1493 | + } |
1494 | + |
1495 | + return $node; |
1496 | + }; |
1497 | + } |
1498 | + elsif ( $order eq $self->POST_ORDER ) { |
1499 | + my @list = $self->traverse( $order ); |
1500 | + |
1501 | + $closure = sub { |
1502 | + return unless @list; |
1503 | + return shift @list; |
1504 | + }; |
1505 | + #my @stack = ( $self ); |
1506 | + #my @next_idx = ( 0 ); |
1507 | + #while ( @{ $stack[0]->{_children} } ) { |
1508 | + # unshift @stack, $stack[0]->{_children}[0]; |
1509 | + # unshift @next_idx, 0; |
1510 | + #} |
1511 | + # |
1512 | + #$closure = sub { |
1513 | + # my $node = $stack[0] || return; |
1514 | + # |
1515 | + # shift @stack; shift @next_idx; |
1516 | + # $next_idx[0]++; |
1517 | + # |
1518 | + # while ( @stack && exists $stack[0]->{_children}[ $next_idx[0] ] ) { |
1519 | + # unshift @stack, $stack[0]->{_children}[ $next_idx[0] ]; |
1520 | + # unshift @next_idx, 0; |
1521 | + # } |
1522 | + # |
1523 | + # return $node; |
1524 | + #}; |
1525 | + } |
1526 | + elsif ( $order eq $self->LEVEL_ORDER ) { |
1527 | + my @nodes = ($self); |
1528 | + $closure = sub { |
1529 | + my $node = shift @nodes; |
1530 | + return unless $node; |
1531 | + push @nodes, grep { $_ } @{$node->{_children}}; |
1532 | + return $node; |
1533 | + }; |
1534 | + } |
1535 | + else { |
1536 | + return $self->error( "traverse(): '$order' is an illegal traversal order" ); |
1537 | + } |
1538 | + |
1539 | + return $closure; |
1540 | + } |
1541 | +} |
1542 | + |
1543 | +1; |
1544 | +__END__ |
1545 | + |
1546 | +=head1 NAME |
1547 | + |
1548 | +Tree::Binary2 - An implementation of a binary tree |
1549 | + |
1550 | +=head1 SYNOPSIS |
1551 | + |
1552 | + my $tree = Tree::Binary2->new( 'root' ); |
1553 | + |
1554 | + my $left = Tree::Binary2->new( 'left' ); |
1555 | + $tree->left( $left ); |
1556 | + |
1557 | + my $right = Tree::Binary2->new( 'left' ); |
1558 | + $tree->right( $right ); |
1559 | + |
1560 | + my $right_child = $tree->right; |
1561 | + |
1562 | + $tree->right( undef ); # Unset the right child. |
1563 | + |
1564 | + my @nodes = $tree->traverse( $tree->POST_ORDER ); |
1565 | + |
1566 | + my $traversal = $tree->traverse( $tree->IN_ORDER ); |
1567 | + while ( my $node = $traversal->() ) { |
1568 | + # Do something with $node here |
1569 | + } |
1570 | + |
1571 | +=head1 DESCRIPTION |
1572 | + |
1573 | +This is an implementation of a binary tree. This class inherits from L<Tree>, |
1574 | +which is an N-ary tree implemenation. Because of this, this class actually |
1575 | +provides an implementation of a complete binary tree vs. a sparse binary tree. |
1576 | +The empty nodes are instances of Tree::Null, which is described in L<Tree>. |
1577 | +This should have no effect on your usage of this class. |
1578 | + |
1579 | +=head1 METHODS |
1580 | + |
1581 | +In addition to the methods provided by L<Tree>, the following items are |
1582 | +provided or overriden. |
1583 | + |
1584 | +=over 4 |
1585 | + |
1586 | +=item * C<left([$child])> / C<right([$child])> |
1587 | + |
1588 | +These access the left and right children, respectively. They are mutators, |
1589 | +which means that their behavior changes depending on if you pass in a value. |
1590 | + |
1591 | +If you do not pass in any parameters, then it will act as a getter for the |
1592 | +specific child, return the child (if set) or undef (if not). |
1593 | + |
1594 | +If you pass in a child, it will act as a setter for the specific child, |
1595 | +setting the child to the passed-in value and returning the $tree. (Thus, this |
1596 | +method chains.) |
1597 | + |
1598 | +If you wish to unset the child, do C<$treeE<gt>left( undef );> |
1599 | + |
1600 | +=item * C<children()> |
1601 | + |
1602 | +This will return the children of the tree. |
1603 | + |
1604 | +B<NOTE:> There will be two children, always. Tree::Binary2 implements a |
1605 | +complete binary tree, filling in missing children with Tree::Null objects. |
1606 | +(Please see L<Tree::Fast> for more information on Tree::Null.) |
1607 | + |
1608 | +=item * B<traverse( [$order] )> |
1609 | + |
1610 | +When called in list context (C<my @traversal = $tree-E<gt>traverse()>), this will |
1611 | +return a list of the nodes in the given traversal order. When called in scalar |
1612 | +context (C<my $traversal = $tree-E<gt>traverse()>), this will return a closure |
1613 | +that will, over successive calls, iterate over the nodes in the given |
1614 | +traversal order. When finished it will return false. |
1615 | + |
1616 | +The default traversal order is pre-order. |
1617 | + |
1618 | +In addition to the traversal orders provided by L<Tree>, Tree::Binary2 provides |
1619 | +in-order traversals. |
1620 | + |
1621 | +=over 4 |
1622 | + |
1623 | +=item * In-order |
1624 | + |
1625 | +This will return the result of an in-order traversal on the left node (if |
1626 | +any), then the node, then the result of an in-order traversal on the right |
1627 | +node (if any). |
1628 | + |
1629 | +=back |
1630 | + |
1631 | +=back |
1632 | + |
1633 | +B<NOTE:> You have access to all the methods provided by L<Tree>, but it is not |
1634 | +recommended that you use many of them, unless you know what you're doing. This |
1635 | +list includes C<add_child()> and C<remove_child()>. |
1636 | + |
1637 | +=head1 TODO |
1638 | + |
1639 | +=over 4 |
1640 | + |
1641 | +=item * Make in-order closure traversal work iteratively |
1642 | + |
1643 | +=item * Make post-order closure traversal work iteratively |
1644 | + |
1645 | +=back |
1646 | + |
1647 | +=head1 CODE COVERAGE |
1648 | + |
1649 | +Please see the relevant sections of L<Tree>. |
1650 | + |
1651 | +=head1 SUPPORT |
1652 | + |
1653 | +Please see the relevant sections of L<Tree>. |
1654 | + |
1655 | +=head1 AUTHORS |
1656 | + |
1657 | +Rob Kinyon E<lt>rob.kinyon@iinteractive.comE<gt> |
1658 | + |
1659 | +Stevan Little E<lt>stevan.little@iinteractive.comE<gt> |
1660 | + |
1661 | +Thanks to Infinity Interactive for generously donating our time. |
1662 | + |
1663 | +=head1 COPYRIGHT AND LICENSE |
1664 | + |
1665 | +Copyright 2004, 2005 by Infinity Interactive, Inc. |
1666 | + |
1667 | +L<http://www.iinteractive.com> |
1668 | + |
1669 | +This library is free software; you can redistribute it and/or modify it under |
1670 | +the same terms as Perl itself. |
1671 | + |
1672 | +=cut |
1673 | |
1674 | === modified file 'lib/Tree/Fast.pm' (properties changed: +x to -x) |
1675 | --- lib/Tree/Fast.pm 2008-01-17 12:56:58 +0000 |
1676 | +++ lib/Tree/Fast.pm 2014-12-12 23:08:52 +0000 |
1677 | @@ -1,543 +1,547 @@ |
1678 | -package Tree::Fast; |
1679 | - |
1680 | -use 5.006; |
1681 | - |
1682 | -use strict; |
1683 | -use warnings FATAL => 'all'; |
1684 | - |
1685 | -our $VERSION = '1.01'; |
1686 | - |
1687 | -use Scalar::Util qw( blessed weaken ); |
1688 | - |
1689 | -sub new { |
1690 | - my $class = shift; |
1691 | - |
1692 | - return $class->clone( @_ ) |
1693 | - if blessed $class; |
1694 | - |
1695 | - my $self = bless {}, $class; |
1696 | - |
1697 | - $self->_init( @_ ); |
1698 | - |
1699 | - return $self; |
1700 | -} |
1701 | - |
1702 | -sub _init { |
1703 | - my $self = shift; |
1704 | - my ($value) = @_; |
1705 | - |
1706 | - $self->{_parent} = $self->_null, |
1707 | - $self->{_children} = []; |
1708 | - $self->{_value} = $value, |
1709 | - |
1710 | - $self->{_meta} = {}; |
1711 | - |
1712 | - return $self; |
1713 | -} |
1714 | - |
1715 | -sub _clone_self { |
1716 | - my $self = shift; |
1717 | - |
1718 | - my $value = @_ ? shift : $self->value; |
1719 | - my $clone = blessed($self)->new( $value ); |
1720 | - return blessed($self)->new( $value ); |
1721 | -} |
1722 | - |
1723 | -sub _clone_children { |
1724 | - my ($self, $clone) = @_; |
1725 | - |
1726 | - if ( my @children = @{$self->{_children}} ) { |
1727 | - $clone->add_child({}, map { $_->clone } @children ); |
1728 | - } |
1729 | -} |
1730 | - |
1731 | -sub clone { |
1732 | - my $self = shift; |
1733 | - |
1734 | - return $self->new(@_) unless blessed $self; |
1735 | - |
1736 | - my $clone = $self->_clone_self(@_); |
1737 | - $self->_clone_children($clone); |
1738 | - |
1739 | - return $clone; |
1740 | -} |
1741 | - |
1742 | -sub add_child { |
1743 | - my $self = shift; |
1744 | - my ( $options, @nodes ) = @_; |
1745 | - |
1746 | - for my $node ( @nodes ) { |
1747 | - $node->_set_parent( $self ); |
1748 | - } |
1749 | - |
1750 | - if ( defined $options->{at} ) { |
1751 | - if ( $options->{at} ) { |
1752 | - splice @{$self->{_children}}, $options->{at}, 0, @nodes; |
1753 | - } |
1754 | - else { |
1755 | - unshift @{$self->{_children}}, @nodes; |
1756 | - } |
1757 | - } |
1758 | - else { |
1759 | - push @{$self->{_children}}, @nodes; |
1760 | - } |
1761 | - |
1762 | - return $self; |
1763 | -} |
1764 | - |
1765 | -sub remove_child { |
1766 | - my $self = shift; |
1767 | - my ($options, @indices) = @_; |
1768 | - |
1769 | - my @return; |
1770 | - for my $idx (sort { $b <=> $a } @indices) { |
1771 | - my $node = splice @{$self->{_children}}, $idx, 1; |
1772 | - $node->_set_parent( $node->_null ); |
1773 | - |
1774 | - push @return, $node; |
1775 | - } |
1776 | - |
1777 | - return @return; |
1778 | -} |
1779 | - |
1780 | -sub parent { |
1781 | - my $self = shift; |
1782 | - return $self->{_parent}; |
1783 | -} |
1784 | - |
1785 | -sub _set_parent { |
1786 | - my $self = shift; |
1787 | - |
1788 | - $self->{_parent} = shift; |
1789 | - weaken( $self->{_parent} ); |
1790 | - |
1791 | - return $self; |
1792 | -} |
1793 | - |
1794 | -sub children { |
1795 | - my $self = shift; |
1796 | - if ( @_ ) { |
1797 | - my @idx = @_; |
1798 | - return @{$self->{_children}}[@idx]; |
1799 | - } |
1800 | - else { |
1801 | - if ( caller->isa( __PACKAGE__ ) || $self->isa( scalar(caller) ) ) { |
1802 | - return wantarray ? @{$self->{_children}} : $self->{_children}; |
1803 | - } |
1804 | - else { |
1805 | - return @{$self->{_children}}; |
1806 | - } |
1807 | - } |
1808 | -} |
1809 | - |
1810 | -sub value { |
1811 | - my $self = shift; |
1812 | - return $self->{_value}; |
1813 | -} |
1814 | - |
1815 | -sub set_value { |
1816 | - my $self = shift; |
1817 | - |
1818 | - $self->{_value} = $_[0]; |
1819 | - |
1820 | - return $self; |
1821 | -} |
1822 | - |
1823 | -sub meta { |
1824 | - my $self = shift; |
1825 | - return $self->{_meta}; |
1826 | -} |
1827 | - |
1828 | -sub mirror { |
1829 | - my $self = shift; |
1830 | - |
1831 | - @{$self->{_children}} = reverse @{$self->{_children}}; |
1832 | - $_->mirror for @{$self->{_children}}; |
1833 | - |
1834 | - return $self; |
1835 | -} |
1836 | - |
1837 | -use constant PRE_ORDER => 1; |
1838 | -use constant POST_ORDER => 2; |
1839 | -use constant LEVEL_ORDER => 3; |
1840 | - |
1841 | -sub traverse { |
1842 | - my $self = shift; |
1843 | - my $order = shift; |
1844 | - $order = $self->PRE_ORDER unless $order; |
1845 | - |
1846 | - if ( wantarray ) { |
1847 | - my @list; |
1848 | - |
1849 | - if ( $order eq $self->PRE_ORDER ) { |
1850 | - @list = ($self); |
1851 | - push @list, map { $_->traverse( $order ) } @{$self->{_children}}; |
1852 | - } |
1853 | - elsif ( $order eq $self->POST_ORDER ) { |
1854 | - @list = map { $_->traverse( $order ) } @{$self->{_children}}; |
1855 | - push @list, $self; |
1856 | - } |
1857 | - elsif ( $order eq $self->LEVEL_ORDER ) { |
1858 | - my @queue = ($self); |
1859 | - while ( my $node = shift @queue ) { |
1860 | - push @list, $node; |
1861 | - push @queue, @{$node->{_children}}; |
1862 | - } |
1863 | - } |
1864 | - else { |
1865 | - return $self->error( "traverse(): '$order' is an illegal traversal order" ); |
1866 | - } |
1867 | - |
1868 | - return @list; |
1869 | - } |
1870 | - else { |
1871 | - my $closure; |
1872 | - |
1873 | - if ( $order eq $self->PRE_ORDER ) { |
1874 | - my $next_node = $self; |
1875 | - my @stack = ( $self ); |
1876 | - my @next_idx = ( 0 ); |
1877 | - |
1878 | - $closure = sub { |
1879 | - my $node = $next_node; |
1880 | - return unless $node; |
1881 | - $next_node = undef; |
1882 | - |
1883 | - while ( @stack && !$next_node ) { |
1884 | - while ( @stack && !exists $stack[0]->{_children}[ $next_idx[0] ] ) { |
1885 | - shift @stack; |
1886 | - shift @next_idx; |
1887 | - } |
1888 | - |
1889 | - if ( @stack ) { |
1890 | - $next_node = $stack[0]->{_children}[ $next_idx[0]++ ]; |
1891 | - unshift @stack, $next_node; |
1892 | - unshift @next_idx, 0; |
1893 | - } |
1894 | - } |
1895 | - |
1896 | - return $node; |
1897 | - }; |
1898 | - } |
1899 | - elsif ( $order eq $self->POST_ORDER ) { |
1900 | - my @stack = ( $self ); |
1901 | - my @next_idx = ( 0 ); |
1902 | - while ( @{ $stack[0]->{_children} } ) { |
1903 | - unshift @stack, $stack[0]->{_children}[0]; |
1904 | - unshift @next_idx, 0; |
1905 | - } |
1906 | - |
1907 | - $closure = sub { |
1908 | - my $node = $stack[0]; |
1909 | - return unless $node; |
1910 | - |
1911 | - shift @stack; shift @next_idx; |
1912 | - $next_idx[0]++; |
1913 | - |
1914 | - while ( @stack && exists $stack[0]->{_children}[ $next_idx[0] ] ) { |
1915 | - unshift @stack, $stack[0]->{_children}[ $next_idx[0] ]; |
1916 | - unshift @next_idx, 0; |
1917 | - } |
1918 | - |
1919 | - return $node; |
1920 | - }; |
1921 | - } |
1922 | - elsif ( $order eq $self->LEVEL_ORDER ) { |
1923 | - my @nodes = ($self); |
1924 | - $closure = sub { |
1925 | - my $node = shift @nodes; |
1926 | - return unless $node; |
1927 | - push @nodes, @{$node->{_children}}; |
1928 | - return $node; |
1929 | - }; |
1930 | - } |
1931 | - else { |
1932 | - return $self->error( "traverse(): '$order' is an illegal traversal order" ); |
1933 | - } |
1934 | - |
1935 | - return $closure; |
1936 | - } |
1937 | -} |
1938 | - |
1939 | -sub _null { |
1940 | - return Tree::Null->new; |
1941 | -} |
1942 | - |
1943 | -package Tree::Null; |
1944 | - |
1945 | -#XXX Add this in once it's been thought out |
1946 | -#our @ISA = qw( Tree ); |
1947 | - |
1948 | -# You want to be able to interrogate the null object as to |
1949 | -# its class, so we don't override isa() as we do can() |
1950 | - |
1951 | -use overload |
1952 | - '""' => sub { return "" }, |
1953 | - '0+' => sub { return 0 }, |
1954 | - 'bool' => sub { return }, |
1955 | - fallback => 1, |
1956 | -; |
1957 | - |
1958 | -{ |
1959 | - my $singleton = bless \my($x), __PACKAGE__; |
1960 | - sub new { return $singleton } |
1961 | - sub AUTOLOAD { return $singleton } |
1962 | - sub can { return sub { return $singleton } } |
1963 | -} |
1964 | - |
1965 | -# The null object can do anything |
1966 | -sub isa { |
1967 | - my ($proto, $class) = @_; |
1968 | - |
1969 | - if ( $class =~ /^Tree(?:::.*)?$/ ) { |
1970 | - return 1; |
1971 | - } |
1972 | - |
1973 | - return $proto->SUPER::isa( $class ); |
1974 | -} |
1975 | - |
1976 | -1; |
1977 | -__END__ |
1978 | - |
1979 | -=head1 NAME |
1980 | - |
1981 | -Tree::Fast - the fastest possible implementation of a tree in pure Perl |
1982 | - |
1983 | -=head1 SYNOPSIS |
1984 | - |
1985 | - my $tree = Tree->new( 'root' ); |
1986 | - my $child = Tree->new( 'child' ); |
1987 | - $tree->add_child( {}, $child ); |
1988 | - |
1989 | - $tree->add_child( { at => 0 }, Tree->new( 'first child' ) ); |
1990 | - $tree->add_child( { at => -1 }, Tree->new( 'last child' ) ); |
1991 | - |
1992 | - my @children = $tree->children; |
1993 | - my @some_children = $tree->children( 0, 2 ); |
1994 | - |
1995 | - $tree->remove_child( 0 ); |
1996 | - |
1997 | - my @nodes = $tree->traverse( $tree->POST_ORDER ); |
1998 | - |
1999 | - my $traversal = $tree->traverse( $tree->POST_ORDER ); |
2000 | - while ( my $node = $traversal->() ) { |
2001 | - # Do something with $node here |
2002 | - } |
2003 | - |
2004 | - my $clone = $tree->clone; |
2005 | - my $mirror = $tree->clone->mirror; |
2006 | - |
2007 | -=head1 DESCRIPTION |
2008 | - |
2009 | -This is meant to be the core implementation for L<Tree>, stripped down as much |
2010 | -as possible. There is no error-checking, bounds-checking, event-handling, |
2011 | -convenience methods, or anything else of the sort. If you want something fuller- |
2012 | -featured, please look at L<Tree>, which is a wrapper around Tree::Fast. |
2013 | - |
2014 | -=head1 METHODS |
2015 | - |
2016 | -=head2 Constructor |
2017 | - |
2018 | -=over 4 |
2019 | - |
2020 | -=item B<new([$value])> |
2021 | - |
2022 | -This will return a Tree object. It will accept one parameter which, if passed, |
2023 | -will become the value (accessible by L<value()>). All other parameters will be |
2024 | -ignored. |
2025 | - |
2026 | -If you call C<$tree-E<gt>new([$value])>, it will instead call C<clone()>, then set |
2027 | -the value of the clone to $value. |
2028 | - |
2029 | -=item B<clone()> |
2030 | - |
2031 | -This will return a clone of C<$tree>. The clone will be a root tree, but all |
2032 | -children will be cloned. |
2033 | - |
2034 | -If you call C<Tree-E<gt>clone([$value])>, it will instead call C<new()>. |
2035 | - |
2036 | -B<NOTE:> the value is merely a shallow copy. This means that all references |
2037 | -will be kept. |
2038 | - |
2039 | -=back |
2040 | - |
2041 | -=head2 Behaviors |
2042 | - |
2043 | -=over 4 |
2044 | - |
2045 | -=item B<add_child($options, @nodes)> |
2046 | - |
2047 | -This will add all the @nodes as children of C<$tree>. $options is a required |
2048 | -hashref that specifies options for add_child(). The optional parameters are: |
2049 | - |
2050 | -=over 4 |
2051 | - |
2052 | -=item * at |
2053 | - |
2054 | -This specifies the index to add @nodes at. If specified, this will be passed |
2055 | -into splice(). The only exceptions are if this is 0, it will act as an |
2056 | -unshift(). If it is unset or undefined, it will act as a push(). |
2057 | - |
2058 | -=back |
2059 | - |
2060 | -=item B<remove_child($options, @nodes)> |
2061 | - |
2062 | -This will remove all the @nodes from the children of C<$tree>. You can either |
2063 | -pass in the actual child object you wish to remove, the index of the child you |
2064 | -wish to remove, or a combination of both. |
2065 | - |
2066 | -$options is a required hashref that specifies parameters for remove_child(). |
2067 | -Currently, no parameters are used. |
2068 | - |
2069 | -=item B<mirror()> |
2070 | - |
2071 | -This will modify the tree such that it is a mirror of what it was before. This |
2072 | -means that the order of all children is reversed. |
2073 | - |
2074 | -B<NOTE>: This is a destructive action. It I<will> modify the tree's internal |
2075 | -structure. If you wish to get a mirror, yet keep the original tree intact, use |
2076 | -C<my $mirror = $tree-E<gt>clone-E<gt>mirror;> |
2077 | - |
2078 | -=item B<traverse( [$order] )> |
2079 | - |
2080 | -When called in list context (C<my @traversal = $tree-E<gt>traverse()>), this will |
2081 | -return a list of the nodes in the given traversal order. When called in scalar |
2082 | -context (C<my $traversal = $tree-E<gt>traverse()>), this will return a closure |
2083 | -that will, over successive calls, iterate over the nodes in the given |
2084 | -traversal order. When finished it will return false. |
2085 | - |
2086 | -The default traversal order is pre-order. |
2087 | - |
2088 | -The various traversal orders do the following steps: |
2089 | - |
2090 | -=over 4 |
2091 | - |
2092 | -=item * Pre-order (aka Prefix traversal) |
2093 | - |
2094 | -This will return the node, then the first sub tree in pre-order traversal, |
2095 | -then the next sub tree, etc. |
2096 | - |
2097 | -Use C<$tree-E<gt>PRE_ORDER> as the C<$order>. |
2098 | - |
2099 | -=item * Post-order (aka Prefix traversal) |
2100 | - |
2101 | -This will return the each sub-tree in post-order traversal, then the node. |
2102 | - |
2103 | -Use C<$tree-E<gt>POST_ORDER> as the C<$order>. |
2104 | - |
2105 | -=item * Level-order (aka Prefix traversal) |
2106 | - |
2107 | -This will return the node, then the all children of the node, then all |
2108 | -grandchildren of the node, etc. |
2109 | - |
2110 | -Use C<$tree-E<gt>LEVEL_ORDER> as the C<$order>. |
2111 | - |
2112 | -=back |
2113 | - |
2114 | -=back |
2115 | - |
2116 | -=head2 Accessors |
2117 | - |
2118 | -=over 4 |
2119 | - |
2120 | -=item * B<parent()> |
2121 | - |
2122 | -This will return the parent of C<$tree>. |
2123 | - |
2124 | -=item * B<children( [ $idx, [$idx, ..] ] )> |
2125 | - |
2126 | -This will return the children of C<$tree>. If called in list context, it will |
2127 | -return all the children. If called in scalar context, it will return the |
2128 | -number of children. |
2129 | - |
2130 | -You may optionally pass in a list of indices to retrieve. This will return the |
2131 | -children in the order you asked for them. This is very much like an |
2132 | -arrayslice. |
2133 | - |
2134 | -=item * B<value()> |
2135 | - |
2136 | -This will return the value stored in the node. |
2137 | - |
2138 | -=item * B<set_value([$value])> |
2139 | - |
2140 | -This will set the value stored in the node to $value, then return $self. |
2141 | - |
2142 | -=item * B<meta()> |
2143 | - |
2144 | -This will return a hashref that can be used to store whatever metadata the client |
2145 | -wishes to store. For example, L<Tree::Persist::DB> uses this to store database |
2146 | -row ids. |
2147 | - |
2148 | -It is recommended that you store your metadata in a subhashref and not in the |
2149 | -top-level metadata hashref, keyed by your package name. L<Tree::Persist> does |
2150 | -this, using a unique key for each persistence layer associated with that tree. |
2151 | -This will help prevent clobbering of metadata. |
2152 | - |
2153 | -=back |
2154 | - |
2155 | -=head1 NULL TREE |
2156 | - |
2157 | -If you call C<$self-E<gt>parent> on a root node, it will return a Tree::Null |
2158 | -object. This is an implementation of the Null Object pattern optimized for |
2159 | -usage with L<Forest>. It will evaluate as false in every case (using |
2160 | -L<overload>) and all methods called on it will return a Tree::Null object. |
2161 | - |
2162 | -=head2 Notes |
2163 | - |
2164 | -=over 4 |
2165 | - |
2166 | -=item * |
2167 | - |
2168 | -Tree::Null does B<not> inherit from anything. This is so that all the |
2169 | -methods will go through AUTOLOAD vs. the actual method. |
2170 | - |
2171 | -=item * |
2172 | - |
2173 | -However, calling isa() on a Tree::Null object will report that it is-a |
2174 | -any object that is either Tree or in the Tree:: hierarchy. |
2175 | - |
2176 | -=item * |
2177 | - |
2178 | -The Tree::Null object is a singleton. |
2179 | - |
2180 | -=item * |
2181 | - |
2182 | -The Tree::Null object I<is> defined, though. I couldn't find a way to |
2183 | -make it evaluate as undefined. That may be a good thing. |
2184 | - |
2185 | -=back |
2186 | - |
2187 | -=head1 CODE COVERAGE |
2188 | - |
2189 | -Please see the relevant sections of L<Tree>. |
2190 | - |
2191 | -=head1 SUPPORT |
2192 | - |
2193 | -Please see the relevant sections of L<Tree>. |
2194 | - |
2195 | -=head1 ACKNOWLEDGEMENTS |
2196 | - |
2197 | -=over 4 |
2198 | - |
2199 | -=item * Stevan Little for writing L<Tree::Simple>, upon which Tree is based. |
2200 | - |
2201 | -=back |
2202 | - |
2203 | -=head1 AUTHORS |
2204 | - |
2205 | -Rob Kinyon E<lt>rob.kinyon@iinteractive.comE<gt> |
2206 | - |
2207 | -Stevan Little E<lt>stevan.little@iinteractive.comE<gt> |
2208 | - |
2209 | -Thanks to Infinity Interactive for generously donating our time. |
2210 | - |
2211 | -=head1 COPYRIGHT AND LICENSE |
2212 | - |
2213 | -Copyright 2004, 2005 by Infinity Interactive, Inc. |
2214 | - |
2215 | -L<http://www.iinteractive.com> |
2216 | - |
2217 | -This library is free software; you can redistribute it and/or modify it under |
2218 | -the same terms as Perl itself. |
2219 | - |
2220 | -=cut |
2221 | +package Tree::Fast; |
2222 | + |
2223 | +use 5.006; |
2224 | + |
2225 | +use strict; |
2226 | +use warnings FATAL => 'all'; |
2227 | + |
2228 | +our $VERSION = '1.05'; |
2229 | + |
2230 | +use Scalar::Util qw( blessed weaken ); |
2231 | + |
2232 | +sub new { |
2233 | + my $class = shift; |
2234 | + |
2235 | + return $class->clone( @_ ) |
2236 | + if blessed $class; |
2237 | + |
2238 | + my $self = bless {}, $class; |
2239 | + |
2240 | + $self->_init( @_ ); |
2241 | + |
2242 | + return $self; |
2243 | +} |
2244 | + |
2245 | +sub _init { |
2246 | + my $self = shift; |
2247 | + my ($value) = @_; |
2248 | + |
2249 | + $self->{_parent} = $self->_null, |
2250 | + $self->{_children} = []; |
2251 | + $self->{_value} = $value, |
2252 | + |
2253 | + $self->{_meta} = {}; |
2254 | + |
2255 | + return $self; |
2256 | +} |
2257 | + |
2258 | +sub _clone_self { |
2259 | + my $self = shift; |
2260 | + |
2261 | + my $value = @_ ? shift : $self->value; |
2262 | + my $clone = blessed($self)->new( $value ); |
2263 | + return blessed($self)->new( $value ); |
2264 | +} |
2265 | + |
2266 | +sub _clone_children { |
2267 | + my ($self, $clone) = @_; |
2268 | + |
2269 | + if ( my @children = @{$self->{_children}} ) { |
2270 | + $clone->add_child({}, map { $_->clone } @children ); |
2271 | + } |
2272 | +} |
2273 | + |
2274 | +sub clone { |
2275 | + my $self = shift; |
2276 | + |
2277 | + return $self->new(@_) unless blessed $self; |
2278 | + |
2279 | + my $clone = $self->_clone_self(@_); |
2280 | + $self->_clone_children($clone); |
2281 | + |
2282 | + return $clone; |
2283 | +} |
2284 | + |
2285 | +sub add_child { |
2286 | + my $self = shift; |
2287 | + my ( $options, @nodes ) = @_; |
2288 | + |
2289 | + for my $node ( @nodes ) { |
2290 | + $node->_set_parent( $self ); |
2291 | + } |
2292 | + |
2293 | + if ( defined $options->{at} ) { |
2294 | + if ( $options->{at} ) { |
2295 | + splice @{$self->{_children}}, $options->{at}, 0, @nodes; |
2296 | + } |
2297 | + else { |
2298 | + unshift @{$self->{_children}}, @nodes; |
2299 | + } |
2300 | + } |
2301 | + else { |
2302 | + push @{$self->{_children}}, @nodes; |
2303 | + } |
2304 | + |
2305 | + return $self; |
2306 | +} |
2307 | + |
2308 | +sub remove_child { |
2309 | + my $self = shift; |
2310 | + my ($options, @indices) = @_; |
2311 | + |
2312 | + my @return; |
2313 | + for my $idx (sort { $b <=> $a } @indices) { |
2314 | + my $node = splice @{$self->{_children}}, $idx, 1; |
2315 | + $node->_set_parent( $node->_null ); |
2316 | + |
2317 | + push @return, $node; |
2318 | + } |
2319 | + |
2320 | + return @return; |
2321 | +} |
2322 | + |
2323 | +sub parent { |
2324 | + my $self = shift; |
2325 | + return $self->{_parent}; |
2326 | +} |
2327 | + |
2328 | +sub _set_parent { |
2329 | + my $self = shift; |
2330 | + |
2331 | + $self->{_parent} = shift; |
2332 | + weaken( $self->{_parent} ); |
2333 | + |
2334 | + return $self; |
2335 | +} |
2336 | + |
2337 | +sub children { |
2338 | + my $self = shift; |
2339 | + if ( @_ ) { |
2340 | + my @idx = @_; |
2341 | + return @{$self->{_children}}[@idx]; |
2342 | + } |
2343 | + else { |
2344 | + if ( caller->isa( __PACKAGE__ ) || $self->isa( scalar(caller) ) ) { |
2345 | + return wantarray ? @{$self->{_children}} : $self->{_children}; |
2346 | + } |
2347 | + else { |
2348 | + return @{$self->{_children}}; |
2349 | + } |
2350 | + } |
2351 | +} |
2352 | + |
2353 | +sub value { |
2354 | + my $self = shift; |
2355 | + my $value = shift; |
2356 | + $self->{_value} = $value if (defined $value); |
2357 | + |
2358 | + return $self->{_value}; |
2359 | +} |
2360 | + |
2361 | +sub set_value { |
2362 | + my $self = shift; |
2363 | + |
2364 | + $self->{_value} = $_[0]; |
2365 | + |
2366 | + return $self; |
2367 | +} |
2368 | + |
2369 | +sub meta { |
2370 | + my $self = shift; |
2371 | + my $meta = shift; |
2372 | + $self->{_meta} = {%{$self->{_meta} }, %$meta} if ($meta && !blessed($meta) && ref($meta) eq 'HASH'); |
2373 | + |
2374 | + return $self->{_meta}; |
2375 | +} |
2376 | + |
2377 | +sub mirror { |
2378 | + my $self = shift; |
2379 | + |
2380 | + @{$self->{_children}} = reverse @{$self->{_children}}; |
2381 | + $_->mirror for @{$self->{_children}}; |
2382 | + |
2383 | + return $self; |
2384 | +} |
2385 | + |
2386 | +use constant PRE_ORDER => 1; |
2387 | +use constant POST_ORDER => 2; |
2388 | +use constant LEVEL_ORDER => 3; |
2389 | + |
2390 | +sub traverse { |
2391 | + my $self = shift; |
2392 | + my $order = shift; |
2393 | + $order = $self->PRE_ORDER unless $order; |
2394 | + |
2395 | + if ( wantarray ) { |
2396 | + my @list; |
2397 | + |
2398 | + if ( $order eq $self->PRE_ORDER ) { |
2399 | + @list = ($self); |
2400 | + push @list, map { $_->traverse( $order ) } @{$self->{_children}}; |
2401 | + } |
2402 | + elsif ( $order eq $self->POST_ORDER ) { |
2403 | + @list = map { $_->traverse( $order ) } @{$self->{_children}}; |
2404 | + push @list, $self; |
2405 | + } |
2406 | + elsif ( $order eq $self->LEVEL_ORDER ) { |
2407 | + my @queue = ($self); |
2408 | + while ( my $node = shift @queue ) { |
2409 | + push @list, $node; |
2410 | + push @queue, @{$node->{_children}}; |
2411 | + } |
2412 | + } |
2413 | + else { |
2414 | + return $self->error( "traverse(): '$order' is an illegal traversal order" ); |
2415 | + } |
2416 | + |
2417 | + return @list; |
2418 | + } |
2419 | + else { |
2420 | + my $closure; |
2421 | + |
2422 | + if ( $order eq $self->PRE_ORDER ) { |
2423 | + my $next_node = $self; |
2424 | + my @stack = ( $self ); |
2425 | + my @next_idx = ( 0 ); |
2426 | + |
2427 | + $closure = sub { |
2428 | + my $node = $next_node; |
2429 | + return unless $node; |
2430 | + $next_node = undef; |
2431 | + |
2432 | + while ( @stack && !$next_node ) { |
2433 | + while ( @stack && !exists $stack[0]->{_children}[ $next_idx[0] ] ) { |
2434 | + shift @stack; |
2435 | + shift @next_idx; |
2436 | + } |
2437 | + |
2438 | + if ( @stack ) { |
2439 | + $next_node = $stack[0]->{_children}[ $next_idx[0]++ ]; |
2440 | + unshift @stack, $next_node; |
2441 | + unshift @next_idx, 0; |
2442 | + } |
2443 | + } |
2444 | + |
2445 | + return $node; |
2446 | + }; |
2447 | + } |
2448 | + elsif ( $order eq $self->POST_ORDER ) { |
2449 | + my @stack = ( $self ); |
2450 | + my @next_idx = ( 0 ); |
2451 | + while ( @{ $stack[0]->{_children} } ) { |
2452 | + unshift @stack, $stack[0]->{_children}[0]; |
2453 | + unshift @next_idx, 0; |
2454 | + } |
2455 | + |
2456 | + $closure = sub { |
2457 | + my $node = $stack[0]; |
2458 | + return unless $node; |
2459 | + |
2460 | + shift @stack; shift @next_idx; |
2461 | + $next_idx[0]++; |
2462 | + |
2463 | + while ( @stack && exists $stack[0]->{_children}[ $next_idx[0] ] ) { |
2464 | + unshift @stack, $stack[0]->{_children}[ $next_idx[0] ]; |
2465 | + unshift @next_idx, 0; |
2466 | + } |
2467 | + |
2468 | + return $node; |
2469 | + }; |
2470 | + } |
2471 | + elsif ( $order eq $self->LEVEL_ORDER ) { |
2472 | + my @nodes = ($self); |
2473 | + $closure = sub { |
2474 | + my $node = shift @nodes; |
2475 | + return unless $node; |
2476 | + push @nodes, @{$node->{_children}}; |
2477 | + return $node; |
2478 | + }; |
2479 | + } |
2480 | + else { |
2481 | + return $self->error( "traverse(): '$order' is an illegal traversal order" ); |
2482 | + } |
2483 | + |
2484 | + return $closure; |
2485 | + } |
2486 | +} |
2487 | + |
2488 | +sub _null { |
2489 | + return Tree::Null->new; |
2490 | +} |
2491 | + |
2492 | +package Tree::Null; |
2493 | + |
2494 | +#XXX Add this in once it's been thought out |
2495 | +#our @ISA = qw( Tree ); |
2496 | + |
2497 | +# You want to be able to interrogate the null object as to |
2498 | +# its class, so we don't override isa() as we do can() |
2499 | + |
2500 | +use overload |
2501 | + '""' => sub { return "" }, |
2502 | + '0+' => sub { return 0 }, |
2503 | + 'bool' => sub { return }, |
2504 | + fallback => 1, |
2505 | +; |
2506 | + |
2507 | +{ |
2508 | + my $singleton = bless \my($x), __PACKAGE__; |
2509 | + sub new { return $singleton } |
2510 | + sub AUTOLOAD { return $singleton } |
2511 | + sub can { return sub { return $singleton } } |
2512 | +} |
2513 | + |
2514 | +# The null object can do anything |
2515 | +sub isa { |
2516 | + my ($proto, $class) = @_; |
2517 | + |
2518 | + if ( $class =~ /^Tree(?:::.*)?$/ ) { |
2519 | + return 1; |
2520 | + } |
2521 | + |
2522 | + return $proto->SUPER::isa( $class ); |
2523 | +} |
2524 | + |
2525 | +1; |
2526 | +__END__ |
2527 | + |
2528 | +=head1 NAME |
2529 | + |
2530 | +Tree::Fast - the fastest possible implementation of a tree in pure Perl |
2531 | + |
2532 | +=head1 SYNOPSIS |
2533 | + |
2534 | + my $tree = Tree->new( 'root' ); |
2535 | + my $child = Tree->new( 'child' ); |
2536 | + $tree->add_child( {}, $child ); |
2537 | + |
2538 | + $tree->add_child( { at => 0 }, Tree->new( 'first child' ) ); |
2539 | + $tree->add_child( { at => -1 }, Tree->new( 'last child' ) ); |
2540 | + |
2541 | + my @children = $tree->children; |
2542 | + my @some_children = $tree->children( 0, 2 ); |
2543 | + |
2544 | + $tree->remove_child( 0 ); |
2545 | + |
2546 | + my @nodes = $tree->traverse( $tree->POST_ORDER ); |
2547 | + |
2548 | + my $traversal = $tree->traverse( $tree->POST_ORDER ); |
2549 | + while ( my $node = $traversal->() ) { |
2550 | + # Do something with $node here |
2551 | + } |
2552 | + |
2553 | + my $clone = $tree->clone; |
2554 | + my $mirror = $tree->clone->mirror; |
2555 | + |
2556 | +=head1 DESCRIPTION |
2557 | + |
2558 | +This is meant to be the core implementation for L<Tree>, stripped down as much |
2559 | +as possible. There is no error-checking, bounds-checking, event-handling, |
2560 | +convenience methods, or anything else of the sort. If you want something fuller-featured, |
2561 | +please look at L<Tree>, which is a wrapper around Tree::Fast. |
2562 | + |
2563 | +=head1 METHODS |
2564 | + |
2565 | +=head2 Constructors |
2566 | + |
2567 | +=head2 new([$value]) |
2568 | + |
2569 | +Here, [] indicate an optional parameter. |
2570 | + |
2571 | +This will return a C<Tree> object. It will accept one parameter which, if passed, |
2572 | +will become the I<value> (accessible by C<value()>). All other parameters will be |
2573 | +ignored. |
2574 | + |
2575 | +If you call C<< $tree->new([$value]) >>, it will instead call C<clone()>, then set |
2576 | +the I<value> of the clone to $value. |
2577 | + |
2578 | +=head2 clone() |
2579 | + |
2580 | +This will return a clone of C<$tree>. The clone will be a root tree, but all |
2581 | +children will be cloned. |
2582 | + |
2583 | +If you call C<< Tree->clone([$value]) >>, it will instead call C<new()>. |
2584 | + |
2585 | +B<NOTE:> the value is merely a shallow copy. This means that all references |
2586 | +will be kept. |
2587 | + |
2588 | +=head2 Behaviors |
2589 | + |
2590 | +=head2 add_child($options, @nodes) |
2591 | + |
2592 | +This will add all the C<@nodes> as children of C<$tree>. C<$options> is a required |
2593 | +hashref that specifies options for C<add_child()>. The optional parameters are: |
2594 | + |
2595 | +=over 4 |
2596 | + |
2597 | +=item * at |
2598 | + |
2599 | +This specifies the index to add C<@nodes> at. If specified, this will be passed |
2600 | +into splice(). The only exceptions are if this is 0, it will act as an |
2601 | +unshift(). If it is unset or undefined, it will act as a push(). |
2602 | + |
2603 | +=back |
2604 | + |
2605 | +=head2 remove_child($options, @nodes) |
2606 | + |
2607 | +This will remove all the C<@nodes> from the children of C<$tree>. You can either |
2608 | +pass in the actual child object you wish to remove, the index of the child you |
2609 | +wish to remove, or a combination of both. |
2610 | + |
2611 | +$options is a required hashref that specifies parameters for remove_child(). |
2612 | +Currently, no parameters are used. |
2613 | + |
2614 | +=head2 mirror() |
2615 | + |
2616 | +This will modify the tree such that it is a mirror of what it was before. This |
2617 | +means that the order of all children is reversed. |
2618 | + |
2619 | +B<NOTE>: This is a destructive action. It I<will> modify the tree's internal |
2620 | +structure. If you wish to get a mirror, yet keep the original tree intact, use |
2621 | +C<< my $mirror = $tree->clone->mirror >>. |
2622 | + |
2623 | +=head2 traverse( [$order] ) |
2624 | + |
2625 | +Here, [] indicate an optional parameter. |
2626 | + |
2627 | +When called in list context (C<< my @traversal = $tree->traverse() >>), this will |
2628 | +return a list of the nodes in the given traversal order. When called in scalar |
2629 | +context (C<< my $traversal = $tree->traverse() >>), this will return a closure |
2630 | +that will, over successive calls, iterate over the nodes in the given |
2631 | +traversal order. When finished it will return false. |
2632 | + |
2633 | +The default traversal order is pre-order. |
2634 | + |
2635 | +The various traversal orders do the following steps: |
2636 | + |
2637 | +=over 4 |
2638 | + |
2639 | +=item * Pre-order |
2640 | + |
2641 | +This will return the node, then the first sub tree in pre-order traversal, |
2642 | +then the next sub tree, etc. |
2643 | + |
2644 | +Use C<< $tree->PRE_ORDER >> as the C<$order>. |
2645 | + |
2646 | +=item * Post-order |
2647 | + |
2648 | +This will return the each sub-tree in post-order traversal, then the node. |
2649 | + |
2650 | +Use C<< $tree->POST_ORDER >> as the C<$order>. |
2651 | + |
2652 | +=item * Level-order |
2653 | + |
2654 | +This will return the node, then the all children of the node, then all |
2655 | +grandchildren of the node, etc. |
2656 | + |
2657 | +Use C<< $tree->LEVEL_ORDER >> as the C<$order>. |
2658 | + |
2659 | +=back |
2660 | + |
2661 | +=head2 Accessors |
2662 | + |
2663 | +=head2 parent() |
2664 | + |
2665 | +This will return the parent of C<$tree>. |
2666 | + |
2667 | +=head2 children( [ $idx, [$idx, ..] ] ) |
2668 | + |
2669 | +Here, [] indicate optional parameters. |
2670 | + |
2671 | +This will return the children of C<$tree>. If called in list context, it will |
2672 | +return all the children. If called in scalar context, it will return the |
2673 | +number of children. |
2674 | + |
2675 | +You may optionally pass in a list of indices to retrieve. This will return the |
2676 | +children in the order you asked for them. This is very much like an |
2677 | +arrayslice. |
2678 | + |
2679 | +=head2 value() |
2680 | + |
2681 | +This will return the value stored in the node. |
2682 | + |
2683 | +=head2 set_value([$value]) |
2684 | + |
2685 | +Here, [] indicate an optional parameter. |
2686 | + |
2687 | +This will set the I<value> stored in the node to $value, then return $self. |
2688 | + |
2689 | +If C<$value> is not provided, undef is used. |
2690 | + |
2691 | +=head2 meta() |
2692 | + |
2693 | +This will return a hashref that can be used to store whatever metadata the client |
2694 | +wishes to store. For example, L<Tree::Persist::DB> uses this to store database |
2695 | +row ids. |
2696 | + |
2697 | +It is recommended that you store your metadata in a subhashref and not in the |
2698 | +top-level metadata hashref, keyed by your package name. L<Tree::Persist> does |
2699 | +this, using a unique key for each persistence layer associated with that tree. |
2700 | +This will help prevent clobbering of metadata. |
2701 | + |
2702 | +=head1 NULL TREE |
2703 | + |
2704 | +If you call C<< $self->parent >> on a root node, it will return a Tree::Null |
2705 | +object. This is an implementation of the Null Object pattern optimized for |
2706 | +usage with L<Tree>. It will evaluate as false in every case (using |
2707 | +I<overload>) and all methods called on it will return a Tree::Null object. |
2708 | + |
2709 | +=head2 Notes |
2710 | + |
2711 | +=over 4 |
2712 | + |
2713 | +=item * |
2714 | + |
2715 | +Tree::Null does B<not> inherit from anything. This is so that all the |
2716 | +methods will go through AUTOLOAD vs. the actual method. |
2717 | + |
2718 | +=item * |
2719 | + |
2720 | +However, calling isa() on a Tree::Null object will report that it is-a |
2721 | +any object that is either Tree or in the Tree:: hierarchy. |
2722 | + |
2723 | +=item * |
2724 | + |
2725 | +The Tree::Null object is a singleton. |
2726 | + |
2727 | +=item * |
2728 | + |
2729 | +The Tree::Null object I<is> defined, though. I couldn't find a way to |
2730 | +make it evaluate as undefined. That may be a good thing. |
2731 | + |
2732 | +=back |
2733 | + |
2734 | +=head1 CODE COVERAGE |
2735 | + |
2736 | +Please see the relevant sections of L<Tree>. |
2737 | + |
2738 | +=head1 SUPPORT |
2739 | + |
2740 | +Please see the relevant sections of L<Tree>. |
2741 | + |
2742 | +=head1 ACKNOWLEDGEMENTS |
2743 | + |
2744 | +=over 4 |
2745 | + |
2746 | +=item * Stevan Little for writing L<Tree::Simple>, upon which Tree is based. |
2747 | + |
2748 | +=back |
2749 | + |
2750 | +=head1 AUTHORS |
2751 | + |
2752 | +Rob Kinyon E<lt>rob.kinyon@iinteractive.comE<gt> |
2753 | + |
2754 | +Stevan Little E<lt>stevan.little@iinteractive.comE<gt> |
2755 | + |
2756 | +Thanks to Infinity Interactive for generously donating our time. |
2757 | + |
2758 | +=head1 COPYRIGHT AND LICENSE |
2759 | + |
2760 | +Copyright 2004, 2005 by Infinity Interactive, Inc. |
2761 | + |
2762 | +L<http://www.iinteractive.com> |
2763 | + |
2764 | +This library is free software; you can redistribute it and/or modify it under |
2765 | +the same terms as Perl itself. |
2766 | + |
2767 | +=cut |
2768 | |
2769 | === modified file 't/Tree/001_root_node.t' |
2770 | --- t/Tree/001_root_node.t 2008-01-17 12:56:58 +0000 |
2771 | +++ t/Tree/001_root_node.t 2014-12-12 23:08:52 +0000 |
2772 | @@ -1,11 +1,12 @@ |
2773 | +use lib 't/lib'; |
2774 | use strict; |
2775 | use warnings; |
2776 | |
2777 | use Test::More; |
2778 | |
2779 | -use t::tests qw( %runs ); |
2780 | +use Tests qw( %runs ); |
2781 | |
2782 | -plan tests => 25 + 3 * $runs{stats}{plan}; |
2783 | +plan tests => 26 + 3 * $runs{stats}{plan}; |
2784 | |
2785 | my $CLASS = 'Tree'; |
2786 | use_ok( $CLASS ) |
2787 | @@ -39,7 +40,10 @@ |
2788 | is( $tree->root, $tree, "... and doesn't change the value" ); |
2789 | |
2790 | $tree->meta->{foo} = 1; |
2791 | - is( $tree->meta->{foo}, 1, "Meta works." ); |
2792 | + is( $tree->meta->{foo}, 1, "Meta works via in-situ update." ); |
2793 | + |
2794 | + $tree->meta({baa => 2}); |
2795 | + is( ${$tree->meta}{baa}, 2, "Meta works via method call." ); |
2796 | } |
2797 | |
2798 | { |
2799 | |
2800 | === modified file 't/Tree/003_child_node.t' |
2801 | --- t/Tree/003_child_node.t 2008-01-17 12:56:58 +0000 |
2802 | +++ t/Tree/003_child_node.t 2014-12-12 23:08:52 +0000 |
2803 | @@ -1,9 +1,10 @@ |
2804 | +use lib 't/lib'; |
2805 | use strict; |
2806 | use warnings; |
2807 | |
2808 | use Test::More; |
2809 | |
2810 | -use t::tests qw( %runs ); |
2811 | +use Tests qw( %runs ); |
2812 | |
2813 | plan tests => 22 + 4 * $runs{stats}{plan}; |
2814 | |
2815 | |
2816 | === modified file 't/Tree/004_multiple_children.t' |
2817 | --- t/Tree/004_multiple_children.t 2008-01-17 12:56:58 +0000 |
2818 | +++ t/Tree/004_multiple_children.t 2014-12-12 23:08:52 +0000 |
2819 | @@ -1,9 +1,10 @@ |
2820 | +use lib 't/lib'; |
2821 | use strict; |
2822 | use warnings; |
2823 | |
2824 | use Test::More; |
2825 | |
2826 | -use t::tests qw( %runs ); |
2827 | +use Tests qw( %runs ); |
2828 | |
2829 | plan tests => 27 + 15 * $runs{stats}{plan}; |
2830 | |
2831 | |
2832 | === modified file 't/Tree/005_multilevel_tree.t' |
2833 | --- t/Tree/005_multilevel_tree.t 2008-01-17 12:56:58 +0000 |
2834 | +++ t/Tree/005_multilevel_tree.t 2014-12-12 23:08:52 +0000 |
2835 | @@ -1,9 +1,10 @@ |
2836 | +use lib 't/lib'; |
2837 | use strict; |
2838 | use warnings; |
2839 | |
2840 | use Test::More; |
2841 | |
2842 | -use t::tests qw( %runs ); |
2843 | +use Tests qw( %runs ); |
2844 | |
2845 | plan tests => 41 + 3 * $runs{stats}{plan}; |
2846 | |
2847 | |
2848 | === modified file 't/Tree/010_errors_addchild.t' |
2849 | --- t/Tree/010_errors_addchild.t 2008-01-17 12:56:58 +0000 |
2850 | +++ t/Tree/010_errors_addchild.t 2014-12-12 23:08:52 +0000 |
2851 | @@ -1,9 +1,10 @@ |
2852 | +use lib 't/lib'; |
2853 | use strict; |
2854 | use warnings; |
2855 | |
2856 | use Test::More; |
2857 | |
2858 | -use t::tests qw( %runs ); |
2859 | +use Tests qw( %runs ); |
2860 | |
2861 | plan tests => 1 + 12 * $runs{error}{plan}; |
2862 | |
2863 | |
2864 | === modified file 't/Tree/011_errors_removechild.t' |
2865 | --- t/Tree/011_errors_removechild.t 2008-01-17 12:56:58 +0000 |
2866 | +++ t/Tree/011_errors_removechild.t 2014-12-12 23:08:52 +0000 |
2867 | @@ -1,9 +1,10 @@ |
2868 | +use lib 't/lib'; |
2869 | use strict; |
2870 | use warnings; |
2871 | |
2872 | use Test::More; |
2873 | |
2874 | -use t::tests qw( %runs ); |
2875 | +use Tests qw( %runs ); |
2876 | |
2877 | plan tests => 1 + 6 * $runs{error}{plan}; |
2878 | |
2879 | |
2880 | === modified file 't/Tree/016_events.t' |
2881 | --- t/Tree/016_events.t 2008-01-17 12:56:58 +0000 |
2882 | +++ t/Tree/016_events.t 2014-12-12 23:08:52 +0000 |
2883 | @@ -1,9 +1,10 @@ |
2884 | +use lib 't/lib'; |
2885 | use strict; |
2886 | use warnings; |
2887 | |
2888 | use Test::More; |
2889 | |
2890 | -#use t::tests qw( %runs ); |
2891 | +#use Tests qw( %runs ); |
2892 | |
2893 | plan tests => 8; |
2894 | |
2895 | |
2896 | === modified file 't/Tree_Binary/000_binary_trees.t' |
2897 | --- t/Tree_Binary/000_binary_trees.t 2008-01-17 12:56:58 +0000 |
2898 | +++ t/Tree_Binary/000_binary_trees.t 2014-12-12 23:08:52 +0000 |
2899 | @@ -1,13 +1,14 @@ |
2900 | +use lib 't/lib'; |
2901 | use strict; |
2902 | use warnings; |
2903 | |
2904 | use Test::More; |
2905 | |
2906 | -use t::tests qw( %runs ); |
2907 | +use Tests qw( %runs ); |
2908 | |
2909 | plan tests => 28 + 15 * $runs{stats}{plan}; |
2910 | |
2911 | -my $CLASS = 'Tree::Binary'; |
2912 | +my $CLASS = 'Tree::Binary2'; |
2913 | use_ok( $CLASS ) |
2914 | or Test::More->builder->BAILOUT( "Cannot load $CLASS" ); |
2915 | |
2916 | |
2917 | === modified file 't/Tree_Binary/001_mirror.t' |
2918 | --- t/Tree_Binary/001_mirror.t 2008-01-17 12:56:58 +0000 |
2919 | +++ t/Tree_Binary/001_mirror.t 2014-12-12 23:08:52 +0000 |
2920 | @@ -5,7 +5,7 @@ |
2921 | |
2922 | plan tests => 16; |
2923 | |
2924 | -my $CLASS = 'Tree::Binary'; |
2925 | +my $CLASS = 'Tree::Binary2'; |
2926 | use_ok( $CLASS ) |
2927 | or Test::More->builder->BAILOUT( "Cannot load $CLASS" ); |
2928 | |
2929 | |
2930 | === modified file 't/Tree_Binary/002_clone.t' |
2931 | --- t/Tree_Binary/002_clone.t 2008-01-17 12:56:58 +0000 |
2932 | +++ t/Tree_Binary/002_clone.t 2014-12-12 23:08:52 +0000 |
2933 | @@ -7,11 +7,11 @@ |
2934 | |
2935 | use Test::More tests => 6; |
2936 | |
2937 | -use_ok( 'Tree::Binary' ); |
2938 | +use_ok( 'Tree::Binary2' ); |
2939 | |
2940 | -my $tree = Tree::Binary->new('root'); |
2941 | -$tree->left(Tree::Binary->new('left')); |
2942 | -$tree->right(Tree::Binary->new('right')); |
2943 | +my $tree = Tree::Binary2->new('root'); |
2944 | +$tree->left(Tree::Binary2->new('left')); |
2945 | +$tree->right(Tree::Binary2->new('right')); |
2946 | |
2947 | my $clone = $tree->clone; |
2948 | |
2949 | |
2950 | === added directory 't/lib' |
2951 | === added file 't/lib/Tests.pm' |
2952 | --- t/lib/Tests.pm 1970-01-01 00:00:00 +0000 |
2953 | +++ t/lib/Tests.pm 2014-12-12 23:08:52 +0000 |
2954 | @@ -0,0 +1,61 @@ |
2955 | +package Tests; |
2956 | + |
2957 | +use strict; |
2958 | +use warnings; |
2959 | + |
2960 | +use Test::More; |
2961 | + |
2962 | +my @stats = qw( height width depth size is_root is_leaf ); |
2963 | + |
2964 | +use base 'Exporter'; |
2965 | + |
2966 | +our @EXPORT_OK = qw( %runs ); |
2967 | +our $VERSION = '1.05'; |
2968 | + |
2969 | +our %runs = ( |
2970 | + stats => { |
2971 | + plan => scalar @stats, |
2972 | + func => \&stat_check, |
2973 | + }, |
2974 | + error => { |
2975 | + plan => 3, |
2976 | + func => \&error_check, |
2977 | + }, |
2978 | +); |
2979 | + |
2980 | +sub stat_check { |
2981 | + my $tree = shift; |
2982 | + my %opts = @_; |
2983 | + |
2984 | + foreach my $stat (@stats) { |
2985 | + if ( $stat =~ /^is_(.*)/ ) { |
2986 | + if ( $opts{$stat} ) { |
2987 | + ok( $tree->$stat, "The tree is a $1" ); |
2988 | + } |
2989 | + else { |
2990 | + ok( !$tree->$stat, "The tree is not a $1" ); |
2991 | + } |
2992 | + } |
2993 | + else { |
2994 | + cmp_ok( |
2995 | + $tree->$stat, '==', $opts{$stat}, |
2996 | + "The tree has a $stat of $opts{$stat}", |
2997 | + ); |
2998 | + } |
2999 | + } |
3000 | +} |
3001 | + |
3002 | +sub error_check { |
3003 | + my $tree = shift; |
3004 | + my %opts = @_; |
3005 | + |
3006 | + my $func = $opts{func}; |
3007 | + my $validator = $opts{validator}; |
3008 | + |
3009 | + is( $tree->$func(@{$opts{args} || []}), undef, "$func(): error testing ..." ); |
3010 | + is( $tree->last_error, $opts{error}, "... and the error is good" ); |
3011 | + cmp_ok( $tree->$validator, '==', $opts{value}, "... and there was no change" ); |
3012 | +} |
3013 | + |
3014 | +1; |
3015 | +__END__ |
3016 | |
3017 | === modified file 't/pod.t' |
3018 | --- t/pod.t 2008-01-17 12:56:58 +0000 |
3019 | +++ t/pod.t 2014-12-12 23:08:52 +0000 |
3020 | @@ -3,7 +3,7 @@ |
3021 | |
3022 | use Test::More; |
3023 | |
3024 | -eval "use Test::Pod 1.14"; |
3025 | -plan skip_all => "Test::Pod 1.14 required for testing POD" if $@; |
3026 | +eval "use Test::Pod 1.45"; |
3027 | +plan skip_all => "Test::Pod 1.45 required for testing POD" if $@; |
3028 | |
3029 | all_pod_files_ok(); |
3030 | |
3031 | === modified file 't/pod_coverage.t' |
3032 | --- t/pod_coverage.t 2008-01-17 12:56:58 +0000 |
3033 | +++ t/pod_coverage.t 2014-12-12 23:08:52 +0000 |
3034 | @@ -3,8 +3,8 @@ |
3035 | |
3036 | use Test::More; |
3037 | |
3038 | -eval "use Test::Pod::Coverage 1.04"; |
3039 | -plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage" if $@; |
3040 | +eval "use Test::Pod::Coverage 1.08"; |
3041 | +plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage" if $@; |
3042 | |
3043 | all_pod_coverage_ok({ |
3044 | also_private => [], |
3045 | |
3046 | === removed file 't/tests.pm' |
3047 | --- t/tests.pm 2008-01-17 12:56:58 +0000 |
3048 | +++ t/tests.pm 1970-01-01 00:00:00 +0000 |
3049 | @@ -1,60 +0,0 @@ |
3050 | -package t::tests; |
3051 | - |
3052 | -use strict; |
3053 | -use warnings; |
3054 | - |
3055 | -use Test::More; |
3056 | - |
3057 | -my @stats = qw( height width depth size is_root is_leaf ); |
3058 | - |
3059 | -use base 'Exporter'; |
3060 | - |
3061 | -our @EXPORT_OK = qw( %runs ); |
3062 | - |
3063 | -our %runs = ( |
3064 | - stats => { |
3065 | - plan => scalar @stats, |
3066 | - func => \&stat_check, |
3067 | - }, |
3068 | - error => { |
3069 | - plan => 3, |
3070 | - func => \&error_check, |
3071 | - }, |
3072 | -); |
3073 | - |
3074 | -sub stat_check { |
3075 | - my $tree = shift; |
3076 | - my %opts = @_; |
3077 | - |
3078 | - foreach my $stat (@stats) { |
3079 | - if ( $stat =~ /^is_(.*)/ ) { |
3080 | - if ( $opts{$stat} ) { |
3081 | - ok( $tree->$stat, "The tree is a $1" ); |
3082 | - } |
3083 | - else { |
3084 | - ok( !$tree->$stat, "The tree is not a $1" ); |
3085 | - } |
3086 | - } |
3087 | - else { |
3088 | - cmp_ok( |
3089 | - $tree->$stat, '==', $opts{$stat}, |
3090 | - "The tree has a $stat of $opts{$stat}", |
3091 | - ); |
3092 | - } |
3093 | - } |
3094 | -} |
3095 | - |
3096 | -sub error_check { |
3097 | - my $tree = shift; |
3098 | - my %opts = @_; |
3099 | - |
3100 | - my $func = $opts{func}; |
3101 | - my $validator = $opts{validator}; |
3102 | - |
3103 | - is( $tree->$func(@{$opts{args} || []}), undef, "$func(): error testing ..." ); |
3104 | - is( $tree->last_error, $opts{error}, "... and the error is good" ); |
3105 | - cmp_ok( $tree->$validator, '==', $opts{value}, "... and there was no change" ); |
3106 | -} |
3107 | - |
3108 | -1; |
3109 | -__END__ |
Thanks. Uploaded.