rdf 0.0.6 → 0.0.7

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.
Files changed (59) hide show
  1. data/AUTHORS +1 -1
  2. data/VERSION +1 -1
  3. data/lib/rdf.rb +25 -22
  4. data/lib/rdf/enumerable.rb +554 -0
  5. data/lib/rdf/format.rb +239 -41
  6. data/lib/rdf/model/graph.rb +82 -0
  7. data/lib/rdf/{literal.rb → model/literal.rb} +47 -4
  8. data/lib/rdf/{node.rb → model/node.rb} +0 -0
  9. data/lib/rdf/{resource.rb → model/resource.rb} +0 -0
  10. data/lib/rdf/{statement.rb → model/statement.rb} +12 -0
  11. data/lib/rdf/{uri.rb → model/uri.rb} +20 -7
  12. data/lib/rdf/model/value.rb +135 -0
  13. data/lib/rdf/ntriples.rb +35 -2
  14. data/lib/rdf/ntriples/format.rb +4 -4
  15. data/lib/rdf/ntriples/reader.rb +2 -2
  16. data/lib/rdf/ntriples/writer.rb +26 -19
  17. data/lib/rdf/query.rb +4 -4
  18. data/lib/rdf/query/pattern.rb +3 -3
  19. data/lib/rdf/query/solution.rb +2 -2
  20. data/lib/rdf/query/variable.rb +3 -3
  21. data/lib/rdf/reader.rb +85 -16
  22. data/lib/rdf/repository.rb +104 -12
  23. data/lib/rdf/version.rb +1 -1
  24. data/lib/rdf/vocab.rb +171 -0
  25. data/lib/rdf/vocab/cc.rb +18 -0
  26. data/lib/rdf/vocab/dc.rb +63 -0
  27. data/lib/rdf/vocab/doap.rb +45 -0
  28. data/lib/rdf/vocab/exif.rb +168 -0
  29. data/lib/rdf/vocab/foaf.rb +69 -0
  30. data/lib/rdf/vocab/http.rb +26 -0
  31. data/lib/rdf/vocab/owl.rb +59 -0
  32. data/lib/rdf/{vocabulary → vocab}/rdf.rb +7 -1
  33. data/lib/rdf/vocab/rdfs.rb +17 -0
  34. data/lib/rdf/{vocabulary → vocab}/rss.rb +6 -1
  35. data/lib/rdf/vocab/sioc.rb +93 -0
  36. data/lib/rdf/vocab/skos.rb +36 -0
  37. data/lib/rdf/vocab/wot.rb +21 -0
  38. data/lib/rdf/vocab/xhtml.rb +9 -0
  39. data/lib/rdf/vocab/xsd.rb +58 -0
  40. data/lib/rdf/writer.rb +123 -16
  41. metadata +26 -27
  42. data/lib/rdf/graph.rb +0 -197
  43. data/lib/rdf/reader/ntriples.rb +0 -5
  44. data/lib/rdf/value.rb +0 -76
  45. data/lib/rdf/vocabulary.rb +0 -133
  46. data/lib/rdf/vocabulary/cc.rb +0 -9
  47. data/lib/rdf/vocabulary/dc.rb +0 -9
  48. data/lib/rdf/vocabulary/doap.rb +0 -9
  49. data/lib/rdf/vocabulary/exif.rb +0 -9
  50. data/lib/rdf/vocabulary/foaf.rb +0 -9
  51. data/lib/rdf/vocabulary/http.rb +0 -9
  52. data/lib/rdf/vocabulary/owl.rb +0 -9
  53. data/lib/rdf/vocabulary/rdfs.rb +0 -9
  54. data/lib/rdf/vocabulary/sioc.rb +0 -9
  55. data/lib/rdf/vocabulary/skos.rb +0 -9
  56. data/lib/rdf/vocabulary/wot.rb +0 -9
  57. data/lib/rdf/vocabulary/xhtml.rb +0 -9
  58. data/lib/rdf/vocabulary/xsd.rb +0 -9
  59. data/lib/rdf/writer/ntriples.rb +0 -5
data/lib/rdf/format.rb CHANGED
@@ -1,20 +1,125 @@
1
1
  module RDF
2
2
  ##
3
3
  # An RDF serialization format.
4
+ #
5
+ # @example Iterating over known RDF serialization formats
6
+ # RDF::Format.each { |klass| puts klass.name }
7
+ #
8
+ # @example Getting a serialization format class
9
+ # RDF::Format.for(:ntriples) #=> RDF::NTriples::Format
10
+ # RDF::Format.for("spec/data/test.nt")
11
+ # RDF::Format.for(:file_name => "spec/data/test.nt")
12
+ # RDF::Format.for(:file_extension => "nt")
13
+ # RDF::Format.for(:content_type => "text/plain")
14
+ #
15
+ # @example Obtaining serialization format MIME types
16
+ # RDF::Format.content_types #=> {"text/plain" => [RDF::NTriples::Format]}
17
+ #
18
+ # @example Obtaining serialization format file extension mappings
19
+ # RDF::Format.file_extensions #=> {:nt => "text/plain"}
20
+ #
21
+ # @example Defining a new RDF serialization format class
22
+ # class RDF::NTriples::Format < RDF::Format
23
+ # content_type 'text/plain', :extension => :nt
24
+ # content_encoding 'ascii'
25
+ #
26
+ # reader RDF::NTriples::Reader
27
+ # writer RDF::NTriples::Writer
28
+ # end
29
+ #
30
+ # @example Instantiating an RDF reader or writer class (1)
31
+ # RDF::Format.for(:ntriples).reader.new($stdin) { |reader| ... }
32
+ # RDF::Format.for(:ntriples).writer.new($stdout) { |writer| ... }
33
+ #
34
+ # @example Instantiating an RDF reader or writer class (2)
35
+ # RDF::Reader.for(:ntriples).new($stdin) { |reader| ... }
36
+ # RDF::Writer.for(:ntriples).new($stdout) { |writer| ... }
37
+ #
38
+ # @abstract
39
+ # @see RDF::Reader
40
+ # @see RDF::Writer
41
+ # @see http://en.wikipedia.org/wiki/Resource_Description_Framework#Serialization_formats
4
42
  class Format
5
- include Enumerable
43
+ extend ::Enumerable
6
44
 
7
45
  ##
8
- # Enumerates known RDF format classes.
46
+ # Enumerates known RDF serialization format classes.
9
47
  #
10
48
  # @yield [klass]
11
49
  # @yieldparam [Class]
50
+ # @return [Enumerator]
12
51
  def self.each(&block)
13
- !block_given? ? @@subclasses : @@subclasses.each { |klass| yield klass } # FIXME: Enumerator
52
+ @@subclasses.each(&block)
14
53
  end
15
54
 
16
55
  ##
17
- # Returns the list of known MIME content types.
56
+ # Finds an RDF serialization format class based on the given criteria.
57
+ #
58
+ # @overload for(format)
59
+ # Finds an RDF serialization format class based on a symbolic name.
60
+ #
61
+ # @param [Symbol] format
62
+ # @return [Class]
63
+ #
64
+ # @overload for(filename)
65
+ # Finds an RDF serialization format class based on a file name.
66
+ #
67
+ # @param [String] filename
68
+ # @return [Class]
69
+ #
70
+ # @overload for(options = {})
71
+ # Finds an RDF serialization format class based on various options.
72
+ #
73
+ # @param [Hash{Symbol => Object}] options
74
+ # @option options [String, #to_s] :file_name (nil)
75
+ # @option options [Symbol, #to_sym] :file_extension (nil)
76
+ # @option options [String, #to_s] :content_type (nil)
77
+ # @return [Class]
78
+ #
79
+ # @return [Class]
80
+ def self.for(options = {})
81
+ case options
82
+ when String
83
+ # Find a format based on the file name
84
+ self.for(:file_name => options)
85
+
86
+ when Hash
87
+ case
88
+ # Find a format based on the file name
89
+ when file_name = options[:file_name]
90
+ self.for(:file_extension => File.extname(file_name.to_s)[1..-1])
91
+ # Find a format based on the file extension
92
+ when file_ext = options[:file_extension]
93
+ if file_extensions.has_key?(file_ext = file_ext.to_sym)
94
+ self.for(:content_type => file_extensions[file_ext])
95
+ end
96
+ # Find a format based on the MIME content type
97
+ when mime_type = options[:content_type]
98
+ if content_types.has_key?(mime_type = mime_type.to_s)
99
+ content_types[mime_type].first
100
+ end
101
+ end
102
+
103
+ when Symbol
104
+ case format = options
105
+ # Special case, since we want this to work despite autoloading
106
+ when :ntriples
107
+ RDF::NTriples::Format
108
+ # For anything else, find a match based on the full class name
109
+ else
110
+ format = format.to_s.downcase
111
+ @@subclasses.each do |klass|
112
+ if klass.name.to_s.split('::').map(&:downcase).include?(format)
113
+ return klass
114
+ end
115
+ end
116
+ nil # not found
117
+ end
118
+ end
119
+ end
120
+
121
+ ##
122
+ # Returns MIME content types for known RDF serialization formats.
18
123
  #
19
124
  # @return [Hash{String => Array<Class>}]
20
125
  def self.content_types
@@ -22,7 +127,7 @@ module RDF
22
127
  end
23
128
 
24
129
  ##
25
- # Returns the list of known file extensions.
130
+ # Returns file extensions for known RDF serialization formats.
26
131
  #
27
132
  # @return [Hash{Symbol => String}]
28
133
  def self.file_extensions
@@ -30,66 +135,159 @@ module RDF
30
135
  end
31
136
 
32
137
  ##
33
- # @param [Symbol] format
34
- # @return [Class]
35
- def self.for(format)
36
- klass = case format.to_s.downcase.to_sym
37
- when :ntriples then RDF::NTriples::Format
38
- else nil # FIXME
138
+ # Retrieves or defines the reader class for this RDF serialization
139
+ # format.
140
+ #
141
+ # @overload reader(klass)
142
+ # Defines the reader class for this RDF serialization format.
143
+ #
144
+ # The class should be a subclass of {RDF::Reader}, or implement the
145
+ # same interface.
146
+ #
147
+ # @param [Class] klass
148
+ # @return [void]
149
+ #
150
+ # @overload reader
151
+ # Defines the reader class for this RDF serialization format.
152
+ #
153
+ # The block should return a subclass of {RDF::Reader}, or a class that
154
+ # implements the same interface. The block won't be invoked until the
155
+ # reader class is first needed.
156
+ #
157
+ # @yield
158
+ # @yieldreturn [Class] klass
159
+ # @return [void]
160
+ #
161
+ # @overload reader
162
+ # Retrieves the reader class for this RDF serialization format.
163
+ #
164
+ # @return [Class]
165
+ #
166
+ # @return [void]
167
+ def self.reader(klass = nil, &block)
168
+ case
169
+ when klass
170
+ @@readers[self] = klass
171
+ when block_given?
172
+ @@readers[self] = block
173
+ else
174
+ klass = @@readers[self]
175
+ klass = @@readers[self] = klass.call if klass.is_a?(Proc)
176
+ klass
39
177
  end
40
178
  end
41
179
 
42
180
  ##
43
- # @yield [format]
44
- # @yieldparam [Format]
45
- def initialize(options = {}, &block)
46
- @options = options
47
-
48
- if block_given?
49
- case block.arity
50
- when 1 then block.call(self)
51
- else instance_eval(&block)
52
- end
181
+ # Retrieves or defines the writer class for this RDF serialization
182
+ # format.
183
+ #
184
+ # @overload writer(klass)
185
+ # Defines the writer class for this RDF serialization format.
186
+ #
187
+ # The class should be a subclass of {RDF::Writer}, or implement the
188
+ # same interface.
189
+ #
190
+ # @param [Class] klass
191
+ # @return [void]
192
+ #
193
+ # @overload writer
194
+ # Defines the writer class for this RDF serialization format.
195
+ #
196
+ # The block should return a subclass of {RDF::Writer}, or a class that
197
+ # implements the same interface. The block won't be invoked until the
198
+ # writer class is first needed.
199
+ #
200
+ # @yield
201
+ # @yieldreturn [Class] klass
202
+ # @return [void]
203
+ #
204
+ # @overload writer
205
+ # Retrieves the writer class for this RDF serialization format.
206
+ #
207
+ # @return [Class]
208
+ #
209
+ # @return [void]
210
+ def self.writer(klass = nil, &block)
211
+ case
212
+ when klass
213
+ @@writers[self] = klass
214
+ when block_given?
215
+ @@writers[self] = block
216
+ else
217
+ klass = @@writers[self]
218
+ klass = @@writers[self] = klass.call if klass.is_a?(Proc)
219
+ klass
53
220
  end
54
221
  end
55
222
 
56
- protected
57
-
58
- @@subclasses = [] # @private
59
- @@file_extensions = {} # @private
60
- @@content_types = {} # @private
61
- @@content_encoding = {} # @private
223
+ class << self
224
+ alias_method :reader_class, :reader
225
+ alias_method :writer_class, :writer
226
+ end
62
227
 
63
- def self.inherited(child) # @private
64
- @@subclasses << child
65
- super
66
- end
228
+ protected
67
229
 
230
+ ##
231
+ # Defines a required Ruby library for this RDF serialization format.
232
+ #
233
+ # The given library will be required lazily, i.e. only when it is
234
+ # actually first needed, such as when instantiating a reader or parser
235
+ # instance for this format.
236
+ #
237
+ # @param [String, #to_s] library
238
+ # @return [void]
68
239
  def self.require(library)
69
- # TODO
240
+ (@@requires[self] ||= []) << library.to_s
70
241
  end
71
242
 
243
+ ##
244
+ # Defines MIME content types for this RDF serialization format.
245
+ #
246
+ # Optionally also defines a file extension, or a list of file
247
+ # extensions, that should be mapped to the given MIME type and handled
248
+ # by this class.
249
+ #
250
+ # @param [String] type
251
+ # @param [Hash{Symbol => Object}] options
252
+ # @option options [Symbol] :extension (nil)
253
+ # @option options [Array<Symbol>] :extensions (nil)
254
+ # @return [void]
72
255
  def self.content_type(type, options = {})
73
- @@content_types[type] ||= []
74
- @@content_types[type] << self
256
+ (@@content_types[type] ||= []) << self
75
257
 
76
- if options[:extension]
77
- extensions = [options[:extension]].flatten.map { |ext| ext.to_sym }
258
+ if extensions = (options[:extension] || options[:extensions])
259
+ extensions = [extensions].flatten.map { |ext| ext.to_sym }
78
260
  extensions.each { |ext| @@file_extensions[ext] = type }
79
261
  end
80
262
  end
81
263
 
264
+ ##
265
+ # Defines the content encoding for this RDF serialization format.
266
+ #
267
+ # @param [#to_sym] encoding
268
+ # @return [void]
82
269
  def self.content_encoding(encoding)
83
270
  @@content_encoding[self] = encoding.to_sym
84
271
  end
85
272
 
86
- def self.reader(klass)
87
- # TODO
88
- end
273
+ private
274
+
275
+ private_class_method :new
89
276
 
90
- def self.writer(klass)
91
- # TODO
277
+ @@subclasses = [] # @private
278
+ @@requires = {} # @private
279
+ @@file_extensions = {} # @private
280
+ @@content_types = {} # @private
281
+ @@content_encoding = {} # @private
282
+ @@readers = {} # @private
283
+ @@writers = {} # @private
284
+
285
+ def self.inherited(child) # @private
286
+ @@subclasses << child
287
+ super
92
288
  end
93
289
 
94
290
  end
291
+
292
+ class FormatError < IOError; end
95
293
  end
@@ -0,0 +1,82 @@
1
+ module RDF
2
+ ##
3
+ # An RDF graph.
4
+ class Graph < Resource
5
+ include RDF::Enumerable
6
+
7
+ # @return [URI]
8
+ attr_accessor :uri
9
+
10
+ # @return [Array<Statement>]
11
+ attr_accessor :data
12
+
13
+ ##
14
+ # @param [URI] uri
15
+ # @yield [graph]
16
+ # @yieldparam [Graph]
17
+ def initialize(uri = nil, options = {}, &block)
18
+ @uri, @options = uri, options
19
+
20
+ if block_given?
21
+ case block.arity
22
+ when 1 then block.call(self)
23
+ else instance_eval(&block)
24
+ end
25
+ end
26
+ end
27
+
28
+ ##
29
+ # Returns `true`.
30
+ #
31
+ # @return [Boolean]
32
+ def graph?
33
+ true
34
+ end
35
+
36
+ ##
37
+ # @return [Boolean]
38
+ def named?() !unnamed? end
39
+
40
+ ##
41
+ # @return [Boolean]
42
+ def unnamed?() uri.nil? end
43
+
44
+ ##
45
+ # @return [Integer]
46
+ def size() @data.size end
47
+
48
+ ##
49
+ # @yield [statement]
50
+ # @yieldparam [Array<Statement>]
51
+ # @return [Graph]
52
+ def each(&block)
53
+ @data.each(&block)
54
+ end
55
+
56
+ ##
57
+ # @return [Resource]
58
+ def context() uri end
59
+
60
+ ##
61
+ # @param [Statement, Array(Value)]
62
+ # @return [Graph]
63
+ def <<(statement)
64
+ @data << case statement
65
+ when Array then Statement.new(*statement)
66
+ when Statement then statement
67
+ else statement
68
+ end
69
+ self
70
+ end
71
+
72
+ ##
73
+ # @return [URI]
74
+ def to_uri() uri end
75
+
76
+ ##
77
+ # @return [String]
78
+ def to_s
79
+ named? ? uri.to_s : "<>"
80
+ end
81
+ end
82
+ end
@@ -29,8 +29,8 @@ module RDF
29
29
  # @example Creating implicitly datatyped literals
30
30
  # RDF::Literal.new(false).datatype #=> XSD.boolean
31
31
  # RDF::Literal.new(true).datatype #=> XSD.boolean
32
- # RDF::Literal.new(123).datatype #=> XSD.int
33
- # RDF::Literal.new(9223372036854775807).datatype #=> XSD.long
32
+ # RDF::Literal.new(123).datatype #=> XSD.integer
33
+ # RDF::Literal.new(9223372036854775807).datatype #=> XSD.integer
34
34
  # RDF::Literal.new(3.1415).datatype #=> XSD.double
35
35
  # RDF::Literal.new(Time.now).datatype #=> XSD.dateTime
36
36
  # RDF::Literal.new(Date.new(2010)).datatype #=> XSD.date
@@ -63,8 +63,8 @@ module RDF
63
63
  when String then nil # implicit XSD.string
64
64
  when TrueClass then XSD.boolean
65
65
  when FalseClass then XSD.boolean
66
- when Fixnum then XSD.int
67
- when Integer then XSD.long # FIXME
66
+ when Fixnum then XSD.integer
67
+ when Integer then XSD.integer
68
68
  when Float
69
69
  @value = case
70
70
  when value.nan? then 'NaN'
@@ -80,12 +80,55 @@ module RDF
80
80
  when Date then XSD.date
81
81
  when Time then XSD.dateTime
82
82
  end
83
+ else
84
+ require 'bigdecimal' unless defined?(BigDecimal)
85
+ case value
86
+ when BigDecimal
87
+ case
88
+ when value.nan? then 'NaN'
89
+ when value.infinite? then value.to_s[0...-'inity'.length].upcase
90
+ when value.finite? then value.to_s('F')
91
+ end
92
+ end
83
93
  end
84
94
  end
85
95
 
86
96
  @value = @value.to_s
87
97
  end
88
98
 
99
+ ##
100
+ # @return [Object]
101
+ def object
102
+ case datatype
103
+ when XSD.string, nil
104
+ value
105
+ when XSD.boolean
106
+ %w(true 1).include?(value)
107
+ when XSD.double, XSD.float
108
+ value.to_f
109
+ when XSD.integer, XSD.long, XSD.int, XSD.short, XSD.byte
110
+ value.to_i
111
+ when XSD.decimal
112
+ require 'bigdecimal' unless defined?(BigDecimal)
113
+ BigDecimal.new(value)
114
+ when XSD.date
115
+ require 'date' unless defined?(Date)
116
+ Date.parse(value)
117
+ when XSD.dateTime
118
+ require 'date' unless defined?(DateTime)
119
+ DateTime.parse(value)
120
+ when XSD.time
121
+ require 'time'
122
+ Time.parse(value)
123
+ when XSD.nonPositiveInteger, XSD.negativeInteger
124
+ value.to_i
125
+ when XSD.nonNegativeInteger, XSD.positiveInteger
126
+ value.to_i
127
+ when XSD.unsignedLong, XSD.unsignedInt, XSD.unsignedShort, XSD.unsignedByte
128
+ value.to_i
129
+ end
130
+ end
131
+
89
132
  ##
90
133
  # Returns `true`.
91
134
  #