Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to define type later? (on instance level instead of class level) #34

Closed
tmaier opened this issue Apr 13, 2014 · 4 comments
Closed

Comments

@tmaier
Copy link
Contributor

tmaier commented Apr 13, 2014

You have the following sample in your readme:

class Man < Spira::Base
  type RDF::URI.new('http://example.org/people/father')
  type RDF::URI.new('http://example.org/people/cop')
end

So when I understand this correctly, all men instantiated with m = Man.new are cops and fathers.

But what when m is a fire fighter?
Do I need to set up another class ManFireFighter?
Or when he gets retired.
Do I need to get his attributes and instantiate a new class of ManRetiredFireFighterAndGrandfather?

As this does not seem feasible, I ask myself how to set the type on instance level?

@abrisse
Copy link
Member

abrisse commented Apr 17, 2014

Hi @tmaier.

Indeed in that example (which should be changed btw since not very clear) each Man would be a cop and a father.

You just need to create a new class FireFighter actually with the attributes. Then:

uri = 'http://example.org/4563'

person = Man.for(uri)
person.firstName = 'John'
person.save!

person = FireFighter.for(uri)
person.level = 5
person.save!

Each save will add the RDF.type statements into the repository.

@cordawyn
Copy link
Member

cordawyn commented May 5, 2014

Think of Spira resources as being "reflections" of your storage - if you have some type declared in the RDF storage, you are expected to have a corresponding Ruby class in Spira, and vice versa. So adding/replacing types is about actually adding/replacing individual Spira types (Ruby classes).

As a side note, I've been pondering the implementation of "automagically" declaring Ruby classes based on the data in the RDF storage, to keep things "synchronized". However, there are certain issues with that, so we've been leaving that to be decided by Spira users' for their projects individually, so to say.

@Robsteranium
Copy link

(I've deleted a previous commented about manipulating the resource's @types set as I've since realised this operates on the singleton_class and therefore affects all instances)

I think there are two issues here: setting type(s) at runtime and removing types from instances.

You can set type at runtime with @abrisse's answer and a bit of metaprogramming:

klass = Class.new(Spira::Base) do
  type RDF::URI("http://example.org/people/firefighter")
end

klass.for(m.uri).save

Removing types doesn't appear to be possible without modifying the repository graph directly:

Spira.repository.delete([m.uri, RDF::URI.new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), RDF::URI.new("http://example.org/people/cop")])

Which will remove the offending statement from the repository, but m.types will still report it (even after m.reload), and m.save will add the statement back into the repository.

If the models have unique types/ predicates then it's possible to remove types with model.destroy:

class Man < Spira::Base
  type RDF::URI.new('http://example.org/people/man')
end

class FireFighter < Spira::Base
  type RDF::URI.new('http://example.org/people/fire_fighter')
end

class Cop < Spira::Base
  type RDF::URI.new('http://example.org/people/cop')
end

uri = 'http://example.org/4563'
m = Man.for(uri).save           # uri a people:man
c = Cop.for(uri).save           # uri a people:man, people:cop

# retires
c.destroy                       # uri a people:man

# new career             
f = FireFighter.for(uri).save   # uri a people:man, people:fire_fighter

But if the types of predicates overlap then they'll be lost:

class PoliceMan < Spira::Base
  type RDF::URI.new('http://example.org/people/man')
  type RDF::URI.new('http://example.org/people/cop')
end

another_uri = 'http://example.org/999'
p = PoliceMan.for(uri).save     # another_uri a people:man, people:cop
p.destroy                       # another_uri has no type

Although it's possible to reinstate them, of course

Man.for(another_uri).save       # another_uri a people:man

Of course the fact that this sort of manipulation is awkward is probably inevitable given that object and graph models are so very different in the first place!

@abrisse
Copy link
Member

abrisse commented Jun 17, 2014

@Robsteranium: You really shouldn't use more than one type per class. You will never find an ontology with an owl:Class which is just a union of 2 others.

I like to compare owl:Classes and Ruby Mixins : they both add new capacities/attributes on an instance.

@abrisse abrisse closed this as completed Jun 17, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants