uri 0.12.2 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e148d563fe056a564cbc9165907417c7ace215e889313648ef7188978de6967b
4
- data.tar.gz: 641d48d8ea5501344b72db29beb2799acf7ffb8711c0b472b31b1cafa670365f
3
+ metadata.gz: 8f4eaea3d45b9a860a4a1765dfa211d195929e01ea90e2ff25405fea90948098
4
+ data.tar.gz: 5f962ae3a2b0c56f589df823edf89560420d8c2dced50ac7332e5a6322a772bc
5
5
  SHA512:
6
- metadata.gz: 63b7b63b2e1d5a141ae795a628b838bfce9ee31a0d1dbcd8b8d693e776f15195a649f17d16c227f6a1f91dcc45026c499706de5fca14f9a2dc7fea2fa08f9eb4
7
- data.tar.gz: 2fbf672737a8b1dc3ab33cd1edec06469ec0691c9c30ee23907e9811c1a263ac27293f659440050a5802bd3e1950891a75695e5b29ecc1a90a45515a4c0f5b5e
6
+ metadata.gz: 8fb0be9745374a552f34d58d834e206adabc9a81bfc15bc7179c4143b639f0f62dd73ab46637023147e10be72b61ffdb2b18ac32a697d185244026a51560dc54
7
+ data.tar.gz: 6961a3339bfa178cd339a14828cbb4be6d79249fc1d262da0ea7d68095435efe801ef71642866ab0de2e7a5edc759a168e8b54a006f038e446d755c9781dbf49
@@ -0,0 +1,46 @@
1
+ name: Deploy RDoc site to Pages
2
+
3
+ on:
4
+ push:
5
+ branches: [ 'master' ]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: "pages"
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Checkout
22
+ uses: actions/checkout@v4
23
+ - name: Setup Ruby
24
+ uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 # v1.152.0
25
+ with:
26
+ ruby-version: '3.2'
27
+ bundler-cache: true
28
+ - name: Setup Pages
29
+ id: pages
30
+ uses: actions/configure-pages@v3
31
+ - name: Build with RDoc
32
+ # Outputs to the './_site' directory by default
33
+ run: bundle exec rake rdoc
34
+ - name: Upload artifact
35
+ uses: actions/upload-pages-artifact@v2
36
+
37
+ deploy:
38
+ environment:
39
+ name: github-pages
40
+ url: ${{ steps.deployment.outputs.page_url }}
41
+ runs-on: ubuntu-latest
42
+ needs: build
43
+ steps:
44
+ - name: Deploy to GitHub Pages
45
+ id: deployment
46
+ uses: actions/deploy-pages@v2
@@ -3,15 +3,21 @@ name: CI
3
3
  on: [push, pull_request]
4
4
 
5
5
  jobs:
6
+ ruby-versions:
7
+ uses: ruby/actions/.github/workflows/ruby_versions.yml@master
8
+ with:
9
+ min_version: 2.5
10
+
6
11
  build:
12
+ needs: ruby-versions
7
13
  name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
14
  strategy:
9
15
  matrix:
10
- ruby: [ 3.1, '3.0', 2.7, 2.6, 2.5, 2.4, head, truffleruby ]
16
+ ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
11
17
  os: [ ubuntu-latest, macos-latest ]
12
18
  runs-on: ${{ matrix.os }}
13
19
  steps:
14
- - uses: actions/checkout@v3
20
+ - uses: actions/checkout@v4
15
21
  - name: Set up Ruby
16
22
  uses: ruby/setup-ruby@v1
17
23
  with:
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  Gemfile.lock
10
+ /_site
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # URI
2
2
 
3
3
  [![CI](https://github.com/ruby/uri/actions/workflows/test.yml/badge.svg)](https://github.com/ruby/uri/actions/workflows/test.yml)
4
+ [![Yard Docs](https://img.shields.io/badge/docs-exist-blue.svg)](https://ruby.github.io/uri/)
4
5
 
5
6
  URI is a module providing classes to handle Uniform Resource Identifiers [RFC2396](http://tools.ietf.org/html/rfc2396).
6
7
 
data/Rakefile CHANGED
@@ -7,11 +7,12 @@ Rake::TestTask.new(:test) do |t|
7
7
  t.test_files = FileList["test/**/test_*.rb"]
8
8
  end
9
9
 
10
- task :sync_tool do
11
- require 'fileutils'
12
- FileUtils.cp "../ruby/tool/lib/test/unit/core_assertions.rb", "./test/lib"
13
- FileUtils.cp "../ruby/tool/lib/envutil.rb", "./test/lib"
14
- FileUtils.cp "../ruby/tool/lib/find_executable.rb", "./test/lib"
10
+ require "rdoc/task"
11
+ RDoc::Task.new do |doc|
12
+ doc.main = "README.md"
13
+ doc.title = "URI - handle Uniform Resource Identifiers"
14
+ doc.rdoc_files = FileList.new %w[lib README.md LICENSE.txt]
15
+ doc.rdoc_dir = "_site" # for github pages
15
16
  end
16
17
 
17
18
  task :default => :test
data/lib/uri/common.rb CHANGED
@@ -68,16 +68,32 @@ module URI
68
68
  end
69
69
  private_constant :Schemes
70
70
 
71
+ # Registers the given +klass+ as the class to be instantiated
72
+ # when parsing a \URI with the given +scheme+:
71
73
  #
72
- # Register the given +klass+ to be instantiated when parsing URLs with the given +scheme+.
73
- # Note that currently only schemes which after .upcase are valid constant names
74
- # can be registered (no -/+/. allowed).
74
+ # URI.register_scheme('MS_SEARCH', URI::Generic) # => URI::Generic
75
+ # URI.scheme_list['MS_SEARCH'] # => URI::Generic
75
76
  #
77
+ # Note that after calling String#upcase on +scheme+, it must be a valid
78
+ # constant name.
76
79
  def self.register_scheme(scheme, klass)
77
80
  Schemes.const_set(scheme.to_s.upcase, klass)
78
81
  end
79
82
 
80
- # Returns a Hash of the defined schemes.
83
+ # Returns a hash of the defined schemes:
84
+ #
85
+ # URI.scheme_list
86
+ # # =>
87
+ # {"MAILTO"=>URI::MailTo,
88
+ # "LDAPS"=>URI::LDAPS,
89
+ # "WS"=>URI::WS,
90
+ # "HTTP"=>URI::HTTP,
91
+ # "HTTPS"=>URI::HTTPS,
92
+ # "LDAP"=>URI::LDAP,
93
+ # "FILE"=>URI::File,
94
+ # "FTP"=>URI::FTP}
95
+ #
96
+ # Related: URI.register_scheme.
81
97
  def self.scheme_list
82
98
  Schemes.constants.map { |name|
83
99
  [name.to_s.upcase, Schemes.const_get(name)]
@@ -88,9 +104,21 @@ module URI
88
104
  private_constant :INITIAL_SCHEMES
89
105
  Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
90
106
 
107
+ # Returns a new object constructed from the given +scheme+, +arguments+,
108
+ # and +default+:
109
+ #
110
+ # - The new object is an instance of <tt>URI.scheme_list[scheme.upcase]</tt>.
111
+ # - The object is initialized by calling the class initializer
112
+ # using +scheme+ and +arguments+.
113
+ # See URI::Generic.new.
114
+ #
115
+ # Examples:
91
116
  #
92
- # Construct a URI instance, using the scheme to detect the appropriate class
93
- # from +URI.scheme_list+.
117
+ # values = ['john.doe', 'www.example.com', '123', nil, '/forum/questions/', nil, 'tag=networking&order=newest', 'top']
118
+ # URI.for('https', *values)
119
+ # # => #<URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
120
+ # URI.for('foo', *values, default: URI::HTTP)
121
+ # # => #<URI::HTTP foo://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
94
122
  #
95
123
  def self.for(scheme, *arguments, default: Generic)
96
124
  const_name = scheme.to_s.upcase
@@ -121,95 +149,49 @@ module URI
121
149
  #
122
150
  class BadURIError < Error; end
123
151
 
124
- #
125
- # == Synopsis
126
- #
127
- # URI::split(uri)
128
- #
129
- # == Args
130
- #
131
- # +uri+::
132
- # String with URI.
133
- #
134
- # == Description
135
- #
136
- # Splits the string on following parts and returns array with result:
137
- #
138
- # * Scheme
139
- # * Userinfo
140
- # * Host
141
- # * Port
142
- # * Registry
143
- # * Path
144
- # * Opaque
145
- # * Query
146
- # * Fragment
147
- #
148
- # == Usage
149
- #
150
- # require 'uri'
151
- #
152
- # URI.split("http://www.ruby-lang.org/")
153
- # # => ["http", nil, "www.ruby-lang.org", nil, nil, "/", nil, nil, nil]
152
+ # Returns a 9-element array representing the parts of the \URI
153
+ # formed from the string +uri+;
154
+ # each array element is a string or +nil+:
155
+ #
156
+ # names = %w[scheme userinfo host port registry path opaque query fragment]
157
+ # values = URI.split('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
158
+ # names.zip(values)
159
+ # # =>
160
+ # [["scheme", "https"],
161
+ # ["userinfo", "john.doe"],
162
+ # ["host", "www.example.com"],
163
+ # ["port", "123"],
164
+ # ["registry", nil],
165
+ # ["path", "/forum/questions/"],
166
+ # ["opaque", nil],
167
+ # ["query", "tag=networking&order=newest"],
168
+ # ["fragment", "top"]]
154
169
  #
155
170
  def self.split(uri)
156
171
  RFC3986_PARSER.split(uri)
157
172
  end
158
173
 
174
+ # Returns a new \URI object constructed from the given string +uri+:
159
175
  #
160
- # == Synopsis
161
- #
162
- # URI::parse(uri_str)
163
- #
164
- # == Args
165
- #
166
- # +uri_str+::
167
- # String with URI.
168
- #
169
- # == Description
170
- #
171
- # Creates one of the URI's subclasses instance from the string.
172
- #
173
- # == Raises
174
- #
175
- # URI::InvalidURIError::
176
- # Raised if URI given is not a correct one.
176
+ # URI.parse('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
177
+ # # => #<URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
178
+ # URI.parse('http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
179
+ # # => #<URI::HTTP http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
177
180
  #
178
- # == Usage
179
- #
180
- # require 'uri'
181
- #
182
- # uri = URI.parse("http://www.ruby-lang.org/")
183
- # # => #<URI::HTTP http://www.ruby-lang.org/>
184
- # uri.scheme
185
- # # => "http"
186
- # uri.host
187
- # # => "www.ruby-lang.org"
188
- #
189
- # It's recommended to first ::escape the provided +uri_str+ if there are any
190
- # invalid URI characters.
181
+ # It's recommended to first ::escape string +uri+
182
+ # if it may contain invalid URI characters.
191
183
  #
192
184
  def self.parse(uri)
193
185
  RFC3986_PARSER.parse(uri)
194
186
  end
195
187
 
188
+ # Merges the given URI strings +str+
189
+ # per {RFC 2396}[https://www.rfc-editor.org/rfc/rfc2396.html].
196
190
  #
197
- # == Synopsis
198
- #
199
- # URI::join(str[, str, ...])
191
+ # Each string in +str+ is converted to an
192
+ # {RFC3986 URI}[https://www.rfc-editor.org/rfc/rfc3986.html] before being merged.
200
193
  #
201
- # == Args
202
- #
203
- # +str+::
204
- # String(s) to work with, will be converted to RFC3986 URIs before merging.
205
- #
206
- # == Description
207
- #
208
- # Joins URIs.
209
- #
210
- # == Usage
211
- #
212
- # require 'uri'
194
+ # Examples:
213
195
  #
214
196
  # URI.join("http://example.com/","main.rbx")
215
197
  # # => #<URI::HTTP http://example.com/main.rbx>
@@ -254,7 +236,7 @@ module URI
254
236
  # URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.")
255
237
  # # => ["http://foo.example.com/bla", "mailto:test@example.com"]
256
238
  #
257
- def self.extract(str, schemes = nil, &block)
239
+ def self.extract(str, schemes = nil, &block) # :nodoc:
258
240
  warn "URI.extract is obsolete", uplevel: 1 if $VERBOSE
259
241
  DEFAULT_PARSER.extract(str, schemes, &block)
260
242
  end
@@ -291,7 +273,7 @@ module URI
291
273
  # p $&
292
274
  # end
293
275
  #
294
- def self.regexp(schemes = nil)
276
+ def self.regexp(schemes = nil)# :nodoc:
295
277
  warn "URI.regexp is obsolete", uplevel: 1 if $VERBOSE
296
278
  DEFAULT_PARSER.make_regexp(schemes)
297
279
  end
@@ -314,40 +296,86 @@ module URI
314
296
  TBLDECWWWCOMP_['+'] = ' '
315
297
  TBLDECWWWCOMP_.freeze
316
298
 
317
- # Encodes given +str+ to URL-encoded form data.
299
+ # Returns a URL-encoded string derived from the given string +str+.
300
+ #
301
+ # The returned string:
302
+ #
303
+ # - Preserves:
304
+ #
305
+ # - Characters <tt>'*'</tt>, <tt>'.'</tt>, <tt>'-'</tt>, and <tt>'_'</tt>.
306
+ # - Character in ranges <tt>'a'..'z'</tt>, <tt>'A'..'Z'</tt>,
307
+ # and <tt>'0'..'9'</tt>.
308
+ #
309
+ # Example:
318
310
  #
319
- # This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP
320
- # (ASCII space) to + and converts others to %XX.
311
+ # URI.encode_www_form_component('*.-_azAZ09')
312
+ # # => "*.-_azAZ09"
321
313
  #
322
- # If +enc+ is given, convert +str+ to the encoding before percent encoding.
314
+ # - Converts:
323
315
  #
324
- # This is an implementation of
325
- # https://www.w3.org/TR/2013/CR-html5-20130806/forms.html#url-encoded-form-data.
316
+ # - Character <tt>' '</tt> to character <tt>'+'</tt>.
317
+ # - Any other character to "percent notation";
318
+ # the percent notation for character <i>c</i> is <tt>'%%%X' % c.ord</tt>.
326
319
  #
327
- # See URI.decode_www_form_component, URI.encode_www_form.
320
+ # Example:
321
+ #
322
+ # URI.encode_www_form_component('Here are some punctuation characters: ,;?:')
323
+ # # => "Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A"
324
+ #
325
+ # Encoding:
326
+ #
327
+ # - If +str+ has encoding Encoding::ASCII_8BIT, argument +enc+ is ignored.
328
+ # - Otherwise +str+ is converted first to Encoding::UTF_8
329
+ # (with suitable character replacements),
330
+ # and then to encoding +enc+.
331
+ #
332
+ # In either case, the returned string has forced encoding Encoding::US_ASCII.
333
+ #
334
+ # Related: URI.encode_uri_component (encodes <tt>' '</tt> as <tt>'%20'</tt>).
328
335
  def self.encode_www_form_component(str, enc=nil)
329
336
  _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_, str, enc)
330
337
  end
331
338
 
332
- # Decodes given +str+ of URL-encoded form data.
339
+ # Returns a string decoded from the given \URL-encoded string +str+.
340
+ #
341
+ # The given string is first encoded as Encoding::ASCII-8BIT (using String#b),
342
+ # then decoded (as below), and finally force-encoded to the given encoding +enc+.
343
+ #
344
+ # The returned string:
345
+ #
346
+ # - Preserves:
347
+ #
348
+ # - Characters <tt>'*'</tt>, <tt>'.'</tt>, <tt>'-'</tt>, and <tt>'_'</tt>.
349
+ # - Character in ranges <tt>'a'..'z'</tt>, <tt>'A'..'Z'</tt>,
350
+ # and <tt>'0'..'9'</tt>.
351
+ #
352
+ # Example:
353
+ #
354
+ # URI.decode_www_form_component('*.-_azAZ09')
355
+ # # => "*.-_azAZ09"
356
+ #
357
+ # - Converts:
358
+ #
359
+ # - Character <tt>'+'</tt> to character <tt>' '</tt>.
360
+ # - Each "percent notation" to an ASCII character.
333
361
  #
334
- # This decodes + to SP.
362
+ # Example:
335
363
  #
336
- # See URI.encode_www_form_component, URI.decode_www_form.
364
+ # URI.decode_www_form_component('Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A')
365
+ # # => "Here are some punctuation characters: ,;?:"
366
+ #
367
+ # Related: URI.decode_uri_component (preserves <tt>'+'</tt>).
337
368
  def self.decode_www_form_component(str, enc=Encoding::UTF_8)
338
369
  _decode_uri_component(/\+|%\h\h/, str, enc)
339
370
  end
340
371
 
341
- # Encodes +str+ using URL encoding
342
- #
343
- # This encodes SP to %20 instead of +.
372
+ # Like URI.encode_www_form_component, except that <tt>' '</tt> (space)
373
+ # is encoded as <tt>'%20'</tt> (instead of <tt>'+'</tt>).
344
374
  def self.encode_uri_component(str, enc=nil)
345
375
  _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCURICOMP_, str, enc)
346
376
  end
347
377
 
348
- # Decodes given +str+ of URL-encoded data.
349
- #
350
- # This does not decode + to SP.
378
+ # Like URI.decode_www_form_component, except that <tt>'+'</tt> is preserved.
351
379
  def self.decode_uri_component(str, enc=Encoding::UTF_8)
352
380
  _decode_uri_component(/%\h\h/, str, enc)
353
381
  end
@@ -372,33 +400,104 @@ module URI
372
400
  end
373
401
  private_class_method :_decode_uri_component
374
402
 
375
- # Generates URL-encoded form data from given +enum+.
403
+ # Returns a URL-encoded string derived from the given
404
+ # {Enumerable}[https://docs.ruby-lang.org/en/master/Enumerable.html#module-Enumerable-label-Enumerable+in+Ruby+Classes]
405
+ # +enum+.
406
+ #
407
+ # The result is suitable for use as form data
408
+ # for an \HTTP request whose <tt>Content-Type</tt> is
409
+ # <tt>'application/x-www-form-urlencoded'</tt>.
410
+ #
411
+ # The returned string consists of the elements of +enum+,
412
+ # each converted to one or more URL-encoded strings,
413
+ # and all joined with character <tt>'&'</tt>.
414
+ #
415
+ # Simple examples:
416
+ #
417
+ # URI.encode_www_form([['foo', 0], ['bar', 1], ['baz', 2]])
418
+ # # => "foo=0&bar=1&baz=2"
419
+ # URI.encode_www_form({foo: 0, bar: 1, baz: 2})
420
+ # # => "foo=0&bar=1&baz=2"
421
+ #
422
+ # The returned string is formed using method URI.encode_www_form_component,
423
+ # which converts certain characters:
424
+ #
425
+ # URI.encode_www_form('f#o': '/', 'b-r': '$', 'b z': '@')
426
+ # # => "f%23o=%2F&b-r=%24&b+z=%40"
427
+ #
428
+ # When +enum+ is Array-like, each element +ele+ is converted to a field:
429
+ #
430
+ # - If +ele+ is an array of two or more elements,
431
+ # the field is formed from its first two elements
432
+ # (and any additional elements are ignored):
433
+ #
434
+ # name = URI.encode_www_form_component(ele[0], enc)
435
+ # value = URI.encode_www_form_component(ele[1], enc)
436
+ # "#{name}=#{value}"
376
437
  #
377
- # This generates application/x-www-form-urlencoded data defined in HTML5
378
- # from given an Enumerable object.
438
+ # Examples:
379
439
  #
380
- # This internally uses URI.encode_www_form_component(str).
440
+ # URI.encode_www_form([%w[foo bar], %w[baz bat bah]])
441
+ # # => "foo=bar&baz=bat"
442
+ # URI.encode_www_form([['foo', 0], ['bar', :baz, 'bat']])
443
+ # # => "foo=0&bar=baz"
381
444
  #
382
- # This method doesn't convert the encoding of given items, so convert them
383
- # before calling this method if you want to send data as other than original
384
- # encoding or mixed encoding data. (Strings which are encoded in an HTML5
385
- # ASCII incompatible encoding are converted to UTF-8.)
445
+ # - If +ele+ is an array of one element,
446
+ # the field is formed from <tt>ele[0]</tt>:
386
447
  #
387
- # This method doesn't handle files. When you send a file, use
388
- # multipart/form-data.
448
+ # URI.encode_www_form_component(ele[0])
389
449
  #
390
- # This refers https://url.spec.whatwg.org/#concept-urlencoded-serializer
450
+ # Example:
391
451
  #
392
- # URI.encode_www_form([["q", "ruby"], ["lang", "en"]])
393
- # #=> "q=ruby&lang=en"
394
- # URI.encode_www_form("q" => "ruby", "lang" => "en")
395
- # #=> "q=ruby&lang=en"
396
- # URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en")
397
- # #=> "q=ruby&q=perl&lang=en"
398
- # URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]])
399
- # #=> "q=ruby&q=perl&lang=en"
452
+ # URI.encode_www_form([['foo'], [:bar], [0]])
453
+ # # => "foo&bar&0"
454
+ #
455
+ # - Otherwise the field is formed from +ele+:
456
+ #
457
+ # URI.encode_www_form_component(ele)
458
+ #
459
+ # Example:
460
+ #
461
+ # URI.encode_www_form(['foo', :bar, 0])
462
+ # # => "foo&bar&0"
463
+ #
464
+ # The elements of an Array-like +enum+ may be mixture:
465
+ #
466
+ # URI.encode_www_form([['foo', 0], ['bar', 1, 2], ['baz'], :bat])
467
+ # # => "foo=0&bar=1&baz&bat"
468
+ #
469
+ # When +enum+ is Hash-like,
470
+ # each +key+/+value+ pair is converted to one or more fields:
471
+ #
472
+ # - If +value+ is
473
+ # {Array-convertible}[https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html#label-Array-Convertible+Objects],
474
+ # each element +ele+ in +value+ is paired with +key+ to form a field:
475
+ #
476
+ # name = URI.encode_www_form_component(key, enc)
477
+ # value = URI.encode_www_form_component(ele, enc)
478
+ # "#{name}=#{value}"
479
+ #
480
+ # Example:
481
+ #
482
+ # URI.encode_www_form({foo: [:bar, 1], baz: [:bat, :bam, 2]})
483
+ # # => "foo=bar&foo=1&baz=bat&baz=bam&baz=2"
484
+ #
485
+ # - Otherwise, +key+ and +value+ are paired to form a field:
486
+ #
487
+ # name = URI.encode_www_form_component(key, enc)
488
+ # value = URI.encode_www_form_component(value, enc)
489
+ # "#{name}=#{value}"
490
+ #
491
+ # Example:
492
+ #
493
+ # URI.encode_www_form({foo: 0, bar: 1, baz: 2})
494
+ # # => "foo=0&bar=1&baz=2"
495
+ #
496
+ # The elements of a Hash-like +enum+ may be mixture:
497
+ #
498
+ # URI.encode_www_form({foo: [0, 1], bar: 2})
499
+ # # => "foo=0&foo=1&bar=2"
400
500
  #
401
- # See URI.encode_www_form_component, URI.decode_www_form.
402
501
  def self.encode_www_form(enum, enc=nil)
403
502
  enum.map do |k,v|
404
503
  if v.nil?
@@ -419,22 +518,39 @@ module URI
419
518
  end.join('&')
420
519
  end
421
520
 
422
- # Decodes URL-encoded form data from given +str+.
521
+ # Returns name/value pairs derived from the given string +str+,
522
+ # which must be an ASCII string.
523
+ #
524
+ # The method may be used to decode the body of Net::HTTPResponse object +res+
525
+ # for which <tt>res['Content-Type']</tt> is <tt>'application/x-www-form-urlencoded'</tt>.
526
+ #
527
+ # The returned data is an array of 2-element subarrays;
528
+ # each subarray is a name/value pair (both are strings).
529
+ # Each returned string has encoding +enc+,
530
+ # and has had invalid characters removed via
531
+ # {String#scrub}[https://docs.ruby-lang.org/en/master/String.html#method-i-scrub].
423
532
  #
424
- # This decodes application/x-www-form-urlencoded data
425
- # and returns an array of key-value arrays.
533
+ # A simple example:
426
534
  #
427
- # This refers http://url.spec.whatwg.org/#concept-urlencoded-parser,
428
- # so this supports only &-separator, and doesn't support ;-separator.
535
+ # URI.decode_www_form('foo=0&bar=1&baz')
536
+ # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
429
537
  #
430
- # ary = URI.decode_www_form("a=1&a=2&b=3")
431
- # ary #=> [['a', '1'], ['a', '2'], ['b', '3']]
432
- # ary.assoc('a').last #=> '1'
433
- # ary.assoc('b').last #=> '3'
434
- # ary.rassoc('a').last #=> '2'
435
- # Hash[ary] #=> {"a"=>"2", "b"=>"3"}
538
+ # The returned strings have certain conversions,
539
+ # similar to those performed in URI.decode_www_form_component:
540
+ #
541
+ # URI.decode_www_form('f%23o=%2F&b-r=%24&b+z=%40')
542
+ # # => [["f#o", "/"], ["b-r", "$"], ["b z", "@"]]
543
+ #
544
+ # The given string may contain consecutive separators:
545
+ #
546
+ # URI.decode_www_form('foo=0&&bar=1&&baz=2')
547
+ # # => [["foo", "0"], ["", ""], ["bar", "1"], ["", ""], ["baz", "2"]]
548
+ #
549
+ # A different separator may be specified:
550
+ #
551
+ # URI.decode_www_form('foo=0--bar=1--baz', separator: '--')
552
+ # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
436
553
  #
437
- # See URI.decode_www_form_component, URI.encode_www_form.
438
554
  def self.decode_www_form(str, enc=Encoding::UTF_8, separator: '&', use__charset_: false, isindex: false)
439
555
  raise ArgumentError, "the input of #{self.name}.#{__method__} must be ASCII only string" unless str.ascii_only?
440
556
  ary = []
@@ -713,7 +829,15 @@ end # module URI
713
829
  module Kernel
714
830
 
715
831
  #
716
- # Returns +uri+ converted to an URI object.
832
+ # Returns a \URI object derived from the given +uri+,
833
+ # which may be a \URI string or an existing \URI object:
834
+ #
835
+ # # Returns a new URI.
836
+ # uri = URI('http://github.com/ruby/ruby')
837
+ # # => #<URI::HTTP http://github.com/ruby/ruby>
838
+ # # Returns the given URI.
839
+ # URI(uri)
840
+ # # => #<URI::HTTP http://github.com/ruby/ruby>
717
841
  #
718
842
  def URI(uri)
719
843
  if uri.is_a?(URI::Generic)
data/lib/uri/generic.rb CHANGED
@@ -1376,6 +1376,7 @@ module URI
1376
1376
  end
1377
1377
  str
1378
1378
  end
1379
+ alias to_str to_s
1379
1380
 
1380
1381
  #
1381
1382
  # Compares two URIs.
@@ -1,9 +1,73 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  module URI
3
3
  class RFC3986_Parser # :nodoc:
4
4
  # URI defined in RFC3986
5
- RFC3986_URI = /\A(?<URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*+):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*+))(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
6
- RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])++))?(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])++)(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
5
+ HOST = %r[
6
+ (?<IP-literal>\[(?:
7
+ (?<IPv6address>
8
+ (?:\h{1,4}:){6}
9
+ (?<ls32>\h{1,4}:\h{1,4}
10
+ | (?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)
11
+ \.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>)
12
+ )
13
+ | ::(?:\h{1,4}:){5}\g<ls32>
14
+ | \h{1,4}?::(?:\h{1,4}:){4}\g<ls32>
15
+ | (?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>
16
+ | (?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>
17
+ | (?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>
18
+ | (?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>
19
+ | (?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}
20
+ | (?:(?:\h{1,4}:){,6}\h{1,4})?::
21
+ )
22
+ | (?<IPvFuture>v\h++\.[!$&-.0-9:;=A-Z_a-z~]++)
23
+ )\])
24
+ | \g<IPv4address>
25
+ | (?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*+)
26
+ ]x
27
+
28
+ USERINFO = /(?:%\h\h|[!$&-.0-9:;=A-Z_a-z~])*+/
29
+
30
+ SCHEME = %r[[A-Za-z][+\-.0-9A-Za-z]*+].source
31
+ SEG = %r[(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/])].source
32
+ SEG_NC = %r[(?:%\h\h|[!$&-.0-9;=@A-Z_a-z~])].source
33
+ FRAGMENT = %r[(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/?])*+].source
34
+
35
+ RFC3986_URI = %r[\A
36
+ (?<seg>#{SEG}){0}
37
+ (?<URI>
38
+ (?<scheme>#{SCHEME}):
39
+ (?<hier-part>//
40
+ (?<authority>
41
+ (?:(?<userinfo>#{USERINFO.source})@)?
42
+ (?<host>#{HOST.source.delete(" \n")})
43
+ (?::(?<port>\d*+))?
44
+ )
45
+ (?<path-abempty>(?:/\g<seg>*+)?)
46
+ | (?<path-absolute>/((?!/)\g<seg>++)?)
47
+ | (?<path-rootless>(?!/)\g<seg>++)
48
+ | (?<path-empty>)
49
+ )
50
+ (?:\?(?<query>[^\#]*+))?
51
+ (?:\#(?<fragment>#{FRAGMENT}))?
52
+ )\z]x
53
+
54
+ RFC3986_relative_ref = %r[\A
55
+ (?<seg>#{SEG}){0}
56
+ (?<relative-ref>
57
+ (?<relative-part>//
58
+ (?<authority>
59
+ (?:(?<userinfo>#{USERINFO.source})@)?
60
+ (?<host>#{HOST.source.delete(" \n")}(?<!/))?
61
+ (?::(?<port>\d*+))?
62
+ )
63
+ (?<path-abempty>(?:/\g<seg>*+)?)
64
+ | (?<path-absolute>/\g<seg>*+)
65
+ | (?<path-noscheme>#{SEG_NC}++(?:/\g<seg>*+)?)
66
+ | (?<path-empty>)
67
+ )
68
+ (?:\?(?<query>[^#]*+))?
69
+ (?:\#(?<fragment>#{FRAGMENT}))?
70
+ )\z]x
7
71
  attr_reader :regexp
8
72
 
9
73
  def initialize
@@ -19,9 +83,9 @@ module URI
19
83
  uri.ascii_only? or
20
84
  raise InvalidURIError, "URI must be ascii only #{uri.dump}"
21
85
  if m = RFC3986_URI.match(uri)
22
- query = m["query".freeze]
23
- scheme = m["scheme".freeze]
24
- opaque = m["path-rootless".freeze]
86
+ query = m["query"]
87
+ scheme = m["scheme"]
88
+ opaque = m["path-rootless"]
25
89
  if opaque
26
90
  opaque << "?#{query}" if query
27
91
  [ scheme,
@@ -32,35 +96,35 @@ module URI
32
96
  nil, # path
33
97
  opaque,
34
98
  nil, # query
35
- m["fragment".freeze]
99
+ m["fragment"]
36
100
  ]
37
101
  else # normal
38
102
  [ scheme,
39
- m["userinfo".freeze],
40
- m["host".freeze],
41
- m["port".freeze],
103
+ m["userinfo"],
104
+ m["host"],
105
+ m["port"],
42
106
  nil, # registry
43
- (m["path-abempty".freeze] ||
44
- m["path-absolute".freeze] ||
45
- m["path-empty".freeze]),
107
+ (m["path-abempty"] ||
108
+ m["path-absolute"] ||
109
+ m["path-empty"]),
46
110
  nil, # opaque
47
111
  query,
48
- m["fragment".freeze]
112
+ m["fragment"]
49
113
  ]
50
114
  end
51
115
  elsif m = RFC3986_relative_ref.match(uri)
52
116
  [ nil, # scheme
53
- m["userinfo".freeze],
54
- m["host".freeze],
55
- m["port".freeze],
117
+ m["userinfo"],
118
+ m["host"],
119
+ m["port"],
56
120
  nil, # registry,
57
- (m["path-abempty".freeze] ||
58
- m["path-absolute".freeze] ||
59
- m["path-noscheme".freeze] ||
60
- m["path-empty".freeze]),
121
+ (m["path-abempty"] ||
122
+ m["path-absolute"] ||
123
+ m["path-noscheme"] ||
124
+ m["path-empty"]),
61
125
  nil, # opaque
62
- m["query".freeze],
63
- m["fragment".freeze]
126
+ m["query"],
127
+ m["fragment"]
64
128
  ]
65
129
  else
66
130
  raise InvalidURIError, "bad URI(is not URI?): #{uri.inspect}"
@@ -92,14 +156,14 @@ module URI
92
156
 
93
157
  def default_regexp # :nodoc:
94
158
  {
95
- SCHEME: /\A[A-Za-z][A-Za-z0-9+\-.]*\z/,
96
- USERINFO: /\A(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*\z/,
97
- HOST: /\A(?:(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{,4}::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))\z/,
98
- ABS_PATH: /\A\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/,
99
- REL_PATH: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/,
100
- QUERY: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
101
- FRAGMENT: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
102
- OPAQUE: /\A(?:[^\/].*)?\z/,
159
+ SCHEME: %r[\A#{SCHEME}\z]o,
160
+ USERINFO: %r[\A#{USERINFO}\z]o,
161
+ HOST: %r[\A#{HOST}\z]o,
162
+ ABS_PATH: %r[\A/#{SEG}*+\z]o,
163
+ REL_PATH: %r[\A(?!/)#{SEG}++\z]o,
164
+ QUERY: %r[\A(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/?])*+\z],
165
+ FRAGMENT: %r[\A#{FRAGMENT}\z]o,
166
+ OPAQUE: %r[\A(?:[^/].*)?\z],
103
167
  PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\z/,
104
168
  }
105
169
  end
data/lib/uri/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module URI
2
2
  # :stopdoc:
3
- VERSION_CODE = '001202'.freeze
3
+ VERSION_CODE = '001300'.freeze
4
4
  VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
5
5
  # :startdoc:
6
6
  end
@@ -0,0 +1,17 @@
1
+ task :sync_tool, [:from] do |t, from: nil|
2
+ from ||= (File.identical?(__dir__, "rakelib") ? "../ruby/tool" : File.dirname(__dir__))
3
+
4
+ require 'fileutils'
5
+
6
+ {
7
+ "rakelib/sync_tool.rake" => "rakelib",
8
+ "lib/core_assertions.rb" => "test/lib",
9
+ "lib/envutil.rb" => "test/lib",
10
+ "lib/find_executable.rb" => "test/lib",
11
+ "lib/helper.rb" => "test/lib",
12
+ }.each do |src, dest|
13
+ FileUtils.mkpath(dest)
14
+ FileUtils.cp "#{from}/#{src}", dest
15
+ rescue Errno::ENOENT
16
+ end
17
+ end
data/uri.gemspec CHANGED
@@ -12,18 +12,26 @@ Gem::Specification.new do |spec|
12
12
 
13
13
  spec.summary = %q{URI is a module providing classes to handle Uniform Resource Identifiers}
14
14
  spec.description = spec.summary
15
- spec.homepage = "https://github.com/ruby/uri"
15
+
16
+ github_link = "https://github.com/ruby/uri"
17
+
18
+ spec.homepage = github_link
16
19
  spec.licenses = ["Ruby", "BSD-2-Clause"]
17
20
 
18
- spec.required_ruby_version = '>= 2.4'
21
+ spec.required_ruby_version = '>= 2.5'
19
22
 
20
- spec.metadata["homepage_uri"] = spec.homepage
21
- spec.metadata["source_code_uri"] = spec.homepage
23
+ spec.metadata = {
24
+ "bug_tracker_uri" => "#{github_link}/issues",
25
+ "changelog_uri" => "#{github_link}/releases",
26
+ "documentation_uri" => "https://ruby.github.io/uri/",
27
+ "homepage_uri" => spec.homepage,
28
+ "source_code_uri" => github_link
29
+ }
22
30
 
23
31
  # Specify which files should be added to the gem when it is released.
24
32
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
33
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
26
- `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
+ `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
35
  end
28
36
  spec.bindir = "exe"
29
37
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uri
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.2
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Akira Yamada
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-29 00:00:00.000000000 Z
11
+ date: 2023-11-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: URI is a module providing classes to handle Uniform Resource Identifiers
14
14
  email:
@@ -18,6 +18,7 @@ extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
20
  - ".github/dependabot.yml"
21
+ - ".github/workflows/gh-pages.yml"
21
22
  - ".github/workflows/test.yml"
22
23
  - ".gitignore"
23
24
  - Gemfile
@@ -41,12 +42,16 @@ files:
41
42
  - lib/uri/version.rb
42
43
  - lib/uri/ws.rb
43
44
  - lib/uri/wss.rb
45
+ - rakelib/sync_tool.rake
44
46
  - uri.gemspec
45
47
  homepage: https://github.com/ruby/uri
46
48
  licenses:
47
49
  - Ruby
48
50
  - BSD-2-Clause
49
51
  metadata:
52
+ bug_tracker_uri: https://github.com/ruby/uri/issues
53
+ changelog_uri: https://github.com/ruby/uri/releases
54
+ documentation_uri: https://ruby.github.io/uri/
50
55
  homepage_uri: https://github.com/ruby/uri
51
56
  source_code_uri: https://github.com/ruby/uri
52
57
  post_install_message:
@@ -57,14 +62,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
57
62
  requirements:
58
63
  - - ">="
59
64
  - !ruby/object:Gem::Version
60
- version: '2.4'
65
+ version: '2.5'
61
66
  required_rubygems_version: !ruby/object:Gem::Requirement
62
67
  requirements:
63
68
  - - ">="
64
69
  - !ruby/object:Gem::Version
65
70
  version: '0'
66
71
  requirements: []
67
- rubygems_version: 3.3.26
72
+ rubygems_version: 3.5.0.dev
68
73
  signing_key:
69
74
  specification_version: 4
70
75
  summary: URI is a module providing classes to handle Uniform Resource Identifiers