rdf 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README +49 -32
- data/VERSION +1 -1
- data/lib/rdf.rb +7 -0
- data/lib/rdf/cli.rb +1 -1
- data/lib/rdf/format.rb +95 -0
- data/lib/rdf/graph.rb +8 -0
- data/lib/rdf/literal.rb +66 -1
- data/lib/rdf/node.rb +34 -4
- data/lib/rdf/ntriples.rb +12 -0
- data/lib/rdf/ntriples/format.rb +13 -0
- data/lib/rdf/ntriples/reader.rb +87 -0
- data/lib/rdf/ntriples/writer.rb +50 -0
- data/lib/rdf/query.rb +212 -0
- data/lib/rdf/query/pattern.rb +152 -0
- data/lib/rdf/query/solution.rb +139 -0
- data/lib/rdf/query/variable.rb +145 -0
- data/lib/rdf/reader.rb +7 -31
- data/lib/rdf/reader/ntriples.rb +4 -85
- data/lib/rdf/repository.rb +3 -1
- data/lib/rdf/statement.rb +54 -11
- data/lib/rdf/uri.rb +19 -0
- data/lib/rdf/value.rb +53 -2
- data/lib/rdf/version.rb +1 -1
- data/lib/rdf/vocabulary.rb +17 -0
- data/lib/rdf/writer.rb +16 -38
- data/lib/rdf/writer/ntriples.rb +4 -49
- metadata +21 -2
@@ -0,0 +1,139 @@
|
|
1
|
+
module RDF class Query
|
2
|
+
##
|
3
|
+
# An RDF query solution.
|
4
|
+
#
|
5
|
+
# @example Iterating over every binding in the solution
|
6
|
+
# solution.each_binding { |name, value| puts value.inspect }
|
7
|
+
# solution.each_variable { |variable| puts variable.value.inspect }
|
8
|
+
#
|
9
|
+
# @example Iterating over every value in the solution
|
10
|
+
# solution.each_value { |value| puts value.inspect }
|
11
|
+
#
|
12
|
+
# @example Checking whether a variable is bound or unbound
|
13
|
+
# solution.bound?(:title)
|
14
|
+
# solution.unbound?(:mbox)
|
15
|
+
#
|
16
|
+
# @example Retrieving the value of a bound variable
|
17
|
+
# solution[:mbox]
|
18
|
+
# solution.mbox
|
19
|
+
#
|
20
|
+
# @example Retrieving all bindings in the solution as a `Hash`
|
21
|
+
# solution.to_hash #=> {:mbox => "jrhacker@example.org", ...}
|
22
|
+
#
|
23
|
+
class Solution
|
24
|
+
undef_method *(instance_methods - %w(__id__ __send__ __class__ __eval__ instance_eval inspect class object_id))
|
25
|
+
|
26
|
+
include Enumerable
|
27
|
+
|
28
|
+
##
|
29
|
+
# @param [Hash{Symbol => Value}] bindings
|
30
|
+
def initialize(bindings = {})
|
31
|
+
@bindings = bindings
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Enumerates over every variable binding in this solution.
|
36
|
+
#
|
37
|
+
# @yield [name, value]
|
38
|
+
# @yieldparam [Symbol, Value]
|
39
|
+
# @return [Enumerator]
|
40
|
+
def each_binding(&block)
|
41
|
+
@bindings.each(&block)
|
42
|
+
end
|
43
|
+
|
44
|
+
alias_method :each, :each_binding
|
45
|
+
|
46
|
+
##
|
47
|
+
# Enumerates over every variable name in this solution.
|
48
|
+
#
|
49
|
+
# @yield [name]
|
50
|
+
# @yieldparam [Symbol]
|
51
|
+
# @return [Enumerator]
|
52
|
+
def each_name(&block)
|
53
|
+
@bindings.each_key(&block)
|
54
|
+
end
|
55
|
+
|
56
|
+
alias_method :each_key, :each_name
|
57
|
+
|
58
|
+
##
|
59
|
+
# Enumerates over every variable value in this solution.
|
60
|
+
#
|
61
|
+
# @yield [value]
|
62
|
+
# @yieldparam [Value]
|
63
|
+
# @return [Enumerator]
|
64
|
+
def each_value(&block)
|
65
|
+
@bindings.each_value(&block)
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Enumerates over every variable in this solution.
|
70
|
+
#
|
71
|
+
# @yield [variable]
|
72
|
+
# @yieldparam [Variable]
|
73
|
+
# @return [Enumerator]
|
74
|
+
def each_variable(&block)
|
75
|
+
@bindings.each do |name, value|
|
76
|
+
block.call(Variable.new(name, value))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Returns `true` if the variable `name` is bound in this solution.
|
82
|
+
#
|
83
|
+
# @param [Symbol] name
|
84
|
+
# @return [Boolean]
|
85
|
+
def bound?(name)
|
86
|
+
!unbound?(name)
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# Returns `true` if the variable `name` is unbound in this solution.
|
91
|
+
#
|
92
|
+
# @param [Symbol] name
|
93
|
+
# @return [Boolean]
|
94
|
+
def unbound?(name)
|
95
|
+
@bindings[name.to_sym].nil?
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Returns the value of the variable `name`.
|
100
|
+
#
|
101
|
+
# @param [Symbol] name
|
102
|
+
# @return [Value]
|
103
|
+
def [](name)
|
104
|
+
@bindings[name.to_sym]
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# @return [Array<Array(Symbol, Value)>}
|
109
|
+
def to_a
|
110
|
+
@bindings.to_a
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# @return [Hash{Symbol => Value}}
|
115
|
+
def to_hash
|
116
|
+
@bindings.dup
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# @return [String]
|
121
|
+
def inspect
|
122
|
+
sprintf("#<%s:%#0x(%s)>", self.class.name, object_id, @bindings.inspect)
|
123
|
+
end
|
124
|
+
|
125
|
+
protected
|
126
|
+
|
127
|
+
##
|
128
|
+
# @param [Symbol] name
|
129
|
+
# @return [Value]
|
130
|
+
def method_missing(name, *args, &block)
|
131
|
+
if args.empty? && @bindings.has_key?(name.to_sym)
|
132
|
+
@bindings[name.to_sym]
|
133
|
+
else
|
134
|
+
super
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module RDF class Query
|
2
|
+
##
|
3
|
+
# An RDF query variable.
|
4
|
+
#
|
5
|
+
# @example Creating an unbound variable
|
6
|
+
# var = RDF::Query::Variable.new(:x)
|
7
|
+
# var.unbound? #=> true
|
8
|
+
# var.value #=> nil
|
9
|
+
#
|
10
|
+
# @example Unbound variables match any value
|
11
|
+
# var === 42 #=> true
|
12
|
+
#
|
13
|
+
# @example Creating a bound variable
|
14
|
+
# var = RDF::Query::Variable.new(:y, 123)
|
15
|
+
# var.bound? #=> true
|
16
|
+
# var.value #=> 123
|
17
|
+
#
|
18
|
+
# @example Bound variables match only their actual value
|
19
|
+
# var === 42 #=> false
|
20
|
+
# var === 123 #=> true
|
21
|
+
#
|
22
|
+
# @example Getting the variable name
|
23
|
+
# var.named? #=> true
|
24
|
+
# var.name #=> :y
|
25
|
+
# var.to_sym #=> :y
|
26
|
+
#
|
27
|
+
# @example Rebinding a variable returns the previous value
|
28
|
+
# var.bind!(456) #=> 123
|
29
|
+
# var.value #=> 456
|
30
|
+
#
|
31
|
+
# @example Unbinding a previously bound variable
|
32
|
+
# var.unbind!
|
33
|
+
# var.unbound? #=> true
|
34
|
+
#
|
35
|
+
# @example Getting the string representation of a variable
|
36
|
+
# var = RDF::Query::Variable.new(:x)
|
37
|
+
# var.to_s #=> "?x"
|
38
|
+
# var = RDF::Query::Variable.new(:y, 123)
|
39
|
+
# var.to_s #=> "?y=123"
|
40
|
+
#
|
41
|
+
class Variable < Value
|
42
|
+
# @return [Symbol] The variable's name.
|
43
|
+
attr_accessor :name
|
44
|
+
|
45
|
+
alias_method :to_sym, :name
|
46
|
+
|
47
|
+
# @return [Value] The variable's value.
|
48
|
+
attr_accessor :value
|
49
|
+
|
50
|
+
##
|
51
|
+
# @param [Symbol] name
|
52
|
+
# @param [Value] value
|
53
|
+
def initialize(name, value = nil)
|
54
|
+
@name, @value = name.to_sym, value
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Returns `true` if this variable has a name.
|
59
|
+
#
|
60
|
+
# @return [Boolean]
|
61
|
+
def named?
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Returns `true` if this variable is bound.
|
67
|
+
#
|
68
|
+
# @return [Boolean]
|
69
|
+
def bound?
|
70
|
+
!unbound?
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Returns `true` if this variable is unbound.
|
75
|
+
#
|
76
|
+
# @return [Boolean]
|
77
|
+
def unbound?
|
78
|
+
value.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Rebinds this variable to the given `value`.
|
83
|
+
#
|
84
|
+
# @param [Value] value
|
85
|
+
# @return [Value] The previous value, if any.
|
86
|
+
def bind(value)
|
87
|
+
old_value = self.value
|
88
|
+
self.value = value
|
89
|
+
old_value
|
90
|
+
end
|
91
|
+
|
92
|
+
alias_method :bind!, :bind
|
93
|
+
|
94
|
+
##
|
95
|
+
# Unbinds this variable, discarding any currently bound value.
|
96
|
+
#
|
97
|
+
# @return [Value] The previous value, if any.
|
98
|
+
def unbind
|
99
|
+
old_value = self.value
|
100
|
+
self.value = nil
|
101
|
+
old_value
|
102
|
+
end
|
103
|
+
|
104
|
+
alias_method :unbind!, :unbind
|
105
|
+
|
106
|
+
##
|
107
|
+
# Returns this variable as `Hash`.
|
108
|
+
#
|
109
|
+
# @return [Hash{Symbol => Variable}]
|
110
|
+
def variables
|
111
|
+
{ name => self }
|
112
|
+
end
|
113
|
+
|
114
|
+
alias_method :to_hash, :variables
|
115
|
+
|
116
|
+
##
|
117
|
+
# Returns this variable's bindings (if any) as a `Hash`.
|
118
|
+
#
|
119
|
+
# @return [Hash{Symbol => Value}]
|
120
|
+
def bindings
|
121
|
+
unbound? ? {} : { name => value }
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Compares this variable with the given value.
|
126
|
+
#
|
127
|
+
# @param [Value] other
|
128
|
+
# @return [Boolean]
|
129
|
+
def ===(other)
|
130
|
+
if unbound?
|
131
|
+
true # match anything when unbound
|
132
|
+
else
|
133
|
+
value === other
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
##
|
138
|
+
# Returns a string representation of this variable.
|
139
|
+
#
|
140
|
+
# @return [String]
|
141
|
+
def to_s
|
142
|
+
unbound? ? "?#{name}" : "?#{name}=#{value}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end end
|
data/lib/rdf/reader.rb
CHANGED
@@ -4,15 +4,10 @@ module RDF
|
|
4
4
|
#
|
5
5
|
# @abstract
|
6
6
|
class Reader
|
7
|
-
autoload :NTriples, 'rdf/reader/ntriples'
|
7
|
+
autoload :NTriples, 'rdf/reader/ntriples' # @deprecated
|
8
8
|
|
9
9
|
include Enumerable
|
10
10
|
|
11
|
-
@@subclasses = []
|
12
|
-
@@file_extensions = {}
|
13
|
-
@@content_types = {}
|
14
|
-
@@content_encoding = {}
|
15
|
-
|
16
11
|
##
|
17
12
|
# Enumerates known RDF reader classes.
|
18
13
|
#
|
@@ -22,24 +17,13 @@ module RDF
|
|
22
17
|
!block_given? ? @@subclasses : @@subclasses.each { |klass| yield klass }
|
23
18
|
end
|
24
19
|
|
25
|
-
##
|
26
|
-
# @return [Hash{String => Symbol}]
|
27
|
-
def self.content_types
|
28
|
-
@@content_types
|
29
|
-
end
|
30
|
-
|
31
|
-
##
|
32
|
-
# @return [Hash{Symbol => String}]
|
33
|
-
def self.file_extensions
|
34
|
-
@@file_extensions
|
35
|
-
end
|
36
|
-
|
37
20
|
##
|
38
21
|
# @param [Symbol] format
|
39
22
|
# @return [Class]
|
40
23
|
def self.for(format)
|
41
24
|
klass = case format.to_s.downcase.to_sym
|
42
|
-
when :ntriples then RDF::Reader
|
25
|
+
when :ntriples then RDF::NTriples::Reader
|
26
|
+
else nil # FIXME
|
43
27
|
end
|
44
28
|
end
|
45
29
|
|
@@ -127,23 +111,15 @@ module RDF
|
|
127
111
|
|
128
112
|
private
|
129
113
|
|
114
|
+
@@subclasses = [] # @private
|
115
|
+
|
130
116
|
def self.inherited(child) #:nodoc:
|
131
117
|
@@subclasses << child
|
132
118
|
super
|
133
119
|
end
|
134
120
|
|
135
|
-
def self.
|
136
|
-
|
137
|
-
@@content_types[type] << self
|
138
|
-
|
139
|
-
if options[:extension]
|
140
|
-
extensions = [options[:extension]].flatten.map { |ext| ext.to_sym }
|
141
|
-
extensions.each { |ext| @@file_extensions[ext] = type }
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def self.content_encoding(encoding)
|
146
|
-
@@content_encoding[self] = encoding.to_sym
|
121
|
+
def self.format(klass)
|
122
|
+
# TODO
|
147
123
|
end
|
148
124
|
|
149
125
|
def lineno
|
data/lib/rdf/reader/ntriples.rb
CHANGED
@@ -1,86 +1,5 @@
|
|
1
|
-
module RDF
|
2
|
-
|
3
|
-
|
4
|
-
#
|
5
|
-
# @see http://www.w3.org/TR/rdf-testcases/#ntriples
|
6
|
-
class NTriples < Reader
|
7
|
-
content_type 'text/plain', :extension => :nt
|
8
|
-
content_encoding 'ascii'
|
9
|
-
|
10
|
-
protected
|
11
|
-
|
12
|
-
##
|
13
|
-
# @return [Array, nil]
|
14
|
-
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar
|
15
|
-
def read_triple
|
16
|
-
loop do
|
17
|
-
readline.strip! # EOFError thrown on end of input
|
18
|
-
|
19
|
-
unless blank? || read_comment
|
20
|
-
subject = read_uriref || read_bnode || fail_subject
|
21
|
-
predicate = read_uriref || fail_predicate
|
22
|
-
object = read_uriref || read_bnode || read_literal || fail_object
|
23
|
-
return [subject, predicate, object]
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
##
|
29
|
-
# @return [Boolean]
|
30
|
-
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar (comment)
|
31
|
-
def read_comment
|
32
|
-
match(/^#\s*(.*)$/)
|
33
|
-
end
|
34
|
-
|
35
|
-
##
|
36
|
-
# @return [URI, nil]
|
37
|
-
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar (uriref)
|
38
|
-
def read_uriref
|
39
|
-
if uri = match(/^<([^>]+)>/)
|
40
|
-
RDF::URI.parse(uri)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
##
|
45
|
-
# @return [Node, nil]
|
46
|
-
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar (nodeID)
|
47
|
-
def read_bnode
|
48
|
-
if node_id = match(/^_:([A-Za-z][A-Za-z0-9]*)/)
|
49
|
-
@nodes[node_id] ||= Object.new # TODO: RDF::Node.new
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
##
|
54
|
-
# @return [String, Literal, nil]
|
55
|
-
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_grammar (literal)
|
56
|
-
def read_literal
|
57
|
-
if literal = match(/^"((?:\\"|[^"])*)"/)
|
58
|
-
literal = unescaped(literal)
|
59
|
-
|
60
|
-
if language = match(/^@([a-z]+[\-a-z0-9]*)/)
|
61
|
-
# TODO: RDF::Literal.new(literal, :language => language)
|
62
|
-
literal
|
63
|
-
elsif datatype = match(/^(\^\^)/)
|
64
|
-
# TODO: RDF::Literal.new(literal, :type => read_uriref || fail_object)
|
65
|
-
literal
|
66
|
-
else
|
67
|
-
literal # plain string literal
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
##
|
73
|
-
# @param [String] string
|
74
|
-
# @return [String]
|
75
|
-
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
|
76
|
-
def unescaped(string)
|
77
|
-
["\t", "\n", "\r", "\"", "\\"].each do |escape|
|
78
|
-
string.gsub!(escape.inspect[1...-1], escape)
|
79
|
-
end
|
80
|
-
string.gsub!(/\\u([0-9A-Fa-f]{4,4})/u) { [$1.hex].pack('U*') }
|
81
|
-
string.gsub!(/\\U([0-9A-Fa-f]{8,8})/u) { [$1.hex].pack('U*') }
|
82
|
-
string
|
83
|
-
end
|
84
|
-
|
1
|
+
module RDF
|
2
|
+
class Reader
|
3
|
+
NTriples = RDF::NTriples::Reader # @deprecated
|
85
4
|
end
|
86
|
-
end
|
5
|
+
end
|
data/lib/rdf/repository.rb
CHANGED
@@ -150,13 +150,15 @@ module RDF
|
|
150
150
|
##
|
151
151
|
# Queries the repository for RDF statements matching the given pattern.
|
152
152
|
#
|
153
|
-
# @param [Statement, Array(Value)] pattern
|
153
|
+
# @param [Query, Statement, Array(Value)] pattern
|
154
154
|
# @yield [statement]
|
155
155
|
# @yieldparam [Statement]
|
156
156
|
# @return [Array<Statement>, nil]
|
157
157
|
def query(pattern, &block)
|
158
158
|
raise TypeError.new("repository is not readable") unless readable?
|
159
159
|
case pattern
|
160
|
+
when Query
|
161
|
+
pattern.execute(self, &block)
|
160
162
|
when Array
|
161
163
|
query(Statement.new(*pattern), &block)
|
162
164
|
when Statement
|