RDF-Helper-2.0000755000765000765 011601114550 11740 5ustar00kipkip000000000000README000644000765000765 51011601114550 12654 0ustar00kipkip000000000000RDF-Helper-2.0 This archive contains the distribution RDF-Helper, version 2.0: Provide a consistent, high-level API for working with RDF with Perl This software is copyright (c) 2011 by Kip Hampton. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Changes000644000765000765 2201111601114550 13327 0ustar00kipkip000000000000RDF-Helper-2.02006-07-30 23:20 kingubu * .DS_Store, Changes, Makefile.PL, lib/RDF/.DS_Store, lib/RDF/Helper.pm, lib/RDF/Helper/RDFQuery.pm, lib/RDF/Helper/RDFRedland.pm, t/2_model_basics.t, t/6_query_perl.t, t/7_property_hash.t, t/8_rdf_object.t: Added SPARQL/RDQL query support for RDF::Core (via RDF::Query). Core now has full parity. 2006-07-27 12:44 kingubu * lib/RDF/Helper/DBI.pm: tiny doc patch 2006-07-27 11:57 kingubu * lib/RDF/Helper/DBI/Query.pm: Added missing files 2006-07-27 11:55 kingubu * lib/RDF/Helper.pm, lib/RDF/Helper/DBI.pm, lib/RDF/Helper/RDFCore.pm, lib/RDF/Helper/RDFRedland.pm, t/1_nodes.t, t/2_model_basics.t, t/7_property_hash.t: Beta support for pure-DBI models added and working 2006-07-24 18:33 kingubu * lib/RDF/Helper.pm, lib/RDF/Helper/PerlConvenience.pm, lib/RDF/Helper/RDFCore.pm, lib/RDF/Helper/RDFRedland.pm, t/1_nodes.t, t/2_model_basics.t: More refactoring to support generalized abstraction. 2006-07-21 18:36 kingubu * lib/RDF/Helper/DBI.pm, lib/RDF/Helper/Statement.pm, t/10_deep_prop_recursive.t: Added missing files. 2006-07-21 18:34 kingubu * META.yml, lib/RDF/Helper.pm, lib/RDF/Helper/PerlConvenience.pm, lib/RDF/Helper/RDFCore.pm, lib/RDF/Helper/RDFRedland.pm, lib/RDF/Helper/TiedPropertyHash.pm, lib/RDF/Helper/RDFRedland/TiedPropertyHash.pm, t/0_basic.t, t/1_nodes.t, t/5_rdf2perl.t: Checkpoint checkin 2006-07-11 23:21 nachbaur * lib/RDF/Helper.pm: Added docs for the BaseURI constructor argument 2006-07-11 23:11 nachbaur * lib/RDF/Helper.pm: Various documentation spelling corrections and POD formatting tags 2006-07-10 10:57 kingubu * lib/RDF/Helper.pm, lib/RDF/Helper/PerlConvenience.pm, lib/RDF/Helper/RDFCore.pm, lib/RDF/Helper/RDFRedland.pm, t/2_model_basics.t, t/3_include_model.t, t/4_include_rdfxml.t, t/5_rdf2perl.t, t/6_query_perl.t, t/7_property_hash.t: Update RDF::Core support. Still more TODO but things are better. 2006-07-09 11:52 kingubu * lib/RDF/: Helper.pm, Helper/RDFRedland/Query.pm: More docs patches. 2006-07-09 11:33 kingubu * MANIFEST, META.yml, lib/RDF/Helper.pm, lib/RDF/Helper/RDFCore.pm, lib/RDF/Helper/RDFRedland.pm, t/0_basic.t, t/1_nodes.t: More docs patches. 2006-07-08 15:59 kingubu * lib/RDF/: Helper.pm, Helper/RDFRedland.pm: More doc-hacking, very near a release. 2006-07-07 02:36 nachbaur * t/8_rdf_object.t: Bollocks! I always forget to update the bloody test count... 2006-07-07 02:34 nachbaur * lib/RDF/Helper/Object.pm, t/8_rdf_object.t, t/data/use.perl.rss: Added tests showing that multi-level object traversal works. Also some document stubs that I forgot I'd added 2006-07-06 12:30 nachbaur * lib/RDF/Helper.pm: More methods doc'd; handing it off to ubu 2006-07-06 04:08 nachbaur * lib/RDF/Helper.pm: Re-added documentation that one of ubu's checkins walked over 2006-07-06 03:05 kingubu * lib/RDF/Helper.pm: Added DESCRIPTION section to the POD, and doc'd the various constructor options. 2006-07-06 02:27 kingubu * lib/RDF/Helper.pm: Checkpoint checkin. 2006-07-06 02:17 kingubu * t/9_pod.t: Added automated POD tests 2006-07-06 01:36 kingubu * lib/RDF/Helper.pm, lib/RDF/Helper/Object.pm, lib/RDF/Helper/PerlConvenience.pm, lib/RDF/Helper/RDFRedland.pm, t/1_nodes.t, t/2_model_basics.t: Added optional QName expansion support for all convenioence methods. Added tests to exercise new funtionality. 2006-07-05 18:10 nachbaur * lib/RDF/Helper.pm: Yet another docs ci; still a work in progress 2006-07-05 13:52 nachbaur * lib/RDF/Helper.pm: Added initial method documentation; more to follow 2006-07-05 09:50 nachbaur * lib/RDF/Helper.pm: Added RDF::Redland as the default BaseInterface 2006-07-03 00:08 kingubu * lib/RDF/Helper.pm, lib/RDF/Helper/RDFQuery.pm, lib/RDF/Helper/RDFRedland.pm, t/6_query_perl.t, t/8_rdf_object.t: Added initial support for RDF::Query to the RDFRedland Helper 2006-07-01 21:01 kingubu * lib/RDF/Helper/RDFRedland.pm, t/7_property_hash.t: Updated Helper::RDFRedland::tied_property_hash to accept and pass on options (like Deep). All tests now pass (including rdf_object). 2006-06-30 18:57 nachbaur * lib/RDF/Helper/RDFRedland.pm: Dur, that teaches me for checking-in new code without running "make test" first 2006-06-30 18:55 nachbaur * lib/RDF/Helper/RDFRedland.pm: Added the Options argument back to the TiedPropertyHash creation for objects, since the previous version accidentally walked over it 2006-06-30 17:57 kingubu * lib/RDF/Helper/RDFRedland.pm, t/2_model_basics.t: Added workaround for literal-as-bare-numeric bug. added test to exercise the fix. 2006-06-30 10:54 nachbaur * lib/RDF/Helper/Object.pm, lib/RDF/Helper/RDFRedland.pm, lib/RDF/Helper/RDFRedland/TiedPropertyHash.pm, t/7_property_hash.t: * Rolled back default behaviour of the tied property hash to only return results one-level deep; this is as per a discussion between Kip and myself. * The RDF::Helper::Object implementation now explicitly sets that deep property hashes will be returned, keeping their current behaviour. * Tests extended to check for this. This rolls back the tied hash's functionality to be easier to use for one-off users (no mystical checking if a value is a reference or not), as well as making it work for our dayjob application. 2006-06-18 10:08 nachbaur * Makefile.PL: Added the Data::Uniqid dependancy to Makefile.PL 2006-06-16 00:40 kingubu * MANIFEST, MANIFEST.SKIP, META.yml, README, lib/RDF/Helper.pm: Prep for CPAN release 2006-04-19 22:52 kingubu * lib/RDF/Helper.pm: Bump revision number pending update release. 2006-04-19 22:49 kingubu * lib/RDF/Helper/RDFRedland/TiedPropertyHash.pm, t/7_property_hash.t: Added somewhat smarter logic to the TiedPropertyHash impementation to allow for resources to be stored in arrarefs 2006-04-18 18:03 nachbaur * t/7_property_hash.t: Added additional test to detect a bug in URI/resource detection 2006-04-18 16:48 nachbaur * t/: 7_property_hash.t, 8_rdf_object.t: Added some more tests to verify that URI-like properties are set as resources, rather than literals 2006-04-18 16:19 nachbaur * Makefile: Removed the Makefile that apparently was accidentally added; this should be built automagically from the Makefile.PL 2006-03-17 14:29 nachbaur * lib/RDF/Helper/Object.pm, lib/RDF/Helper/RDFRedland/TiedPropertyHash.pm, t/7_property_hash.t, t/8_rdf_object.t: Added resource traversal to Tied Hashes. Added similar functionality to RDF::Helper::Object. Added test cases. 2006-02-02 19:36 nachbaur * lib/RDF/Helper/RDFRedland.pm, t/8_rdf_object.t: Added the convenience method get_object() to RDF::Helper::RDFRedland to ease the process of using RDF::Helper::Object 2006-01-25 16:14 nachbaur * lib/RDF/Helper/Object.pm, lib/RDF/Helper/RDFRedland.pm, t/8_rdf_object.t: Added RDF::Helper::Object support 2006-01-25 16:13 nachbaur * t/: 1_nodes.t, 6_query_perl.t: Fixed tests so they pass on install 2005-11-21 21:33 nachbaur * lib/RDF/Helper/: PerlConvenience.pm, RDFRedland.pm: - Checked in some sick auto-expansion of namespace prefixes, rdf:about labelling for hashref2rdf, and auto-detection of resource identifiers 2005-11-21 20:23 nachbaur * META.yml, lib/RDF/Helper.pm, lib/RDF/Helper/RDFRedland.pm: - Checked in some of ubu's changes 2005-06-03 01:45 kingubu * lib/RDF/Helper/RDFRedland.pm: Better type magic for hashref2rdf 2005-05-26 11:23 nachbaur * lib/RDF/Helper/RDFRedland.pm: Serialize the RDF model using any provided namespace prefixes 2005-05-19 07:31 kingubu * META.yml, lib/RDF/Helper/RDFRedland.pm: New convenience function: hashlist_from_statement 2005-05-13 13:33 kingubu * lib/RDF/Helper.pm: lose the 'our' bit 2005-05-13 13:31 kingubu * Makefile.PL, lib/RDF/Helper.pm: remove Trix requirement 2005-05-13 13:20 kingubu * dump.rdf: remove debugging dumpfile 2005-05-13 13:13 kingubu * .DS_Store, Changes, MANIFEST, MANIFEST.SKIP, META.yml, Makefile, Makefile.PL, README, dump.rdf, lib/RDF/.DS_Store, lib/RDF/Helper.pm, lib/RDF/Helper/Constants.pm, lib/RDF/Helper/PerlConvenience.pm, lib/RDF/Helper/RDFCore.pm, lib/RDF/Helper/RDFRedland.pm, lib/RDF/Helper/RDFRedland/Query.pm, lib/RDF/Helper/RDFRedland/TiedPropertyHash.pm, t/0_basic.t, t/1_nodes.t, t/2_model_basics.t, t/3_include_model.t, t/4_include_rdfxml.t, t/5_rdf2perl.t, t/6_query_perl.t, t/7_property_hash.t, t/data/use.perl.rss: Initial commit 2005-05-13 13:13 kingubu * .DS_Store, Changes, MANIFEST, MANIFEST.SKIP, META.yml, Makefile, Makefile.PL, README, dump.rdf, lib/RDF/.DS_Store, lib/RDF/Helper.pm, lib/RDF/Helper/Constants.pm, lib/RDF/Helper/PerlConvenience.pm, lib/RDF/Helper/RDFCore.pm, lib/RDF/Helper/RDFRedland.pm, lib/RDF/Helper/RDFRedland/Query.pm, lib/RDF/Helper/RDFRedland/TiedPropertyHash.pm, t/0_basic.t, t/1_nodes.t, t/2_model_basics.t, t/3_include_model.t, t/4_include_rdfxml.t, t/5_rdf2perl.t, t/6_query_perl.t, t/7_property_hash.t, t/data/use.perl.rss: Initial revision CONTRIB000644000765000765 7211601114550 13002 0ustar00kipkip000000000000RDF-Helper-2.0* Deep recursion fix for deep_prophash, Gregory Willians. LICENSE000644000765000765 4351111601114550 13051 0ustar00kipkip000000000000RDF-Helper-2.0This software is copyright (c) 2011 by Kip Hampton. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2011 by Kip Hampton. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2011 by Kip Hampton. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End dist.ini000644000765000765 51711601114550 13447 0ustar00kipkip000000000000RDF-Helper-2.0name = RDF-Helper version = 2.0 author = Kip Hampton license = Perl_5 copyright_holder = Kip Hampton [@Basic] [PodCoverageTests] [PodSyntaxTests] [Prereqs] Test::Simple = 0.88 Data::UUID = 0 RDF::Query = 2.905 URI = 0 Moose = 1.09 MooseX::Aliases = 0 [@Git] tag_format = release-%v META.yml000644000765000765 104711601114550 13273 0ustar00kipkip000000000000RDF-Helper-2.0--- abstract: 'Provide a consistent, high-level API for working with RDF with Perl' author: - 'Kip Hampton ' build_requires: {} configure_requires: ExtUtils::MakeMaker: 6.31 dynamic_config: 0 generated_by: 'Dist::Zilla version 4.200004, CPAN::Meta::Converter version 2.110930' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: RDF-Helper requires: Data::UUID: 0 Moose: 1.09 MooseX::Aliases: 0 RDF::Query: 2.905 Test::Simple: 0.88 URI: 0 version: 2.0 MANIFEST000644000765000765 121711601114550 13152 0ustar00kipkip000000000000RDF-Helper-2.0CONTRIB Changes LICENSE MANIFEST META.yml Makefile.PL README dist.ini lib/RDF/Helper.pm lib/RDF/Helper/API.pm lib/RDF/Helper/Constants.pm lib/RDF/Helper/Object.pm lib/RDF/Helper/PerlConvenience.pm lib/RDF/Helper/RDFQuery.pm lib/RDF/Helper/RDFRedland.pm lib/RDF/Helper/RDFRedland/Query.pm lib/RDF/Helper/RDFTrine.pm lib/RDF/Helper/Statement.pm lib/RDF/Helper/TiedPropertyHash.pm t/0_basic.t t/10_deep_prop_recursive.t t/11_serialized_namespaces.t t/1_nodes.t t/2_model_basics.t t/3_include_model.t t/4_include_rdfxml.t t/5_rdf2perl.t t/6_query_perl.t t/7_property_hash.t t/8_rdf_object.t t/data/use.perl.rss t/release-pod-coverage.t t/release-pod-syntax.t t000755000765000765 011601114550 12124 5ustar00kipkip000000000000RDF-Helper-2.00_basic.t000644000765000765 136511601114550 13755 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use strict; use warnings; BEGIN { use_ok('RDF::Helper'); use_ok('RDF::Helper::Constants'); } my $found_libs = 0; test( base => 'RDF::Redland', class => 'RDF::Helper::RDFRedland' ); test( base => 'RDF::Trine', class => 'RDF::Helper::RDFTrine' ); ok( $found_libs > 0) or diag("You must have one of Perl's RDF libraries (RDF::Redland, RDF::Trine etc.) installed for this package to work!!!"); sub test { my %args = @_; SKIP: { eval "require $args{base}"; skip "$args{base} not installed", 1 if $@; my $helper = RDF::Helper->new( BaseInterface => $args{base} ); $found_libs++; isa_ok( $helper, 'RDF::Helper' ); isa_ok($helper->backend, $args{class} ); } } done_testing(); 1_nodes.t000644000765000765 325211601114550 14002 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use strict; use warnings; use Data::Dumper; use RDF::Helper; use constant URI1 => 'http://example.org/one'; use constant XSD_INT => 'http://www.w3.org/2001/XMLSchema#int'; #---------------------------------------------------------------------- # RDF::Redland #---------------------------------------------------------------------- SKIP: { eval { require RDF::Redland }; skip "RDF::Redland not installed", 6 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Redland', namespaces => { xsd => 'http://www.w3.org/2001/XMLSchema#', }, ExpandQNames => 1, BaseURI => 'http://totalcinema.com/NS/test#' ); test( $rdf ); } #---------------------------------------------------------------------- # RDF::Trine #---------------------------------------------------------------------- SKIP: { eval { require RDF::Trine }; skip "RDF::Redland not installed", 6 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', namespaces => { xsd => 'http://www.w3.org/2001/XMLSchema#', }, ExpandQNames => 1, BaseURI => 'http://totalcinema.com/NS/test#' ); test( $rdf ); } sub test { my $rdf = shift; ok( $rdf->new_resource(URI1) ); ok( $rdf->new_literal('A Value') ); ok( $rdf->new_bnode ); my $typed = $rdf->new_literal('15', undef, XSD_INT); my $typed2 = $rdf->new_literal('42.17', undef, 'xsd:decimal'); my $langed = $rdf->new_literal('Speek Amurrican', 'en-US'); is($typed->literal_datatype->as_string, XSD_INT); is($typed2->literal_datatype->as_string, 'http://www.w3.org/2001/XMLSchema#decimal'); is($langed->literal_value_language, 'en-US'); } done_testing(); Makefile.PL000644000765000765 220111601114550 13765 0ustar00kipkip000000000000RDF-Helper-2.0 use strict; use warnings; use ExtUtils::MakeMaker 6.31; my %WriteMakefileArgs = ( 'ABSTRACT' => 'Provide a consistent, high-level API for working with RDF with Perl', 'AUTHOR' => 'Kip Hampton ', 'BUILD_REQUIRES' => {}, 'CONFIGURE_REQUIRES' => { 'ExtUtils::MakeMaker' => '6.31' }, 'DISTNAME' => 'RDF-Helper', 'EXE_FILES' => [], 'LICENSE' => 'perl', 'NAME' => 'RDF::Helper', 'PREREQ_PM' => { 'Data::UUID' => '0', 'Moose' => '1.09', 'MooseX::Aliases' => '0', 'RDF::Query' => '2.905', 'Test::Simple' => '0.88', 'URI' => '0' }, 'VERSION' => '2.0', 'test' => { 'TESTS' => 't/*.t' } ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.56) } ) { my $br = delete $WriteMakefileArgs{BUILD_REQUIRES}; my $pp = $WriteMakefileArgs{PREREQ_PM}; for my $mod ( keys %$br ) { if ( exists $pp->{$mod} ) { $pp->{$mod} = $br->{$mod} if $br->{$mod} > $pp->{$mod}; } else { $pp->{$mod} = $br->{$mod}; } } } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); 5_rdf2perl.t000644000765000765 733711601114550 14426 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use RDF::Helper; use Data::Dumper; #---------------------------------------------------------------------- # RDF::Redland #---------------------------------------------------------------------- SKIP: { eval { require RDF::Redland }; skip "RDF::Redland not installed", 2 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", }, ); $rdf->include_rdfxml(filename => 't/data/use.perl.rss'); my $ref = $rdf->deep_prophash('http://use.perl.org/'); ok( scalar keys %{$ref} > 0 ); my $hash_count = scalar keys %{$ref->{items}}; #warn Dumper( $ref ); ok ( $hash_count > 0 ); # my %data = ( 'dc:name' => 'kingubu', 'name' => 'Fooo', 'array' => [ 'one', 'two', 'three' ], ); my $rdf2 = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", }, ); $rdf2->hashref2rdf( \%data ); #warn $rdf2->serialize( filename => 'dump.rdf' ); #warn $rdf2->serialize( format => 'rdfxml-abbrev' ); } #---------------------------------------------------------------------- # RDF::Trine #---------------------------------------------------------------------- SKIP: { eval { require RDF::Trine }; skip "RDF::Trine not installed", 2 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", }, ); $rdf->include_rdfxml(filename => 't/data/use.perl.rss'); my $ref = $rdf->deep_prophash('http://use.perl.org/'); ok( scalar keys %{$ref} > 0 ); my $hash_count = scalar keys %{$ref->{items}}; #warn Dumper( $ref ); ok ( $hash_count > 0 ); # my %data = ( 'dc:name' => 'kingubu', 'name' => 'Fooo', 'array' => [ 'one', 'two', 'three' ], ); my $rdf2 = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", }, ); $rdf2->hashref2rdf( \%data ); #warn $rdf2->serialize( filename => 'dump.rdf' ); #warn $rdf2->serialize( format => 'rdfxml-abbrev' ); } done_testing(); 6_query_perl.t000644000765000765 1172011601114550 15105 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use RDF::Helper; use Data::Dumper; #---------------------------------------------------------------------- # RDF::Redland #---------------------------------------------------------------------- SKIP: { eval { require RDF::Redland }; skip "RDF::Redland not installed", 6 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#', QueryInterface => 'RDF::Helper::RDFRedland::Query', Namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", }, ); test( $rdf ); } #---------------------------------------------------------------------- # RDF::Trine #---------------------------------------------------------------------- SKIP: { eval { require RDF::Trine }; skip "RDF::Trine not installed", 12 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#', QueryInterface => 'RDF::Helper::RDFQuery', Namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", }, ); test( $rdf ); my $rdf2 = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#', QueryInterface => 'RDF::Helper::RDFQuery', namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", }, ); test( $rdf2 ); } done_testing(); # # Test Methods # sub test { my $rdf = shift; $rdf->include_rdfxml(filename => 't/data/use.perl.rss'); my $ref = $rdf->deep_prophash('http://use.perl.org/'); #warn Dumper( $rdf, $ref ); ok( scalar keys %{$ref} > 0, 'property hash contains key values' ); my $hash_count = scalar keys %{$ref->{items}}; #warn Dumper( $ref->{items} ); #warn Dumper( $ref->{items}->{_1} ); ok ( $hash_count > 0, 'items hash key contains key values' ); my $query1 = qq| SELECT ?creator ?date ?subject WHERE (?s dc:subject ?subject) (?s dc:creator ?creator) (?s dc:date ?date) USING dc FOR |; my $result1_count = 0; my $q_obj = $rdf->new_query( $query1, 'rdql' ); while ( my $item = $q_obj->selectrow_hashref ) { #warn Dumper( $item ); if ( defined $item->{creator} and defined $item->{subject} and defined $item->{date} ) { $result1_count++; } } #warn "ITEMS: $result1_count BY hash: $hash_count\n"; ok( $hash_count == $result1_count, 'query returned the expected number of results' ); my $array_count = 0; while ( my $array = $q_obj->selectrow_arrayref ) { #warn Dumper( $array ); $array_count++ if scalar @{$array} == 3; } ok( $hash_count == $array_count, 'DBI-like interface returned the expected number of results' ); my $query2 = qq| PREFIX dc: SELECT ?creator ?date ?subject WHERE { ?s dc:subject ?subject . ?s dc:creator ?creator . ?s dc:date ?date } |; my $result2_count = 0; my $q_obj2 = $rdf->new_query( $query2, 'sparql' ); while ( my $item = $q_obj2->selectrow_hashref ) { #warn Dumper( $item ); if ( defined $item->{creator} and defined $item->{subject} and defined $item->{date} ) { $result2_count++; } } ok( $hash_count == $result2_count, 'sparql query returned the expected number of results' ); # $rdf->query_interface('RDF::Helper::RDFQuery'); my $result3_count = 0; my $q_obj3 = $rdf->new_query( $query2, 'sparql' ); while ( my $item = $q_obj3->selectrow_hashref ) { #warn Dumper( $item ); if ( defined $item->{creator} and defined $item->{subject} and defined $item->{date} ) { $result3_count++; } } note "Hash count $hash_count ER@ count $result3_count \n"; ok( $hash_count == $result3_count, 'RDF::Query sparql query returned the expected number of results' ); } 8_rdf_object.t000644000765000765 1164411601114550 15026 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use RDF::Helper; use RDF::Helper::Object; use Data::Dumper; #---------------------------------------------------------------------- # RDF::Redland #---------------------------------------------------------------------- SKIP: { eval { require RDF::Redland }; skip "RDF::Redland not installed", 28 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", contact => "http://www.w3.org/2000/10/swap/pim/contact#", air => "http://www.daml.org/2001/10/html/airport-ont#", }, ); test( $rdf ); } #---------------------------------------------------------------------- # RDF::Trine #---------------------------------------------------------------------- SKIP: { eval { require RDF::Trine }; skip "RDF::Trine not installed", 28 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", contact => "http://www.w3.org/2000/10/swap/pim/contact#", air => "http://www.daml.org/2001/10/html/airport-ont#", }, ); test( $rdf ); } done_testing(); # # Test Functions # sub test { my $rdf = shift; $rdf->include_rdfxml(filename => 't/data/use.perl.rss'); my $obj1 = new RDF::Helper::Object( RDFHelper => $rdf, ResourceURI => 'http://use.perl.org/' ); ok(UNIVERSAL::isa($obj1, 'RDF::Helper::Object'), 'object isa RDF::Helper::Object'); ok(sprintf($obj1) eq 'http://use.perl.org/', 'object scalar overloading'); ok($obj1 eq 'http://use.perl.org/', 'object "eq" overloading'); ok($obj1 == 'http://use.perl.org/', 'object "==" overloading'); is( $obj1->title, 'use Perl', 'get resource value via default namespace' ); is( $obj1->dc_language, 'en-us', 'get resource value via specified namespace prefix, using underscore' ); ok( $obj1->title('New Title for use Perl'), 'set a new title' ); is( $obj1->title, 'New Title for use Perl', 'new title properly set' ); ok( $obj1->dc_language('en-gb'), 'set a new language via underscore prefix' ); is( $obj1->dc_language, 'en-gb', 'new language value properly set' ); ok( $obj1->title(undef), 'removing a value' ); is( $obj1->title, undef, 'value removed successfully' ); ok( $obj1->dc_language([qw( en-gb jp fr )]), 'set multiple language values' ); is( ref(scalar($obj1->dc_language)), 'ARRAY', 'multiple values - scalar arrayref' ); my @languages = $obj1->dc_language; is( join(',', sort(@languages)), join(',', sort(qw( en-gb jp fr ))), 'proper languages returned - list context' ); is( join(',', sort(@{$obj1->dc_language})), join(',', sort(qw( en-gb jp fr ))), 'proper languages returned - scalar arrayref' ); is( join(',', sort($obj1->dc_language)), join(',', sort(qw( en-gb jp fr ))), 'proper languages returned - array' ); ok( $obj1->dc_language([qw( en-gb fr )]), 'remove value from multiple language set' ); is( join(',', sort($obj1->dc_language)), join(',', sort(qw( en-gb fr ))), 'proper languages returned - array' ); is( $obj1->dc_author->dc_fullname, 'Mike Nachbaur', 'Traverse 2 object levels'); is( $obj1->dc_author->contact_nearestAirport->air_iata, 'YHW', 'Traverse 3 object levels'); $obj1->link('http://www.google.com/'); my ($link_res) = $rdf->get_statements('http://use.perl.org/', 'http://purl.org/rss/1.0/link', undef); ok($link_res->object->is_resource, 'set a string that looks like a URI encodes it as a resource'); is( $obj1->image, "http://use.perl.org/images/topics/useperl.gif", 'image property' ); is( ref($obj1->image), "RDF::Helper::Object", 'image property blessed resource' ); is( $obj1->image->object_uri, "http://use.perl.org/images/topics/useperl.gif", 'image property blessed object URI' ); is( $obj1->image->link, "http://use.perl.org/", 'image property traversed blessed object property' ); is( ref($obj1->items), "RDF::Helper::Object", 'items property blessed blank node' ); my $seq = $obj1->items; my @items = $seq->rdf_li; #warn "ITEMS " . Dumper( \@items ); my $obj2 = $rdf->get_object('http://use.perl.org/'); ok(UNIVERSAL::isa($obj2, 'RDF::Helper::Object'), 'object via get_object() isa RDF::Helper::Object'); } RDF000755000765000765 011601114550 13042 5ustar00kipkip000000000000RDF-Helper-2.0/libHelper.pm000644000765000765 4174711601114550 15013 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDFpackage RDF::Helper; use 5.10.1; use Moose; our $VERSION = '2.0'; use RDF::Helper::Statement; use RDF::Helper::Object; has backend => ( does => 'RDF::Helper::API', is => 'ro', required => 1, handles => 'RDF::Helper::API', ); sub BUILDARGS { my $this = shift; my $args = $this->SUPER::BUILDARGS(@_); return $args if $args->{backend}; my $class = delete $args->{BaseInterface}; $class = 'RDF::Redland' if (!$class && $args->{Model} && $args->{Model}->isa('RDF::Redland::Model') ); given ($class) { when (qr/RDF::Helper::.*/) { } when ('RDF::Redland') { $class = 'RDF::Helper::RDFRedland'; }; default { $class = 'RDF::Helper::RDFTrine' } } Class::MOP::load_class($class); my $backend = $class->new(%$args); return { backend => $backend }; } 1; __END__ =head1 NAME RDF::Helper - Provide a consistent, high-level API for working with RDF with Perl =head1 SYNOPSIS use RDF::Helper; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', namespaces => { dct => 'http://purl.org/dc/terms/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", } ); =head1 DESCRIPTION This module intends to simplify, normalize and extend Perl's existing facilities for interacting with RDF data. RDF::Helper's goal is to offer a syntactic sugar which will enable developers to work more efficiently. To achieve this, it implements methods to work with RDF in a way that would be familiar to Perl programmers who are less experienced with RDF. It builds on L, which in turn provides the low-level API which is closer to RDF. =head1 CONSTRUCTOR OPTIONS my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', namespaces => { dc => 'http://purl.org/dc/terms/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", }, ExpandQNames => 1 ); =head2 BaseInterface The C option expects a string that corresponds to the class name of the underlying Perl RDF library that will be used by this instance of the Helper. L is the default, but C is retained as an option for historical reasons, but may be removed in the future. If you have a Redland-based database, you can use L. =head2 Model The C option expects a blessed instance object of the RDF model that will be operated on with this instance of the Helper. Obviously, the type of object passed should correspond to the L used (L for a BaseInterface of L, etc.). If this option is omitted, a new, in-memory model will be created. =head2 namespaces The C option expects a hash reference of prefix/value pairs for the namespaces that will be used with this instance of the Helper. The special '#default' prefix is reserved for setting the default namespace. For convenience, the L class will export a number of useful constants that can be used to set the namespaces for common grammars: use RDF::Helper; use RDF::Helper::Constants qw(:rdf :rss1 :foaf); my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', namespaces => { rdf => RDF_NS, rss => RSS1_NS, foaf => FOAF_NS }, ExpandQNames => 1 ); =head2 ExpandQNames Setting a non-zero value for the C option configures the current instance of the Helper to allow for qualified URIs to be used in the arguments to many of the Helper's convenience methods. For example, given the L option for the previous example, with C turned on, the following will work as expected. $rdf->assert_resource( $uri, 'rdf:type', 'foaf:Person' ); With C turned off, you would have to pass the full URI for both the C predicate, and the C object to achieve the same result. =head2 base_uri If specified, this option sets what the base URI will be when working with so called abbreviated URIs, like C<#me>. If you do not specify an explicit base_uri option, then one will be created automatically for you. See L for more information on abbreviated URIs. =head1 METHODS =head2 new_resource $res = $rdf->new_resource($uri) Creates and returns a new resource object that represents the supplied URI. In many cases this is not necessary as the methods available in L will automatically convert a string URI to the appropriate object type in the back-end RDF implementation. =head2 new_literal $lit = $rdf->new_literal($text) $lit = $rdf->new_literal($text, $lang) $lit = $rdf->new_literal($text, $lang, $type) Creates and returns a new literal text object that represents the supplied string. In many cases this is not necessary as the methods available in L will automatically convert the value to the appropriate object type in the back-end RDF implementation. When it is necessary to explicitly create a literal object is when you want to specify the language or datatype of the text string. The datatype argument expects a Resource object or a string URI. =head2 new_bnode $bnode = $rdf->new_bnode() Creates and returns a new "Blank Node" that can be used as the subject or object in a new statement. =head2 assert_literal $rdf->assert_literal($subject, $predicate, $object) This method will assert, or "insert", a new statement whose value, or "object", is a literal. Both the subject and predicate arguments can either take a URI object, a URI string. Additionally, if you used the L option when creating the L object, you can use QNames in place of the subject and predicate values. For example, "rdf:type" would be properly expanded to its full URI value. =head2 assert_resource $rdf->assert_resource($subject, $predicate, $object) This method will assert, or "insert", a new statement whose value, or "object", is a resource. The subject, predicate and object arguments can either take a URI object, or a URI string. Like L, if you used the L option when creating the L object, you can use QNames in place of any of the arguments to this method. For example, "rdf:type" would be properly expanded to its full URI value. =head2 remove_statements $count = $rdf->remove_statements() $count = $rdf->remove_statements($subject) $count = $rdf->remove_statements($subject, $predicate) $count = $rdf->remove_statements($subject, $predicate, $object) This method is used to remove statements from the back-end RDF model whose constituent parts match the supplied arguments. Any of the arguments can be omitted, or passed in as C, which means any value for that triple part will be matched and removed. For instance, if values for the predicate and object are given, but the subject is left as "undef", then any statement will be removed that matches the supplied predicate and object. If no arguments are supplied, then all statements in the RDF model will be removed. The number of statements that were removed in this operation is returned. =head2 update_node $rdf->update_node($subject, $predicate, $object, $new_object) This method is used when you wish to change the object value of an existing statement. This method acts as an intelligent wrapper around the L and L methods, and will try to auto-detect what type of object is currently in the datastore, and will try to set the new value accordingly. If it can't make that determination it will fallback to L. Keep in mind that if you need to change a statement from having a Resource to a Literal, or vice versa, as its object, then you may need to invoke the appropriate update method directly. =head2 update_literal $rdf->update_literal($subject, $predicate, $object, $new_object) Updates an existing statement's literal object value to a new one. For more information on the operation of this method, see L. =head2 update_resource $rdf->update_resource($subject, $predicate, $object, $new_object) Updates an existing statement's resource object value to a new one. For more information on the operation of this method, see L. =head2 get_statements @stmts = $rdf->get_statements() @stmts = $rdf->get_statements($subject) @stmts = $rdf->get_statements($subject, $predicate) @stmts = $rdf->get_statements($subject, $predicate, $object) This method is used to fetch and return statements from the back-end RDF model whose constituent parts match the supplied arguments. Any of the arguments can be omitted, or passed in as C, which means any value for that triple part will be matched and returned. For instance, if values for the predicate and object are given, but the subject is left as "undef", then any statement will be returned that matches the supplied predicate and object. If no arguments are supplied, then all statements in the RDF model will be returned. Depending on which back-end type being used, different object types will be returned. For instance, if L is used, then all the returned objects will be of type L. =head2 get_triples @stmts = $rdf->get_triples() @stmts = $rdf->get_triples($subject) @stmts = $rdf->get_triples($subject, $predicate) @stmts = $rdf->get_triples($subject, $predicate, $object) This method functions in the same way as L, except instead of the statements being represented as objects, the statement's values are broken down into plain strings and returned as an anonymous array. Therefore, an individual element of the returned array may look like this: [ "http://some/statement/uri", "http://some/predicate/uri", "some object value" ] =head2 resourcelist @subjects = $rdf->resourcelist() @subjects = $rdf->resourcelist($predicate) @subjects = $rdf->resourcelist($predicate, $object) This method returns the unique list of subject URIs from within the RDF model that optionally match the predicate and/or object arguments. Like in L, either or all of the arguments to this method can be C. =head2 exists $result = $rdf->exists() $result = $rdf->exists($subject) $result = $rdf->exists($subject, $predicate) $result = $rdf->exists($subject, $predicate, $object) Returns a boolean value indicating if any statements exist in the RDF model that matches the supplied arguments. =head2 count $count = $rdf->count() $count = $rdf->count($subject) $count = $rdf->count($subject, $predicate) $count = $rdf->count($subject, $predicate, $object) Returns the number of statements that exist in the RDF model that matches the supplied arguments. If no arguments are supplied, it returns the total number of statements in the model are returned. =head2 include_model $rdf->include_model($model) Include the contents of another, already opened, RDF model into the current model. =head2 include_rdfxml $rdf->include_rdfxml(xml => $xml_string) $rdf->include_rdfxml(filename => $file_path) This method will import the RDF statements contained in an RDF/XML document, either from a file or a string, into the current RDF model. If a L was specified in the L L, then that URI is used as the base for when the supplied RDF/XML is imported. For instance, if the hash notation is used to reference an RDF node (e.g. Crdf:Description rdf:about="#dahut"/E>), the L will be prepended to the C URI. =head2 serialize $string = $rdf->serialize() $string = $rdf->serialize(format => 'ntriple') $rdf->serialize(filename => 'out.rdf') $rdf->serialize(filename => 'out.n3', format => 'ntriple') Serializes the back-end RDF model to a string, using the specified format type, or defaulting to abbreviated RDF/XML. The serialization types depends on which RDF back-end is in use. The L support within L supports the following serialization types: =over 4 =item * ntriples =item * nquads =item * rdfxml =item * rdfjson =item * ntriples-canonical =item * turtle =back =head2 new_query $query_object = $obj->new_query( $query, [$base_uri, $lang_uri, $lang_name] ); Returns an instance of the class defined by the L argument passed to the constructor (or the default class for the base interface if none is explicitly set) that can be used to query the currently selected model. =head1 PERLISH CONVENIENCE METHODS =head2 property_hash $hash_ref = $rdf->property_hash($subject) For instances when you don't know what properties are bound to an RDF node, or when it is too cumbersome to iterate over the results of a L method call, this method can be used to return all the properties and values bound to an RDF node as a hash reference. The key name will be the predicate URI (QName-encoded if a matching namespace is found), and the value will be the object value of the given predicate. Multiple object values for the same predicate URI will be returned as an array reference. It is important to note that this is a read-only dump from the RDF model. For a "live" alternative to this, see L. =head2 deep_prophash $hashref = $rdf->deep_prophash($subject) This method is similar to the L method, except this method will recurse over children nodes, in effect creating a nested hashref data structure representing a node and all of its associations. B This method performs no checks to ensure that it doesn't get stuck in a deep recursion loop, so be careful when using this. =head2 tied_property_hash $hash_ref = $rdf->tied_property_hash($subject) $hash_ref = $rdf->tied_property_hash($subject, \%options) Like L, this method returns a hash reference containing the predicates and objects bound to the given subject URI. This method differs however in that any changes to the hash will immediately be represented in the RDF model. So if a new value is assigned to an existing hash key, if a new key is added, or a key is deleted from the hash, that will transparently be represented as updates, assertions or removal operations against the model. Optionally a hash can be passed to this method when tieing a property hash to give additional instructions to the L object. Please see the documentation in that class for more information. =head2 get_object $obj = $rdf->get_object($subject, %options) $obj = $rdf->get_object($subject, \%options) Returns an instance of L bound to the given subject URI. This exposes that RDF node as an object-oriented class interface, allowing you to interact with and change that RDF node and its properties using standard Perl-like accessor methods. For more information on the use of this method, please see L. =head2 arrayref2rdf $obj->arrayref2rdf(\@list, $subject, $predicate); $obj->arrayref2rdf(\@list, undef, $predicate); Asserts a list of triples with the the subject C<$subject>, predicate C<$predicate> and object(s) contained in C<\@list>. It the subject is undefined, a new blank node will be used. =head2 hashref2rdf $object->hashref2rdf( \%hash ); $object->hashref2rdf( \%hash, $subject ); This method is the reverse of L and L in that it accepts a Perl hash reference and unwinds it into a set of triples in the RDF store. If the C<$subject> is missing or undefined a new blank node will be used. =head2 hashlist_from_statement @list = $rdf->hashlist_from_statement() @list = $rdf->hashlist_from_statement($subject) @list = $rdf->hashlist_from_statement($subject, $predicate) @list = $rdf->hashlist_from_statement($subject, $predicate, $object) Accepting a sparsely populated triple pattern as its argument, this methods return a list of subject/hash reference pairs for all statements that match the pattern. Each member in the list will have the following structure: [ $subject, $hash_reference ] =head1 ACCESSOR METHODS =head2 model $model = $rdf->model() $rdf->model($new_model) An accessor method that can be used to retrieve or set the back-end RDF model that this L instance uses. =head2 query_interface $iface = $rdf->query_interface() $rdf->query_interface($iface) Accessor method that is used to either set or retrieve the current class name that should be used for composing and performing queries. =head1 SEE ALSO L; L, L; L =head1 SUPPORT There is a mailing list at L. A bunch of people are also hanging out in C<#perlrdf> on C. =head1 AUTHOR Kip Hampton, Ekhampton@totalcinema.com =head1 COPYRIGHT AND LICENSE Copyright 2004-2011 by Kip Hampton, Chris Prather, Mike Nachbaur This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 2_model_basics.t000644000765000765 1156211601114550 15342 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use strict; use warnings; use RDF::Helper; use RDF::Helper::Constants qw(:rdf :rss1 :foaf); use constant URI1 => 'http://example.org/one'; use constant URI2 => 'http://example.org/two'; #---------------------------------------------------------------------- # RDF::Redland #---------------------------------------------------------------------- SKIP: { eval { require RDF::Redland }; skip "RDF::Redland not installed", 25 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#' ); test( $rdf ); #print $rdf->serialize(); my $rdf2 = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { rdf => RDF_NS, rss => RSS1_NS }, ExpandQNames => 1, ); test_qnames( $rdf2 ); #warn $rdf->serialize; my $rdf3 = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#', namespaces => { rdf => RDF_NS, rss => RSS1_NS }, ExpandQNames => 1, ); test_qnames( $rdf3 ); } #---------------------------------------------------------------------- # RDF::Trine #---------------------------------------------------------------------- SKIP: { eval { require RDF::Trine }; skip "RDF::Trine not installed", 25 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#' ); test( $rdf ); #print $rdf->serialize(); my $rdf2 = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { rdf => RDF_NS, rss => RSS1_NS }, ExpandQNames => 1, ); test_qnames( $rdf2 ); #warn $rdf->serialize; my $rdf3 = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#', namespaces => { rdf => RDF_NS, rss => RSS1_NS }, ExpandQNames => 1, ); test_qnames( $rdf3 ); } done_testing(); # # Test Methods # sub test { my $rdf = shift; # assert_resource - explicit constructors/nodes my $subj = $rdf->new_resource(URI1); my $pred = $rdf->new_resource(RDF_TYPE); my $obj = $rdf->new_resource(RSS1_ITEM); $rdf->assert_resource($subj, $pred, $obj); ok( $rdf->exists($subj, $pred, $obj) == 1, 'assert_resource as objects' ); # assert_resource - as strings $rdf->assert_resource(URI1, RSS1_LINK, URI2); ok( $rdf->exists(URI1, RSS1_LINK, $rdf->new_resource(URI2)) == 1, 'assert_resource as strings' ); # assert_literal - explicit constructors/nodes $subj = $rdf->new_resource(URI1); $pred = $rdf->new_resource(RSS1_TITLE); $obj = $rdf->new_literal('Some Title'); $rdf->assert_literal($subj, $pred, $obj); ok( $rdf->exists($subj, $pred, $obj) == 1, 'assert_literal as objects' ); # assert_literal - as strings $rdf->assert_literal(URI1, RSS1_DESCRIPTION, 'Some Description'); ok( $rdf->exists(URI1, RSS1_DESCRIPTION, 'Some Description') == 1, 'assert_literal as strings' ); # bugfix test # assert_literal - numeric unquoted $rdf->assert_literal(URI1, RSS1_DESCRIPTION, 420); ok( $rdf->exists(URI1, RSS1_DESCRIPTION, 420) == 1, 'assert_literal as bare numeric string' ); ok( $rdf->count() == 5, 'count() with no args.'); ok( $rdf->count(URI1) == 5, 'count() with subject only.'); ok( $rdf->count(undef, RSS1_TITLE) == 1, 'count() with pred only.'); ok( $rdf->count(undef, undef, 'Some Title') == 1, 'count() with object only.'); $rdf->remove_statements(undef, RSS1_TITLE); ok( $rdf->count() == 4, 'remove statement'); $rdf->update_literal(URI1, RSS1_DESCRIPTION, 'Some Description', 'New Description'); ok( $rdf->exists(URI1, RSS1_DESCRIPTION, 'Some Description') == 0, 'update literal' ); ok( $rdf->exists(URI1, RSS1_DESCRIPTION, 'New Description') == 1, 'update literal' ); my @trips = $rdf->get_triples(URI1, undef, undef); ok( scalar(@trips) == 4, 'get triples'); } sub test_qnames { my $rdf = shift; $rdf->assert_resource( URI1, 'rdf:type', 'rss:item' ); ok( $rdf->exists(URI1, RDF_TYPE, RSS1_ITEM) == 1, 'assert_resource using qnames' ); ok( $rdf->exists(URI1, 'rdf:type', 'rss:item') == 1, 'assert_resource using qnames and checking with qnames' ); $rdf->assert_literal( URI1, 'rss:description', 'Some Description' ); ok( $rdf->exists(URI1, RSS1_DESCRIPTION, 'Some Description') == 1, 'assert_literal using qnames' ); $rdf->update_literal( URI1, 'rss:description', 'Some Description', 'Some Other Description' ); ok( $rdf->exists(URI1, RSS1_DESCRIPTION, 'Some Description') == 0, 'update_literal using qnames' ); ok( $rdf->exists(URI1, RSS1_DESCRIPTION, 'Some Other Description') == 1, 'update_literal using qnames' ); ok( $rdf->count(undef, 'rss:description') == 1, 'count() with qnamed pred only.'); } 3_include_model.t000644000765000765 514211601114550 15477 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use strict; use warnings; use RDF::Helper; use RDF::Helper::Constants qw(:rdf :rss1); use constant URI1 => 'http://example.org/one'; use constant URI2 => 'http://example.org/two'; #---------------------------------------------------------------------- # RDF::Redland #---------------------------------------------------------------------- SKIP: { eval { require RDF::Redland }; skip "RDF::Redland not installed", 5 if $@; my $rdf1 = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#' ); my $rdf2 = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#' ); $rdf1->assert_resource(URI1, RSS1_LINK, URI2); $rdf1->assert_literal(URI1, RSS1_DESCRIPTION, 'Some Description'); $rdf2->assert_resource(URI2, RSS1_LINK, URI1); $rdf2->assert_literal(URI2, RSS1_DESCRIPTION, 'Some Other Description'); $rdf1->include_model( $rdf2->model() ); ok ( $rdf1->count() == 4, '4 nodes'); ok( $rdf1->exists(URI1, RSS1_LINK, $rdf1->new_resource(URI2)) == 1 ); ok( $rdf1->exists(URI1, RSS1_DESCRIPTION, 'Some Description') == 1 ); ok( $rdf1->exists(URI2, RSS1_LINK, $rdf1->new_resource(URI1)) == 1 ); ok( $rdf1->exists(URI2, RSS1_DESCRIPTION, 'Some Other Description') == 1 ); #my $serializer=new RDF::Redland::Serializer(); # my $out = $serializer->serialize_model_to_file("deleteme.rdf", RDF::Redland::URI->new('http://totalcinema.com/NS/test#'), $rdf1->model); } #---------------------------------------------------------------------- # RDF::Trine #---------------------------------------------------------------------- SKIP: { eval { require RDF::Trine }; skip "RDF::Trine not installed", 5 if $@; my $rdf1 = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#' ); my $rdf2 = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#' ); $rdf1->assert_resource(URI1, RSS1_LINK, URI2); $rdf1->assert_literal(URI1, RSS1_DESCRIPTION, 'Some Description'); $rdf2->assert_resource(URI2, RSS1_LINK, URI1); $rdf2->assert_literal(URI2, RSS1_DESCRIPTION, 'Some Other Description'); $rdf1->include_model( $rdf2->model() ); ok ( $rdf1->count() == 4, '4 nodes'); ok( $rdf1->exists(URI1, RSS1_LINK, $rdf1->new_resource(URI2)) == 1 ); ok( $rdf1->exists(URI1, RSS1_DESCRIPTION, 'Some Description') == 1 ); ok( $rdf1->exists(URI2, RSS1_LINK, $rdf1->new_resource(URI1)) == 1 ); ok( $rdf1->exists(URI2, RSS1_DESCRIPTION, 'Some Other Description') == 1 ); } done_testing(); 7_property_hash.t000644000765000765 1265011601114550 15611 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use RDF::Helper; use RDF::Helper::TiedPropertyHash; use Data::Dumper; #---------------------------------------------------------------------- # RDF::Redland #---------------------------------------------------------------------- SKIP: { eval { require RDF::Redland }; skip "RDF::Redland not installed", 22 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", }, ); test( $rdf ); my $in_memory = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", dc => 'http://purl.org/dc/elements/1.1/', }, ); test_inmemory( $in_memory ); } #---------------------------------------------------------------------- # RDF::Trine #---------------------------------------------------------------------- SKIP: { eval { require RDF::Trine }; skip "RDF::Trine not installed", 22 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { dc => 'http://purl.org/dc/elements/1.1/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://purl.org/rss/1.0/", slash => "http://purl.org/rss/1.0/modules/slash/", taxo => "http://purl.org/rss/1.0/modules/taxonomy/", syn => "http://purl.org/rss/1.0/modules/syndication/", admin => "http://webns.net/mvcb/", }, ); test( $rdf ); my $in_memory = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#', Namespaces => { rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", dc => 'http://purl.org/dc/elements/1.1/', }, ); test_inmemory( $in_memory ); } done_testing(); # # Test Functions # sub test { my $rdf = shift; $rdf->include_rdfxml(filename => 't/data/use.perl.rss'); my %hash = (); tie %hash, RDF::Helper::TiedPropertyHash, $rdf, 'urn:x-test:1'; is( tied(%hash), 'urn:x-test:1', 'Tied property "" overloading' ); ok( tied(%hash) eq 'urn:x-test:1', 'Tied property eq overloading' ); ok( tied(%hash) == 'urn:x-test:1', 'Tied property == overloading' ); $hash{foo} = 'wibble'; $hash{bar} = 'norkle'; is( $hash{foo}, 'wibble', 'Set hash property "foo"' ); is( $hash{bar}, 'norkle', 'Set hash property "bar"' ); my $tester = delete $hash{foo}; is( $tester, 'wibble', 'Delete hash property "foo"'); my $hashref = $rdf->tied_property_hash('urn:x-test:1'); ok( $hashref, 'tied_property_hash' ); $hashref->{'dc:creator'} = 'ubu'; is( $hashref->{'dc:creator'}, 'ubu', 'Set hash property "dc:creator"' ); $hashref->{'dc:language'} = [qw( en-US jp fr es )]; is( join(',', sort(@{$hashref->{'dc:language'}})), join(',', sort(qw( en-US jp fr es ))), 'set / return multiple property "dc:language" values' ); $hashref->{'dc:language'} = [qw( en-US jp es )]; is( join(',', sort(@{$hashref->{'dc:language'}})), join(',', sort(qw( en-US jp es ))), 'set / return different property "dc:language" values' ); $hashref->{'dc:language'} = "en-US"; is( ref($hashref->{'dc:language'}), '', 'Set single value into "dc:language" property' ); is( $hashref->{'dc:language'}, 'en-US', 'Fetch value from "dc:language" property' ); $hashref->{'link'} = 'http://www.google.com/'; my ($link_res_1) = $rdf->get_statements('urn:x-test:1', 'http://purl.org/rss/1.0/link', undef); ok($link_res_1->object->is_resource, 'Set a string that looks like a URI encodes it as a resource'); $hashref->{'link'} = ['http://www.google.com/']; my ($link_res_2) = $rdf->get_statements('urn:x-test:1', 'http://purl.org/rss/1.0/link', undef); ok($link_res_2->object->is_resource, 'Set an arrayref that looks like a URI encodes it as a resource'); my %useperl1; tie %useperl1, RDF::Helper::TiedPropertyHash, $rdf, 'http://use.perl.org/'; is( $useperl1{title}, 'use Perl', 'Get existing RSS property "title"' ); is( $useperl1{'dc:language'}, 'en-us', 'Get existing RSS property "dc:language"' ); ok( !ref($useperl1{'image'}), 'Resource node does not return a reference' ); is( $useperl1{'image'}, 'http://use.perl.org/images/topics/useperl.gif', 'Resource node returns a plain value' ); my %useperl2; tie %useperl2, RDF::Helper::TiedPropertyHash, $rdf, 'http://use.perl.org/', { Deep => 1 }; is( $useperl2{title}, 'use Perl', 'Got title for deep-tied hash' ); is( ref($useperl2{'image'}), 'HASH', 'Deep-tied resource node returns a hash reference' ); is( $useperl2{'image'}->{url}, 'http://use.perl.org/images/topics/useperl.gif', 'Traverse deep-tied resource node to image -> url property' ); } sub test_inmemory { my $rdf = shift; my %dummy = (); tie %dummy, RDF::Helper::TiedPropertyHash, $rdf, 'http://totalcinema.com/'; $dummy{'dc:creator'} = [ 'mike', 'kip', 'kjetil' ]; my $creators = $dummy{'dc:creator'}; ok( ref( $creators ) eq 'ARRAY' and scalar @{$creators} == 3 ); } data000755000765000765 011601114550 13035 5ustar00kipkip000000000000RDF-Helper-2.0/tuse.perl.rss000644000765000765 10460711601114550 15532 0ustar00kipkip000000000000RDF-Helper-2.0/t/data use Perl http://use.perl.org/ All the Perl that's Practical to Extract and Report en-us use Perl; is Copyright 1998-2004, Chris Nandor. Stories, comments, journals, and other submissions posted on use Perl; are Copyright their respective owners. 2005-04-06T05:35:23+00:00 pudge pudge@perl.org Technology hourly 1 1970-01-01T00:00+00:00 use Perl http://use.perl.org/images/topics/useperl.gif http://use.perl.org/ Mike Nachbaur Mike Nachbaur YHW Perl 5.9.2 released http://use.perl.org/article.pl?sid=05/04/02/2135258&from=rss The Perl 5 developer team is pleased to announce the release of perl 5.9.2, the third development release of perl 5.9, incorporating developments towards the next major stable version of perl, perl 5.10. <p /> It is available from the Comprehensive Perl Archive Network as <pre> ftp://ftp.cpan.org/pub/CPAN/src/perl-5.9.2.tar.gz </pre> Its MD5 checksum is a98df18c362355172c86c2f6cb1be9a2 and its size is 12450287 bytes. <p /> The perl592delta document outlines the changes between perl 5.9.1 and perl 5.9.2. It can be found at: <pre> http://search.cpan.org/~rgarcia/perl-5.9.2/pod/perl592delta.pod </pre> rafael 2005-04-02T21:30:00+00:00 releases mainpage 0,0,0,0,0,0,0 YAPC::NA 2nd Call-for-Papers http://use.perl.org/article.pl?sid=05/04/01/1634248&from=rss <A HREF="http://yapc.org/America/">RichDice</A> writes <i>"Just a reminder -- the Call-For-Papers deadline for Yet Another Perl Conference North America 2005 in Toronto is April 18 -- that's only 2.5 weeks away from now. As a reminder that this is coming up soon, we are issuing this Second Call-For-Papers. <p> Once all papers are submitted, the YAPC conference organizing team will review them over the following week and hopefully have a draft conference schedule by Monday 25 April. <p> Get more details about the Call-For-Papers at: <A HREF="http://yapc.org/America/cfp-2005.shtml">http://yapc.org/America/cfp-2005.shtml</a> <p> Also, if you haven't registered yet, please do! Prompt registration is <b>very</b> recommended as hotel and other accommodations in Toronto are going to book up quickly for the end of June. Book by the first week of May -- you're good. After that, nothing can be guaranteed. Registration info is here: <A HREF="http://yapc.org/America/register-2005.shtml">http://yapc.org/America/register-2005.shtml</a> <p> Questions / comments regarding the Call-For-Papers: <A HREF="mailto:na-author@yapc.org">na-author@yapc.org</a> <br> General questions / comments: <A HREF="mailto:na-help@yapc.org">na-help@yapc.org</a>"</i> KM 2005-04-01T16:54:00+00:00 yapc yapc 0,0,0,0,0,0,0 YAPC::NA::2005 Registration Open http://use.perl.org/article.pl?sid=05/03/18/192229&from=rss Registration for <a href="http://yapc.org/America/">YAPC::NA</a> (Yet Another Perl Conference, North America) 2005 in Toronto, Ontario, Canada is now open. <p> The conference registration price is USD$85. This price includes admission to all aspects of the conference, respectable amounts of catering, several activities and a few conference goodies. Please see <a href="http://yapc.org/America/register-2005.shtml">the website</a> for full details, and we hope to see you in Toronto this summer! KM 2005-03-18T19:00:00+00:00 yapc yapc 7,7,7,2,0,0,0 7 Parrot 0.1.2 "Phoenix" Released http://use.perl.org/article.pl?sid=05/03/07/1451236&from=rss <A HREF="http://use.perl.org/~coke/">Will Coleda</A> writes <i>"From leo&mdash;<br> <br> On behalf of the Parrot team I'm proud to announce the release of Parrot 0.1.2. <br> <br> What is Parrot? <br> <br> Parrot is a virtual machine aimed at running Perl6 and other dynamic languages. <br> <br> Parrot 0.1.2 contains a lot of new stuff: <br> <br> <ul> <li>New string handling code. Strings now have charset and encoding <li>Parts of a generational garbage collector <li>Better Python support, separated into dynclasses <li>Parrot Grammar Engine <li>Improved test coverage and documentation <li>and a lot more </ul> You can grab it from <A HREF="http://www.cpan.org/authors/id/L/LT/LTOETSCH/parrot-0.1.2.tar.gz">CPAN</a>. <br> <br> As parrot is still in steady development we recommend that you just <A HREF="http://dev.perl.org/cvs/">get the latest and best from CVS</a>. <br> <br> Turn your web browser towards <A HREF="http://www.parrotcode.org/">http://www.parrotcode.org</a> for more information about Parrot, get involved, and: <br> <br> Have fun!<br> leo"</i> KM 2005-03-07T15:11:00+00:00 parrot news 3,3,3,1,0,0,0 3 Pugs Apocryphon 1 released http://use.perl.org/article.pl?sid=05/02/27/0930208&from=rss <A HREF="mailto:autrijus@autrijus.org">autrijus</A> writes <i>"I'm glad to report that I have released <A HREF="http://svn.perl.org/perl6/pugs/trunk/docs/01Overview.html">Pugs Apocryphon 1: Overview of the Pugs project</a>. In it I explained the relationship between existing Perl 6 projects and Pugs (a Perl 6 implementation). I have also listed some resources for people who'd like to help. Feedbacks are most welcome!"</i> rafael 2005-02-27T09:48:00+00:00 perl6 mainpage 2,2,2,0,0,0,0 2 The Perl Review, Spring 2005 http://use.perl.org/article.pl?sid=05/02/27/0431255&from=rss <A HREF="mailto:comdog@panix.com">brian_d_foy</A> writes <i>"The third print issue of <A HREF="http://www.theperlreview.com/">The Perl Review</a> is now on the presses and will be mailed on March 1 (so you have time to <A HREF="https://www.theperlreview.com/cgi-bin/subscribe.cgi/up">get your name on the subscriber list</a>). TPR is the only print magazine entirely devoted to Perl. <p> In this issue ( 1.2, Spring 2005 ) </p> <ul> <li>Hashes with History -- Alberto Manuel Sim&otilde;es <li>Test::Number::Delta -- David Golden <li>9-Block Quilt Patterns in Perl -- Daniel Allen <li>Packet Sniffing with Perl -- Gerry Finkel <li>Serious Perl -- Henning Koch <li>Barcodes from Perl -- brian d foy <li>plus Perl News, Perl Mongers and Perl Foundation reports, book reviews, short notes, and more. </ul> <p> Subscribers get immediate access to the <A HREF="http://www.theperlreview.com/Subscribers/?up">online PDF versions</a>:"</i> ziggy 2005-02-27T04:50:00+00:00 news news 0,0,0,0,0,0,0 FOSDEM: Perl Developer Room http://use.perl.org/article.pl?sid=05/02/23/0030241&from=rss <A HREF="mailto:dave@dave.org.uk">davorg</A> writes <i>"<A HREF="http://www.fosdem.org/">FOSDEM</a> is on in Brussels this weekend and this year, for the first time, there is a dedicated 'Perl Developers' Room.' I've just posted posted the <A HREF="http://www.fosdem.org/2005/index/dev_room_perl/schedule">schedule of talks</a> which includes both of the current Perl 5.x pumpkings and Allison Randal giving an update on Perl 6. If you're near Brussels this weekend then please drop in and say hello. Attendance at FOSDEM is free."</i> pudge 2005-02-23T00:49:00+00:00 events mainpage 0,0,0,0,0,0,0 Perl Foundation Funding Goals: 2005-2006 http://use.perl.org/article.pl?sid=05/02/14/1523219&from=rss Allison writes <i>"Thanks to amazingly generous members of the Perl community The Perl Foundation was able to fund Damian Conway, Larry Wall, and Dan Sugalski in 2002-2003. In 2005-2006 we hope to repeat this pattern and fund Larry Wall, Patrick Michaud, Leopold T&ouml;tsch, and a second Parrot developer. Why now? For one thing, Parrot and Perl 6 are both close enough to completion that a few full-time developers could polish them off in a very small number of "Christmases". Another (more urgent) reason is that we've just learned that we have about 6 weeks left of Leo's time before he's forced to take a sabbatical from Parrot to pursue the noble task of "putting food on the table". This would set the project back by six months or more. So here we stand, on the edge of acceleration or a severe setback. US $200 funds a day of developer time; you can read more about it in the <A HREF="http://www.perlfoundation.org/gc/grants/2005-p6-proposal.html">Perl 6 &amp; Parrot Proposal</a>. <p> Our sincere thanks go to the German Perl Workshop organizers and participants, who got things started by donating funds for just over 20 days of developer time."</i> KM 2005-02-14T15:43:00+00:00 perlfoundation news 64,64,64,22,0,0,0 64 CPAN::Forum http://use.perl.org/article.pl?sid=05/02/07/1751255&from=rss <A HREF="http://www.cpanforum.com/">gabor</A> writes <i>"I am happy to announce the first live version of <A HREF="http://www.cpanforum.com/">CPAN::Forum</a>. Graham integrated links to the individual subforums in the <A HREF="http://search.cpan.org/">search.cpan</a> results and Randy in the Kobes' search. I hope people who are searching for modules will find it a good place to discuss them. <p> You can post a message to a distribution, and people who are subscribed to that distribution will get an e-mail alert regarding the new post. For example if you have something to say about <A HREF="http://www.cpanforum.com/dist/CPAN-Forum">CPAN::Forum</a> you can do that in the its own subforum and people interested in this topic will be notified."</i> rafael 2005-02-07T18:11:00+00:00 cpan mainpage 0,0,0,0,0,0,0 YAPC::Taipei 2005 Registration Opens http://use.perl.org/article.pl?sid=05/02/07/140211&from=rss <A HREF="mailto:hcchien@hcchien.org">hcchien</A> writes <i>"The <A HREF="http://yapc.elixus.org/english/speakers.html">abstracts</a> and <A HREF="http://yapc.elixus.org/english/schedule.html">schedule</a> for YAPC::Taipei 2005, together with a <A HREF="http://register.elixus.org/yapc2005/">registration form</a>, are now online. <p> This year, we will hear Jesse Vincent's talk about plans for <A HREF="http://www.bestpractical.com/rt/">RT</a> 4.0 and beyond, as well as Brian Ingerson's thoughts on <A HREF="http://kwiki.org/">Kwiki</a>'s future. Tatsuhiko Miyagawa, the prolific CPAN author and Movable Type staff, will share his social software tricks with us, echoed by Leon Brocard's talk of exploiting web services offered by certain Other Enterprises. <p> <p> Sam Vilain and the <A HREF="http://svk.elixus.org/">SVK</a> author Chia-Liang Kao will talk about their CPAN modules: <A HREF="http://search.cpan.org/dist/Tangram/">Tangram</a> and <A HREF="http://search.cpan.org/dist/RunApp/">RunApp</a> respectively. Another local speaker Tsung-Hsiang Chang will cover practical applications of <A HREF="http://search.cpan.org/dist/Mail-SpamAssassin/">SpamAssassin</a>. </p> <p> As the closing session, Autrijus Tang will unleash a working interpreter for Perl6 (known as <A HREF="http://autrijus.org/pugs/">Pugs</a>), as well as its design documents, the Apocrypha."</i> rafael 2005-02-07T14:17:00+00:00 yapc yapc 0,0,0,0,0,0,0 Boston.pm Tech Meeting with brian d foy http://use.perl.org/article.pl?sid=05/02/04/0048202&from=rss <A HREF="http://use.perl.org/~n1vux/journal">n1vux</A> writes <i>"<A HREF="http://boston.pm.org/">Boston.pm</A> will have a tech meeting Tuesday, February 8, at Boston University, Kenmore Classroom Building, 565 Commonwealth Ave, room 103 (<A HREF="http://boston.pm.org/kwiki/index.cgi?BuDirections">directions</A> on web), starting at 7:30pm. (This is the same building but a different room from our usual location.) <P> Well-known Perl trainer and writer <code>brian d foy</code> will be presenting at this month's meeting. brian is also the publisher of <A HREF="http://www.theperlreview.com/">The Perl Review</A>. <P>At the meeting, brian will be giving his talk on <A HREF="http://www.panix.com/~comdog/#talks">Automating Software Releases</A>. <P>Please RSVP to [Boston.pm facilitor Ron] if you're planning to attend - rjk-bostonpm(at)tamias.net <P>Pizza and soda will be provided. <P>For more information about Boston Perl Mongers, or to subscribe to one of our mailing lists, visit our <A HREF="http://boston.pm.org/">website</A> at <A HREF="http://boston.pm.org/">http://boston.pm.org/</A> <P>[Cribbed from Boston.pm announcement]"</i> jjohn 2005-02-03T08:00:00+00:00 groups meetings 0,0,0,0,0,0,0 7th German Perl Workshop Schedule and Registration http://use.perl.org/article.pl?sid=05/01/25/0420255&from=rss <A HREF="mailto:wsorga@perl-workshop.de">JStenzel</A> writes <i>"The <A HREF="http://www.perl-workshop.de/en/2005/">schedule of the 7th German Perl Workshop</A>, together with the abstracts, is now online. A <A HREF="http://www.perl-workshop.de/en/db/register.epl">registration form</A> is provided on the same page. The Workshop will be held in Dresden from 9th to 11th February 2005. Both German and English talks will be presented in the typical workshop atmosphere which inspired me as often as I took part."</i> pudge 2005-01-25T04:40:00+00:00 events meetings 0,0,0,0,0,0,0 YAPC::NA 2005 Call For Papers Released http://use.perl.org/article.pl?sid=05/01/24/1357207&from=rss <A HREF="mailto:na-help@yapc.org">Richard Dice</A> writes <i>" <b>YAPC::NA 2005</b> (Yet Another Perl Conference, North America) has just released its call-for-papers; potential and aspiring speakers can submit a presentation proposal via: <p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <A HREF="http://yapc.org/America/cfp-2005.shtml">http://yapc.org/America/cfp-2005.shtml</a>"</i> KM 2005-01-24T14:16:00+00:00 news yapc 0,0,0,0,0,0,0 OSCON Call For Proposals http://use.perl.org/article.pl?sid=05/01/21/1356251&from=rss <A HREF="http://www.askbjoernhansen.com/">Ask Bjørn Hansen</A> writes <i>"<A HREF="http://conferences.oreillynet.com/os2005/">OSCON</a> is headed back to friendly, economical Portland, Oregon during the week of August 1-5, 2005. If you've ever wanted to join the OSCON speaker firmament, now's your chance to submit a proposal (or two) by February 13, 2005.<BR></I> KM 2005-01-21T14:15:00+00:00 events news 0,0,0,0,0,0,0 Dutch Perl Workshop 2005, Program Available http://use.perl.org/article.pl?sid=05/01/07/1431223&from=rss <A HREF="mailto:mark@overmeer.net">Mark Ovemeer</A> writes <i>"The schedule of the second Dutch Perl Workshop has just been released. With speakers like Allison Randal, Johan Vromans, Abigail, H.Merijn Brand (config pumpkin), and Abe (mr Smoke) [just to give a few examples] we have a very interesting day ahead of us. I am very sorry for most of you: all but one talk will be in Dutch! See <A HREF="http://workshop.perlpromo.nl/">http://workshop.perlpromo.nl</A>."</i> rafael 2005-01-07T14:50:00+00:00 events meetings 0,0,0,0,0,0,0 January 2005 Dallas/Ft. Worth Perl Mongers Meeting http://use.perl.org/article.pl?sid=05/01/04/2246222&from=rss <A HREF="http://reversethis-{moc.liamg} {ta} {tarksum.rm}">Mr. Muskrat</A> writes <i>"The first Dallas / Ft. Worth Perl Mongers technical meeting of 2005 will feature Patrick Michaud speaking about the Perl 6 grammars. The meeting will be held at 7pm on January 25, 2005. The <A HREF="http://dfw.pm.org/news.html">D/FW PM News</a> has the complete details (including a map)."</i> pudge 2005-01-05T12:05:00+00:00 perl6 meetings 4,4,4,1,0,0,0 4 YAPC::EU::2005 Call for Papers http://use.perl.org/article.pl?sid=05/01/04/2243255&from=rss <A HREF="http://{cog} {at} {cpan.org}">cog</A> writes <i>"This is the first Call for Papers for YAPC::EU::2005, at the University of Minho, Braga, Portugal from 31 August to 2 September, 2005. Proposals are due 15 May, speakers will be notified 19 June, and papers/slides are due 31 July. The theme for this year's conference is 'Perl Everywhere'; we are therefore looking for talks on this topic. Show us on which platforms you use Perl and what for. We will also, of course, accept talks on topics that are not related to the theme. If you have an idea for a talk you'd like to give, or a topic you'd like to hear a talk on, you should post a synopsis on our <A HREF="http://braga.yapceurope.org/index.cgi?TalkProposals">conference wiki</A> to see what others think. Proposed talks with a favourable response on the wiki have a better chance of getting accepted."</i> pudge 2005-01-04T23:02:00+00:00 events yapc 0,0,0,0,0,0,0 Perl Mongers Hosting Changes http://use.perl.org/article.pl?sid=04/12/29/1522251&from=rss <A HREF="mailto:dave@dave.org.uk">davorg</A> writes <i>"Early in 2005 the <A HREF="http://www.pm.org/">pm.org</a> server that hosts a large number of Perl Monger web sites and mailing lists will be moving and will become part of the <A HREF="http://www.perl.org/">perl.org</a> server farm. <p>We are planning to take this opportunity to remove a lot of inactive web sites and mailing lists and will therefore only be moving over sites and lists that are specifically requested by PM groups.</p> <p>If you're the leader of a PM group that uses these services then you need to send an email to <A HREF="mailto:user_groups@pm.org">user_groups@pm.org</a> with the subject "Please save xxx.pm". Within the email please list the web sites and mailing lists that you want saved.</p> <p>If you're a member of a PM group that uses this services, them please do what you can to ensure that your group leader is aware of these forthcoming changes."</i> KM 2004-12-29T15:42:00+00:00 groups mainpage 0,0,0,0,0,0,0 Help Regenerate the Phalanx 100 http://use.perl.org/article.pl?sid=04/12/21/0534201&from=rss <A HREF="mailto:andy@petdance.com">Andy Lester</A> writes <i>"The Phalanx 100 is a list of the 'top 100' modules on CPAN, and by extension, those that should have the most attention paid to them by the Phalanx project. <P> The first time I generated the P100 was over a year ago, and things are old and stale. Distributions have changed names (CGI::Kwiki is now Kwiki, for example). Some distros have come and some have gone. It's time to be updated. <P> This time, YOU can help determine the P100."</i> pudge 2004-12-21T05:46:00+00:00 modules mainpage 9,9,9,8,0,0,0 9 "Practical mod_perl" Book Goes Open Source http://use.perl.org/article.pl?sid=04/12/17/0929203&from=rss <A HREF="mailto:stas@stason.org">stas</A> writes : <i>"The complete <A HREF="http://modperlbook.org/">"Practical mod_perl"</a> book is now available online under the terms of the <A HREF="http://creativecommons.org/">CreativeCommons</a> <A HREF="http://creativecommons.org/licenses/by-sa/2.0/">"Attribution Share-Alike License"</a>. <p>Thanks to all who have purchased our book so far. You can still get the printed version from your favorite book store and it will certainly make a nice "light" XMas present (hint, hint<nobr> <wbr></nobr>:)."</p></i> rafael 2004-12-17T09:46:00+00:00 books mainpage 3,3,3,0,0,0,0 3 The Perl Review Offers Cheaper Subscription Options http://use.perl.org/article.pl?sid=04/12/07/2227256&from=rss <A HREF="mailto:comdog@panix.com">brian_d_foy</A> writes <i>"A lot of people have asked about an online-only edition of TPR, so <A HREF="https://www.theperlreview.com/cgi-bin/subscribe.cgi">I created one</a>. International customers can pay the same price as US subscribers ($US16), although they won't get the print edition. Those subscribers still have full access to the PDF versions. <p> We are, however, working on a European edition. If we get enough European subscribers, the online-only edition will convert to a print subscription at no additional cost. Online-only subscribers can also get the print versions for the price of shipping if they change their minds later. </p> <p> We've also reduced the price to $US20 for Canada and Mexico, since the shipping is a bit cheaper than overseas. Anyone who recently subscribed from either of those countries can contact me if they want to get the lower rate (or something else for the extra money)."</i> pudge 2004-12-07T22:47:00+00:00 news mainpage 0,0,0,0,0,0,0 CPAN Master Site Back in Business http://use.perl.org/article.pl?sid=04/12/05/2116255&from=rss <A HREF="mailto:jhi@iki.fi">jhi</A> writes <i>"The CPAN master site disk problems reported <A HREF="http://use.perl.org/article.pl?sid=04/11/29/2140235&amp;tid=32">earlier</a> are now resolved. The RAID controller had lost its mind, or more importantly, its configuration. As soon as the RAID controller was replaced, all the disks were found to be safe and sound. CPAN should be working normally now."</i> hfb 2004-12-05T21:36:00+00:00 cpan mainpage 1,1,1,0,0,0,0 1 The Perl Review 1.1 is Available http://use.perl.org/article.pl?sid=04/12/03/1045228&from=rss <A HREF="mailto:comdog@panix.com">brian_d_foy</A> writes <i>"The Winter 2004 issue of The Perl Review is now available for <A HREF="http://www.theperlreview.com/Subscribers/ThePerlReview-v1i1.pdf">subscriber download</a> from <A HREF="http://www.theperlreview.com/">our website</a>. Print versions go into the mail next week. Features include: <ul> <li>Down Translating XML -- Alberto Manuel Sim&otilde;es <li>Module Release and Beyond -- brian d foy <li>Functional Perl Programming -- Frank Antonsen <li>Faking Stored Procedures -- Zach Thompson </ul> There are a lot of changes with this issue, including a completely re-designed look by Eric Maki, and recurring columns for Perl Mongers and The Perl Foundation."</i> rafael 2004-12-03T10:57:00+00:00 news news 2,2,2,0,0,0,0 2 Perl Advent Calendar Returns for 2004 http://use.perl.org/article.pl?sid=04/12/01/1121244&from=rss <A HREF="http://2shortplanks.com/contact/">2shortplanks</A> writes <i>"The <A HREF="http://perladvent.org/">Perl Advent Calendar</a> returns for another year, again offering up a recommendation and mini-tutorial on a different CPAN module each day."</i> Yay. rafael 2004-12-01T11:40:00+00:00 news news 2,2,2,2,0,0,0 2 Perl 5.8.6 released http://use.perl.org/article.pl?sid=04/11/30/1125252&from=rss <A HREF="http://www.ccl4.org/~nick/">nicholas</A> writes <i>"The Perl 5 developer team is pleased to announce the Perl Release 5.8.6, the sixth maintenance release of Perl 5.8. It was uploaded to CPAN shortly before the <A HREF="http://use.perl.org/article.pl?sid=04/11/29/2140235&amp;tid=32">current master site issues</a>, and so hasn't been affected by this.</i>" rafael 2004-11-30T11:42:00+00:00 releases mainpage 0,0,0,0,0,0,0 4_include_rdfxml.t000644000765000765 676511601114550 15710 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use RDF::Helper; my $xml_string = undef; { local $/= undef; $xml_string = ; } #---------------------------------------------------------------------- # RDF::Redland #---------------------------------------------------------------------- SKIP: { eval { require RDF::Redland }; skip "RDF::Redland not installed", 11 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://totalcinema.com/NS/test#' ); ok($rdf->include_rdfxml(xml => $xml_string), 'include_rdfxml'); ok($rdf->exists('urn:test:1', 'http://totalcinema.com/NS/test#testa', 'Test A1'), 'test t:testa (1)'); ok($rdf->exists('urn:test:1', 'http://totalcinema.com/NS/test#testb', 'Test B1'), 'test t:testb (1)'); ok($rdf->exists('urn:test:1', 'http://totalcinema.com/NS/test#testc', 'Test C1'), 'test t:testc (1)'); ok(!$rdf->exists('urn:test:1', 'http://totalcinema.com/NS/test#testd', undef), 'test nonexistant t:testd'); ok($rdf->exists('urn:test:2', 'http://totalcinema.com/NS/test#testa', 'Test A2'), 'test t:testa (2)'); ok($rdf->exists('urn:test:2', 'http://totalcinema.com/NS/test#testb', 'Test B2'), 'test t:testb (2)'); ok($rdf->exists('urn:test:2', 'http://totalcinema.com/NS/test#testc', 'Test C2'), 'test t:testc (2)'); is($rdf->count(undef, 'http://totalcinema.com/NS/test#testa', undef), 2, 'count of t:testa'); is($rdf->count(undef, 'http://totalcinema.com/NS/test#testb', undef), 2, 'count of t:testb'); is($rdf->count(undef, 'http://totalcinema.com/NS/test#testc', undef), 2, 'count of t:testc'); } #---------------------------------------------------------------------- # RDF::Trine #---------------------------------------------------------------------- SKIP: { eval { require RDF::Trine }; skip "RDF::Trine not installed", 11 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://totalcinema.com/NS/test#' ); ok($rdf->include_rdfxml(xml => $xml_string), 'include_rdfxml'); ok($rdf->exists('urn:test:1', 'http://totalcinema.com/NS/test#testa', 'Test A1'), 'test t:testa (1)'); ok($rdf->exists('urn:test:1', 'http://totalcinema.com/NS/test#testb', 'Test B1'), 'test t:testb (1)'); ok($rdf->exists('urn:test:1', 'http://totalcinema.com/NS/test#testc', 'Test C1'), 'test t:testc (1)'); ok(!$rdf->exists('urn:test:1', 'http://totalcinema.com/NS/test#testd', undef), 'test nonexistant t:testd'); ok($rdf->exists('urn:test:2', 'http://totalcinema.com/NS/test#testa', 'Test A2'), 'test t:testa (2)'); ok($rdf->exists('urn:test:2', 'http://totalcinema.com/NS/test#testb', 'Test B2'), 'test t:testb (2)'); ok($rdf->exists('urn:test:2', 'http://totalcinema.com/NS/test#testc', 'Test C2'), 'test t:testc (2)'); is($rdf->count(undef, 'http://totalcinema.com/NS/test#testa', undef), 2, 'count of t:testa'); is($rdf->count(undef, 'http://totalcinema.com/NS/test#testb', undef), 2, 'count of t:testb'); is($rdf->count(undef, 'http://totalcinema.com/NS/test#testc', undef), 2, 'count of t:testc'); } done_testing(); __DATA__ Test A1 Test B1 Test C1 Test A2 Test B2 Test C2 Helper000755000765000765 011601114550 14261 5ustar00kipkip000000000000RDF-Helper-2.0/lib/RDFAPI.pm000644000765000765 1236411601114550 15415 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/Helperpackage RDF::Helper::API; use Moose::Role; requires qw( arrayref2rdf assert_literal assert_resource deep_prophash exists get_perl_type hashlist_from_statement hashref2rdf include_model include_rdfxml model namespaces new_bnode prefixed2resolved property_hash query_interface remove_statements resolved2prefixed resourcelist serialize tied_property_hash update_node ); sub normalize_triple_pattern { my $self = shift; my ( $s, $p, $o ) = @_; my ( $subj, $pred, $obj ) = ( undef, undef, undef ); if ( defined($s) ) { $subj = ref($s) ? $s : $self->new_resource( $self->{ExpandQNames} ? $self->qname2resolved($s) : $s ); } if ( defined($p) ) { $pred = ref($p) ? $p : $self->new_resource( $self->{ExpandQNames} ? $self->qname2resolved($p) : $p ); } if ( defined($o) ) { if ( ref($o) ) { $obj = $o; } else { my $testval = $self->{ExpandQNames} ? $self->qname2resolved($o) : $o; my $type = $self->get_perl_type($testval); if ( $type eq 'resource' ) { $obj = $self->new_resource("$testval"); } else { $obj = $self->new_literal("$testval"); } } } return ( $subj, $pred, $obj ); } sub new_resource { my $self = shift; my $uri = shift; return RDF::Helper::Node::Resource->new( uri => $uri ); } sub get_object { my $self = shift; my $resource = shift; my %args = ref( $_[0] ) eq 'HASH' ? %{ $_[0] } : @_; my $obj = new RDF::Helper::Object( RDFHelper => $self, ResourceURI => $resource, %args ); return $obj; } sub new_query { my $self = shift; my ( $query_string, $query_lang ) = @_; my $class = $self->query_interface; Class::MOP::load_class($class); return $class->new( $query_string, $query_lang, $self->model ); } sub new_literal { my $self = shift; my ( $val, $lang, $type ) = @_; if (defined($type)) { $type = $self->{ExpandQNames} ? $self->qname2resolved($type) : $type; } return RDF::Helper::Node::Literal->new( value => $val, language => $lang, datatype => $type ); } sub new_bnode { my $self = shift; my $id = shift; $id ||= time . 'r' . $self->{bnodecounter}++; return RDF::Helper::Node::Blank->new( identifier => $id ); } sub get_statements { my $self = shift; my @ret_array = (); my $e = $self->get_enumerator(@_); while ( my $s = $e->next ) { push @ret_array, $s; } return @ret_array; } sub get_triples { my $self = shift; my @ret_array = (); foreach my $stmnt ( $self->get_statements(@_) ) { my $subj = $stmnt->subject; my $obj = $stmnt->object; my $subj_value = $subj->is_blank ? $subj->blank_identifier : $subj->uri->as_string; my $obj_value; if ( $obj->is_literal ) { $obj_value = $obj->literal_value; } elsif ( $obj->is_resource ) { $obj_value = $obj->uri->as_string; } else { $obj_value = $obj->as_string; } push @ret_array, [ $subj_value, $stmnt->predicate->uri->as_string, $obj_value ]; } return @ret_array; } sub exists { my $self = shift; if ( $self->count(@_) > 0 ) { return 1; } return 0; } sub update_literal { my $self = shift; my ( $s, $p, $o, $new ) = @_; my $count = $self->remove_statements( $s, $p, $o ); warn "More than one resource removed.\n" if $count > 1; return $self->assert_literal( $s, $p, $new ); } sub update_resource { my $self = shift; my ( $s, $p, $o, $new ) = @_; my $count = $self->remove_statements( $s, $p, $o ); warn "More than one resource removed.\n" if $count > 1; return $self->assert_resource( $s, $p, $new ); } sub helper2native { my $self = shift; my $in = shift; my $out = undef; return undef unless $in; if ( $in->is_resource ) { $out = $self->new_native_resource( $in->uri->as_string ); } elsif ( $in->is_blank ) { $out = $self->new_native_bnode( $in->blank_identifier ); } else { my $type_uri = undef; if ( my $uri = $in->literal_datatype ) { $type_uri = $uri->as_string; } $out = $self->new_native_literal( $in->literal_value, $in->literal_value_language, $type_uri ); } return $out; } sub count { my $self = shift; my ( $s, $p, $o ) = @_; my $retval = 0; # if no args are passed, just return the size of the model unless ( defined($s) or defined($p) or defined($o) ) { return $self->model->size; } my $stream = $self->get_enumerator( $s, $p, $o ); my $e = $self->get_enumerator(@_); while ( my $s = $e->next ) { $retval++; } return $retval; } sub include_model { my $self = shift; my $model = shift; my $stream = $model->as_stream; while ( $stream && !$stream->end ) { $self->model->add_statement( $stream->current ); $stream->next; } return 1; } 1; __END__ release-pod-syntax.t000644000765000765 45011601114550 16153 0ustar00kipkip000000000000RDF-Helper-2.0/t#!perl BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } use Test::More; eval "use Test::Pod 1.41"; plan skip_all => "Test::Pod 1.41 required for testing POD" if $@; all_pod_files_ok(); Object.pm000644000765000765 1464711601114550 16220 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/Helperpackage RDF::Helper::Object; use strict; use warnings; use Data::Dumper; use Data::UUID; use RDF::Helper::TiedPropertyHash; use vars qw( $AUTOLOAD ); use overload '""' => \&object_uri, 'eq' => \&object_uri_equals, '==' => \&object_uri_equals; # TODO: # - Handle namespaces properly =head1 NAME RDF::Helper::Object - Perl extension to use RDF property names as methods =head1 SYNOPSIS use RDF::Helper; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', namespaces => { dc => 'http://purl.org/dc/terms/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://xmlns.com/foaf/0.1/" } ); my $obj = $rdf->get_object('http://dahut.pm.org/dahut_group.rdf#bender'); $obj->rdf_type('http://xmlns.com/foaf/0.1/Person'); $obj->name("Bender"); $obj->dc_description("A description of Bender"); print $rdf->serialize(format => 'rdfxml') =head1 DESCRIPTION An object of this class is returned by the L C method, which takes a B URI as the first argument, and optionally a hash or hashref of options as the second argument. On this object, you may then call methods that correspond to property names of the properties you want to get or set. For properties in the default namespace, you may use them without any regard to prefixes, whereas with properties in other namespaces, you need to use the prefix and an underscore before the property name. This class does not make any attempt to verify whether the methods are actually valid properties within the used schema, it just blindly does what you tell it to. It is suitable for creating relatively simple RDF. To set more than one object, use an arrayref as argument, e.g. $obj->rdfs_label(['Foo', 'Bar']) will result in two triples, one for each C. =cut sub new { my $proto = shift; my %args; if ($#_ % 2) { %args = @_; } else { my $ResourceURI = shift; %args = @_; $args{ResourceURI} = $ResourceURI; } my $class = ref( $proto ) || $proto; my $self = {}; $self->{_datastore_} = $args{RDFHelper}; my $ug = new Data::UUID; my $uuid = $ug->create(); $self->{_uri_} = $args{ResourceURI} || "urn:" . $ug->to_string( $uuid ); $self->{_rdftype_} = $args{RDFType}; $self->{_defaultns_} = $args{DefaultNS} || $self->{_datastore_}->namespaces->{'#default'} || ''; if ( defined( $args{NoTie} ) and $args{NoTie} == 1 ) { $self->{_data_} = $self->{_datastore_}->property_hash( $self->{_uri_} ); $self->{_tied_} = 0; } else { unless (defined( $args{TiedHashOptions} )) { $args{TiedHashOptions}->{Deep} = 1; } $self->{_data_} = $self->{_datastore_}->tied_property_hash( $self->{_uri_}, $args{TiedHashOptions} ); $self->{_tied_} = 1; } #warn "inired with data" . Dumper( $self->{_data_} ); my $obj = bless $self, $class; # init for new objects $obj->object_init_internal; return $obj; } sub object_default_namespace { my $self = shift; if ( @_ ) { $self->{_defaultns_} = shift; } return $self->{_defaultns_}; } sub object_init_internal { my $self = shift; unless ( defined( $self->{_data_}->{'rdf:type'} ) ) { my $type = $self->object_rdfclasstype; $self->{_data_}->{'rdf:type'} = $type if ($type); } } sub object_is_tied { my $self = shift; return $self->{_tied_}; } sub object_uri { my $self = shift; return $self->{_uri_}; } sub object_uri_equals { my $self = shift; my $value = shift; return $self->object_uri eq $value; } sub object_datastore { my $self = shift; return $self->{_datastore_}; } sub object_rdfclasstype { my $self = shift; if ( $#_ > -1 and $_[0] ) { $self->{_rdftype_} = shift; } if ($self->{_rdftype_}) { return $self->{_rdftype_}; } else { return $self->{_data_}->{'rdf:type'}; } } sub object_data { my $self = shift; my $new = shift; if ( $new ) { # this is a little different since its a tied hash %{$self->{_data_}} = (); foreach my $key ( keys( %{$new} ) ) { $self->{_data_}->{$key} = $new->{$key}; } $self->object_init_internal; return 1; } # don'[t cough up the tied data, give a copy # and add the internal properties my $clone = {}; foreach my $k ( keys( %{$self->{_data_}} ) ) { $clone->{$k} = $self->{_data_}->{$k}; } $clone->{object_uri} = $self->object_uri; #warn "returning clone" . Dumper( $clone ); return $clone; } sub AUTOLOAD { # don't DESTROY return if $AUTOLOAD =~ /::DESTROY/; die "Unknown method" if $AUTOLOAD =~ /::object_.*$/; my $self = $_[0]; # fetch the attribute name $AUTOLOAD =~ /.*::([a-zA-Z0-9_]+)/; my $ns = $self->object_default_namespace; my $attr = $1; my $attr_uri = $ns . $attr; if ($attr =~ /^([^_]+)_(.+)$/) { my $nsprefix = $1; my $nsattr = $2; if ($self->{_datastore_}->namespaces->{$nsprefix}) { $ns = $self->{_datastore_}->namespaces->{$nsprefix}; $attr = $nsprefix . ':' . $nsattr; $attr_uri = $ns . $nsattr; } } if ( $attr ) { no strict 'refs'; # create the method *{$AUTOLOAD} = sub { #warn "accessor called: $attr"; my $self = shift; if ( @_ ) { my $val = shift; unless( defined( $val ) ) { delete $self->{_data_}->{$attr}; return 1; } $self->{_data_}->{$attr} = $val; return 1; } if (defined $self->{_data_}->{$attr}) { my $result = $self->{_data_}->{$attr}; my @results = ref($result) eq 'ARRAY' ? @$result : $result; @results = map {ref($_) eq 'HASH' ? $self->{_datastore_}->get_object($_->{resource_uri}) : $_ } @results; if ($#results > 0) { return wantarray ? @results : \@results; } else { return $results[0]; } } return undef; }; # now do it goto &{$AUTOLOAD}; } } 1; release-pod-coverage.t000644000765000765 76511601114550 16431 0ustar00kipkip000000000000RDF-Helper-2.0/t#!perl BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } use Test::More; eval "use Test::Pod::Coverage 1.08"; plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage" if $@; eval "use Pod::Coverage::TrustPod"; plan skip_all => "Pod::Coverage::TrustPod required for testing POD coverage" if $@; all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' }); RDFQuery.pm000644000765000765 367611601114550 16433 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/Helperpackage RDF::Helper::RDFQuery; use strict; use warnings; use vars qw( @ISA ); use RDF::Query; #$RDF::Query::debug = 1; @ISA = qw( RDF::Query ); use Data::Dumper; sub query_interface { 'RDF::Helper::RDFQuery' } sub new { my $proto = shift; my ($query_string, $query_lang, $model ) = @_; my $class = ref ($proto) || $proto; my $obj = $class->SUPER::new( $query_string, undef, undef, $query_lang ) || die "WTF?!?!?!"; $obj->{Model} = $model; return bless $obj, $class; } sub execute { my $self = shift; my $model = shift; #warn "HMM?" . Dumper($self->{Model} ); $self->{_RESULTS_} = $self->SUPER::execute( $model || $self->{Model} ) || die $self->error(); } sub selectrow_hashref { my $self = shift; unless ( defined( $self->{_RESULTS_} ) ) { $self->execute; } if ( $self->{_RESULTS_}->finished ) { $self->{_RESULTS_} = undef; return undef; } my $found_data = {}; for (my $i=0; $i < $self->{_RESULTS_}->bindings_count(); $i++) { my $node = $self->{_RESULTS_}->binding_value($i); my $value = $node->is_literal ? $node->literal_value : $node->uri->as_string; my $key = $self->{_RESULTS_}->binding_name($i); $found_data->{$key} = $value; }; $self->{_RESULTS_}->next_result; return $found_data; } sub selectrow_arrayref { my $self = shift; unless ( defined( $self->{_RESULTS_} ) ) { $self->execute; } if ( $self->{_RESULTS_}->finished ) { $self->{_RESULTS_} = undef; return undef; } my $found_data = []; for (my $i=0; $i < $self->{_RESULTS_}->bindings_count(); $i++) { my $node = $self->{_RESULTS_}->binding_value($i); my $value = $node->is_literal ? $node->literal_value : $node->uri->as_string; push @{$found_data}, $value; }; $self->{_RESULTS_}->next_result; return $found_data; } sub __node_value RDFTrine.pm000644000765000765 2146011601114550 16416 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/Helperpackage RDF::Helper::RDFTrine; use Moose; use MooseX::Aliases; use RDF::Trine; use Cwd; use RDF::Helper::Statement; use Data::Dumper; has query_interface => ( isa => 'Str', is => 'ro', alias => ['QueryInterface'], default => 'RDF::Helper::RDFQuery' ); has Model => ( isa => 'RDF::Trine::Model', accessor => 'model', lazy => 1, builder => '_build_model' ); sub _build_model { RDF::Trine::Model->new( RDF::Trine::Store::Memory->new() ); } has namespaces => ( isa => 'HashRef', is => 'ro', alias => ['Namespaces'], builder => '_build_namespaces' ); sub _build_namespaces { { rdf => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', }; } has _NS => ( isa => 'HashRef', is => 'ro', ); has ExpandQNames => ( isa => 'Bool', is => 'ro' ); with qw(RDF::Helper::API RDF::Helper::PerlConvenience); has base_uri => ( isa => 'Str', is => 'ro', alias => ['BaseURI'], default => sub { 'file:' . getcwd(); } ); sub BUILD { my ( $self, $args ) = @_; unless ( defined( $self->namespaces->{'#default'} ) ) { $self->namespaces->{'#default'} = $self->BaseURI; } my %foo = reverse %{ $self->namespaces }; $self->{_NS} = \%foo; } sub new_native_resource { my $self = shift; my $val = shift; return RDF::Trine::Node::Resource->new($val); } sub new_native_literal { my $self = shift; my ( $val, $lang, $type ) = @_; return RDF::Trine::Node::Literal->new( $val, $lang, $type ); } sub new_native_bnode { my $self = shift; my $id = shift; return RDF::Trine::Node::Blank->new($id); } sub assert_literal { my $self = shift; my ( $s, $p, $o ) = @_; my ( $subj, $pred, $obj ) = $self->normalize_triple_pattern( $s, $p, undef ); my @nodes = map { $self->helper2native($_) } ( $subj, $pred ); $obj = ref($o) ? $o->does('RDF::Helper::Node::API') ? $self->helper2native($o) : $o : $self->new_native_literal("$o"); push @nodes, $obj; $self->model->add_statement( RDF::Trine::Statement->new(@nodes) ); } sub assert_resource { my $self = shift; my ( $s, $p, $o ) = @_; my ( $subj, $pred, $obj ) = $self->normalize_triple_pattern( $s, $p, undef ); my @nodes = map { $self->helper2native($_) } ( $subj, $pred ); $obj = ref($o) ? $o->does('RDF::Helper::Node::API') ? $self->helper2native($o) : $o : $self->new_native_resource( $self->ExpandQNames ? $self->qname2resolved($o) : $o ); push @nodes, $obj; $self->model->add_statement( RDF::Trine::Statement->new(@nodes) ); } sub add_statement { my $self = shift; my $statement = shift; my @nodes = (); foreach my $type qw( subject predicate object ) { push @nodes, $self->helper2native( $statement->$type ); } $self->model->add_statement( RDF::Trine::Statement->new(@nodes) ); } sub remove_statements { my $self = shift; my $del_count = 0; my $e = $self->get_enumerator(@_); while ( my $s = $e->next ) { my @nodes = (); foreach my $type qw( subject predicate object ) { push @nodes, $self->helper2native( $s->$type ); } $self->model->remove_statement( RDF::Trine::Statement->new(@nodes) ); $del_count++; } return $del_count; } sub update_node { my $self = shift; my ( $s, $p, $o, $new ) = @_; my $update_method = undef; # first, try to grok the type form the incoming node if ( ref($new) and $new->does('RDF::Trine::Node::API') ) { if ( $new->is_literal ) { $update_method = 'update_literal'; } elsif ( $new->is_resource or $new->is_blank ) { $update_method = 'update_resource'; } } unless ($update_method) { foreach my $stmnt ( $self->get_statements( $s, $p, $o ) ) { my $obj = $stmnt->object; if ( $obj->is_literal ) { $update_method = 'update_literal'; } elsif ( $obj->is_resource or $obj->is_blank ) { $update_method = 'update_resource'; } else { warn "updating unknown node type, falling back to literal."; $update_method = 'update_literal'; } } } return $self->$update_method( $s, $p, $o, $new ); } sub get_enumerator { my $self = shift; my ( $s, $p, $o ) = @_; my ( $subj, $pred, $obj ) = $self->normalize_triple_pattern( $s, $p, $o ); my @nodes = map { $self->helper2native($_) } ( $subj, $pred, $obj ); return RDF::Helper::RDFTrine::Enumerator->new( statement => RDF::Trine::Statement->new(@nodes), model => $self->model, ); } #--------------------------------------------------------------------- # Batch inclusions #--------------------------------------------------------------------- sub include_rdfxml { my $self = shift; my %args = @_; my $p = RDF::Trine::Parser->new('rdfxml'); my $base_uri = $self->BaseURI; if ( defined( $args{filename} ) ) { $p->parse_file_into_model( $base_uri, $args{filename}, $self->model() ); } elsif ( defined( $args{xml} ) ) { $p->parse_into_model( $base_uri, $args{xml}, $self->model() ); } else { die "Missing argument. Yous must pass in an 'xml' or 'filename' argument"; } return 1; } #--------------------------------------------------------------------- # Sub-object Accessors #--------------------------------------------------------------------- sub serialize { my $self = shift; my %args = @_; $args{format} ||= 'rdfxml'; my %namespaces = %{$self->namespaces}; delete $namespaces{'#default'}; my $serializer = RDF::Trine::Serializer->new( $args{format}, namespaces => \%namespaces, base_uri => $self->base_uri ); if ( $args{filename} ) { return $serializer->serialize_model_to_file( $args{filename}, $self->model ); } else { return $serializer->serialize_model_to_string( $self->model ); } } 1; #--------------------------------------------------------------------- # RDF::Trine-specific enumerator #--------------------------------------------------------------------- package RDF::Helper::RDFTrine::Enumerator; use Moose; use RDF::Trine::Statement; use RDF::Helper::Statement; sub new { my $proto = shift; my %args = @_; my $class = ref($proto) || $proto; die "Not enough args" unless $args{model}; my $statement = delete $args{statement} || RDF::Trine::Statement->new( undef, undef, undef ); my $self = bless \%args, $class; $self->{stream} = $self->{model}->get_statements( $statement->nodes ); return $self; } sub next { my $self = shift; my $in = undef; if ( defined $self->{stream} && !$self->{stream}->end ) { $in = $self->{stream}->current; $self->{stream}->next; } unless ($in) { ; delete $self->{stream}; return undef; } my $s = undef; my @nodes = (); foreach my $type qw( subject predicate object ) { push @nodes, process_node( $in->$type ); } return RDF::Helper::Statement->new(@nodes); } sub process_node { my $in = shift; my $out = undef; if ( $in->is_resource ) { $out = RDF::Helper::Node::Resource->new( uri => $in->uri_value ); } elsif ( $in->is_blank ) { $out = RDF::Helper::Node::Blank->new( identifier => $in->blank_identifier ); } else { my $type_uri = undef; if ( my $uri = $in->literal_datatype ) { $type_uri = blessed($uri) ? $uri->can('as_string') ? $uri->as_string : confess "$uri is not something we can coerce" : $uri; } $out = RDF::Helper::Node::Literal->new( value => $in->literal_value, language => $in->literal_value_language, datatype => $type_uri ); } return $out; } 1; __END__ =head1 NAME RDF::Helper::RDFReland - RDF::Helper bridge for RDF::Trine =head1 SYNOPSIS my $model = RDF::Trine::Model->new( RDF::Trine::Storage->new( %storage_options ) ); my $rdf = RDF::Helper->new( Namespaces => \%namespaces, BaseURI => 'http://domain/NS/2004/09/03-url#' ); =head1 DESCRIPTION RDF::Helper::RDFTrine is the bridge class that connects RDF::Helper's facilites to RDF::Trine and should not be used directly. See L for method documentation =head1 AUTHOR Kip Hampton, khampton@totalcinema.com =head1 COPYRIGHT Copyright (c) 2004 Kip Hampton. =head1 LICENSE This module is free sofrware; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L L. =cut 10_deep_prop_recursive.t000644000765000765 740511601114550 17022 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use RDF::Helper; use Data::Dumper; my $xml_string = undef; { local $/= undef; $xml_string = ; } my @models; #---------------------------------------------------------------------- # RDF::Redland #---------------------------------------------------------------------- SKIP: { eval { require RDF::Redland }; skip "RDF::Redland not installed", 11 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Redland', BaseURI => 'http://example.com/' ); ok($rdf->include_rdfxml(xml => $xml_string), 'include_rdfxml'); ok($rdf->exists('http://example.com/first', 'http://example.com/value', '1'), 'test t:testa (1)'); my $first = $rdf->property_hash( 'http://example.com/first' ); is_deeply( $first, { 'next' => 'http://example.com/next', 'value' => '1', 'rdf:type' => 'http://example.com/item' }, 'first non-recursive' ); my $second = $rdf->property_hash( 'http://example.com/second' ); is_deeply( $second, { 'next' => 'http://example.com/third', 'value' => '2', 'rdf:type' => 'http://example.com/item' }, 'second non-recursive' ); my $second_deep = $rdf->deep_prophash( 'http://example.com/second' ); is_deeply( $second_deep, { 'next' => { 'next' => 'http://example.com/next', 'value' => '3', 'rdf:type' => 'http://example.com/item', }, 'value' => '2', 'rdf:type' => 'http://example.com/item' }, 'second non-recursive' ); my %expect; %expect = ( 'next' => \%expect, 'value' => '9', 'rdf:type' => 'http://example.com/item' ); my $deep = $rdf->deep_prophash( 'http://example.com/recurse' ); is_deeply( $deep, \%expect, 'deeply recursive' ); } #---------------------------------------------------------------------- # RDF::Trine #---------------------------------------------------------------------- SKIP: { eval { require RDF::Trine }; skip "RDF::Trine not installed", 11 if $@; my $rdf = RDF::Helper->new( BaseInterface => 'RDF::Trine', BaseURI => 'http://example.com/' ); ok($rdf->include_rdfxml(xml => $xml_string), 'include_rdfxml'); ok($rdf->exists('http://example.com/first', 'http://example.com/value', '1'), 'test t:testa (1)'); my $first = $rdf->property_hash( 'http://example.com/first' ); is_deeply( $first, { 'next' => 'http://example.com/next', 'value' => '1', 'rdf:type' => 'http://example.com/item' }, 'first non-recursive' ); my $second = $rdf->property_hash( 'http://example.com/second' ); is_deeply( $second, { 'next' => 'http://example.com/third', 'value' => '2', 'rdf:type' => 'http://example.com/item' }, 'second non-recursive' ); my $second_deep = $rdf->deep_prophash( 'http://example.com/second' ); is_deeply( $second_deep, { 'next' => { 'next' => 'http://example.com/next', 'value' => '3', 'rdf:type' => 'http://example.com/item', }, 'value' => '2', 'rdf:type' => 'http://example.com/item' }, 'second non-recursive' ); my %expect; %expect = ( 'next' => \%expect, 'value' => '9', 'rdf:type' => 'http://example.com/item' ); my $deep = $rdf->deep_prophash( 'http://example.com/recurse' ); is_deeply( $deep, \%expect, 'deeply recursive' ); } done_testing(); __DATA__ 1 2 3 9 Constants.pm000644000765000765 3753511601114550 16767 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/Helperpackage RDF::Helper::Constants; use strict; use warnings; use vars qw(%EXPORT_TAGS @ISA @EXPORT_OK); use Exporter; @ISA = qw (Exporter); my @FOAF_EXPR = qw(FOAF_HOMEPAGE FOAF_NAME FOAF_PASTPROJECT FOAF_TIPJAR FOAF_GIVENNAME FOAF_KNOWS FOAF_THUMBNAIL FOAF_PLAN FOAF_PRIMARYTOPIC FOAF_MYERSBRIGGS FOAF_TITLE FOAF_AIMCHATID FOAF_JABBERID FOAF_MADE FOAF_INTEREST FOAF_NICK FOAF_IMG FOAF_PERSON FOAF_CURRENTPROJECT FOAF_TOPIC FOAF_WORKPLACEHOMEPAGE FOAF_LOGO FOAF_MBOX_SHA1SUM FOAF_FIRSTNAME FOAF_GENDER FOAF_WEBLOG FOAF_MSNCHATID FOAF_IMAGE FOAF_GEEKCODE FOAF_FAMILY_NAME FOAF_WORKINFOHOMEPAGE FOAF_SCHOOLHOMEPAGE FOAF_DEPICTION FOAF_PHONE FOAF_TOPIC_INTEREST FOAF_DEPICTS FOAF_MBOX FOAF_YAHOOCHATID FOAF_MAKER FOAF_PAGE FOAF_PERSONALPROFILEDOCUMENT FOAF_SURNAME FOAF_DOCUMENT FOAF_ICQCHATID FOAF_GROUP FOAF_MEMBER FOAF_NS); my @RSS1_EXPR = qw(RSS1_NS RSS1_DESCRIPTION RSS1_TITLE RSS1_CHANNEL RSS1_LINK RSS1_IMAGE RSS1_ITEMS RSS1_ITEM RSS1_NAME RSS1_URL RSS1_TEXTINPUT); my @DC_EXPR = qw(DC_NS DC_TITLE DC_CREATOR DC_SUBJECT DC_DESCRIPTION DC_PUBLISHER DC_CONTRIBUTOR DC_DATE DC_TYPE DC_FORMAT DC_IDENTIFIER DC_SOURCE DC_LANGUAGE DC_RELATION DC_COVERAGE DC_RIGHTS); my @COMMENT_EXPR = qw(COMMENT_NS COMMENT_COMMENTS COMMENT_COMMENT COMMENT_NAME COMMENT_EMAIL COMMENT_IP COMMENT_URL COMMENT_DATE COMMENT_BODY); my @DCTERMS_EXPR = qw(DCTERMS_NS DCTERMS_ALTERNATIVE DCTERMS_ABSTRACT DCTERMS_TABLEOFCONTENTS DCTERMS_CREATED DCTERMS_VALID DCTERMS_AVAILABLE DCTERMS_ISSUED DCTERMS_MODIFIED DCTERMS_DATEACCEPTED DCTERMS_DATECOPYRIGHTED DCTERMS_DATESUBMITTED DCTERMS_EXTENT DCTERMS_MEDIUM DCTERMS_ISVERSIONOF DCTERMS_HASVERSION DCTERMS_ISREPLACEDBY DCTERMS_REPLACES DCTERMS_ISREQUIREDBY DCTERMS_REQUIRES DCTERMS_ISPARTOF DCTERMS_HASPART DCTERMS_ISREFERENCEDBY DCTERMS_REFERENCES DCTERMS_ISFORMATOF DCTERMS_HASFORMAT DCTERMS_CONFORMSTO DCTERMS_SPATIAL DCTERMS_TEMPORAL DCTERMS_AUDIENCE DCTERMS_MEDIATOR); my @RELATIONSHIP_EXPR = qw(REL_NS REL_FRIENDOF REL_ACQUAINTANCEOF REL_PARENTOF REL_SIBLINGOF REL_CHILDOF REL_GRANDCHILDOF REL_SPOUSEOF REL_ENEMYOF REL_ANTAGONISTOF REL_AMBIVALENTOF REL_LOSTCONTACTWITH REL_KNOWSOF REL_WOULDLIKETOKNOW REL_KNOWSINPASSING REL_KNOWSBYREPUTATION REL_CLOSEFRIENDOF REL_HASMET REL_WORKSWITH REL_COLLEAGUEOF REL_COLLABORATESWITH REL_EMPLOYEROF REL_EMPLOYEDBY REL_MENTOROF REL_APPRENTICETO REL_LIVESWITH REL_NEIGHBOROF REL_GRANDPARENTOF REL_LIFEPARTNEROF REL_ENGAGEDTO REL_ANCESTOROF REL_DESCENDANTOF REL_PARTICIPANTIN REL_PARTICIPANT); my @XML_EXP = qw (XML_NS XMLA_LANG XMLA_BASE); my @RDF_EXP = qw (RDF_NS RDF_RDF RDF_DESCRIPTION RDF_BAG RDF_ALT RDF_SEQ RDF_LI RDF_TYPE RDF_OBJECT RDF_SUBJECT RDF_PREDICATE RDF_STATEMENT RDF_PROPERTY RDF_LIST RDF_FIRST RDF_REST RDF_NIL RDFA_ABOUT RDFA_ABOUTEACH RDFA_ID RDFA_NODEID RDFA_BAGID RDFA_RESOURCE RDFA_PARSETYPE RDFA_TYPE RDFA_DATATYPE RDF_XMLLITERAL); my @RDFS_EXP = qw(RDFS_NS RDFS_RESOURCE RDFS_CLASS RDFS_LITERAL RDFS_CONTAINER RDFS_CONTAINER_MEMBER RDFS_IS_DEFINED_BY RDFS_MEMBER RDFS_SUBCLASS_OF RDFS_SUBPROPERTY_OF RDFS_COMMENT RDFS_LABEL RDFS_DOMAIN RDFS_RANGE RDFS_SEE_ALSO); my @ALL = (@FOAF_EXPR, @RSS1_EXPR, @DC_EXPR, @DCTERMS_EXPR, @COMMENT_EXPR, @RELATIONSHIP_EXPR, @XML_EXP, @RDF_EXP, @RDFS_EXP); %EXPORT_TAGS = (all => \@ALL, foaf => \@FOAF_EXPR, dc => \@DC_EXPR, rss1 => \@RSS1_EXPR, dcterms => \@DCTERMS_EXPR, comment => \@COMMENT_EXPR, relationship => \@RELATIONSHIP_EXPR, xml => \@XML_EXP, rdf => \@RDF_EXP, rdfs => \@RDFS_EXP, xml => \@XML_EXP); @EXPORT_OK = (@ALL, @FOAF_EXPR, @DC_EXPR, @RSS1_EXPR, @COMMENT_EXPR, @RELATIONSHIP_EXPR, @XML_EXP, @RDF_EXP, @RDFS_EXP); # XML use constant XML_NS => 'http://www.w3.org/XML/1998/namespace'; use constant XMLA_LANG => XML_NS . 'lang'; use constant XMLA_BASE => XML_NS . 'base'; # RDF use constant RDF_NS => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; use constant RDF_RDF => RDF_NS . 'RDF'; use constant RDF_DESCRIPTION => RDF_NS . 'Description'; use constant RDF_BAG => RDF_NS . 'Bag'; use constant RDF_ALT => RDF_NS . 'Alt'; use constant RDF_SEQ => RDF_NS . 'Seq'; use constant RDF_LI => RDF_NS . 'li'; use constant RDF_TYPE => RDF_NS . 'type'; use constant RDF_OBJECT => RDF_NS . 'object'; use constant RDF_SUBJECT => RDF_NS . 'subject'; use constant RDF_PREDICATE => RDF_NS . 'predicate'; use constant RDF_STATEMENT => RDF_NS . 'Statement'; use constant RDF_PROPERTY => RDF_NS . 'Property'; use constant RDF_LIST => RDF_NS . 'List'; use constant RDF_FIRST => RDF_NS . 'first'; use constant RDF_REST => RDF_NS . 'rest'; use constant RDF_NIL => RDF_NS . 'nil'; use constant RDF_VALUE => RDF_NS . 'value'; use constant RDF_XMLLITERAL => RDF_NS . 'XMLLiteral'; # RDF attributes use constant RDFA_ABOUT => RDF_NS . 'about'; use constant RDFA_ABOUTEACH => RDF_NS . 'aboutEach'; use constant RDFA_ID => RDF_NS . 'ID'; use constant RDFA_NODEID => RDF_NS . 'nodeID'; use constant RDFA_BAGID => RDF_NS . 'bagID'; use constant RDFA_RESOURCE => RDF_NS . 'resource'; use constant RDFA_PARSETYPE => RDF_NS . 'parseType'; use constant RDFA_TYPE => RDF_NS . 'type'; use constant RDFA_DATATYPE => RDF_NS . 'datatype'; # RDFS use constant RDFS_NS => 'http://www.w3.org/2000/01/rdf-schema#'; use constant RDFS_RESOURCE => RDFS_NS . 'Resource'; use constant RDFS_CLASS => RDFS_NS . 'Class'; use constant RDFS_LITERAL => RDFS_NS . 'Literal'; use constant RDFS_CONTAINER => RDFS_NS . 'Container'; use constant RDFS_CONTAINER_MEMBER => RDFS_NS . 'ContainerMembershipProperty'; use constant RDFS_IS_DEFINED_BY => RDFS_NS . 'isDefinedBy'; use constant RDFS_MEMBER => RDFS_NS . 'member'; use constant RDFS_SUBCLASS_OF => RDFS_NS . 'subClassOf'; use constant RDFS_SUBPROPERTY_OF => RDFS_NS . 'subPropertyOf'; use constant RDFS_COMMENT => RDFS_NS . 'comment'; use constant RDFS_LABEL => RDFS_NS . 'label'; use constant RDFS_DOMAIN => RDFS_NS . 'domain'; use constant RDFS_RANGE => RDFS_NS . 'range'; use constant RDFS_SEE_ALSO => RDFS_NS . 'seeAlso'; # FOAF (Friend of a Friend) use constant FOAF_NS => 'http://xmlns.com/foaf/0.1/'; use constant FOAF_HOMEPAGE => FOAF_NS . 'homepage'; use constant FOAF_NAME => FOAF_NS . 'name'; use constant FOAF_PASTPROJECT => FOAF_NS . 'pastProject'; use constant FOAF_TIPJAR => FOAF_NS . 'tipjar'; use constant FOAF_GIVENNAME => FOAF_NS . 'givenname'; use constant FOAF_KNOWS => FOAF_NS . 'knows'; use constant FOAF_THUMBNAIL => FOAF_NS . 'thumbnail'; use constant FOAF_PLAN => FOAF_NS . 'plan'; use constant FOAF_PRIMARYTOPIC => FOAF_NS . 'primaryTopic'; use constant FOAF_MYERSBRIGGS => FOAF_NS . 'myersBriggs'; use constant FOAF_TITLE => FOAF_NS . 'title'; use constant FOAF_AIMCHATID => FOAF_NS . 'aimChatID'; use constant FOAF_JABBERID => FOAF_NS . 'jabberID'; use constant FOAF_MADE => FOAF_NS . 'made'; use constant FOAF_INTEREST => FOAF_NS . 'interest'; use constant FOAF_NICK => FOAF_NS . 'nick'; use constant FOAF_IMG => FOAF_NS . 'img'; use constant FOAF_PERSON => FOAF_NS . 'Person'; use constant FOAF_CURRENTPROJECT => FOAF_NS . 'currentProject'; use constant FOAF_TOPIC => FOAF_NS . 'topic'; use constant FOAF_WORKPLACEHOMEPAGE => FOAF_NS . 'workplaceHomepage'; use constant FOAF_LOGO => FOAF_NS . 'logo'; use constant FOAF_MBOX_SHA1SUM => FOAF_NS . 'mbox_sha1sum'; use constant FOAF_FIRSTNAME => FOAF_NS . 'firstName'; use constant FOAF_GENDER => FOAF_NS . 'gender'; use constant FOAF_WEBLOG => FOAF_NS . 'weblog'; use constant FOAF_MSNCHATID => FOAF_NS . 'msnChatID'; use constant FOAF_IMAGE => FOAF_NS . 'Image'; use constant FOAF_GEEKCODE => FOAF_NS . 'geekcode'; use constant FOAF_FAMILY_NAME => FOAF_NS . 'family_name'; use constant FOAF_WORKINFOHOMEPAGE => FOAF_NS . 'workInfoHomepage'; use constant FOAF_SCHOOLHOMEPAGE => FOAF_NS . 'schoolHomepage'; use constant FOAF_DEPICTION => FOAF_NS . 'depiction'; use constant FOAF_PHONE => FOAF_NS . 'phone'; use constant FOAF_TOPIC_INTEREST => FOAF_NS . 'topic_interest'; use constant FOAF_DEPICTS => FOAF_NS . 'depicts'; use constant FOAF_MBOX => FOAF_NS . 'mbox'; use constant FOAF_YAHOOCHATID => FOAF_NS . 'yahooChatID'; use constant FOAF_MAKER => FOAF_NS . 'maker'; use constant FOAF_PAGE => FOAF_NS . 'page'; use constant FOAF_PERSONALPROFILEDOCUMENT => FOAF_NS . 'PersonalProfileDocument '; use constant FOAF_SURNAME => FOAF_NS . 'surname'; use constant FOAF_DOCUMENT => FOAF_NS . 'Document'; use constant FOAF_ICQCHATID => FOAF_NS . 'icqChatID'; # Group stuff use constant FOAF_GROUP => FOAF_NS . 'Group'; use constant FOAF_MEMBER => FOAF_NS . 'member'; # Relationship extension for FOAF use constant REL_NS => 'http://purl.org/vocab/relationship/'; use constant REL_FRIENDOF => REL_NS . 'friendOf'; use constant REL_ACQUAINTANCEOF => REL_NS . 'acquaintanceOf'; use constant REL_PARENTOF => REL_NS . 'parentOf'; use constant REL_SIBLINGOF => REL_NS . 'siblingOf'; use constant REL_CHILDOF => REL_NS . 'childOf'; use constant REL_GRANDCHILDOF => REL_NS . 'grandchildOf'; use constant REL_SPOUSEOF => REL_NS . 'spouseOf'; use constant REL_ENEMYOF => REL_NS . 'enemyOf'; use constant REL_ANTAGONISTOF => REL_NS . 'antagonistOf'; use constant REL_AMBIVALENTOF => REL_NS . 'ambivalentOf'; use constant REL_LOSTCONTACTWITH => REL_NS . 'lostContactWith'; use constant REL_KNOWSOF => REL_NS . 'knowsOf'; use constant REL_WOULDLIKETOKNOW => REL_NS . 'wouldLikeToKnow'; use constant REL_KNOWSINPASSING => REL_NS . 'knowsInPassing'; use constant REL_KNOWSBYREPUTATION => REL_NS . 'knowsByReputation'; use constant REL_CLOSEFRIENDOF => REL_NS . 'closeFriendOf'; use constant REL_HASMET => REL_NS . 'hasMet'; use constant REL_WORKSWITH => REL_NS . 'worksWith'; use constant REL_COLLEAGUEOF => REL_NS . 'colleagueOf'; use constant REL_COLLABORATESWITH => REL_NS . 'collaboratesWith'; use constant REL_EMPLOYEROF => REL_NS . 'employerOf'; use constant REL_EMPLOYEDBY => REL_NS . 'employedBy'; use constant REL_MENTOROF => REL_NS . 'mentorOf'; use constant REL_APPRENTICETO => REL_NS . 'apprenticeTo'; use constant REL_LIVESWITH => REL_NS . 'livesWith'; use constant REL_NEIGHBOROF => REL_NS . 'neighborOf'; use constant REL_GRANDPARENTOF => REL_NS . 'grandparentOf'; use constant REL_LIFEPARTNEROF => REL_NS . 'lifePartnerOf'; use constant REL_ENGAGEDTO => REL_NS . 'engagedTo'; use constant REL_ANCESTOROF => REL_NS . 'ancestorOf'; use constant REL_DESCENDANTOF => REL_NS . 'descendantOf'; use constant REL_PARTICIPANTIN => REL_NS . 'participantIn'; use constant REL_PARTICIPANT => REL_NS . 'participant'; # RSS 1.0 use constant RSS1_NS => 'http://purl.org/rss/1.0/'; use constant RSS1_DESCRIPTION => RSS1_NS . 'description'; use constant RSS1_TITLE => RSS1_NS . 'title'; use constant RSS1_CHANNEL => RSS1_NS . 'channel'; use constant RSS1_LINK => RSS1_NS . 'link'; use constant RSS1_IMAGE => RSS1_NS . 'image'; use constant RSS1_ITEMS => RSS1_NS . 'items'; use constant RSS1_ITEM => RSS1_NS . 'item'; use constant RSS1_NAME => RSS1_NS . 'name'; use constant RSS1_URL => RSS1_NS . 'url'; use constant RSS1_TEXTINPUT => RSS1_NS . 'textinput'; # Dublin Core use constant DC_NS => 'http://purl.org/dc/elements/1.1/'; use constant DC_TITLE => DC_NS . 'title'; use constant DC_CREATOR => DC_NS . 'creator'; use constant DC_SUBJECT => DC_NS . 'subject'; use constant DC_DESCRIPTION => DC_NS . 'description'; use constant DC_PUBLISHER => DC_NS . 'publisher'; use constant DC_CONTRIBUTOR => DC_NS . 'contributor'; use constant DC_DATE => DC_NS . 'date'; use constant DC_TYPE => DC_NS . 'type'; use constant DC_FORMAT => DC_NS . 'format'; use constant DC_IDENTIFIER => DC_NS . 'identifier'; use constant DC_SOURCE => DC_NS . 'source'; use constant DC_LANGUAGE => DC_NS . 'language'; use constant DC_RELATION => DC_NS . 'relation'; use constant DC_COVERAGE => DC_NS . 'coverage'; use constant DC_RIGHTS => DC_NS . 'rights'; # Dublin Core Terms use constant DCTERMS_NS => 'http://purl.org/dc/terms/'; use constant DCTERMS_ALTERNATIVE => DCTERMS_NS . 'alternative'; use constant DCTERMS_ABSTRACT => DCTERMS_NS . 'abstract'; use constant DCTERMS_TABLEOFCONTENTS => DCTERMS_NS . 'tableOfContents'; use constant DCTERMS_CREATED => DCTERMS_NS . 'created'; use constant DCTERMS_VALID => DCTERMS_NS . 'valid'; use constant DCTERMS_AVAILABLE => DCTERMS_NS . 'available'; use constant DCTERMS_ISSUED => DCTERMS_NS . 'issued'; use constant DCTERMS_MODIFIED => DCTERMS_NS . 'modified'; use constant DCTERMS_DATEACCEPTED => DCTERMS_NS . 'dateAccepted'; use constant DCTERMS_DATECOPYRIGHTED => DCTERMS_NS . 'dateCopyrighted'; use constant DCTERMS_DATESUBMITTED => DCTERMS_NS . 'dateSubmitted'; use constant DCTERMS_EXTENT => DCTERMS_NS . 'extent'; use constant DCTERMS_MEDIUM => DCTERMS_NS . 'medium'; use constant DCTERMS_ISVERSIONOF => DCTERMS_NS . 'isVersionOf'; use constant DCTERMS_HASVERSION => DCTERMS_NS . 'hasVersion'; use constant DCTERMS_ISREPLACEDBY => DCTERMS_NS . 'isReplacedBy'; use constant DCTERMS_REPLACES => DCTERMS_NS . 'replaces'; use constant DCTERMS_ISREQUIREDBY => DCTERMS_NS . 'isRequiredBy'; use constant DCTERMS_REQUIRES => DCTERMS_NS . 'requires'; use constant DCTERMS_ISPARTOF => DCTERMS_NS . 'isPartOf'; use constant DCTERMS_HASPART => DCTERMS_NS . 'hasPart'; use constant DCTERMS_ISREFERENCEDBY => DCTERMS_NS . 'isReferencedBy'; use constant DCTERMS_REFERENCES => DCTERMS_NS . 'references'; use constant DCTERMS_ISFORMATOF => DCTERMS_NS . 'isFormatOf'; use constant DCTERMS_HASFORMAT => DCTERMS_NS . 'hasFormat'; use constant DCTERMS_CONFORMSTO => DCTERMS_NS . 'conformsTo'; use constant DCTERMS_SPATIAL => DCTERMS_NS . 'spatial'; use constant DCTERMS_TEMPORAL => DCTERMS_NS . 'temporal'; use constant DCTERMS_AUDIENCE => DCTERMS_NS . 'audience'; use constant DCTERMS_MEDIATOR => DCTERMS_NS . 'mediator'; # # RSS Comments Extention use constant COMMENT_NS => 'http://purl.org/net/rssmodules/blogcomments/'; use constant COMMENT_COMMENTS => COMMENT_NS . 'comments'; use constant COMMENT_COMMENT => COMMENT_NS . 'comment'; use constant COMMENT_NAME => COMMENT_NS . 'name'; use constant COMMENT_EMAIL => COMMENT_NS . 'email'; use constant COMMENT_IP => COMMENT_NS . 'ip'; use constant COMMENT_URL => COMMENT_NS . 'url'; use constant COMMENT_DATE => COMMENT_NS . 'date'; use constant COMMENT_BODY => COMMENT_NS . 'body'; # RSS Syndication Module use constant SYN_NS => 'http://purl.org/rss/1.0/modules/syndication/'; use constant SYN_UPDATEPERIOD => SYN_NS . 'updatePeriod'; use constant SYN_UPDATEFREQUENCY => SYN_NS . 'updateFrequency'; use constant SYN_UPDATEBASE => SYN_NS . 'updateBase'; 1; Statement.pm000644000765000765 332211601114550 16722 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/Helperpackage RDF::Helper::Statement; use Moose; use Moose::Util::TypeConstraints; class_type 'RDF::Helper::Node::Resource'; class_type 'RDF::Helper::Node::Literal'; class_type 'RDF::Helper::Node::Blank'; my $ValidNode = subtype as 'RDF::Helper::Node::Resource|RDF::Helper::Node::Literal|RDF::Helper::Node::Blank'; has [qw(subject predicate object)] => ( isa => $ValidNode, is => 'ro', required => 1 ); sub BUILDARGS { my $class = shift; my ( $s, $p, $o ) = @_; return { subject => $s, predicate => $p, object => $o }; } package RDF::Helper::Node::API; use Moose::Role; requires 'as_string'; sub is_resource { 0 } sub is_literal { 0 } sub is_blank { 0 } package RDF::Helper::Node::Resource; use Moose; use URI; with qw(RDF::Helper::Node::API); has uri => ( isa => 'Str', reader => 'uri_value', required => 1, ); sub uri { URI->new( shift->uri_value ) } sub is_resource { 1 } sub as_string { shift->uri_value } package RDF::Helper::Node::Literal; use Moose; with qw(RDF::Helper::Node::API); has value => ( isa => 'Str', reader => 'literal_value', required => 1, ); has datatype => ( is => 'ro', predicate => 'has_datatype' ); has language => ( reader => 'literal_value_language', ); sub literal_datatype { my $self = shift; return unless defined $self->has_datatype; return URI->new( $self->datatype ); } sub is_literal { 1 } sub as_string { shift->literal_value } package RDF::Helper::Node::Blank; use Moose; with qw(RDF::Helper::Node::API); has identifier => ( isa => 'Str', reader => 'blank_identifier', required => 1 ); sub is_blank { 1 } sub as_string { shift->blank_identifier } 1 __END__RDFRedland.pm000644000765000765 2353611601114550 16714 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/Helperpackage RDF::Helper::RDFRedland; use Moose; use MooseX::Aliases; use RDF::Redland; use RDF::Helper::RDFRedland::Query; use Cwd; use RDF::Helper::Statement; has query_interface => ( isa => 'Str', is => 'ro', default => 'RDF::Helper::RDFRedland::Query' ); has Model => ( isa => 'RDF::Redland::Model', accessor => 'model', lazy => 1, builder => '_build_model' ); sub _build_model { RDF::Redland::Model->new( RDF::Redland::Storage->new( "hashes", "temp", "new='yes',hash-type='memory'" ), "" ); } has namespaces => ( isa => 'HashRef', is => 'ro', alias => ['Namespaces'], builder => '_build_namespaces' ); sub _build_namespaces { { rdf => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', }; } has _NS => ( isa => 'HashRef', is => 'ro', ); has ExpandQNames => ( isa => 'Bool', is => 'ro' ); with qw(RDF::Helper::API RDF::Helper::PerlConvenience ); has base_uri => ( isa => 'Str', is => 'ro', alias => ['BaseURI'], default => sub { 'file:' . getcwd(); } ); sub BUILD { my ( $self, $args ) = @_; unless ( defined( $self->namespaces->{'#default'} ) ) { $self->namespaces->{'#default'} = $self->BaseURI; } my %foo = reverse %{ $self->namespaces }; $self->{_NS} = \%foo; } sub new_native_resource { my $self = shift; my $val = shift; return RDF::Redland::Node->new( RDF::Redland::URI->new($val) ); } sub new_native_literal { my $self = shift; my ( $val, $lang, $type ) = @_; if ( defined($type) and !ref($type) ) { $type = RDF::Redland::URI->new($type); } return RDF::Redland::Node->new_literal( "$val", $type, $lang ); } sub new_native_bnode { my $self = shift; my $id = shift; return RDF::Redland::Node->new_from_blank_identifier($id); } sub assert_literal { my $self = shift; my ( $s, $p, $o ) = @_; my ( $subj, $pred, $obj ) = $self->normalize_triple_pattern( $s, $p, undef ); my @nodes = map { $self->helper2native($_) } ( $subj, $pred ); $obj = ref($o) ? $o->does('RDF::Helper::Node::API') ? $self->helper2native($o) : $o : $self->new_native_literal("$o"); push @nodes, $obj; $self->model->add_statement(@nodes); } sub assert_resource { my $self = shift; my ( $s, $p, $o ) = @_; my ( $subj, $pred, $obj ) = $self->normalize_triple_pattern( $s, $p, undef ); my @nodes = map { $self->helper2native($_) } ( $subj, $pred ); $obj = ref($o) ? $o->does('RDF::Helper::Node::API') ? $self->helper2native($o) : $o : $self->new_native_resource( $self->ExpandQNames ? $self->qname2resolved($o) : $o ); push @nodes, $obj; $self->model->add_statement(@nodes); } sub add_statement { my $self = shift; my $statement = shift; my @nodes = (); foreach my $type qw( subject predicate object ) { push @nodes, $self->helper2native( $statement->$type ); } $self->model->add_statement(@nodes); } sub remove_statements { my $self = shift; my $del_count = 0; my $e = $self->get_enumerator(@_); while ( my $s = $e->next ) { my @nodes = (); foreach my $type qw( subject predicate object ) { push @nodes, $self->helper2native( $s->$type ); } $self->model->remove_statement( RDF::Redland::Statement->new(@nodes) ); $del_count++; } return $del_count; } sub update_node { my $self = shift; my ( $s, $p, $o, $new ) = @_; my $update_method = undef; # first, try to grok the type form the incoming node if ( ref($new) and $new->does('RDF::Redland::Node::API') ) { if ( $new->is_literal ) { $update_method = 'update_literal'; } elsif ( $new->is_resource or $new->is_blank ) { $update_method = 'update_resource'; } } unless ($update_method) { foreach my $stmnt ( $self->get_statements( $s, $p, $o ) ) { my $obj = $stmnt->object; if ( $obj->is_literal ) { $update_method = 'update_literal'; } elsif ( $obj->is_resource or $obj->is_blank ) { $update_method = 'update_resource'; } else { warn "updating unknown node type, falling back to literal."; $update_method = 'update_literal'; } } } return $self->$update_method( $s, $p, $o, $new ); } sub get_enumerator { my $self = shift; my ( $s, $p, $o ) = @_; my ( $subj, $pred, $obj ) = $self->normalize_triple_pattern( $s, $p, $o ); my @nodes = map { $self->helper2native($_) } ( $subj, $pred, $obj ); return RDF::Helper::RDFRedland::Enumerator->new( statement => RDF::Redland::Statement->new(@nodes), model => $self->model, ); } #--------------------------------------------------------------------- # Batch inclusions #--------------------------------------------------------------------- sub include_rdfxml { my $self = shift; my %args = @_; my $p = RDF::Redland::Parser->new('rdfxml'); my $base_uri = RDF::Redland::URI->new( $self->BaseURI ); if ( defined( $args{filename} ) ) { my $file = $args{filename}; if ( $file !~ /^file:/ ) { $file = 'file:' . $file; } my $source_uri = RDF::Redland::URI->new($file); $p->parse_into_model( $source_uri, $base_uri, $self->model() ); } elsif ( defined( $args{xml} ) ) { $p->parse_string_into_model( $args{xml}, $base_uri, $self->model() ); } else { confess "Missing argument. Yous must pass in an 'xml' or 'filename' argument"; } return 1; } #--------------------------------------------------------------------- # Sub-object Accessors #--------------------------------------------------------------------- sub serialize { my $self = shift; my %args = @_; $args{format} ||= 'rdfxml-abbrev'; my $serializer = undef; # Trix is handled differently if ( $args{format} eq 'trix' ) { eval "require RDF::Trix::Serializer::Redland"; $serializer = RDF::Trix::Serializer::Redland->new( Models => [ [ $self->model ] ] ); # XXX: Cleanup on aisle 5... my $trix = $serializer->as_string(); if ( $args{filename} ) { open( TRIX, $args{filename} ) || die "could not open file '$args{filename}' for writing: $! \n"; print TRIX $trix; close TRIX; return 1; } return $trix; } $serializer = RDF::Redland::Serializer->new( $args{format} ); if ( $serializer->can("set_namespace") ) { while ( my ( $prefix, $uri ) = each %{ $self->namespaces } ) { next if ( $prefix eq 'rdf' or $prefix eq '#default' ); $serializer->set_namespace( $prefix, RDF::Redland::URI->new($uri) ); } } if ( $args{filename} ) { return $serializer->serialize_model_to_file( $args{filename}, RDF::Redland::URI->new( $self->BaseURI ), $self->model ); } else { return $serializer->serialize_model_to_string( RDF::Redland::URI->new( $self->BaseURI ), $self->model ); } } #--------------------------------------------------------------------- # Redland-specific enumerator #--------------------------------------------------------------------- package RDF::Helper::RDFRedland::Enumerator; use strict; use warnings; use RDF::Redland::Statement; use RDF::Helper::Statement; sub new { my $proto = shift; my %args = @_; my $class = ref($proto) || $proto; die "Not enough args" unless $args{model}; my $statement = delete $args{statement} || RDF::Redland::Statement->new( undef, undef, undef ); my $self = bless \%args, $class; $self->{stream} = $self->{model}->find_statements($statement); return $self; } ## sub next { my $self = shift; my $in = undef; if ( defined $self->{stream} && !$self->{stream}->end ) { $in = $self->{stream}->current; $self->{stream}->next; } unless ($in) { ; delete $self->{stream}; return undef; } my $s = undef; my @nodes = (); foreach my $type qw( subject predicate object ) { push @nodes, process_node( $in->$type ); } return RDF::Helper::Statement->new(@nodes); } sub process_node { my $in = shift; my $out = undef; if ( $in->is_resource ) { $out = RDF::Helper::Node::Resource->new( uri => $in->uri->as_string ); } elsif ( $in->is_blank ) { $out = RDF::Helper::Node::Blank->new( identifier => $in->blank_identifier ); } else { my $type_uri = undef; if ( my $uri = $in->literal_datatype ) { $type_uri = $uri->as_string; } $out = RDF::Helper::Node::Literal->new( value => $in->literal_value, language => $in->literal_value_language, datatype => $type_uri ); } return $out; } 1; __END__ =head1 NAME RDF::Helper::RDFReland - RDF::Helper bridge for RDF::Redland =head1 SYNOPSIS my $model = RDF::Redland::Model->new( RDF::Redland::Storage->new( %storage_options ) ); my $rdf = RDF::Helper->new( Namespaces => \%namespaces, BaseURI => 'http://domain/NS/2004/09/03-url#' ); =head1 DESCRIPTION RDF::Helper::RDFRedland is the bridge class that connects RDF::Helper's facilites to RDF::Redland and should not be used directly. See L for method documentation =head1 AUTHOR Kip Hampton, khampton@totalcinema.com =head1 COPYRIGHT Copyright (c) 2004 Kip Hampton. =head1 LICENSE This module is free sofrware; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L L. =cut 11_serialized_namespaces.t000644000765000765 321411601114550 17303 0ustar00kipkip000000000000RDF-Helper-2.0/tuse Test::More; use strict; use warnings; use RDF::Helper; #---------------------------------------------------------------------- # RDF::Redland #---------------------------------------------------------------------- SKIP: { eval { require RDF::Redland }; skip "RDF::Redland not installed", 5 if $@; test( 'RDF::Redland' ); } #---------------------------------------------------------------------- # RDF::Trine #---------------------------------------------------------------------- SKIP: { eval { require RDF::Trine }; skip "RDF::Trine not installed", 5 if $@; test( 'RDF::Trine' ); } done_testing(); # # Test Methods # sub test { my $class = shift; my $rdf = RDF::Helper->new( BaseInterface => $class, namespaces => { dc => 'http://purl.org/dc/terms/', rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", '#default' => "http://xmlns.com/foaf/0.1/" } ); my $obj = $rdf->get_object('http://dahut.pm.org/dahut_group.rdf#bender'); $obj->rdf_type('http://xmlns.com/foaf/0.1/Person'); $obj->name("Bender"); $obj->dc_description("A description of Bender"); my $xmlstring = $rdf->serialize(format => 'rdfxml'); like($xmlstring, qr|xmlns:dc="http://purl.org/dc/terms/"|, 'RDF/XML DC prefix declaration'); like($xmlstring, qr||, 'RDF/XML DC element present'); my $turtlestring = $rdf->serialize(format => 'turtle'); like($turtlestring, qr|\@prefix dc: .|, 'Turtle DC prefix declaration'); like($turtlestring, qr|dc:description|, 'Turtle DC property present'); like($turtlestring, qr|a |, 'Turtle type present'); } PerlConvenience.pm000644000765000765 2006011601114550 20053 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/Helperpackage RDF::Helper::PerlConvenience; use Moose::Role; sub get_perl_type { my $self = shift; my $wtf = shift; my $type = ref( $wtf ); if ( $type ) { if ( $type eq 'ARRAY' or $type eq 'HASH' or $type eq 'SCALAR') { return $type; } else { # we were passed an object, yuk. # props to barrie slaymaker for the tip here... mine was much fuglier. ;-) if ( UNIVERSAL::isa( $wtf, "HASH" ) ) { return 'HASH'; } elsif ( UNIVERSAL::isa( $wtf, "ARRAY" ) ) { return 'ARRAY'; } elsif ( UNIVERSAL::isa( $wtf, "SCALAR" ) ) { return 'SCALAR'; } else { return $type; } } } else { if ( $wtf =~ /^(http|file|ftp|urn|shttp):/ ) { #warn "type for $wtf is resource"; return 'resource'; } else { return 'literal'; } } } sub hashlist_from_statement { my $self = shift; my ($s, $p, $o) = @_; my @lookup_subjects = (); my @found_data = (); foreach my $stmnt ( $self->get_statements( $s, $p, $o ) ) { my $subj = $stmnt->subject; my $key = $subj->is_resource ? $subj->uri->as_string : $subj->blank_identifier; push @found_data, [$key, $self->property_hash( $subj )]; } return @found_data; } sub property_hash { my $self = shift; my $resource = shift; my %found_data = (); my %seen_keys = (); $resource ||= $self->new_bnode; foreach my $t ( $self->get_triples( $resource ) ) { my $key = $self->resolved2prefixed( $t->[1] ) || $t->[1]; if ( $seen_keys{$key} ) { if ( ref $found_data{$key} eq 'ARRAY' ) { push @{$found_data{$key}}, $t->[2]; } else { my $was = $found_data{$key}; $found_data{$key} = [$was, $t->[2]]; } } else { $found_data{$key} = $t->[2]; } $seen_keys{$key} = 1; } return \%found_data; } sub deep_prophash { my $self = shift; my $resource = shift; my $seen_nodes = shift || {}; my %found_data = (); $seen_nodes->{ $resource } ||= \%found_data; my %seen_keys = (); foreach my $stmnt ( $self->get_statements($resource, undef, undef)) { my $pred = $stmnt->predicate->uri->as_string, my $obj = $stmnt->object; my $value; if ( $obj->is_literal ) { $value = $obj->literal_value; } elsif ( $obj->is_resource ) { # if nothing else in the model points to this resource # just give the URI as a literal string if ( $self->count( $obj, undef, undef) == 0 ) { $value = $obj->uri->as_string; } # otherwise, recurse else { if (exists $seen_nodes->{ $obj->uri->as_string }) { $value = $seen_nodes->{ $obj->uri->as_string }; } else { $value = $self->deep_prophash( $obj, $seen_nodes ); } } } else { if (exists $seen_nodes->{ $obj->blank_identifier }) { $value = $seen_nodes->{ $obj->blank_identifier }; } else { $value = $self->deep_prophash( $obj, $seen_nodes ); } } my $key = $self->resolved2prefixed( $pred ) || $pred; if ( $seen_keys{$key} ) { if ( ref $found_data{$key} eq 'ARRAY' ) { push @{$found_data{$key}}, $value; } else { my $was = $found_data{$key}; $found_data{$key} = [$was, $value]; } } else { $found_data{$key} = $value; } $seen_keys{$key} = 1; } return \%found_data; } sub tied_property_hash { my $self = shift; my $lookup_uri = shift; my $options = shift; eval "require RDF::Helper::TiedPropertyHash"; return RDF::Helper::TiedPropertyHash->new( Helper => $self, ResourceURI => $lookup_uri, Options => $options); } sub arrayref2rdf { my $self = shift; my $array = shift; my $subject = shift; my $predicate = shift; $subject ||= $self->new_bnode; foreach my $value (@{$array}) { my $type = $self->get_perl_type( $value ); if ( $type eq 'HASH' ) { my $obj = $self->new_bnode; $self->assert_resource( $subject, $predicate, $obj ); $self->hashref2rdf( $value, $obj ); } elsif ( $type eq 'ARRAY' ) { die "Lists of lists (arrays of arrays) are not compatible with storage via RDF"; } elsif ( $type eq 'SCALAR' ) { $self->assert_resource( $subject, $predicate, $$value ); } else { $self->assert_literal( $subject, $predicate, $value ); } } } sub resourcelist { my $self = shift; my ( $p, $o ) = @_; my %seen_resources = (); my @retval = (); foreach my $stmnt ( $self->get_statements( undef, $p, $o ) ) { my $s = $stmnt->subject->is_resource ? $stmnt->subject->uri->as_string : $stmnt->subject->blank_identifier; next if defined $seen_resources{$s}; push @retval, $s; $seen_resources{$s} = 1; } return @retval; } sub resolved2prefixed { my $self = shift; my $lookup = shift; foreach my $uri ( sort {length $b <=> length $a} (keys( %{$self->_NS} )) ) { #warn "URI $uri LOOKUP $lookup "; if ( $lookup =~ /^($uri)(.*)$/ ) { my $prefix = $self->_NS->{$uri}; return $2 if $prefix eq '#default'; return $prefix . ':' . $2; } } return undef; } sub hashref2rdf { my $self = shift; my $hash = shift; my $subject = shift; $subject ||= $hash->{"rdf:about"}; $subject ||= $self->new_bnode; unless ( ref( $subject ) ) { $subject = $self->new_resource( $subject ); } foreach my $key (keys( %{$hash} )) { next if ($key eq 'rdf:about'); my $value = $hash->{$key}; my $type = $self->get_perl_type( $value ); my $predicate = $self->prefixed2resolved( $key ); if ( $type eq 'HASH' ) { my $obj = $value->{'rdf:about'} || $self->new_bnode; $self->assert_resource( $subject, $predicate, $obj ); $self->hashref2rdf( $value, $obj ); } elsif ( $type eq 'ARRAY' ) { $self->arrayref2rdf( $value, $subject, $predicate ); } # XXX Nacho: This part was buggy, but it's been ages since # I ran into this problem. elsif ( $type eq 'SCALAR' ) { $self->assert_resource( $subject, $predicate, $$value ); } elsif ( $type eq 'resource' ) { $self->assert_resource( $subject, $predicate, $value ); } else { $self->assert_literal( $subject, $predicate, $value ); } } } sub prefixed2resolved { my $self = shift; my $lookup = shift; my ( $name, $prefix ) = reverse ( split /:/, $lookup ); my $uri; if ( $prefix ) { if ( defined $self->namespaces->{$prefix} ) { $uri = $self->namespaces->{$prefix}; } else { warn "Unknown prefix: $prefix, in QName $lookup. Falling back to the default predicate URI"; } } $uri ||= $self->namespaces->{'#default'}; return $uri . $name; } sub qname2resolved { my $self = shift; my $lookup = shift; my ( $prefix, $name ) = $lookup =~ /^([^:]+):(.+)$/; return $lookup unless ( defined $prefix and exists($self->namespaces->{$prefix})); return $self->namespaces->{$prefix} . $name; } 1; TiedPropertyHash.pm000644000765000765 1147111601114550 20240 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/Helperpackage RDF::Helper::TiedPropertyHash; use strict; use warnings; require Tie::Hash; use Data::Dumper; use vars qw( @ISA ); @ISA = qw( Tie::ExtraHash ); use overload '""' => \&overload_uri, 'eq' => \&overload_uri_equals, '==' => \&overload_uri_equals; sub new { my $proto = shift; my %args = @_; my %data; unless ( $args{Helper} ) { eval "require RDF::Helper"; $args{Helper} = RDF::Helper->new( BaseInterface => 'RDF::Redland' ); } tie %data, 'RDF::Helper::TiedPropertyHash', $args{Helper}, $args{ResourceURI}, $args{Options}; return \%data; } #---------------------------------------- # here, $self is an array ref with the following indices # 0 -- a ref to the hash we're operation on # 1 -- a ref to the RDF::Helper object that suppies the backend # 2 -- The subject URI associated with this set of properties. #---------------------------------------- sub TIEHASH { my $class = shift; my ( $helper, $lookup_uri, $options ) = @_; $options ||= { Deep => 0 }; my $data = {}; unless ( defined $helper ) { eval "require RDF::Helper"; $helper = RDF::Helper->new( BaseInterface => 'RDF::Redland' ); } if ( defined $lookup_uri ) { foreach my $stmnt ( $helper->get_statements( $lookup_uri, undef, undef ) ) { my $predicate = $stmnt->predicate->uri->as_string; my $prop_key = $helper->resolved2prefixed( $predicate ); push @{$data->{$prop_key}}, $stmnt->object; } } else { $lookup_uri = $helper->new_bnode; } bless [$data, $helper, $lookup_uri, $options], $class; } sub DELETE { my $self = shift; my $key = shift; my $prop_uri = $self->[1]->prefixed2resolved( $key ); $self->[1]->remove_statements( $self->[2], $prop_uri ); my @results = map { $self->_node_value($_) } @{$self->[0]->{$key}}; delete $self->[0]->{$key}; if ($#results > 0) { return \@results; } else { return $results[0]; } } sub CLEAR { #warn "clear called!!!!"; my $self = shift; my $key = shift; $self->[1]->remove_statements( $self->[2] ); %{$self->[0]} = (); } sub FETCH { my $self = shift; my $key = shift; # Return the resource URI of this hash if requested if ($key eq 'resource_uri') { return $self->[2]; } # Otherwise, return the property value if (defined($self->[0]->{$key}) and ref($self->[0]->{$key}) eq 'ARRAY' and scalar(@{$self->[0]->{$key}}) > 0) { my @results = (); foreach my $obj (@{$self->[0]->{$key}}) { # Find the node's value my $val = $self->_node_value($obj); # If it's a resource, make it an object if ($self->[3]->{Deep} and ($obj->is_resource or $obj->is_blank)) { $val = $self->[1]->tied_property_hash( $val ); } push @results, $val; } if ($#results > 0) { return \@results; } else { return $results[0]; } } return undef; } sub STORE { my $self = shift; my ($key, $value) = @_; my $val_type = $self->[1]->get_perl_type( $value ); my $prop_uri = $self->[1]->prefixed2resolved( $key ); my $old_val = $self->[0]->{$key}; if ( defined $old_val and ref($old_val) eq 'ARRAY' and scalar(@$old_val) > 0) { $self->[1]->remove_statements( $self->[2], $prop_uri ); } if ( $val_type eq 'literal' ) { $self->[1]->assert_literal( $self->[2], $prop_uri, $value ) } elsif ( $val_type eq 'resource' or $val_type eq 'SCALAR') { $self->[1]->assert_resource( $self->[2], $prop_uri, $value ) } elsif ( $val_type eq 'ARRAY' ) { foreach my $v ( @{$value} ) { # this is dubious my $type = $self->[1]->get_perl_type( $v ); if ( $type eq 'resource' ) { $self->[1]->assert_resource( $self->[2], $prop_uri, $v ); } else { $self->[1]->assert_literal( $self->[2], $prop_uri, $v ); } } } # get smarter here else { die "I do not know how to store value of reference type '$val_type' as RDF, please contact the module author"; } $self->[0]->{$key} = [ map { $_->object } $self->[1]->get_statements( $self->[2], $prop_uri, undef ) ]; } sub _node_value { my $self = shift; my $obj = shift; return $obj unless (ref($obj)); if ($obj->is_literal) { return $obj->literal_value; } elsif ($obj->is_resource) { return $obj->uri->as_string; } else { return $obj->as_string; } } sub overload_uri { my $self = shift; return $self->[2]; } sub overload_uri_equals { my $self = shift; my $value = shift; return $self->[2] eq $value; } 1; RDFRedland000755000765000765 011601114550 16166 5ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/HelperQuery.pm000644000765000765 720111601114550 17770 0ustar00kipkip000000000000RDF-Helper-2.0/lib/RDF/Helper/RDFRedlandpackage RDF::Helper::RDFRedland::Query; use Moose; use RDF::Redland::Query; has [qw(query_string query_lang)] => ( isa => 'Str', is => 'ro', required => 1 ); has model => ( is => 'ro', required => 1 ); has query => ( isa => 'RDF::Redland::Query', is => 'ro', lazy => 1, builder => '_build_query', handles => { _execute => 'execute' } ); sub _build_query { my $self = shift; RDF::Redland::Query->new( $self->query_string, undef, undef, $self->query_lang ); } has results => ( is => 'ro', lazy => 1, predicate => 'has_results', clearer => '_clear_results', default => sub { shift->execute }, ); sub execute { my ($self, $model) = @_; $self->_execute( $model || $self->model ); } sub BUILDARGS { my $class = shift; my ( $query_string, $query_lang, $model ) = @_; return { query_string => $query_string, query_lang => $query_lang, model => $model }; } sub selectrow_hashref { my $self = shift; $self->execute unless $self->has_results; if ( $self->results->finished ) { $self->_clear_results; return; } my $found_data = {}; for ( my $i = 0 ; $i < $self->results->bindings_count() ; $i++ ) { my $node = $self->results->binding_value($i); my $value = $node->is_literal ? $node->literal_value : $node->uri->as_string; my $key = $self->results->binding_name($i); $found_data->{$key} = $value; } $self->results->next_result; return $found_data; } sub selectrow_arrayref { my $self = shift; unless ( defined( $self->results ) ) { $self->execute; } if ( $self->results->finished ) { $self->_clear_results; return; } my $found_data = []; for ( my $i = 0 ; $i < $self->results->bindings_count() ; $i++ ) { my $node = $self->results->binding_value($i); my $value = $node->is_literal ? $node->literal_value : $node->uri->as_string; push @{$found_data}, $value; } $self->results->next_result; return $found_data; } 1; __END__ =head1 NAME RDF::Helper::RDFReland::Query - Perlish convenience extension for RDF::Redland::Query =head1 SYNOPSIS my $model = RDF::Redland::Model->new( RDF::Redland::Storage->new( %storage_options ) ); my $rdf = RDF::Helper->new( Namespaces => \%namespaces, BaseURI => 'http://domain/NS/2004/09/03-url#' ); my $q_obj = $rdf->new_query( $sparql_text, 'sparql' ); # arrays while ( my $row = $q_obj->selectrow_arrayref ) { # $row is an array reference. } # hashes while ( my $row = $q_obj->selectrow_hashref ) { # $row is a hash reference. } =head1 DESCRIPTION RDF::Helper::RDFRedland::Query is the object retuned from RDF::Helper's new_query() method when using RDF::Redland as the base interface class. This object provides everything that an instance of RDF::Redland::Query offers, plus the convenience methods detailed below. =head1 METHODS =head2 selectrow_arrayref Returns each row as a Perl array references. The order of the array's indices will correspond to the order of the variable bindings in the query. =head2 selectrow_hashref Returns each row as a Perl hash references. The keys in the hash will have the same names as the variable bindings in the query. =head1 AUTHOR Kip Hampton, khampton@totalcinema.com =head1 COPYRIGHT Copyright (c) 2004 Kip Hampton. =head1 LICENSE This module is free sofrware; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L L. =cut