lib/uri/generic.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  # $Id: generic.rb,v 1.4 2002/06/12 09:31:41 akira Exp $
   3  #
   4  # Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
   5  # You can redistribute it and/or modify it under the same term as Ruby.
   6  #
   7  
   8  require 'uri/common'
   9  
  10  module URI
  11  
  12  =begin
  13  
  14  == URI::Generic
  15  
  16  === Super Class
  17  
  18  Object
  19  
  20  =end
  21  
  22    class Generic
  23      include REGEXP
  24  
  25  =begin
  26  
  27  === Class Methods
  28  
  29  --- URI::Generic::default_port
  30  
  31  =end
  32      DEFAULT_PORT = nil
  33  
  34      def self.default_port
  35        self::DEFAULT_PORT
  36      end
  37  
  38      def default_port
  39        self.type.default_port
  40      end
  41  
  42  =begin
  43  --- URI::Generic::component
  44  =end
  45      COMPONENT = [
  46        :scheme, 
  47        :userinfo, :host, :port, :registry, 
  48        :path, :opaque, 
  49        :query, 
  50        :fragment
  51      ].freeze
  52  
  53      def self.component
  54        self::COMPONENT
  55      end
  56  
  57  =begin
  58  --- URI::Generic::use_registry
  59  =end
  60      USE_REGISTRY = false
  61  
  62      def self.use_registry
  63        self::USE_REGISTRY
  64      end
  65  
  66  =begin
  67  
  68  --- URI::Generic::build2
  69      At first, try to create a new URI::Generic object using
  70      URI::Generic::build. But, if you get a exception
  71      URI::InvalidComponentError, then re-try to create an object with
  72      escaped components.
  73  
  74  --- URI::Generic::build
  75      Create a new URI::Generic object from components of URI::Generic
  76      with check.  It is scheme, userinfo, host, port, registry, path,
  77      opaque, query and fragment. It provided by an Array of a Hash.
  78  
  79  --- URI::Generic::new
  80      Create new URI::Generic object from ``generic'' components with no
  81      check.
  82  
  83  =end
  84      def self.build2(args)
  85        begin
  86          return self.build(args)
  87        rescue InvalidComponentError
  88          if args.kind_of?(Array)
  89            return self.build(args.collect{|x| 
  90                                if x
  91                                  URI.escape(x)
  92                                else
  93                                  x
  94                                end
  95                              })
  96          elsif args.kind_of?(Hash)
  97            tmp = {}
  98            args.each do |key, value|
  99              tmp[key] = if value
 100                           URI.escape(value)
 101                         else
 102                           value
 103                         end
 104            end
 105            return self.build(tmp)
 106          end
 107        end
 108      end
 109  
 110      def self.build(args)
 111        if args.kind_of?(Array) &&
 112            args.size == ::URI::Generic::COMPONENT.size
 113          tmp = args
 114        elsif args.kind_of?(Hash)
 115          tmp = ::URI::Generic::COMPONENT.collect do |c|
 116            if args.include?(c)
 117              args[c]
 118            else
 119              nil
 120            end
 121          end
 122        else
 123          raise ArgumentError, 
 124            "expected Array of or Hash of components of #{self.type} (#{self.type.component.join(', ')})"
 125        end
 126  
 127        tmp << true
 128        return self.new(*tmp)
 129      end
 130  
 131      def initialize(scheme, 
 132                     userinfo, host, port, registry, 
 133                     path, opaque, 
 134                     query, 
 135                     fragment,
 136                     arg_check = false)
 137        @scheme = nil
 138        @user = nil
 139        @password = nil
 140        @host = nil
 141        @port = nil
 142        @path = nil
 143        @query = nil
 144        @opaque = nil
 145        @registry = nil
 146        @fragment = nil
 147  
 148        if arg_check
 149          self.scheme = scheme
 150          self.userinfo = userinfo
 151          self.host = host
 152          self.port = port
 153          self.path = path
 154          self.query = query
 155          self.opaque = opaque
 156          self.registry = registry
 157          self.fragment = fragment
 158        else
 159          self.set_scheme(scheme)
 160          self.set_userinfo(userinfo)
 161          self.set_host(host)
 162          self.set_port(port)
 163          self.set_path(path)
 164          self.set_query(query)
 165          self.set_opaque(opaque)
 166          self.set_registry(registry)
 167          self.set_fragment(fragment)
 168        end
 169        if @registry && !self.class.use_registry
 170          raise InvalidURIError, "the scheme #{@scheme} does not accept registry part: #{@registry} (or bad hostname?)"
 171        end
 172        
 173        @scheme.freeze if @scheme
 174        self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2)
 175        self.set_port(self.default_port) if self.default_port && !@port
 176      end
 177      attr_reader :scheme
 178      attr_reader :host
 179      attr_reader :port
 180      attr_reader :registry
 181      attr_reader :path
 182      attr_reader :query
 183      attr_reader :opaque
 184      attr_reader :fragment
 185  
 186  =begin
 187  
 188  === Instance Methods
 189  
 190  =end
 191  
 192  =begin
 193  
 194  --- URI::Generic#component
 195  
 196  =end
 197      def component
 198        self.type.component
 199      end
 200  
 201      # set_XXX method sets value to @XXX instance variable with no check, 
 202      # so be careful if you use these methods. or, you use these method 
 203      # with check_XXX method, or you use XXX= methods.
 204  
 205  =begin
 206  
 207  --- URI::Generic#scheme
 208  
 209  --- URI::Generic#scheme=(v)
 210  
 211  =end
 212      #
 213      # methods for scheme
 214      #
 215      def check_scheme(v)
 216        if v && SCHEME !~ v
 217          raise InvalidComponentError,
 218            "bad component(expected scheme component): #{v}"
 219        end
 220  
 221        return true
 222      end
 223      private :check_scheme
 224  
 225      def set_scheme(v)
 226        @scheme = v
 227      end
 228      protected :set_scheme
 229  
 230      def scheme=(v)
 231        check_scheme(v)
 232        set_scheme(v)
 233      end
 234  
 235  =begin
 236  
 237  --- URI::Generic#userinfo
 238  
 239  --- URI::Generic#userinfo=(v)
 240  
 241  --- URI::Generic#user
 242  
 243  --- URI::Generic#user=(v)
 244  
 245  --- URI::Generic#password
 246  
 247  --- URI::Generic#password=(v)
 248  
 249  =end
 250      #
 251      # methods for userinfo
 252      #
 253      def check_userinfo(user, password = nil)
 254        if (user || password) &&
 255            (@registry || @opaque)
 256          raise InvalidURIError, 
 257            "can not set userinfo with registry or opaque"
 258        end
 259  
 260        if !password
 261          user, password = split_userinfo(user)
 262        end
 263        check_user(user)
 264        check_password(password)
 265  
 266        return true
 267      end
 268      private :check_userinfo
 269  
 270      def check_user(v)
 271        return v unless v
 272  
 273        if USERINFO !~ v
 274          raise InvalidComponentError,
 275            "bad component(expected userinfo component or user component): #{v}"
 276        end
 277  
 278        return true
 279      end
 280      private :check_user
 281  
 282      def check_password(v)
 283        return v unless v
 284  
 285        if !@password
 286          raise InvalidURIError,
 287            "password component depends user component"
 288        end
 289  
 290        if USERINFO !~ v
 291          raise InvalidComponentError,
 292            "bad component(expected user component): #{v}"
 293        end
 294  
 295        return true
 296      end
 297      private :check_password
 298  
 299      def userinfo=(userinfo)
 300        if userinfo.nil?
 301          return nil
 302        end
 303        check_userinfo(*userinfo)
 304        set_userinfo(*userinfo)
 305      end
 306  
 307      def user=(user)
 308        check_user(user)
 309        set_user(user)
 310      end
 311  
 312      def password=(password)
 313        check_password(password)
 314        set_password(password)
 315      end
 316  
 317      def set_userinfo(user, password = nil)
 318        unless password 
 319          user, password = split_userinfo(user)
 320        end
 321        @user     = user
 322        @password = password if password
 323  
 324        [@user, @password]
 325      end
 326      protected :set_userinfo
 327  
 328      def set_user(v)
 329        set_userinfo(v, @password)
 330        v
 331      end
 332      protected :set_user
 333  
 334      def set_password(v)
 335        set_userinfo(@user, v)
 336        v
 337      end
 338      protected :set_password
 339  
 340      def split_userinfo(ui)
 341        return nil, nil unless ui
 342        tmp = ui.index(':')
 343        if tmp
 344          user     = ui[0..tmp - 1]
 345          password = ui[tmp + 1..-1]
 346        else
 347          user     = ui
 348          password = nil
 349        end
 350  
 351        return user, password
 352      end
 353      private :split_userinfo
 354  
 355      def escape_userpass(v)
 356        v = URI.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/
 357      end
 358      private :escape_userpass
 359  
 360      def userinfo
 361        if !@password
 362          @user
 363        else
 364          @user + ':' + @password
 365        end
 366      end
 367  
 368      def user
 369        @user
 370      end
 371  
 372      def password
 373        @password
 374      end
 375  
 376  =begin
 377  
 378  --- URI::Generic#host
 379  
 380  --- URI::Generic#host=(v)
 381  
 382  =end
 383      #
 384      # methods for host
 385      #
 386  
 387      def check_host(v)
 388        return v unless v
 389  
 390        if @registry || @opaque
 391          raise InvalidURIError, 
 392            "can not set host with registry or opaque"
 393        elsif HOST !~ v
 394          raise InvalidComponentError,
 395            "bad component(expected host component): #{v}"
 396        end
 397  
 398        return true
 399      end
 400      private :check_host
 401  
 402      def set_host(v)
 403        @host = v
 404      end
 405      protected :set_host
 406  
 407      def host=(v)
 408        check_host(v)
 409        set_host(v)
 410      end
 411  
 412  =begin
 413  
 414  --- URI::Generic#port
 415  
 416  --- URI::Generic#port=(v)
 417  
 418  =end
 419      #
 420      # methods for port
 421      #
 422  
 423      def check_port(v)
 424        return v unless v
 425  
 426        if @registry || @opaque
 427          raise InvalidURIError, 
 428            "can not set port with registry or opaque"
 429        elsif !v.kind_of?(Fixnum) && PORT !~ v
 430          raise InvalidComponentError,
 431            "bad component(expected port component): #{v}"
 432        end
 433  
 434        return true
 435      end
 436      private :check_port
 437  
 438      def set_port(v)
 439        v = v.to_i if v && !v.kind_of?(Fixnum)
 440        @port = v
 441      end
 442      protected :set_port
 443  
 444      def port=(v)
 445        check_port(v)
 446        set_port(v)
 447      end
 448  
 449  =begin
 450  
 451  --- URI::Generic#registry
 452  
 453  --- URI::Generic#registry=(v)
 454  
 455  =end
 456      #
 457      # methods for registry
 458      #
 459  
 460      def check_registry(v)
 461        return v unless v
 462  
 463        # raise if both server and registry are not nil, because:
 464        # authority     = server | reg_name
 465        # server        = [ [ userinfo "@" ] hostport ]
 466        if @host || @port || @user # userinfo = @user + ':' + @password
 467          raise InvalidURIError, 
 468            "can not set registry with host, port, or userinfo"
 469        elsif v && REGISTRY !~ v
 470          raise InvalidComponentError,
 471            "bad component(expected registry component): #{v}"
 472        end
 473  
 474        return true
 475      end
 476      private :check_registry
 477  
 478      def set_registry(v)
 479        @registry = v
 480      end
 481      protected :set_registry
 482  
 483      def registry=(v)
 484        check_registry(v)
 485        set_registry(v)
 486      end
 487  
 488  =begin
 489  
 490  --- URI::Generic#path
 491  
 492  --- URI::Generic#path=(v)
 493  
 494  =end
 495      #
 496      # methods for path
 497      #
 498  
 499      def check_path(v)
 500        # raise if both hier and opaque are not nil, because:
 501        # absoluteURI   = scheme ":" ( hier_part | opaque_part )
 502        # hier_part     = ( net_path | abs_path ) [ "?" query ]
 503        if v && @opaque
 504          raise InvalidURIError, 
 505            "path conflicts with opaque"
 506        end
 507  
 508        if @scheme
 509          if v && v != '' && ABS_PATH !~ v
 510            raise InvalidComponentError, 
 511              "bad component(expected absolute path component): #{v}"
 512          end
 513        else
 514          if v && v != '' && ABS_PATH !~ v && REL_PATH !~ v
 515            raise InvalidComponentError, 
 516              "bad component(expected relative path component): #{v}"
 517          end
 518        end
 519  
 520        return true
 521      end
 522      private :check_path
 523  
 524      def set_path(v)
 525        @path = v
 526      end
 527      protected :set_path
 528  
 529      def path=(v)
 530        check_path(v)
 531        set_path(v)
 532      end
 533  
 534  =begin
 535  
 536  --- URI::Generic#query
 537  
 538  --- URI::Generic#query=(v)
 539  
 540  =end
 541      #
 542      # methods for query
 543      #
 544  
 545      def check_query(v)
 546        return v unless v
 547  
 548        # raise if both hier and opaque are not nil, because:
 549        # absoluteURI   = scheme ":" ( hier_part | opaque_part )
 550        # hier_part     = ( net_path | abs_path ) [ "?" query ]
 551        if @opaque
 552          raise InvalidURIError, 
 553            "query conflicts with opaque"
 554        end
 555  
 556        if v && v != '' && QUERY !~ v
 557            raise InvalidComponentError, 
 558              "bad component(expected query component): #{v}"
 559          end
 560  
 561        return true
 562      end
 563      private :check_query
 564  
 565      def set_query(v)
 566        @query = v
 567      end
 568      protected :set_query
 569  
 570      def query=(v)
 571        check_query(v)
 572        set_query(v)
 573      end
 574  
 575  =begin
 576  
 577  --- URI::Generic#opaque
 578  
 579  --- URI::Generic#opaque=(v)
 580  
 581  =end
 582      #
 583      # methods for opaque
 584      #
 585  
 586      def check_opaque(v)
 587        return v unless v
 588  
 589        # raise if both hier and opaque are not nil, because:
 590        # absoluteURI   = scheme ":" ( hier_part | opaque_part )
 591        # hier_part     = ( net_path | abs_path ) [ "?" query ]
 592        if @host || @port || @usr || @path  # userinfo = @user + ':' + @password
 593          raise InvalidURIError, 
 594            "can not set opaque with host, port, userinfo or path"
 595        elsif v && OPAQUE !~ v
 596          raise InvalidComponentError,
 597            "bad component(expected opaque component): #{v}"
 598        end
 599  
 600        return true
 601      end
 602      private :check_opaque
 603  
 604      def set_opaque(v)
 605        @opaque = v
 606      end
 607      protected :set_opaque
 608  
 609      def opaque=(v)
 610        check_opaque(v)
 611        set_opaque(v)
 612      end
 613  
 614  =begin
 615  
 616  --- URI::Generic#fragment
 617  
 618  --- URI::Generic#fragment=(v)
 619  
 620  =end
 621      #
 622      # methods for fragment
 623      #
 624  
 625      def check_fragment(v)
 626        return v unless v
 627  
 628        if v && v != '' && FRAGMENT !~ v
 629          raise InvalidComponentError, 
 630            "bad component(expected fragment component): #{v}"
 631        end
 632  
 633        return true
 634      end
 635      private :check_fragment
 636  
 637      def set_fragment(v)
 638        @fragment = v
 639      end
 640      protected :set_fragment
 641  
 642      def fragment=(v)
 643        check_fragment(v)
 644        set_fragment(v)
 645      end
 646  
 647  =begin
 648  
 649  --- URI::Generic#hierarchical?
 650  
 651  =end
 652      def hierarchical?
 653        if @path
 654          true
 655        else
 656          false
 657        end
 658      end
 659  
 660  =begin
 661  
 662  --- URI::Generic#absolute?
 663  
 664  =end
 665      def absolute?
 666        if @scheme
 667          true
 668        else
 669          false
 670        end
 671      end
 672      alias absolute absolute?
 673  
 674  =begin
 675  
 676  --- URI::Generic#relative?
 677  
 678  =end
 679      def relative?
 680        !absolute?
 681      end
 682  
 683  =begin
 684  
 685  --- URI::Generic#merge(rel)
 686  --- URI::Generic#+(rel)
 687  
 688  =end
 689      def split_path(path)
 690        path.split(%r{/+}, -1)
 691      end
 692      private :split_path
 693  
 694      def merge_path(base, rel)
 695        # RFC2396, Section 5.2, 5)
 696        if rel[0] == ?/ #/
 697          # RFC2396, Section 5.2, 5)
 698          return rel
 699  
 700        else
 701          # RFC2396, Section 5.2, 6)
 702          base_path = split_path(base)
 703          rel_path  = split_path(rel)
 704  
 705          if base_path.empty?
 706            base_path = [''] # XXX
 707          end
 708  
 709          # RFC2396, Section 5.2, 6), a)
 710          base_path.pop unless base_path.size == 1
 711  
 712          # RFC2396, Section 5.2, 6), c)
 713          # RFC2396, Section 5.2, 6), d)
 714          rel_path.push('') if rel_path.last == '.'
 715          rel_path.delete('.')
 716  
 717          # RFC2396, Section 5.2, 6), e)
 718          tmp = []
 719          rel_path.each do |x|
 720            if x == '..' &&
 721                !(tmp.empty? || tmp.last == '..')
 722              tmp.pop
 723            else
 724              tmp << x
 725            end
 726          end
 727  
 728          add_trailer_slash = true
 729          while x = tmp.shift
 730            if x == '..' && base_path.size > 1
 731              # RFC2396, Section 4
 732              # a .. or . in an absolute path has no special meaning
 733              base_path.pop
 734            else
 735              # if x == '..'
 736              #   valid absolute (but abnormal) path "/../..."
 737              # else
 738              #   valid absolute path
 739              # end
 740              base_path << x
 741              tmp.each {|t| base_path << t}
 742              add_trailer_slash = false
 743              break
 744            end
 745          end
 746          base_path.push('') if add_trailer_slash
 747  
 748          return base_path.join('/')
 749        end
 750      end
 751      private :merge_path
 752  
 753      # abs(self) + rel(oth) => abs(new)
 754      def merge(oth)
 755        base, rel = merge0(oth)
 756        if base == rel
 757          return base
 758        end
 759  
 760        authority = rel.userinfo || rel.host || rel.port
 761  
 762        # RFC2396, Section 5.2, 2)
 763        if rel.path.empty? && !authority && !rel.query
 764          base.set_fragment(rel.fragment) if rel.fragment
 765          return base
 766        end
 767  
 768        base.set_query(nil)
 769        base.set_fragment(nil)
 770  
 771        # RFC2396, Section 5.2, 4)
 772        if !authority
 773          base.set_path(merge_path(base.path, rel.path))
 774        else
 775          # RFC2396, Section 5.2, 4)
 776          base.set_path(rel.path)
 777        end
 778  
 779        # RFC2396, Section 5.2, 7)
 780        base.set_userinfo(rel.userinfo) if rel.userinfo
 781        base.set_host(rel.host)         if rel.host
 782        base.set_port(rel.port)         if rel.port
 783        base.set_query(rel.query)       if rel.query
 784        base.set_fragment(rel.fragment) if rel.fragment
 785  
 786        return base
 787      end # merge
 788      alias + merge
 789  
 790      # return base and rel.
 791      # you can modify `base', but can not `rel'.
 792      def merge0(oth)
 793        case oth
 794        when Generic
 795        when String
 796          oth = URI.parse(oth)
 797        else
 798          raise ArgumentError,
 799            "bad argument(expected URI object or URI string)"
 800        end
 801  
 802        if self.relative? && oth.relative?
 803          raise BadURIError, 
 804            "both URI are relative"
 805        end
 806  
 807        if self.absolute? && oth.absolute?
 808          #raise BadURIError, 
 809          #  "both URI are absolute"
 810          # hmm... should return oth for usability?
 811          return oth, oth
 812        end
 813  
 814        if !self.hierarchical?
 815          raise BadURIError, 
 816            "not hierarchical URI: #{self}"
 817        elsif !oth.hierarchical?
 818          raise BadURIError, 
 819            "not hierarchical URI: #{oth}"
 820        end
 821  
 822        if self.absolute?
 823          return self.dup, oth
 824        else
 825          return oth, oth
 826        end
 827      end
 828      private :merge0
 829  
 830  =begin
 831  
 832  --- URI::Generic#route_from(src)
 833  --- URI::Generic#-(src)
 834  
 835  =end
 836      def route_from_path(src, dst)
 837        # RFC2396, Section 4.2
 838        return '' if src == dst
 839  
 840        src_path = split_path(src)
 841        dst_path = split_path(dst)
 842  
 843        # hmm... dst has abnormal absolute path, 
 844        # like "/./", "/../", "/x/../", ...
 845        if dst_path.include?('..') ||
 846            dst_path.include?('.')
 847          return dst.dup
 848        end
 849  
 850        src_path.pop
 851  
 852        # discard same parts
 853        while dst_path.first == src_path.first
 854          break if dst_path.empty?
 855  
 856          src_path.shift
 857          dst_path.shift
 858        end
 859  
 860        tmp = dst_path.join('/')
 861  
 862        # calculate
 863        if src_path.empty?
 864          if tmp.empty?
 865            return './'
 866          elsif dst_path.first.include?(':') # (see RFC2396 Section 5)
 867            return './' + tmp
 868          else
 869            return tmp
 870          end
 871        end
 872  
 873        return '../' * src_path.size + tmp
 874      end
 875      private :route_from_path
 876  
 877      def route_from0(oth)
 878        case oth
 879        when Generic
 880        when String
 881          oth = URI.parse(oth)
 882        else
 883          raise ArgumentError,
 884            "bad argument(expected URI object or URI string)"
 885        end
 886  
 887        if self.relative?
 888          raise BadURIError, 
 889            "relative URI: #{self}"
 890        end
 891        if oth.relative?
 892          raise BadURIError, 
 893            "relative URI: #{oth}"
 894        end
 895  
 896        if !self.hierarchical? || !oth.hierarchical?
 897          return self, self.dup
 898        end
 899  
 900        if self.scheme != oth.scheme
 901          return oth, oth.dup
 902        end
 903        rel = URI::Generic.new(nil, # it is relative URI
 904                               self.userinfo, self.host, self.port, 
 905                               self.registry, self.path, self.opaque,
 906                               self.query, self.fragment)
 907  
 908        if rel.userinfo != oth.userinfo ||
 909            rel.host != oth.host ||
 910            rel.port != oth.port
 911          rel.set_port(nil) if rel.port == oth.default_port
 912          return rel, rel
 913        end
 914        rel.set_userinfo(nil)
 915        rel.set_host(nil)
 916        rel.set_port(nil)
 917  
 918        if rel.path == oth.path
 919          rel.set_path('')
 920          rel.set_query(nil) if rel.query == oth.query
 921          return rel, rel
 922        end
 923  
 924        # you can modify `rel', but can not `oth'.
 925        return oth, rel
 926      end
 927      private :route_from0
 928  
 929      # calculate relative path from oth to self
 930      def route_from(oth)
 931        # you can modify `rel', but can not `oth'.
 932        oth, rel = route_from0(oth)
 933        if oth == rel
 934          return rel
 935        end
 936  
 937        rel.set_path(route_from_path(oth.path, self.path))
 938        if rel.path == './' && self.query
 939          # "./?foo" -> "?foo"
 940          rel.set_path('')
 941        end
 942  
 943        return rel
 944      end
 945      # abs1 - abs2 => relative_path_to_abs1_from_abs2
 946      # (see http://www.nikonet.or.jp/spring/what_v/what_v_4.htm :-)
 947      alias - route_from
 948  
 949  =begin
 950  
 951  --- URI::Generic#route_to(dst)
 952  
 953  =end
 954      # calculate relative path to oth from self
 955      def route_to(oth)
 956        case oth
 957        when Generic
 958        when String
 959          oth = URI.parse(oth)
 960        else
 961          raise ArgumentError,
 962            "bad argument(expected URI object or URI string)"
 963        end
 964  
 965        oth.route_from(self)
 966      end
 967  
 968  =begin
 969  
 970  --- URI::Generic#normalize
 971  --- URI::Generic#normalize!
 972  
 973  =end
 974      def normalize
 975        uri = dup
 976        uri.normalize!
 977        uri
 978      end
 979  
 980      def normalize!
 981        if path && path == ''
 982          set_path('/')
 983        end
 984        if host && host != host.downcase
 985          set_host(self.host.downcase)
 986        end       
 987      end
 988  
 989  =begin
 990  
 991  --- URI::Generic#to_s
 992  
 993  =end
 994      def path_query
 995        str = @path
 996        if @query
 997          str += '?' + @query
 998        end
 999        str
1000      end
1001      private :path_query
1002  
1003      def to_str
1004        str = ''
1005        if @scheme
1006          str << @scheme
1007          str << ':'
1008        end
1009  
1010        if @opaque
1011          str << @opaque
1012  
1013        else
1014          if @registry
1015            str << @registry
1016          else
1017            if @host
1018              str << '//'
1019            end
1020            if self.userinfo
1021              str << self.userinfo
1022              str << '@'
1023            end
1024            if @host
1025              str << @host
1026            end
1027            if @port && @port != self.default_port
1028              str << ':'
1029              str << @port.to_s
1030            end
1031          end
1032  
1033          str << path_query
1034        end
1035  
1036        if @fragment
1037          str << '#'
1038          str << @fragment
1039        end
1040  
1041        str
1042      end
1043  
1044      def to_s
1045        to_str
1046      end
1047  
1048  =begin
1049  
1050  --- URI::Generic#==(oth)
1051  
1052  =end
1053      def ==(oth)
1054        if oth.kind_of?(String)
1055          oth = URI.parse(oth)
1056        end
1057  
1058        if self.class == oth.class
1059          self.normalize.to_ary == oth.normalize.to_ary
1060        else
1061          false
1062        end
1063      end
1064  
1065  =begin
1066  
1067  --- URI::Generic#===(oth)
1068  
1069  =end
1070  #    def ===(oth)
1071  #      raise NotImplementedError
1072  #    end
1073  
1074  =begin
1075  --- URI::Generic#to_a
1076  =end
1077      def to_ary
1078        component.collect do |x|
1079          self.send(x)
1080        end
1081      end
1082  
1083      def to_a
1084        to_ary
1085      end
1086  
1087  =begin
1088  =end
1089      def inspect
1090        sprintf("#<%s:0x%x URL:%s>", self.type.to_s, self.id, self.to_s)
1091      end
1092  
1093  =begin
1094  =end
1095      def coerce(oth)
1096        case oth
1097        when String
1098          oth = URI.parse(oth)
1099        else
1100          super
1101        end
1102  
1103        return oth, self
1104      end
1105    end # Generic
1106  end # URI