redlander 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +8 -4
- data/lib/redlander.rb +17 -22
- data/lib/redlander/error_container.rb +28 -27
- data/lib/redlander/model.rb +23 -11
- data/lib/redlander/model_proxy.rb +41 -29
- data/lib/redlander/node.rb +36 -29
- data/lib/redlander/parser.rb +15 -17
- data/lib/redlander/parser_proxy.rb +11 -10
- data/lib/redlander/serializer.rb +15 -10
- data/lib/redlander/statement.rb +47 -91
- data/lib/redlander/storage.rb +14 -36
- data/lib/redlander/stream.rb +57 -0
- data/lib/redlander/stream.rb~ +43 -0
- data/lib/redlander/stream_enumerator.rb +17 -0
- data/lib/redlander/stream_enumerator.rb~ +15 -0
- data/lib/redlander/uri.rb +29 -0
- data/lib/redlander/uri.rb~ +12 -0
- data/lib/redlander/version.rb +1 -1
- data/spec/integration/memory_leak_spec.rb +24 -0
- data/spec/integration/memory_leak_spec.rb~ +24 -0
- data/spec/redlander/model_spec.rb +6 -14
- data/spec/redlander/statement_spec.rb +0 -9
- metadata +43 -24
- data/ext/README +0 -1
- data/ext/extconf.rb +0 -17
- data/ext/redland-pre.i +0 -6
- data/ext/redland-types.i +0 -9
- data/ext/redland_wrap.c +0 -8052
- data/lib/redlander/statement_iterator.rb +0 -37
@@ -1,18 +1,19 @@
|
|
1
|
-
require 'redlander/statement'
|
2
|
-
|
3
1
|
module Redlander
|
4
|
-
|
5
2
|
class ParserProxy
|
6
|
-
|
7
|
-
include StatementIterator
|
3
|
+
include StreamEnumerator
|
8
4
|
|
9
5
|
def initialize(parser, content, options = {})
|
10
|
-
|
11
|
-
@
|
12
|
-
|
13
|
-
|
6
|
+
# TODO: consider a streaming content, as it may be large to fit in memory
|
7
|
+
@parser = parser
|
8
|
+
@content = content
|
9
|
+
@options = options
|
14
10
|
end
|
15
11
|
|
16
|
-
end
|
17
12
|
|
13
|
+
private
|
14
|
+
|
15
|
+
def reset_stream
|
16
|
+
@stream = Stream.new(@parser, @content, @options)
|
17
|
+
end
|
18
|
+
end
|
18
19
|
end
|
data/lib/redlander/serializer.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module Redlander
|
2
|
-
|
3
2
|
class Serializer
|
4
|
-
|
5
3
|
# Create a new serializer.
|
6
4
|
# Name can be either of [:rdfxml, :ntriples, :turtle, :json, :dot],
|
7
5
|
# or nil, which defaults to :rdfxml.
|
@@ -10,8 +8,8 @@ module Redlander
|
|
10
8
|
# because the rest seem to be very buggy.
|
11
9
|
def initialize(name = :rdfxml)
|
12
10
|
@rdf_serializer = Redland.librdf_new_serializer(Redlander.rdf_world, name.to_s, nil, nil)
|
13
|
-
raise RedlandError.new("Failed to create a new serializer")
|
14
|
-
ObjectSpace.define_finalizer(
|
11
|
+
raise RedlandError.new("Failed to create a new serializer") if @rdf_serializer.null?
|
12
|
+
ObjectSpace.define_finalizer(self, proc { Redland.librdf_free_serializer(@rdf_serializer) })
|
15
13
|
end
|
16
14
|
|
17
15
|
# Serialize a model into a string.
|
@@ -19,7 +17,12 @@ module Redlander
|
|
19
17
|
# Options are:
|
20
18
|
# :base_uri base URI (String or URI)
|
21
19
|
def to_string(model, options = {})
|
22
|
-
|
20
|
+
base_uri = if options.has_key?(:base_uri)
|
21
|
+
Uri.new(options[:base_uri]).rdf_uri
|
22
|
+
else
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
Redland.librdf_serializer_serialize_model_to_string(@rdf_serializer, base_uri, model.rdf_model)
|
23
26
|
end
|
24
27
|
|
25
28
|
# Serializes a model and stores it in a file
|
@@ -31,14 +34,18 @@ module Redlander
|
|
31
34
|
#
|
32
35
|
# Returns true on success, or false.
|
33
36
|
def to_file(model, filename, options = {})
|
34
|
-
|
37
|
+
base_uri = if options.has_key?(:base_uri)
|
38
|
+
Uri.new(options[:base_uri]).rdf_uri
|
39
|
+
else
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
Redland.librdf_serializer_serialize_model_to_file(@rdf_serializer, filename, base_uri, model.rdf_model).zero?
|
35
43
|
end
|
36
|
-
|
37
44
|
end
|
38
45
|
|
39
46
|
|
47
|
+
# Applied to Model
|
40
48
|
module SerializingInstanceMethods
|
41
|
-
|
42
49
|
def to_rdfxml(options = {})
|
43
50
|
serializer = Serializer.new(:rdfxml)
|
44
51
|
serializer.to_string(self, options)
|
@@ -74,7 +81,5 @@ module Redlander
|
|
74
81
|
serializer = Serializer.new(serializer_options.delete(:format) || :rdfxml)
|
75
82
|
serializer.to_file(self, filename, serializer_options)
|
76
83
|
end
|
77
|
-
|
78
84
|
end
|
79
|
-
|
80
85
|
end
|
data/lib/redlander/statement.rb
CHANGED
@@ -1,105 +1,73 @@
|
|
1
1
|
module Redlander
|
2
|
-
|
3
2
|
class Statement
|
4
|
-
|
5
3
|
include ErrorContainer
|
6
4
|
|
7
5
|
attr_reader :rdf_statement
|
8
6
|
|
9
7
|
# Create an RDF statement.
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
8
|
+
# Source can be:
|
9
|
+
# Hash, where
|
10
|
+
# :subject
|
11
|
+
# :predicate
|
12
|
+
# :object
|
13
|
+
# Stream, so that a statement is extracted from its current position
|
14
|
+
def initialize(source = {})
|
15
|
+
@rdf_statement = case source
|
16
|
+
when Stream
|
17
|
+
# Pull a (current) statement from the stream
|
18
|
+
Redland.librdf_stream_get_object(source.rdf_stream)
|
19
|
+
when Hash
|
20
|
+
# Create a new statement from nodes
|
21
|
+
s = source[:subject] && Node.new(source[:subject]).rdf_node
|
22
|
+
p = source[:predicate] && Node.new(source[:predicate]).rdf_node
|
23
|
+
o = source[:object] && Node.new(source[:object]).rdf_node
|
23
24
|
Redland.librdf_new_statement_from_nodes(Redlander.rdf_world, s, p, o)
|
25
|
+
else
|
26
|
+
# TODO
|
27
|
+
raise NotImplementedError.new
|
24
28
|
end
|
25
|
-
|
26
|
-
|
27
|
-
ObjectSpace.define_finalizer(@rdf_statement, proc { Redland.librdf_free_statement(@rdf_statement) })
|
29
|
+
raise RedlandError.new("Failed to create a new statement") if @rdf_statement.null?
|
30
|
+
ObjectSpace.define_finalizer(self, proc { Redland.librdf_free_statement(@rdf_statement) })
|
28
31
|
end
|
29
32
|
|
30
33
|
def subject
|
31
|
-
|
32
|
-
rdf_node
|
34
|
+
node = Node.new(self, :subject)
|
35
|
+
node.rdf_node.null? ? nil : node
|
33
36
|
end
|
34
37
|
|
35
38
|
def predicate
|
36
|
-
|
37
|
-
rdf_node
|
39
|
+
node = Node.new(self, :predicate)
|
40
|
+
node.rdf_node.null? ? nil : node
|
38
41
|
end
|
39
42
|
|
40
43
|
def object
|
41
|
-
|
42
|
-
rdf_node
|
44
|
+
node = Node.new(self, :object)
|
45
|
+
node.rdf_node.null? ? nil : node
|
43
46
|
end
|
44
47
|
|
45
48
|
# set the subject of the statement
|
46
49
|
def subject=(node)
|
47
|
-
|
50
|
+
binding_to_statement(node) {
|
51
|
+
Redland.librdf_statement_set_subject(@rdf_statement, node.rdf_node)
|
52
|
+
}
|
48
53
|
end
|
49
54
|
|
50
55
|
# set the predicate of the statement
|
51
56
|
def predicate=(node)
|
52
|
-
|
57
|
+
binding_to_statement(node) {
|
58
|
+
Redland.librdf_statement_set_predicate(@rdf_statement, node.rdf_node)
|
59
|
+
}
|
53
60
|
end
|
54
61
|
|
55
62
|
# set the object of the statement
|
56
63
|
def object=(node)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
def model
|
61
|
-
@model
|
62
|
-
end
|
63
|
-
|
64
|
-
# Add the statement to the given model.
|
65
|
-
#
|
66
|
-
# Returns the model on success, or nil.
|
67
|
-
# NOTE: Duplicate statements are not added to the model.
|
68
|
-
# However, this doesn't result in an error here.
|
69
|
-
def model=(model)
|
70
|
-
if model.nil?
|
71
|
-
@model = nil
|
72
|
-
else
|
73
|
-
if self.valid?
|
74
|
-
if Redland.librdf_model_add_statement(model.rdf_model, @rdf_statement).zero?
|
75
|
-
@model = model
|
76
|
-
else
|
77
|
-
nil
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# Destroy the statement (remove it from the model, if possible).
|
84
|
-
#
|
85
|
-
# Returns true if successfully removed from the model, or false.
|
86
|
-
# If the statement is not bound to a model, false is returned.
|
87
|
-
def destroy
|
88
|
-
if @model
|
89
|
-
if Redland.librdf_model_remove_statement(@model.rdf_model, @rdf_statement).zero?
|
90
|
-
self.model = nil
|
91
|
-
true
|
92
|
-
else
|
93
|
-
false
|
94
|
-
end
|
95
|
-
else
|
96
|
-
false
|
97
|
-
end
|
64
|
+
binding_to_statement(node) {
|
65
|
+
Redland.librdf_statement_set_object(@rdf_statement, node.rdf_node)
|
66
|
+
}
|
98
67
|
end
|
99
68
|
|
100
69
|
def eql?(other_statement)
|
101
|
-
|
102
|
-
subject == other_statement.subject &&
|
70
|
+
subject == other_statement.subject &&
|
103
71
|
predicate == other_statement.predicate &&
|
104
72
|
object == other_statement.object
|
105
73
|
end
|
@@ -116,38 +84,26 @@ module Redlander
|
|
116
84
|
# A valid statement satisfies the following:
|
117
85
|
# URI or blank subject, URI predicate and URI or blank or literal object (i.e. anything).
|
118
86
|
def valid?
|
119
|
-
|
120
|
-
|
121
|
-
else
|
122
|
-
errors.add("is invalid")
|
123
|
-
end
|
124
|
-
is_valid
|
87
|
+
attributes_satisfy? ? errors.clear : errors.add("is invalid")
|
88
|
+
errors.empty?
|
125
89
|
end
|
126
90
|
|
127
91
|
|
128
92
|
private
|
129
93
|
|
130
|
-
def rdf_node_from(node)
|
131
|
-
if node.nil?
|
132
|
-
nil
|
133
|
-
else
|
134
|
-
# According to Redland docs,
|
135
|
-
# the node here becomes a part of the statement
|
136
|
-
# and must not be used by the caller!
|
137
|
-
if node.frozen?
|
138
|
-
raise RedlandError.new("The node is already bound to a statement and cannot be added.")
|
139
|
-
else
|
140
|
-
node.freeze.rdf_node
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
94
|
def attributes_satisfy?
|
146
95
|
!subject.nil? && (subject.resource? || subject.blank?) &&
|
147
96
|
!predicate.nil? && predicate.resource? &&
|
148
97
|
!object.nil?
|
149
98
|
end
|
150
99
|
|
100
|
+
def binding_to_statement(node)
|
101
|
+
if node.frozen?
|
102
|
+
raise RedlandError.new("Cannot assign a bound node")
|
103
|
+
else
|
104
|
+
node.freeze
|
105
|
+
yield
|
106
|
+
end
|
107
|
+
end
|
151
108
|
end
|
152
|
-
|
153
109
|
end
|
data/lib/redlander/storage.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Redlander
|
2
|
-
|
3
|
-
module Storage
|
4
|
-
|
2
|
+
class Storage
|
5
3
|
VALID_STORAGE_TYPES = [:memory, :hashes, :file, :uri, :tstore, :mysql, :sqlite, :postgresql]
|
6
4
|
|
5
|
+
attr_reader :rdf_storage
|
6
|
+
|
7
7
|
# Creates a store of the given type
|
8
8
|
#
|
9
9
|
# Store types (:storage option) are:
|
@@ -31,49 +31,27 @@ module Redlander
|
|
31
31
|
#
|
32
32
|
# NOTE: When dealing with databases,
|
33
33
|
# Redland (1.0.7) just crashes when the required tables aren't available!
|
34
|
-
def
|
35
|
-
storage_type, storage_options = split_options(options)
|
36
|
-
storage_type ||= :memory
|
34
|
+
def initialize(options = {})
|
35
|
+
storage_type, storage_options = split_options(options.dup)
|
37
36
|
|
38
37
|
unless VALID_STORAGE_TYPES.include?(storage_type)
|
39
38
|
raise RedlandError.new("Unknown storage type: #{storage_type}")
|
40
39
|
end
|
41
40
|
|
42
|
-
rdf_storage = Redland.librdf_new_storage(Redlander.rdf_world,
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
raise RedlandError.new("Failed to initialize storage")
|
47
|
-
ObjectSpace.define_finalizer(
|
48
|
-
|
49
|
-
rdf_storage
|
50
|
-
end
|
51
|
-
|
52
|
-
# Wrap changes to the given model in a transaction.
|
53
|
-
# If an exception is raised in the block, the transaction is rolled back.
|
54
|
-
# (Does not work for all storages, in which case the changes are instanteous).
|
55
|
-
def self.transaction(model, &block)
|
56
|
-
Redland.librdf_model_transaction_start(model.rdf_model).zero? || RedlandError.new("Failed to initialize a transaction")
|
57
|
-
block.call
|
58
|
-
Redland.librdf_model_transaction_commit(model.rdf_model).zero? || RedlandError.new("Failed to commit the transaction")
|
59
|
-
rescue
|
60
|
-
rollback(model)
|
61
|
-
end
|
62
|
-
|
63
|
-
# Rollback a latest transaction for the given model.
|
64
|
-
def self.rollback(model)
|
65
|
-
Redland.librdf_model_transaction_rollback(model.rdf_model).zero? || RedlandError.new("Failed to rollback the latest transaction")
|
41
|
+
@rdf_storage = Redland.librdf_new_storage(Redlander.rdf_world,
|
42
|
+
storage_type.to_s,
|
43
|
+
storage_options.delete(:name).to_s,
|
44
|
+
Redlander.to_rdf_options(storage_options))
|
45
|
+
raise RedlandError.new("Failed to initialize storage") if @rdf_storage.null?
|
46
|
+
ObjectSpace.define_finalizer(self, proc { Redland.librdf_free_storage(@rdf_storage) })
|
66
47
|
end
|
67
48
|
|
68
49
|
|
69
50
|
private
|
70
51
|
|
71
|
-
def
|
72
|
-
|
73
|
-
storage_type
|
74
|
-
[storage_type, storage_options]
|
52
|
+
def split_options(options)
|
53
|
+
storage_type = options.delete(:storage) || :memory
|
54
|
+
[storage_type, options]
|
75
55
|
end
|
76
|
-
|
77
56
|
end
|
78
|
-
|
79
57
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Redlander
|
2
|
+
class Stream
|
3
|
+
attr_reader :rdf_stream
|
4
|
+
|
5
|
+
# Convert something to an RDF stream.
|
6
|
+
# Source can be:
|
7
|
+
# Parser - to parse content into a stream
|
8
|
+
# Model - to convert a model to an RDF stream, or
|
9
|
+
# if content (Statement) supplied,
|
10
|
+
# produce a stream of statements from the given model,
|
11
|
+
# matching the non-empty nodes of the given statement.
|
12
|
+
def initialize(source, content = nil, options = {})
|
13
|
+
@rdf_stream = case source
|
14
|
+
when Model
|
15
|
+
if content.is_a?(Statement)
|
16
|
+
Redland.librdf_model_find_statements(source.rdf_model, content.rdf_statement)
|
17
|
+
else
|
18
|
+
Redland.librdf_model_as_stream(source.rdf_model)
|
19
|
+
end
|
20
|
+
when Parser
|
21
|
+
base_uri = options[:base_uri] ? Uri.new(options[:base_uri]).rdf_uri : nil
|
22
|
+
Redland.librdf_parser_parse_string_as_stream(source.rdf_parser, content, base_uri)
|
23
|
+
else
|
24
|
+
# TODO
|
25
|
+
raise NotImplementedError.new
|
26
|
+
end
|
27
|
+
raise RedlandError.new("Failed to create a new stream") if @rdf_stream.null?
|
28
|
+
ObjectSpace.define_finalizer(self, proc { Redland.librdf_free_stream(@rdf_stream) })
|
29
|
+
end
|
30
|
+
|
31
|
+
# End-of-stream?
|
32
|
+
def eos?
|
33
|
+
Redland.librdf_stream_end(@rdf_stream) != 0
|
34
|
+
end
|
35
|
+
|
36
|
+
# Move stream pointer forward
|
37
|
+
def succ
|
38
|
+
Redland.librdf_stream_next(@rdf_stream).zero?
|
39
|
+
end
|
40
|
+
|
41
|
+
# Current statement in the stream, or nil
|
42
|
+
def current
|
43
|
+
Statement.new(self) unless eos?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return all the remaining statements in the stream
|
47
|
+
# from the current position.
|
48
|
+
def tail
|
49
|
+
[].tap do |all|
|
50
|
+
while !eos?
|
51
|
+
all << current
|
52
|
+
succ
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Redlander
|
2
|
+
class Stream
|
3
|
+
attr_reader :rdf_stream
|
4
|
+
|
5
|
+
def initialize(source)
|
6
|
+
@rdf_stream = case source
|
7
|
+
when Statement
|
8
|
+
Redland.librdf_model_find_statements(source.model.rdf_model, source.rdf_statement)
|
9
|
+
when Model
|
10
|
+
Redland.librdf_model_as_stream(source.rdf_model)
|
11
|
+
else
|
12
|
+
# TODO
|
13
|
+
raise NotImplementedError.new
|
14
|
+
end
|
15
|
+
raise RedlandError.new("Failed to create a new stream") if @rdf_stream.null?
|
16
|
+
ObjectSpace.define_finalizer(self, proc { Redland.librdf_free_stream(@rdf_stream) })
|
17
|
+
end
|
18
|
+
|
19
|
+
# End-of-stream?
|
20
|
+
def eos?
|
21
|
+
Redland.librdf_stream_end(@rdf_stream) != 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def succ
|
25
|
+
Redland.librdf_stream_next(@rdf_stream).zero?
|
26
|
+
end
|
27
|
+
|
28
|
+
def current
|
29
|
+
Statement.new(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return all the remaining statements in the stream
|
33
|
+
# from the current position.
|
34
|
+
def tail
|
35
|
+
[].tap do |all|
|
36
|
+
while !eos?
|
37
|
+
all << current
|
38
|
+
succ
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|