rdf 1.1.0p4 → 1.1.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.
Files changed (54) hide show
  1. checksums.yaml +6 -14
  2. data/README +33 -33
  3. data/VERSION +1 -1
  4. data/lib/rdf.rb +60 -12
  5. data/lib/rdf/cli.rb +7 -1
  6. data/lib/rdf/cli/vocab-loader.rb +240 -0
  7. data/lib/rdf/format.rb +2 -2
  8. data/lib/rdf/mixin/enumerable.rb +12 -4
  9. data/lib/rdf/mixin/queryable.rb +13 -13
  10. data/lib/rdf/model/graph.rb +5 -4
  11. data/lib/rdf/model/list.rb +15 -4
  12. data/lib/rdf/model/literal.rb +2 -1
  13. data/lib/rdf/model/statement.rb +10 -1
  14. data/lib/rdf/model/term.rb +8 -0
  15. data/lib/rdf/model/uri.rb +107 -2
  16. data/lib/rdf/model/value.rb +8 -0
  17. data/lib/rdf/ntriples/reader.rb +5 -4
  18. data/lib/rdf/query.rb +47 -12
  19. data/lib/rdf/query/solutions.rb +29 -29
  20. data/lib/rdf/reader.rb +13 -3
  21. data/lib/rdf/repository.rb +1 -0
  22. data/lib/rdf/util/file.rb +86 -6
  23. data/lib/rdf/vocab.rb +158 -58
  24. data/lib/rdf/vocab/cc.rb +28 -11
  25. data/lib/rdf/vocab/cert.rb +127 -9
  26. data/lib/rdf/vocab/dc.rb +242 -60
  27. data/lib/rdf/vocab/dc11.rb +42 -20
  28. data/lib/rdf/vocab/doap.rb +121 -42
  29. data/lib/rdf/vocab/exif.rb +540 -165
  30. data/lib/rdf/vocab/foaf.rb +353 -66
  31. data/lib/rdf/vocab/geo.rb +40 -10
  32. data/lib/rdf/vocab/gr.rb +1094 -0
  33. data/lib/rdf/vocab/http.rb +81 -23
  34. data/lib/rdf/vocab/ical.rb +361 -0
  35. data/lib/rdf/vocab/ma.rb +281 -69
  36. data/lib/rdf/vocab/og.rb +98 -0
  37. data/lib/rdf/vocab/owl.rb +226 -56
  38. data/lib/rdf/vocab/prov.rb +489 -0
  39. data/lib/rdf/vocab/rdfs.rb +38 -14
  40. data/lib/rdf/vocab/rsa.rb +25 -9
  41. data/lib/rdf/vocab/rss.rb +29 -11
  42. data/lib/rdf/vocab/schema.rb +3729 -647
  43. data/lib/rdf/vocab/sioc.rb +224 -89
  44. data/lib/rdf/vocab/skos.rb +141 -33
  45. data/lib/rdf/vocab/skosxl.rb +43 -0
  46. data/lib/rdf/vocab/v.rb +154 -0
  47. data/lib/rdf/vocab/vcard.rb +337 -0
  48. data/lib/rdf/vocab/void.rb +142 -0
  49. data/lib/rdf/vocab/wdrs.rb +129 -0
  50. data/lib/rdf/vocab/wot.rb +52 -18
  51. data/lib/rdf/vocab/xhtml.rb +3 -6
  52. data/lib/rdf/vocab/xhv.rb +239 -0
  53. data/lib/rdf/writer.rb +3 -3
  54. metadata +81 -14
@@ -60,6 +60,35 @@ module RDF; class Query
60
60
  super
61
61
  end
62
62
 
63
+ ##
64
+ # Returns an array of the distinct variable names used in this solution
65
+ # sequence.
66
+ #
67
+ # @return [Array<Symbol>]
68
+ def variable_names
69
+ variables = self.inject({}) do |result, solution|
70
+ solution.each_name do |name|
71
+ result[name] ||= true
72
+ end
73
+ result
74
+ end
75
+ variables.keys
76
+ end
77
+
78
+ ##
79
+ # Returns `true` if this solution sequence contains bindings for any of
80
+ # the given `variables`.
81
+ #
82
+ # @param [Array<Symbol, #to_sym>] variables
83
+ # an array of variables to check
84
+ # @return [Boolean] `true` or `false`
85
+ # @see RDF::Query::Solution#has_variables?
86
+ # @see RDF::Query#execute
87
+ def have_variables?(variables)
88
+ self.any? { |solution| solution.has_variables?(variables) }
89
+ end
90
+ alias_method :has_variables?, :have_variables?
91
+
63
92
  ##
64
93
  # Returns hash of bindings from each solution. Each bound variable will have
65
94
  # an array of bound values representing those from each solution, where a given
@@ -222,34 +251,5 @@ module RDF; class Query
222
251
  self
223
252
  end
224
253
  alias_method :limit!, :limit
225
-
226
- ##
227
- # Returns an array of the distinct variable names used in this solution
228
- # sequence.
229
- #
230
- # @return [Array<Symbol>]
231
- def variable_names
232
- variables = self.inject({}) do |result, solution|
233
- solution.each_name do |name|
234
- result[name] ||= true
235
- end
236
- result
237
- end
238
- variables.keys
239
- end
240
-
241
- ##
242
- # Returns `true` if this solution sequence contains bindings for any of
243
- # the given `variables`.
244
- #
245
- # @param [Array<Symbol, #to_sym>] variables
246
- # an array of variables to check
247
- # @return [Boolean] `true` or `false`
248
- # @see RDF::Query::Solution#has_variables?
249
- # @see RDF::Query#execute
250
- def have_variables?(variables)
251
- self.any? { |solution| solution.has_variables?(variables) }
252
- end
253
- alias_method :has_variables?, :have_variables?
254
254
  end # Solutions
255
255
  end; end # RDF::Query
data/lib/rdf/reader.rb CHANGED
@@ -217,10 +217,10 @@ module RDF
217
217
  # @example
218
218
  # reader.prefixes[:dc] #=> RDF::URI('http://purl.org/dc/terms/')
219
219
  #
220
- # @return [Hash{Symbol => RDF::URI}]
220
+ # @return [RDF::URI]
221
221
  # @since 0.3.0
222
222
  def base_uri
223
- @options[:base_uri]
223
+ RDF::URI(@options[:base_uri]) if @options[:base_uri]
224
224
  end
225
225
 
226
226
  ##
@@ -486,7 +486,17 @@ module RDF
486
486
  @line = @line_rest || @input.readline
487
487
  @line, @line_rest = @line.split("\r", 2)
488
488
  @line = @line.to_s.chomp
489
- @line.encode!(encoding)
489
+ begin
490
+ @line.encode!(encoding)
491
+ rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError, Encoding::ConverterNotFoundError
492
+ # It is likely the persisted line was not encoded on initial write
493
+ # (i.e. persisted via RDF <= 1.0.9 and read via RDF >= 1.0.10)
494
+ #
495
+ # Encoding::UndefinedConversionError is raised by MRI.
496
+ # Encoding::InvalidByteSequenceError is raised by jruby >= 1.7.5
497
+ # Encoding::ConverterNotFoundError is raised by jruby < 1.7.5
498
+ @line = RDF::NTriples::Reader.unescape(@line).encode(encoding)
499
+ end
490
500
  @line
491
501
  end
492
502
 
@@ -232,6 +232,7 @@ module RDF
232
232
  # statement contexts / named graphs
233
233
  when :context then @options[:with_context]
234
234
  when :inference then false # forward-chaining inference
235
+ when :validity then @options.fetch(:with_validity, true)
235
236
  else false
236
237
  end
237
238
  end
data/lib/rdf/util/file.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require 'net/http'
2
+ require 'time'
3
+
1
4
  module RDF; module Util
2
5
  ##
3
6
  # Wrapper for Kernel.open. Allows implementations to override to get
@@ -23,6 +26,8 @@ module RDF; module Util
23
26
  # Adds Accept header based on available reader content types to allow
24
27
  # for content negotiation based on available readers.
25
28
  #
29
+ # When retrieving documents over HTTP(S), use the mechanism described in [Providing and Discovering URI Documentation](http://www.w3.org/2001/tag/awwsw/issue57/latest/) to pass the appropriate `base_uri` to the block or as the return.
30
+ #
26
31
  # @param [String] filename_or_url to open
27
32
  # @param [Hash{Symbol => Object}] options
28
33
  # options are ignored in this implementation. Applications are encouraged
@@ -31,19 +36,94 @@ module RDF; module Util
31
36
  # options are passed to `Kernel.open`.
32
37
  # @option options [Array, String] :headers
33
38
  # HTTP Request headers, passed to Kernel.open.
34
- # @return [IO] File stream
35
- # @yield [IO] File stream
39
+ # @return [IO, Reader] File stream with no block, and the block return otherwise
40
+ # @yield [IO, StringIO] File stream
36
41
  def self.open_file(filename_or_url, options = {}, &block)
37
42
  filename_or_url = $1 if filename_or_url.to_s.match(/^file:(.*)$/)
38
- if filename_or_url.to_s =~ /^#{RDF::URI::SCHEME}/
39
- # Open as a URL
43
+ if filename_or_url.to_s =~ /^https?/
44
+ # Open as a URL with Net::HTTP
40
45
  headers = options.fetch(:headers, {})
41
- headers['Accept'] ||= (RDF::Format.reader_types + %w(*/*;q=0.1)).join(", ")
42
- Kernel.open(filename_or_url.to_s, headers, &block)
46
+ # Receive text/html and text/plain at a lower priority than other formats
47
+ reader_types = RDF::Format.reader_types.map do |t|
48
+ t.to_s =~ /text\/(?:plain|html)/ ? "#{t};q=0.5" : t
49
+ end
50
+ headers['Accept'] ||= (reader_types + %w(*/*;q=0.1)).join(", ")
51
+
52
+ redirect_count = 0
53
+ max_redirects = 5
54
+ remote_document = nil
55
+ parsed_url = ::URI.parse(filename_or_url.to_s)
56
+ base_uri = parsed_url.to_s
57
+ result = nil
58
+ until remote_document do
59
+ Net::HTTP::start(parsed_url.host, parsed_url.port,
60
+ :open_timeout => 60 * 1000,
61
+ :use_ssl => filename_or_url.start_with?("https")
62
+ ) do |http|
63
+ request = Net::HTTP::Get.new(parsed_url.request_uri, headers)
64
+ http.request(request) do |response|
65
+ case response
66
+ when Net::HTTPSuccess
67
+ # found object
68
+
69
+ # If a Location is returned, it defines the base resource for this file, not it's actual ending location
70
+
71
+ document_options = {
72
+ :content_type => response.content_type,
73
+ :charset => "utf-8",
74
+ :base_uri => RDF::URI(response["Location"] ? response["Location"] : base_uri)
75
+ }.merge(response.type_params)
76
+ document_options[:last_modified] = DateTime.parse(response["Last-Modified"]) if response["Last-Modified"]
77
+
78
+ remote_document = RemoteDocument.new(response.body, document_options)
79
+
80
+ # Yield the result and close, or cause it to be returned
81
+ result = if block_given?
82
+ ret = yield remote_document
83
+ remote_document.close
84
+ ret
85
+ else
86
+ remote_document
87
+ end
88
+ when Net::HTTPRedirection
89
+ # Follow redirection
90
+ raise IOError, "Too many redirects" if (redirect_count += 1) > max_redirects
91
+
92
+ parsed_url = ::URI.parse(response["Location"])
93
+
94
+ # If response is not a status 303, update base_uri too
95
+ base_uri = parsed_url.to_s unless response.code == "303"
96
+ else
97
+ raise IOError, "<#{parsed_url}>: #{response.msg}(#{response.code})"
98
+ end
99
+ end
100
+ end
101
+ end
102
+ result
43
103
  else
44
104
  # Open as a file, passing any options
45
105
  Kernel.open(filename_or_url, "r", options, &block)
46
106
  end
47
107
  end
108
+
109
+ class RemoteDocument < StringIO
110
+ attr_reader :base_uri
111
+ attr_reader :content_type
112
+ attr_reader :charset
113
+ attr_reader :content_encoding
114
+ attr_reader :last_modified
115
+
116
+ ##
117
+ # Set content
118
+ def initialize(body, options = {})
119
+ super(body)
120
+ options.each do |key, value|
121
+ # de-quote charset
122
+ value = $1 if key == "charset" && value =~ /^["'](.*)["']$/
123
+ instance_variable_set(:"@#{key}", value)
124
+ end
125
+ set_encoding Encoding.find(@charset) if @charset
126
+ end
127
+ end
48
128
  end # File
49
129
  end; end # RDF::Util
data/lib/rdf/vocab.rb CHANGED
@@ -15,16 +15,27 @@ module RDF
15
15
  # * {RDF::EXIF} - Exchangeable Image File Format (EXIF)
16
16
  # * {RDF::FOAF} - Friend of a Friend (FOAF)
17
17
  # * {RDF::GEO} - WGS84 Geo Positioning (GEO)
18
+ # * {RDF::GR} - Good Relations
18
19
  # * {RDF::HTTP} - Hypertext Transfer Protocol (HTTP)
20
+ # * {RDF::ICAL} - iCal
21
+ # * {RDF::MA} - W3C Meda Annotations
22
+ # * {RDF::OG} - FaceBook OpenGraph
19
23
  # * {RDF::OWL} - Web Ontology Language (OWL)
24
+ # * {RDF::PROV} - W3C Provenance Ontology
20
25
  # * {RDF::RDFS} - RDF Schema (RDFS)
21
26
  # * {RDF::RSA} - W3 RSA Keys (RSA)
22
27
  # * {RDF::RSS} - RDF Site Summary (RSS)
23
28
  # * {RDF::SCHEMA} - Schema.org
24
29
  # * {RDF::SIOC} - Semantically-Interlinked Online Communities (SIOC)
25
30
  # * {RDF::SKOS} - Simple Knowledge Organization System (SKOS)
31
+ # * {RDF::SKOSXL} - SKOS Simple Knowledge Organization System eXtension for Labels (SKOS-XL)
32
+ # * {RDF::V} - Data Vocabulary
33
+ # * {RDF::VCARD} - vCard vocabulary
34
+ # * {RDF::VOID} - Vocabulary of Interlinked Datasets (VoID)
35
+ # * {RDF::WDRS} - Protocol for Web Description Resources (POWDER)
26
36
  # * {RDF::WOT} - Web of Trust (WOT)
27
37
  # * {RDF::XHTML} - Extensible HyperText Markup Language (XHTML)
38
+ # * {RDF::XHV} - W3C XHTML Vocabulary
28
39
  # * {RDF::XSD} - XML Schema (XSD)
29
40
  #
30
41
  # @example Using pre-defined RDF vocabularies
@@ -49,72 +60,99 @@ module RDF
49
60
  class Vocabulary
50
61
  extend ::Enumerable
51
62
 
52
- ##
53
- # Enumerates known RDF vocabulary classes.
54
- #
55
- # @yield [klass]
56
- # @yieldparam [Class] klass
57
- # @return [Enumerator]
58
- def self.each(&block)
59
- if self.equal?(Vocabulary)
60
- # This is needed since all vocabulary classes are defined using
61
- # Ruby's autoloading facility, meaning that `@@subclasses` will be
62
- # empty until each subclass has been touched or require'd.
63
- RDF::VOCABS.each { |v| require "rdf/vocab/#{v}" unless v == :rdf }
64
- @@subclasses.each(&block)
65
- else
66
- # TODO: should enumerate vocabulary-specific defined properties.
63
+ class << self
64
+ ##
65
+ # Enumerates known RDF vocabulary classes.
66
+ #
67
+ # @yield [klass]
68
+ # @yieldparam [Class] klass
69
+ # @return [Enumerator]
70
+ def each(&block)
71
+ if self.equal?(Vocabulary)
72
+ # This is needed since all vocabulary classes are defined using
73
+ # Ruby's autoloading facility, meaning that `@@subclasses` will be
74
+ # empty until each subclass has been touched or require'd.
75
+ RDF::VOCABS.each { |v| require "rdf/vocab/#{v}" unless v == :rdf }
76
+ @@subclasses.each(&block)
77
+ else
78
+ # TODO: should enumerate vocabulary-specific defined properties.
79
+ end
67
80
  end
68
- end
69
81
 
70
- ##
71
- # Defines a vocabulary term called `property`.
72
- #
73
- # @param [Symbol] property
74
- # @return [void]
75
- def self.property(property)
76
- metaclass = class << self; self; end
77
- metaclass.send(:define_method, property) { self[property] } # class method
78
- end
82
+ ##
83
+ # @overload property
84
+ # Returns `property` in the current vocabulary
85
+ # @return [RDF::URI]
86
+ #
87
+ # @overload property(name, options)
88
+ # Defines a new property or class in the vocabulary.
89
+ # Optional labels and comments are stripped of unnecessary whitespace.
90
+ #
91
+ # @param [String, #to_s] name
92
+ # @param [Hash{Symbol => Object}] options
93
+ # @option options [String, #to_s] :label
94
+ # @option options [String, #to_s] :comment
95
+ def property(*args)
96
+ case args.length
97
+ when 0
98
+ RDF::URI.intern("#{self}property")
99
+ else
100
+ name, options = args
101
+ options ||= {}
102
+ prop = RDF::URI.intern([to_s, name.to_s].join(''))
103
+ @@labels[prop] = options[:label].to_s.strip.gsub(/\s+/m, ' ') if options[:label]
104
+ @@comments[prop] = options[:comment].to_s.strip.gsub(/\s+/m, ' ') if options[:comment]
105
+ (class << self; self; end).send(:define_method, name) { prop } unless name.to_s == "property"
106
+ end
107
+ end
79
108
 
80
- ##
81
- # Returns the URI for the term `property` in this vocabulary.
82
- #
83
- # @param [#to_s] property
84
- # @return [RDF::URI]
85
- def self.[](property)
86
- RDF::URI.intern([to_s, property.to_s].join(''))
87
- end
109
+ ##
110
+ # Returns the URI for the term `property` in this vocabulary.
111
+ #
112
+ # @param [#to_s] property
113
+ # @return [RDF::URI]
114
+ def [](property)
115
+ RDF::URI.intern([to_s, property.to_s].join(''))
116
+ end
88
117
 
89
- ##
90
- # Returns the base URI for this vocabulary class.
91
- #
92
- # @return [RDF::URI]
93
- def self.to_uri
94
- RDF::URI.intern(to_s)
95
- end
118
+ # @return [String] The label for the named property
119
+ def label_for(name)
120
+ @@labels[self[name]]
121
+ end
96
122
 
97
- ##
98
- # Returns a string representation of this vocabulary class.
99
- #
100
- # @return [String]
101
- def self.to_s
102
- @@uris.has_key?(self) ? @@uris[self].to_s : super
103
- end
123
+ # @return [String] The comment for the named property
124
+ def comment_for(name)
125
+ @@comments[self[name]]
126
+ end
104
127
 
105
- ##
106
- # Returns a developer-friendly representation of this vocabulary class.
107
- #
108
- # @return [String]
109
- def self.inspect
110
- if self == Vocabulary
111
- self.to_s
112
- else
113
- sprintf("%s(%s)", superclass.to_s, to_s)
128
+ ##
129
+ # Returns the base URI for this vocabulary class.
130
+ #
131
+ # @return [RDF::URI]
132
+ def to_uri
133
+ RDF::URI.intern(to_s)
134
+ end
135
+
136
+ ##
137
+ # Returns a string representation of this vocabulary class.
138
+ #
139
+ # @return [String]
140
+ def to_s
141
+ @@uris.has_key?(self) ? @@uris[self].to_s : super
142
+ end
143
+
144
+ ##
145
+ # Returns a developer-friendly representation of this vocabulary class.
146
+ #
147
+ # @return [String]
148
+ def inspect
149
+ if self == Vocabulary
150
+ self.to_s
151
+ else
152
+ sprintf("%s(%s)", superclass.to_s, to_s)
153
+ end
114
154
  end
115
- end
116
155
 
117
- class << self
118
156
  # Preserve the class name so that it can be obtained even for
119
157
  # vocabularies that define a `name` property:
120
158
  alias_method :__name__, :name
@@ -216,5 +254,67 @@ module RDF
216
254
  @@subclasses = [::RDF] # @private
217
255
  @@uris = {} # @private
218
256
  @@uri = nil # @private
257
+ @@labels = {}
258
+ @@comments = {}
219
259
  end # Vocabulary
260
+
261
+ # Represents an RDF Vocabulary. The difference from {RDF::Vocabulary} is that
262
+ # that every concept in the vocabulary is required to be declared. To assist
263
+ # in this, an existing RDF representation of the vocabulary can be loaded as
264
+ # the basis for concepts being available
265
+ class StrictVocabulary < Vocabulary
266
+ class << self
267
+ begin
268
+ # Redefines method_missing to the original definition
269
+ # By remaining a subclass of Vocabulary, we remain available to
270
+ # Vocabulary::each etc.
271
+ define_method(:method_missing, BasicObject.instance_method(:method_missing))
272
+ rescue NameError
273
+ define_method(:method_missing, Kernel.instance_method(:method_missing))
274
+ end
275
+
276
+ ##
277
+ # @overload property
278
+ # Returns `property` in the current vocabulary
279
+ # @return [RDF::URI]
280
+ #
281
+ # @overload property(name, options)
282
+ # Defines a new property or class in the vocabulary.
283
+ # Optional labels and comments are stripped of unnecessary whitespace.
284
+ #
285
+ # @param [String, #to_s] name
286
+ # @param [Hash{Symbol => Object}] options
287
+ # @option options [String, #to_s] :label
288
+ # @option options [String, #to_s] :comment
289
+ def property(*args)
290
+ case args.length
291
+ when 0
292
+ RDF::URI.intern("#{self}property")
293
+ else
294
+ name, options = args
295
+ options ||= {}
296
+ prop = RDF::URI.intern([to_s, name.to_s].join(''))
297
+ @@properties[prop] = true
298
+ @@labels[prop] = options[:label].to_s.strip.gsub(/\s+/m, ' ') if options[:label]
299
+ @@comments[prop] = options[:comment].to_s.strip.gsub(/\s+/m, ' ') if options[:comment]
300
+ (class << self; self; end).send(:define_method, name) { prop } unless name.to_s == "property"
301
+ end
302
+ end
303
+
304
+ def [](name)
305
+ prop = RDF::URI.intern([to_s, name.to_s].join(''))
306
+ @@properties.fetch(prop) #raises KeyError on missing value
307
+ return prop
308
+ end
309
+ end
310
+
311
+ begin
312
+ define_method(:method_missing, BasicObject.instance_method(:method_missing))
313
+ rescue NameError
314
+ define_method(:method_missing, Kernel.instance_method(:method_missing))
315
+ end
316
+
317
+ private
318
+ @@properties = {}
319
+ end # StrictVocabulary
220
320
  end # RDF