rdf 3.0.11 → 3.1.2
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.
- 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
|