openlogic-rdf 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +3 -0
- data/CREDITS +9 -0
- data/README +361 -0
- data/UNLICENSE +24 -0
- data/VERSION +1 -0
- data/bin/rdf +18 -0
- data/etc/doap.nt +62 -0
- data/lib/df.rb +1 -0
- data/lib/rdf/cli.rb +200 -0
- data/lib/rdf/format.rb +383 -0
- data/lib/rdf/mixin/countable.rb +39 -0
- data/lib/rdf/mixin/durable.rb +31 -0
- data/lib/rdf/mixin/enumerable.rb +637 -0
- data/lib/rdf/mixin/indexable.rb +26 -0
- data/lib/rdf/mixin/inferable.rb +5 -0
- data/lib/rdf/mixin/mutable.rb +191 -0
- data/lib/rdf/mixin/queryable.rb +265 -0
- data/lib/rdf/mixin/readable.rb +15 -0
- data/lib/rdf/mixin/type_check.rb +21 -0
- data/lib/rdf/mixin/writable.rb +152 -0
- data/lib/rdf/model/graph.rb +263 -0
- data/lib/rdf/model/list.rb +731 -0
- data/lib/rdf/model/literal/boolean.rb +121 -0
- data/lib/rdf/model/literal/date.rb +73 -0
- data/lib/rdf/model/literal/datetime.rb +72 -0
- data/lib/rdf/model/literal/decimal.rb +86 -0
- data/lib/rdf/model/literal/double.rb +189 -0
- data/lib/rdf/model/literal/integer.rb +126 -0
- data/lib/rdf/model/literal/numeric.rb +184 -0
- data/lib/rdf/model/literal/time.rb +87 -0
- data/lib/rdf/model/literal/token.rb +47 -0
- data/lib/rdf/model/literal/xml.rb +39 -0
- data/lib/rdf/model/literal.rb +373 -0
- data/lib/rdf/model/node.rb +156 -0
- data/lib/rdf/model/resource.rb +28 -0
- data/lib/rdf/model/statement.rb +296 -0
- data/lib/rdf/model/term.rb +77 -0
- data/lib/rdf/model/uri.rb +570 -0
- data/lib/rdf/model/value.rb +133 -0
- data/lib/rdf/nquads.rb +152 -0
- data/lib/rdf/ntriples/format.rb +48 -0
- data/lib/rdf/ntriples/reader.rb +239 -0
- data/lib/rdf/ntriples/writer.rb +219 -0
- data/lib/rdf/ntriples.rb +104 -0
- data/lib/rdf/query/pattern.rb +329 -0
- data/lib/rdf/query/solution.rb +252 -0
- data/lib/rdf/query/solutions.rb +237 -0
- data/lib/rdf/query/variable.rb +221 -0
- data/lib/rdf/query.rb +404 -0
- data/lib/rdf/reader.rb +511 -0
- data/lib/rdf/repository.rb +389 -0
- data/lib/rdf/transaction.rb +161 -0
- data/lib/rdf/util/aliasing.rb +63 -0
- data/lib/rdf/util/cache.rb +139 -0
- data/lib/rdf/util/file.rb +38 -0
- data/lib/rdf/util/uuid.rb +36 -0
- data/lib/rdf/util.rb +6 -0
- data/lib/rdf/version.rb +19 -0
- data/lib/rdf/vocab/cc.rb +18 -0
- data/lib/rdf/vocab/cert.rb +13 -0
- data/lib/rdf/vocab/dc.rb +63 -0
- data/lib/rdf/vocab/dc11.rb +23 -0
- data/lib/rdf/vocab/doap.rb +45 -0
- data/lib/rdf/vocab/exif.rb +168 -0
- data/lib/rdf/vocab/foaf.rb +69 -0
- data/lib/rdf/vocab/geo.rb +13 -0
- data/lib/rdf/vocab/http.rb +26 -0
- data/lib/rdf/vocab/owl.rb +59 -0
- data/lib/rdf/vocab/rdfs.rb +17 -0
- data/lib/rdf/vocab/rsa.rb +12 -0
- data/lib/rdf/vocab/rss.rb +14 -0
- data/lib/rdf/vocab/sioc.rb +93 -0
- data/lib/rdf/vocab/skos.rb +36 -0
- data/lib/rdf/vocab/wot.rb +21 -0
- data/lib/rdf/vocab/xhtml.rb +9 -0
- data/lib/rdf/vocab/xsd.rb +58 -0
- data/lib/rdf/vocab.rb +215 -0
- data/lib/rdf/writer.rb +475 -0
- data/lib/rdf.rb +192 -0
- metadata +173 -0
data/lib/rdf/cli.rb
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
require 'rdf/ntriples'
|
3
|
+
require 'rdf/nquads'
|
4
|
+
require 'optparse'
|
5
|
+
begin
|
6
|
+
gem 'linkeddata'
|
7
|
+
require 'linkeddata'
|
8
|
+
rescue LoadError
|
9
|
+
# Silently load without linkeddata
|
10
|
+
end
|
11
|
+
|
12
|
+
class OptionParser
|
13
|
+
def options; @options || {}; end
|
14
|
+
def options=(value); @options = value; end
|
15
|
+
end
|
16
|
+
|
17
|
+
module RDF
|
18
|
+
class CLI
|
19
|
+
|
20
|
+
COMMANDS = {
|
21
|
+
"count" => lambda do |argv, opts|
|
22
|
+
start = Time.new
|
23
|
+
count = 0
|
24
|
+
self.parse(argv, opts) do |reader|
|
25
|
+
reader.each_statement do |statement|
|
26
|
+
count += 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
secs = Time.new - start
|
30
|
+
$stdout.puts "Parsed #{count} statements with #{@readers.join(', ')} in #{secs} seconds @ #{count/secs} statements/second."
|
31
|
+
end,
|
32
|
+
"lenghts" => lambda do |argv, opts|
|
33
|
+
self.parse(argv, opts) do |reader|
|
34
|
+
reader.each_statement do |statement|
|
35
|
+
$stdout.puts statement.to_s.size
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end,
|
39
|
+
"objects" => lambda do |argv, opts|
|
40
|
+
self.parse(argv, opts) do |reader|
|
41
|
+
reader.each_statement do |statement|
|
42
|
+
$stdout.puts statement.object.to_ntriples
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end,
|
46
|
+
"predicates" => lambda do |argv, opts|
|
47
|
+
self.parse(argv, opts) do |reader|
|
48
|
+
reader.each_statement do |statement|
|
49
|
+
$stdout.puts statement.predicate.to_ntriples
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end,
|
53
|
+
"serialize" => lambda do |argv, opts|
|
54
|
+
writer_class = RDF::Writer.for(opts[:output_format]) || RDF::NTriples::Writer
|
55
|
+
out = opts[:output] || $stdout
|
56
|
+
opts = opts.merge(:prefixes => {})
|
57
|
+
writer_opts = opts.merge(:standard_prefixes => true)
|
58
|
+
self.parse(argv, opts) do |reader|
|
59
|
+
writer_class.new(out, writer_opts) do |writer|
|
60
|
+
writer << reader
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end,
|
64
|
+
"subjects" => lambda do |argv, opts|
|
65
|
+
self.parse(argv, opts) do |reader|
|
66
|
+
reader.each_statement do |statement|
|
67
|
+
$stdout.puts statement.subject.to_ntriples
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
}
|
72
|
+
|
73
|
+
##
|
74
|
+
# @return [String]
|
75
|
+
def self.basename() File.basename($0) end
|
76
|
+
|
77
|
+
##
|
78
|
+
# @yield [options]
|
79
|
+
# @yieldparam [OptionParser]
|
80
|
+
# @return [OptionParser]
|
81
|
+
def self.options(&block)
|
82
|
+
options = OptionParser.new
|
83
|
+
opts = options.options = {
|
84
|
+
:base_uri => nil,
|
85
|
+
:canonicalize => false,
|
86
|
+
:debug => false,
|
87
|
+
:evaluate => nil,
|
88
|
+
:format => nil,
|
89
|
+
:output => $stdout,
|
90
|
+
:output_format => :ntriples,
|
91
|
+
:validate => false,
|
92
|
+
}
|
93
|
+
|
94
|
+
# Command-specific options
|
95
|
+
if block_given?
|
96
|
+
case block.arity
|
97
|
+
when 1 then block.call(options)
|
98
|
+
else options.instance_eval(&block)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
options.banner ||= "Usage: #{self.basename} [options] command [args...]"
|
102
|
+
|
103
|
+
options.on('--canonicalize', 'Canonicalize input.') do
|
104
|
+
opts[:canonicalize] = true
|
105
|
+
end
|
106
|
+
|
107
|
+
options.on('-d', '--debug', 'Enable debug output for troubleshooting.') do
|
108
|
+
opts[:debug] = $DEBUG = true
|
109
|
+
end
|
110
|
+
|
111
|
+
options.on("-e", "--evaluate STRING", "Evaluate argument as RDF input, if no files are specified") do |arg|
|
112
|
+
opts[:evaluate] = arg
|
113
|
+
end
|
114
|
+
|
115
|
+
options.on("--input-format FORMAT", "Format of input file, uses heuristic if not specified") do |arg|
|
116
|
+
opts[:format] = arg.downcase.to_sym
|
117
|
+
end
|
118
|
+
|
119
|
+
options.on("-o", "--output FILE", "File to write output, defaults to STDOUT") do |arg|
|
120
|
+
opts[:output] = File.open(arg, "w")
|
121
|
+
end
|
122
|
+
|
123
|
+
options.on("--output-format FORMAT", "Format of output file, defaults to NTriples") do |arg|
|
124
|
+
opts[:output_format] = arg.downcase.to_sym
|
125
|
+
end
|
126
|
+
|
127
|
+
options.on('--uri URI', 'Base URI of input file, defaults to the filename.') do |arg|
|
128
|
+
opts[:base_uri] = arg
|
129
|
+
end
|
130
|
+
|
131
|
+
options.on('--validate', 'Validate input file.') do
|
132
|
+
opts[:validate] = true
|
133
|
+
end
|
134
|
+
|
135
|
+
options.on_tail("-h", "--help", "Show this message") do
|
136
|
+
$stdout.puts options
|
137
|
+
$stdout.puts "Available commands:\n\t#{self.commands.join("\n\t")}"
|
138
|
+
exit
|
139
|
+
end
|
140
|
+
|
141
|
+
begin
|
142
|
+
options.parse!
|
143
|
+
rescue OptionParser::InvalidOption => e
|
144
|
+
abort e
|
145
|
+
end
|
146
|
+
|
147
|
+
options
|
148
|
+
end
|
149
|
+
|
150
|
+
##
|
151
|
+
# @param [String] command
|
152
|
+
# @param [Array<String>] args
|
153
|
+
# @return [Boolean]
|
154
|
+
def self.exec_command(command, args, options = {})
|
155
|
+
unless COMMANDS.has_key?(command)
|
156
|
+
abort "#{File.basename($0)}: unknown command `#{command}'"
|
157
|
+
end
|
158
|
+
|
159
|
+
COMMANDS[command].call(args, options)
|
160
|
+
end
|
161
|
+
|
162
|
+
##
|
163
|
+
# @return [Array<String>] list of executable commands
|
164
|
+
def self.commands
|
165
|
+
COMMANDS.keys
|
166
|
+
end
|
167
|
+
|
168
|
+
##
|
169
|
+
# Parse each file, STDIN or specified string in options[:evaluate] yielding
|
170
|
+
# a reader
|
171
|
+
#
|
172
|
+
# @param [Array<String>] files
|
173
|
+
# @yield [reader]
|
174
|
+
# @yieldparam [RDF::Reader]
|
175
|
+
# @return [nil]
|
176
|
+
def self.parse(files, options = {}, &block)
|
177
|
+
if files.empty?
|
178
|
+
# If files are empty, either use options[:execute]
|
179
|
+
input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
|
180
|
+
RDF::Reader.for(options[:format] || :ntriples).new(input, options) do |reader|
|
181
|
+
yield(reader)
|
182
|
+
end
|
183
|
+
else
|
184
|
+
files.each do |file|
|
185
|
+
RDF::Reader.open(file, options) do |reader|
|
186
|
+
(@readers ||= []) << reader.class.to_s
|
187
|
+
yield(reader)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# @param [String] msg
|
195
|
+
# @return [void]
|
196
|
+
def self.abort(msg)
|
197
|
+
Kernel.abort "#{basename}: #{msg}"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
data/lib/rdf/format.rb
ADDED
@@ -0,0 +1,383 @@
|
|
1
|
+
module RDF
|
2
|
+
##
|
3
|
+
# The base class for RDF serialization formats.
|
4
|
+
#
|
5
|
+
# @example Loading an RDF serialization format implementation
|
6
|
+
# require 'rdf/ntriples'
|
7
|
+
#
|
8
|
+
# @example Iterating over known RDF serialization formats
|
9
|
+
# RDF::Format.each { |klass| puts klass.name }
|
10
|
+
#
|
11
|
+
# @example Getting a serialization format class
|
12
|
+
# RDF::Format.for(:ntriples) #=> RDF::NTriples::Format
|
13
|
+
# RDF::Format.for("etc/doap.nt")
|
14
|
+
# RDF::Format.for(:file_name => "etc/doap.nt")
|
15
|
+
# RDF::Format.for(:file_extension => "nt")
|
16
|
+
# RDF::Format.for(:content_type => "text/plain")
|
17
|
+
#
|
18
|
+
# @example Obtaining serialization format MIME types
|
19
|
+
# RDF::Format.content_types #=> {"text/plain" => [RDF::NTriples::Format]}
|
20
|
+
#
|
21
|
+
# @example Obtaining serialization format file extension mappings
|
22
|
+
# RDF::Format.file_extensions #=> {:nt => [RDF::NTriples::Format]}
|
23
|
+
#
|
24
|
+
# @example Defining a new RDF serialization format class
|
25
|
+
# class RDF::NTriples::Format < RDF::Format
|
26
|
+
# content_type 'text/plain', :extension => :nt
|
27
|
+
# content_encoding 'ascii'
|
28
|
+
#
|
29
|
+
# reader RDF::NTriples::Reader
|
30
|
+
# writer RDF::NTriples::Writer
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# @example Instantiating an RDF reader or writer class (1)
|
34
|
+
# RDF::Format.for(:ntriples).reader.new($stdin) { |reader| ... }
|
35
|
+
# RDF::Format.for(:ntriples).writer.new($stdout) { |writer| ... }
|
36
|
+
#
|
37
|
+
# @example Instantiating an RDF reader or writer class (2)
|
38
|
+
# RDF::Reader.for(:ntriples).new($stdin) { |reader| ... }
|
39
|
+
# RDF::Writer.for(:ntriples).new($stdout) { |writer| ... }
|
40
|
+
#
|
41
|
+
# @abstract
|
42
|
+
# @see RDF::Reader
|
43
|
+
# @see RDF::Writer
|
44
|
+
# @see http://en.wikipedia.org/wiki/Resource_Description_Framework#Serialization_formats
|
45
|
+
class Format
|
46
|
+
extend ::Enumerable
|
47
|
+
|
48
|
+
##
|
49
|
+
# Enumerates known RDF serialization format classes.
|
50
|
+
#
|
51
|
+
# @yield [klass]
|
52
|
+
# @yieldparam [Class]
|
53
|
+
# @return [Enumerator]
|
54
|
+
def self.each(&block)
|
55
|
+
@@subclasses.each(&block)
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Finds an RDF serialization format class based on the given criteria.
|
60
|
+
#
|
61
|
+
# @overload for(format)
|
62
|
+
# Finds an RDF serialization format class based on a symbolic name.
|
63
|
+
#
|
64
|
+
# @param [Symbol] format
|
65
|
+
# @return [Class]
|
66
|
+
#
|
67
|
+
# @overload for(filename)
|
68
|
+
# Finds an RDF serialization format class based on a file name.
|
69
|
+
#
|
70
|
+
# @param [String] filename
|
71
|
+
# @return [Class]
|
72
|
+
#
|
73
|
+
# @overload for(options = {})
|
74
|
+
# Finds an RDF serialization format class based on various options.
|
75
|
+
#
|
76
|
+
# @param [Hash{Symbol => Object}] options
|
77
|
+
# @option options [String, #to_s] :file_name (nil)
|
78
|
+
# @option options [Symbol, #to_sym] :file_extension (nil)
|
79
|
+
# @option options [String, #to_s] :content_type (nil)
|
80
|
+
# Note that content_type will be taken from a URL opened using {RDF::Util::File.open_file}.
|
81
|
+
# @option options [Boolean] :has_reader (false)
|
82
|
+
# Only return a format having a reader.
|
83
|
+
# @option options [Boolean] :has_writer (false)
|
84
|
+
# Only return a format having a writer.
|
85
|
+
# @option options [String] :sample (nil)
|
86
|
+
# A sample of input used for performing format detection.
|
87
|
+
# If we find no formats, or we find more than one, and we have a sample, we can
|
88
|
+
# perform format detection to find a specific format to use, in which case
|
89
|
+
# we pick the first one we find
|
90
|
+
# @return [Class]
|
91
|
+
# @yieldreturn [String] another way to provide a sample, allows lazy for retrieving the sample.
|
92
|
+
#
|
93
|
+
# @return [Class]
|
94
|
+
def self.for(options = {})
|
95
|
+
format = case options
|
96
|
+
when String
|
97
|
+
# Find a format based on the file name
|
98
|
+
self.for(:file_name => options)
|
99
|
+
|
100
|
+
when Hash
|
101
|
+
case
|
102
|
+
# Find a format based on the MIME content type:
|
103
|
+
when mime_type = options[:content_type]
|
104
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17
|
105
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
|
106
|
+
mime_type = mime_type.to_s
|
107
|
+
mime_type = mime_type.split(';').first # remove any media type parameters
|
108
|
+
content_types[mime_type]
|
109
|
+
# Find a format based on the file name:
|
110
|
+
when file_name = options[:file_name]
|
111
|
+
self.for(:file_extension => File.extname(file_name.to_s)[1..-1])
|
112
|
+
# Find a format based on the file extension:
|
113
|
+
when file_ext = options[:file_extension]
|
114
|
+
file_extensions[file_ext.to_sym]
|
115
|
+
end
|
116
|
+
|
117
|
+
when Symbol
|
118
|
+
case format = options
|
119
|
+
# Special case, since we want this to work despite autoloading
|
120
|
+
when :ntriples
|
121
|
+
RDF::NTriples::Format
|
122
|
+
# For anything else, find a match based on the full class name
|
123
|
+
else
|
124
|
+
@@subclasses.detect { |klass| klass.to_sym == format }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
if format.is_a?(Array)
|
129
|
+
format = format.select {|f| f.reader} if options[:has_reader]
|
130
|
+
format = format.select {|f| f.writer} if options[:has_writer]
|
131
|
+
|
132
|
+
return format.first if format.uniq.length == 1
|
133
|
+
elsif !format.nil?
|
134
|
+
return format
|
135
|
+
end
|
136
|
+
|
137
|
+
# If we have a sample, use that for format detection
|
138
|
+
if sample = (options[:sample] if options.is_a?(Hash)) || (yield if block_given?)
|
139
|
+
# Given a sample, perform format detection across the appropriate formats, choosing
|
140
|
+
# the first that matches
|
141
|
+
format ||= @@subclasses
|
142
|
+
|
143
|
+
# Return first format that has a positive detection
|
144
|
+
format.detect {|f| f.detect(sample)} || format.first
|
145
|
+
elsif format.is_a?(Array)
|
146
|
+
# Otherwise, just return the first matching format
|
147
|
+
format.first
|
148
|
+
else
|
149
|
+
nil
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Returns MIME content types for known RDF serialization formats.
|
155
|
+
#
|
156
|
+
# @return [Hash{String => Array<Class>}]
|
157
|
+
def self.content_types
|
158
|
+
@@content_types
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# Returns file extensions for known RDF serialization formats.
|
163
|
+
#
|
164
|
+
# @return [Hash{Symbol => Array<Class>}]
|
165
|
+
def self.file_extensions
|
166
|
+
@@file_extensions
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Returns a symbol appropriate to use with RDF::Format.for()
|
171
|
+
# @return [Symbol]
|
172
|
+
def self.to_sym
|
173
|
+
elements = self.to_s.split("::")
|
174
|
+
sym = elements.pop
|
175
|
+
sym = elements.pop if sym == 'Format'
|
176
|
+
sym.downcase.to_s.to_sym
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# Retrieves or defines the reader class for this RDF serialization
|
181
|
+
# format.
|
182
|
+
#
|
183
|
+
# @overload reader(klass)
|
184
|
+
# Defines the reader class for this RDF serialization format.
|
185
|
+
#
|
186
|
+
# The class should be a subclass of {RDF::Reader}, or implement the
|
187
|
+
# same interface.
|
188
|
+
#
|
189
|
+
# @param [Class] klass
|
190
|
+
# @return [void]
|
191
|
+
#
|
192
|
+
# @overload reader
|
193
|
+
# Defines the reader class for this RDF serialization format.
|
194
|
+
#
|
195
|
+
# The block should return a subclass of {RDF::Reader}, or a class that
|
196
|
+
# implements the same interface. The block won't be invoked until the
|
197
|
+
# reader class is first needed.
|
198
|
+
#
|
199
|
+
# @yield
|
200
|
+
# @yieldreturn [Class] klass
|
201
|
+
# @return [void]
|
202
|
+
#
|
203
|
+
# @overload reader
|
204
|
+
# Retrieves the reader class for this RDF serialization format.
|
205
|
+
#
|
206
|
+
# @return [Class]
|
207
|
+
#
|
208
|
+
# @return [void]
|
209
|
+
def self.reader(klass = nil, &block)
|
210
|
+
case
|
211
|
+
when klass
|
212
|
+
@@readers[self] = klass
|
213
|
+
when block_given?
|
214
|
+
@@readers[self] = block
|
215
|
+
else
|
216
|
+
klass = @@readers[self]
|
217
|
+
klass = @@readers[self] = klass.call if klass.is_a?(Proc)
|
218
|
+
klass
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
##
|
223
|
+
# Retrieves or defines the writer class for this RDF serialization
|
224
|
+
# format.
|
225
|
+
#
|
226
|
+
# @overload writer(klass)
|
227
|
+
# Defines the writer class for this RDF serialization format.
|
228
|
+
#
|
229
|
+
# The class should be a subclass of {RDF::Writer}, or implement the
|
230
|
+
# same interface.
|
231
|
+
#
|
232
|
+
# @param [Class] klass
|
233
|
+
# @return [void]
|
234
|
+
#
|
235
|
+
# @overload writer
|
236
|
+
# Defines the writer class for this RDF serialization format.
|
237
|
+
#
|
238
|
+
# The block should return a subclass of {RDF::Writer}, or a class that
|
239
|
+
# implements the same interface. The block won't be invoked until the
|
240
|
+
# writer class is first needed.
|
241
|
+
#
|
242
|
+
# @yield
|
243
|
+
# @yieldreturn [Class] klass
|
244
|
+
# @return [void]
|
245
|
+
#
|
246
|
+
# @overload writer
|
247
|
+
# Retrieves the writer class for this RDF serialization format.
|
248
|
+
#
|
249
|
+
# @return [Class]
|
250
|
+
#
|
251
|
+
# @return [void]
|
252
|
+
def self.writer(klass = nil, &block)
|
253
|
+
case
|
254
|
+
when klass
|
255
|
+
@@writers[self] = klass
|
256
|
+
when block_given?
|
257
|
+
@@writers[self] = block
|
258
|
+
else
|
259
|
+
klass = @@writers[self]
|
260
|
+
klass = @@writers[self] = klass.call if klass.is_a?(Proc)
|
261
|
+
klass
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
|
266
|
+
##
|
267
|
+
# Use a text sample to detect the format of an input file. Sub-classes implement
|
268
|
+
# a matcher sufficient to detect probably format matches, including disambiguating
|
269
|
+
# between other similar formats.
|
270
|
+
#
|
271
|
+
# Used to determine format class from loaded formats by {RDF::Format.for} when a
|
272
|
+
# match cannot be unambigiously found otherwise.
|
273
|
+
#
|
274
|
+
# @example
|
275
|
+
# RDF::NTriples::Format.detect("<a> <b> <c> .") => true
|
276
|
+
#
|
277
|
+
# @param [String] sample Beginning several bytes (~ 1K) of input.
|
278
|
+
# @return [Boolean]
|
279
|
+
def self.detect(sample)
|
280
|
+
false
|
281
|
+
end
|
282
|
+
|
283
|
+
class << self
|
284
|
+
alias_method :reader_class, :reader
|
285
|
+
alias_method :writer_class, :writer
|
286
|
+
end
|
287
|
+
|
288
|
+
##
|
289
|
+
# Retrieves or defines MIME content types for this RDF serialization format.
|
290
|
+
#
|
291
|
+
# @overload content_type(type, options)
|
292
|
+
# Retrieves or defines the MIME content type for this RDF serialization format.
|
293
|
+
#
|
294
|
+
# Optionally also defines alias MIME content types for this RDF serialization format.
|
295
|
+
#
|
296
|
+
# Optionally also defines a file extension, or a list of file
|
297
|
+
# extensions, that should be mapped to the given MIME type and handled
|
298
|
+
# by this class.
|
299
|
+
#
|
300
|
+
# @param [String] type
|
301
|
+
# @param [Hash{Symbol => Object}] options
|
302
|
+
# @option options [String] :alias (nil)
|
303
|
+
# @option options [Array<String>] :aliases (nil)
|
304
|
+
# @option options [Symbol] :extension (nil)
|
305
|
+
# @option options [Array<Symbol>] :extensions (nil)
|
306
|
+
# @return [void]
|
307
|
+
#
|
308
|
+
# @overload content_type
|
309
|
+
# Retrieves the MIME content types for this RDF serialization format.
|
310
|
+
#
|
311
|
+
# The return is an array where the first element is the cannonical
|
312
|
+
# MIME type for the format and following elements are alias MIME types.
|
313
|
+
#
|
314
|
+
# @return [Array<String>]
|
315
|
+
def self.content_type(type = nil, options = {})
|
316
|
+
if type.nil?
|
317
|
+
[@@content_type[self], @@content_types.map {
|
318
|
+
|ct, cl| (cl.include?(self) && ct != @@content_type[self]) ? ct : nil }].flatten.compact
|
319
|
+
else
|
320
|
+
@@content_type[self] = type
|
321
|
+
(@@content_types[type] ||= []) << self
|
322
|
+
|
323
|
+
if extensions = (options[:extension] || options[:extensions])
|
324
|
+
extensions = [extensions].flatten.map(&:to_sym)
|
325
|
+
extensions.each { |ext| (@@file_extensions[ext] ||= []) << self }
|
326
|
+
end
|
327
|
+
if aliases = (options[:alias] || options[:aliases])
|
328
|
+
aliases = [aliases].flatten.each { |a| (@@content_types[a] ||= []) << self }
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
protected
|
334
|
+
|
335
|
+
##
|
336
|
+
# Defines a required Ruby library for this RDF serialization format.
|
337
|
+
#
|
338
|
+
# The given library will be required lazily, i.e. only when it is
|
339
|
+
# actually first needed, such as when instantiating a reader or parser
|
340
|
+
# instance for this format.
|
341
|
+
#
|
342
|
+
# @param [String, #to_s] library
|
343
|
+
# @return [void]
|
344
|
+
def self.require(library)
|
345
|
+
(@@requires[self] ||= []) << library.to_s
|
346
|
+
end
|
347
|
+
|
348
|
+
##
|
349
|
+
# Defines the content encoding for this RDF serialization format.
|
350
|
+
#
|
351
|
+
# @param [#to_sym] encoding
|
352
|
+
# @return [void]
|
353
|
+
def self.content_encoding(encoding)
|
354
|
+
@@content_encoding[self] = encoding.to_sym
|
355
|
+
end
|
356
|
+
|
357
|
+
private
|
358
|
+
|
359
|
+
private_class_method :new
|
360
|
+
|
361
|
+
@@requires = {} # @private
|
362
|
+
@@file_extensions = {} # @private
|
363
|
+
@@content_type = {} # @private
|
364
|
+
@@content_types = {} # @private
|
365
|
+
@@content_encoding = {} # @private
|
366
|
+
@@readers = {} # @private
|
367
|
+
@@writers = {} # @private
|
368
|
+
@@subclasses = [] # @private
|
369
|
+
|
370
|
+
##
|
371
|
+
# @private
|
372
|
+
# @return [void]
|
373
|
+
def self.inherited(child)
|
374
|
+
@@subclasses << child
|
375
|
+
super
|
376
|
+
end
|
377
|
+
end # Format
|
378
|
+
|
379
|
+
##
|
380
|
+
# The base class for RDF serialization format errors.
|
381
|
+
class FormatError < IOError
|
382
|
+
end # FormatError
|
383
|
+
end # RDF
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module RDF
|
2
|
+
##
|
3
|
+
# @since 0.2.0
|
4
|
+
module Countable
|
5
|
+
extend RDF::Util::Aliasing::LateBound
|
6
|
+
|
7
|
+
##
|
8
|
+
# Returns `true` if `self` contains no RDF statements.
|
9
|
+
#
|
10
|
+
# @return [Boolean]
|
11
|
+
def empty?
|
12
|
+
empty = true
|
13
|
+
each { empty = false; break }
|
14
|
+
empty
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Returns the number of RDF statements in `self`.
|
19
|
+
#
|
20
|
+
# @return [Integer]
|
21
|
+
def count
|
22
|
+
count = 0
|
23
|
+
each { count += 1 }
|
24
|
+
count
|
25
|
+
end
|
26
|
+
alias_method :size, :count
|
27
|
+
|
28
|
+
##
|
29
|
+
# @private
|
30
|
+
# @param [Symbol, #to_sym] method
|
31
|
+
# @return [Enumerator]
|
32
|
+
# @see Object#enum_for
|
33
|
+
def enum_for(method = :each, *args)
|
34
|
+
# Ensure that enumerators support the `#empty?` and `#count` methods:
|
35
|
+
super.extend(RDF::Countable)
|
36
|
+
end
|
37
|
+
alias_method :to_enum, :enum_for
|
38
|
+
end # Countable
|
39
|
+
end # RDF
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RDF
|
2
|
+
##
|
3
|
+
module Durable
|
4
|
+
extend RDF::Util::Aliasing::LateBound
|
5
|
+
|
6
|
+
##
|
7
|
+
# Returns `true` if `self` is durable.
|
8
|
+
#
|
9
|
+
# @return [Boolean]
|
10
|
+
# @see #nondurable?
|
11
|
+
def durable?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
alias_method :persistent?, :durable?
|
16
|
+
|
17
|
+
##
|
18
|
+
# Returns `true` if `self` is nondurable.
|
19
|
+
#
|
20
|
+
# @return [Boolean]
|
21
|
+
# @see #durable?
|
22
|
+
def nondurable?
|
23
|
+
!durable?
|
24
|
+
end
|
25
|
+
|
26
|
+
alias_method :ephemeral?, :nondurable?
|
27
|
+
alias_method :nonpersistent?, :nondurable?
|
28
|
+
alias_method :transient?, :nondurable?
|
29
|
+
alias_method :volatile?, :nondurable?
|
30
|
+
end
|
31
|
+
end
|