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
         |