rdf 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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
  #