rdf 1.1.0p4 → 1.1.0

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