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.
Files changed (60) hide show
  1. data/Manifest.txt +11 -1
  2. data/Rakefile +1 -1
  3. data/lib/extensions/digest/ext/Rakefile +11 -6
  4. data/lib/extensions/digest/ext/build.bat +2 -0
  5. data/lib/extensions/uri/uri.rb +29 -0
  6. data/lib/extensions/uri/uri/common.rb +727 -0
  7. data/lib/extensions/uri/uri/ftp.rb +198 -0
  8. data/lib/extensions/uri/uri/generic.rb +1128 -0
  9. data/lib/extensions/uri/uri/http.rb +100 -0
  10. data/lib/extensions/uri/uri/https.rb +20 -0
  11. data/lib/extensions/uri/uri/ldap.rb +190 -0
  12. data/lib/extensions/uri/uri/ldaps.rb +12 -0
  13. data/lib/extensions/uri/uri/mailto.rb +266 -0
  14. data/lib/framework/rhodes.rb +2 -2
  15. data/lib/framework/rhom/rhom_db_adapter.rb +12 -26
  16. data/lib/framework/rhom/rhom_object_factory.rb +8 -1
  17. data/lib/framework/version.rb +2 -2
  18. data/lib/rhodes.rb +2 -2
  19. data/platform/android/Rhodes/AndroidManifest.xml +2 -2
  20. data/platform/android/Rhodes/src/com/rhomobile/rhodes/Rhodes.java +87 -42
  21. data/platform/android/Rhodes/src/com/rhomobile/rhodes/SplashScreen.java +58 -7
  22. data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/MainView.java +2 -0
  23. data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/SimpleMainView.java +35 -19
  24. data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/TabbedMainView.java +4 -0
  25. data/platform/android/build/android.rake +30 -25
  26. data/platform/bb/build/rhodes_build.files +1 -1
  27. data/platform/bb/rhodes/rhodes.jdp +1 -1
  28. data/platform/bb/rhodes/src/com/rho/RhoRubyHelper.java +1 -1
  29. data/platform/bb/rhodes/src/com/rho/rubyext/Alert.java +300 -0
  30. data/platform/bb/rhodes/src/com/rho/rubyext/GeoLocation.java +42 -5
  31. data/platform/bb/rhodes/src/rhomobile/PushListeningThread.java +3 -4
  32. data/platform/bb/rhodes/src/rhomobile/RhodesApplication.java +33 -107
  33. data/platform/iphone/Classes/RhoRunnerAppDelegate.m +2 -0
  34. data/platform/iphone/Info.plist +1 -1
  35. data/platform/iphone/rbuild/iphone.rake +1 -1
  36. data/platform/iphone/rhoextlib/rhoextlib.xcodeproj/project.pbxproj +4 -0
  37. data/platform/shared/common/RhoMutexLock.h +8 -1
  38. data/platform/shared/common/RhodesApp.cpp +1 -1
  39. data/platform/shared/db/DBAdapter.cpp +77 -8
  40. data/platform/shared/db/DBAdapter.h +24 -9
  41. data/platform/shared/db/DBResult.cpp +19 -0
  42. data/platform/shared/db/DBResult.h +7 -5
  43. data/platform/shared/net/HttpServer.cpp +2 -0
  44. data/platform/shared/ruby/ext/rho/rhoruby.c +55 -0
  45. data/platform/shared/ruby/ext/rho/rhoruby.h +9 -0
  46. data/platform/shared/ruby/ext/rho/rhosupport.c +13 -4
  47. data/platform/shared/ruby/ext/sqlite3_api/sqlite3_api_wrap.c +21 -0
  48. data/platform/shared/ruby/thread_pthread.c +4 -4
  49. data/platform/shared/ruby/thread_win32.c +4 -4
  50. data/platform/shared/rubyJVM/src/com/rho/RhodesApp.java +19 -1
  51. data/platform/shared/rubyJVM/src/com/rho/db/DBAdapter.java +57 -24
  52. data/platform/shared/rubyJVM/src/com/rho/net/NetRequest.java +6 -1
  53. data/platform/shared/rubyJVM/src/com/rho/sync/SyncSource.java +2 -2
  54. data/platform/shared/rubyJVM/src/com/rho/sync/SyncThread.java +5 -5
  55. data/platform/shared/sync/SyncSource.cpp +1 -1
  56. data/platform/shared/sync/SyncThread.cpp +6 -9
  57. data/platform/wm/rhodes/Rhodes.cpp +4 -0
  58. data/rakefile.rb +1 -1
  59. metadata +13 -3
  60. 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