rdf 0.1.10 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,35 +13,67 @@ module RDF
13
13
  ##
14
14
  # Queries `self` for RDF statements matching the given `pattern`.
15
15
  #
16
+ # This method delegates to the protected {#query_pattern} method for the
17
+ # actual lower-level query pattern matching implementation.
18
+ #
16
19
  # @example
17
20
  # queryable.query([nil, RDF::DOAP.developer, nil])
18
21
  # queryable.query(:predicate => RDF::DOAP.developer)
19
22
  #
20
23
  # @param [Query, Statement, Array(Value), Hash] pattern
21
24
  # @yield [statement]
22
- # @yieldparam [Statement]
23
- # @return [Array<Statement>]
25
+ # @yieldparam [RDF::Statement]
26
+ # @return [Enumerator<RDF::Statement>]
27
+ # @see RDF::Queryable#query_pattern
24
28
  def query(pattern, &block)
25
29
  raise TypeError.new("#{self} is not readable") if respond_to?(:readable?) && !readable?
26
30
 
27
31
  case pattern
28
32
  when Query
29
33
  pattern.execute(self, &block)
30
- when Array
31
- query(Statement.new(*pattern), &block)
32
- when Hash
33
- query(Statement.new(pattern), &block)
34
- when Statement
34
+ else
35
+ pattern = case pattern
36
+ when Query::Pattern, Statement then pattern
37
+ when Array then Query::Pattern.new(*pattern)
38
+ when Hash then Query::Pattern.new(pattern)
39
+ else raise ArgumentError.new("expected RDF::Query, RDF::Query::Pattern, Array, or Hash, but got #{pattern.inspect}")
40
+ end
41
+
35
42
  if block_given?
36
- find_all { |statement| pattern === statement }.each(&block)
43
+ query_pattern(pattern, &block)
44
+ return nil
37
45
  else
38
- find_all { |statement| pattern === statement }.extend(RDF::Enumerable, RDF::Queryable)
46
+ enum = enum_for(:query_pattern, pattern)
47
+ enum.extend(RDF::Queryable, RDF::Enumerable, RDF::Countable)
48
+ def enum.to_a
49
+ super.extend(RDF::Queryable, RDF::Enumerable, RDF::Countable)
50
+ end
51
+ return enum
39
52
  end
40
- else
41
- raise ArgumentError.new("expected RDF::Query, RDF::Pattern, Array or Hash, but got #{pattern.inspect}")
42
53
  end
43
54
  end
44
55
 
56
+ ##
57
+ # Queries `self` for RDF statements matching the given `pattern`,
58
+ # yielding each matched statement to the given block.
59
+ #
60
+ # Since RDF.rb 0.2.0, this is the preferred method that subclasses of
61
+ # `RDF::Repository` should override in order to provide an optimized
62
+ # query implementation.
63
+ #
64
+ # @param [RDF::Query::Pattern] pattern
65
+ # @yield [statement]
66
+ # @yieldparam [RDF::Statement]
67
+ # @return [void]
68
+ # @see RDF::Queryable#query
69
+ # @since 0.2.0
70
+ def query_pattern(pattern, &block)
71
+ # @see http://ruby-doc.org/core/classes/Enumerable.html#M003121
72
+ grep(pattern, &block)
73
+ end
74
+
75
+ protected :query_pattern
76
+
45
77
  ##
46
78
  # Queries `self` for an RDF statement matching the given `pattern` and
47
79
  # returns that statement if found.
@@ -1,6 +1,8 @@
1
1
  module RDF
2
2
  ##
3
3
  module Readable
4
+ extend RDF::Util::Aliasing::LateBound
5
+
4
6
  ##
5
7
  # Returns `true` if `self` is readable.
6
8
  #
@@ -1,6 +1,8 @@
1
1
  module RDF
2
2
  ##
3
3
  module Writable
4
+ extend RDF::Util::Aliasing::LateBound
5
+
4
6
  ##
5
7
  # Returns `true` if `self` is writable.
6
8
  #
@@ -9,5 +11,133 @@ module RDF
9
11
  def writable?
10
12
  true
11
13
  end
14
+
15
+ ##
16
+ # Inserts RDF data into `self`.
17
+ #
18
+ # @param [RDF::Enumerable, RDF::Statement, #to_rdf] data
19
+ # @return [Writable]
20
+ def <<(data)
21
+ case data
22
+ when RDF::Graph
23
+ insert_graph(data)
24
+ when RDF::Enumerable
25
+ insert_statements(data)
26
+ when RDF::Statement
27
+ insert_statement(data)
28
+ else case
29
+ when data.respond_to?(:to_rdf) && !data.equal?(rdf = data.to_rdf)
30
+ self << rdf
31
+ else
32
+ insert_statement(create_statement(data))
33
+ end
34
+ end
35
+
36
+ return self
37
+ end
38
+
39
+ ##
40
+ # Inserts RDF statements into `self`.
41
+ #
42
+ # @param [Array<RDF::Statement>] statements
43
+ # @return [Writable]
44
+ def insert(*statements)
45
+ statements.map! do |value|
46
+ case
47
+ when value.respond_to?(:each_statement)
48
+ insert_statements(value)
49
+ nil
50
+ when (statement = create_statement(value)).valid?
51
+ statement
52
+ else
53
+ raise ArgumentError.new("not a valid statement: #{value.inspect}")
54
+ end
55
+ end
56
+ statements.compact!
57
+ insert_statements(statements) unless statements.empty?
58
+
59
+ return self
60
+ end
61
+
62
+ alias_method :insert!, :insert
63
+
64
+ protected
65
+
66
+ ##
67
+ # Inserts the given RDF graph into the underlying storage or output
68
+ # stream.
69
+ #
70
+ # Defaults to passing the graph to the {#insert_statements} method.
71
+ #
72
+ # Subclasses of {RDF::Repository} may wish to override this method in
73
+ # case their underlying storage architecture is graph-centric rather
74
+ # than statement-oriented.
75
+ #
76
+ # Subclasses of {RDF::Writer} may wish to override this method if the
77
+ # output format they implement supports named graphs, in which case
78
+ # implementing this method may help in producing prettier and more
79
+ # concise output.
80
+ #
81
+ # @param [RDF::Graph] graph
82
+ # @return [void]
83
+ def insert_graph(graph)
84
+ insert_statements(graph)
85
+ end
86
+
87
+ ##
88
+ # Inserts the given RDF statements into the underlying storage or output
89
+ # stream.
90
+ #
91
+ # Defaults to invoking {#insert_statement} for each given statement.
92
+ #
93
+ # Subclasses of {RDF::Repository} may wish to override this method if
94
+ # they are capable of more efficiently inserting multiple statements at
95
+ # once.
96
+ #
97
+ # Subclasses of {RDF::Writer} don't generally need to implement this
98
+ # method.
99
+ #
100
+ # @param [RDF::Enumerable] statements
101
+ # @return [void]
102
+ def insert_statements(statements)
103
+ each = statements.respond_to?(:each_statement) ? :each_statement : :each
104
+ statements.__send__(each) do |statement|
105
+ insert_statement(statement)
106
+ end
107
+ end
108
+
109
+ ##
110
+ # Inserts an RDF statement into the underlying storage or output stream.
111
+ #
112
+ # Subclasses of {RDF::Repository} must implement this method, except if
113
+ # they are immutable.
114
+ #
115
+ # Subclasses of {RDF::Writer} must implement this method.
116
+ #
117
+ # @param [RDF::Statement] statement
118
+ # @return [void]
119
+ # @abstract
120
+ def insert_statement(statement)
121
+ raise NotImplementedError.new("#{self.class}#insert_statement")
122
+ end
123
+
124
+ ##
125
+ # Transforms various input into an `RDF::Statement` instance.
126
+ #
127
+ # @param [RDF::Statement, Hash, Array, #to_a] statement
128
+ # @return [RDF::Statement]
129
+ def create_statement(statement)
130
+ # TODO: move this to RDF::Statement.construct or the like.
131
+ case statement
132
+ when Statement then statement
133
+ when Hash then Statement.new(statement)
134
+ when Array then Statement.new(*statement)
135
+ else raise ArgumentError.new # FIXME
136
+ end
137
+ end
138
+
139
+ protected :insert_statements
140
+ protected :insert_statement
141
+ protected :create_statement
12
142
  end
13
143
  end
@@ -19,17 +19,26 @@ module RDF
19
19
  #
20
20
  # graph = RDF::Graph.load("http://www.bbc.co.uk/programmes/b0081dq5.rdf")
21
21
  #
22
- class Graph < Resource
22
+ class Graph
23
+ include RDF::Resource
24
+
25
+ include RDF::Countable
23
26
  include RDF::Enumerable
24
- include RDF::Mutable
25
27
  include RDF::Queryable
28
+ include RDF::Mutable
26
29
 
27
30
  ##
28
- # @return [Resource]
31
+ # Returns the options passed to this graph when it was constructed.
32
+ #
33
+ # @return [Hash{Symbol => Object}]
34
+ attr_reader :options
35
+
36
+ ##
37
+ # @return [RDF::Resource]
29
38
  attr_accessor :context
30
39
 
31
40
  ##
32
- # @return [Array<Statement>]
41
+ # @return [RDF::Queryable]
33
42
  attr_accessor :data
34
43
 
35
44
  ##
@@ -56,7 +65,7 @@ module RDF
56
65
  end
57
66
 
58
67
  ##
59
- # @param [Resource] context
68
+ # @param [RDF::Resource] context
60
69
  # @param [Hash{Symbol => Object}] options
61
70
  # @yield [graph]
62
71
  # @yieldparam [Graph]
@@ -68,7 +77,7 @@ module RDF
68
77
  end
69
78
 
70
79
  @options = options.dup
71
- @data = @options.delete(:data) || []
80
+ @data = @options.delete(:data) || RDF::Repository.new
72
81
 
73
82
  if block_given?
74
83
  case block.arity
@@ -115,15 +124,15 @@ module RDF
115
124
  ##
116
125
  # Returns all unique RDF contexts for this graph.
117
126
  #
118
- # @return [Array<Resource>]
127
+ # @return [Enumerator<RDF::Resource>]
119
128
  def contexts
120
- named? ? [context] : []
129
+ (named? ? [context] : []).to_enum.extend(RDF::Countable)
121
130
  end
122
131
 
123
132
  ##
124
133
  # Returns the URI representation of this graph.
125
134
  #
126
- # @return [URI]
135
+ # @return [RDF::URI]
127
136
  def to_uri
128
137
  context
129
138
  end
@@ -145,13 +154,21 @@ module RDF
145
154
  @data.empty?
146
155
  end
147
156
 
157
+ ##
158
+ # Returns `true` if this graph has an anonymous context, `false` otherwise.
159
+ #
160
+ # @return [Boolean]
161
+ def anonymous?
162
+ context.nil? ? false : context.anonymous?
163
+ end
164
+
148
165
  ##
149
166
  # Returns the number of RDF statements in this graph.
150
167
  #
151
168
  # @return [Integer]
152
169
  # @see RDF::Enumerable#count
153
170
  def count
154
- @data.size
171
+ @data.query(:context => context).count
155
172
  end
156
173
 
157
174
  ##
@@ -163,7 +180,7 @@ module RDF
163
180
  def has_statement?(statement)
164
181
  statement = statement.dup
165
182
  statement.context = context
166
- @data.include?(statement)
183
+ @data.has_statement?(statement)
167
184
  end
168
185
 
169
186
  ##
@@ -174,7 +191,7 @@ module RDF
174
191
  # @return [Enumerator]
175
192
  # @see RDF::Enumerable#each_statement
176
193
  def each(&block)
177
- @data.each(&block)
194
+ @data.query(:context => context).each(&block)
178
195
  end
179
196
 
180
197
  ##
@@ -186,7 +203,7 @@ module RDF
186
203
  def insert_statement(statement)
187
204
  statement = statement.dup
188
205
  statement.context = context
189
- @data.push(statement.dup) unless @data.include?(statement)
206
+ @data.insert(statement)
190
207
  end
191
208
 
192
209
  ##
@@ -207,11 +224,27 @@ module RDF
207
224
  # @return [void]
208
225
  # @see RDF::Mutable#clear
209
226
  def clear_statements
210
- @data.clear
227
+ @data.delete(:context => context)
211
228
  end
212
229
 
213
230
  protected :insert_statement
214
231
  protected :delete_statement
215
232
  protected :clear_statements
233
+
234
+ ##
235
+ # @private
236
+ # @see RDF::Enumerable#graphs
237
+ # @since 0.2.0
238
+ def graphs
239
+ enum_graph
240
+ end
241
+
242
+ ##
243
+ # @private
244
+ # @see RDF::Enumerable#each_graph
245
+ # @since 0.2.0
246
+ def each_graph(&block)
247
+ block_given? ? block.call(self) : enum_graph
248
+ end
216
249
  end
217
250
  end
@@ -38,7 +38,9 @@ module RDF
38
38
  #
39
39
  # @see http://www.w3.org/TR/rdf-concepts/#section-Literals
40
40
  # @see http://www.w3.org/TR/rdf-concepts/#section-Datatypes-intro
41
- class Literal < Value
41
+ class Literal
42
+ include RDF::Value
43
+
42
44
  # @return [String] The normalized string representation of the value.
43
45
  attr_accessor :value
44
46
 
@@ -57,7 +59,7 @@ module RDF
57
59
  @language = options[:language] ? options[:language].to_s.to_sym : nil
58
60
 
59
61
  if datatype = options[:datatype]
60
- @datatype = datatype.respond_to?(:to_uri) ? datatype.to_uri : URI.new(datatype.to_s)
62
+ @datatype = datatype.respond_to?(:to_uri) ? datatype.to_uri : URI.intern(datatype.to_s)
61
63
  else
62
64
  @datatype = case value
63
65
  when String then nil # implicit XSD.string
@@ -137,6 +139,14 @@ module RDF
137
139
  true
138
140
  end
139
141
 
142
+ ##
143
+ # Returns `false`.
144
+ #
145
+ # @return [Boolean]
146
+ def anonymous?
147
+ false
148
+ end
149
+
140
150
  ##
141
151
  # @return [Boolean]
142
152
  def eql?(other)
@@ -11,7 +11,9 @@ module RDF
11
11
  #
12
12
  # @see http://rubygems.org/gems/uuid
13
13
  # @see http://rubygems.org/gems/uuidtools
14
- class Node < Resource
14
+ class Node
15
+ include RDF::Resource
16
+
15
17
  ##
16
18
  # Returns a blank node with a random UUID-based identifier.
17
19
  #
@@ -30,6 +32,17 @@ module RDF
30
32
  end
31
33
  end
32
34
 
35
+ ##
36
+ # Alias for `RDF::Node.new`, at the moment.
37
+ #
38
+ # @private
39
+ # @param [#to_s] id
40
+ # @return [RDF::Node]
41
+ # @since 0.2.0
42
+ def self.intern(id)
43
+ self.new(id)
44
+ end
45
+
33
46
  # @return [String]
34
47
  attr_accessor :id
35
48
 
@@ -65,12 +78,48 @@ module RDF
65
78
  !unlabeled?
66
79
  end
67
80
 
81
+ ##
82
+ # Returns a hash code for this blank node.
83
+ #
84
+ # @return [Fixnum]
85
+ def hash
86
+ @id.hash
87
+ end
88
+
89
+ ##
90
+ # Checks whether this blank node is equal to `other`.
91
+ #
92
+ # @param [Node] other
93
+ # @return [Boolean]
94
+ def eql?(other)
95
+ other.is_a?(Node) && self == other
96
+ end
97
+
98
+ ##
99
+ # Checks whether this blank node is equal to `other`.
100
+ #
101
+ # @param [Object] other
102
+ # @return [Boolean]
103
+ def ==(other)
104
+ other.respond_to?(:node?) && other.node? &&
105
+ other.respond_to?(:id) && @id == other.id
106
+ end
107
+
68
108
  ##
69
109
  # Returns a string representation of this blank node.
70
110
  #
71
111
  # @return [String]
72
112
  def to_s
73
- "_:%s" % id.to_s
113
+ "_:%s" % @id.to_s
114
+ end
115
+
116
+ ##
117
+ # Returns a symbol representation of this blank node.
118
+ #
119
+ # @return [Symbol]
120
+ # @since 0.2.0
121
+ def to_sym
122
+ @id.to_s.to_sym
74
123
  end
75
124
  end
76
125
  end