redlander 0.3.6 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/ChangeLog +19 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +30 -0
- data/LICENSE +7 -0
- data/README.rdoc +85 -12
- data/Rakefile +5 -4
- data/lib/redland.rb +6 -2
- data/lib/redlander.rb +5 -3
- data/lib/redlander/model.rb +98 -16
- data/lib/redlander/model_proxy.rb +115 -58
- data/lib/redlander/node.rb +62 -59
- data/lib/redlander/parsing.rb +123 -0
- data/lib/redlander/serializing.rb +89 -0
- data/lib/redlander/statement.rb +61 -60
- data/lib/redlander/uri.rb +20 -13
- data/lib/redlander/version.rb +2 -1
- data/redlander.gemspec +28 -0
- data/spec/fixtures/doap.nt +62 -0
- data/spec/fixtures/doap.rdf +189 -0
- data/spec/fixtures/doap.ttl +53 -0
- data/spec/lib/redlander/model_spec.rb +304 -0
- data/spec/{redlander → lib/redlander}/node_spec.rb +26 -12
- data/spec/lib/redlander/statement_spec.rb +56 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +15 -4
- metadata +49 -37
- data/lib/redlander/error_container.rb +0 -42
- data/lib/redlander/parser.rb +0 -92
- data/lib/redlander/parser_proxy.rb +0 -22
- data/lib/redlander/serializer.rb +0 -85
- data/lib/redlander/storage.rb +0 -56
- data/lib/redlander/stream.rb +0 -57
- data/lib/redlander/stream_enumerator.rb +0 -17
- data/spec/redlander/model_spec.rb +0 -255
- data/spec/redlander/parser_spec.rb +0 -96
- data/spec/redlander/serializer_spec.rb +0 -52
- data/spec/redlander/statement_spec.rb +0 -77
data/.gitignore
ADDED
data/ChangeLog
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
redlander (0.4.0)
|
2
|
+
|
3
|
+
* deprecated Parser, Serializer, Storage, Stream and related classes and modules
|
4
|
+
* moved parsing and serialization methods to Model instance
|
5
|
+
* renamed parsing/serialization option :name to :format
|
6
|
+
* Redlander::Uri now explicitly belongs to private (internal) API
|
7
|
+
* ModelProxy (model.statements) is now Enumerable, with all benefits thereof
|
8
|
+
* Statement no longer has "valid?" method and "errors" container
|
9
|
+
* blank Nodes can be created with a given ID (:blank_id option)
|
10
|
+
* public methods for handling transactions
|
11
|
+
* URI is preferred over Redlander::Uri as method arguments or output,
|
12
|
+
e.g., Node#datatype, Node#uri and others return an instance of URI
|
13
|
+
* updated gem dependencies
|
14
|
+
* updated README and YARD documentation
|
15
|
+
* added LICENSE (MIT)
|
16
|
+
|
17
|
+
redlander (0.3.6)
|
18
|
+
|
19
|
+
... the dark ages ...
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
redlander (0.4.0)
|
5
|
+
ffi (~> 1.1)
|
6
|
+
xml_schema (~> 0.1.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
diff-lcs (1.1.3)
|
12
|
+
ffi (1.1.0)
|
13
|
+
rake (0.9.2.2)
|
14
|
+
rspec (2.11.0)
|
15
|
+
rspec-core (~> 2.11.0)
|
16
|
+
rspec-expectations (~> 2.11.0)
|
17
|
+
rspec-mocks (~> 2.11.0)
|
18
|
+
rspec-core (2.11.1)
|
19
|
+
rspec-expectations (2.11.1)
|
20
|
+
diff-lcs (~> 1.1.3)
|
21
|
+
rspec-mocks (2.11.1)
|
22
|
+
xml_schema (0.1.0)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
rake
|
29
|
+
redlander!
|
30
|
+
rspec (~> 2)
|
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2012 Slava Kravchenko
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
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 OR COPYRIGHT HOLDERS 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.
|
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
=
|
1
|
+
= Redlander
|
2
2
|
|
3
|
-
Redlander is Ruby bindings to Redland library (see http://librdf.org). This is an alternative implementation of the bindings, aiming to be more intuitive, lightweight and
|
3
|
+
Redlander is Ruby bindings to Redland library (see http://librdf.org) written in C, which is used to manipulate RDF graphs. This is an alternative implementation of Ruby bindings (as opposed to the official bindings), aiming to be more intuitive, lightweight, high-performing and as bug-free as possible.
|
4
4
|
|
5
5
|
= Installing
|
6
6
|
|
@@ -8,17 +8,21 @@ Installing Redlander is simple:
|
|
8
8
|
|
9
9
|
$ gem install redlander
|
10
10
|
|
11
|
-
Note, that you will have to install
|
11
|
+
Note, that you will have to install Redland runtime library (librdf) for Redlander to work.
|
12
12
|
|
13
13
|
= Usage
|
14
14
|
|
15
|
+
This README outlines most obvious use cases. For more details please refer to YARD documentation of Redlander.
|
16
|
+
|
15
17
|
To start doing anything useful with Redlander, you need to initialize a model first:
|
16
18
|
|
17
19
|
$ m = Redlander::Model.new
|
18
20
|
|
19
|
-
This creates a model where all RDF statements are stored in the memory. Depending on the selected storage you may need to supply extra parameters like :user or :password. Look-up the options for
|
21
|
+
This creates a model where all RDF statements are stored in the memory. Depending on the selected storage you may need to supply extra parameters like :user or :password. Look-up the options for Model.initialize for the list of available options.
|
20
22
|
Naturally, you don't need to create a model if you just want to play around with independent statements, nodes and the like.
|
21
23
|
|
24
|
+
== RDF Statements
|
25
|
+
|
22
26
|
Now that you have created a model, you can access its RDF statements:
|
23
27
|
|
24
28
|
$ m.statements
|
@@ -41,21 +45,90 @@ Most of Redlander functionality is accessable via these statements. The API is a
|
|
41
45
|
|
42
46
|
Finding statements:
|
43
47
|
|
44
|
-
m.statements.find(:first, :object => "subject!")
|
45
|
-
m.statements.all(:object => "another label")
|
46
|
-
m.statements.
|
47
|
-
|
48
|
-
|
48
|
+
$ m.statements.find(:first, :object => "subject!")
|
49
|
+
$ m.statements.all(:object => "another label")
|
50
|
+
$ m.statements.each(:object => "subject!") { |statement|
|
51
|
+
puts statement.subject
|
52
|
+
}
|
53
|
+
|
54
|
+
Note that "m.statements.each" is "lazy", while "m.statements.all" (and other finders) is not.
|
55
|
+
|
56
|
+
You can access the subject, predicate or object of a statement:
|
57
|
+
|
58
|
+
$ m.statements.first.subject # => (Redlander::Node)
|
59
|
+
|
60
|
+
Please refer to Redlander::Node API doc for details.
|
61
|
+
|
62
|
+
== Parsing Input
|
63
|
+
|
64
|
+
You can fill your model with statements by parsing some external sources like plain or streamed data.
|
65
|
+
|
66
|
+
$ data = File.read("data.xml")
|
67
|
+
$ m.from(data, :format => "rdfxml")
|
68
|
+
|
69
|
+
If the input is too large, you may prefer streaming it:
|
70
|
+
|
71
|
+
$ source = URI("http://example.com/data.nt")
|
72
|
+
$ m.from(source, :format => "ntriples")
|
73
|
+
|
74
|
+
If you want to get the data from a local file, you can use "file://" schema for your URI
|
75
|
+
(or Redlander::Uri) or use "from_file" method with a local file name (without schema):
|
76
|
+
|
77
|
+
$ m.from_file("../data.ttl", :format => "turtle")
|
78
|
+
|
79
|
+
Most frequently used parsing methods are aliased to save you some typing:
|
80
|
+
"from_rdfxml", "from_ntriples", "from_turtle", "from_uri/from_file".
|
81
|
+
|
82
|
+
Finally, you can filter the parsed input to prevent certain statements from getting into your model:
|
83
|
+
|
84
|
+
$ m.from_turtle(data) do |statement|
|
85
|
+
statement.object.value == "good"
|
86
|
+
end
|
87
|
+
|
88
|
+
If the block returns "false", the statement will not be added to the model.
|
89
|
+
The above example will add only statements having "literal" objects with a value of "good".
|
90
|
+
|
91
|
+
== Serializing Model
|
92
|
+
|
93
|
+
Naturally, you can convert your model into a portable syntax:
|
94
|
+
|
95
|
+
$ m.to(:format => "rdfxml") # => RDF/XML output
|
96
|
+
|
97
|
+
There are aliases as well: "to_rdfxml", "to_dot", etc.
|
98
|
+
|
99
|
+
You can also dump the output directly into a local file:
|
100
|
+
|
101
|
+
$ m.to_file("data.nt", :format => "ntriples")
|
102
|
+
|
103
|
+
== Transactions
|
104
|
+
|
105
|
+
It is possible to wrap all changes you perform on a model in a transaction,
|
106
|
+
if transactions are supported by the backend storage. If they are not supported,
|
107
|
+
all changes will be instantaneous.
|
108
|
+
|
109
|
+
$ m.transaction { m.statements.delete_all }
|
110
|
+
|
111
|
+
There are also dedicated methods to start, commit and rollback a transaction,
|
112
|
+
should you not be able to explicitly wrap your changes in a block:
|
113
|
+
|
114
|
+
$ m.transaction_start
|
115
|
+
$ m.delete_all
|
116
|
+
$ if lucky?
|
117
|
+
m.transaction_commit
|
118
|
+
else
|
119
|
+
m.transaction_rollback
|
120
|
+
end
|
49
121
|
|
50
|
-
|
122
|
+
All the above methods have their "banged" counterparts ("transaction_start!",
|
123
|
+
"transaction_commit!" and "transaction_rollback!") that would raise RedlandError
|
124
|
+
in case of an error.
|
51
125
|
|
52
|
-
For more details refer to the documentation of Model, Statement, Storage and other classes of Redlander.
|
53
126
|
|
54
127
|
= Exceptions
|
55
128
|
|
56
129
|
If anything unexpected happens, Redlander raises RedlandError.
|
57
130
|
|
58
|
-
= Authors
|
131
|
+
= Authors and Contributors
|
59
132
|
|
60
133
|
Slava Kravchenko <slava.kravchenko@gmail.com>
|
61
134
|
|
data/Rakefile
CHANGED
data/lib/redland.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
# @api private
|
1
2
|
# FFI bindings
|
2
|
-
|
3
3
|
module Redland
|
4
|
-
|
4
|
+
# Handling FFI difference between MRI and Rubinius
|
5
|
+
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
|
5
6
|
require 'ffi'
|
6
7
|
extend FFI::Library
|
7
8
|
ffi_lib "rdf.so.0"
|
@@ -52,6 +53,7 @@ module Redland
|
|
52
53
|
attach_function :librdf_node_is_resource, [:pointer], :int
|
53
54
|
attach_function :librdf_node_is_literal, [:pointer], :int
|
54
55
|
attach_function :librdf_node_is_blank, [:pointer], :int
|
56
|
+
attach_function :librdf_node_get_literal_value, [:pointer], :string
|
55
57
|
attach_function :librdf_node_get_literal_value_datatype_uri, [:pointer], :pointer
|
56
58
|
attach_function :librdf_node_equals, [:pointer, :pointer], :int
|
57
59
|
attach_function :librdf_node_to_string, [:pointer], :string
|
@@ -74,6 +76,7 @@ module Redland
|
|
74
76
|
attach_function :librdf_free_parser, [:pointer], :void
|
75
77
|
attach_function :librdf_parser_parse_into_model, [:pointer, :pointer, :pointer, :pointer], :int
|
76
78
|
attach_function :librdf_parser_parse_string_into_model, [:pointer, :string, :pointer, :pointer], :int
|
79
|
+
attach_function :librdf_parser_parse_as_stream, [:pointer, :pointer, :pointer], :pointer
|
77
80
|
attach_function :librdf_parser_parse_string_as_stream, [:pointer, :string, :pointer], :pointer
|
78
81
|
|
79
82
|
# URI
|
@@ -81,4 +84,5 @@ module Redland
|
|
81
84
|
attach_function :librdf_new_uri_from_uri, [:pointer], :pointer
|
82
85
|
attach_function :librdf_free_uri, [:pointer], :void
|
83
86
|
attach_function :librdf_uri_to_string, [:pointer], :string
|
87
|
+
attach_function :librdf_uri_equals, [:pointer, :pointer], :int
|
84
88
|
end
|
data/lib/redlander.rb
CHANGED
@@ -9,26 +9,28 @@ require 'redlander/node'
|
|
9
9
|
require 'redlander/model'
|
10
10
|
require 'redlander/statement'
|
11
11
|
|
12
|
+
# Main Redlander namespace
|
12
13
|
module Redlander
|
13
|
-
|
14
14
|
class << self
|
15
|
+
# @api private
|
15
16
|
def rdf_world
|
16
17
|
unless @rdf_world
|
17
18
|
@rdf_world = Redland.librdf_new_world
|
18
|
-
raise RedlandError
|
19
|
+
raise RedlandError, "Could not create a new RDF world" if @rdf_world.null?
|
19
20
|
ObjectSpace.define_finalizer(self, proc { Redland.librdf_free_world(@rdf_world) })
|
20
21
|
Redland.librdf_world_open(@rdf_world)
|
21
22
|
end
|
22
23
|
@rdf_world
|
23
24
|
end
|
24
25
|
|
26
|
+
# @api private
|
25
27
|
# Convert options hash into a string for librdf.
|
26
28
|
# What it does:
|
27
29
|
# 1) Convert boolean values into 'yes/no' values
|
28
30
|
# 2) Change underscores in key names into dashes ('dhar_ma' => 'dhar-ma')
|
29
31
|
# 3) Join all options as "key='value'" pairs in a comma-separated string
|
30
32
|
#
|
31
|
-
#
|
33
|
+
# @example
|
32
34
|
# to_rdf_options {:key => true, "key_board" => 3}
|
33
35
|
# # => "key='yes',key-board='3'"
|
34
36
|
def to_rdf_options(options = {})
|
data/lib/redlander/model.rb
CHANGED
@@ -1,22 +1,58 @@
|
|
1
|
-
require 'redlander/
|
2
|
-
require 'redlander/
|
3
|
-
require 'redlander/serializer'
|
1
|
+
require 'redlander/parsing'
|
2
|
+
require 'redlander/serializing'
|
4
3
|
require 'redlander/model_proxy'
|
5
4
|
|
6
5
|
module Redlander
|
6
|
+
# The core object incorporating the repository of RDF statements.
|
7
7
|
class Model
|
8
|
-
include Redlander::
|
9
|
-
include Redlander::
|
8
|
+
include Redlander::Parsing
|
9
|
+
include Redlander::Serializing
|
10
10
|
|
11
|
+
# @api private
|
11
12
|
attr_reader :rdf_model
|
12
13
|
|
13
14
|
# Create a new RDF model.
|
14
|
-
# For
|
15
|
+
# (For available storage options see http://librdf.org/docs/api/redland-storage-modules.html)
|
16
|
+
#
|
17
|
+
# @param [Hash] options
|
18
|
+
# @option options [String] :storage
|
19
|
+
# - "memory" - default, if :storage option is omitted,
|
20
|
+
# - "hashes"
|
21
|
+
# - "file" - memory model initialized from RDF/XML file,
|
22
|
+
# - "uri" - read-only memory model with URI provided in 'name' arg,
|
23
|
+
# - "mysql"
|
24
|
+
# - "sqlite"
|
25
|
+
# - "postgresql"
|
26
|
+
# - "tstore"
|
27
|
+
# - "virtuoso"
|
28
|
+
# - ... anything else that Redland can handle.
|
29
|
+
# @option options [String] :name storage identifier (DB file name or database name),
|
30
|
+
# @option options [String] :host database host name (for store types: :postgres, :mysql, :tstore),
|
31
|
+
# @option options [String] :port database host port (for store types: :postgres, :mysql, :tstore),
|
32
|
+
# @option options [String] :database database name (for store types: :postgres, :mysql, :tstore),
|
33
|
+
# @option options [String] :user database user name (for store types: :postgres, :mysql, :tstore),
|
34
|
+
# @option options [String] :password database user password (for store types: :postgres, :mysql, :tstore),
|
35
|
+
# @option options [String] :hash_type hash type (for store types: :bdb), can be either 'memory' or 'bdb',
|
36
|
+
# @option options [String] :new force creation of a new store,
|
37
|
+
# @option options [String] :dir directory path (for store types: :hashes),
|
38
|
+
# @option options [String] :contexts support contexts (for store types: :hashes, :memory),
|
39
|
+
# @option options [String] :write allow writing data to the store (for store types: :hashes),
|
40
|
+
# @option options [...] ... other storage-specific options.
|
41
|
+
# @raise [RedlandError] if it fails to create a storage or a model.
|
15
42
|
def initialize(options = {})
|
16
|
-
|
43
|
+
options = options.dup
|
44
|
+
storage_type = options.delete(:storage) || "memory"
|
45
|
+
storage_name = options.delete(:name)
|
46
|
+
|
47
|
+
@rdf_storage = Redland.librdf_new_storage(Redlander.rdf_world,
|
48
|
+
storage_type.to_s,
|
49
|
+
storage_name.to_s,
|
50
|
+
Redlander.to_rdf_options(options))
|
51
|
+
raise RedlandError, "Failed to initialize '#{storage_name}' storage (type: #{storage_type})" if @rdf_storage.null?
|
52
|
+
ObjectSpace.define_finalizer(self, proc { Redland.librdf_free_storage(@rdf_storage) })
|
17
53
|
|
18
|
-
@rdf_model = Redland.librdf_new_model(Redlander.rdf_world, @
|
19
|
-
raise RedlandError
|
54
|
+
@rdf_model = Redland.librdf_new_model(Redlander.rdf_world, @rdf_storage, "")
|
55
|
+
raise RedlandError, "Failed to create a new model" if @rdf_model.null?
|
20
56
|
ObjectSpace.define_finalizer(self, proc { Redland.librdf_free_model(@rdf_model) })
|
21
57
|
end
|
22
58
|
|
@@ -24,27 +60,73 @@ module Redlander
|
|
24
60
|
#
|
25
61
|
# Similar to Ruby on Rails, a proxy object is actually returned,
|
26
62
|
# which delegates methods to Statement class.
|
63
|
+
#
|
64
|
+
# @return [ModelProxy]
|
27
65
|
def statements
|
28
66
|
ModelProxy.new(self)
|
29
67
|
end
|
30
68
|
|
31
69
|
# Wrap changes to the given model in a transaction.
|
32
70
|
# If an exception is raised in the block, the transaction is rolled back.
|
33
|
-
#
|
71
|
+
#
|
72
|
+
# @note Does not work for all storages, in which case the changes are instanteous
|
73
|
+
#
|
74
|
+
# @yieldparam [void]
|
75
|
+
# @return [void]
|
34
76
|
def transaction
|
35
77
|
if block_given?
|
36
|
-
|
78
|
+
transaction_start
|
37
79
|
yield
|
38
|
-
|
80
|
+
transaction_commit
|
39
81
|
end
|
40
82
|
rescue
|
41
|
-
|
83
|
+
transaction_rollback
|
42
84
|
raise
|
43
85
|
end
|
44
86
|
|
45
|
-
#
|
46
|
-
|
47
|
-
|
87
|
+
# Start a transaction, if it is supported by the backend storage.
|
88
|
+
#
|
89
|
+
# @return [Boolean]
|
90
|
+
def transaction_start
|
91
|
+
Redland.librdf_model_transaction_start(@rdf_model).zero?
|
92
|
+
end
|
93
|
+
|
94
|
+
# Start a transaction.
|
95
|
+
#
|
96
|
+
# @raise [RedlandError] if it is not supported by the backend storage
|
97
|
+
# @return [true]
|
98
|
+
def transaction_start!
|
99
|
+
raise RedlandError, "Failed to initialize a transaction" unless transaction_start
|
100
|
+
end
|
101
|
+
|
102
|
+
# Commit a transaction, if it is supported by the backend storage.
|
103
|
+
#
|
104
|
+
# @return [Boolean]
|
105
|
+
def transaction_commit
|
106
|
+
Redland.librdf_model_transaction_commit(@rdf_model).zero?
|
107
|
+
end
|
108
|
+
|
109
|
+
# Commit a transaction.
|
110
|
+
#
|
111
|
+
# @raise [RedlandError] if it is not supported by the backend storage
|
112
|
+
# @return [true]
|
113
|
+
def transaction_commit!
|
114
|
+
raise RedlandError, "Failed to commit the transaction" unless transaction_commit
|
115
|
+
end
|
116
|
+
|
117
|
+
# Rollback a transaction, if it is supported by the backend storage.
|
118
|
+
#
|
119
|
+
# @return [Boolean]
|
120
|
+
def transaction_rollback
|
121
|
+
Redland.librdf_model_transaction_rollback(@rdf_model).zero?
|
122
|
+
end
|
123
|
+
|
124
|
+
# Rollback a transaction.
|
125
|
+
#
|
126
|
+
# @raise [RedlandError] if it is not supported by the backend storage
|
127
|
+
# @return [true]
|
128
|
+
def transaction_rollback!
|
129
|
+
raise RedlandError, "Failed to rollback the latest transaction" unless transaction_rollback
|
48
130
|
end
|
49
131
|
end
|
50
132
|
end
|
@@ -1,104 +1,161 @@
|
|
1
|
-
require 'redlander/stream'
|
2
|
-
require 'redlander/stream_enumerator'
|
3
|
-
|
4
1
|
module Redlander
|
2
|
+
# Proxy between model and its statements,
|
3
|
+
# allowing to scope actions on statements
|
4
|
+
# within a certain model.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# model = Redlander::Model.new
|
8
|
+
# model.statements
|
9
|
+
# # => ModelProxy
|
10
|
+
# model.statements.add(...)
|
11
|
+
# model.statements.each(...)
|
12
|
+
# model.statements.find(...)
|
13
|
+
# # etc...
|
5
14
|
class ModelProxy
|
6
|
-
include
|
15
|
+
include Enumerable
|
7
16
|
|
17
|
+
# @param [Redlander::Model] model
|
8
18
|
def initialize(model)
|
9
19
|
@model = model
|
10
20
|
end
|
11
21
|
|
12
22
|
# Add a statement to the model.
|
13
|
-
# It must be a complete statement - all of subject, predicate, object parts must be present.
|
14
|
-
# Only statements that are legal RDF can be added.
|
15
|
-
# If the statement already exists in the model, it is not added.
|
16
23
|
#
|
17
|
-
#
|
24
|
+
# @note
|
25
|
+
# All of subject, predicate, object nodes of the statement must be present.
|
26
|
+
# Only statements that are legal RDF can be added.
|
27
|
+
# If the statement already exists in the model, it is not added.
|
28
|
+
#
|
29
|
+
# @param [Statement] statement
|
30
|
+
# @return [Boolean]
|
18
31
|
def add(statement)
|
19
|
-
|
20
|
-
Redland.librdf_model_add_statement(@model.rdf_model, statement.rdf_statement).zero?
|
21
|
-
end
|
32
|
+
Redland.librdf_model_add_statement(@model.rdf_model, statement.rdf_statement).zero?
|
22
33
|
end
|
34
|
+
alias_method :<<, :add
|
23
35
|
|
24
|
-
# Delete a statement from the model
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
|
32
|
-
# :object
|
33
|
-
def delete(source)
|
34
|
-
statement = case source
|
35
|
-
when Statement
|
36
|
-
source
|
37
|
-
when Hash
|
38
|
-
Statement.new(source)
|
39
|
-
else
|
40
|
-
# TODO
|
41
|
-
raise NotImplementedError.new
|
42
|
-
end
|
36
|
+
# Delete a statement from the model.
|
37
|
+
#
|
38
|
+
# @note
|
39
|
+
# All of subject, predicate, object nodes of the statement must be present.
|
40
|
+
#
|
41
|
+
# @param [Statement] statement
|
42
|
+
# @return [Boolean]
|
43
|
+
def delete(statement)
|
43
44
|
Redland.librdf_model_remove_statement(@model.rdf_model, statement.rdf_statement).zero?
|
44
45
|
end
|
45
46
|
|
46
|
-
#
|
47
|
+
# Delete all statements from the model.
|
47
48
|
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
|
49
|
+
# @todo Fix this extremely ineffective (slow) implementation
|
50
|
+
# @return [Boolean]
|
51
|
+
def delete_all
|
52
|
+
each { |st| delete(st) }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Create a statement and add it to the model.
|
51
56
|
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
+
# @param [Hash] source subject, predicate and object nodes
|
58
|
+
# of the statement to be created (see Statement#initialize).
|
59
|
+
# @option source [Node, URI, String, nil] :subject
|
60
|
+
# @option source [Node, URI, String, nil] :predicate
|
61
|
+
# @option source [Node, URI, String, nil] :object
|
62
|
+
# @return [Statement, nil]
|
63
|
+
def create(source)
|
64
|
+
statement = Statement.new(source)
|
65
|
+
add(statement) ? statement : nil
|
57
66
|
end
|
58
67
|
|
68
|
+
# Checks whether there are no statements in the model.
|
69
|
+
#
|
70
|
+
# @return [Boolean]
|
59
71
|
def empty?
|
60
72
|
size.zero?
|
61
73
|
end
|
62
74
|
|
75
|
+
# Size of the model in statements.
|
76
|
+
#
|
77
|
+
# @note
|
78
|
+
# While #count must iterate across all statements in the model,
|
79
|
+
# {#size} tries to use a more efficient C implementation.
|
80
|
+
# So {#size} should be preferred to #count in terms of performance.
|
81
|
+
# However, for non-countable storages, {#size} falls back to
|
82
|
+
# using #count. Also, {#size} is not available for enumerables
|
83
|
+
# (e.g. produced from {#each} (without a block) or otherwise) and
|
84
|
+
# thus cannot be used to count "filtered" results.
|
85
|
+
#
|
86
|
+
# @return [Fixnum]
|
63
87
|
def size
|
64
88
|
s = Redland.librdf_model_size(@model.rdf_model)
|
65
|
-
|
66
|
-
|
89
|
+
s < 0 ? count : s
|
90
|
+
end
|
91
|
+
|
92
|
+
# Enumerate (and filter) model statements.
|
93
|
+
# If given no block, returns Enumerator.
|
94
|
+
#
|
95
|
+
# @param [Statement, Hash, void] args
|
96
|
+
# if given Statement or Hash, filter the model statements
|
97
|
+
# according to the specified pattern (see {#find} options).
|
98
|
+
# @yieldparam [Statement]
|
99
|
+
# @return [void]
|
100
|
+
def each(*args)
|
101
|
+
if block_given?
|
102
|
+
rdf_stream =
|
103
|
+
if args.empty?
|
104
|
+
Redland.librdf_model_as_stream(@model.rdf_model)
|
105
|
+
else
|
106
|
+
pattern = args.first.is_a?(Statement) ? args.first.rdf_statement : Statement.new(args.first)
|
107
|
+
Redland.librdf_model_find_statements(@model.rdf_model, pattern.rdf_statement)
|
108
|
+
end
|
109
|
+
raise RedlandError, "Failed to create a new stream" if rdf_stream.null?
|
110
|
+
|
111
|
+
begin
|
112
|
+
while Redland.librdf_stream_end(rdf_stream).zero?
|
113
|
+
statement = Statement.new(Redland.librdf_stream_get_object(rdf_stream))
|
114
|
+
yield statement
|
115
|
+
Redland.librdf_stream_next(rdf_stream)
|
116
|
+
end
|
117
|
+
ensure
|
118
|
+
Redland.librdf_free_stream(rdf_stream)
|
119
|
+
end
|
67
120
|
else
|
68
|
-
|
121
|
+
enum_for(:each, *args)
|
69
122
|
end
|
70
123
|
end
|
71
124
|
|
72
125
|
# Find statements satisfying the given criteria.
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
|
77
|
-
|
78
|
-
|
126
|
+
#
|
127
|
+
# @param [:first, :all] scope find just one or all matches
|
128
|
+
# @param [Hash, Statement] options matching pattern made of:
|
129
|
+
# - Hash with :subject, :predicate or :object nodes, or
|
130
|
+
# - "patternized" Statement (nil nodes are matching anything).
|
131
|
+
# @return [Statement, Array, nil]
|
132
|
+
def find(scope, options = {})
|
79
133
|
case scope
|
80
134
|
when :first
|
81
|
-
|
135
|
+
each(options).first
|
82
136
|
when :all
|
83
|
-
|
137
|
+
each(options).to_a
|
84
138
|
else
|
85
|
-
raise RedlandError
|
139
|
+
raise RedlandError, "Invalid search scope '#{scope}' specified."
|
86
140
|
end
|
87
141
|
end
|
88
142
|
|
143
|
+
# Find a first statement matching the given criteria.
|
144
|
+
# (Shortcut for {#find}(:first, options)).
|
145
|
+
#
|
146
|
+
# @param [Hash] options (see {#find})
|
147
|
+
# @return [Statement, nil]
|
89
148
|
def first(options = {})
|
90
149
|
find(:first, options)
|
91
150
|
end
|
92
151
|
|
152
|
+
# Find all statements matching the given criteria.
|
153
|
+
# (Shortcut for {#find}(:all, options)).
|
154
|
+
#
|
155
|
+
# @param [Hash] options (see {#find})
|
156
|
+
# @return [Array<Statement>]
|
93
157
|
def all(options = {})
|
94
158
|
find(:all, options)
|
95
159
|
end
|
96
|
-
|
97
|
-
|
98
|
-
private
|
99
|
-
|
100
|
-
def reset_stream
|
101
|
-
@stream = Stream.new(@model)
|
102
|
-
end
|
103
160
|
end
|
104
161
|
end
|