rhodes 1.5.4 → 1.5.5
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.
- data/Manifest.txt +11 -1
- data/Rakefile +1 -1
- data/lib/extensions/digest/ext/Rakefile +11 -6
- data/lib/extensions/digest/ext/build.bat +2 -0
- data/lib/extensions/uri/uri.rb +29 -0
- data/lib/extensions/uri/uri/common.rb +727 -0
- data/lib/extensions/uri/uri/ftp.rb +198 -0
- data/lib/extensions/uri/uri/generic.rb +1128 -0
- data/lib/extensions/uri/uri/http.rb +100 -0
- data/lib/extensions/uri/uri/https.rb +20 -0
- data/lib/extensions/uri/uri/ldap.rb +190 -0
- data/lib/extensions/uri/uri/ldaps.rb +12 -0
- data/lib/extensions/uri/uri/mailto.rb +266 -0
- data/lib/framework/rhodes.rb +2 -2
- data/lib/framework/rhom/rhom_db_adapter.rb +12 -26
- data/lib/framework/rhom/rhom_object_factory.rb +8 -1
- data/lib/framework/version.rb +2 -2
- data/lib/rhodes.rb +2 -2
- data/platform/android/Rhodes/AndroidManifest.xml +2 -2
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/Rhodes.java +87 -42
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/SplashScreen.java +58 -7
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/MainView.java +2 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/SimpleMainView.java +35 -19
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/TabbedMainView.java +4 -0
- data/platform/android/build/android.rake +30 -25
- data/platform/bb/build/rhodes_build.files +1 -1
- data/platform/bb/rhodes/rhodes.jdp +1 -1
- data/platform/bb/rhodes/src/com/rho/RhoRubyHelper.java +1 -1
- data/platform/bb/rhodes/src/com/rho/rubyext/Alert.java +300 -0
- data/platform/bb/rhodes/src/com/rho/rubyext/GeoLocation.java +42 -5
- data/platform/bb/rhodes/src/rhomobile/PushListeningThread.java +3 -4
- data/platform/bb/rhodes/src/rhomobile/RhodesApplication.java +33 -107
- data/platform/iphone/Classes/RhoRunnerAppDelegate.m +2 -0
- data/platform/iphone/Info.plist +1 -1
- data/platform/iphone/rbuild/iphone.rake +1 -1
- data/platform/iphone/rhoextlib/rhoextlib.xcodeproj/project.pbxproj +4 -0
- data/platform/shared/common/RhoMutexLock.h +8 -1
- data/platform/shared/common/RhodesApp.cpp +1 -1
- data/platform/shared/db/DBAdapter.cpp +77 -8
- data/platform/shared/db/DBAdapter.h +24 -9
- data/platform/shared/db/DBResult.cpp +19 -0
- data/platform/shared/db/DBResult.h +7 -5
- data/platform/shared/net/HttpServer.cpp +2 -0
- data/platform/shared/ruby/ext/rho/rhoruby.c +55 -0
- data/platform/shared/ruby/ext/rho/rhoruby.h +9 -0
- data/platform/shared/ruby/ext/rho/rhosupport.c +13 -4
- data/platform/shared/ruby/ext/sqlite3_api/sqlite3_api_wrap.c +21 -0
- data/platform/shared/ruby/thread_pthread.c +4 -4
- data/platform/shared/ruby/thread_win32.c +4 -4
- data/platform/shared/rubyJVM/src/com/rho/RhodesApp.java +19 -1
- data/platform/shared/rubyJVM/src/com/rho/db/DBAdapter.java +57 -24
- data/platform/shared/rubyJVM/src/com/rho/net/NetRequest.java +6 -1
- data/platform/shared/rubyJVM/src/com/rho/sync/SyncSource.java +2 -2
- data/platform/shared/rubyJVM/src/com/rho/sync/SyncThread.java +5 -5
- data/platform/shared/sync/SyncSource.cpp +1 -1
- data/platform/shared/sync/SyncThread.cpp +6 -9
- data/platform/wm/rhodes/Rhodes.cpp +4 -0
- data/rakefile.rb +1 -1
- metadata +13 -3
- data/platform/bb/rhodes/src/rhomobile/Alert.java +0 -65
@@ -0,0 +1,198 @@
|
|
1
|
+
#
|
2
|
+
# = uri/ftp.rb
|
3
|
+
#
|
4
|
+
# Author:: Akira Yamada <akira@ruby-lang.org>
|
5
|
+
# License:: You can redistribute it and/or modify it under the same term as Ruby.
|
6
|
+
# Revision:: $Id: ftp.rb 11708 2007-02-12 23:01:19Z shyouhei $
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'uri/generic'
|
10
|
+
|
11
|
+
module URI
|
12
|
+
|
13
|
+
#
|
14
|
+
# FTP URI syntax is defined by RFC1738 section 3.2.
|
15
|
+
#
|
16
|
+
class FTP < Generic
|
17
|
+
DEFAULT_PORT = 21
|
18
|
+
|
19
|
+
COMPONENT = [
|
20
|
+
:scheme,
|
21
|
+
:userinfo, :host, :port,
|
22
|
+
:path, :typecode
|
23
|
+
].freeze
|
24
|
+
#
|
25
|
+
# Typecode is "a", "i" or "d".
|
26
|
+
#
|
27
|
+
# * "a" indicates a text file (the FTP command was ASCII)
|
28
|
+
# * "i" indicates a binary file (FTP command IMAGE)
|
29
|
+
# * "d" indicates the contents of a directory should be displayed
|
30
|
+
#
|
31
|
+
TYPECODE = ['a', 'i', 'd'].freeze
|
32
|
+
TYPECODE_PREFIX = ';type='.freeze
|
33
|
+
|
34
|
+
def self.new2(user, password, host, port, path,
|
35
|
+
typecode = nil, arg_check = true)
|
36
|
+
typecode = nil if typecode.size == 0
|
37
|
+
if typecode && !TYPECODE.include?(typecode)
|
38
|
+
raise ArgumentError,
|
39
|
+
"bad typecode is specified: #{typecode}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# do escape
|
43
|
+
|
44
|
+
self.new('ftp',
|
45
|
+
[user, password],
|
46
|
+
host, port, nil,
|
47
|
+
typecode ? path + TYPECODE_PREFIX + typecode : path,
|
48
|
+
nil, nil, nil, arg_check)
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# == Description
|
53
|
+
#
|
54
|
+
# Creates a new URI::FTP object from components, with syntax checking.
|
55
|
+
#
|
56
|
+
# The components accepted are +userinfo+, +host+, +port+, +path+ and
|
57
|
+
# +typecode+.
|
58
|
+
#
|
59
|
+
# The components should be provided either as an Array, or as a Hash
|
60
|
+
# with keys formed by preceding the component names with a colon.
|
61
|
+
#
|
62
|
+
# If an Array is used, the components must be passed in the order
|
63
|
+
# [userinfo, host, port, path, typecode]
|
64
|
+
#
|
65
|
+
# If the path supplied is absolute, it will be escaped in order to
|
66
|
+
# make it absolute in the URI. Examples:
|
67
|
+
#
|
68
|
+
# require 'uri'
|
69
|
+
#
|
70
|
+
# uri = URI::FTP.build(['user:password', 'ftp.example.com', nil,
|
71
|
+
# '/path/file.> zip', 'i'])
|
72
|
+
# puts uri.to_s -> ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=a
|
73
|
+
#
|
74
|
+
# uri2 = URI::FTP.build({:host => 'ftp.example.com',
|
75
|
+
# :path => 'ruby/src'})
|
76
|
+
# puts uri2.to_s -> ftp://ftp.example.com/ruby/src
|
77
|
+
#
|
78
|
+
def self.build(args)
|
79
|
+
|
80
|
+
# Fix the incoming path to be generic URL syntax
|
81
|
+
# FTP path -> URL path
|
82
|
+
# foo/bar /foo/bar
|
83
|
+
# /foo/bar /%2Ffoo/bar
|
84
|
+
#
|
85
|
+
if args.kind_of?(Array)
|
86
|
+
args[3] = '/' + args[3].sub(/^\//, '%2F')
|
87
|
+
else
|
88
|
+
args[:path] = '/' + args[:path].sub(/^\//, '%2F')
|
89
|
+
end
|
90
|
+
|
91
|
+
tmp = Util::make_components_hash(self, args)
|
92
|
+
|
93
|
+
if tmp[:typecode]
|
94
|
+
if tmp[:typecode].size == 1
|
95
|
+
tmp[:typecode] = TYPECODE_PREFIX + tmp[:typecode]
|
96
|
+
end
|
97
|
+
tmp[:path] << tmp[:typecode]
|
98
|
+
end
|
99
|
+
|
100
|
+
return super(tmp)
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# == Description
|
105
|
+
#
|
106
|
+
# Creates a new URI::FTP object from generic URL components with no
|
107
|
+
# syntax checking.
|
108
|
+
#
|
109
|
+
# Unlike build(), this method does not escape the path component as
|
110
|
+
# required by RFC1738; instead it is treated as per RFC2396.
|
111
|
+
#
|
112
|
+
# Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
|
113
|
+
# +opaque+, +query+ and +fragment+, in that order.
|
114
|
+
#
|
115
|
+
def initialize(*arg)
|
116
|
+
super(*arg)
|
117
|
+
@typecode = nil
|
118
|
+
tmp = @path.index(TYPECODE_PREFIX)
|
119
|
+
if tmp
|
120
|
+
typecode = @path[tmp + TYPECODE_PREFIX.size..-1]
|
121
|
+
self.set_path(@path[0..tmp - 1])
|
122
|
+
|
123
|
+
if arg[-1]
|
124
|
+
self.typecode = typecode
|
125
|
+
else
|
126
|
+
self.set_typecode(typecode)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
attr_reader :typecode
|
131
|
+
|
132
|
+
def check_typecode(v)
|
133
|
+
if TYPECODE.include?(v)
|
134
|
+
return true
|
135
|
+
else
|
136
|
+
raise InvalidComponentError,
|
137
|
+
"bad typecode(expected #{TYPECODE.join(', ')}): #{v}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
private :check_typecode
|
141
|
+
|
142
|
+
def set_typecode(v)
|
143
|
+
@typecode = v
|
144
|
+
end
|
145
|
+
protected :set_typecode
|
146
|
+
|
147
|
+
def typecode=(typecode)
|
148
|
+
check_typecode(typecode)
|
149
|
+
set_typecode(typecode)
|
150
|
+
typecode
|
151
|
+
end
|
152
|
+
|
153
|
+
def merge(oth) # :nodoc:
|
154
|
+
tmp = super(oth)
|
155
|
+
if self != tmp
|
156
|
+
tmp.set_typecode(oth.typecode)
|
157
|
+
end
|
158
|
+
|
159
|
+
return tmp
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns the path from an FTP URI.
|
163
|
+
#
|
164
|
+
# RFC 1738 specifically states that the path for an FTP URI does not
|
165
|
+
# include the / which separates the URI path from the URI host. Example:
|
166
|
+
#
|
167
|
+
# ftp://ftp.example.com/pub/ruby
|
168
|
+
#
|
169
|
+
# The above URI indicates that the client should connect to
|
170
|
+
# ftp.example.com then cd pub/ruby from the initial login directory.
|
171
|
+
#
|
172
|
+
# If you want to cd to an absolute directory, you must include an
|
173
|
+
# escaped / (%2F) in the path. Example:
|
174
|
+
#
|
175
|
+
# ftp://ftp.example.com/%2Fpub/ruby
|
176
|
+
#
|
177
|
+
# This method will then return "/pub/ruby"
|
178
|
+
#
|
179
|
+
def path
|
180
|
+
return @path.sub(/^\//,'').sub(/^%2F/,'/')
|
181
|
+
end
|
182
|
+
|
183
|
+
def to_s
|
184
|
+
save_path = nil
|
185
|
+
if @typecode
|
186
|
+
save_path = @path
|
187
|
+
@path = @path + TYPECODE_PREFIX + @typecode
|
188
|
+
end
|
189
|
+
str = super
|
190
|
+
if @typecode
|
191
|
+
@path = save_path
|
192
|
+
end
|
193
|
+
|
194
|
+
return str
|
195
|
+
end
|
196
|
+
end
|
197
|
+
@@schemes['FTP'] = FTP
|
198
|
+
end
|
@@ -0,0 +1,1128 @@
|
|
1
|
+
#
|
2
|
+
# = uri/generic.rb
|
3
|
+
#
|
4
|
+
# Author:: Akira Yamada <akira@ruby-lang.org>
|
5
|
+
# License:: You can redistribute it and/or modify it under the same term as Ruby.
|
6
|
+
# Revision:: $Id: generic.rb 20258 2008-11-18 16:46:16Z yugui $
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'uri/common'
|
10
|
+
|
11
|
+
module URI
|
12
|
+
|
13
|
+
#
|
14
|
+
# Base class for all URI classes.
|
15
|
+
# Implements generic URI syntax as per RFC 2396.
|
16
|
+
#
|
17
|
+
class Generic
|
18
|
+
include URI
|
19
|
+
|
20
|
+
DEFAULT_PORT = nil
|
21
|
+
|
22
|
+
#
|
23
|
+
# Returns default port
|
24
|
+
#
|
25
|
+
def self.default_port
|
26
|
+
self::DEFAULT_PORT
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_port
|
30
|
+
self.class.default_port
|
31
|
+
end
|
32
|
+
|
33
|
+
COMPONENT = [
|
34
|
+
:scheme,
|
35
|
+
:userinfo, :host, :port, :registry,
|
36
|
+
:path, :opaque,
|
37
|
+
:query,
|
38
|
+
:fragment
|
39
|
+
].freeze
|
40
|
+
|
41
|
+
#
|
42
|
+
# Components of the URI in the order.
|
43
|
+
#
|
44
|
+
def self.component
|
45
|
+
self::COMPONENT
|
46
|
+
end
|
47
|
+
|
48
|
+
USE_REGISTRY = false
|
49
|
+
|
50
|
+
#
|
51
|
+
# DOC: FIXME!
|
52
|
+
#
|
53
|
+
def self.use_registry
|
54
|
+
self::USE_REGISTRY
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# == Synopsis
|
59
|
+
#
|
60
|
+
# See #new
|
61
|
+
#
|
62
|
+
# == Description
|
63
|
+
#
|
64
|
+
# At first, tries to create a new URI::Generic instance using
|
65
|
+
# URI::Generic::build. But, if exception URI::InvalidComponentError is raised,
|
66
|
+
# then it URI::Escape.escape all URI components and tries again.
|
67
|
+
#
|
68
|
+
#
|
69
|
+
def self.build2(args)
|
70
|
+
begin
|
71
|
+
return self.build(args)
|
72
|
+
rescue InvalidComponentError
|
73
|
+
if args.kind_of?(Array)
|
74
|
+
return self.build(args.collect{|x|
|
75
|
+
if x
|
76
|
+
@parser.escape(x)
|
77
|
+
else
|
78
|
+
x
|
79
|
+
end
|
80
|
+
})
|
81
|
+
elsif args.kind_of?(Hash)
|
82
|
+
tmp = {}
|
83
|
+
args.each do |key, value|
|
84
|
+
tmp[key] = if value
|
85
|
+
@parser.escape(value)
|
86
|
+
else
|
87
|
+
value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
return self.build(tmp)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# == Synopsis
|
97
|
+
#
|
98
|
+
# See #new
|
99
|
+
#
|
100
|
+
# == Description
|
101
|
+
#
|
102
|
+
# Creates a new URI::Generic instance from components of URI::Generic
|
103
|
+
# with check. Components are: scheme, userinfo, host, port, registry, path,
|
104
|
+
# opaque, query and fragment. You can provide arguments either by an Array or a Hash.
|
105
|
+
# See #new for hash keys to use or for order of array items.
|
106
|
+
#
|
107
|
+
def self.build(args)
|
108
|
+
if args.kind_of?(Array) &&
|
109
|
+
args.size == ::URI::Generic::COMPONENT.size
|
110
|
+
tmp = args
|
111
|
+
elsif args.kind_of?(Hash)
|
112
|
+
tmp = ::URI::Generic::COMPONENT.collect do |c|
|
113
|
+
if args.include?(c)
|
114
|
+
args[c]
|
115
|
+
else
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
else
|
120
|
+
raise ArgumentError,
|
121
|
+
"expected Array of or Hash of components of #{self.class} (#{self.class.component.join(', ')})"
|
122
|
+
end
|
123
|
+
|
124
|
+
tmp << DEFAULT_PARSER
|
125
|
+
tmp << true
|
126
|
+
return self.new(*tmp)
|
127
|
+
end
|
128
|
+
#
|
129
|
+
# == Args
|
130
|
+
#
|
131
|
+
# +scheme+::
|
132
|
+
# Protocol scheme, i.e. 'http','ftp','mailto' and so on.
|
133
|
+
# +userinfo+::
|
134
|
+
# User name and password, i.e. 'sdmitry:bla'
|
135
|
+
# +host+::
|
136
|
+
# Server host name
|
137
|
+
# +port+::
|
138
|
+
# Server port
|
139
|
+
# +registry+::
|
140
|
+
# DOC: FIXME!
|
141
|
+
# +path+::
|
142
|
+
# Path on server
|
143
|
+
# +opaque+::
|
144
|
+
# DOC: FIXME!
|
145
|
+
# +query+::
|
146
|
+
# Query data
|
147
|
+
# +fragment+::
|
148
|
+
# A part of URI after '#' sign
|
149
|
+
# +parser+::
|
150
|
+
# Parser for internal use [URI::DEFAULT_PARSER by default]
|
151
|
+
# +arg_check+::
|
152
|
+
# Check arguments [false by default]
|
153
|
+
#
|
154
|
+
# == Description
|
155
|
+
#
|
156
|
+
# Creates a new URI::Generic instance from ``generic'' components without check.
|
157
|
+
#
|
158
|
+
def initialize(scheme,
|
159
|
+
userinfo, host, port, registry,
|
160
|
+
path, opaque,
|
161
|
+
query,
|
162
|
+
fragment,
|
163
|
+
parser = DEFAULT_PARSER,
|
164
|
+
arg_check = false)
|
165
|
+
@scheme = nil
|
166
|
+
@user = nil
|
167
|
+
@password = nil
|
168
|
+
@host = nil
|
169
|
+
@port = nil
|
170
|
+
@path = nil
|
171
|
+
@query = nil
|
172
|
+
@opaque = nil
|
173
|
+
@registry = nil
|
174
|
+
@fragment = nil
|
175
|
+
@parser = parser
|
176
|
+
|
177
|
+
if arg_check
|
178
|
+
self.scheme = scheme
|
179
|
+
self.userinfo = userinfo
|
180
|
+
self.host = host
|
181
|
+
self.port = port
|
182
|
+
self.path = path
|
183
|
+
self.query = query
|
184
|
+
self.opaque = opaque
|
185
|
+
self.registry = registry
|
186
|
+
self.fragment = fragment
|
187
|
+
else
|
188
|
+
self.set_scheme(scheme)
|
189
|
+
self.set_userinfo(userinfo)
|
190
|
+
self.set_host(host)
|
191
|
+
self.set_port(port)
|
192
|
+
self.set_path(path)
|
193
|
+
self.set_query(query)
|
194
|
+
self.set_opaque(opaque)
|
195
|
+
self.set_registry(registry)
|
196
|
+
self.set_fragment(fragment)
|
197
|
+
end
|
198
|
+
if @registry && !self.class.use_registry
|
199
|
+
raise InvalidURIError,
|
200
|
+
"the scheme #{@scheme} does not accept registry part: #{@registry} (or bad hostname?)"
|
201
|
+
end
|
202
|
+
|
203
|
+
@scheme.freeze if @scheme
|
204
|
+
self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2)
|
205
|
+
self.set_port(self.default_port) if self.default_port && !@port
|
206
|
+
end
|
207
|
+
attr_reader :scheme
|
208
|
+
attr_reader :host
|
209
|
+
attr_reader :port
|
210
|
+
attr_reader :registry
|
211
|
+
attr_reader :path
|
212
|
+
attr_reader :query
|
213
|
+
attr_reader :opaque
|
214
|
+
attr_reader :fragment
|
215
|
+
attr_reader :parser
|
216
|
+
|
217
|
+
# replace self by other URI object
|
218
|
+
def replace!(oth)
|
219
|
+
if self.class != oth.class
|
220
|
+
raise ArgumentError, "expected #{self.class} object"
|
221
|
+
end
|
222
|
+
|
223
|
+
component.each do |c|
|
224
|
+
self.__send__("#{c}=", oth.__send__(c))
|
225
|
+
end
|
226
|
+
end
|
227
|
+
private :replace!
|
228
|
+
|
229
|
+
def component
|
230
|
+
self.class.component
|
231
|
+
end
|
232
|
+
|
233
|
+
def check_scheme(v)
|
234
|
+
if v && @parser.regexp[:SCHEME] !~ v
|
235
|
+
raise InvalidComponentError,
|
236
|
+
"bad component(expected scheme component): #{v}"
|
237
|
+
end
|
238
|
+
|
239
|
+
return true
|
240
|
+
end
|
241
|
+
private :check_scheme
|
242
|
+
|
243
|
+
def set_scheme(v)
|
244
|
+
@scheme = v
|
245
|
+
end
|
246
|
+
protected :set_scheme
|
247
|
+
|
248
|
+
def scheme=(v)
|
249
|
+
check_scheme(v)
|
250
|
+
set_scheme(v)
|
251
|
+
v
|
252
|
+
end
|
253
|
+
|
254
|
+
def check_userinfo(user, password = nil)
|
255
|
+
if !password
|
256
|
+
user, password = split_userinfo(user)
|
257
|
+
end
|
258
|
+
check_user(user)
|
259
|
+
check_password(password, user)
|
260
|
+
|
261
|
+
return true
|
262
|
+
end
|
263
|
+
private :check_userinfo
|
264
|
+
|
265
|
+
def check_user(v)
|
266
|
+
if @registry || @opaque
|
267
|
+
raise InvalidURIError,
|
268
|
+
"can not set user with registry or opaque"
|
269
|
+
end
|
270
|
+
|
271
|
+
return v unless v
|
272
|
+
|
273
|
+
if @parser.regexp[: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, user = @user)
|
283
|
+
if @registry || @opaque
|
284
|
+
raise InvalidURIError,
|
285
|
+
"can not set password with registry or opaque"
|
286
|
+
end
|
287
|
+
return v unless v
|
288
|
+
|
289
|
+
if !user
|
290
|
+
raise InvalidURIError,
|
291
|
+
"password component depends user component"
|
292
|
+
end
|
293
|
+
|
294
|
+
if @parser.regexp[:USERINFO] !~ v
|
295
|
+
raise InvalidComponentError,
|
296
|
+
"bad component(expected user component): #{v}"
|
297
|
+
end
|
298
|
+
|
299
|
+
return true
|
300
|
+
end
|
301
|
+
private :check_password
|
302
|
+
|
303
|
+
#
|
304
|
+
# Sets userinfo, argument is string like 'name:pass'
|
305
|
+
#
|
306
|
+
def userinfo=(userinfo)
|
307
|
+
if userinfo.nil?
|
308
|
+
return nil
|
309
|
+
end
|
310
|
+
check_userinfo(*userinfo)
|
311
|
+
set_userinfo(*userinfo)
|
312
|
+
# returns userinfo
|
313
|
+
end
|
314
|
+
|
315
|
+
def user=(user)
|
316
|
+
check_user(user)
|
317
|
+
set_user(user)
|
318
|
+
# returns user
|
319
|
+
end
|
320
|
+
|
321
|
+
def password=(password)
|
322
|
+
check_password(password)
|
323
|
+
set_password(password)
|
324
|
+
# returns password
|
325
|
+
end
|
326
|
+
|
327
|
+
def set_userinfo(user, password = nil)
|
328
|
+
unless password
|
329
|
+
user, password = split_userinfo(user)
|
330
|
+
end
|
331
|
+
@user = user
|
332
|
+
@password = password if password
|
333
|
+
|
334
|
+
[@user, @password]
|
335
|
+
end
|
336
|
+
protected :set_userinfo
|
337
|
+
|
338
|
+
def set_user(v)
|
339
|
+
set_userinfo(v, @password)
|
340
|
+
v
|
341
|
+
end
|
342
|
+
protected :set_user
|
343
|
+
|
344
|
+
def set_password(v)
|
345
|
+
@password = v
|
346
|
+
# returns v
|
347
|
+
end
|
348
|
+
protected :set_password
|
349
|
+
|
350
|
+
def split_userinfo(ui)
|
351
|
+
return nil, nil unless ui
|
352
|
+
user, password = ui.split(/:/, 2)
|
353
|
+
|
354
|
+
return user, password
|
355
|
+
end
|
356
|
+
private :split_userinfo
|
357
|
+
|
358
|
+
def escape_userpass(v)
|
359
|
+
v = @parser.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/
|
360
|
+
end
|
361
|
+
private :escape_userpass
|
362
|
+
|
363
|
+
def userinfo
|
364
|
+
if @user.nil?
|
365
|
+
nil
|
366
|
+
elsif @password.nil?
|
367
|
+
@user
|
368
|
+
else
|
369
|
+
@user + ':' + @password
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def user
|
374
|
+
@user
|
375
|
+
end
|
376
|
+
|
377
|
+
def password
|
378
|
+
@password
|
379
|
+
end
|
380
|
+
|
381
|
+
def check_host(v)
|
382
|
+
return v unless v
|
383
|
+
|
384
|
+
if @registry || @opaque
|
385
|
+
raise InvalidURIError,
|
386
|
+
"can not set host with registry or opaque"
|
387
|
+
elsif @parser.regexp[:HOST] !~ v
|
388
|
+
raise InvalidComponentError,
|
389
|
+
"bad component(expected host component): #{v}"
|
390
|
+
end
|
391
|
+
|
392
|
+
return true
|
393
|
+
end
|
394
|
+
private :check_host
|
395
|
+
|
396
|
+
def set_host(v)
|
397
|
+
@host = v
|
398
|
+
end
|
399
|
+
protected :set_host
|
400
|
+
|
401
|
+
def host=(v)
|
402
|
+
check_host(v)
|
403
|
+
set_host(v)
|
404
|
+
v
|
405
|
+
end
|
406
|
+
|
407
|
+
def check_port(v)
|
408
|
+
return v unless v
|
409
|
+
|
410
|
+
if @registry || @opaque
|
411
|
+
raise InvalidURIError,
|
412
|
+
"can not set port with registry or opaque"
|
413
|
+
elsif !v.kind_of?(Fixnum) && @parser.regexp[:PORT] !~ v
|
414
|
+
raise InvalidComponentError,
|
415
|
+
"bad component(expected port component): #{v}"
|
416
|
+
end
|
417
|
+
|
418
|
+
return true
|
419
|
+
end
|
420
|
+
private :check_port
|
421
|
+
|
422
|
+
def set_port(v)
|
423
|
+
unless !v || v.kind_of?(Fixnum)
|
424
|
+
if v.empty?
|
425
|
+
v = nil
|
426
|
+
else
|
427
|
+
v = v.to_i
|
428
|
+
end
|
429
|
+
end
|
430
|
+
@port = v
|
431
|
+
end
|
432
|
+
protected :set_port
|
433
|
+
|
434
|
+
def port=(v)
|
435
|
+
check_port(v)
|
436
|
+
set_port(v)
|
437
|
+
port
|
438
|
+
end
|
439
|
+
|
440
|
+
def check_registry(v)
|
441
|
+
return v unless v
|
442
|
+
|
443
|
+
# raise if both server and registry are not nil, because:
|
444
|
+
# authority = server | reg_name
|
445
|
+
# server = [ [ userinfo "@" ] hostport ]
|
446
|
+
if @host || @port || @user # userinfo = @user + ':' + @password
|
447
|
+
raise InvalidURIError,
|
448
|
+
"can not set registry with host, port, or userinfo"
|
449
|
+
elsif v && @parser.regexp[:REGISTRY] !~ v
|
450
|
+
raise InvalidComponentError,
|
451
|
+
"bad component(expected registry component): #{v}"
|
452
|
+
end
|
453
|
+
|
454
|
+
return true
|
455
|
+
end
|
456
|
+
private :check_registry
|
457
|
+
|
458
|
+
def set_registry(v)
|
459
|
+
@registry = v
|
460
|
+
end
|
461
|
+
protected :set_registry
|
462
|
+
|
463
|
+
def registry=(v)
|
464
|
+
check_registry(v)
|
465
|
+
set_registry(v)
|
466
|
+
v
|
467
|
+
end
|
468
|
+
|
469
|
+
def check_path(v)
|
470
|
+
# raise if both hier and opaque are not nil, because:
|
471
|
+
# absoluteURI = scheme ":" ( hier_part | opaque_part )
|
472
|
+
# hier_part = ( net_path | abs_path ) [ "?" query ]
|
473
|
+
if v && @opaque
|
474
|
+
raise InvalidURIError,
|
475
|
+
"path conflicts with opaque"
|
476
|
+
end
|
477
|
+
|
478
|
+
if @scheme
|
479
|
+
if v && v != '' && @parser.regexp[:ABS_PATH] !~ v
|
480
|
+
raise InvalidComponentError,
|
481
|
+
"bad component(expected absolute path component): #{v}"
|
482
|
+
end
|
483
|
+
else
|
484
|
+
if v && v != '' && @parser.regexp[:ABS_PATH] !~ v && @parser.regexp[:REL_PATH] !~ v
|
485
|
+
raise InvalidComponentError,
|
486
|
+
"bad component(expected relative path component): #{v}"
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
return true
|
491
|
+
end
|
492
|
+
private :check_path
|
493
|
+
|
494
|
+
def set_path(v)
|
495
|
+
@path = v
|
496
|
+
end
|
497
|
+
protected :set_path
|
498
|
+
|
499
|
+
def path=(v)
|
500
|
+
check_path(v)
|
501
|
+
set_path(v)
|
502
|
+
v
|
503
|
+
end
|
504
|
+
|
505
|
+
def check_query(v)
|
506
|
+
return v unless v
|
507
|
+
|
508
|
+
# raise if both hier and opaque are not nil, because:
|
509
|
+
# absoluteURI = scheme ":" ( hier_part | opaque_part )
|
510
|
+
# hier_part = ( net_path | abs_path ) [ "?" query ]
|
511
|
+
if @opaque
|
512
|
+
raise InvalidURIError,
|
513
|
+
"query conflicts with opaque"
|
514
|
+
end
|
515
|
+
|
516
|
+
if v && v != '' && @parser.regexp[:QUERY] !~ v
|
517
|
+
raise InvalidComponentError,
|
518
|
+
"bad component(expected query component): #{v}"
|
519
|
+
end
|
520
|
+
|
521
|
+
return true
|
522
|
+
end
|
523
|
+
private :check_query
|
524
|
+
|
525
|
+
def set_query(v)
|
526
|
+
@query = v
|
527
|
+
end
|
528
|
+
protected :set_query
|
529
|
+
|
530
|
+
def query=(v)
|
531
|
+
check_query(v)
|
532
|
+
set_query(v)
|
533
|
+
v
|
534
|
+
end
|
535
|
+
|
536
|
+
def check_opaque(v)
|
537
|
+
return v unless v
|
538
|
+
|
539
|
+
# raise if both hier and opaque are not nil, because:
|
540
|
+
# absoluteURI = scheme ":" ( hier_part | opaque_part )
|
541
|
+
# hier_part = ( net_path | abs_path ) [ "?" query ]
|
542
|
+
if @host || @port || @user || @path # userinfo = @user + ':' + @password
|
543
|
+
raise InvalidURIError,
|
544
|
+
"can not set opaque with host, port, userinfo or path"
|
545
|
+
elsif v && @parser.regexp[:OPAQUE] !~ v
|
546
|
+
raise InvalidComponentError,
|
547
|
+
"bad component(expected opaque component): #{v}"
|
548
|
+
end
|
549
|
+
|
550
|
+
return true
|
551
|
+
end
|
552
|
+
private :check_opaque
|
553
|
+
|
554
|
+
def set_opaque(v)
|
555
|
+
@opaque = v
|
556
|
+
end
|
557
|
+
protected :set_opaque
|
558
|
+
|
559
|
+
def opaque=(v)
|
560
|
+
check_opaque(v)
|
561
|
+
set_opaque(v)
|
562
|
+
v
|
563
|
+
end
|
564
|
+
|
565
|
+
def check_fragment(v)
|
566
|
+
return v unless v
|
567
|
+
|
568
|
+
if v && v != '' && @parser.regexp[:FRAGMENT] !~ v
|
569
|
+
raise InvalidComponentError,
|
570
|
+
"bad component(expected fragment component): #{v}"
|
571
|
+
end
|
572
|
+
|
573
|
+
return true
|
574
|
+
end
|
575
|
+
private :check_fragment
|
576
|
+
|
577
|
+
def set_fragment(v)
|
578
|
+
@fragment = v
|
579
|
+
end
|
580
|
+
protected :set_fragment
|
581
|
+
|
582
|
+
def fragment=(v)
|
583
|
+
check_fragment(v)
|
584
|
+
set_fragment(v)
|
585
|
+
v
|
586
|
+
end
|
587
|
+
|
588
|
+
#
|
589
|
+
# Checks if URI has a path
|
590
|
+
#
|
591
|
+
def hierarchical?
|
592
|
+
if @path
|
593
|
+
true
|
594
|
+
else
|
595
|
+
false
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
#
|
600
|
+
# Checks if URI is an absolute one
|
601
|
+
#
|
602
|
+
def absolute?
|
603
|
+
if @scheme
|
604
|
+
true
|
605
|
+
else
|
606
|
+
false
|
607
|
+
end
|
608
|
+
end
|
609
|
+
alias absolute absolute?
|
610
|
+
|
611
|
+
#
|
612
|
+
# Checks if URI is relative
|
613
|
+
#
|
614
|
+
def relative?
|
615
|
+
!absolute?
|
616
|
+
end
|
617
|
+
|
618
|
+
def split_path(path)
|
619
|
+
path.split(%r{/+}, -1)
|
620
|
+
end
|
621
|
+
private :split_path
|
622
|
+
|
623
|
+
def merge_path(base, rel)
|
624
|
+
|
625
|
+
# RFC2396, Section 5.2, 5)
|
626
|
+
# RFC2396, Section 5.2, 6)
|
627
|
+
base_path = split_path(base)
|
628
|
+
rel_path = split_path(rel)
|
629
|
+
|
630
|
+
# RFC2396, Section 5.2, 6), a)
|
631
|
+
base_path << '' if base_path.last == '..'
|
632
|
+
while i = base_path.index('..')
|
633
|
+
base_path.slice!(i - 1, 2)
|
634
|
+
end
|
635
|
+
|
636
|
+
if (first = rel_path.first) and first.empty?
|
637
|
+
base_path.clear
|
638
|
+
rel_path.shift
|
639
|
+
end
|
640
|
+
|
641
|
+
# RFC2396, Section 5.2, 6), c)
|
642
|
+
# RFC2396, Section 5.2, 6), d)
|
643
|
+
rel_path.push('') if rel_path.last == '.' || rel_path.last == '..'
|
644
|
+
rel_path.delete('.')
|
645
|
+
|
646
|
+
# RFC2396, Section 5.2, 6), e)
|
647
|
+
tmp = []
|
648
|
+
rel_path.each do |x|
|
649
|
+
if x == '..' &&
|
650
|
+
!(tmp.empty? || tmp.last == '..')
|
651
|
+
tmp.pop
|
652
|
+
else
|
653
|
+
tmp << x
|
654
|
+
end
|
655
|
+
end
|
656
|
+
|
657
|
+
add_trailer_slash = !tmp.empty?
|
658
|
+
if base_path.empty?
|
659
|
+
base_path = [''] # keep '/' for root directory
|
660
|
+
elsif add_trailer_slash
|
661
|
+
base_path.pop
|
662
|
+
end
|
663
|
+
while x = tmp.shift
|
664
|
+
if x == '..'
|
665
|
+
# RFC2396, Section 4
|
666
|
+
# a .. or . in an absolute path has no special meaning
|
667
|
+
base_path.pop if base_path.size > 1
|
668
|
+
else
|
669
|
+
# if x == '..'
|
670
|
+
# valid absolute (but abnormal) path "/../..."
|
671
|
+
# else
|
672
|
+
# valid absolute path
|
673
|
+
# end
|
674
|
+
base_path << x
|
675
|
+
tmp.each {|t| base_path << t}
|
676
|
+
add_trailer_slash = false
|
677
|
+
break
|
678
|
+
end
|
679
|
+
end
|
680
|
+
base_path.push('') if add_trailer_slash
|
681
|
+
|
682
|
+
return base_path.join('/')
|
683
|
+
end
|
684
|
+
private :merge_path
|
685
|
+
|
686
|
+
#
|
687
|
+
# == Args
|
688
|
+
#
|
689
|
+
# +oth+::
|
690
|
+
# URI or String
|
691
|
+
#
|
692
|
+
# == Description
|
693
|
+
#
|
694
|
+
# Destructive form of #merge
|
695
|
+
#
|
696
|
+
# == Usage
|
697
|
+
#
|
698
|
+
# require 'uri'
|
699
|
+
#
|
700
|
+
# uri = URI.parse("http://my.example.com")
|
701
|
+
# uri.merge!("/main.rbx?page=1")
|
702
|
+
# p uri
|
703
|
+
# # => #<URI::HTTP:0x2021f3b0 URL:http://my.example.com/main.rbx?page=1>
|
704
|
+
#
|
705
|
+
def merge!(oth)
|
706
|
+
t = merge(oth)
|
707
|
+
if self == t
|
708
|
+
nil
|
709
|
+
else
|
710
|
+
replace!(t)
|
711
|
+
self
|
712
|
+
end
|
713
|
+
end
|
714
|
+
|
715
|
+
#
|
716
|
+
# == Args
|
717
|
+
#
|
718
|
+
# +oth+::
|
719
|
+
# URI or String
|
720
|
+
#
|
721
|
+
# == Description
|
722
|
+
#
|
723
|
+
# Merges two URI's.
|
724
|
+
#
|
725
|
+
# == Usage
|
726
|
+
#
|
727
|
+
# require 'uri'
|
728
|
+
#
|
729
|
+
# uri = URI.parse("http://my.example.com")
|
730
|
+
# p uri.merge("/main.rbx?page=1")
|
731
|
+
# # => #<URI::HTTP:0x2021f3b0 URL:http://my.example.com/main.rbx?page=1>
|
732
|
+
#
|
733
|
+
def merge(oth)
|
734
|
+
begin
|
735
|
+
base, rel = merge0(oth)
|
736
|
+
rescue
|
737
|
+
raise $!.class, $!.message
|
738
|
+
end
|
739
|
+
|
740
|
+
if base == rel
|
741
|
+
return base
|
742
|
+
end
|
743
|
+
|
744
|
+
authority = rel.userinfo || rel.host || rel.port
|
745
|
+
|
746
|
+
# RFC2396, Section 5.2, 2)
|
747
|
+
if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
|
748
|
+
base.set_fragment(rel.fragment) if rel.fragment
|
749
|
+
return base
|
750
|
+
end
|
751
|
+
|
752
|
+
base.set_query(nil)
|
753
|
+
base.set_fragment(nil)
|
754
|
+
|
755
|
+
# RFC2396, Section 5.2, 4)
|
756
|
+
if !authority
|
757
|
+
base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path
|
758
|
+
else
|
759
|
+
# RFC2396, Section 5.2, 4)
|
760
|
+
base.set_path(rel.path) if rel.path
|
761
|
+
end
|
762
|
+
|
763
|
+
# RFC2396, Section 5.2, 7)
|
764
|
+
base.set_userinfo(rel.userinfo) if rel.userinfo
|
765
|
+
base.set_host(rel.host) if rel.host
|
766
|
+
base.set_port(rel.port) if rel.port
|
767
|
+
base.set_query(rel.query) if rel.query
|
768
|
+
base.set_fragment(rel.fragment) if rel.fragment
|
769
|
+
|
770
|
+
return base
|
771
|
+
end # merge
|
772
|
+
alias + merge
|
773
|
+
|
774
|
+
# return base and rel.
|
775
|
+
# you can modify `base', but can not `rel'.
|
776
|
+
def merge0(oth)
|
777
|
+
case oth
|
778
|
+
when Generic
|
779
|
+
when String
|
780
|
+
oth = @parser.parse(oth)
|
781
|
+
else
|
782
|
+
raise ArgumentError,
|
783
|
+
"bad argument(expected URI object or URI string)"
|
784
|
+
end
|
785
|
+
|
786
|
+
if self.relative? && oth.relative?
|
787
|
+
raise BadURIError,
|
788
|
+
"both URI are relative"
|
789
|
+
end
|
790
|
+
|
791
|
+
if self.absolute? && oth.absolute?
|
792
|
+
#raise BadURIError,
|
793
|
+
# "both URI are absolute"
|
794
|
+
# hmm... should return oth for usability?
|
795
|
+
return oth, oth
|
796
|
+
end
|
797
|
+
|
798
|
+
if self.absolute?
|
799
|
+
return self.dup, oth
|
800
|
+
else
|
801
|
+
return oth, oth
|
802
|
+
end
|
803
|
+
end
|
804
|
+
private :merge0
|
805
|
+
|
806
|
+
def route_from_path(src, dst)
|
807
|
+
# RFC2396, Section 4.2
|
808
|
+
return '' if src == dst
|
809
|
+
|
810
|
+
src_path = split_path(src)
|
811
|
+
dst_path = split_path(dst)
|
812
|
+
|
813
|
+
# hmm... dst has abnormal absolute path,
|
814
|
+
# like "/./", "/../", "/x/../", ...
|
815
|
+
if dst_path.include?('..') ||
|
816
|
+
dst_path.include?('.')
|
817
|
+
return dst.dup
|
818
|
+
end
|
819
|
+
|
820
|
+
src_path.pop
|
821
|
+
|
822
|
+
# discard same parts
|
823
|
+
while dst_path.first == src_path.first
|
824
|
+
break if dst_path.empty?
|
825
|
+
|
826
|
+
src_path.shift
|
827
|
+
dst_path.shift
|
828
|
+
end
|
829
|
+
|
830
|
+
tmp = dst_path.join('/')
|
831
|
+
|
832
|
+
# calculate
|
833
|
+
if src_path.empty?
|
834
|
+
if tmp.empty?
|
835
|
+
return './'
|
836
|
+
elsif dst_path.first.include?(':') # (see RFC2396 Section 5)
|
837
|
+
return './' + tmp
|
838
|
+
else
|
839
|
+
return tmp
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
return '../' * src_path.size + tmp
|
844
|
+
end
|
845
|
+
private :route_from_path
|
846
|
+
|
847
|
+
def route_from0(oth)
|
848
|
+
case oth
|
849
|
+
when Generic
|
850
|
+
when String
|
851
|
+
oth = @parser.parse(oth)
|
852
|
+
else
|
853
|
+
raise ArgumentError,
|
854
|
+
"bad argument(expected URI object or URI string)"
|
855
|
+
end
|
856
|
+
|
857
|
+
if self.relative?
|
858
|
+
raise BadURIError,
|
859
|
+
"relative URI: #{self}"
|
860
|
+
end
|
861
|
+
if oth.relative?
|
862
|
+
raise BadURIError,
|
863
|
+
"relative URI: #{oth}"
|
864
|
+
end
|
865
|
+
|
866
|
+
if self.scheme != oth.scheme
|
867
|
+
return self, self.dup
|
868
|
+
end
|
869
|
+
rel = URI::Generic.new(nil, # it is relative URI
|
870
|
+
self.userinfo, self.host, self.port,
|
871
|
+
self.registry, self.path, self.opaque,
|
872
|
+
self.query, self.fragment, @parser)
|
873
|
+
|
874
|
+
if rel.userinfo != oth.userinfo ||
|
875
|
+
rel.host.to_s.downcase != oth.host.to_s.downcase ||
|
876
|
+
rel.port != oth.port
|
877
|
+
if self.userinfo.nil? && self.host.nil?
|
878
|
+
return self, self.dup
|
879
|
+
end
|
880
|
+
rel.set_port(nil) if rel.port == oth.default_port
|
881
|
+
return rel, rel
|
882
|
+
end
|
883
|
+
rel.set_userinfo(nil)
|
884
|
+
rel.set_host(nil)
|
885
|
+
rel.set_port(nil)
|
886
|
+
|
887
|
+
if rel.path && rel.path == oth.path
|
888
|
+
rel.set_path('')
|
889
|
+
rel.set_query(nil) if rel.query == oth.query
|
890
|
+
return rel, rel
|
891
|
+
elsif rel.opaque && rel.opaque == oth.opaque
|
892
|
+
rel.set_opaque('')
|
893
|
+
rel.set_query(nil) if rel.query == oth.query
|
894
|
+
return rel, rel
|
895
|
+
end
|
896
|
+
|
897
|
+
# you can modify `rel', but can not `oth'.
|
898
|
+
return oth, rel
|
899
|
+
end
|
900
|
+
private :route_from0
|
901
|
+
#
|
902
|
+
# == Args
|
903
|
+
#
|
904
|
+
# +oth+::
|
905
|
+
# URI or String
|
906
|
+
#
|
907
|
+
# == Description
|
908
|
+
#
|
909
|
+
# Calculates relative path from oth to self
|
910
|
+
#
|
911
|
+
# == Usage
|
912
|
+
#
|
913
|
+
# require 'uri'
|
914
|
+
#
|
915
|
+
# uri = URI.parse('http://my.example.com/main.rbx?page=1')
|
916
|
+
# p uri.route_from('http://my.example.com')
|
917
|
+
# #=> #<URI::Generic:0x20218858 URL:/main.rbx?page=1>
|
918
|
+
#
|
919
|
+
def route_from(oth)
|
920
|
+
# you can modify `rel', but can not `oth'.
|
921
|
+
begin
|
922
|
+
oth, rel = route_from0(oth)
|
923
|
+
rescue
|
924
|
+
raise $!.class, $!.message
|
925
|
+
end
|
926
|
+
if oth == rel
|
927
|
+
return rel
|
928
|
+
end
|
929
|
+
|
930
|
+
rel.set_path(route_from_path(oth.path, self.path))
|
931
|
+
if rel.path == './' && self.query
|
932
|
+
# "./?foo" -> "?foo"
|
933
|
+
rel.set_path('')
|
934
|
+
end
|
935
|
+
|
936
|
+
return rel
|
937
|
+
end
|
938
|
+
|
939
|
+
alias - route_from
|
940
|
+
|
941
|
+
#
|
942
|
+
# == Args
|
943
|
+
#
|
944
|
+
# +oth+::
|
945
|
+
# URI or String
|
946
|
+
#
|
947
|
+
# == Description
|
948
|
+
#
|
949
|
+
# Calculates relative path to oth from self
|
950
|
+
#
|
951
|
+
# == Usage
|
952
|
+
#
|
953
|
+
# require 'uri'
|
954
|
+
#
|
955
|
+
# uri = URI.parse('http://my.example.com')
|
956
|
+
# p uri.route_to('http://my.example.com/main.rbx?page=1')
|
957
|
+
# #=> #<URI::Generic:0x2020c2f6 URL:/main.rbx?page=1>
|
958
|
+
#
|
959
|
+
def route_to(oth)
|
960
|
+
case oth
|
961
|
+
when Generic
|
962
|
+
when String
|
963
|
+
oth = @parser.parse(oth)
|
964
|
+
else
|
965
|
+
raise ArgumentError,
|
966
|
+
"bad argument(expected URI object or URI string)"
|
967
|
+
end
|
968
|
+
|
969
|
+
oth.route_from(self)
|
970
|
+
end
|
971
|
+
|
972
|
+
#
|
973
|
+
# Returns normalized URI
|
974
|
+
#
|
975
|
+
def normalize
|
976
|
+
uri = dup
|
977
|
+
uri.normalize!
|
978
|
+
uri
|
979
|
+
end
|
980
|
+
|
981
|
+
#
|
982
|
+
# Destructive version of #normalize
|
983
|
+
#
|
984
|
+
def normalize!
|
985
|
+
if path && path == ''
|
986
|
+
set_path('/')
|
987
|
+
end
|
988
|
+
if host && host != host.downcase
|
989
|
+
set_host(self.host.downcase)
|
990
|
+
end
|
991
|
+
end
|
992
|
+
|
993
|
+
def path_query
|
994
|
+
str = @path
|
995
|
+
if @query
|
996
|
+
str += '?' + @query
|
997
|
+
end
|
998
|
+
str
|
999
|
+
end
|
1000
|
+
private :path_query
|
1001
|
+
|
1002
|
+
#
|
1003
|
+
# Constructs String from URI
|
1004
|
+
#
|
1005
|
+
def to_s
|
1006
|
+
str = ''
|
1007
|
+
if @scheme
|
1008
|
+
str << @scheme
|
1009
|
+
str << ':'
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
if @opaque
|
1013
|
+
str << @opaque
|
1014
|
+
|
1015
|
+
else
|
1016
|
+
if @registry
|
1017
|
+
str << @registry
|
1018
|
+
else
|
1019
|
+
if @host
|
1020
|
+
str << '//'
|
1021
|
+
end
|
1022
|
+
if self.userinfo
|
1023
|
+
str << self.userinfo
|
1024
|
+
str << '@'
|
1025
|
+
end
|
1026
|
+
if @host
|
1027
|
+
str << @host
|
1028
|
+
end
|
1029
|
+
if @port && @port != self.default_port
|
1030
|
+
str << ':'
|
1031
|
+
str << @port.to_s
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
str << path_query
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
if @fragment
|
1039
|
+
str << '#'
|
1040
|
+
str << @fragment
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
str
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
#
|
1047
|
+
# Compares to URI's
|
1048
|
+
#
|
1049
|
+
def ==(oth)
|
1050
|
+
if self.class == oth.class
|
1051
|
+
self.normalize.component_ary == oth.normalize.component_ary
|
1052
|
+
else
|
1053
|
+
false
|
1054
|
+
end
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def hash
|
1058
|
+
self.component_ary.hash
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
def eql?(oth)
|
1062
|
+
@parser == oth.parser &&
|
1063
|
+
self.component_ary.eql?(oth.component_ary)
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
=begin
|
1067
|
+
|
1068
|
+
--- URI::Generic#===(oth)
|
1069
|
+
|
1070
|
+
=end
|
1071
|
+
# def ===(oth)
|
1072
|
+
# raise NotImplementedError
|
1073
|
+
# end
|
1074
|
+
|
1075
|
+
=begin
|
1076
|
+
=end
|
1077
|
+
def component_ary
|
1078
|
+
component.collect do |x|
|
1079
|
+
self.send(x)
|
1080
|
+
end
|
1081
|
+
end
|
1082
|
+
protected :component_ary
|
1083
|
+
|
1084
|
+
# == Args
|
1085
|
+
#
|
1086
|
+
# +components+::
|
1087
|
+
# Multiple Symbol arguments defined in URI::HTTP
|
1088
|
+
#
|
1089
|
+
# == Description
|
1090
|
+
#
|
1091
|
+
# Selects specified components from URI
|
1092
|
+
#
|
1093
|
+
# == Usage
|
1094
|
+
#
|
1095
|
+
# require 'uri'
|
1096
|
+
#
|
1097
|
+
# uri = URI.parse('http://myuser:mypass@my.example.com/test.rbx')
|
1098
|
+
# p uri.select(:userinfo, :host, :path)
|
1099
|
+
# # => ["myuser:mypass", "my.example.com", "/test.rbx"]
|
1100
|
+
#
|
1101
|
+
def select(*components)
|
1102
|
+
components.collect do |c|
|
1103
|
+
if component.include?(c)
|
1104
|
+
self.send(c)
|
1105
|
+
else
|
1106
|
+
raise ArgumentError,
|
1107
|
+
"expected of components of #{self.class} (#{self.class.component.join(', ')})"
|
1108
|
+
end
|
1109
|
+
end
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
@@to_s = Kernel.instance_method(:to_s)
|
1113
|
+
def inspect
|
1114
|
+
@@to_s.bind(self).call.sub!(/>\z/) {" URL:#{self}>"}
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
def coerce(oth)
|
1118
|
+
case oth
|
1119
|
+
when String
|
1120
|
+
oth = @parser.parse(oth)
|
1121
|
+
else
|
1122
|
+
super
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
return oth, self
|
1126
|
+
end
|
1127
|
+
end
|
1128
|
+
end
|