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.
@@ -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
- @model = nil # the yielded statements will not be bound to a model
11
- @rdf_stream = Redland.librdf_parser_parse_string_as_stream(parser.rdf_parser, content, Redlander.to_rdf_uri(options[:base_uri]))
12
- raise RedlandError.new("Failed to create a new stream") unless @rdf_stream
13
- ObjectSpace.define_finalizer(@rdf_stream, proc { Redland.librdf_free_stream(@rdf_stream) })
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
@@ -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") unless @rdf_serializer
14
- ObjectSpace.define_finalizer(@rdf_serializer, proc { Redland.librdf_free_serializer(@rdf_serializer) })
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
- Redland.librdf_serializer_serialize_model_to_string(@rdf_serializer, Redlander.to_rdf_uri(options[:base_uri]), model.rdf_model)
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
- Redland.librdf_serializer_serialize_model_to_file(@rdf_serializer, filename, Redlander.to_rdf_uri(options[:base_uri]), model.rdf_model).zero?
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
@@ -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
- # Options are:
11
- # :subject
12
- # :predicate
13
- # :object
14
- def initialize(options = {})
15
- @rdf_statement = if options.is_a?(SWIG::TYPE_p_librdf_statement_s)
16
- # A special case, where you can pass an instance of SWIG::TYPE_p_librdf_statement_s
17
- # in order to create a Statement from an internal RDF statement representation.
18
- options
19
- else
20
- s = options[:subject] && Node.new(options[:subject]).rdf_node
21
- p = options[:predicate] && Node.new(options[:predicate]).rdf_node
22
- o = options[:object] && Node.new(options[:object]).rdf_node
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
- raise RedlandError.new("Failed to create a new statement") unless @rdf_statement
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
- rdf_node = Redland.librdf_statement_get_subject(@rdf_statement)
32
- rdf_node && Node.new(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
- rdf_node = Redland.librdf_statement_get_predicate(@rdf_statement)
37
- rdf_node && Node.new(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
- rdf_node = Redland.librdf_statement_get_object(@rdf_statement)
42
- rdf_node && Node.new(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
- Redland.librdf_statement_set_subject(@rdf_statement, rdf_node_from(node))
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
- Redland.librdf_statement_set_predicate(@rdf_statement, rdf_node_from(node))
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
- Redland.librdf_statement_set_object(@rdf_statement, rdf_node_from(node))
58
- end
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
- model == other_statement.model &&
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
- if is_valid = attributes_satisfy?
120
- errors.clear
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
@@ -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 self.initialize_storage(options = {})
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
- storage_type.to_s,
44
- storage_options.delete(:name).to_s,
45
- Redlander.to_rdf_options(storage_options))
46
- raise RedlandError.new("Failed to initialize storage") unless rdf_storage
47
- ObjectSpace.define_finalizer(rdf_storage, proc { Redland.librdf_free_storage(rdf_storage) })
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 self.split_options(options = {})
72
- storage_options = options.dup
73
- storage_type = storage_options.delete(:storage)
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