changesets 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +32 -0
- data/Rakefile +60 -0
- data/lib/changesets.rb +4 -0
- data/lib/changesets/rdf_changeset.rb +139 -0
- data/tests/tc_rdf_changeset.rb +158 -0
- data/tests/ts_changeset.rb +2 -0
- metadata +102 -0
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
CHANGESET.RB
|
2
|
+
------------
|
3
|
+
|
4
|
+
A plugin for RDF.rb that provides support for creating Changesets that describe changes to an RDF
|
5
|
+
graph[1].
|
6
|
+
|
7
|
+
Changesets can be serialized as RDF and then applied to a triple store. Changesets are currently supported
|
8
|
+
by Talis Platform stores and Kasabi[0] datasets.
|
9
|
+
|
10
|
+
AUTHOR
|
11
|
+
------
|
12
|
+
|
13
|
+
Leigh Dodds (ld@kasabi.com)
|
14
|
+
|
15
|
+
INSTALLATION
|
16
|
+
------------
|
17
|
+
|
18
|
+
Changesets.rb is packaged as a Ruby Gem and can be installed as follows:
|
19
|
+
|
20
|
+
sudo gem install changesets
|
21
|
+
|
22
|
+
The source for the project is maintained in github at:
|
23
|
+
|
24
|
+
http://github.com/ldodds/changesets.rb
|
25
|
+
|
26
|
+
USAGE
|
27
|
+
-----
|
28
|
+
|
29
|
+
The test suite provides some simple examples of how to construct changesets.
|
30
|
+
|
31
|
+
[0]: [http://kasabi.com]
|
32
|
+
[1]: [http://vocab.org/changeset/schema.html]
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'rake/clean'
|
7
|
+
|
8
|
+
NAME = "changesets"
|
9
|
+
VER = "0.1"
|
10
|
+
|
11
|
+
RDOC_OPTS = ['--quiet', '--title', 'RDF Changesets API']
|
12
|
+
|
13
|
+
PKG_FILES = %w( README.md Rakefile ) +
|
14
|
+
Dir.glob("{tests,lib}/**/*")
|
15
|
+
|
16
|
+
CLEAN.include ['*.gem', 'pkg']
|
17
|
+
SPEC =
|
18
|
+
Gem::Specification.new do |s|
|
19
|
+
s.name = NAME
|
20
|
+
s.version = VER
|
21
|
+
s.platform = Gem::Platform::RUBY
|
22
|
+
s.required_ruby_version = ">= 1.8.7"
|
23
|
+
s.has_rdoc = true
|
24
|
+
s.rdoc_options = RDOC_OPTS
|
25
|
+
s.summary = "RDF Changesets API"
|
26
|
+
s.description = s.summary
|
27
|
+
s.author = "Leigh Dodds"
|
28
|
+
s.email = 'ld@kasabi.com'
|
29
|
+
s.homepage = 'http://github.com/ldodds/changesets.rb'
|
30
|
+
s.files = PKG_FILES
|
31
|
+
s.require_path = "lib"
|
32
|
+
s.test_file = "tests/ts_changeset.rb"
|
33
|
+
s.add_dependency("rdf")
|
34
|
+
s.add_dependency("mocha", ">= 0.9.5")
|
35
|
+
end
|
36
|
+
|
37
|
+
Rake::GemPackageTask.new(SPEC) do |pkg|
|
38
|
+
pkg.need_tar = true
|
39
|
+
end
|
40
|
+
|
41
|
+
Rake::RDocTask.new do |rdoc|
|
42
|
+
rdoc.rdoc_dir = 'doc/rdoc'
|
43
|
+
rdoc.options += RDOC_OPTS
|
44
|
+
rdoc.rdoc_files.include("CHANGES", "lib/**/*.rb")
|
45
|
+
end
|
46
|
+
|
47
|
+
Rake::TestTask.new do |test|
|
48
|
+
test.test_files = FileList['tests/tc_*.rb']
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "Install from a locally built copy of the gem"
|
52
|
+
task :install do
|
53
|
+
sh %{rake package}
|
54
|
+
sh %{sudo gem install pkg/#{NAME}-#{VER}}
|
55
|
+
end
|
56
|
+
|
57
|
+
desc "Uninstall the gem"
|
58
|
+
task :uninstall => [:clean] do
|
59
|
+
sh %{sudo gem uninstall #{NAME}}
|
60
|
+
end
|
data/lib/changesets.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
module RDF
|
2
|
+
module Talis
|
3
|
+
class Changeset < RDF::Vocabulary('http://purl.org/vocab/changeset/schema#')
|
4
|
+
property :removal
|
5
|
+
property :addition
|
6
|
+
property :creatorName
|
7
|
+
property :createdDate
|
8
|
+
property :subjectOfChange
|
9
|
+
property :changeReason
|
10
|
+
property :ChangeSet
|
11
|
+
property :precedingChangeSet
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module RDF
|
17
|
+
|
18
|
+
class Changeset
|
19
|
+
|
20
|
+
#Media type for Changesets
|
21
|
+
CONTENT_TYPE_TURTLE = "application/vnd.talis.changeset+turtle"
|
22
|
+
CONTENT_TYPE_XML = "application/vnd.talis.changeset+xml"
|
23
|
+
#Default reason for applying the update to a graph
|
24
|
+
DEFAULT_REASON = "Generated in changeset.rb"
|
25
|
+
#Default name/label for the change agent
|
26
|
+
DEFAULT_CREATOR = "changeset.rb"
|
27
|
+
|
28
|
+
attr_reader :statements, :subject_of_change
|
29
|
+
|
30
|
+
def initialize(subject_of_change, change_reason=DEFAULT_REASON, creator_name=DEFAULT_CREATOR)
|
31
|
+
@resource = RDF::Node.new
|
32
|
+
@subject_of_change = subject_of_change
|
33
|
+
@statements = []
|
34
|
+
@statements.concat [RDF::Statement.new(@resource, RDF.type, RDF::Talis::Changeset.ChangeSet),
|
35
|
+
RDF::Statement.new(@resource, RDF::Talis::Changeset.changeReason, change_reason),
|
36
|
+
RDF::Statement.new(@resource, RDF::Talis::Changeset.creatorName, creator_name),
|
37
|
+
RDF::Statement.new(@resource, RDF::Talis::Changeset.createdDate, Time.now),
|
38
|
+
RDF::Statement.new(@resource, RDF::Talis::Changeset.subjectOfChange, subject_of_change)]
|
39
|
+
if block_given?
|
40
|
+
yield self
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#Remove these statements from the graph
|
45
|
+
def remove_statements(stmts)
|
46
|
+
stmts = [stmts] if stmts.is_a?(RDF::Statement)
|
47
|
+
stmts.each do |stmt|
|
48
|
+
raise ArgumentError unless stmt.subject == @subject_of_change
|
49
|
+
@statements.concat changeset_statement(stmt, :removal)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#Add these statements to the graph
|
54
|
+
def add_statements(stmts)
|
55
|
+
stmts = [stmts] if stmts.is_a?(RDF::Statement)
|
56
|
+
stmts.each do |stmt|
|
57
|
+
next unless stmt
|
58
|
+
raise ArgumentError unless stmt.subject == @subject_of_change
|
59
|
+
@statements.concat changeset_statement(stmt, :addition)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def changeset_statement(stmt, action)
|
64
|
+
s = RDF::Node.new
|
65
|
+
[RDF::Statement.new(@resource, RDF::Talis::Changeset.send(action), s),
|
66
|
+
RDF::Statement.new(s, RDF.type, RDF.to_rdf+"Statement"),
|
67
|
+
RDF::Statement.new(s, RDF.subject, stmt.subject),
|
68
|
+
RDF::Statement.new(s, RDF.predicate, stmt.predicate),
|
69
|
+
RDF::Statement.new(s, RDF.object, stmt.object)]
|
70
|
+
end
|
71
|
+
|
72
|
+
#Convert into an RDF::Graph object
|
73
|
+
def to_graph
|
74
|
+
graph = RDF::Graph.new()
|
75
|
+
@statements.each do |s|
|
76
|
+
graph << s
|
77
|
+
end
|
78
|
+
graph
|
79
|
+
end
|
80
|
+
|
81
|
+
#Update a predicate from one value to another
|
82
|
+
#Will only remove the specified old value, other values for predicate will remain unchanged
|
83
|
+
def Changeset.update_property(subject, predicate, old_value, new_value, change_reason=DEFAULT_REASON, creator_name=DEFAULT_CREATOR)
|
84
|
+
cs = Changeset.new(subject, change_reason, creator_name) do |cs|
|
85
|
+
cs.remove_statements( RDF::Statement.new( subject, predicate, old_value ) )
|
86
|
+
cs.add_statements( RDF::Statement.new( subject, predicate, new_value ) )
|
87
|
+
end
|
88
|
+
cs
|
89
|
+
end
|
90
|
+
|
91
|
+
#Remove a specific single property for a subject
|
92
|
+
def Changeset.remove_property(subject, predicate, value, change_reason=DEFAULT_REASON, creator_name=DEFAULT_CREATOR)
|
93
|
+
return Changeset.remove_statement( RDF::Statement.new( subject, predicate, value ) )
|
94
|
+
end
|
95
|
+
|
96
|
+
#Remove a statement
|
97
|
+
def Changeset.remove_statement( statement, change_reason=DEFAULT_REASON, creator_name=DEFAULT_CREATOR)
|
98
|
+
cs = Changeset.new(statement.subject, change_reason, creator_name) do |cs|
|
99
|
+
cs.remove_statements( statement )
|
100
|
+
end
|
101
|
+
cs
|
102
|
+
end
|
103
|
+
|
104
|
+
#Remove all statements with a specific predicate for a specific resource
|
105
|
+
def Changeset.remove_properties(subject, predicate, graph, change_reason=DEFAULT_REASON, creator_name=DEFAULT_CREATOR)
|
106
|
+
cs = Changeset.new(subject, change_reason, creator_name) do |cs|
|
107
|
+
graph.query( [subject, predicate, nil] ).each do |statement|
|
108
|
+
cs.remove_statements( statement )
|
109
|
+
end
|
110
|
+
end
|
111
|
+
cs
|
112
|
+
end
|
113
|
+
|
114
|
+
#Remove all statements where the indicated resource is the subject
|
115
|
+
def Changeset.remove_subject(subject, graph, change_reason=DEFAULT_REASON, creator_name=DEFAULT_CREATOR)
|
116
|
+
cs = Changeset.new(subject, change_reason, creator_name) do |cs|
|
117
|
+
graph.query( [subject, nil, nil] ).each do |statement|
|
118
|
+
cs.remove_statements( statement )
|
119
|
+
end
|
120
|
+
end
|
121
|
+
cs
|
122
|
+
end
|
123
|
+
|
124
|
+
#Apply an update by removing all statements for the indicated subject from the old graph, replacing it
|
125
|
+
#with statements in the new graph
|
126
|
+
def Changeset.update(subject, new, old, change_reason=DEFAULT_REASON, creator_name=DEFAULT_CREATOR)
|
127
|
+
cs = Changeset.new(subject, change_reason, creator_name) do |cs|
|
128
|
+
old.query( [subject, nil, nil] ).each do |statement|
|
129
|
+
cs.remove_statements( statement )
|
130
|
+
end
|
131
|
+
new.query( [subject, nil, nil] ).each do |statement|
|
132
|
+
cs.add_statements( statement )
|
133
|
+
end
|
134
|
+
end
|
135
|
+
cs
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'changesets'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'mocha'
|
5
|
+
|
6
|
+
class ChangesetTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_init
|
9
|
+
cs = RDF::Changeset.new( RDF::URI.new("http://www.example.org") )
|
10
|
+
assert_equal( RDF::URI.new("http://www.example.org"), cs.subject_of_change )
|
11
|
+
assert_equal( false, cs.statements.empty? )
|
12
|
+
|
13
|
+
graph = cs.to_graph()
|
14
|
+
assert_not_nil( graph )
|
15
|
+
assert_equal( cs.statements.length, cs.to_graph.size )
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_add_single_statement
|
19
|
+
uri = RDF::URI.new("http://www.example.org")
|
20
|
+
cs = RDF::Changeset.new( uri )
|
21
|
+
stmts = RDF::Statement.new( uri , RDF.type, RDF::RDFS.Class )
|
22
|
+
cs.add_statements( stmts )
|
23
|
+
test_for( RDF::Talis::Changeset.addition, cs, stmts )
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_remove_single_statement
|
27
|
+
uri = RDF::URI.new("http://www.example.org")
|
28
|
+
cs = RDF::Changeset.new( uri )
|
29
|
+
stmts = RDF::Statement.new( uri , RDF.type, RDF::RDFS.Class )
|
30
|
+
cs.remove_statements( stmts )
|
31
|
+
test_for( RDF::Talis::Changeset.removal, cs, stmts )
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_add_statements
|
35
|
+
uri = RDF::URI.new("http://www.example.org")
|
36
|
+
cs = RDF::Changeset.new( uri )
|
37
|
+
stmts = [ RDF::Statement.new( uri , RDF.type, RDF::RDFS.Class ) ]
|
38
|
+
cs.add_statements( stmts )
|
39
|
+
test_for( RDF::Talis::Changeset.addition, cs, stmts )
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_remove_statements
|
43
|
+
uri = RDF::URI.new("http://www.example.org")
|
44
|
+
cs = RDF::Changeset.new( uri )
|
45
|
+
stmts = [ RDF::Statement.new( uri , RDF.type, RDF::RDFS.Class ) ]
|
46
|
+
cs.remove_statements( stmts )
|
47
|
+
test_for( RDF::Talis::Changeset.removal, cs, stmts )
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_precondition
|
51
|
+
uri = RDF::URI.new("http://www.example.org")
|
52
|
+
other = RDF::URI.new("http://www.example.com")
|
53
|
+
cs = RDF::Changeset.new( uri )
|
54
|
+
|
55
|
+
assert_raise ArgumentError do
|
56
|
+
cs.add_statements( RDF::Statement.new( other , RDF.type, RDF::RDFS.Class ) )
|
57
|
+
end
|
58
|
+
assert_raise ArgumentError do
|
59
|
+
cs.remove_statements( RDF::Statement.new( other , RDF.type, RDF::RDFS.Class ) )
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_update_property()
|
65
|
+
uri = RDF::URI.new("http://www.example.org")
|
66
|
+
cs = RDF::Changeset.update_property(uri, RDF::RDFS.label, RDF::Literal.new("Old"), RDF::Literal.new("New") )
|
67
|
+
removal = RDF::Statement.new( uri, RDF::RDFS.label, RDF::Literal.new("Old"))
|
68
|
+
addition = RDF::Statement.new( uri, RDF::RDFS.label, RDF::Literal.new("New"))
|
69
|
+
test_for( RDF::Talis::Changeset.removal, cs, removal )
|
70
|
+
test_for( RDF::Talis::Changeset.addition, cs, addition )
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_remove_property()
|
74
|
+
uri = RDF::URI.new("http://www.example.org")
|
75
|
+
cs = RDF::Changeset.remove_property(uri, RDF::RDFS.label, RDF::Literal.new("Gone") )
|
76
|
+
removal = RDF::Statement.new( uri, RDF::RDFS.label, RDF::Literal.new("Gone"))
|
77
|
+
test_for( RDF::Talis::Changeset.removal, cs, removal )
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_remove_statement()
|
81
|
+
uri = RDF::URI.new("http://www.example.org")
|
82
|
+
removal = RDF::Statement.new( uri, RDF::RDFS.label, RDF::Literal.new("Gone") )
|
83
|
+
cs = RDF::Changeset.remove_statement( removal )
|
84
|
+
test_for( RDF::Talis::Changeset.removal, cs, removal )
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_remove_properties()
|
88
|
+
uri = RDF::URI.new("http://www.example.org")
|
89
|
+
graph = RDF::Graph.new()
|
90
|
+
label = RDF::Statement.new( uri, RDF::RDFS.label, RDF::Literal.new("Label") )
|
91
|
+
title = RDF::Statement.new( uri, RDF::RDFS.label, RDF::Literal.new("Title") )
|
92
|
+
graph << label
|
93
|
+
graph << title
|
94
|
+
cs = RDF::Changeset.remove_properties(uri, RDF::RDFS.label, graph )
|
95
|
+
#puts cs.statements
|
96
|
+
test_for( RDF::Talis::Changeset.removal, cs, label )
|
97
|
+
test_for( RDF::Talis::Changeset.removal, cs, title )
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_remove_subject()
|
101
|
+
uri = RDF::URI.new("http://www.example.org")
|
102
|
+
graph = RDF::Graph.new()
|
103
|
+
label = RDF::Statement.new( uri, RDF::RDFS.label, "Label")
|
104
|
+
title = RDF::Statement.new( uri, RDF::DC.title, "Title")
|
105
|
+
graph << label
|
106
|
+
graph << title
|
107
|
+
cs = RDF::Changeset.remove_subject(uri, graph )
|
108
|
+
test_for( RDF::Talis::Changeset.removal, cs, [ label, title ] )
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_update()
|
112
|
+
uri = RDF::URI.new("http://www.example.org")
|
113
|
+
graph = RDF::Graph.new()
|
114
|
+
label = RDF::Statement.new( uri, RDF::RDFS.label, "Label")
|
115
|
+
title = RDF::Statement.new( uri, RDF::DC.title, "Title")
|
116
|
+
graph << label
|
117
|
+
graph << title
|
118
|
+
cs = RDF::Changeset.update(uri, RDF::Graph.new(), graph )
|
119
|
+
test_for( RDF::Talis::Changeset.removal, cs, [ label, title ] )
|
120
|
+
|
121
|
+
cs = RDF::Changeset.update(uri, graph, RDF::Graph.new() )
|
122
|
+
test_for( RDF::Talis::Changeset.addition, cs, [ label, title ] )
|
123
|
+
end
|
124
|
+
|
125
|
+
# def test_apply_to()
|
126
|
+
# uri = RDF::URI.new("http://www.example.org")
|
127
|
+
# graph = RDF::Graph.new()
|
128
|
+
# label = RDF::Statement.new( uri, RDF::RDFS.label, RDF::Literal.new("Label") )
|
129
|
+
# title = RDF::Statement.new( uri, RDF::DC.title, RDF::Literal.new("Title") )
|
130
|
+
# graph << label
|
131
|
+
# graph << title
|
132
|
+
# cs = RDF::Changeset.remove_properties(uri, RDF::RDFS.label, graph )
|
133
|
+
#
|
134
|
+
# cs.apply_to(graph)
|
135
|
+
#
|
136
|
+
# label = graph.first_object( [uri, RDF::RDFS.label, nil ] )
|
137
|
+
# assert_nil(label)
|
138
|
+
# end
|
139
|
+
|
140
|
+
|
141
|
+
def test_for( predicate, cs, statements )
|
142
|
+
statements = [statements] if statements.is_a?(RDF::Statement)
|
143
|
+
|
144
|
+
statements.each do |s|
|
145
|
+
query = RDF::Query.new do
|
146
|
+
pattern [ :x, predicate, :stmt ]
|
147
|
+
pattern [ :stmt, RDF.subject, s.subject]
|
148
|
+
pattern [ :stmt, RDF.predicate, s.predicate]
|
149
|
+
pattern [ :stmt, RDF.object, s.object]
|
150
|
+
end
|
151
|
+
query.execute(cs.to_graph)
|
152
|
+
if query.failed?
|
153
|
+
raise "Unable to find #{predicate} for #{s.subject} #{s.predicate}, #{s.object}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: changesets
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: "0.1"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Leigh Dodds
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-10-12 00:00:00 Z
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: rdf
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 3
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: mocha
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
hash: 49
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
- 9
|
45
|
+
- 5
|
46
|
+
version: 0.9.5
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
description: RDF Changesets API
|
50
|
+
email: ld@kasabi.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- README.md
|
59
|
+
- Rakefile
|
60
|
+
- tests/ts_changeset.rb
|
61
|
+
- tests/tc_rdf_changeset.rb
|
62
|
+
- lib/changesets.rb
|
63
|
+
- lib/changesets/rdf_changeset.rb
|
64
|
+
homepage: http://github.com/ldodds/changesets.rb
|
65
|
+
licenses: []
|
66
|
+
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options:
|
69
|
+
- --quiet
|
70
|
+
- --title
|
71
|
+
- RDF Changesets API
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 57
|
80
|
+
segments:
|
81
|
+
- 1
|
82
|
+
- 8
|
83
|
+
- 7
|
84
|
+
version: 1.8.7
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
requirements: []
|
95
|
+
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 1.8.9
|
98
|
+
signing_key:
|
99
|
+
specification_version: 3
|
100
|
+
summary: RDF Changesets API
|
101
|
+
test_files:
|
102
|
+
- tests/ts_changeset.rb
|