rdf 0.1.10 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,131 @@
1
+ module RDF; module Util
2
+ ##
3
+ # A `Hash`-like cache that holds only weak references to the values it
4
+ # caches, meaning that values contained in the cache can be garbage
5
+ # collected. This allows the cache to dynamically adjust to changing
6
+ # memory conditions, caching more objects when memory is plentiful, but
7
+ # evicting most objects if memory pressure increases to the point of
8
+ # scarcity.
9
+ #
10
+ # @see RDF::URI.intern
11
+ # @see http://en.wikipedia.org/wiki/Weak_reference
12
+ # @since 0.2.0
13
+ class Cache
14
+ ##
15
+ # @private
16
+ def self.new(*args)
17
+ # JRuby doesn't support `ObjectSpace#_id2ref` unless the `-X+O`
18
+ # startup option is given, so on that platform we'll default to using
19
+ # the WeakRef-based cache:
20
+ klass = case RUBY_PLATFORM
21
+ when /java/ then WeakRefCache
22
+ else ObjectSpaceCache
23
+ end
24
+ cache = klass.allocate
25
+ cache.send(:initialize, *args)
26
+ cache
27
+ end
28
+
29
+ ##
30
+ # @param [Integer] capacity
31
+ def initialize(capacity = -1)
32
+ @capacity = capacity
33
+ @cache ||= {}
34
+ @index ||= {}
35
+ end
36
+
37
+ ##
38
+ # @return [Integer]
39
+ def size
40
+ @cache.size
41
+ end
42
+
43
+ ##
44
+ # @return [Boolean]
45
+ def has_capacity?
46
+ @capacity == -1 || @capacity > @cache.size
47
+ end
48
+
49
+ ##
50
+ # @param [Object] value
51
+ # @return [void]
52
+ def define_finalizer!(value)
53
+ ObjectSpace.define_finalizer(value, finalizer)
54
+ end
55
+
56
+ ##
57
+ # @return [Proc]
58
+ def finalizer
59
+ lambda { |object_id| @cache.delete(@index.delete(object_id)) }
60
+ end
61
+
62
+ ##
63
+ # This implementation relies on `ObjectSpace#_id2ref` and performs
64
+ # optimally on Ruby 1.8.x and 1.9.x; however, it does not work on JRuby
65
+ # by default since much `ObjectSpace` functionality on that platform is
66
+ # disabled unless the `-X+O` startup option is given.
67
+ #
68
+ # @see http://ruby-doc.org/ruby-1.9/classes/ObjectSpace.html
69
+ # @see http://eigenclass.org/hiki/weakhash+and+weakref
70
+ class ObjectSpaceCache < Cache
71
+ ##
72
+ # @param [Object] key
73
+ # @return [Object]
74
+ def [](key)
75
+ if value_id = @cache[key]
76
+ value = ObjectSpace._id2ref(value_id)
77
+ end
78
+ end
79
+
80
+ ##
81
+ # @param [Object] key
82
+ # @param [Object] value
83
+ # @return [Object]
84
+ def []=(key, value)
85
+ if has_capacity?
86
+ @cache[key] = value.object_id
87
+ @index[value.object_id] = key
88
+ define_finalizer!(value)
89
+ end
90
+ value
91
+ end
92
+ end # class ObjectSpaceCache
93
+
94
+ ##
95
+ # This implementation uses the `WeakRef` class from Ruby's standard
96
+ # library, and provides adequate performance on JRuby and on Ruby 1.9.x;
97
+ # however, it performs very suboptimally on Ruby 1.8.x.
98
+ #
99
+ # @see http://ruby-doc.org/ruby-1.9/classes/WeakRef.html
100
+ class WeakRefCache < Cache
101
+ ##
102
+ # @param [Integer] capacity
103
+ def initialize(capacity = -1)
104
+ require 'weakref' unless defined?(::WeakRef)
105
+ super
106
+ end
107
+
108
+ ##
109
+ # @param [Object] key
110
+ # @return [Object]
111
+ def [](key)
112
+ if (ref = @cache[key]) && ref.weakref_alive?
113
+ value = ref.__getobj__
114
+ end
115
+ end
116
+
117
+ ##
118
+ # @param [Object] key
119
+ # @param [Object] value
120
+ # @return [Object]
121
+ def []=(key, value)
122
+ if has_capacity?
123
+ @cache[key] = WeakRef.new(value)
124
+ @index[value.object_id] = key
125
+ define_finalizer!(value)
126
+ end
127
+ value
128
+ end
129
+ end # class WeakRefCache
130
+ end # class Cache
131
+ end; end # module RDF::Util
@@ -1,12 +1,11 @@
1
1
  module RDF
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 1
5
- TINY = 10
4
+ MINOR = 2
5
+ TINY = 0
6
6
  EXTRA = nil
7
7
 
8
- STRING = [MAJOR, MINOR, TINY].join('.')
9
- STRING << ".#{EXTRA}" if EXTRA
8
+ STRING = [MAJOR, MINOR, TINY, EXTRA].compact.join('.')
10
9
 
11
10
  ##
12
11
  # @return [String]
@@ -7,14 +7,17 @@ module RDF
7
7
  # The following vocabularies are pre-defined for your convenience:
8
8
  #
9
9
  # * {RDF::CC} - Creative Commons (CC)
10
+ # * {RDF::CERT} - W3 Authentication Certificate (CERT)
10
11
  # * {RDF::DC} - Dublin Core (DC)
11
12
  # * {RDF::DC11} - Dublin Core 1.1 (DC11) _deprecated_
12
13
  # * {RDF::DOAP} - Description of a Project (DOAP)
13
14
  # * {RDF::EXIF} - Exchangeable Image File Format (EXIF)
14
15
  # * {RDF::FOAF} - Friend of a Friend (FOAF)
16
+ # * {RDF::GEO} - WGS84 Geo Positioning (GEO)
15
17
  # * {RDF::HTTP} - Hypertext Transfer Protocol (HTTP)
16
18
  # * {RDF::OWL} - Web Ontology Language (OWL)
17
19
  # * {RDF::RDFS} - RDF Schema (RDFS)
20
+ # * {RDF::RSA} - W3 RSA Keys (RSA)
18
21
  # * {RDF::RSS} - RDF Site Summary (RSS)
19
22
  # * {RDF::SIOC} - Semantically-Interlinked Online Communities (SIOC)
20
23
  # * {RDF::SKOS} - Simple Knowledge Organization System (SKOS)
@@ -52,11 +55,9 @@ module RDF
52
55
  def self.each(&block)
53
56
  if self.equal?(Vocabulary)
54
57
  # This is needed since all vocabulary classes are defined using
55
- # Ruby's autoloading facility, meaning that `@@subclasses` will
56
- # be empty until each subclass has been touched or require'd.
57
- %w(cc dc dc11 doap exif foaf http owl rdfs rss sioc skos wot xhtml xsd).each do |prefix|
58
- require "rdf/vocab/#{prefix}"
59
- end
58
+ # Ruby's autoloading facility, meaning that `@@subclasses` will be
59
+ # empty until each subclass has been touched or require'd.
60
+ RDF::VOCABS.each { |v| require "rdf/vocab/#{v}" unless v == :rdf }
60
61
  @@subclasses.each(&block)
61
62
  else
62
63
  # TODO: should enumerate vocabulary-specific defined properties.
@@ -79,7 +80,7 @@ module RDF
79
80
  # @param [#to_s] property
80
81
  # @return [URI]
81
82
  def self.[](property)
82
- RDF::URI.new([to_s, property.to_s].join(''))
83
+ RDF::URI.intern([to_s, property.to_s].join(''))
83
84
  end
84
85
 
85
86
  ##
@@ -87,7 +88,7 @@ module RDF
87
88
  #
88
89
  # @return [URI]
89
90
  def self.to_uri
90
- RDF::URI.new(to_s)
91
+ RDF::URI.intern(to_s)
91
92
  end
92
93
 
93
94
  ##
@@ -117,7 +118,7 @@ module RDF
117
118
  end
118
119
 
119
120
  # Undefine all superfluous instance methods:
120
- undef_method *(instance_methods.map { |s| s.to_sym } - [:__id__, :__send__, :__class__, :__eval__, :object_id, :instance_eval, :inspect, :class, :is_a?])
121
+ undef_method(*(instance_methods.map(&:to_sym) - [:__id__, :__send__, :__class__, :__eval__, :object_id, :instance_eval, :inspect, :class, :is_a?]))
121
122
 
122
123
  ##
123
124
  # @param [URI, String, #to_s]
@@ -134,7 +135,7 @@ module RDF
134
135
  # @param [#to_s] property
135
136
  # @return [URI]
136
137
  def [](property)
137
- RDF::URI.new([to_s, property.to_s].join(''))
138
+ RDF::URI.intern([to_s, property.to_s].join(''))
138
139
  end
139
140
 
140
141
  ##
@@ -142,7 +143,7 @@ module RDF
142
143
  #
143
144
  # @return [URI]
144
145
  def to_uri
145
- RDF::URI.new(to_s)
146
+ RDF::URI.intern(to_s)
146
147
  end
147
148
 
148
149
  ##
@@ -0,0 +1,13 @@
1
+ module RDF
2
+ ##
3
+ # W3 Authentication Certificates (CERT) vocabulary.
4
+ #
5
+ # @see http://www.w3.org/ns/auth/cert#
6
+ # @since 0.2.0
7
+ class CERT < Vocabulary("http://www.w3.org/ns/auth/cert#")
8
+ property :decimal
9
+ property :hex
10
+ property :identity
11
+ property :public_key
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module RDF
2
+ ##
3
+ # WGS84 Geo Positioning (GEO) vocabulary.
4
+ #
5
+ # @see http://www.w3.org/2003/01/geo/wgs84_pos#
6
+ # @since 0.2.0
7
+ class GEO < Vocabulary("http://www.w3.org/2003/01/geo/wgs84_pos#")
8
+ property :lat
9
+ property :location
10
+ property :long
11
+ property :lat_long
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module RDF
2
+ ##
3
+ # W3 RSA Keys (RSA) vocabulary.
4
+ #
5
+ # @see http://www.w3.org/ns/auth/rsa#
6
+ # @since 0.2.0
7
+ class RSA < Vocabulary("http://www.w3.org/ns/auth/rsa#")
8
+ property :modulus
9
+ property :private_exponent
10
+ property :public_exponent
11
+ end
12
+ end
@@ -34,7 +34,7 @@ module RDF
34
34
  # @see RDF::Reader
35
35
  class Writer
36
36
  extend ::Enumerable
37
- include ::Enumerable
37
+ include RDF::Writable
38
38
 
39
39
  ##
40
40
  # Enumerates known RDF writer classes.
@@ -96,24 +96,34 @@ module RDF
96
96
  alias_method :format_class, :format
97
97
  end
98
98
 
99
+ ##
100
+ # @param [Object] data
101
+ # @param [IO, File] io
102
+ # @param [Hash{Symbol => Object}] options
103
+ # @return [void]
99
104
  def self.dump(data, io = nil, options = {})
100
105
  io = File.open(io, 'w') if io.is_a?(String)
106
+ method = data.respond_to?(:each_statement) ? :each_statement : :each
101
107
  if io
102
108
  new(io) do |writer|
103
- data.each_statement do |statement|
109
+ data.send(method) do |statement|
104
110
  writer << statement
105
111
  end
106
112
  writer.flush
107
113
  end
108
114
  else
109
115
  buffer do |writer|
110
- data.each_statement do |statement|
116
+ data.send(method) do |statement|
111
117
  writer << statement
112
118
  end
113
119
  end
114
120
  end
115
121
  end
116
122
 
123
+ ##
124
+ # @yield [writer]
125
+ # @yieldparam [Writer] writer
126
+ # @return [String]
117
127
  def self.buffer(*args, &block)
118
128
  require 'stringio' unless defined?(StringIO)
119
129
 
@@ -123,6 +133,10 @@ module RDF
123
133
  end
124
134
  end
125
135
 
136
+ ##
137
+ # @param [String] filename
138
+ # @param [Hash{Symbol => Object}] options
139
+ # @return [Writer]
126
140
  def self.open(filename, options = {}, &block)
127
141
  File.open(filename, 'wb') do |file|
128
142
  self.for(options[:format] || filename).new(file, options, &block)
@@ -135,16 +149,29 @@ module RDF
135
149
  # @yield [writer]
136
150
  # @yieldparam [RDF::Writer] writer
137
151
  def initialize(output = $stdout, options = {}, &block)
138
- @output, @options = output, options
139
- @nodes, @node_id = {}, 0
152
+ @output, @options = output, options.dup
153
+ @nodes, @node_id = {}, 0
140
154
 
141
155
  if block_given?
142
156
  write_prologue
143
- block.call(self)
157
+ case block.arity
158
+ when 1 then block.call(self)
159
+ else instance_eval(&block)
160
+ end
144
161
  write_epilogue
145
162
  end
146
163
  end
147
164
 
165
+ ##
166
+ # Flushes the underlying output buffer.
167
+ #
168
+ # @return [void]
169
+ def flush
170
+ @output.flush if @output.respond_to?(:flush)
171
+ end
172
+
173
+ alias_method :flush!, :flush
174
+
148
175
  ##
149
176
  # @return [void]
150
177
  # @abstract
@@ -156,84 +183,57 @@ module RDF
156
183
  def write_epilogue() end
157
184
 
158
185
  ##
186
+ # @param [String] text
159
187
  # @return [void]
160
188
  # @abstract
161
189
  def write_comment(text) end
162
190
 
163
191
  ##
164
- # @raise [ArgumentError]
165
- def <<(data)
166
- case data # TODO
167
- #when Graph
168
- # write_graph(data)
169
- #when Resource
170
- # #register!(resource) && write_node(resource)
171
- # write_resource(data)
172
- when Statement
173
- write_statement(data)
174
- else
175
- if data.respond_to?(:to_a)
176
- write_triple(*data.to_a)
177
- else
178
- raise ArgumentError.new("expected RDF::Statement or RDF::Resource, got #{data.inspect}")
179
- end
180
- end
181
- end
182
-
183
- ##
184
- # @param [Graph] graph
192
+ # @param [RDF::Graph] graph
185
193
  # @return [void]
186
194
  def write_graph(graph)
187
- write_triples(*graph.triples)
195
+ graph.each_triple { |*triple| write_triple(*triple) }
188
196
  end
189
197
 
190
198
  ##
191
- # @return [void]
192
- def write_resource(subject) # FIXME
193
- edge_nodes = []
194
- subject.each do |predicate, objects|
195
- [objects].flatten.each do |object|
196
- edge_nodes << object if register!(object)
197
- write_triple subject, predicate, object
198
- end
199
- end
200
- edge_nodes.each { |node| write_resource node }
201
- end
202
-
203
- ##
204
- # @param [Array<Statement>] statements
199
+ # @param [Array<RDF::Statement>] statements
205
200
  # @return [void]
206
201
  def write_statements(*statements)
207
- statements.flatten.each { |stmt| write_statement(stmt) }
202
+ statements.flatten.each { |statement| write_statement(statement) }
208
203
  end
209
204
 
210
205
  ##
211
- # @param [Statement] statement
206
+ # @param [RDF::Statement] statement
212
207
  # @return [void]
213
208
  def write_statement(statement)
214
- write_triple(*statement.to_a)
209
+ write_triple(*statement.to_triple)
215
210
  end
216
211
 
217
212
  ##
218
- # @param [Array<Array(Value)>] triples
213
+ # @param [Array<Array(RDF::Resource, RDF::URI, RDF::Value)>] triples
219
214
  # @return [void]
220
215
  def write_triples(*triples)
221
216
  triples.each { |triple| write_triple(*triple) }
222
217
  end
223
218
 
224
219
  ##
225
- # @param [Resource] subject
226
- # @param [URI] predicate
227
- # @param [Value] object
220
+ # @param [RDF::Resource] subject
221
+ # @param [RDF::URI] predicate
222
+ # @param [RDF::Value] object
228
223
  # @return [void]
229
224
  # @raise [NotImplementedError] unless implemented in subclass
230
225
  # @abstract
231
226
  def write_triple(subject, predicate, object)
232
- raise NotImplementedError # override in subclasses
227
+ raise NotImplementedError.new("#{self.class}#write_triple") # override in subclasses
233
228
  end
234
229
 
230
+ # Support the RDF::Writable interface:
231
+ alias_method :insert_graph, :write_graph
232
+ alias_method :insert_statements, :write_statements
233
+ alias_method :insert_statement, :write_statement
234
+
235
235
  ##
236
- # @param [Value] value
236
+ # @param [RDF::Value] value
237
237
  # @return [String]
238
238
  def format_value(value, options = {})
239
239
  case value
@@ -252,7 +252,7 @@ module RDF
252
252
  # @raise [NotImplementedError] unless implemented in subclass
253
253
  # @abstract
254
254
  def format_uri(value, options = {})
255
- raise NotImplementedError # override in subclasses
255
+ raise NotImplementedError.new("#{self.class}#format_uri") # override in subclasses
256
256
  end
257
257
 
258
258
  ##
@@ -262,7 +262,7 @@ module RDF
262
262
  # @raise [NotImplementedError] unless implemented in subclass
263
263
  # @abstract
264
264
  def format_node(value, options = {})
265
- raise NotImplementedError # override in subclasses
265
+ raise NotImplementedError.new("#{self.class}#format_node") # override in subclasses
266
266
  end
267
267
 
268
268
  ##
@@ -272,78 +272,71 @@ module RDF
272
272
  # @raise [NotImplementedError] unless implemented in subclass
273
273
  # @abstract
274
274
  def format_literal(value, options = {})
275
- raise NotImplementedError # override in subclasses
275
+ raise NotImplementedError.new("#{self.class}#format_literal") # override in subclasses
276
276
  end
277
277
 
278
+ protected
279
+
278
280
  ##
279
- # Flushes the underlying output buffer.
280
- #
281
281
  # @return [void]
282
- def flush
283
- @output.flush if @output.respond_to?(:flush)
282
+ def puts(*args)
283
+ @output.puts(*args)
284
284
  end
285
285
 
286
- alias_method :flush!, :flush
287
-
288
- protected
289
-
290
- def puts(*args)
291
- @output.puts(*args)
292
- end
293
-
294
- ##
295
- # @param [Resource] uriref
296
- # @return [String]
297
- def uri_for(uriref)
298
- case
299
- when uriref.is_a?(RDF::Node)
300
- @nodes[uriref]
301
- when uriref.respond_to?(:to_uri)
302
- uriref.to_uri.to_s
303
- else
304
- uriref.to_s
305
- end
286
+ ##
287
+ # @param [RDF::Resource] uriref
288
+ # @return [String]
289
+ def uri_for(uriref)
290
+ case
291
+ when uriref.is_a?(RDF::Node)
292
+ @nodes[uriref]
293
+ when uriref.respond_to?(:to_uri)
294
+ uriref.to_uri.to_s
295
+ else
296
+ uriref.to_s
306
297
  end
298
+ end
307
299
 
308
- ##
309
- # @return [String]
310
- def node_id
311
- "_:n#{@node_id += 1}"
312
- end
300
+ ##
301
+ # @return [String]
302
+ def node_id
303
+ "_:n#{@node_id += 1}"
304
+ end
313
305
 
314
- def register!(resource)
315
- if resource.kind_of?(RDF::Resource)
316
- unless @nodes[resource] # have we already seen it?
317
- @nodes[resource] = resource.uri || node_id
318
- end
306
+ ##
307
+ # @deprecated
308
+ def register!(resource)
309
+ if resource.kind_of?(RDF::Resource)
310
+ unless @nodes[resource] # have we already seen it?
311
+ @nodes[resource] = resource.uri || node_id
319
312
  end
320
313
  end
314
+ end
321
315
 
322
- ##
323
- # @param [String] string
324
- # @return [String]
325
- def escaped(string)
326
- string.gsub('\\', '\\\\').gsub("\t", '\\t').
327
- gsub("\n", '\\n').gsub("\r", '\\r').gsub('"', '\\"')
328
- end
329
-
330
- ##
331
- # @param [String] string
332
- # @return [String]
333
- def quoted(string)
334
- "\"#{string}\""
335
- end
316
+ ##
317
+ # @param [String] string
318
+ # @return [String]
319
+ def escaped(string)
320
+ string.gsub('\\', '\\\\').gsub("\t", '\\t').
321
+ gsub("\n", '\\n').gsub("\r", '\\r').gsub('"', '\\"')
322
+ end
336
323
 
337
- private
324
+ ##
325
+ # @param [String] string
326
+ # @return [String]
327
+ def quoted(string)
328
+ "\"#{string}\""
329
+ end
338
330
 
339
- @@subclasses = [] # @private
331
+ private
340
332
 
341
- def self.inherited(child) # @private
342
- @@subclasses << child
343
- super
344
- end
333
+ @@subclasses = [] # @private
345
334
 
346
- end
335
+ def self.inherited(child) # @private
336
+ @@subclasses << child
337
+ super
338
+ end
339
+ end # class Writer
347
340
 
348
341
  class WriterError < IOError; end
349
342
  end