uri 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d86620a487d2769ad2d77ec2d040b38ce8d97c49c7e58228083cd41cae23e94
4
- data.tar.gz: 5bc762b3a032fedea0ecd0640fd3d580296171ce12231e6cd6c766ff51622675
3
+ metadata.gz: 8f4eaea3d45b9a860a4a1765dfa211d195929e01ea90e2ff25405fea90948098
4
+ data.tar.gz: 5f962ae3a2b0c56f589df823edf89560420d8c2dced50ac7332e5a6322a772bc
5
5
  SHA512:
6
- metadata.gz: 026e3ef8b7e0cb8b5d243169a8eab6b8be7ca820328456b737fc21862ec8e09f1390e9010891607ed6a4689a8bc075384d51ae6c79aaaf872b5f1f5f50473f42
7
- data.tar.gz: c7817221a6ee496344c4d62e91da663ff2eaf4f7d93a05818460225ce75c069b414eb24248bff1d0979cc57f9c559381053768845ffcfdad7997a9e968aa7d8e
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,19 +3,25 @@ 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:
18
24
  ruby-version: ${{ matrix.ruby }}
19
- bundler-cache: true
25
+ - run: bundle install --jobs 4 --retry 3
20
26
  - name: Run test
21
27
  run: rake test
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  Gemfile.lock
10
+ /_site
data/Gemfile CHANGED
@@ -6,4 +6,5 @@ group :development do
6
6
  gem "bundler"
7
7
  gem "rake"
8
8
  gem "test-unit"
9
+ gem "test-unit-ruby-core"
9
10
  end
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.
@@ -497,8 +497,8 @@ module URI
497
497
  ret = {}
498
498
 
499
499
  # for URI::split
500
- ret[:ABS_URI] = Regexp.new('\A\s*' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
501
- ret[:REL_URI] = Regexp.new('\A\s*' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
500
+ ret[:ABS_URI] = Regexp.new('\A\s*+' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
501
+ ret[:REL_URI] = Regexp.new('\A\s*+' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
502
502
 
503
503
  # for URI::extract
504
504
  ret[:URI_REF] = Regexp.new(pattern[:URI_REF])
@@ -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,15 +156,15 @@ 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/,
103
- PORT: /\A[\x09\x0a\x0c\x0d ]*\d*[\x09\x0a\x0c\x0d ]*\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],
167
+ PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\z/,
104
168
  }
105
169
  end
106
170
 
data/lib/uri/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module URI
2
2
  # :stopdoc:
3
- VERSION_CODE = '001201'.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.1
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-03-28 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,7 +62,7 @@ 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
  - - ">="