rdf 3.0.11 → 3.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/AUTHORS +1 -1
- data/README.md +127 -95
- data/UNLICENSE +1 -1
- data/VERSION +1 -1
- data/etc/doap.nt +79 -85
- data/lib/rdf.rb +35 -23
- data/lib/rdf/changeset.rb +80 -19
- data/lib/rdf/cli.rb +7 -7
- data/lib/rdf/format.rb +17 -10
- data/lib/rdf/mixin/enumerable.rb +4 -3
- data/lib/rdf/mixin/mutable.rb +5 -15
- data/lib/rdf/mixin/queryable.rb +12 -4
- data/lib/rdf/mixin/transactable.rb +2 -2
- data/lib/rdf/mixin/writable.rb +9 -14
- data/lib/rdf/model/dataset.rb +1 -1
- data/lib/rdf/model/graph.rb +7 -4
- data/lib/rdf/model/list.rb +5 -5
- data/lib/rdf/model/literal.rb +3 -3
- data/lib/rdf/model/statement.rb +32 -9
- data/lib/rdf/model/uri.rb +53 -32
- data/lib/rdf/nquads.rb +6 -6
- data/lib/rdf/ntriples.rb +7 -5
- data/lib/rdf/ntriples/reader.rb +29 -7
- data/lib/rdf/ntriples/writer.rb +10 -1
- data/lib/rdf/query.rb +27 -35
- data/lib/rdf/query/hash_pattern_normalizer.rb +14 -12
- data/lib/rdf/query/pattern.rb +51 -18
- data/lib/rdf/query/solution.rb +20 -1
- data/lib/rdf/query/solutions.rb +15 -5
- data/lib/rdf/query/variable.rb +17 -5
- data/lib/rdf/reader.rb +76 -25
- data/lib/rdf/repository.rb +32 -18
- data/lib/rdf/transaction.rb +1 -1
- data/lib/rdf/util.rb +6 -5
- data/lib/rdf/util/cache.rb +2 -2
- data/lib/rdf/util/coercions.rb +60 -0
- data/lib/rdf/util/file.rb +20 -10
- data/lib/rdf/util/logger.rb +6 -6
- data/lib/rdf/util/uuid.rb +4 -4
- data/lib/rdf/vocab/owl.rb +401 -86
- data/lib/rdf/vocab/rdfs.rb +81 -18
- data/lib/rdf/vocab/rdfv.rb +147 -1
- data/lib/rdf/vocab/writer.rb +41 -3
- data/lib/rdf/vocab/xsd.rb +203 -2
- data/lib/rdf/vocabulary.rb +73 -15
- data/lib/rdf/writer.rb +33 -11
- metadata +34 -28
data/lib/rdf/mixin/queryable.rb
CHANGED
@@ -19,7 +19,7 @@ module RDF
|
|
19
19
|
#
|
20
20
|
# @example Querying for statements having a given predicate
|
21
21
|
# queryable.query([nil, RDF::Vocab::DOAP.developer, nil])
|
22
|
-
# queryable.query(predicate: RDF::Vocab::DOAP.developer) do |statement|
|
22
|
+
# queryable.query({predicate: RDF::Vocab::DOAP.developer}) do |statement|
|
23
23
|
# puts statement.inspect
|
24
24
|
# end
|
25
25
|
#
|
@@ -50,7 +50,7 @@ module RDF
|
|
50
50
|
solutions = RDF::Query::Solutions.new
|
51
51
|
block = lambda {|solution| solutions << solution} unless block_given?
|
52
52
|
before_query(pattern) if respond_to?(:before_query)
|
53
|
-
query_execute(pattern, options, &block)
|
53
|
+
query_execute(pattern, **options, &block)
|
54
54
|
after_query(pattern) if respond_to?(:after_query)
|
55
55
|
# Returns the solutions, not an enumerator
|
56
56
|
solutions
|
@@ -85,7 +85,7 @@ module RDF
|
|
85
85
|
|
86
86
|
# Otherwise, we delegate to `#query_pattern`:
|
87
87
|
else # pattern.variable?
|
88
|
-
query_pattern(pattern, options, &block)
|
88
|
+
query_pattern(pattern, **options, &block)
|
89
89
|
end
|
90
90
|
after_query(pattern) if respond_to?(:after_query)
|
91
91
|
enum
|
@@ -116,7 +116,7 @@ module RDF
|
|
116
116
|
# query execution by breaking down the query into its constituent
|
117
117
|
# triple patterns and invoking `RDF::Query::Pattern#execute` on each
|
118
118
|
# pattern.
|
119
|
-
query.execute(self, options, &block)
|
119
|
+
query.execute(self, **options, &block)
|
120
120
|
end
|
121
121
|
protected :query_execute
|
122
122
|
|
@@ -128,6 +128,14 @@ module RDF
|
|
128
128
|
# method in order to provide for storage-specific optimized triple
|
129
129
|
# pattern matching.
|
130
130
|
#
|
131
|
+
# ## RDFStar (RDF*)
|
132
|
+
#
|
133
|
+
# Statements may have embedded statements as either a subject or object, recursively.
|
134
|
+
#
|
135
|
+
# Patterns may also have embedded patterns as either a subject or object, recursively.
|
136
|
+
#
|
137
|
+
# When matching, match an embedded pattern against embedded statements, recursively. (see {RDF::Query::Pattern#eql?})
|
138
|
+
#
|
131
139
|
# @param [RDF::Query::Pattern] pattern
|
132
140
|
# the query pattern to match
|
133
141
|
# @param [Hash{Symbol => Object}] options ({})
|
@@ -21,14 +21,14 @@ module RDF
|
|
21
21
|
#
|
22
22
|
# @example running a transaction
|
23
23
|
# repository.transaction(mutable: true) do |tx|
|
24
|
-
# tx.insert [RDF::URI("
|
24
|
+
# tx.insert [RDF::URI("https://rubygems.org/gems/rdf"), RDF::RDFS.label, "RDF.rb"]
|
25
25
|
# end
|
26
26
|
#
|
27
27
|
# Raising an error within the transaction block causes automatic rollback.
|
28
28
|
#
|
29
29
|
# @example manipulating a live transaction
|
30
30
|
# tx = repository.transaction(mutable: true)
|
31
|
-
# tx.insert [RDF::URI("
|
31
|
+
# tx.insert [RDF::URI("https://rubygems.org/gems/rdf"), RDF::RDFS.label, "RDF.rb"]
|
32
32
|
# tx.execute
|
33
33
|
#
|
34
34
|
# @overload transaction(mutable: false)
|
data/lib/rdf/mixin/writable.rb
CHANGED
@@ -7,6 +7,7 @@ module RDF
|
|
7
7
|
# @see RDF::Repository
|
8
8
|
module Writable
|
9
9
|
extend RDF::Util::Aliasing::LateBound
|
10
|
+
include RDF::Util::Coercions
|
10
11
|
|
11
12
|
##
|
12
13
|
# Returns `true` if `self` is writable.
|
@@ -53,31 +54,20 @@ module RDF
|
|
53
54
|
# @overload insert(*statements)
|
54
55
|
# @param [Array<RDF::Statement>] statements
|
55
56
|
# @return [self]
|
57
|
+
# @raise [ArgumentError] on an attempt to insert an embedded statement when it is not supported
|
56
58
|
#
|
57
59
|
# @overload insert(statements)
|
58
60
|
# @param [Enumerable<RDF::Statement>] statements
|
59
61
|
# @return [self]
|
62
|
+
# @raise [ArgumentError] on an attempt to insert an embedded statement when it is not supported
|
60
63
|
def insert(*statements)
|
61
|
-
statements
|
62
|
-
case
|
63
|
-
when value.respond_to?(:each_statement)
|
64
|
-
insert_statements(value)
|
65
|
-
nil
|
66
|
-
when (statement = Statement.from(value))
|
67
|
-
statement
|
68
|
-
else
|
69
|
-
raise ArgumentError.new("not a valid statement: #{value.inspect}")
|
70
|
-
end
|
71
|
-
end
|
72
|
-
statements.compact!
|
73
|
-
insert_statements(statements) unless statements.empty?
|
64
|
+
coerce_statements(statements) { |value| insert_statements value }
|
74
65
|
|
75
66
|
return self
|
76
67
|
end
|
77
68
|
alias_method :insert!, :insert
|
78
69
|
|
79
70
|
protected
|
80
|
-
|
81
71
|
##
|
82
72
|
# Inserts statements from the given RDF reader into the underlying
|
83
73
|
# storage or output stream.
|
@@ -132,10 +122,14 @@ module RDF
|
|
132
122
|
#
|
133
123
|
# @param [RDF::Enumerable] statements
|
134
124
|
# @return [void]
|
125
|
+
# @raise [ArgumentError] on an attempt to insert an embedded statement when it is not supported
|
135
126
|
# @since 0.1.6
|
136
127
|
def insert_statements(statements)
|
137
128
|
each = statements.respond_to?(:each_statement) ? :each_statement : :each
|
138
129
|
statements.__send__(each) do |statement|
|
130
|
+
if statement.embedded? && respond_to?(:supports?) && !supports?(:rdfstar)
|
131
|
+
raise ArgumentError, "Wriable does not support embedded statements"
|
132
|
+
end
|
139
133
|
insert_statement(statement)
|
140
134
|
end
|
141
135
|
end
|
@@ -150,6 +144,7 @@ module RDF
|
|
150
144
|
#
|
151
145
|
# @param [RDF::Statement] statement
|
152
146
|
# @return [void]
|
147
|
+
# @raise [ArgumentError] on an attempt to insert an embedded statement when it is not supported
|
153
148
|
# @abstract
|
154
149
|
def insert_statement(statement)
|
155
150
|
raise NotImplementedError.new("#{self.class}#insert_statement")
|
data/lib/rdf/model/dataset.rb
CHANGED
data/lib/rdf/model/graph.rb
CHANGED
@@ -211,7 +211,7 @@ module RDF
|
|
211
211
|
# @return [Integer]
|
212
212
|
# @see RDF::Enumerable#count
|
213
213
|
def count
|
214
|
-
@data.query(graph_name: graph_name || false).count
|
214
|
+
@data.query({graph_name: graph_name || false}).count
|
215
215
|
end
|
216
216
|
|
217
217
|
##
|
@@ -237,7 +237,7 @@ module RDF
|
|
237
237
|
# @see RDF::Enumerable#each_statement
|
238
238
|
def each(&block)
|
239
239
|
if @data.respond_to?(:query)
|
240
|
-
@data.query(graph_name: graph_name || false, &block)
|
240
|
+
@data.query({graph_name: graph_name || false}, &block)
|
241
241
|
elsif @data.respond_to?(:each)
|
242
242
|
@data.each(&block)
|
243
243
|
else
|
@@ -259,11 +259,11 @@ module RDF
|
|
259
259
|
##
|
260
260
|
# Graph equivalence based on the contents of each graph being _exactly_
|
261
261
|
# the same. To determine if the have the same _meaning_, consider
|
262
|
-
# [rdf-isomorphic](
|
262
|
+
# [rdf-isomorphic](https://rubygems.org/gems/rdf-isomorphic).
|
263
263
|
#
|
264
264
|
# @param [RDF::Graph] other
|
265
265
|
# @return [Boolean]
|
266
|
-
# @see
|
266
|
+
# @see https://rubygems.org/gems/rdf-isomorphic
|
267
267
|
def ==(other)
|
268
268
|
other.is_a?(RDF::Graph) &&
|
269
269
|
graph_name == other.graph_name &&
|
@@ -283,6 +283,9 @@ module RDF
|
|
283
283
|
# @private
|
284
284
|
# @see RDF::Mutable#insert
|
285
285
|
def insert_statement(statement)
|
286
|
+
if statement.embedded? && !@data.supports?(:rdfstar)
|
287
|
+
raise ArgumentError, "Graph does not support embedded statements"
|
288
|
+
end
|
286
289
|
statement = statement.dup
|
287
290
|
statement.graph_name = graph_name
|
288
291
|
@data.insert(statement)
|
data/lib/rdf/model/list.rb
CHANGED
@@ -59,7 +59,7 @@ module RDF
|
|
59
59
|
def initialize(subject: nil, graph: nil, values: nil, &block)
|
60
60
|
@subject = subject || RDF.nil
|
61
61
|
@graph = graph || RDF::Graph.new
|
62
|
-
is_empty = @graph.query(subject: subject, predicate: RDF.first).empty?
|
62
|
+
is_empty = @graph.query({subject: subject, predicate: RDF.first}).empty?
|
63
63
|
|
64
64
|
if subject && is_empty
|
65
65
|
# An empty list with explicit subject and value initializers
|
@@ -115,7 +115,7 @@ module RDF
|
|
115
115
|
list_nodes << li
|
116
116
|
rest = nil
|
117
117
|
firsts = rests = 0
|
118
|
-
@graph.query(subject: li) do |st|
|
118
|
+
@graph.query({subject: li}) do |st|
|
119
119
|
return false unless st.subject.node?
|
120
120
|
case st.predicate
|
121
121
|
when RDF.first
|
@@ -136,7 +136,7 @@ module RDF
|
|
136
136
|
|
137
137
|
# All elements other than the head must be referenced exactly once
|
138
138
|
return list_nodes.all? do |li|
|
139
|
-
refs = @graph.query(object: li).count
|
139
|
+
refs = @graph.query({object: li}).count
|
140
140
|
case refs
|
141
141
|
when 0 then li == subject
|
142
142
|
when 1 then true
|
@@ -479,7 +479,7 @@ module RDF
|
|
479
479
|
# @return [Boolean]
|
480
480
|
# @see http://ruby-doc.org/core-2.2.2/Array.html#method-i-empty-3F
|
481
481
|
def empty?
|
482
|
-
graph.query(subject: subject, predicate: RDF.first).empty?
|
482
|
+
graph.query({subject: subject, predicate: RDF.first}).empty?
|
483
483
|
end
|
484
484
|
|
485
485
|
##
|
@@ -822,7 +822,7 @@ module RDF
|
|
822
822
|
return enum_statement unless block_given?
|
823
823
|
|
824
824
|
each_subject do |subject|
|
825
|
-
graph.query(subject: subject, &block)
|
825
|
+
graph.query({subject: subject}, &block)
|
826
826
|
end
|
827
827
|
end
|
828
828
|
alias_method :to_rdf, :each_statement
|
data/lib/rdf/model/literal.rb
CHANGED
@@ -49,7 +49,7 @@ module RDF
|
|
49
49
|
# RDF::Literal.new(123).datatype #=> XSD.integer
|
50
50
|
# RDF::Literal.new(9223372036854775807).datatype #=> XSD.integer
|
51
51
|
# RDF::Literal.new(3.1415).datatype #=> XSD.double
|
52
|
-
# RDF::Literal.new(Time.now).datatype #=> XSD.
|
52
|
+
# RDF::Literal.new(Time.now).datatype #=> XSD.dateTime
|
53
53
|
# RDF::Literal.new(Date.new(2010)).datatype #=> XSD.date
|
54
54
|
# RDF::Literal.new(DateTime.new(2010)).datatype #=> XSD.dateTime
|
55
55
|
#
|
@@ -119,8 +119,8 @@ module RDF
|
|
119
119
|
when ::Float then RDF::Literal::Double
|
120
120
|
when ::BigDecimal then RDF::Literal::Decimal
|
121
121
|
when ::DateTime then RDF::Literal::DateTime
|
122
|
+
when ::Time then RDF::Literal::DateTime
|
122
123
|
when ::Date then RDF::Literal::Date
|
123
|
-
when ::Time then RDF::Literal::Time # FIXME: Ruby's Time class can represent datetimes as well
|
124
124
|
when ::Symbol then RDF::Literal::Token
|
125
125
|
else self
|
126
126
|
end
|
@@ -360,7 +360,7 @@ module RDF
|
|
360
360
|
# @return [Boolean] `true` or `false`
|
361
361
|
# @since 0.2.1
|
362
362
|
def valid?
|
363
|
-
return false if language? && language.to_s !~ /^[a-zA-Z]
|
363
|
+
return false if language? && language.to_s !~ /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/
|
364
364
|
return false if datatype? && datatype.invalid?
|
365
365
|
grammar = self.class.const_get(:GRAMMAR) rescue nil
|
366
366
|
grammar.nil? || value.match?(grammar)
|
data/lib/rdf/model/statement.rb
CHANGED
@@ -3,7 +3,7 @@ module RDF
|
|
3
3
|
# An RDF statement.
|
4
4
|
#
|
5
5
|
# @example Creating an RDF statement
|
6
|
-
# s = RDF::URI.new("
|
6
|
+
# s = RDF::URI.new("https://rubygems.org/gems/rdf")
|
7
7
|
# p = RDF::Vocab::DC.creator
|
8
8
|
# o = RDF::URI.new("http://ar.to/#self")
|
9
9
|
# RDF::Statement(s, p, o)
|
@@ -14,7 +14,7 @@ module RDF
|
|
14
14
|
#
|
15
15
|
# @example Creating an RDF statement from a `Hash`
|
16
16
|
# RDF::Statement({
|
17
|
-
# subject: RDF::URI.new("
|
17
|
+
# subject: RDF::URI.new("https://rubygems.org/gems/rdf"),
|
18
18
|
# predicate: RDF::Vocab::DC.creator,
|
19
19
|
# object: RDF::URI.new("http://ar.to/#self"),
|
20
20
|
# })
|
@@ -26,7 +26,7 @@ module RDF
|
|
26
26
|
# RDF::Statement(s, p, "o")
|
27
27
|
#
|
28
28
|
class Statement
|
29
|
-
include RDF::
|
29
|
+
include RDF::Resource
|
30
30
|
|
31
31
|
##
|
32
32
|
# @private
|
@@ -112,7 +112,7 @@ module RDF
|
|
112
112
|
elsif @subject.nil?
|
113
113
|
nil
|
114
114
|
else
|
115
|
-
raise ArgumentError, "expected subject to be nil or a
|
115
|
+
raise ArgumentError, "expected subject to be nil or a resource, was #{@subject.inspect}"
|
116
116
|
end
|
117
117
|
@predicate = Node.intern(@predicate) if @predicate.is_a?(Symbol)
|
118
118
|
@object = if @object.is_a?(Value)
|
@@ -124,6 +124,15 @@ module RDF
|
|
124
124
|
else
|
125
125
|
Literal.new(@object)
|
126
126
|
end
|
127
|
+
@graph_name = if @graph_name.is_a?(Value)
|
128
|
+
@graph_name.to_term
|
129
|
+
elsif @graph_name.is_a?(Symbol)
|
130
|
+
Node.intern(@graph_name)
|
131
|
+
elsif !@graph_name
|
132
|
+
@graph_name
|
133
|
+
else
|
134
|
+
raise ArgumentError, "expected graph_name to be nil or a resource, was #{@graph_name.inspect}"
|
135
|
+
end
|
127
136
|
end
|
128
137
|
|
129
138
|
##
|
@@ -140,10 +149,18 @@ module RDF
|
|
140
149
|
#
|
141
150
|
# @return [Boolean]
|
142
151
|
def variable?
|
143
|
-
!(has_subject? && subject.
|
144
|
-
has_predicate? && predicate.
|
145
|
-
has_object? &&
|
146
|
-
(has_graph? ? graph_name.
|
152
|
+
!(has_subject? && subject.constant? &&
|
153
|
+
has_predicate? && predicate.constant? &&
|
154
|
+
has_object? && object.constant? &&
|
155
|
+
(has_graph? ? graph_name.constant? : true))
|
156
|
+
end
|
157
|
+
|
158
|
+
##
|
159
|
+
# Returns `true` if any element of the statement is, itself, a statement.
|
160
|
+
#
|
161
|
+
# @return [Boolean]
|
162
|
+
def embedded?
|
163
|
+
subject && subject.statement? || object && object.statement?
|
147
164
|
end
|
148
165
|
|
149
166
|
##
|
@@ -386,7 +403,13 @@ module RDF
|
|
386
403
|
# @return [String]
|
387
404
|
def to_s
|
388
405
|
(graph_name ? to_quad : to_triple).map do |term|
|
389
|
-
term.
|
406
|
+
if term.is_a?(Statement)
|
407
|
+
"<<#{term.to_s[0..-3]}>>"
|
408
|
+
elsif term.respond_to?(:to_base)
|
409
|
+
term.to_base
|
410
|
+
else
|
411
|
+
term.inspect
|
412
|
+
end
|
390
413
|
end.join(" ") + " ."
|
391
414
|
end
|
392
415
|
|
data/lib/rdf/model/uri.rb
CHANGED
@@ -7,23 +7,23 @@ module RDF
|
|
7
7
|
# Also compatible with International Resource Identifier (IRI)
|
8
8
|
#
|
9
9
|
# @example Creating a URI reference (1)
|
10
|
-
# uri = RDF::URI.new("
|
10
|
+
# uri = RDF::URI.new("https://rubygems.org/gems/rdf")
|
11
11
|
#
|
12
12
|
# @example Creating a URI reference (2)
|
13
13
|
# uri = RDF::URI.new(scheme: 'http', host: 'rubygems.org', path: '/gems/rdf')
|
14
|
-
# #=> RDF::URI.new("
|
14
|
+
# #=> RDF::URI.new("https://rubygems.org/gems/rdf")
|
15
15
|
#
|
16
16
|
# @example Creating an interned URI reference
|
17
|
-
# uri = RDF::URI.intern("
|
17
|
+
# uri = RDF::URI.intern("https://rubygems.org/gems/rdf")
|
18
18
|
#
|
19
19
|
# @example Getting the string representation of a URI
|
20
|
-
# uri.to_s #=> "
|
20
|
+
# uri.to_s #=> "https://rubygems.org/gems/rdf"
|
21
21
|
#
|
22
|
-
#
|
23
|
-
# @see
|
24
|
-
# @see
|
25
|
-
# @see
|
26
|
-
# @see
|
22
|
+
# @see https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier
|
23
|
+
# @see https://en.wikipedia.org/wiki/Uniform_Resource_Identifier
|
24
|
+
# @see https://www.ietf.org/rfc/rfc3986.txt
|
25
|
+
# @see https://www.ietf.org/rfc/rfc3987.txt
|
26
|
+
# @see https://rubydoc.info/gems/addressable
|
27
27
|
class URI
|
28
28
|
include RDF::Resource
|
29
29
|
|
@@ -141,8 +141,8 @@ module RDF
|
|
141
141
|
#
|
142
142
|
# (see #initialize)
|
143
143
|
# @return [RDF::URI] an immutable, frozen URI object
|
144
|
-
def self.intern(str, *args)
|
145
|
-
(cache[(str = str.to_s).to_sym] ||= self.new(str, *args)).freeze
|
144
|
+
def self.intern(str, *args, **options)
|
145
|
+
(cache[(str = str.to_s).to_sym] ||= self.new(str, *args, **options)).freeze
|
146
146
|
end
|
147
147
|
|
148
148
|
##
|
@@ -225,11 +225,9 @@ module RDF
|
|
225
225
|
@mutex = Mutex.new
|
226
226
|
uri = args.first
|
227
227
|
if uri
|
228
|
-
@value = uri.to_s
|
229
|
-
if @value.encoding != Encoding::UTF_8
|
230
|
-
|
231
|
-
@value.freeze
|
232
|
-
end
|
228
|
+
@value = uri.to_s.dup
|
229
|
+
@value.dup.force_encoding(Encoding::UTF_8) if @value.encoding != Encoding::UTF_8
|
230
|
+
@value.freeze
|
233
231
|
else
|
234
232
|
%w(
|
235
233
|
scheme
|
@@ -402,7 +400,7 @@ module RDF
|
|
402
400
|
# @example Joining two URIs
|
403
401
|
# RDF::URI.new('http://example.org/foo/bar').join('/foo')
|
404
402
|
# #=> RDF::URI('http://example.org/foo')
|
405
|
-
# @see <
|
403
|
+
# @see <https://github.com/ruby-rdf/rdf-spec/blob/master/lib/rdf/spec/uri.rb>
|
406
404
|
# @see <http://tools.ietf.org/html/rfc3986#section-5.2>
|
407
405
|
# @see RDF::URI#/
|
408
406
|
# @see RDF::URI#+
|
@@ -431,7 +429,9 @@ module RDF
|
|
431
429
|
joined_parts[:query] = uri.query
|
432
430
|
else
|
433
431
|
# Merge path segments from section 5.2.3
|
434
|
-
|
432
|
+
# Note that if the path includes no segments, the entire path is removed
|
433
|
+
# > return a string consisting of the reference's path component appended to all but the last segment of the base URI's path (i.e., excluding any characters after the right-most "/" in the base URI path, or excluding the entire base URI path if it does not contain any "/" characters).
|
434
|
+
base_path = path.to_s.include?('/') ? path.to_s.sub(/\/[^\/]*$/, '/') : ''
|
435
435
|
joined_parts[:path] = self.class.normalize_path(base_path + uri.path)
|
436
436
|
joined_parts[:query] = uri.query
|
437
437
|
end
|
@@ -439,7 +439,7 @@ module RDF
|
|
439
439
|
end
|
440
440
|
|
441
441
|
# Return joined URI
|
442
|
-
RDF::URI.new(joined_parts)
|
442
|
+
RDF::URI.new(**joined_parts)
|
443
443
|
end
|
444
444
|
|
445
445
|
##
|
@@ -471,7 +471,7 @@ module RDF
|
|
471
471
|
# @see RDF::URI#+
|
472
472
|
# @see RDF::URI#join
|
473
473
|
# @see <http://tools.ietf.org/html/rfc3986#section-5.2>
|
474
|
-
# @see <
|
474
|
+
# @see <https://github.com/ruby-rdf/rdf-spec/blob/master/lib/rdf/spec/uri.rb>
|
475
475
|
# @example Building a HTTP URL
|
476
476
|
# RDF::URI.new('http://example.org') / 'jhacker' / 'foaf.ttl'
|
477
477
|
# #=> RDF::URI('http://example.org/jhacker/foaf.ttl')
|
@@ -507,7 +507,7 @@ module RDF
|
|
507
507
|
case fragment.to_s[0,1]
|
508
508
|
when '#'
|
509
509
|
# Base ending with '/', fragment beginning with '#'. The fragment wins, we use '#'.
|
510
|
-
res.path = res.path.to_s.sub
|
510
|
+
res.path = res.path.to_s.sub(/\/*$/, '')
|
511
511
|
# Add fragment
|
512
512
|
res.fragment = fragment.to_s.sub(/^#+/,'')
|
513
513
|
else
|
@@ -572,7 +572,7 @@ module RDF
|
|
572
572
|
self
|
573
573
|
else
|
574
574
|
RDF::URI.new(
|
575
|
-
object.merge(path: '/').
|
575
|
+
**object.merge(path: '/').
|
576
576
|
keep_if {|k, v| [:scheme, :authority, :path].include?(k)})
|
577
577
|
end
|
578
578
|
end
|
@@ -657,7 +657,7 @@ module RDF
|
|
657
657
|
#
|
658
658
|
# @return [RDF::URI]
|
659
659
|
def dup
|
660
|
-
self.class.new(
|
660
|
+
self.class.new(@value, **(@object || {}))
|
661
661
|
end
|
662
662
|
|
663
663
|
##
|
@@ -846,7 +846,7 @@ module RDF
|
|
846
846
|
parts[:user] = (user.dup.force_encoding(Encoding::UTF_8) if user)
|
847
847
|
parts[:password] = (password.dup.force_encoding(Encoding::UTF_8) if password)
|
848
848
|
parts[:host] = (host.dup.force_encoding(Encoding::UTF_8) if host)
|
849
|
-
parts[:port] = (
|
849
|
+
parts[:port] = (URI.decode(port).to_i if port)
|
850
850
|
parts[:path] = (path.to_s.dup.force_encoding(Encoding::UTF_8) unless path.empty?)
|
851
851
|
parts[:query] = (query[1..-1].dup.force_encoding(Encoding::UTF_8) if query)
|
852
852
|
parts[:fragment] = (fragment[1..-1].dup.force_encoding(Encoding::UTF_8) if fragment)
|
@@ -902,7 +902,7 @@ module RDF
|
|
902
902
|
# Normalized version of user
|
903
903
|
# @return [String]
|
904
904
|
def normalized_user
|
905
|
-
|
905
|
+
URI.encode(URI.decode(user), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if user
|
906
906
|
end
|
907
907
|
|
908
908
|
##
|
@@ -928,7 +928,7 @@ module RDF
|
|
928
928
|
# Normalized version of password
|
929
929
|
# @return [String]
|
930
930
|
def normalized_password
|
931
|
-
|
931
|
+
URI.encode(URI.decode(password), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if password
|
932
932
|
end
|
933
933
|
|
934
934
|
HOST_FROM_AUTHORITY_RE = /(?:[^@]+@)?([^:]+)(?::.*)?$/.freeze
|
@@ -937,7 +937,7 @@ module RDF
|
|
937
937
|
# @return [String]
|
938
938
|
def host
|
939
939
|
object.fetch(:host) do
|
940
|
-
@object[:host] = ($1 if HOST_FROM_AUTHORITY_RE.match(@object[:authority]))
|
940
|
+
@object[:host] = ($1 if @object[:authority] && HOST_FROM_AUTHORITY_RE.match(@object[:authority]))
|
941
941
|
end
|
942
942
|
end
|
943
943
|
|
@@ -965,7 +965,7 @@ module RDF
|
|
965
965
|
# @return [String]
|
966
966
|
def port
|
967
967
|
object.fetch(:port) do
|
968
|
-
@object[:port] = ($1 if PORT_FROM_AUTHORITY_RE.match(@object[:authority]))
|
968
|
+
@object[:port] = ($1 if @object[:authority] && PORT_FROM_AUTHORITY_RE.match(@object[:authority]))
|
969
969
|
end
|
970
970
|
end
|
971
971
|
|
@@ -1180,8 +1180,8 @@ module RDF
|
|
1180
1180
|
inject(return_type == Hash ? {} : []) do |memo,kv|
|
1181
1181
|
k,v = kv.to_s.split('=', 2)
|
1182
1182
|
next if k.to_s.empty?
|
1183
|
-
k =
|
1184
|
-
v =
|
1183
|
+
k = URI.decode(k)
|
1184
|
+
v = URI.decode(v) if v
|
1185
1185
|
if return_type == Hash
|
1186
1186
|
case memo[k]
|
1187
1187
|
when nil then memo[k] = v
|
@@ -1293,9 +1293,9 @@ module RDF
|
|
1293
1293
|
def normalize_segment(value, expr, downcase = false)
|
1294
1294
|
if value
|
1295
1295
|
value = value.dup.force_encoding(Encoding::UTF_8)
|
1296
|
-
decoded =
|
1296
|
+
decoded = URI.decode(value)
|
1297
1297
|
decoded.downcase! if downcase
|
1298
|
-
|
1298
|
+
URI.encode(decoded, /[^(?:#{expr})]/)
|
1299
1299
|
end
|
1300
1300
|
end
|
1301
1301
|
|
@@ -1314,6 +1314,27 @@ module RDF
|
|
1314
1314
|
""
|
1315
1315
|
end
|
1316
1316
|
end
|
1317
|
+
|
1318
|
+
# URI encode matching characters in value
|
1319
|
+
# From URI gem, as this is now generally deprecated
|
1320
|
+
def self.encode(str, expr)
|
1321
|
+
str.gsub(expr) do
|
1322
|
+
us = $&
|
1323
|
+
tmp = ''
|
1324
|
+
us.each_byte do |uc|
|
1325
|
+
tmp << sprintf('%%%02X', uc)
|
1326
|
+
end
|
1327
|
+
tmp
|
1328
|
+
end.force_encoding(Encoding::US_ASCII)
|
1329
|
+
end
|
1330
|
+
|
1331
|
+
# URI decode escape sequences in value
|
1332
|
+
# From URI gem, as this is now generally deprecated
|
1333
|
+
def self.decode(str)
|
1334
|
+
enc = str.encoding
|
1335
|
+
enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
|
1336
|
+
str.gsub(PCT_ENCODED) { [$&[1, 2]].pack('H2').force_encoding(enc) }
|
1337
|
+
end
|
1317
1338
|
end
|
1318
1339
|
|
1319
1340
|
# RDF::IRI is a synonym for RDF::URI
|