Konstantin Baierer avatar Konstantin Baierer committed ad2ec13 Merge

branch merge

Comments (0)

Files changed (25)

File contents unchanged.

+48acb79065a2b8b061ac4e020f76a0708a499134 v0.003
         # 'MooseX::Unique' => '0.005',
         'LWP::UserAgent' => 0,
         'Scalar::Util' => 0,
-        'Set::Object' => 1.28,
+        'Set::Object' => '1.28',
         'URI' => 0,
         'RDF::NS' => '20111124',
+        'MooseX::HasDefaults' => '0.03',
 
         # 'perl'          => '5.6.1',
         # 'Some::Module'  => '1.23',

File contents unchanged.

File contents unchanged.

-* Int and Num are subtypes of Str, not Value!
+Tue Mar 27 02:57:43 CEST 2012
+-----------------------------
+* A meta-attribute 'inverse' to specify that $self->rdf_about should be the
+  object of a statement, not it's subject.
+* A Moose class for all that is known about $self->rdf_about across named
+  graphs/contexts and with '$self->rdf_about' as subject or object
+
+Fri Feb 24 15:10:35 CET 2012
+----------------------------
+* Just found out toby has written a small schema for perl modules
+  (Module::Install::DOAP) - really useful. Could be foundation for solving
+  the inheritance problem, i.e. have MXS RdfImport recognize a special
+  cpanterms:package_name property and instantiating that instead of the
+  base class specified in isa
+
+Fri Feb 24 05:30:07 CET 2012
+----------------------------
+
+Additionally:
+* Detect attributes that contain a model and export the model
+
+On 02/23/2012 07:49 PM, Kjetil Kjernsmo wrote:
+> On Friday 10. February 2012 16.37.34 Kjetil Kjernsmo wrote:
+>> "what would we do with Moose if 
+>> we got to hack on it for a few days with cabal members to help us?"
+Some ideas off the top of my head:
+
+* How to map Moose TypeConstraints to RDF in a generalized way, i.e.
+  * how to handle multiple statements with the same predicate
+  * how to handle type inheritance (e.g. for an attribute that "isa 
+    =>'My::Plugin'" but should be instantiated as My::Plugin::Specialized
+    depending on some additional data
+  * how to handle rdf:List/rdf:Seq/rdf:Bag etc.
+  * mapping to/from MooseX::Type/subtype
+  * Offering hooks to add application-specific behaviour for Moose<->RDF
+    mapping, e.g. using MooseX::Role::Parametrized.
+
+* A separate MooseX::Types distribution with ready-to-use RDF::Trine
+specific types and coercions
+
+* A role that adds a RDF::Trine::Model to any object, along with some
+delegation methods. This can be useful as a general data container, for
+storing obsolete statements, contextual information.
+
+* A utility role or maybe a MooseX::Singleton that encapsulates
+shortcuts for tedious tasks, at least what RDF::Trine exports (iri,
+literal, statement etc.), one or more solutions for Namespaces
+Management and other stuff that RDF::TrineShortcuts et. al. offer.
+
+* Integrate with MooseX::Storage?
+
+* By introspecting a RDF schema, MooseX::Semantic powered classes can in
+theory be created from scratch or MooseX::Semantic attributes "injected"
+into existing Moose classes. While this works, it requires conventions
+how to do it in a general way.
+
+* Tools for extracting the schema out of a set of MooseX::Class and
+validating it.
+
+* Conventions for exporting any Moose class to RDF, something like
+
+@prefix ns1: <urn:moose:My::Plugin#> .
+@prefix moose: <http://moose.perl.org/onto#> .
+ns1:name a moose:Attribute ;
+    moose:isa "Str";
+    moose:default "ANONYMOUS".
+_:inst123 a <urn:moose:My::Plugin> ;
+         ns1:name "John Doe";
+         ns1:age  26.
+
+* Porting Class::OWL to Moose
+
+* Two modules MooseX::Semantic::NonMoose,
+MooseX::Semantic::NonMooseXSemantic] that make it easy to wrap Non-Moose
+or Moose-but-not-MooseX::Semanic classes (a more specialized version of
+MooseX::NonMoose)
+
+* A way to query all objects of one or more Moose classes using SPARQL
+(some metaclass trickery to track all created objects and convert them
+to RDF/query them on the fly)
+
+
+Cheers,
+Konstantin

lib/MooseX/Semantic.pm

 package MooseX::Semantic;
-our $VERSION = '0.002';
+BEGIN { $MooseX::Semantic::AUTHORITY = 'cpan:KBA'; }
+BEGIN { $MooseX::Semantic::VERSION = '0.003'; }
 
 1;
 

lib/MooseX/Semantic/Meta/Attribute/Trait.pm

 use Moose::Role;
 use MooseX::Semantic::Types qw(TrineResource ArrayOfTrineResources);
 use Data::Dumper;
-
+with ( 'MooseX::HasDefaults::Meta::IsRW' );
 =head1 NAME
 
 MooseX::Semantic::Meta::Attribute::Trait - Attribute trait for semantic attributes
 
 =cut
 
+=head1 DESCRIPTION
+
+Attributes that apply the C<Semantic> trait can be extended using the attributes listed below.
+
+By default, all Semantic attributes are read-write, i.e. C<is => 'rw'>.
+
 =head1 ATTRIBUTES
 
 =cut
 #     predicate => 'has_rdfs_comment',
 # );
 
+=head2 rdf_formatter
+
+CodeRef of a function for coercing the value to a RDF literal. Defaults to the identity function.
+
+=cut
+
+has rdf_formatter => (
+    is => 'rw',
+    isa => 'CodeRef',
+    predicate => 'has_rdf_formatter',
+    # default => sub { sub{ return $_[0] }},
+);
+
+=head2 rdf_parser
+
+CodeRef of a function for parsing the literal value before importing this statement. Defaults to the identity function.
+
+=cut
+
+has rdf_parser => (
+    is => 'rw',
+    isa => 'CodeRef',
+    default => sub {sub{ return $_[0] }},
+);
+
+has 'is' => (
+    is => 'rw',
+    default => 'rw',
+);
+
 1;
 =head1 AUTHOR
 

lib/MooseX/Semantic/Role/Graph.pm

+package MooseX::Semantic::Role::Graph;
+use Moose::Role;
+use MooseX::Semantic::Types qw(TrineModel TrineLiteral TrineNode TrineResource );
+use RDF::Trine qw(iri literal statement);
+use Data::Dumper;
+
+with qw(
+    MooseX::Semantic::Role::Resource
+);
+
+=head1 NAME
+
+MooseX::Semantic::Role::Graph - Role for Moose objects that represent named graphs
+
+=cut
+
+=head2 
+
+=head2 SYNOPSIS
+
+    package GraphPackage;
+    use Moose;
+    with qw( MooseX::Semantic::Role::Graph MooseX::Semantic::Role::RdfExport );
+    has 'timestamp' => (
+        traits => ['Semantic'],
+        is => 'rw',
+        default => '1234',
+        uri => 'dc:date',
+    );
+    package main;
+    my $g = GraphPackage->new;
+    $g->rdf_graph->add_statement(statement iri('A'), iri('B'), iri('C') );
+
+=cut
+
+=head2 ATTRIBUTES
+
+=head3 rdf_graph
+
+The model this graph represents
+
+=cut
+
+has rdf_graph => (
+    traits => ['Semantic'],
+    is => 'rw',
+    isa => TrineModel,
+    coerce => 1,
+    default => sub { TrineModel->coerce },
+    uri => 'http://moosex-semantic.org/onto#rdf_graph',
+    # lazy => 1,
+    handles => [qw(
+        add_statement
+        get_statements
+    )],
+);
+
+=head2 METHODS
+
+=head3 From RDF::Trine::Model
+
+=over 4
+
+=item add_statement
+
+=back
+
+=head3 add_statement_smartly
+
+More DWIMmy version of RDF::Trine::Model->add_statmeent
+
+=cut
+
+sub add_statement_smartly {
+    my $self = shift;
+    my @args = @_;
+
+    $args[0] = TrineResource->coerce($args[0]);
+    $args[1] = TrineResource->coerce($args[1]);
+    $args[2] = TrineLiteral->coerce($args[2]);
+    return $self->rdf_graph->add_statement(statement(@args));
+}
+
+
+1;

lib/MooseX/Semantic/Role/PortableResource.pm

+package MooseX::Semantic::Role::PortableResource;
+use Moose::Role;
+with qw(
+    MooseX::Semantic::Role::Resource
+    MooseX::Semantic::Role::RdfExport
+    MooseX::Semantic::Role::RdfImport
+    MooseX::Semantic::Role::WithRdfType
+);
+
+1;

lib/MooseX/Semantic/Role/RdfExport.pm

                 push (@{$stash->{uris}}, @{$attr->uri_writer}) if $attr->has_uri_writer;
                 return not $stash->{attr_val};
             },
+            model => sub {
+                my ($attr, $stash) = @_;
+                my $iter = $stash->{attr_val}->as_stream;
+                while (my $stmt = $iter->next) {
+                    # warn Dumper $stmt;
+                    if ($self->does('MooseX::Semantic::Role::Graph')) {
+                        $stmt->[3] = $self->rdf_about;
+                    }
+                    $model->add_statement($stmt);
+                }
+            },
             literal => sub {
                 my ($attr, $stash) = @_;
-                $self->_export_one_scalar( $model, $stash->{attr_val}, $_, $attr->rdf_lang, $attr->rdf_datatype, $opts{context})
+                my $val = $stash->{attr_val};
+                if ($attr->has_rdf_formatter) {
+                    $val = $attr->rdf_formatter->( $val );
+                }
+                $self->_export_one_scalar( $model, $val, $_, $attr->rdf_lang, $attr->rdf_datatype, $opts{context})
                     for (@{ $stash->{uris} });
             },
             resource => sub {
             literal_in_array => sub {
                 my ($attr, $stash) = @_;
                 for my $subval ( @{$stash->{attr_val}} ) {
+                    if ($attr->has_rdf_formatter) {
+                        $subval = $attr->rdf_formatter->( $subval );
+                    }
                     $self->_export_one_scalar($model, $subval, $_, $attr->rdf_lang, $attr->rdf_datatype, $opts{context} )
                         for (@{ $stash->{uris} });
                 }
     my $self = shift;
     my ($model,  $single_val, $rel, $context) = @_;
     if (blessed $single_val) {
-        if ($single_val->does('MooseX::Semantic::Role::RdfExport')) {
+        # warn Dumper ref $single_val;
+        if (ref $single_val eq 'RDF::Trine::Node::Resource' ) {
+            $model->add_statement(RDF::Trine::Statement->new(
+                    $self->rdf_about,
+                    $rel,
+                    $single_val,
+                ),
+                $context,
+            );
+        }
+        elsif ($single_val->does('MooseX::Semantic::Role::RdfExport')) {
             #
             # Here's the recursion
             #
             $single_val->export_to_model($model);
             $model->add_statement(RDF::Trine::Statement->new(
-                $self->rdf_about,
-                $rel,
-                $single_val->rdf_about
-            ),
-            $context,
-        );
+                    $self->rdf_about,
+                    $rel,
+                    $single_val->rdf_about
+                ),
+                $context,
+            );
         } else {
             warn "Can't export this object since it doesn't MooseX::Semantic::Role::RdfExport";
         }
 sub _export_one_scalar {
     my $self = shift;
     my ($model,  $val, $rel, $lang, $datatype, $context) = @_;
+    # warn Dumper \@_;
     my $lit;
     if ($lang) {
         $lit = RDF::Trine::Node::Literal->new($val, $lang);
     my $self = shift;
     my (%opts) = @_;
     # warn Dumper keys %opts;
-    my $format =  $opts{format} || 'turtle';
+    my $format =  $opts{format} || 'nquads';
     my $options = $opts{serializer_opts} || {};
     my $serializer = RDF::Trine::Serializer->new($format, %{$options} );
     return $serializer;
     
     my $req = HTTP::Request->new(POST => $uri);
     $req->header(Content_Type => $type);
-    my $model = $self->export_to_model($opts{model});
+    my $model = $self->export_to_model($opts{model}, %opts);
     $req->content( $ser->serialize_model_to_string($model) );
     
     my $res = $self->_user_agent->request($req);
 =cut
 
 sub export_to_hash {
+    # warn Dumper [@_];<>;
     my ($self, %opts) = @_;
     my $self_hash = {};
     $opts{max_recursion} //= 0;
             my ($attr, $stash) = @_;
             $self->_attr_to_hash( $self_hash, $attr, $stash->{attr_val}, %opts);
         },
+        model => sub {
+            my ($attr, $stash) = @_;
+            $self_hash->{$attr->name} = $self->{$attr->name}->as_hashref;
+        },
         resource => sub {
             my ($attr, $stash) = @_;
             my $self_hash_value = $self->export_to_hash( $stash->{attr_val}, %opts );
 
 =item format
 
-Format string to be passed to L<RDF::Trine::Parser>, e.g. C<turtle> or C<rdfxml>.
+Format string to be passed to L<RDF::Trine::Parser>, e.g. C<turtle> or C<rdfxml>. Defaults to C<nquads>.
 
 =item serializer_opts
 

lib/MooseX/Semantic/Role/RdfImport.pm

 package MooseX::Semantic::Role::RdfImport;
 use Moose::Role;
-use RDF::Trine;
+use RDF::Trine qw(statement);
 use Data::Dumper;
-use MooseX::Semantic::Types qw(TrineResource);
+use MooseX::Semantic::Types qw(TrineResource TrineModel);
 use Set::Object;
 use namespace::autoclean;
+use Log::Log4perl;
+my $logger = Log::Log4perl->get_logger(__PACKAGE__);
 
 with(
     'MooseX::Semantic::Role::Resource',
     return $resource_obj;
 }
 
+sub new_from_string {
+    my ($cls, $model_string, $uri, %opts) = @_;
+    $opts{format} //= 'nquads';
+    $opts{base_uri} //= 'urn:none:';
+    my $model = RDF::Trine::Model->temporary_model;
+    my $parser = RDF::Trine::Parser->new($opts{format});
+    $parser->parse_into_model($opts{base_uri}, $model_string, $model);
+    return $cls->new_from_model($model, $uri);
+}
+
+=head2 get_instance_hash
+
+Creates a hash of attribute/value pairs that can be passed to $cls->new
+
+=cut
+
+sub get_instance_hash {
+    my ( $cls, $model, $uri, $unfinished_resources ) = @_;
+
+    my $resource = TrineResource->coerce( $uri );
+    $unfinished_resources = Set::Object->new unless $unfinished_resources;
+    $unfinished_resources->insert( $resource );
+    my $inst_hash        = $cls->_build_instance_hash($resource, $model, $unfinished_resources);
+    $inst_hash->{rdf_about} = $resource;
+
+    return $inst_hash;
+}
+
 sub _build_instance_hash {
     my $cls = shift;
     my ($resource, $model, $unfinished_resources) = @_;
+    $resource = TrineResource->coerce( $resource );
 
     # callback for the type hierarchy walking to find
     # the first thing that's a class and a Resource
             # skip attribute we can't import to (lack of uri)
             return 1 unless scalar $stash->{uris};
 
-            # retrieve nodes from model
-            my @nodes = $model->objects_for_predicate_list($resource, @{ $stash->{uris} });
 
-            # skip attribute if no values are to be set
-            return 1 unless scalar @nodes;
+            # warn Dumper $stash->{uris};
+            if ($stash->{uris}->[0]->as_string eq '<http://moosex-semantic.org/onto#rdf_graph>') {
+                $stash->{statement_iterator} = $model->get_statements(undef,undef,undef,$resource);
+            }
+            else {
+                # retrieve nodes from model
+                my @nodes = $model->objects_for_predicate_list($resource, @{ $stash->{uris} });
 
-            # stash nodes away for other callbacks
-            $stash->{nodes} = \@nodes;
-            $stash->{literal_nodes} = [ map {$_->literal_value} grep { $_->is_literal } @nodes ];
+                # skip attribute if no values are to be set
+                return 1 unless scalar @nodes;
+
+                # stash nodes away for other callbacks
+                $stash->{nodes} = \@nodes;
+                $stash->{literal_nodes} = [ map {$_->literal_value} grep { $_->is_literal } @nodes ];
+            }
 
             # *Don't* skip this attribute
             return undef;
             return unless $stash->{literal_nodes}->[0];
             $inst_hash->{$attr->name} = $stash->{literal_nodes};
         },
+        model => sub {
+            my ($attr, $stash) = @_;
+
+            # support for MooseX::Semantic::Role::Graph
+            # push (@{$stash->{rdf_graph} = $) if $attr->name eq 'rdf_graph';
+            # warn Dumper $resource;
+            # warn Dumper "I LIVE";
+            my $graph_model = TrineModel->coerce;
+            # while (my $stmt = $model->get_statements(undef,undef,undef)) {
+            # warn Dumper $stash;
+            while (my $stmt = $stash->{statement_iterator}->next){
+                # warn Dumper $stmt;
+                $graph_model->add_statement(statement( $stmt->[0], $stmt->[1], $stmt->[2] ));
+            }
+            # warn Dumper $inst_hash;
+            $inst_hash->{$attr->name} = $graph_model;
+        },
         resource => sub {
             my ($attr, $stash) = @_;
             my $attr_type_cls = $cls->_find_parent_type( $attr, $does_resource );
     my $cls = shift;
     my ($uri) = @_;
 
-    # my $rdfa = RDF::RDFa::Parser->new_from_url($uri);
-    # my $model = $rdfa->graph;
     my $model = RDF::Trine::Model->temporary_model;
     RDF::Trine::Parser->parse_url_into_model( $uri, $model );
     return $cls->new_from_model( $model, $uri );
 sub _instantiate_one_object {
     my ($cls, $model, $resource, $instance_class, $unfinished_resources) = @_;
     # warn Dumper [$unfinished_resources->elements];
+    # warn Dumper $resource;
+    unless ($instance_class) {
+        die "Can't instantiate $resource / $cls. Did you forget to load the type for this attribute TODO?";
+        # warn Dumper $model;
+        # warn Dumper $cls;
+        # warn Dumper $resource;
+        # die "DEATH";
+    }
     if (! $instance_class->does('MooseX::Semantic::Role::Resource')) {
         warn "Resource $resource can't be instantiated as $instance_class ($instance_class doesn't MooseX::Semantic::Role::Resource)";
         return;

lib/MooseX/Semantic/Role/Resource.pm

     lazy => 1,
     builder => '_build_rdf_about',
     handles => [qw( is_blank is_resource )],
+    trigger => sub {
+        my $self = shift;
+        $self->_is_auto_generated(undef);
+    },
 );
 sub _build_rdf_about {
+    my $self = shift;
     # XXX should Resources be by default blank nodes or have a UUID URI?
+    $self->_is_auto_generated(1);
     TrineResource->coerce(sprintf('urn:uuid:%s', Data::UUID->new->create_str));
 }
 
+has _is_auto_generated => (
+    is => 'rw',
+    isa => 'Bool',
+    init_arg => undef,
+    default => 0,
+    lazy => 1,
+);
+sub is_auto_generated {
+    my $self = shift;
+    # make sure rdf_about has been initialized lazily
+    $self->rdf_about;
+    return $self->_is_auto_generated;
+}
+
 1;
 
 =head1 METHODS
 
 =cut
 
+=head2 C<is_auto_generated>
+
+Returns true value if the 'rdf_about' attribute was aut-generated, false if it
+has been explicitly set (at constructor time or using the 'rdf_about' accessor)
+
+=cut
+
 =head1 AUTHOR
 
 Konstantin Baierer (<kba@cpan.org>)

lib/MooseX/Semantic/Test/ModelContainingPerson.pm

+package MooseX::Semantic::Test::ModelContainingPerson;
+use Moose;
+# use MooseX::Semantic::
+
+with qw(
+    MooseX::Semantic::Role::RdfExport
+);
+
+has data_bucket => (
+    traits => ['Semantic'],
+    is => 'rw',
+    isa => 'RDF::Trine::Model',
+    default => sub { RDF::Trine::Model->temporary_model },
+    uri => 'DUMMY'
+);
+
+
+1;

lib/MooseX/Semantic/Types.pm

 use RDF::Trine qw(iri);
 use RDF::Trine::Namespace qw(xsd);
 use MooseX::Types -declare => [qw( 
+    TrineNode
     TrineBlank
     TrineResource 
+    TrineModel
+    TrineLiteral
+    TrineStore
+    TrineLiteralOrTrineResorce
+    TrineBlankOrUndef 
     ArrayOfTrineResources
-    TrineNode
     ArrayOfTrineNodes
-    TrineLiteral
-    TrineBlankOrUndef 
     ArrayOfTrineLiterals
+    HashOfTrineResources
+    HashOfTrineNodes
+    HashOfTrineLiterals
     CPAN_URI
     UriStr
-    TrineModel
-    TrineStore
     )];
 use MooseX::Types::URI Uri => { -as => 'MooseX__Types__URI__Uri' };
 use MooseX::Types::Moose qw{:all};
 
 class_type TrineResource, { class => 'RDF::Trine::Node::Resource' };
 subtype ArrayOfTrineResources, as ArrayRef[TrineResource];
+subtype HashOfTrineResources, as HashRef[TrineResource];
 class_type TrineBlank, { class => 'RDF::Trine::Node::Blank' };
 subtype TrineBlankOrUndef, as Maybe[TrineBlank];
 class_type TrineLiteral, { class => 'RDF::Trine::Node::Literal' };
 subtype ArrayOfTrineLiterals, as ArrayRef[TrineLiteral];
+subtype HashOfTrineLiterals, as HashRef[TrineLiteral];
 subtype TrineNode, as Object, where {$_->isa('RDF::Trine::Node::Blank') || $_->isa('RDF::Trine::Node::Resource')};
 subtype ArrayOfTrineNodes, as ArrayRef[TrineNode];
+subtype HashOfTrineNodes, as HashRef[TrineNode];
 subtype UriStr, as Str;
 class_type TrineModel, { class => 'RDF::Trine::Model' };
 class_type TrineStore, { class => 'RDF::Trine::Store' };
 
 
 class_type CPAN_URI, { class => 'URI' };
+# coerce( CPAN_URI,
+#     from Str, via { if (/^[a-z]+:/) { URI->new($_) },
+# );
 
 coerce( TrineBlankOrUndef,
     from Bool, via { return undef unless $_; RDF::Trine::Node::Blank->new },
 );
 
 coerce( ArrayOfTrineResources,
+    # from Str, via { [ TrineResource->coerce( $_ ) ] },
     from TrineResource, via { [ $_ ] },
     from ArrayRef, via { my $u = $_; [map {TrineResource->coerce($_)} @$u] },
     from Value, via { [ TrineResource->coerce( $_ ) ] },

lib/MooseX/Semantic/Util/TypeConstraintWalker.pm

 use Try::Tiny;
 use Data::Dumper;
 use MooseX::Semantic::Types qw(UriStr);
+use Data::Printer;
 use feature qw(switch);
+use Log::Log4perl;
+my $logger = Log::Log4perl->get_logger(__PACKAGE__);
+
+#TODO proper support for MooseX::Types!!!
 
 sub _find_parent_type {
     my ($self, $attr_or_type_constraint, $needle, %opts) = @_;
     elsif ($type_ref =~ m'^Moose::Meta::(?:Attribute|Class)') {
         $type_constraint = $attr_or_type_constraint->type_constraint;
     }
-    elsif ($type_ref =~ m'^Moose::Meta::TypeConstraint') {
+    # elsif ($type_ref =~ m'^(?:Moose::Meta::TypeConstraint::Class)') {
+    #     $type_constraint = $attr_or_type_constraint;
+    # }
+    elsif ($type_ref =~ m'^(?:Moose::Meta::TypeConstraint|MooseX::Types::TypeDecorator)') {
         $type_constraint = $attr_or_type_constraint;
     }
     else {
 
 sub _find_parent_type_for_type_constraint {
     my ($self, $type_constraint, $needle, %opts) = @_;
+    # warn Dumper $type_constraint->name;
+    # warn Dumper $needle;
     $opts{max_depth} = 9999 unless defined $opts{max_depth};
     $opts{max_width} = 9999 unless defined $opts{max_width};
     $opts{current_depth} = 0 unless $opts{current_depth};
     $opts{current_width} = 0 unless $opts{current_width};
+    # warn Dumper [keys(%$type_constraint)];
     # warn Dumper $type_constraint->name;
     # warn Dumper \%opts;
     # warn Dumper $opts{current_depth};
     elsif ($type_constraint->name eq $needle) {
         return $needle;
     }
+    if ( $type_constraint->can('class') && ! blessed $type_constraint->class && $type_constraint->class eq $needle ) {
+        return $type_constraint->class;
+    }
+    if ( $type_constraint->{'__type_constraint'} 
+    ) {
+        # warn Dumper $type_constraint->{'__type_constraint'};
+        # if( $type_constraint->{'__type_constraint'}->can('class')
+        #     && $type_constraint->{'__type_constraint'}->class eq $needle 
+        # ) {
+            # return $needle;
+        # warn Dumper [ keys(%{$type_constraint}->{'__type_constraint'}) ];
+        # warn Dumper {%{$type_constraint->{'__type_constraint'}}};
+        return $self->_find_parent_type_for_type_constraint($type_constraint->{'__type_constraint'}, $needle, %opts);
+        # }
+        # else {
+        #     return
+        # }
+    }
     if ($type_constraint->has_parent) {
+        # warn Dumper {keys(%{$type_constraint})};
         return $self->_find_parent_type_for_type_constraint($type_constraint->parent, $needle, %opts );
     }
     else {
 sub _walk_attributes{
     my ($self, $cb_opts, $cb_selector) = @_;
     my $cb;
-    for (qw(before literal resource literal_in_array resource_in_array)) { 
+    for (qw(before literal resource literal_in_array resource_in_array model)) { 
         $cb->{$_} = defined $cb_opts->{$_} ? $cb_opts->{$_} : sub {}
     }
     ATTR:
-    for my $attr_name ($self->meta->get_attribute_list) {
-        my $attr = $self->meta->get_attribute($attr_name);
+    for my $attr ($self->meta->get_all_attributes) {
+        my $attr_name = $attr->name;
+        # my $attr = $self->meta->get_attribute($attr_name);
         next unless ($attr->does('MooseX::Semantic::Meta::Attribute::Trait'));
         my $attr_type = $attr->type_constraint;
+        if (ref $attr_type eq 'MooseX::Types::TypeDecorator') {
+            # warn Dumper $attr_name;
+            # warn Dumper ref $attr_type;
+            $attr_type = $attr_type->__type_constraint->parent;
+            # p $attr_type;
+        }
+        # else {
+        #     # p $attr_name;
+        #     # p $attr_type;
+        # }
 
         my $stash = {};
         $stash->{uris}  = [$attr->uri] if $attr->has_uri;
         # skip this attribute if the 'before' callback returns a true value
         next if $cb->{before}->($attr, $stash, @_);
         my $callback_name;
-        if ( ! $attr_type
+        if ( $attr->has_rdf_formatter
+            || ! $attr_type
             || $attr_type eq 'Str'
             || $self->_find_parent_type( $attr_type, 'Num' )
             || $self->_find_parent_type( $attr_type, 'Bool' ))
         {
             $callback_name = 'literal';
         }
-        elsif ($self->_find_parent_type($attr->type_constraint, 'Object')
-            || $self->_find_parent_type($attr->type_constraint, 'ClassName'))
+        elsif ($self->_find_parent_type($attr_type, 'Object')
+            # || $self->_find_parent_type($attr_type, 'ClassName')
+            )
         {
             $callback_name = 'resource';
+            # warn Dumper keys(%{ $attr->type_constraint->{__type_constraint} });
+            if ( 
+                # $self->$attr_name->isa('RDF::Trine::Model')
+                $self->_find_parent_type( $attr, 'RDF::Trine::Model' 
+                # || $attr->uri->as_string eq '<http://moosex-semantic.org/onto#rdf_graph>'
+                )
+                # || $self->uri eq 'http:
+            ) {
+                # warn "It's amodel";
+                $callback_name = 'model';
+            }
+        }
+        elsif ($self->_find_parent_type($attr_type, 'Str')) {
+            $callback_name = 'literal';
         }
         elsif ($self->_find_parent_type($attr->type_constraint, 'ArrayRef')) {
-            if ( ! $attr_type->can('type_parameter')
-                || $attr_type->type_parameter eq 'Str'
-                || $self->_find_parent_type( $attr_type->type_parameter, 'Num' )
-                || $self->_find_parent_type( $attr_type->type_parameter, 'Bool' ))
+            if ( ! $attr_type->can('type_parameter')) {
+                warn Dumper "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
+                # warn Dumper ref $attr_type;
+                # p $attr_type;
+                $callback_name = 'literal_in_array';
+            }
+            elsif ( $self->_find_parent_type( $attr_type->type_parameter, 'Object' ) 
+            or      $self->_find_parent_type( $attr_type->type_parameter, 'ClassName' ) ) 
+            {
+                $callback_name = 'resource_in_array';
+            }
+            elsif ( $attr_type->type_parameter eq 'Str'
+            or      $self->_find_parent_type( $attr_type->type_parameter, 'Num' )
+            or      $self->_find_parent_type( $attr_type->type_parameter, 'Bool' ))
             {
                 $callback_name = 'literal_in_array';
             }
-            elsif ( $self->_find_parent_type( $attr_type->type_parameter, 'Object' ) 
-                || $self->_find_parent_type( $attr_type->type_parameter, 'ClassName' ) ) {
-                $callback_name = 'resource_in_array';
-            }
         }
+        else {
+            # warn Dumper $attr_type->has_parent;
+            # warn Dumper $attr_type->parent;
+            warn Dumper ref $attr_type;
+            # warn Dumper $self->_find_parent_type($attr_type, 'Object');
+            warn "Can't handle this attribute: $attr_name";
+            next;
+        }
+        # warn Dumper $attr->uri;
+        # warn Dumper $callback_name;
         $cb->{$callback_name}->($attr, $stash, @_);
     }
 }
+let SessionLoad = 1
+if &cp | set nocp | endif
+let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0
+let v:this_session=expand("<sfile>:p")
+silent only
+cd /code/perl/p5-moosex-semantic
+if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''
+  let s:wipebuf = bufnr('%')
+endif
+set shortmess=aoO
+badd +12 lib/MooseX/Semantic/Role/RdfExport.pm
+badd +18 lib/MooseX/Semantic/Role/Graph.pm
+badd +0 lib/MooseX/Semantic/Util/TypeConstraintWalker.pm
+badd +0 t/rdf_export/graph.t
+silent! argdel *
+edit lib/MooseX/Semantic/Role/RdfExport.pm
+set splitbelow splitright
+wincmd _ | wincmd |
+vsplit
+1wincmd h
+wincmd w
+set nosplitbelow
+set nosplitright
+wincmd t
+set winheight=1 winwidth=1
+exe 'vert 1resize ' . ((&columns * 30 + 98) / 197)
+exe 'vert 2resize ' . ((&columns * 166 + 98) / 197)
+argglobal
+enew
+file NERD_tree_1
+setlocal fdm=marker
+setlocal fde=0
+setlocal fmr={{{,}}}
+setlocal fdi=#
+setlocal fdl=0
+setlocal fml=1
+setlocal fdn=20
+setlocal fen
+wincmd w
+argglobal
+setlocal fdm=marker
+setlocal fde=0
+setlocal fmr={{{,}}}
+setlocal fdi=#
+setlocal fdl=0
+setlocal fml=1
+setlocal fdn=20
+setlocal fen
+let s:l = 12 - ((11 * winheight(0) + 24) / 48)
+if s:l < 1 | let s:l = 1 | endif
+exe s:l
+normal! zt
+12
+normal! 0
+wincmd w
+exe 'vert 1resize ' . ((&columns * 30 + 98) / 197)
+exe 'vert 2resize ' . ((&columns * 166 + 98) / 197)
+tabedit lib/MooseX/Semantic/Role/Graph.pm
+set splitbelow splitright
+set nosplitbelow
+set nosplitright
+wincmd t
+set winheight=1 winwidth=1
+argglobal
+setlocal fdm=marker
+setlocal fde=0
+setlocal fmr={{{,}}}
+setlocal fdi=#
+setlocal fdl=0
+setlocal fml=1
+setlocal fdn=20
+setlocal fen
+let s:l = 15 - ((14 * winheight(0) + 24) / 48)
+if s:l < 1 | let s:l = 1 | endif
+exe s:l
+normal! zt
+15
+normal! 017l
+tabedit lib/MooseX/Semantic/Util/TypeConstraintWalker.pm
+set splitbelow splitright
+set nosplitbelow
+set nosplitright
+wincmd t
+set winheight=1 winwidth=1
+argglobal
+setlocal fdm=marker
+setlocal fde=0
+setlocal fmr={{{,}}}
+setlocal fdi=#
+setlocal fdl=0
+setlocal fml=1
+setlocal fdn=20
+setlocal fen
+let s:l = 1 - ((0 * winheight(0) + 24) / 48)
+if s:l < 1 | let s:l = 1 | endif
+exe s:l
+normal! zt
+1
+normal! 0
+tabedit t/rdf_export/graph.t
+set splitbelow splitright
+set nosplitbelow
+set nosplitright
+wincmd t
+set winheight=1 winwidth=1
+argglobal
+setlocal fdm=marker
+setlocal fde=0
+setlocal fmr={{{,}}}
+setlocal fdi=#
+setlocal fdl=0
+setlocal fml=1
+setlocal fdn=20
+setlocal fen
+let s:l = 20 - ((19 * winheight(0) + 24) / 48)
+if s:l < 1 | let s:l = 1 | endif
+exe s:l
+normal! zt
+20
+normal! 025l
+tabnext 4
+if exists('s:wipebuf')
+  silent exe 'bwipe ' . s:wipebuf
+endif
+unlet! s:wipebuf
+set winheight=1 winwidth=20 shortmess=filnxtToO
+let s:sx = expand("<sfile>:p:r")."x.vim"
+if file_readable(s:sx)
+  exe "source " . fnameescape(s:sx)
+endif
+let &so = s:so_save | let &siso = s:siso_save
+doautoall SessionLoadPost
+unlet SessionLoad
+" vim: set ft=vim :

t/data/blank_node_01.ttl

 _:b1
     a foaf:Person ;
     foaf:name "Bob" .
+
+<alice-inline>
+    a foaf:person ;
+    foaf:name "Alice Inline" ;
+    foaf:knows [
+        a foaf:person ;
+        foaf:name "Bob Inline" 
+    ] .

t/rdf_export/basic.t

 use Test::More tests=>10;
 use Test::Moose;
-use RDF::Trine qw(blank);
+use Carp::Always;
+use RDF::Trine qw(blank literal iri statement);
 use Data::Dumper;
 use MooseX::Semantic::Test::Person;
 use File::Temp qw( tempfile );
     print $p->export_to_string(format=>'turtle');
 }
 
+sub model_export {
+    {
+        package My::Model::Person;
+        use Moose;
+        with qw(MooseX::Semantic::Role::RdfExport);
+        has bucket => (
+            traits => ['Semantic'],
+            is => 'rw',
+            isa => 'RDF::Trine::Model',
+            uri => 'http://xmlns.com/foaf/0.1/dataBucket',
+            uri_writer => ['http://myont.org/onto#name'],
+        );
+    }
+    my $dummy_model = RDF::Trine::Model->temporary_model;
+    $dummy_model->add_statement(statement(
+        iri('Someone'),
+        iri('is'),
+        literal('bored'),
+    ));
+    my $p = My::Model::Person->new(
+        rdf_about => 'http://myont.org/data/John',
+        bucket      => $dummy_model
+    );
+    print $p->export_to_string(format=>'turtle');
+}
+
 &basic_export;
 &basic_blank_node;
 &basic_to_turtle;
+&model_export;
 # done_testing;

t/rdf_export/graph.t

+#=======================================================================
+# graph.t
+#=======================================================================
+use common::sense;
+use Test::Most tests => 6;
+use RDF::Trine qw(iri statement);
+use Data::Dumper;
+use Scalar::Util qw(refaddr);
+
+{
+    package GraphPackage;
+    use Moose;
+    with qw( MooseX::Semantic::Role::Graph MooseX::Semantic::Role::RdfExport MooseX::Semantic::Role::RdfImport );
+    has 'timestamp' => (
+        traits => ['Semantic'],
+        is => 'rw',
+        default => '1234',
+        uri => 'dc:date',
+    );
+}
+
+my $g = GraphPackage->new(rdf_about => 'graph_1');
+# warn Dumper $g->rdf_graph;
+$g->add_statement(statement iri('A'), iri('B'), iri('C') );
+$g->add_statement_smartly('D', 'E', 'F');
+# warn Dumper $g->rdf_graph;
+# warn Dumper ref $g->rdf_graph;
+# warn Dumper $g->export_to_hash;
+# warn Dumper $g->export_to_string(format=>'nquads');
+is($g->rdf_about->as_string, '<graph_1>');
+ok($g->get_statements(iri 'A', iri 'B', iri 'C')->next);
+
+diag "round trip";
+# warn Dumper $g->rdf_graph->get_statements->next;
+# warn Dumper $g->export_to_model;
+my $g_model = $g->export_to_model;
+my $g2 = GraphPackage->new_from_model($g_model, $g->rdf_about);
+# warn Dumper $g2->rdf_graph->get_statements->next;
+ok($g2->get_statements->next);
+
+# warn Dumper $g->export_to_string(format=>'nquads');
+# warn Dumper $g2->export_to_string(format=>'nquads');
+is($g->export_to_string(format=>'nquads'), $g2->export_to_string(format=>'nquads') );
+isnt(refaddr $g, refaddr $g2);
+isnt(refaddr $g->rdf_graph, refaddr $g2->rdf_graph);

t/rdf_import/blank_node.t

-use Test::More tests=>4;
+use Test::More tests=>8;
 use RDF::Trine;
 use Data::Dumper;
 use MooseX::Semantic::Test::Person;
 # warn Dumper $serializer->serialize_model_to_string($model);
 ok( my $alice = MooseX::Semantic::Test::Person->new_from_model($model, 'http://example.com/alice'), 'Alice is detected');
 ok( $alice->has_friends, 'Alice has a friend' );
-TODO: {
-    local $TODO = "recursive import NIH";
-    is( $alice->friends->[0]->name, Bob, "Alice's friend's name is Bob" );
-}
+is( $alice->friends->[0]->name, Bob, "Alice's friend's name is Bob" );
 ok( $alice->friends->[0]->is_blank, "Bob is a blank node" );
+ok( my $alice_inline = MooseX::Semantic::Test::Person->new_from_model($model, 'http://example.com/alice-inline'), 'Alice is detected');
+ok( $alice_inline->has_friends, "Alice has a friend Inline" );
+is( $alice_inline->friends->[0]->name, "Bob Inline", "Alice's friend's name is Bob Inline" );
+ok( $alice_inline->friends->[0]->is_blank, "Bob is a blank node Inline" );
+
+
 # warn Dumper $alice;

t/rdf_import/rdf_import.t

     # warn Dumper $alice_model_str;
 }
 
+sub import_instance_hash {
+    my $base_uri = 'http://tobyinkster.co.uk/#i';
+    my $test_model = RDF::Trine::Model->temporary_model;
+    RDF::Trine::Parser::Turtle->parse_file_into_model(
+        $base_uri,
+        't/data/toby_inkster.ttl',
+        $test_model,
+    );
+    my $hash = MooseX::Semantic::Test::Person->get_instance_hash( $test_model, $base_uri );
+    is(keys %{$hash}, 7, 'correct number of keys');
+    # warn Dumper $hash;
+}
+
 &import_from_ttl;
 &symmetrical_property;
+&import_instance_hash;
 # &import_from_web;
 done_testing;
+#=======================================================================
+# rdf_resource.t
+#=======================================================================
+use common::sense;
+use Test::Most tests => 3;
+use Data::Dumper;
+{
+    package SemTest;
+    use Moose;
+    with qw(MooseX::Semantic::Role::Resource);
+    has foo => (
+        # is => 'rw' ,
+        traits => ['Semantic'],
+        uri => 'http://bar.baz/foo',
+    );
+}
+
+my $t1 = SemTest->new();
+my $t2 = SemTest->new(
+    rdf_about => 'foo',
+);
+# warn Dumper $t->rdf_about;
+ok( $t1->is_auto_generated, 't1 has auto-generated ID' );
+ok( ! $t2->is_auto_generated, 't1 has explicit rdf_about' );
+$t1->rdf_about('bar');
+ok( ! $t1->is_auto_generated, 'Now t1 has explicit rdf_about' );
+
+
+
+
 use warnings;
 use Test::More
     skip_all => 'no reason'
+    # tests => 1
     ; 
 use Test::Moose;
 use Data::Dumper;
 use URI;
 
 my $p = MooseX::Semantic::Test::Person->new;
-done_testing;

t/util/util_walker.t

 }
 
 
-&simple_type_walker
+&simple_type_walker;
 &class_name_finder;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.