rdf 1.1.0.p0 → 1.1.0.p1
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 +8 -8
- data/README +8 -6
- data/VERSION +1 -1
- data/lib/rdf.rb +8 -8
- data/lib/rdf/mixin/mutable.rb +4 -1
- data/lib/rdf/model/literal.rb +8 -3
- data/lib/rdf/model/statement.rb +12 -0
- data/lib/rdf/model/term.rb +0 -9
- data/lib/rdf/model/uri.rb +596 -71
- data/lib/rdf/model/value.rb +10 -1
- data/lib/rdf/ntriples/format.rb +1 -0
- data/lib/rdf/ntriples/reader.rb +3 -0
- data/lib/rdf/ntriples/writer.rb +19 -6
- data/lib/rdf/query/pattern.rb +0 -23
- data/lib/rdf/reader.rb +8 -6
- data/lib/rdf/writer.rb +11 -3
- metadata +5 -21
- data/lib/rdf/model/literal/string.rb +0 -38
- data/lib/rdf/model/literal/xml.rb +0 -41
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MmJiOTYzMzMzOTA3MWUwZGU0OWM2YjI2OTNiNTkwMGI0NmFhOTdmMw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NmMzMGE3OGQ0ZWY0MjNhMzc3NDk3MTdhOWRiNWY4ZTBkM2YwMzliZA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MGM3NzBiNDdkN2MxNGRjMTIyMzRhMmYyZWVkZDdmMGM0OTcxNjEwYTk4NmFh
|
10
|
+
YTQzODMzYjZhYzNkOTY0ZGU1ZWRjMjUwNGQ0YmZjMTcwYjY2ZjU2NmM1OGY5
|
11
|
+
NzM2ZmFiZWNhNTRmNzVmYjQzOTJhNmRmMWJhMzQzNzNmMjAwNzE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YzRkYmU0YzYzYzVlZTBhOTAxNDYzMmNhYzg5ZTU1ZGZjNjEwN2E5YzdmZTc4
|
14
|
+
OTRhZTQyOGI3ZDhhOGZhNWJhM2ZmOGVmZDBkNGVkNmRiMjdjNmJjMmU5Njky
|
15
|
+
ZTcxMGJlZWU2NDJhNjhkYWE5ZTJjZmYxNzc1NjZjNjE1ZjMxNDU=
|
data/README
CHANGED
@@ -25,7 +25,7 @@ This is a pure-Ruby library for working with [Resource Description Framework
|
|
25
25
|
not modify any of Ruby's core classes or standard library.
|
26
26
|
* Based entirely on Ruby's autoloading, meaning that you can generally make
|
27
27
|
use of any one part of the library without needing to load up the rest.
|
28
|
-
* Compatible with Ruby Ruby 1.9.
|
28
|
+
* Compatible with Ruby Ruby 1.9.2, Ruby 2.0, Rubinius and JRuby 1.7+.
|
29
29
|
* Compatible with older Ruby versions with the help of the [Backports][] gem.
|
30
30
|
* Performs auto-detection of input to select appropriate Reader class if one
|
31
31
|
cannot be determined from file characteristics.
|
@@ -117,7 +117,7 @@ to use when loading a file. The specific format to use can be forced using, e.g.
|
|
117
117
|
option where the specific format symbol is determined by the available readers. Both also use
|
118
118
|
MimeType or file extension, where available.
|
119
119
|
|
120
|
-
require '
|
120
|
+
require 'rdf/nquads'
|
121
121
|
|
122
122
|
graph = RDF::Graph.load("http://ruby-rdf.github.com/rdf/etc/doap.nq", :format => :nquads)
|
123
123
|
|
@@ -151,7 +151,10 @@ appropriate writer to use.
|
|
151
151
|
|
152
152
|
A specific sub-type of Writer can also be invoked directly:
|
153
153
|
|
154
|
-
|
154
|
+
require 'rdf/nquads'
|
155
|
+
|
156
|
+
repo = RDF::Repository.new << RDF::Statement.new(:hello, RDF::DC.title, "Hello, world!", :context => RDF::URI("context"))
|
157
|
+
File.open("hello.nq", "w") {|f| f << repo.dump(:nquads)}
|
155
158
|
|
156
159
|
## Reader/Writer convenience methods
|
157
160
|
{RDF::Enumerable} implements `to_{format}` for each available instance of {RDF::Reader}.
|
@@ -331,15 +334,14 @@ from BNode identity (i.e., they each entail the other)
|
|
331
334
|
|
332
335
|
## Dependencies
|
333
336
|
|
334
|
-
* [Ruby](http://ruby-lang.org/) (>= 1.9.
|
335
|
-
* [Addressable](http://rubygems.org/gems/addressable) (>= 2.2.0)
|
337
|
+
* [Ruby](http://ruby-lang.org/) (>= 1.9.2)
|
336
338
|
|
337
339
|
## Installation
|
338
340
|
|
339
341
|
The recommended installation method is via [RubyGems](http://rubygems.org/).
|
340
342
|
To install the latest official release of RDF.rb, do:
|
341
343
|
|
342
|
-
% [sudo] gem install rdf # Ruby 1.9.
|
344
|
+
% [sudo] gem install rdf # Ruby 1.9.2+
|
343
345
|
|
344
346
|
## Download
|
345
347
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.0.
|
1
|
+
1.1.0.p1
|
data/lib/rdf.rb
CHANGED
@@ -5,6 +5,7 @@ require 'bigdecimal'
|
|
5
5
|
require 'date'
|
6
6
|
require 'time'
|
7
7
|
|
8
|
+
require 'rdf/version'
|
8
9
|
require 'rdf/version'
|
9
10
|
|
10
11
|
module RDF
|
@@ -64,6 +65,7 @@ module RDF
|
|
64
65
|
##
|
65
66
|
# Alias for `RDF::Resource.new`.
|
66
67
|
#
|
68
|
+
# @param (see RDF::Resource#initialize)
|
67
69
|
# @return [RDF::Resource]
|
68
70
|
def self.Resource(*args, &block)
|
69
71
|
Resource.new(*args, &block)
|
@@ -72,6 +74,7 @@ module RDF
|
|
72
74
|
##
|
73
75
|
# Alias for `RDF::Node.new`.
|
74
76
|
#
|
77
|
+
# @param (see RDF::Node#initialize)
|
75
78
|
# @return [RDF::Node]
|
76
79
|
def self.Node(*args, &block)
|
77
80
|
Node.new(*args, &block)
|
@@ -80,13 +83,7 @@ module RDF
|
|
80
83
|
##
|
81
84
|
# Alias for `RDF::URI.new`.
|
82
85
|
#
|
83
|
-
# @
|
84
|
-
# @param [URI, String, #to_s] uri
|
85
|
-
#
|
86
|
-
# @overload URI(options = {})
|
87
|
-
# @param [Hash{Symbol => Object}] options
|
88
|
-
# passed to `Addressable::URI.new`
|
89
|
-
#
|
86
|
+
# @param (see RDF::URI#initialize)
|
90
87
|
# @return [RDF::URI]
|
91
88
|
def self.URI(*args, &block)
|
92
89
|
case uri = args.first
|
@@ -101,6 +98,7 @@ module RDF
|
|
101
98
|
##
|
102
99
|
# Alias for `RDF::Literal.new`.
|
103
100
|
#
|
101
|
+
# @param (see RDF::Literal#initialize)
|
104
102
|
# @return [RDF::Literal]
|
105
103
|
def self.Literal(*args, &block)
|
106
104
|
case literal = args.first
|
@@ -112,6 +110,7 @@ module RDF
|
|
112
110
|
##
|
113
111
|
# Alias for `RDF::Graph.new`.
|
114
112
|
#
|
113
|
+
# @param (see RDF::Graph#initialize)
|
115
114
|
# @return [RDF::Graph]
|
116
115
|
def self.Graph(*args, &block)
|
117
116
|
Graph.new(*args, &block)
|
@@ -120,6 +119,7 @@ module RDF
|
|
120
119
|
##
|
121
120
|
# Alias for `RDF::Statement.new`.
|
122
121
|
#
|
122
|
+
# @param (see RDF::Statement#initialize)
|
123
123
|
# @return [RDF::Statement]
|
124
124
|
def self.Statement(*args, &block)
|
125
125
|
Statement.new(*args, &block)
|
@@ -128,7 +128,7 @@ module RDF
|
|
128
128
|
##
|
129
129
|
# Alias for `RDF::Vocabulary.create`.
|
130
130
|
#
|
131
|
-
# @param
|
131
|
+
# @param (see RDF::Vocabulary#initialize)
|
132
132
|
# @return [Class]
|
133
133
|
def self.Vocabulary(uri)
|
134
134
|
Vocabulary.create(uri)
|
data/lib/rdf/mixin/mutable.rb
CHANGED
@@ -106,6 +106,9 @@ module RDF
|
|
106
106
|
|
107
107
|
##
|
108
108
|
# Deletes RDF statements from `self`.
|
109
|
+
# If any statement contains a {Query::Variable}, it is
|
110
|
+
# considered to be a pattern, and used to query
|
111
|
+
# self to find matching statements to delete.
|
109
112
|
#
|
110
113
|
# @param [Enumerable<RDF::Statement>] statements
|
111
114
|
# @raise [TypeError] if `self` is immutable
|
@@ -118,7 +121,7 @@ module RDF
|
|
118
121
|
when value.respond_to?(:each_statement)
|
119
122
|
delete_statements(value)
|
120
123
|
nil
|
121
|
-
when (statement = Statement.from(value)).
|
124
|
+
when (statement = Statement.from(value)).constant?
|
122
125
|
statement
|
123
126
|
else
|
124
127
|
delete_statements(query(value))
|
data/lib/rdf/model/literal.rb
CHANGED
@@ -78,7 +78,6 @@ module RDF
|
|
78
78
|
require 'rdf/model/literal/datetime'
|
79
79
|
require 'rdf/model/literal/time'
|
80
80
|
require 'rdf/model/literal/token'
|
81
|
-
require 'rdf/model/literal/xml'
|
82
81
|
|
83
82
|
include RDF::Term
|
84
83
|
|
@@ -132,8 +131,14 @@ module RDF
|
|
132
131
|
# depending on if there is language
|
133
132
|
#
|
134
133
|
# @param [Object] value
|
135
|
-
# @option options [Symbol]
|
136
|
-
# @option options [
|
134
|
+
# @option options [Symbol] :language (nil)
|
135
|
+
# @option options [String] :lexical (nil)
|
136
|
+
# Supplied lexical representation of this literal,
|
137
|
+
# otherwise it comes from transforming `value` to a string form
|
138
|
+
# See {#to_s}.
|
139
|
+
# @option options [URI] :datatype (nil)
|
140
|
+
# @option options [Boolean] :validate (false)
|
141
|
+
# @option options [Boolean] :canonicalize (false)
|
137
142
|
# @raise [ArgumentError]
|
138
143
|
# if there is a language and datatype is no rdf:langString
|
139
144
|
# @see http://www.w3.org/TR/rdf11-concepts/#section-Graph-Literal
|
data/lib/rdf/model/statement.rb
CHANGED
@@ -105,6 +105,18 @@ module RDF
|
|
105
105
|
true
|
106
106
|
end
|
107
107
|
|
108
|
+
##
|
109
|
+
# Returns `true` if any element of the statement is not a
|
110
|
+
# URI, Node or Literal.
|
111
|
+
#
|
112
|
+
# @return [Boolean]
|
113
|
+
def variable?
|
114
|
+
!(has_subject? && subject.resource? &&
|
115
|
+
has_predicate? && predicate.resource? &&
|
116
|
+
has_object? && (object.resource? || object.literal?) &&
|
117
|
+
(has_context? ? context.resource? : true ))
|
118
|
+
end
|
119
|
+
|
108
120
|
##
|
109
121
|
# @return [Boolean]
|
110
122
|
def invalid?
|
data/lib/rdf/model/term.rb
CHANGED
@@ -56,15 +56,6 @@ module RDF
|
|
56
56
|
super
|
57
57
|
end
|
58
58
|
|
59
|
-
##
|
60
|
-
# Returns `true` if this term is constant.
|
61
|
-
#
|
62
|
-
# @return [Boolean] `true` or `false`
|
63
|
-
# @see #variable?
|
64
|
-
def constant?
|
65
|
-
!(variable?)
|
66
|
-
end
|
67
|
-
|
68
59
|
##
|
69
60
|
# Returns a base representation of `self`.
|
70
61
|
#
|
data/lib/rdf/model/uri.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
require 'uri'
|
2
3
|
|
3
4
|
module RDF
|
4
5
|
##
|
5
6
|
# A Uniform Resource Identifier (URI).
|
6
7
|
# Also compatible with International Resource Identifier (IRI)
|
7
8
|
#
|
8
|
-
# `RDF::URI` supports all the instance methods of `Addressable::URI`.
|
9
|
-
#
|
10
9
|
# @example Creating a URI reference (1)
|
11
10
|
# uri = RDF::URI.new("http://rdf.rubyforge.org/")
|
12
11
|
#
|
@@ -45,7 +44,7 @@ module RDF
|
|
45
44
|
SCHEME = Regexp.compile("[A-za-z](?:[A-Za-z0-9+-\.])*").freeze
|
46
45
|
PORT = Regexp.compile("[0-9]*").freeze
|
47
46
|
IP_literal = Regexp.compile("\\[[0-9A-Fa-f:\\.]*\\]").freeze # Simplified, no IPvFuture
|
48
|
-
PCT_ENCODED = Regexp.compile("%[0-9A-Fa-f]
|
47
|
+
PCT_ENCODED = Regexp.compile("%[0-9A-Fa-f][0-9A-Fa-f]").freeze
|
49
48
|
GEN_DELIMS = Regexp.compile("[:/\\?\\#\\[\\]@]").freeze
|
50
49
|
SUB_DELIMS = Regexp.compile("[!\\$&'\\(\\)\\*\\+,;=]").freeze
|
51
50
|
RESERVED = Regexp.compile("(?:#{GEN_DELIMS}|#{SUB_DELIMS})").freeze
|
@@ -79,7 +78,36 @@ module RDF
|
|
79
78
|
|
80
79
|
IHIER_PART = Regexp.compile("(?:(?://#{IAUTHORITY}#{IPATH_ABEMPTY})|(?:#{IPATH_ABSOLUTE})|(?:#{IPATH_ROOTLESS})|(?:#{IPATH_EMPTY}))").freeze
|
81
80
|
IRI = Regexp.compile("^#{SCHEME}:(?:#{IHIER_PART})(?:\\?#{IQUERY})?(?:\\##{IFRAGMENT})?$").freeze
|
82
|
-
|
81
|
+
|
82
|
+
# Split an IRI into it's component parts
|
83
|
+
IRI_PARTS = /^(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(\?[^#]*)?(#.*)?$/
|
84
|
+
|
85
|
+
# Remove dot expressions regular expressions
|
86
|
+
RDS_2A = /^\.?\.\/(.*)$/.freeze
|
87
|
+
RDS_2B1 = /^\/\.$/.freeze
|
88
|
+
RDS_2B2 = /^(?:\/\.\/)(.*)$/.freeze
|
89
|
+
RDS_2C1 = /^\/\.\.$/.freeze
|
90
|
+
RDS_2C2 = /^(?:\/\.\.\/)(.*)$/.freeze
|
91
|
+
RDS_2D = /^\.\.?$/.freeze
|
92
|
+
RDS_2E = /^(\/?[^\/]*)(\/?.*)?$/.freeze
|
93
|
+
|
94
|
+
# Remove port, if it is standard for the scheme when normalizing
|
95
|
+
PORT_MAPPING = {
|
96
|
+
"http" => 80,
|
97
|
+
"https" => 443,
|
98
|
+
"ftp" => 21,
|
99
|
+
"tftp" => 69,
|
100
|
+
"sftp" => 22,
|
101
|
+
"ssh" => 22,
|
102
|
+
"svn+ssh" => 22,
|
103
|
+
"telnet" => 23,
|
104
|
+
"nntp" => 119,
|
105
|
+
"gopher" => 70,
|
106
|
+
"wais" => 210,
|
107
|
+
"ldap" => 389,
|
108
|
+
"prospero" => 1525
|
109
|
+
}
|
110
|
+
|
83
111
|
##
|
84
112
|
# @return [RDF::Util::Cache]
|
85
113
|
# @private
|
@@ -103,7 +131,7 @@ module RDF
|
|
103
131
|
# object can't be returned for some reason, this method will fall back
|
104
132
|
# to returning a freshly-allocated one.
|
105
133
|
#
|
106
|
-
# @param
|
134
|
+
# @param (see #initialize)
|
107
135
|
# @return [RDF::URI] an immutable, frozen URI object
|
108
136
|
def self.intern(str)
|
109
137
|
(cache[str = str.to_s] ||= self.new(str)).freeze
|
@@ -113,7 +141,8 @@ module RDF
|
|
113
141
|
# Creates a new `RDF::URI` instance based on the given `uri` string.
|
114
142
|
#
|
115
143
|
# This is just an alias for {RDF::URI#initialize} for compatibity
|
116
|
-
# with `Addressable::URI.parse`.
|
144
|
+
# with `Addressable::URI.parse`. Actual parsing is defered
|
145
|
+
# until {#object} is accessed.
|
117
146
|
#
|
118
147
|
# @param [String, #to_s] str
|
119
148
|
# @return [RDF::URI]
|
@@ -122,20 +151,97 @@ module RDF
|
|
122
151
|
end
|
123
152
|
|
124
153
|
##
|
125
|
-
#
|
126
|
-
# @param [RDF::URI, String, #to_s] uri
|
154
|
+
# Resolve paths to their simplest form.
|
127
155
|
#
|
128
|
-
#
|
156
|
+
# TODO: This process is correct, but overly iterative. It could be better done with a single regexp which handled most of the segment collapses all at once. Parent segments would still require iteration.
|
157
|
+
#
|
158
|
+
# @param [String] path
|
159
|
+
# @return [String] normalized path
|
160
|
+
# @see http://tools.ietf.org/html/rfc3986#section-5.2.4
|
161
|
+
def self.normalize_path(path)
|
162
|
+
output, input = "", path.to_s
|
163
|
+
if input.encoding != Encoding::ASCII_8BIT
|
164
|
+
input = input.dup if input.frozen?
|
165
|
+
input = input.force_encoding(Encoding::ASCII_8BIT)
|
166
|
+
end
|
167
|
+
until input.empty?
|
168
|
+
if input.match(RDS_2A)
|
169
|
+
# If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
|
170
|
+
input = $1
|
171
|
+
elsif input.match(RDS_2B1) || input.match(RDS_2B2)
|
172
|
+
# if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
|
173
|
+
input = "/#{$1}"
|
174
|
+
elsif input.match(RDS_2C1) || input.match(RDS_2C2)
|
175
|
+
# if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer
|
176
|
+
input = "/#{$1}"
|
177
|
+
|
178
|
+
# and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
|
179
|
+
output.sub!(/\/?[^\/]*$/, '')
|
180
|
+
elsif input.match(RDS_2D)
|
181
|
+
# if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
|
182
|
+
input = ""
|
183
|
+
elsif input.match(RDS_2E)
|
184
|
+
# move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer.end
|
185
|
+
seg, input = $1, $2
|
186
|
+
output << seg
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
output.sub(/\/+/, '/').force_encoding(Encoding::UTF_8)
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# @overload URI(uri, options = {})
|
195
|
+
# @param [URI, String, #to_s] uri
|
129
196
|
# @param [Hash{Symbol => Object}] options
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
197
|
+
# @option options [Boolean] :validate (false)
|
198
|
+
# @option options [Boolean] :canonicalize (false)
|
199
|
+
#
|
200
|
+
# @overload URI(options = {})
|
201
|
+
# @param [Hash{Symbol => Object}] options
|
202
|
+
# @option options [Boolean] :validate (false)
|
203
|
+
# @option options [Boolean] :canonicalize (false)
|
204
|
+
# @option [String, #to_s] :scheme The scheme component.
|
205
|
+
# @option [String, #to_s] :user The user component.
|
206
|
+
# @option [String, #to_s] :password The password component.
|
207
|
+
# @option [String, #to_s] :userinfo
|
208
|
+
# The userinfo component. If this is supplied, the user and password
|
209
|
+
# components must be omitted.
|
210
|
+
# @option [String, #to_s] :host The host component.
|
211
|
+
# @option [String, #to_s] :port The port component.
|
212
|
+
# @option [String, #to_s] :authority
|
213
|
+
# The authority component. If this is supplied, the user, password,
|
214
|
+
# userinfo, host, and port components must be omitted.
|
215
|
+
# @option [String, #to_s] :path The path component.
|
216
|
+
# @option [String, #to_s] :query The query component.
|
217
|
+
# @option [String, #to_s] :fragment The fragment component.
|
218
|
+
def initialize(*args)
|
219
|
+
options = args.last.is_a?(Hash) ? args.last : {}
|
220
|
+
uri = args.first
|
221
|
+
case uri
|
222
|
+
when Hash
|
223
|
+
%w(
|
224
|
+
scheme
|
225
|
+
user password userinfo
|
226
|
+
host port authority
|
227
|
+
path query fragment
|
228
|
+
).map(&:to_sym).each do |meth|
|
229
|
+
if uri.has_key?(meth)
|
230
|
+
self.send("#{meth}=".to_sym, uri[meth])
|
231
|
+
else
|
232
|
+
self.send(meth)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
else
|
236
|
+
@value = uri.to_s
|
237
|
+
if @value.encoding != Encoding::UTF_8
|
238
|
+
@value = @value.dup if @value.frozen?
|
239
|
+
@value.force_encoding(Encoding::UTF_8)
|
240
|
+
end
|
138
241
|
end
|
242
|
+
|
243
|
+
validate! if options[:validate]
|
244
|
+
canonicalize! if options[:canonicalize]
|
139
245
|
end
|
140
246
|
|
141
247
|
##
|
@@ -157,7 +263,7 @@ module RDF
|
|
157
263
|
# @see http://en.wikipedia.org/wiki/Uniform_Resource_Name
|
158
264
|
# @since 0.2.0
|
159
265
|
def urn?
|
160
|
-
|
266
|
+
@object ? @object[:scheme] == 'urn' : start_with?('urn:')
|
161
267
|
end
|
162
268
|
|
163
269
|
##
|
@@ -173,6 +279,16 @@ module RDF
|
|
173
279
|
!urn?
|
174
280
|
end
|
175
281
|
|
282
|
+
##
|
283
|
+
# A URI is absolute when it has a scheme
|
284
|
+
# @return [Boolean] `true` or `false`
|
285
|
+
def absolute?; !scheme.nil?; end
|
286
|
+
|
287
|
+
##
|
288
|
+
# A URI is relative when it does not have a scheme
|
289
|
+
# @return [Boolean] `true` or `false`
|
290
|
+
def relative?; !absolute?; end
|
291
|
+
|
176
292
|
##
|
177
293
|
# Returns the string length of this URI.
|
178
294
|
#
|
@@ -187,14 +303,13 @@ module RDF
|
|
187
303
|
alias_method :size, :length
|
188
304
|
|
189
305
|
##
|
190
|
-
# Determine if the URI is
|
306
|
+
# Determine if the URI is a valid according to RFC3987
|
191
307
|
#
|
192
308
|
# @return [Boolean] `true` or `false`
|
193
309
|
# @since 0.3.9
|
194
310
|
def valid?
|
195
|
-
#
|
196
|
-
|
197
|
-
to_s.match(RDF::URI::IRI) || to_s.match(RDF::URI::IRELATIVE_REF) || false
|
311
|
+
# Validate relative to RFC3987
|
312
|
+
to_s.match(RDF::URI::IRI) || false
|
198
313
|
end
|
199
314
|
|
200
315
|
##
|
@@ -217,6 +332,7 @@ module RDF
|
|
217
332
|
def canonicalize
|
218
333
|
self.dup.canonicalize!
|
219
334
|
end
|
335
|
+
alias_method :normalize, :canonicalize
|
220
336
|
|
221
337
|
##
|
222
338
|
# Converts this URI into its canonical lexical representation.
|
@@ -224,9 +340,17 @@ module RDF
|
|
224
340
|
# @return [RDF::URI] `self`
|
225
341
|
# @since 0.3.0
|
226
342
|
def canonicalize!
|
227
|
-
@
|
343
|
+
@object = {
|
344
|
+
:scheme => normalized_scheme,
|
345
|
+
:authority => normalized_authority,
|
346
|
+
:path => normalized_path,
|
347
|
+
:query => normalized_query,
|
348
|
+
:fragment => normalized_fragment
|
349
|
+
}
|
350
|
+
@value = nil
|
228
351
|
self
|
229
352
|
end
|
353
|
+
alias_method :normalize!, :canonicalize!
|
230
354
|
|
231
355
|
##
|
232
356
|
# Joins several URIs together.
|
@@ -250,12 +374,40 @@ module RDF
|
|
250
374
|
# @see RDF::URI#+
|
251
375
|
# @param [Array<String, RDF::URI, #to_s>] uris
|
252
376
|
# @return [RDF::URI]
|
377
|
+
# @see http://tools.ietf.org/html/rfc3986#section-5.2.2
|
378
|
+
# @see http://tools.ietf.org/html/rfc3986#section-5.2.3
|
253
379
|
def join(*uris)
|
254
|
-
|
380
|
+
joined_parts = object.dup.delete_if {|k, v| [:user, :password, :host, :port].include?(k)}
|
381
|
+
|
255
382
|
uris.each do |uri|
|
256
|
-
|
383
|
+
uri = RDF::URI.new(uri) unless uri.is_a?(RDF::URI)
|
384
|
+
next if uri.to_s.empty? # Don't mess with base URI
|
385
|
+
|
386
|
+
case
|
387
|
+
when uri.scheme
|
388
|
+
joined_parts = uri.object.merge(:path => self.class.normalize_path(uri.path))
|
389
|
+
when uri.authority
|
390
|
+
joined_parts[:authority] = uri.authority
|
391
|
+
joined_parts[:path] = self.class.normalize_path(uri.path)
|
392
|
+
joined_parts[:query] = uri.query
|
393
|
+
when uri.path.to_s.empty?
|
394
|
+
joined_parts[:query] = uri.query if uri.query
|
395
|
+
when uri.path[0,1] == '/'
|
396
|
+
joined_parts[:path] = self.class.normalize_path(uri.path)
|
397
|
+
joined_parts[:query] = uri.query
|
398
|
+
else
|
399
|
+
base_path = self.class.normalize_path(path.to_s)
|
400
|
+
|
401
|
+
# Merge path segments from section 5.2.3
|
402
|
+
base_path.sub!(/\/[^\/]*$/, '/')
|
403
|
+
joined_parts[:path] = self.class.normalize_path(base_path + uri.path)
|
404
|
+
joined_parts[:query] = uri.query
|
405
|
+
end
|
406
|
+
joined_parts[:fragment] = uri.fragment
|
257
407
|
end
|
258
|
-
|
408
|
+
|
409
|
+
# Return joined URI
|
410
|
+
RDF::URI.new(joined_parts)
|
259
411
|
end
|
260
412
|
|
261
413
|
##
|
@@ -281,6 +433,7 @@ module RDF
|
|
281
433
|
#
|
282
434
|
# @param [Any] fragment A URI fragment to be appended to this URI
|
283
435
|
# @return [RDF::URI]
|
436
|
+
# @raise [ArgumentError] if the URI is invalid
|
284
437
|
# @see RDF::URI#+
|
285
438
|
# @see RDF::URI#join
|
286
439
|
# @see <http://tools.ietf.org/html/rfc3986#section-5.2>
|
@@ -303,22 +456,34 @@ module RDF
|
|
303
456
|
if urn?
|
304
457
|
RDF::URI.intern(to_s.sub(/:+$/,'') + ':' + fragment.to_s.sub(/^:+/,''))
|
305
458
|
else # !urn?
|
306
|
-
|
307
|
-
|
308
|
-
case fragment.to_s[0]
|
309
|
-
when '/'
|
310
|
-
|
459
|
+
res = self.dup
|
460
|
+
if res.fragment
|
461
|
+
case fragment.to_s[0,1]
|
462
|
+
when '/'
|
463
|
+
# Base with a fragment, fragment beginning with '/'. The fragment wins, we use '/'.
|
464
|
+
path, frag = fragment.to_s.split('#', 2)
|
465
|
+
res.path = "#{res.path}/#{path.sub(/^\/*/,'')}"
|
466
|
+
res.fragment = frag
|
311
467
|
else
|
312
|
-
|
468
|
+
# Replace fragment
|
469
|
+
res.fragment = fragment.to_s.sub(/^#+/,'')
|
313
470
|
end
|
314
|
-
else
|
315
|
-
|
316
|
-
|
317
|
-
|
471
|
+
else
|
472
|
+
# Not a fragment. includes '/'. Results from bases ending in '/' are the same as if there were no trailing slash.
|
473
|
+
case fragment.to_s[0,1]
|
474
|
+
when '#'
|
475
|
+
# Base ending with '/', fragment beginning with '#'. The fragment wins, we use '#'.
|
476
|
+
res.path = res.path.to_s.sub!(/\/*$/, '')
|
477
|
+
# Add fragment
|
478
|
+
res.fragment = fragment.to_s.sub(/^#+/,'')
|
318
479
|
else
|
319
|
-
|
480
|
+
# Add fragment as path component
|
481
|
+
path, frag = fragment.to_s.split('#', 2)
|
482
|
+
res.path = res.path.to_s.sub(/\/*$/,'/') + path.sub(/^\/*/,'')
|
483
|
+
res.fragment = frag
|
320
484
|
end
|
321
485
|
end
|
486
|
+
RDF::URI.intern(res.to_s)
|
322
487
|
end
|
323
488
|
end
|
324
489
|
|
@@ -353,7 +518,7 @@ module RDF
|
|
353
518
|
#
|
354
519
|
# @return [Boolean] `true` or `false`
|
355
520
|
def root?
|
356
|
-
self.path == '/' || self.path.empty?
|
521
|
+
self.path == '/' || self.path.to_s.empty?
|
357
522
|
end
|
358
523
|
|
359
524
|
##
|
@@ -368,9 +533,9 @@ module RDF
|
|
368
533
|
if root?
|
369
534
|
self
|
370
535
|
else
|
371
|
-
|
372
|
-
|
373
|
-
|
536
|
+
RDF::URI.new(
|
537
|
+
object.merge(:path => '/').
|
538
|
+
keep_if {|k, v| [:scheme, :authority, :path].include?(k)})
|
374
539
|
end
|
375
540
|
end
|
376
541
|
|
@@ -410,7 +575,7 @@ module RDF
|
|
410
575
|
end
|
411
576
|
|
412
577
|
##
|
413
|
-
# Returns a qualified name (QName) for this URI, if possible.
|
578
|
+
# Returns a qualified name (QName) for this URI based on available vocabularies, if possible.
|
414
579
|
#
|
415
580
|
# @example
|
416
581
|
# RDF::URI('http://purl.org/dc/terms/').qname #=> [:dc, nil]
|
@@ -446,14 +611,21 @@ module RDF
|
|
446
611
|
#
|
447
612
|
# @return [RDF::URI]
|
448
613
|
def dup
|
449
|
-
self.class.new(@
|
614
|
+
self.class.new((@value || @object).dup)
|
450
615
|
end
|
451
616
|
|
452
617
|
##
|
453
618
|
# @private
|
454
619
|
def freeze
|
455
|
-
|
456
|
-
|
620
|
+
unless frozen?
|
621
|
+
# Create derived components
|
622
|
+
authority; userinfo; user; password; host; port
|
623
|
+
@value = value.freeze
|
624
|
+
@object = object.freeze
|
625
|
+
@hash = hash.freeze
|
626
|
+
super
|
627
|
+
end
|
628
|
+
self
|
457
629
|
end
|
458
630
|
|
459
631
|
##
|
@@ -521,7 +693,7 @@ module RDF
|
|
521
693
|
# If other is a Literal, reverse test to consolodate complex type checking logic
|
522
694
|
other == self
|
523
695
|
when String then to_s == other
|
524
|
-
when URI
|
696
|
+
when URI then to_s == other.to_s
|
525
697
|
else other.respond_to?(:to_uri) && to_s == other.to_uri.to_s
|
526
698
|
end
|
527
699
|
end
|
@@ -577,7 +749,7 @@ module RDF
|
|
577
749
|
#
|
578
750
|
# @return [Sring]
|
579
751
|
def to_base
|
580
|
-
"<#{escape(
|
752
|
+
"<#{escape(to_s)}>"
|
581
753
|
end
|
582
754
|
|
583
755
|
##
|
@@ -587,48 +759,401 @@ module RDF
|
|
587
759
|
# RDF::URI('http://example.org/').to_str #=> 'http://example.org/'
|
588
760
|
#
|
589
761
|
# @return [String]
|
590
|
-
def to_str
|
591
|
-
@uri.to_s
|
592
|
-
end
|
762
|
+
def to_str; value; end
|
593
763
|
alias_method :to_s, :to_str
|
594
764
|
|
765
|
+
##
|
766
|
+
# Returns a <code>String</code> representation of the URI object's state.
|
767
|
+
#
|
768
|
+
# @return [String] The URI object's state, as a <code>String</code>.
|
769
|
+
def inspect
|
770
|
+
sprintf("#<%s:%#0x URI:%s>", URI.to_s, self.object_id, self.to_s)
|
771
|
+
end
|
772
|
+
|
773
|
+
##
|
774
|
+
# lexical representation of URI, either absolute or relative
|
775
|
+
# @return [String]
|
776
|
+
def value
|
777
|
+
@value ||= [
|
778
|
+
("#{scheme}:" if absolute?),
|
779
|
+
("//#{authority}" if authority),
|
780
|
+
path,
|
781
|
+
("?#{query}" if query),
|
782
|
+
("##{fragment}" if fragment)
|
783
|
+
].compact.join("")
|
784
|
+
end
|
785
|
+
|
595
786
|
##
|
596
787
|
# Returns a hash code for this URI.
|
597
788
|
#
|
598
789
|
# @return [Fixnum]
|
599
790
|
def hash
|
600
|
-
@
|
791
|
+
return @hash ||= (to_s.hash * -1)
|
601
792
|
end
|
602
793
|
|
603
794
|
##
|
604
|
-
# Returns
|
795
|
+
# Returns object representation of this URI, broken into components
|
605
796
|
#
|
606
|
-
# @
|
607
|
-
|
608
|
-
|
609
|
-
|
797
|
+
# @return [Hash{Symbol => String}]
|
798
|
+
def object
|
799
|
+
@object ||= begin
|
800
|
+
parse @value
|
801
|
+
end
|
610
802
|
end
|
803
|
+
alias_method :to_hash, :object
|
611
804
|
|
612
|
-
|
805
|
+
##{
|
806
|
+
# Parse a URI into it's components
|
807
|
+
#
|
808
|
+
# @param [String, to_s] value
|
809
|
+
# @return [Object{Symbol => String}]
|
810
|
+
def parse(value)
|
811
|
+
value = value.to_s.dup.force_encoding(Encoding::ASCII_8BIT)
|
812
|
+
parts = {}
|
813
|
+
if matchdata = value.to_s.match(IRI_PARTS)
|
814
|
+
scheme, authority, path, query, fragment = matchdata.to_a[1..-1]
|
815
|
+
userinfo, hostport = authority.to_s.split('@', 2)
|
816
|
+
hostport, userinfo = userinfo, nil unless hostport
|
817
|
+
user, password = userinfo.to_s.split(':', 2)
|
818
|
+
host, port = hostport.to_s.split(':', 2)
|
819
|
+
|
820
|
+
parts[:scheme] = (scheme.force_encoding(Encoding::UTF_8) if scheme)
|
821
|
+
parts[:authority] = (authority.force_encoding(Encoding::UTF_8) if authority)
|
822
|
+
parts[:userinfo] = (userinfo.force_encoding(Encoding::UTF_8) if userinfo)
|
823
|
+
parts[:user] = (user.force_encoding(Encoding::UTF_8) if user)
|
824
|
+
parts[:password] = (password.force_encoding(Encoding::UTF_8) if password)
|
825
|
+
parts[:host] = (host.force_encoding(Encoding::UTF_8) if host)
|
826
|
+
parts[:port] = (::URI.decode(port).to_i if port)
|
827
|
+
parts[:path] = (path.to_s.force_encoding(Encoding::UTF_8) unless path.empty?)
|
828
|
+
parts[:query] = (query[1..-1].force_encoding(Encoding::UTF_8) if query)
|
829
|
+
parts[:fragment] = (fragment[1..-1].force_encoding(Encoding::UTF_8) if fragment)
|
830
|
+
|
831
|
+
parts.each_key do |k|
|
832
|
+
parts[k].force_encoding(Encoding::UTF_8) if parts[k].respond_to?(:encoding)
|
833
|
+
end
|
834
|
+
end
|
835
|
+
|
836
|
+
parts
|
837
|
+
end
|
613
838
|
|
614
839
|
##
|
615
|
-
# @
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
# @
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
840
|
+
# @return [String]
|
841
|
+
def scheme; object.fetch(:scheme, nil); end
|
842
|
+
|
843
|
+
##
|
844
|
+
# @param [String, #to_s] value
|
845
|
+
# @return [RDF::URI] self
|
846
|
+
def scheme=(value)
|
847
|
+
object[:scheme] = (value.to_s.force_encoding(Encoding::UTF_8) if value)
|
848
|
+
@value = nil
|
849
|
+
self
|
850
|
+
end
|
851
|
+
|
852
|
+
##
|
853
|
+
# Return normalized version of scheme, if any
|
854
|
+
# @return [String]
|
855
|
+
def normalized_scheme
|
856
|
+
scheme.strip.downcase if scheme
|
857
|
+
end
|
858
|
+
|
859
|
+
##
|
860
|
+
# @return [String]
|
861
|
+
def user
|
862
|
+
object.fetch(:user) do
|
863
|
+
@object[:user] = (userinfo.split(':', 2)[0] if userinfo)
|
864
|
+
end
|
865
|
+
end
|
866
|
+
|
867
|
+
##
|
868
|
+
# @param [String, #to_s] value
|
869
|
+
# @return [RDF::URI] self
|
870
|
+
def user=(value)
|
871
|
+
object[:user] = (value.to_s.force_encoding(Encoding::UTF_8) if value)
|
872
|
+
@object[:userinfo] = format_userinfo("")
|
873
|
+
@object[:authority] = format_authority
|
874
|
+
@value = nil
|
875
|
+
self
|
876
|
+
end
|
877
|
+
|
878
|
+
##
|
879
|
+
# Normalized version of user
|
880
|
+
# @return [String]
|
881
|
+
def normalized_user
|
882
|
+
::URI.encode(::URI.decode(user), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if user
|
883
|
+
end
|
884
|
+
|
885
|
+
##
|
886
|
+
# @return [String]
|
887
|
+
def password
|
888
|
+
object.fetch(:password) do
|
889
|
+
@object[:password] = (userinfo.split(':', 2)[1] if userinfo)
|
890
|
+
end
|
891
|
+
end
|
892
|
+
|
893
|
+
##
|
894
|
+
# @param [String, #to_s] value
|
895
|
+
# @return [RDF::URI] self
|
896
|
+
def password=(value)
|
897
|
+
object[:password] = (value.to_s.force_encoding(Encoding::UTF_8) if value)
|
898
|
+
@object[:userinfo] = format_userinfo("")
|
899
|
+
@object[:authority] = format_authority
|
900
|
+
@value = nil
|
901
|
+
self
|
902
|
+
end
|
903
|
+
|
904
|
+
##
|
905
|
+
# Normalized version of password
|
906
|
+
# @return [String]
|
907
|
+
def normalized_password
|
908
|
+
::URI.encode(::URI.decode(password), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if password
|
909
|
+
end
|
910
|
+
|
911
|
+
##
|
912
|
+
# @return [String]
|
913
|
+
def host
|
914
|
+
object.fetch(:host) do
|
915
|
+
@object[:host] = ($1 if @object[:authority].to_s.match(/(?:[^@]+@)?([^:]+)(?::.*)?$/))
|
916
|
+
end
|
917
|
+
end
|
918
|
+
|
919
|
+
##
|
920
|
+
# @param [String, #to_s] value
|
921
|
+
# @return [RDF::URI] self
|
922
|
+
def host=(value)
|
923
|
+
object[:host] = (value.to_s.force_encoding(Encoding::UTF_8) if value)
|
924
|
+
@object[:authority] = format_authority
|
925
|
+
@value = nil
|
926
|
+
self
|
927
|
+
end
|
928
|
+
|
929
|
+
##
|
930
|
+
# Normalized version of host
|
931
|
+
# @return [String]
|
932
|
+
def normalized_host
|
933
|
+
# Remove trailing '.' characters
|
934
|
+
normalize_segment(host, IHOST, true).sub(/\.*$/, '') if host
|
935
|
+
end
|
936
|
+
|
937
|
+
##
|
938
|
+
# @return [String]
|
939
|
+
def port
|
940
|
+
object.fetch(:port) do
|
941
|
+
@object[:port] = ($1 if @object[:authority].to_s.match(/:(\d+)$/))
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
945
|
+
##
|
946
|
+
# @param [String, #to_s] value
|
947
|
+
# @return [RDF::URI] self
|
948
|
+
def port=(value)
|
949
|
+
object[:port] = (value.to_s.to_i if value)
|
950
|
+
@object[:authority] = format_authority
|
951
|
+
@value = nil
|
952
|
+
self
|
953
|
+
end
|
954
|
+
|
955
|
+
##
|
956
|
+
# Normalized version of port
|
957
|
+
# @return [String]
|
958
|
+
def normalized_port
|
959
|
+
if port
|
960
|
+
np = normalize_segment(port.to_s, PORT)
|
961
|
+
if PORT_MAPPING[normalized_scheme] == np.to_i
|
962
|
+
nil
|
963
|
+
else
|
964
|
+
np.to_i
|
626
965
|
end
|
966
|
+
end
|
967
|
+
end
|
968
|
+
|
969
|
+
##
|
970
|
+
# @return [String]
|
971
|
+
def path; object.fetch(:path, nil); end
|
972
|
+
|
973
|
+
##
|
974
|
+
# @param [String, #to_s] value
|
975
|
+
# @return [RDF::URI] self
|
976
|
+
def path=(value)
|
977
|
+
if value
|
978
|
+
# Always lead with a slash
|
979
|
+
value = "/#{value}" if host && value.to_s =~ /^[^\/]/
|
980
|
+
object[:path] = value.to_s.force_encoding(Encoding::UTF_8)
|
627
981
|
else
|
628
|
-
|
982
|
+
object[:path] = nil
|
983
|
+
end
|
984
|
+
@value = nil
|
985
|
+
self
|
986
|
+
end
|
987
|
+
|
988
|
+
##
|
989
|
+
# Normalized version of path
|
990
|
+
# @return [String]
|
991
|
+
def normalized_path
|
992
|
+
segments = path.to_s.split('/', -1) # preserve null segments
|
993
|
+
|
994
|
+
norm_segs = case
|
995
|
+
when authority
|
996
|
+
# ipath-abempty
|
997
|
+
segments.map {|s| normalize_segment(s, ISEGMENT)}
|
998
|
+
when segments.first.nil?
|
999
|
+
# ipath-absolute
|
1000
|
+
res = [nil]
|
1001
|
+
res << normalize_segment(segments[1], ISEGMENT_NZ) if segments.length > 1
|
1002
|
+
res += segments[2..-1].map {|s| normalize_segment(s, ISEGMENT)} if segments.length > 2
|
1003
|
+
res
|
1004
|
+
when segments.first.to_s.index(':')
|
1005
|
+
# ipath-noscheme
|
1006
|
+
res = []
|
1007
|
+
res << normalize_segment(segments[1], ISEGMENT_NZ_NC)
|
1008
|
+
res += segments[1..-1].map {|s| normalize_segment(s, ISEGMENT)} if segments.length > 1
|
1009
|
+
when segments.first
|
1010
|
+
# ipath-rootless
|
1011
|
+
# ipath-noscheme
|
1012
|
+
res = []
|
1013
|
+
res << normalize_segment(segments[0], ISEGMENT_NZ)
|
1014
|
+
res += segments[1..-1].map {|s| normalize_segment(s, ISEGMENT)} if segments.length > 1
|
1015
|
+
res
|
1016
|
+
else
|
1017
|
+
# Should be empty
|
1018
|
+
segments
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
res = self.class.normalize_path(norm_segs.join("/"))
|
1022
|
+
# Special rules for specific protocols having empty paths
|
1023
|
+
res.empty? ? (%w(http https ftp tftp).include?(normalized_scheme) ? '/' : "") : res
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
##
|
1027
|
+
# @return [String]
|
1028
|
+
def query; object.fetch(:query, nil); end
|
1029
|
+
|
1030
|
+
##
|
1031
|
+
# @param [String, #to_s] value
|
1032
|
+
# @return [RDF::URI] self
|
1033
|
+
def query=(value)
|
1034
|
+
object[:query] = (value.to_s.force_encoding(Encoding::UTF_8) if value)
|
1035
|
+
@value = nil
|
1036
|
+
self
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
##
|
1040
|
+
# Normalized version of query
|
1041
|
+
# @return [String]
|
1042
|
+
def normalized_query
|
1043
|
+
normalize_segment(query, IQUERY) if query
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
##
|
1047
|
+
# @return [String]
|
1048
|
+
def fragment; object.fetch(:fragment, nil); end
|
1049
|
+
|
1050
|
+
##
|
1051
|
+
# @param [String, #to_s] value
|
1052
|
+
# @return [RDF::URI] self
|
1053
|
+
def fragment=(value)
|
1054
|
+
object[:fragment] = (value.to_s.force_encoding(Encoding::UTF_8) if value)
|
1055
|
+
@value = nil
|
1056
|
+
self
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
##
|
1060
|
+
# Normalized version of fragment
|
1061
|
+
# @return [String]
|
1062
|
+
def normalized_fragment
|
1063
|
+
normalize_segment(fragment, IFRAGMENT) if fragment
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
##
|
1067
|
+
# Authority is a combination of user, password, host and port
|
1068
|
+
def authority
|
1069
|
+
object.fetch(:authority) {
|
1070
|
+
@object[:authority] = (format_authority if @object[:host])
|
1071
|
+
}
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
##
|
1075
|
+
# @param [String, #to_s] value
|
1076
|
+
# @return [RDF::URI] self
|
1077
|
+
def authority=(value)
|
1078
|
+
object.delete_if {|k, v| [:user, :password, :host, :port, :userinfo].include?(k)}
|
1079
|
+
object[:authority] = (value.to_s.force_encoding(Encoding::UTF_8) if value)
|
1080
|
+
user; password; userinfo; host; port
|
1081
|
+
@value = nil
|
1082
|
+
self
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
##
|
1086
|
+
# Return normalized version of authority, if any
|
1087
|
+
# @return [String]
|
1088
|
+
def normalized_authority
|
1089
|
+
if authority
|
1090
|
+
(userinfo ? "#{normalized_userinfo}@" : "") +
|
1091
|
+
normalized_host +
|
1092
|
+
(normalized_port ? ":#{normalized_port}" : "")
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
##
|
1097
|
+
# Userinfo is a combination of user and password
|
1098
|
+
def userinfo
|
1099
|
+
object.fetch(:userinfo) {
|
1100
|
+
@object[:userinfo] = (format_userinfo("") if @object[:user])
|
1101
|
+
}
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
##
|
1105
|
+
# @param [String, #to_s] value
|
1106
|
+
# @return [RDF::URI] self
|
1107
|
+
def userinfo=(value)
|
1108
|
+
object.delete_if {|k, v| [:user, :password, :authority].include?(k)}
|
1109
|
+
object[:userinfo] = (value.to_s.force_encoding(Encoding::UTF_8) if value)
|
1110
|
+
user; password; authority
|
1111
|
+
@value = nil
|
1112
|
+
self
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
##
|
1116
|
+
# Normalized version of userinfo
|
1117
|
+
# @return [String]
|
1118
|
+
def normalized_userinfo
|
1119
|
+
normalized_user + (password ? ":#{normalized_password}" : "") if userinfo
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
private
|
1123
|
+
|
1124
|
+
##
|
1125
|
+
# Normalize a segment using a character range
|
1126
|
+
#
|
1127
|
+
# @param [String] segment
|
1128
|
+
# @param [Regexp] expr
|
1129
|
+
# @param [Boolean] downcase
|
1130
|
+
# @result [String]
|
1131
|
+
def normalize_segment(value, expr, downcase = false)
|
1132
|
+
if value
|
1133
|
+
value = value.dup if value.frozen?
|
1134
|
+
value = value.force_encoding(Encoding::UTF_8)
|
1135
|
+
decoded = ::URI.decode(value)
|
1136
|
+
decoded.downcase! if downcase
|
1137
|
+
::URI.encode(decoded, /[^#{expr}]/)
|
1138
|
+
end
|
1139
|
+
end
|
1140
|
+
|
1141
|
+
def format_userinfo(append = "")
|
1142
|
+
if @object[:user]
|
1143
|
+
@object[:user] + (@object[:password] ? ":#{@object[:password]}" : "") + append
|
1144
|
+
else
|
1145
|
+
""
|
1146
|
+
end
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
def format_authority
|
1150
|
+
if @object[:host]
|
1151
|
+
format_userinfo("@") + @object[:host] + (object[:port] ? ":#{object[:port]}" : "")
|
1152
|
+
else
|
1153
|
+
""
|
629
1154
|
end
|
630
1155
|
end
|
631
|
-
end
|
1156
|
+
end
|
632
1157
|
|
633
1158
|
# RDF::IRI is a synonym for RDF::URI
|
634
1159
|
IRI = URI
|