rdf 1.1.0.p0 → 1.1.0.p1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|