rdf 0.1.10 → 0.2.0

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.
@@ -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