Class: RDF::URI
Overview
A Uniform Resource Identifier (URI). Also compatible with International Resource Identifier (IRI)
Direct Known Subclasses
Constant Summary collapse
- CACHE_SIZE =
Defines the maximum number of interned URI references that can be held cached in memory at any one time.
-1 # unlimited by default
- UCSCHAR =
IRI components
Regexp.compile(<<-EOS.gsub(/\s+/, '')) [\\u00A0-\\uD7FF]|[\\uF900-\\uFDCF]|[\\uFDF0-\\uFFEF]| [\\u{10000}-\\u{1FFFD}]|[\\u{20000}-\\u{2FFFD}]|[\\u{30000}-\\u{3FFFD}]| [\\u{40000}-\\u{4FFFD}]|[\\u{50000}-\\u{5FFFD}]|[\\u{60000}-\\u{6FFFD}]| [\\u{70000}-\\u{7FFFD}]|[\\u{80000}-\\u{8FFFD}]|[\\u{90000}-\\u{9FFFD}]| [\\u{A0000}-\\u{AFFFD}]|[\\u{B0000}-\\u{BFFFD}]|[\\u{C0000}-\\u{CFFFD}]| [\\u{D0000}-\\u{DFFFD}]|[\\u{E1000}-\\u{EFFFD}] EOS
- IPRIVATE =
Regexp.compile("[\\uE000-\\uF8FF]|[\\u{F0000}-\\u{FFFFD}]|[\\u100000-\\u10FFFD]").freeze
- SCHEME =
Regexp.compile("[A-za-z](?:[A-Za-z0-9+-\.])*").freeze
- PORT =
Regexp.compile("[0-9]*").freeze
- IP_literal =
Simplified, no IPvFuture
Regexp.compile("\\[[0-9A-Fa-f:\\.]*\\]").freeze
- PCT_ENCODED =
Regexp.compile("%[0-9A-Fa-f][0-9A-Fa-f]").freeze
- GEN_DELIMS =
Regexp.compile("[:/\\?\\#\\[\\]@]").freeze
- SUB_DELIMS =
Regexp.compile("[!\\$&'\\(\\)\\*\\+,;=]").freeze
- RESERVED =
Regexp.compile("(?:#{GEN_DELIMS}|#{SUB_DELIMS})").freeze
- UNRESERVED =
Regexp.compile("[A-Za-z0-9\._~-]").freeze
- IUNRESERVED =
Regexp.compile("[A-Za-z0-9\._~-]|#{UCSCHAR}").freeze
- IPCHAR =
Regexp.compile("(?:#{IUNRESERVED}|#{PCT_ENCODED}|#{SUB_DELIMS}|:|@)").freeze
- IQUERY =
Regexp.compile("(?:#{IPCHAR}|#{IPRIVATE}|/|\\?)*").freeze
- IFRAGMENT =
Regexp.compile("(?:#{IPCHAR}|/|\\?)*").freeze.freeze
- ISEGMENT =
Regexp.compile("(?:#{IPCHAR})*").freeze
- ISEGMENT_NZ =
Regexp.compile("(?:#{IPCHAR})+").freeze
- ISEGMENT_NZ_NC =
Regexp.compile("(?:(?:#{IUNRESERVED})|(?:#{PCT_ENCODED})|(?:#{SUB_DELIMS})|@)+").freeze
- IPATH_ABEMPTY =
Regexp.compile("(?:/#{ISEGMENT})*").freeze
- IPATH_ABSOLUTE =
Regexp.compile("/(?:(?:#{ISEGMENT_NZ})(/#{ISEGMENT})*)?").freeze
- IPATH_NOSCHEME =
Regexp.compile("(?:#{ISEGMENT_NZ_NC})(?:/#{ISEGMENT})*").freeze
- IPATH_ROOTLESS =
Regexp.compile("(?:#{ISEGMENT_NZ})(?:/#{ISEGMENT})*").freeze
- IPATH_EMPTY =
Regexp.compile("").freeze
- IREG_NAME =
Regexp.compile("(?:(?:#{IUNRESERVED})|(?:#{PCT_ENCODED})|(?:#{SUB_DELIMS}))*").freeze
- IHOST =
Regexp.compile("(?:#{IP_literal})|(?:#{IREG_NAME})").freeze
- IUSERINFO =
Regexp.compile("(?:(?:#{IUNRESERVED})|(?:#{PCT_ENCODED})|(?:#{SUB_DELIMS})|:)*").freeze
- IAUTHORITY =
Regexp.compile("(?:#{IUSERINFO}@)?#{IHOST}(?::#{PORT})?").freeze
- IRELATIVE_PART =
Regexp.compile("(?:(?://#{IAUTHORITY}(?:#{IPATH_ABEMPTY}))|(?:#{IPATH_ABSOLUTE})|(?:#{IPATH_NOSCHEME})|(?:#{IPATH_EMPTY}))").freeze
- IRELATIVE_REF =
Regexp.compile("^#{IRELATIVE_PART}(?:\\?#{IQUERY})?(?:\\##{IFRAGMENT})?$").freeze
- IHIER_PART =
Regexp.compile("(?:(?://#{IAUTHORITY}#{IPATH_ABEMPTY})|(?:#{IPATH_ABSOLUTE})|(?:#{IPATH_ROOTLESS})|(?:#{IPATH_EMPTY}))").freeze
- IRI =
Regexp.compile("^#{SCHEME}:(?:#{IHIER_PART})(?:\\?#{IQUERY})?(?:\\##{IFRAGMENT})?$").freeze
- IRI_PARTS =
Split an IRI into it’s component parts
/^(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(\?[^#]*)?(#.*)?$/- RDS_2A =
Remove dot expressions regular expressions
/^\.?\.\/(.*)$/.freeze
- RDS_2B1 =
/^\/\.$/.freeze
- RDS_2B2 =
/^(?:\/\.\/)(.*)$/.freeze
- RDS_2C1 =
/^\/\.\.$/.freeze
- RDS_2C2 =
/^(?:\/\.\.\/)(.*)$/.freeze
- RDS_2D =
/^\.\.?$/.freeze
- RDS_2E =
/^(\/?[^\/]*)(\/?.*)?$/.freeze
- PORT_MAPPING =
Remove port, if it is standard for the scheme when normalizing
{ "http" => 80, "https" => 443, "ftp" => 21, "tftp" => 69, "sftp" => 22, "ssh" => 22, "svn+ssh" => 22, "telnet" => 23, "nntp" => 119, "gopher" => 70, "wais" => 210, "ldap" => 389, "prospero" => 1525 }
- NON_HIER_SCHEMES =
List of schemes known not to be hierarchical
%w( about acct bitcoin callto cid data fax geo gtalk h323 iax icon im jabber jms magnet mailto maps news pres proxy session sip sips skype sms spotify stun stuns tag tel turn turns tv urn javascript ).freeze
Class Method Summary collapse
- .cache ⇒ RDF::Util::Cache
-
.intern(*args) ⇒ RDF::URI
Returns an interned ‘RDF::URI` instance based on the given `uri` string.
-
.normalize_path(path) ⇒ String
Resolve paths to their simplest form.
-
.parse(str) ⇒ RDF::URI
Creates a new ‘RDF::URI` instance based on the given `uri` string.
Instance Method Summary collapse
-
#+(other) ⇒ RDF::URI
Simple concatenation operator.
-
#/(fragment) ⇒ RDF::URI
‘Smart separator’ URI builder.
-
#==(other) ⇒ Boolean
Checks whether this URI is equal to ‘other` (type checking).
-
#===(other) ⇒ Boolean
Checks for case equality to the given ‘other` object.
-
#=~(pattern) ⇒ Integer
Performs a pattern match using the given regular expression.
-
#absolute? ⇒ Boolean
A URI is absolute when it has a scheme.
-
#authority ⇒ Object
Authority is a combination of user, password, host and port.
-
#authority=(value) ⇒ RDF::URI
Self.
-
#canonicalize ⇒ RDF::URI
(also: #normalize)
Returns a copy of this URI converted into its canonical lexical representation.
-
#canonicalize! ⇒ RDF::URI
(also: #normalize!)
Converts this URI into its canonical lexical representation.
-
#dup ⇒ RDF::URI
Returns a duplicate copy of ‘self`.
-
#end_with?(string) ⇒ Boolean
(also: #ends_with?)
Returns ‘true` if this URI ends with the given `string`.
-
#eql?(other) ⇒ Boolean
Checks whether this URI the same term as ‘other`.
- #fragment ⇒ String
-
#fragment=(value) ⇒ RDF::URI
Self.
- #freeze ⇒ Object
-
#has_parent? ⇒ Boolean
Returns ‘true` if this URI is hierarchical and it’s path component isn’t equal to ‘/`.
-
#hash ⇒ Fixnum
Returns a hash code for this URI.
-
#hier? ⇒ Boolean
Returns ‘true` if the URI scheme is hierarchical.
- #host ⇒ String
-
#host=(value) ⇒ RDF::URI
Self.
-
#initialize(*args, validate: false, canonicalize: false, **options) ⇒ URI
constructor
A new instance of URI.
-
#inspect ⇒ String
Returns a
Stringrepresentation of the URI object’s state. -
#join(*uris) ⇒ RDF::URI
Joins several URIs together.
-
#length ⇒ Integer
(also: #size)
Returns the string length of this URI.
-
#normalized_authority ⇒ String
Return normalized version of authority, if any.
-
#normalized_fragment ⇒ String
Normalized version of fragment.
-
#normalized_host ⇒ String
Normalized version of host.
-
#normalized_password ⇒ String
Normalized version of password.
-
#normalized_path ⇒ String
Normalized version of path.
-
#normalized_port ⇒ String
Normalized version of port.
-
#normalized_query ⇒ String
Normalized version of query.
-
#normalized_scheme ⇒ String
Return normalized version of scheme, if any.
-
#normalized_user ⇒ String
Normalized version of user.
-
#normalized_userinfo ⇒ String
Normalized version of userinfo.
-
#object ⇒ Hash{Symbol => String}
(also: #to_hash)
Returns object representation of this URI, broken into components.
-
#parent ⇒ RDF::URI
Returns a copy of this URI with the path component ascended to the parent directory, if any.
-
#parse(value) ⇒ Object{Symbol => String}
{ Parse a URI into it’s components.
- #password ⇒ String
-
#password=(value) ⇒ RDF::URI
Self.
- #path ⇒ String
-
#path=(value) ⇒ RDF::URI
Self.
-
#pname ⇒ String
Returns a string version of the QName or the full IRI.
- #port ⇒ String
-
#port=(value) ⇒ RDF::URI
Self.
-
#qname ⇒ Array(Symbol, Symbol)
Returns a qualified name (QName) for this URI based on available vocabularies, if possible.
- #query ⇒ String
-
#query=(value) ⇒ RDF::URI
Self.
-
#query_values(return_type = Hash) ⇒ Hash, Array
Converts the query component to a Hash value.
-
#query_values=(value) ⇒ Object
Sets the query component for this URI from a Hash object.
-
#relative? ⇒ Boolean
A URI is relative when it does not have a scheme.
-
#relativize(base_uri) ⇒ RDF::URI
Attempt to make this URI relative to the provided ‘base_uri`.
-
#request_uri ⇒ String
The HTTP request URI for this URI.
-
#root ⇒ RDF::URI
Returns a copy of this URI with the path component set to ‘/`.
-
#root? ⇒ Boolean
Returns ‘true` if this URI’s scheme is not hierarchical, or its path component is equal to ‘/`.
- #scheme ⇒ String
-
#scheme=(value) ⇒ RDF::URI
Self.
-
#start_with?(string) ⇒ Boolean
(also: #starts_with?)
Returns ‘true` if this URI starts with the given `string`.
-
#to_str ⇒ String
(also: #to_s)
Returns the string representation of this URI.
-
#to_uri ⇒ RDF::URI
Returns ‘self`.
-
#uri? ⇒ Boolean
Returns ‘true`.
-
#url? ⇒ Boolean
Returns ‘true` if this URI is a URL.
-
#urn? ⇒ Boolean
Returns ‘true` if this URI is a URN.
- #user ⇒ String
-
#user=(value) ⇒ RDF::URI
Self.
-
#userinfo ⇒ Object
Userinfo is a combination of user and password.
-
#userinfo=(value) ⇒ RDF::URI
Self.
-
#valid? ⇒ Boolean
Determine if the URI is a valid according to RFC3987.
-
#validate! ⇒ RDF::URI
Validates this URI, raising an error if it is invalid.
-
#value ⇒ String
lexical representation of URI, either absolute or relative.
Methods included from Resource
Methods included from Term
#<=>, #compatible?, #term?, #to_base, #to_term
Methods included from Value
#anonymous?, #constant?, #graph?, #inspect!, #invalid?, #iri?, #list?, #literal?, #node?, #resource?, #statement?, #term?, #to_nquads, #to_ntriples, #to_rdf, #to_term, #type_error, #variable?
Constructor Details
#URI(uri, options = {}) ⇒ URI #URI(options = {}) ⇒ URI
Returns a new instance of URI.
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/rdf/model/uri.rb', line 225 def initialize(*args, validate: false, canonicalize: false, **) uri = args.first if uri @value = uri.to_s if @value.encoding != Encoding::UTF_8 @value = @value.dup if @value.frozen? @value.force_encoding(Encoding::UTF_8) @value.freeze end else %w( scheme user password userinfo host port authority path query fragment ).map(&:to_sym).each do |meth| if .has_key?(meth) self.send("#{meth}=".to_sym, [meth]) else self.send(meth) end end end validate! if validate canonicalize! if canonicalize end |
Class Method Details
.cache ⇒ RDF::Util::Cache
122 123 124 125 |
# File 'lib/rdf/model/uri.rb', line 122 def self.cache require 'rdf/util/cache' unless defined?(::RDF::Util::Cache) @cache ||= RDF::Util::Cache.new(CACHE_SIZE) end |
.intern(*args) ⇒ RDF::URI
Returns an interned ‘RDF::URI` instance based on the given `uri` string.
The maximum number of cached interned URI references is given by the ‘CACHE_SIZE` constant. This value is unlimited by default, in which case an interned URI object will be purged only when the last strong reference to it is garbage collected (i.e., when its finalizer runs).
Excepting special memory-limited circumstances, it should always be safe and preferred to construct new URI references using ‘RDF::URI.intern` instead of `RDF::URI.new`, since if an interned object can’t be returned for some reason, this method will fall back to returning a freshly-allocated one.
144 145 146 147 |
# File 'lib/rdf/model/uri.rb', line 144 def self.intern(*args) str = args.first (cache[(str = str.to_s).to_sym] ||= self.new(*args)).freeze end |
.normalize_path(path) ⇒ String
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.
Resolve paths to their simplest form.
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/rdf/model/uri.rb', line 170 def self.normalize_path(path) output, input = "", path.to_s if input.encoding != Encoding::ASCII_8BIT input = input.dup if input.frozen? input = input.force_encoding(Encoding::ASCII_8BIT) end until input.empty? if input.match(RDS_2A) # If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, input = $1 elsif input.match(RDS_2B1) || input.match(RDS_2B2) # 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, input = "/#{$1}" elsif input.match(RDS_2C1) || input.match(RDS_2C2) # 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 input = "/#{$1}" # and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise, output.sub!(/\/?[^\/]*$/, '') elsif input.match(RDS_2D) # if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, input = "" elsif input.match(RDS_2E) # 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 seg, input = $1, $2 output << seg end end output.force_encoding(Encoding::UTF_8) end |
.parse(str) ⇒ RDF::URI
Creates a new ‘RDF::URI` instance based on the given `uri` string.
This is just an alias for #initialize for compatibity with ‘Addressable::URI.parse`. Actual parsing is defered until #object is accessed.
158 159 160 |
# File 'lib/rdf/model/uri.rb', line 158 def self.parse(str) self.new(str) end |
Instance Method Details
#+(other) ⇒ RDF::URI
Simple concatenation operator. Returns a URI formed from concatenating the string form of two elements.
For building URIs from fragments, you may want to use the smart separator, ‘#/`. `#join` implements another set of URI building semantics.
540 541 542 |
# File 'lib/rdf/model/uri.rb', line 540 def +(other) RDF::URI.intern(self.to_s + other.to_s) end |
#/(fragment) ⇒ RDF::URI
‘Smart separator’ URI builder
This method attempts to use some understanding of the most common use cases for URLs and URNs to create a simple method for building new URIs from fragments. This means that it will always insert a separator of some sort, will remove duplicate seperators, will always assume that a fragment argument represents a relative and not absolute path, and throws an exception when an absolute URI is received for a fragment argument.
This is separate from the semantics for ‘#join`, which are well-defined by RFC3986 section 5.2 as part of the merging and normalization process; this method does not perform any normalization, removal of spurious paths, or removal of parent directory references `(/../)`.
See also ‘#+`, which concatenates the string forms of two URIs without any sort of checking or processing.
For an up-to-date list of edge case behavior, see the shared examples for RDF::URI in the rdf-spec project.
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 |
# File 'lib/rdf/model/uri.rb', line 485 def /(fragment) frag = fragment.respond_to?(:to_uri) ? fragment.to_uri : RDF::URI(fragment.to_s) raise ArgumentError, "Non-absolute URI or string required, got #{frag}" unless frag.relative? if urn? RDF::URI.intern(to_s.sub(/:+$/,'') + ':' + fragment.to_s.sub(/^:+/,'')) else # !urn? res = self.dup if res.fragment case fragment.to_s[0,1] when '/' # Base with a fragment, fragment beginning with '/'. The fragment wins, we use '/'. path, frag = fragment.to_s.split('#', 2) res.path = "#{res.path}/#{path.sub(/^\/*/,'')}" res.fragment = frag else # Replace fragment res.fragment = fragment.to_s.sub(/^#+/,'') end else # Not a fragment. includes '/'. Results from bases ending in '/' are the same as if there were no trailing slash. case fragment.to_s[0,1] when '#' # Base ending with '/', fragment beginning with '#'. The fragment wins, we use '#'. res.path = res.path.to_s.sub!(/\/*$/, '') # Add fragment res.fragment = fragment.to_s.sub(/^#+/,'') else # Add fragment as path component path, frag = fragment.to_s.split('#', 2) res.path = res.path.to_s.sub(/\/*$/,'/') + path.sub(/^\/*/,'') res.fragment = frag end end RDF::URI.intern(res.to_s) end end |
#==(other) ⇒ Boolean
Checks whether this URI is equal to ‘other` (type checking).
Per SPARQL data-r2/expr-equal/eq-2-2, numeric can’t be compared with other types
734 735 736 737 738 739 740 741 742 743 |
# File 'lib/rdf/model/uri.rb', line 734 def ==(other) case other when Literal # If other is a Literal, reverse test to consolodate complex type checking logic other == self when String then to_s == other when URI then hash == other.hash && to_s == other.to_s else other.respond_to?(:to_uri) && to_s == other.to_uri.to_s end end |
#===(other) ⇒ Boolean
Checks for case equality to the given ‘other` object.
758 759 760 761 762 763 |
# File 'lib/rdf/model/uri.rb', line 758 def ===(other) case other when Regexp then other === to_s else self == other end end |
#=~(pattern) ⇒ Integer
Performs a pattern match using the given regular expression.
776 777 778 779 780 781 |
# File 'lib/rdf/model/uri.rb', line 776 def =~(pattern) case pattern when Regexp then to_s =~ pattern else super # `Object#=~` returns `false` end end |
#absolute? ⇒ Boolean
A URI is absolute when it has a scheme
306 |
# File 'lib/rdf/model/uri.rb', line 306 def absolute?; !scheme.nil?; end |
#authority ⇒ Object
Authority is a combination of user, password, host and port
1115 1116 1117 1118 1119 |
# File 'lib/rdf/model/uri.rb', line 1115 def object.fetch(:authority) { @object[:authority] = ( if @object[:host]) } end |
#authority=(value) ⇒ RDF::URI
Returns self.
1124 1125 1126 1127 1128 1129 1130 |
# File 'lib/rdf/model/uri.rb', line 1124 def (value) object.delete_if {|k, v| [:user, :password, :host, :port, :userinfo].include?(k)} object[:authority] = (value.to_s.force_encoding(Encoding::UTF_8) if value) user; password; userinfo; host; port @value = nil self end |
#canonicalize ⇒ RDF::URI Also known as: normalize
Returns a copy of this URI converted into its canonical lexical representation.
366 367 368 |
# File 'lib/rdf/model/uri.rb', line 366 def canonicalize self.dup.canonicalize! end |
#canonicalize! ⇒ RDF::URI Also known as: normalize!
Converts this URI into its canonical lexical representation.
376 377 378 379 380 381 382 383 384 385 386 |
# File 'lib/rdf/model/uri.rb', line 376 def canonicalize! @object = { scheme: normalized_scheme, authority: , path: normalized_path.sub(/\/+/, '/'), query: normalized_query, fragment: normalized_fragment } @value = nil self end |
#dup ⇒ RDF::URI
Returns a duplicate copy of ‘self`.
657 658 659 |
# File 'lib/rdf/model/uri.rb', line 657 def dup self.class.new((@value || @object).dup) end |
#end_with?(string) ⇒ Boolean Also known as: ends_with?
Returns ‘true` if this URI ends with the given `string`.
702 703 704 |
# File 'lib/rdf/model/uri.rb', line 702 def end_with?(string) to_s.end_with?(string.to_s) end |
#eql?(other) ⇒ Boolean
Checks whether this URI the same term as ‘other`.
717 718 719 |
# File 'lib/rdf/model/uri.rb', line 717 def eql?(other) other.is_a?(URI) && self.hash == other.hash && self == other end |
#fragment ⇒ String
1091 1092 1093 1094 1095 |
# File 'lib/rdf/model/uri.rb', line 1091 def fragment object.fetch(:fragment) do nil end end |
#fragment=(value) ⇒ RDF::URI
Returns self.
1100 1101 1102 1103 1104 |
# File 'lib/rdf/model/uri.rb', line 1100 def fragment=(value) object[:fragment] = (value.to_s.force_encoding(Encoding::UTF_8) if value) @value = nil self end |
#freeze ⇒ Object
663 664 665 666 667 668 669 670 671 672 673 |
# File 'lib/rdf/model/uri.rb', line 663 def freeze unless frozen? # Create derived components ; userinfo; user; password; host; port @value = value.freeze @object = object.freeze @hash = hash.freeze super end self end |
#has_parent? ⇒ Boolean
Returns ‘true` if this URI is hierarchical and it’s path component isn’t equal to ‘/`.
586 587 588 |
# File 'lib/rdf/model/uri.rb', line 586 def has_parent? !root? end |
#hash ⇒ Fixnum
Returns a hash code for this URI.
826 827 828 |
# File 'lib/rdf/model/uri.rb', line 826 def hash @hash ||= (value.hash * -1) end |
#hier? ⇒ Boolean
Returns ‘true` if the URI scheme is hierarchical.
286 287 288 |
# File 'lib/rdf/model/uri.rb', line 286 def hier? !NON_HIER_SCHEMES.include?(scheme) end |
#host ⇒ String
947 948 949 950 951 |
# File 'lib/rdf/model/uri.rb', line 947 def host object.fetch(:host) do @object[:host] = ($1 if @object[:authority].to_s.match(/(?:[^@]+@)?([^:]+)(?::.*)?$/)) end end |
#host=(value) ⇒ RDF::URI
Returns self.
956 957 958 959 960 961 |
# File 'lib/rdf/model/uri.rb', line 956 def host=(value) object[:host] = (value.to_s.force_encoding(Encoding::UTF_8) if value) @object[:authority] = @value = nil self end |
#inspect ⇒ String
Returns a String representation of the URI object’s state.
805 806 807 |
# File 'lib/rdf/model/uri.rb', line 805 def inspect sprintf("#<%s:%#0x URI:%s>", URI.to_s, self.object_id, self.to_s) end |
#join(*uris) ⇒ RDF::URI
Joins several URIs together.
This method conforms to join normalization semantics as per RFC3986, section 5.2. This method normalizes URIs, removes some duplicate path information, such as double slashes, and other behavior specified in the RFC.
Other URI building methods are ‘#/` and `#+`.
For an up-to-date list of edge case behavior, see the shared examples for RDF::URI in the rdf-spec project.
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
# File 'lib/rdf/model/uri.rb', line 413 def join(*uris) joined_parts = object.dup.delete_if {|k, v| [:user, :password, :host, :port].include?(k)} uris.each do |uri| uri = RDF::URI.new(uri) unless uri.is_a?(RDF::URI) next if uri.to_s.empty? # Don't mess with base URI case when uri.scheme joined_parts = uri.object.merge(path: self.class.normalize_path(uri.path)) when uri. joined_parts[:authority] = uri. joined_parts[:path] = self.class.normalize_path(uri.path) joined_parts[:query] = uri.query when uri.path.to_s.empty? joined_parts[:query] = uri.query if uri.query when uri.path[0,1] == '/' joined_parts[:path] = self.class.normalize_path(uri.path) joined_parts[:query] = uri.query else # Merge path segments from section 5.2.3 base_path = path.to_s.sub(/\/[^\/]*$/, '/') joined_parts[:path] = self.class.normalize_path(base_path + uri.path) joined_parts[:query] = uri.query end joined_parts[:fragment] = uri.fragment end # Return joined URI RDF::URI.new(joined_parts) end |
#length ⇒ Integer Also known as: size
Returns the string length of this URI.
333 334 335 |
# File 'lib/rdf/model/uri.rb', line 333 def length to_s.length end |
#normalized_authority ⇒ String
Return normalized version of authority, if any
1135 1136 1137 1138 1139 1140 1141 |
# File 'lib/rdf/model/uri.rb', line 1135 def if (userinfo ? "#{normalized_userinfo}@" : "") + normalized_host.to_s + (normalized_port ? ":#{normalized_port}" : "") end end |
#normalized_fragment ⇒ String
Normalized version of fragment
1109 1110 1111 |
# File 'lib/rdf/model/uri.rb', line 1109 def normalized_fragment normalize_segment(fragment, IFRAGMENT) if fragment end |
#normalized_host ⇒ String
Normalized version of host
966 967 968 969 |
# File 'lib/rdf/model/uri.rb', line 966 def normalized_host # Remove trailing '.' characters normalize_segment(host, IHOST, true).sub(/\.*$/, '') if host end |
#normalized_password ⇒ String
Normalized version of password
941 942 943 |
# File 'lib/rdf/model/uri.rb', line 941 def normalized_password ::URI.encode(::URI.decode(password), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if password end |
#normalized_path ⇒ String
Normalized version of path
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 |
# File 'lib/rdf/model/uri.rb', line 1029 def normalized_path segments = path.to_s.split('/', -1) # preserve null segments norm_segs = case when # ipath-abempty segments.map {|s| normalize_segment(s, ISEGMENT)} when segments[0].nil? # ipath-absolute res = [nil] res << normalize_segment(segments[1], ISEGMENT_NZ) if segments.length > 1 res += segments[2..-1].map {|s| normalize_segment(s, ISEGMENT)} if segments.length > 2 res when segments[0].to_s.index(':') # ipath-noscheme res = [] res << normalize_segment(segments[0], ISEGMENT_NZ_NC) res += segments[1..-1].map {|s| normalize_segment(s, ISEGMENT)} if segments.length > 1 res when segments[0] # ipath-rootless # ipath-noscheme res = [] res << normalize_segment(segments[0], ISEGMENT_NZ) res += segments[1..-1].map {|s| normalize_segment(s, ISEGMENT)} if segments.length > 1 res else # Should be empty segments end res = self.class.normalize_path(norm_segs.join("/")) # Special rules for specific protocols having empty paths res.empty? ? (%w(http https ftp tftp).include?(normalized_scheme) ? '/' : "") : res end |
#normalized_port ⇒ String
Normalized version of port
992 993 994 995 996 997 998 999 1000 1001 |
# File 'lib/rdf/model/uri.rb', line 992 def normalized_port if port np = normalize_segment(port.to_s, PORT) if PORT_MAPPING[normalized_scheme] == np.to_i nil else np.to_i end end end |
#normalized_query ⇒ String
Normalized version of query
1085 1086 1087 |
# File 'lib/rdf/model/uri.rb', line 1085 def normalized_query normalize_segment(query, IQUERY) if query end |
#normalized_scheme ⇒ String
Return normalized version of scheme, if any
889 890 891 |
# File 'lib/rdf/model/uri.rb', line 889 def normalized_scheme scheme.strip.downcase if scheme end |
#normalized_user ⇒ String
Normalized version of user
915 916 917 |
# File 'lib/rdf/model/uri.rb', line 915 def normalized_user ::URI.encode(::URI.decode(user), /[^#{IUNRESERVED}|#{SUB_DELIMS}]/) if user end |
#normalized_userinfo ⇒ String
Normalized version of userinfo
1165 1166 1167 |
# File 'lib/rdf/model/uri.rb', line 1165 def normalized_userinfo normalized_user + (password ? ":#{normalized_password}" : "") if userinfo end |
#object ⇒ Hash{Symbol => String} Also known as: to_hash
Returns object representation of this URI, broken into components
834 835 836 |
# File 'lib/rdf/model/uri.rb', line 834 def object @object ||= parse(@value) end |
#parent ⇒ RDF::URI
Returns a copy of this URI with the path component ascended to the parent directory, if any.
599 600 601 602 603 604 605 606 607 608 609 610 611 |
# File 'lib/rdf/model/uri.rb', line 599 def parent case when root? then nil else require 'pathname' unless defined?(Pathname) if path = Pathname.new(self.path).parent uri = self.dup uri.path = path.to_s uri.path << '/' unless uri.root? uri end end end |
#parse(value) ⇒ Object{Symbol => String}
{ Parse a URI into it’s components
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 |
# File 'lib/rdf/model/uri.rb', line 844 def parse(value) value = value.to_s.dup.force_encoding(Encoding::ASCII_8BIT) parts = {} if matchdata = value.to_s.match(IRI_PARTS) scheme, , path, query, fragment = matchdata.to_a[1..-1] userinfo, hostport = .to_s.split('@', 2) hostport, userinfo = userinfo, nil unless hostport user, password = userinfo.to_s.split(':', 2) host, port = hostport.to_s.split(':', 2) parts[:scheme] = (scheme.force_encoding(Encoding::UTF_8) if scheme) parts[:authority] = (.force_encoding(Encoding::UTF_8) if ) parts[:userinfo] = (userinfo.force_encoding(Encoding::UTF_8) if userinfo) parts[:user] = (user.force_encoding(Encoding::UTF_8) if user) parts[:password] = (password.force_encoding(Encoding::UTF_8) if password) parts[:host] = (host.force_encoding(Encoding::UTF_8) if host) parts[:port] = (::URI.decode(port).to_i if port) parts[:path] = (path.to_s.force_encoding(Encoding::UTF_8) unless path.empty?) parts[:query] = (query[1..-1].force_encoding(Encoding::UTF_8) if query) parts[:fragment] = (fragment[1..-1].force_encoding(Encoding::UTF_8) if fragment) end parts end |
#password ⇒ String
921 922 923 924 925 |
# File 'lib/rdf/model/uri.rb', line 921 def password object.fetch(:password) do @object[:password] = (userinfo.split(':', 2)[1] if userinfo) end end |
#password=(value) ⇒ RDF::URI
Returns self.
930 931 932 933 934 935 936 |
# File 'lib/rdf/model/uri.rb', line 930 def password=(value) object[:password] = (value.to_s.force_encoding(Encoding::UTF_8) if value) @object[:userinfo] = format_userinfo("") @object[:authority] = @value = nil self end |
#path ⇒ String
1005 1006 1007 1008 1009 |
# File 'lib/rdf/model/uri.rb', line 1005 def path object.fetch(:path) do nil end end |
#path=(value) ⇒ RDF::URI
Returns self.
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
# File 'lib/rdf/model/uri.rb', line 1014 def path=(value) if value # Always lead with a slash value = "/#{value}" if host && value.to_s =~ /^[^\/]/ object[:path] = value.to_s.force_encoding(Encoding::UTF_8) else object[:path] = nil end @value = nil self end |
#pname ⇒ String
Returns a string version of the QName or the full IRI
649 650 651 |
# File 'lib/rdf/model/uri.rb', line 649 def pname (q = self.qname) ? q.join(":") : to_s end |
#port ⇒ String
973 974 975 976 977 |
# File 'lib/rdf/model/uri.rb', line 973 def port object.fetch(:port) do @object[:port] = ($1 if @object[:authority].to_s.match(/:(\d+)$/)) end end |
#port=(value) ⇒ RDF::URI
Returns self.
982 983 984 985 986 987 |
# File 'lib/rdf/model/uri.rb', line 982 def port=(value) object[:port] = (value.to_s.to_i if value) @object[:authority] = @value = nil self end |
#qname ⇒ Array(Symbol, Symbol)
Returns a qualified name (QName) for this URI based on available vocabularies, if possible.
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 |
# File 'lib/rdf/model/uri.rb', line 622 def qname if self.to_s =~ %r([:/#]([^:/#]*)$) local_name = $1 vocab_uri = local_name.empty? ? self.to_s : self.to_s[0...-(local_name.length)] Vocabulary.each do |vocab| if vocab.to_uri == vocab_uri prefix = vocab.equal?(RDF) ? :rdf : vocab.__prefix__ return [prefix, local_name.empty? ? nil : local_name.to_sym] end end else Vocabulary.each do |vocab| vocab_uri = vocab.to_uri if self.start_with?(vocab_uri) prefix = vocab.equal?(RDF) ? :rdf : vocab.__prefix__ local_name = self.to_s[vocab_uri.length..-1] return [prefix, local_name.empty? ? nil : local_name.to_sym] end end end return nil # no QName found end |
#query ⇒ String
1067 1068 1069 1070 1071 |
# File 'lib/rdf/model/uri.rb', line 1067 def query object.fetch(:query) do nil end end |
#query=(value) ⇒ RDF::URI
Returns self.
1076 1077 1078 1079 1080 |
# File 'lib/rdf/model/uri.rb', line 1076 def query=(value) object[:query] = (value.to_s.force_encoding(Encoding::UTF_8) if value) @value = nil self end |
#query_values(return_type = Hash) ⇒ Hash, Array
Converts the query component to a Hash value.
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 |
# File 'lib/rdf/model/uri.rb', line 1183 def query_values(return_type=Hash) raise ArgumentError, "Invalid return type. Must be Hash or Array." unless [Hash, Array].include?(return_type) return nil if query.nil? query.to_s.split('&'). inject(return_type == Hash ? {} : []) do |memo,kv| k,v = kv.to_s.split('=', 2) next if k.to_s.empty? k = ::URI.decode(k) v = ::URI.decode(v) if v if return_type == Hash case memo[k] when nil then memo[k] = v when Array then memo[k] << v else memo[k] = [memo[k], v] end else memo << [k, v].compact end memo end end |
#query_values=(value) ⇒ Object
Sets the query component for this URI from a Hash object. An empty Hash or Array will result in an empty query string.
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 |
# File 'lib/rdf/model/uri.rb', line 1230 def query_values=(value) if value.nil? self.query = nil return end value = value.to_hash if value.respond_to?(:to_hash) self.query = case value when Array, Hash value.map do |(k,v)| k = normalize_segment(k.to_s, UNRESERVED) if v.nil? k else Array(v).map do |vv| if vv === TrueClass k else "#{k}=#{normalize_segment(vv.to_s, UNRESERVED)}" end end.join("&") end end else raise TypeError, "Can't convert #{value.class} into Hash." end.join("&") end |
#relative? ⇒ Boolean
A URI is relative when it does not have a scheme
311 |
# File 'lib/rdf/model/uri.rb', line 311 def relative?; !absolute?; end |
#relativize(base_uri) ⇒ RDF::URI
Attempt to make this URI relative to the provided ‘base_uri`. If successful, returns a relative URI, otherwise the original URI
316 317 318 319 320 321 322 323 |
# File 'lib/rdf/model/uri.rb', line 316 def relativize(base_uri) if base_uri.to_s.end_with?("/", "#") && self.to_s.start_with?(base_uri.to_s) RDF::URI(self.to_s[base_uri.to_s.length..-1]) else self end end |
#request_uri ⇒ String
The HTTP request URI for this URI. This is the path and the query string.
1264 1265 1266 1267 1268 1269 |
# File 'lib/rdf/model/uri.rb', line 1264 def request_uri return nil if absolute? && scheme !~ /^https?$/ res = path.to_s.empty? ? "/" : path res += "?#{self.query}" if self.query return res end |
#root ⇒ RDF::URI
Returns a copy of this URI with the path component set to ‘/`.
568 569 570 571 572 573 574 575 576 |
# File 'lib/rdf/model/uri.rb', line 568 def root if root? self else RDF::URI.new( object.merge(path: '/'). keep_if {|k, v| [:scheme, :authority, :path].include?(k)}) end end |
#root? ⇒ Boolean
Returns ‘true` if this URI’s scheme is not hierarchical, or its path component is equal to ‘/`. Protocols not using hierarchical components are always considered to be at the root.
556 557 558 |
# File 'lib/rdf/model/uri.rb', line 556 def root? !self.hier? || self.path == '/' || self.path.to_s.empty? end |
#scheme ⇒ String
871 872 873 874 875 |
# File 'lib/rdf/model/uri.rb', line 871 def scheme object.fetch(:scheme) do nil end end |
#scheme=(value) ⇒ RDF::URI
Returns self.
880 881 882 883 884 |
# File 'lib/rdf/model/uri.rb', line 880 def scheme=(value) object[:scheme] = (value.to_s.force_encoding(Encoding::UTF_8) if value) @value = nil self end |
#start_with?(string) ⇒ Boolean Also known as: starts_with?
Returns ‘true` if this URI starts with the given `string`.
686 687 688 |
# File 'lib/rdf/model/uri.rb', line 686 def start_with?(string) to_s.start_with?(string.to_s) end |
#to_str ⇒ String Also known as: to_s
Returns the string representation of this URI.
798 |
# File 'lib/rdf/model/uri.rb', line 798 def to_str; value; end |
#to_uri ⇒ RDF::URI
Returns ‘self`.
787 788 789 |
# File 'lib/rdf/model/uri.rb', line 787 def to_uri self end |
#uri? ⇒ Boolean
Returns ‘true`.
258 259 260 |
# File 'lib/rdf/model/uri.rb', line 258 def uri? true end |
#url? ⇒ Boolean
Returns ‘true` if this URI is a URL.
299 300 301 |
# File 'lib/rdf/model/uri.rb', line 299 def url? !urn? end |
#urn? ⇒ Boolean
Returns ‘true` if this URI is a URN.
271 272 273 |
# File 'lib/rdf/model/uri.rb', line 271 def urn? @object ? @object[:scheme] == 'urn' : start_with?('urn:') end |
#user ⇒ String
895 896 897 898 899 |
# File 'lib/rdf/model/uri.rb', line 895 def user object.fetch(:user) do @object[:user] = (userinfo.split(':', 2)[0] if userinfo) end end |
#user=(value) ⇒ RDF::URI
Returns self.
904 905 906 907 908 909 910 |
# File 'lib/rdf/model/uri.rb', line 904 def user=(value) object[:user] = (value.to_s.force_encoding(Encoding::UTF_8) if value) @object[:userinfo] = format_userinfo("") @object[:authority] = @value = nil self end |
#userinfo ⇒ Object
Userinfo is a combination of user and password
1145 1146 1147 1148 1149 |
# File 'lib/rdf/model/uri.rb', line 1145 def userinfo object.fetch(:userinfo) { @object[:userinfo] = (format_userinfo("") if @object[:user]) } end |
#userinfo=(value) ⇒ RDF::URI
Returns self.
1154 1155 1156 1157 1158 1159 1160 |
# File 'lib/rdf/model/uri.rb', line 1154 def userinfo=(value) object.delete_if {|k, v| [:user, :password, :authority].include?(k)} object[:userinfo] = (value.to_s.force_encoding(Encoding::UTF_8) if value) user; password; @value = nil self end |
#valid? ⇒ Boolean
Determine if the URI is a valid according to RFC3987
Note that RDF URIs syntactically can contain Unicode escapes, which are unencoded in the internal representation. To validate, %-encode specifically excluded characters from IRIREF
345 346 347 |
# File 'lib/rdf/model/uri.rb', line 345 def valid? to_s.match(RDF::URI::IRI) || false end |
#validate! ⇒ RDF::URI
Validates this URI, raising an error if it is invalid.
355 356 357 358 |
# File 'lib/rdf/model/uri.rb', line 355 def validate! raise ArgumentError, "#{to_base.inspect} is not a valid IRI" if invalid? self end |
#value ⇒ String
lexical representation of URI, either absolute or relative
812 813 814 815 816 817 818 819 820 |
# File 'lib/rdf/model/uri.rb', line 812 def value @value ||= [ ("#{scheme}:" if absolute?), ("//#{}" if ), path, ("?#{query}" if query), ("##{fragment}" if fragment) ].compact.join("").freeze end |