Skip to content
This repository has been archived by the owner on Sep 12, 2018. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bhuga committed Mar 30, 2010
0 parents commit 78ec944
Show file tree
Hide file tree
Showing 6 changed files with 330 additions and 0 deletions.
27 changes: 27 additions & 0 deletions README.md
@@ -0,0 +1,27 @@
# Spira

Bringing linked data to life

Spira is a framework for using the information in RDF.rb repositories as model objects.

Example:

class Person
base_path "http://example.org/example/people"
source ::RDF::Repository

property :name, RDF::FOAF.name, String
property :age, RDF::FOAF.age, Integer

end

bob = Person.create 'bob'
bob.age = 15
bob.name = "Bob Smith"
bob.save!

bob.each_statement
#<http://example.org/example/people/bob> <http://xmlns.com/foaf/0.1/age> "15"^^<http://www.w3.org/2001/XMLSchema#integer> .
#<http://example.org/example/people/bob> <http://www.w3.org/2000/01/rdf-schema#label> "Bob Smith" .

You probably don't want to be using this yet. Major changes are still forthcoming.
24 changes: 24 additions & 0 deletions UNLICENSE
@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <http://unlicense.org/>
97 changes: 97 additions & 0 deletions lib/spira.rb
@@ -0,0 +1,97 @@
require 'rdf'
require 'rdf/isomorphic'

module RDF
module Enumerable
alias_method :==, :isomorphic_with?
end
end


module Spira

def self.included(child)
child.extend ClassMethods
child.instance_eval do
class << self
attr_accessor :base_uri, :repository, :properties
end
@properties = {}
end
end

attr_reader :uri

def initialize(identifier, attributes = {})
@uri = RDF::URI.parse(self.class.base_uri + "/" + identifier)
@repo = RDF::Repository.new
@repo.insert(*(attributes[:statements])) unless attributes[:statements].nil?
@original_repo = @repo.dup
end

def destroy!
self.class.properties.each do | name, predicate |
result = (self.class.repository.query(:subject => @uri, :predicate => predicate))
self.class.repository.delete(*result) unless result.empty?
end
end

def save!
destroy!
self.class.repository.insert(*@repo)
end

def each(*args, &block)
@repo.each(*args, &block)
end
include ::RDF::Enumerable, ::RDF::Queryable

module ClassMethods

def source(klass, *args)
self.repository = klass.new *args
end

def base_path(string)
self.base_uri = string
end

def property(name, predicate, type)
@properties[name] = predicate
name_equals = (name.to_s + "=").to_sym
self.class_eval do

define_method(name_equals) do |arg|
old = @repo.query(:subject => @uri, :predicate => predicate)
@repo.delete(old) unless old.empty?
@repo.insert(RDF::Statement.new(@uri, predicate, arg))
end

define_method(name) do
object = @repo.query(:subject => @uri, :predicate => predicate).first.object
object = case
when type == String
object.object.to_s
when type == Integer
object.object
end
end

end
end

def find(identifier)
statements = self.repository.query(:subject => RDF::URI.parse(self.base_uri + "/" + identifier))
if statements.empty?
nil
else
self.new(identifier, :statements => statements)
end
end

def create(name, attributes = {})
self.new(name, attributes)
end

end
end
3 changes: 3 additions & 0 deletions spec/fixtures/bob.nt
@@ -0,0 +1,3 @@
<http://example.org/example/people/bob> <http://xmlns.com/foaf/0.1/age> "15"^^<http://www.w3.org/2001/XMLSchema#integer> .
<http://example.org/example/people/bob> <http://www.w3.org/2000/01/rdf-schema#label> "Bob Smith" .

18 changes: 18 additions & 0 deletions spec/fixtures/person.rb
@@ -0,0 +1,18 @@
require 'spira'
require 'rdf'

class Person

include Spira

# Find and create instances here
source ::RDF::Repository

# the base path to find Persons
base_path "http://example.org/example/people"

property :name, RDF::RDFS.label, String
property :age, RDF::FOAF.age, Integer


end
161 changes: 161 additions & 0 deletions spec/spira.spec
@@ -0,0 +1,161 @@
$:.unshift(File.join(File.dirname(__FILE__),'..','lib'))
$:.unshift(File.join(File.dirname(__FILE__),'fixtures',''))

$:.unshift(File.join(File.dirname(__FILE__),'..','..','rdf-spec','lib'))
$:.unshift(File.join(File.dirname(__FILE__),'..','..','rdf','lib'))
require 'spira'
require 'rdf/spec/enumerable'
require 'rdf/spec'

def fixture(filename)
File.join(File.dirname(__FILE__),'fixtures',filename)
end

describe Spira do

context "The person fixture" do

before :all do
require 'person'
require 'rdf/ntriples'
@person_repository = RDF::Repository.load(fixture('bob.nt'))
end

it "should be instantiable" do
x = Person.create 'bob'
end

it "should know its source" do
Person.repository.should be_a RDF::Repository
end

it "should have a base path" do
Person.base_uri.should == "http://example.org/example/people"
end

it "should have a find method" do
Person.should respond_to :find
end

it "should return nil for a non-existent person" do
Person.find('nobody').should == nil
end

context "A newly-created person" do

before :each do
@person = Person.create 'bob'
end

after :each do
@person.destroy!
end

it "should be destroyable" do
lambda {@person.destroy!}.should_not raise_error
end

it "should be createable with a URI path" do
@person.uri.should be_a RDF::URI
@person.uri.to_s.should == "http://example.org/example/people/bob"
end

it "should have a name method" do
@person.should respond_to :name
end

it "should have an age method" do
@person.should respond_to :age
end

it "should allow setting a name" do
lambda { @person.name = "Bob Smith" }.should_not raise_error
end

it "should allow getting a name" do
@person.name = "Bob Smith"
@person.name.should == "Bob Smith"
end

it "should allow setting an age" do
lambda { @person.age = 15 }.should_not raise_error
end

it "should allow getting an age" do
@person.age = 15
@person.age.should == 15
end

it "should return strings for the name" do
@person.name = "Bob Smith"
@person.name.should be_a String
end

it "should return integers for the age" do
@person.age = 15
@person.age.should be_a Integer
end

it "should save both properties" do
@person.age = 15
@person.name = "Bob Smith"
@person.age.should == 15
@person.name.should == "Bob Smith"
end

end

context "getting, setting, and saving" do

before :all do
require 'rdf/ntriples'
@person_repository = RDF::Repository.load(fixture('bob.nt'))
end

before :each do
@person = Person.create 'bob'
@person.name = "Bob Smith"
@person.age = 15
end

after :each do
@person.destroy!
end

it "should be saveable" do
lambda { @person.save! }.should_not raise_error
end

it "should be findable after saving" do
@person.save!
bob = Person.find 'bob'
bob.should == @person
end

it "should not find non-existent identifiers after saving one" do
@person.save!
Person.find('xyz').should == nil
end

end

context "as an RDF::Enumerable" do

before :each do
@statements = @person_repository
@person = Person.create 'bob'
@person.name = "Bob Smith"
@person.age = 15
@enumerable = @person
end

it_should_behave_like RDF_Enumerable
end

end


end



0 comments on commit 78ec944

Please sign in to comment.