iri 0.10.0 → 0.11.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.
data/lib/iri.rb CHANGED
@@ -1,76 +1,78 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # (The MIT License)
4
- #
5
- # Copyright (c) 2019-2025 Yegor Bugayenko
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy
8
- # of this software and associated documentation files (the 'Software'), to deal
9
- # in the Software without restriction, including without limitation the rights
10
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- # copies of the Software, and to permit persons to whom the Software is
12
- # furnished to do so, subject to the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be included in all
15
- # copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- # SOFTWARE.
3
+ # SPDX-FileCopyrightText: Copyright (c) 2019-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
24
5
 
25
6
  require 'uri'
26
7
  require 'cgi'
27
8
 
28
- # It is a simple URI builder.
9
+ # Iri is a simple, immutable URI builder with a fluent interface.
29
10
  #
30
- # require 'iri'
31
- # url = Iri.new('http://google.com/')
32
- # .add(q: 'books about OOP', limit: 50)
33
- # .del(:q) // remove this query parameter
34
- # .del('limit') // remove this one too
35
- # .over(q: 'books about tennis', limit: 10) // replace these params
36
- # .scheme('https')
37
- # .host('localhost')
38
- # .port('443')
39
- # .to_s
11
+ # The Iri class provides methods to manipulate different parts of a URI,
12
+ # including the scheme, host, port, path, query parameters, and fragment.
13
+ # Each method returns a new Iri instance, maintaining immutability.
40
14
  #
41
- # For more information read
15
+ # @example Creating and manipulating a URI
16
+ # require 'iri'
17
+ # url = Iri.new('http://google.com/')
18
+ # .add(q: 'books about OOP', limit: 50)
19
+ # .del(:q) # remove this query parameter
20
+ # .del('limit') # remove this one too
21
+ # .over(q: 'books about tennis', limit: 10) # replace these params
22
+ # .scheme('https')
23
+ # .host('localhost')
24
+ # .port('443')
25
+ # .to_s
26
+ #
27
+ # @example Using the local option
28
+ # Iri.new('/path?foo=bar', local: true).to_s # => "/path?foo=bar"
29
+ #
30
+ # @example Using the safe mode
31
+ # Iri.new('invalid://uri', safe: true).to_s # => "/" (no exception thrown)
32
+ # Iri.new('invalid://uri', safe: false) # => raises Iri::InvalidURI
33
+ #
34
+ # For more information read the
42
35
  # {README}[https://github.com/yegor256/iri/blob/master/README.md] file.
43
36
  #
44
37
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
45
38
  # Copyright:: Copyright (c) 2019-2025 Yegor Bugayenko
46
39
  # License:: MIT
47
40
  class Iri
48
- # When URI is not valid.
41
+ # Exception raised when a URI is not valid and safe mode is disabled.
49
42
  class InvalidURI < StandardError; end
50
43
 
51
- # When .add(), .over(), or .del() arguments are not valid.
44
+ # Exception raised when arguments to .add(), .over(), or .del() are not valid Hashes.
52
45
  class InvalidArguments < StandardError; end
53
46
 
54
- # Makes a new object.
47
+ # Creates a new Iri object for URI manipulation.
55
48
  #
56
- # You can even ignore the argument, which will produce an empty URI.
49
+ # You can even ignore the argument, which will produce an empty URI ("/").
57
50
  #
58
51
  # By default, this class will never throw any exceptions, even if your URI
59
- # is not valid. It will just assume that the URI is"/". However,
60
- # you can turn this mode off, by specifying safe as FALSE.
52
+ # is not valid. It will just assume that the URI is "/". However,
53
+ # you can turn this safe mode off by specifying safe as FALSE, which will
54
+ # cause InvalidURI to be raised if the URI is malformed.
55
+ #
56
+ # The local parameter can be used if you only want to work with the path,
57
+ # query, and fragment portions of a URI, without the scheme, host, and port.
61
58
  #
62
- # @param [String] uri URI
63
- # @param [Boolean] local Is it local (no host, port, and scheme)?
64
- # @param [Boolean] safe Should it safe?
59
+ # @param [String] uri URI string to parse
60
+ # @param [Boolean] local When true, ignores scheme, host and port parts
61
+ # @param [Boolean] safe When true, prevents InvalidURI exceptions
62
+ # @raise [InvalidURI] If the URI is malformed and safe is false
65
63
  def initialize(uri = '', local: false, safe: true)
64
+ raise ArgumentError, "The uri can't be nil" if uri.nil?
66
65
  @uri = uri
67
66
  @local = local
68
67
  @safe = safe
69
68
  end
70
69
 
71
- # Convert it to a string.
70
+ # Converts the Iri object to a string representation of the URI.
72
71
  #
73
- # @return [String] New URI
72
+ # When local mode is enabled, only the path, query, and fragment parts are included.
73
+ # Otherwise, the full URI including scheme, host, and port is returned.
74
+ #
75
+ # @return [String] String representation of the URI
74
76
  def to_s
75
77
  u = the_uri
76
78
  if @local
@@ -84,44 +86,60 @@ class Iri
84
86
  end
85
87
  end
86
88
 
87
- # Inspect it, like a string can be inspected.
89
+ # Returns a string representation of the Iri object for inspection purposes.
90
+ #
91
+ # This method is used when the object is displayed in irb/console or with puts/p.
88
92
  #
89
- # @return [String] Details of it
93
+ # @return [String] String representation for inspection
90
94
  def inspect
91
95
  @uri.to_s.inspect
92
96
  end
93
97
 
94
- # Convert it to an object of class +URI+.
98
+ # Converts the Iri object to a Ruby standard library URI object.
95
99
  #
96
- # @return [String] New URI
100
+ # @return [URI] A cloned URI object from the underlying URI
97
101
  def to_uri
98
102
  the_uri.clone
99
103
  end
100
104
 
101
- # Removes the host, the port, and the scheme and returns
102
- # only the local address, for example, converting "https://google.com/foo"
103
- # into "/foo".
105
+ # Creates a new Iri object with only the local parts of the URI.
104
106
  #
105
- # @return [Iri] Iri with no host/port/scheme
107
+ # Removes the host, the port, and the scheme, returning only the local address.
108
+ # For example, converting "https://google.com/foo" into "/foo".
109
+ # The path, query string, and fragment are preserved.
110
+ #
111
+ # @return [Iri] A new Iri object with local:true and the same URI
112
+ # @see #initialize
106
113
  def to_local
107
114
  Iri.new(@uri, local: true, safe: @safe)
108
115
  end
109
116
 
110
- # Add a few query arguments.
117
+ # Adds query parameters to the URI.
118
+ #
119
+ # This method appends query parameters to existing ones. If a parameter with the same
120
+ # name already exists, both values will be present in the resulting URI.
111
121
  #
112
- # For example:
122
+ # @example Adding query parameters
123
+ # Iri.new('https://google.com').add(q: 'test', limit: 10)
124
+ # # => "https://google.com?q=test&limit=10"
113
125
  #
114
- # Iri.new('https://google.com').add(q: 'test', limit: 10)
126
+ # @example Adding parameters with the same name
127
+ # Iri.new('https://google.com?q=foo').add(q: 'bar')
128
+ # # => "https://google.com?q=foo&q=bar"
115
129
  #
116
- # You can add many of them and they will all be present in the resulting
117
- # URI, even if their names are the same. In order to make sure you have
118
- # only one instance of a query argument, use +del+ first:
130
+ # You can ensure only one instance of a parameter by using +del+ first:
119
131
  #
120
- # Iri.new('https://google.com').del(:q).add(q: 'test')
132
+ # @example Replacing a parameter by deleting it first
133
+ # Iri.new('https://google.com?q=foo').del(:q).add(q: 'test')
134
+ # # => "https://google.com?q=test"
121
135
  #
122
- # @param [Hash] hash Hash of names/values to set into the query part
123
- # @return [Iri] A new iri
136
+ # @param [Hash] hash Hash of parameter names/values to add to the query part
137
+ # @return [Iri] A new Iri instance
138
+ # @raise [InvalidArguments] If the argument is not a Hash
139
+ # @see #del
140
+ # @see #over
124
141
  def add(hash)
142
+ raise ArgumentError, "The hash can't be nil" if hash.nil?
125
143
  raise InvalidArguments unless hash.is_a?(Hash)
126
144
  modify_query do |params|
127
145
  hash.each do |k, v|
@@ -130,15 +148,24 @@ class Iri
130
148
  end
131
149
  end
132
150
  end
151
+ alias with add
133
152
 
134
- # Delete a few query arguments.
153
+ # Deletes query parameters from the URI.
135
154
  #
136
- # For example:
155
+ # This method removes all instances of the specified parameters from the query string.
137
156
  #
138
- # Iri.new('https://google.com?q=test').del(:q)
157
+ # @example Deleting a query parameter
158
+ # Iri.new('https://google.com?q=test&limit=10').del(:q)
159
+ # # => "https://google.com?limit=10"
139
160
  #
140
- # @param [Array] keys List of keys to delete
141
- # @return [Iri] A new iri
161
+ # @example Deleting multiple parameters
162
+ # Iri.new('https://google.com?q=test&limit=10&sort=asc').del(:q, :limit)
163
+ # # => "https://google.com?sort=asc"
164
+ #
165
+ # @param [Array<Symbol, String>] keys List of parameter names to delete
166
+ # @return [Iri] A new Iri instance
167
+ # @see #add
168
+ # @see #over
142
169
  def del(*keys)
143
170
  modify_query do |params|
144
171
  keys.each do |k|
@@ -146,94 +173,164 @@ class Iri
146
173
  end
147
174
  end
148
175
  end
176
+ alias without del
149
177
 
150
- # Replace query argument(s).
178
+ # Replaces query parameters in the URI.
179
+ #
180
+ # Unlike #add, this method replaces any existing parameters with the same name
181
+ # rather than adding additional instances. If a parameter doesn't exist,
182
+ # it will be added.
183
+ #
184
+ # @example Replacing a query parameter
185
+ # Iri.new('https://google.com?q=test').over(q: 'hey you!')
186
+ # # => "https://google.com?q=hey+you%21"
151
187
  #
152
- # Iri.new('https://google.com?q=test').over(q: 'hey you!')
188
+ # @example Replacing multiple parameters
189
+ # Iri.new('https://google.com?q=test&limit=5').over(q: 'books', limit: 10)
190
+ # # => "https://google.com?q=books&limit=10"
153
191
  #
154
- # @param [Hash] hash Hash of names/values to set into the query part
155
- # @return [Iri] A new iri
192
+ # @param [Hash] hash Hash of parameter names/values to replace in the query part
193
+ # @return [Iri] A new Iri instance
194
+ # @raise [InvalidArguments] If the argument is not a Hash
195
+ # @see #add
196
+ # @see #del
156
197
  def over(hash)
198
+ raise ArgumentError, "The hash can't be nil" if hash.nil?
157
199
  raise InvalidArguments unless hash.is_a?(Hash)
158
200
  modify_query do |params|
159
201
  hash.each do |k, v|
160
- params[k.to_s] = [] unless params[k]
202
+ params[k.to_s] = [] unless params[k.to_s]
161
203
  params[k.to_s] = [v]
162
204
  end
163
205
  end
164
206
  end
165
207
 
166
- # Replace the scheme.
208
+ # Replaces the scheme part of the URI.
209
+ #
210
+ # @example Changing the scheme
211
+ # Iri.new('http://google.com').scheme('https')
212
+ # # => "https://google.com"
167
213
  #
168
214
  # @param [String] val New scheme to set, like "https" or "http"
169
- # @return [Iri] A new iri
215
+ # @return [Iri] A new Iri instance
216
+ # @see #host
217
+ # @see #port
170
218
  def scheme(val)
219
+ raise ArgumentError, "The scheme can't be nil" if val.nil?
171
220
  modify do |c|
172
221
  c.scheme = val
173
222
  end
174
223
  end
175
224
 
176
- # Replace the host.
225
+ # Replaces the host part of the URI.
177
226
  #
178
- # @param [String] val New host to set, like "google.com" or "192.168.0.1"
179
- # @return [Iri] A new iri
227
+ # @example Changing the host
228
+ # Iri.new('https://google.com').host('example.com')
229
+ # # => "https://example.com"
230
+ #
231
+ # @param [String] val New host to set, like "example.com" or "192.168.0.1"
232
+ # @return [Iri] A new Iri instance
233
+ # @see #scheme
234
+ # @see #port
180
235
  def host(val)
236
+ raise ArgumentError, "The host can't be nil" if val.nil?
181
237
  modify do |c|
182
238
  c.host = val
183
239
  end
184
240
  end
185
241
 
186
- # Replace the port.
242
+ # Replaces the port part of the URI.
243
+ #
244
+ # @example Changing the port
245
+ # Iri.new('https://example.com').port('8443')
246
+ # # => "https://example.com:8443"
187
247
  #
188
248
  # @param [String] val New TCP port to set, like "8080" or "443"
189
- # @return [Iri] A new iri
249
+ # @return [Iri] A new Iri instance
250
+ # @see #scheme
251
+ # @see #host
190
252
  def port(val)
253
+ raise ArgumentError, "The port can't be nil" if val.nil?
191
254
  modify do |c|
192
255
  c.port = val
193
256
  end
194
257
  end
195
258
 
196
- # Replace the path part of the URI.
259
+ # Replaces the path part of the URI.
260
+ #
261
+ # @example Changing the path
262
+ # Iri.new('https://example.com/foo').path('/bar/baz')
263
+ # # => "https://example.com/bar/baz"
197
264
  #
198
265
  # @param [String] val New path to set, like "/foo/bar"
199
- # @return [Iri] A new iri
266
+ # @return [Iri] A new Iri instance
267
+ # @see #query
268
+ # @see #fragment
200
269
  def path(val)
270
+ raise ArgumentError, "The path can't be nil" if val.nil?
201
271
  modify do |c|
202
272
  c.path = val
203
273
  end
204
274
  end
205
275
 
206
- # Replace the fragment part of the URI.
276
+ # Replaces the fragment part of the URI (the part after #).
277
+ #
278
+ # @example Setting a fragment
279
+ # Iri.new('https://example.com/page').fragment('section2')
280
+ # # => "https://example.com/page#section2"
207
281
  #
208
- # @param [String] val New fragment to set, like "hello"
209
- # @return [Iri] A new iri
282
+ # @param [String] val New fragment to set, like "section2"
283
+ # @return [Iri] A new Iri instance
284
+ # @see #path
285
+ # @see #query
210
286
  def fragment(val)
287
+ raise ArgumentError, "The fragment can't be nil" if val.nil?
211
288
  modify do |c|
212
289
  c.fragment = val.to_s
213
290
  end
214
291
  end
215
292
 
216
- # Replace the query part of the URI.
293
+ # Replaces the entire query part of the URI.
294
+ #
295
+ # Use this method to completely replace the query string. For modifying
296
+ # individual parameters, see #add, #del, and #over.
297
+ #
298
+ # @example Setting a query string
299
+ # Iri.new('https://example.com/search').query('q=ruby&limit=10')
300
+ # # => "https://example.com/search?q=ruby&limit=10"
217
301
  #
218
- # @param [String] val New query to set, like "a=1&b=2"
219
- # @return [Iri] A new iri
302
+ # @param [String] val New query string to set, like "a=1&b=2"
303
+ # @return [Iri] A new Iri instance
304
+ # @see #add
305
+ # @see #del
306
+ # @see #over
220
307
  def query(val)
308
+ raise ArgumentError, "The query can't be nil" if val.nil?
221
309
  modify do |c|
222
310
  c.query = val
223
311
  end
224
312
  end
225
313
 
226
- # Remove the entire path+query+fragment part.
314
+ # Removes the entire path, query, and fragment parts and sets a new path.
227
315
  #
228
- # For example:
316
+ # This method is useful for "cutting off" everything after the host:port
317
+ # and setting a new path, effectively removing query string and fragment.
229
318
  #
230
- # Iri.new('https://google.com/a/b?q=test').cut('/hello')
319
+ # @example Cutting off path/query/fragment and setting a new path
320
+ # Iri.new('https://google.com/a/b?q=test').cut('/hello')
321
+ # # => "https://google.com/hello"
231
322
  #
232
- # The result will contain "https://google.com/hello".
323
+ # @example Resetting to root path
324
+ # Iri.new('https://google.com/a/b?q=test#section2').cut()
325
+ # # => "https://google.com/"
233
326
  #
234
- # @param [String] path New path to set, like "/foo"
235
- # @return [Iri] A new iri
327
+ # @param [String] path New path to set, defaults to "/"
328
+ # @return [Iri] A new Iri instance
329
+ # @see #path
330
+ # @see #query
331
+ # @see #fragment
236
332
  def cut(path = '/')
333
+ raise ArgumentError, "The path can't be nil" if path.nil?
237
334
  modify do |c|
238
335
  c.query = nil
239
336
  c.path = path
@@ -241,17 +338,28 @@ class Iri
241
338
  end
242
339
  end
243
340
 
244
- # Append something new to the path.
341
+ # Appends a new segment to the existing path.
245
342
  #
246
- # For example:
343
+ # This method adds a new segment to the existing path, automatically handling
344
+ # the slash between segments and URL encoding the new segment.
247
345
  #
248
- # Iri.new('https://google.com/a/b?q=test').append('/hello')
346
+ # @example Appending a path segment
347
+ # Iri.new('https://example.com/a/b?q=test').append('hello')
348
+ # # => "https://example.com/a/b/hello?q=test"
249
349
  #
250
- # The result will contain "https://google.com/a/b/hello?q=test".
350
+ # @example Appending to a path with a trailing slash
351
+ # Iri.new('https://example.com/a/').append('hello')
352
+ # # => "https://example.com/a/hello?q=test"
251
353
  #
252
- # @param [String] part New segment to add to existing path
253
- # @return [Iri] A new iri
354
+ # @example Appending a segment that needs URL encoding
355
+ # Iri.new('https://example.com/docs').append('section 1')
356
+ # # => "https://example.com/docs/section%201"
357
+ #
358
+ # @param [String, #to_s] part New segment to add to the existing path
359
+ # @return [Iri] A new Iri instance
360
+ # @see #path
254
361
  def append(part)
362
+ raise ArgumentError, "The part can't be nil" if part.nil?
255
363
  modify do |c|
256
364
  tail = (c.path.end_with?('/') ? '' : '/') + CGI.escape(part.to_s)
257
365
  c.path = c.path + tail
@@ -260,6 +368,14 @@ class Iri
260
368
 
261
369
  private
262
370
 
371
+ # Parses the URI string into a URI object.
372
+ #
373
+ # This method handles the safe mode by catching and handling invalid URI errors.
374
+ # When safe mode is enabled (default), invalid URIs will return the root path URI "/"
375
+ # instead of raising an exception.
376
+ #
377
+ # @return [URI] The parsed URI object
378
+ # @raise [InvalidURI] If the URI is invalid and safe mode is disabled
263
379
  def the_uri
264
380
  @the_uri ||= URI(@uri)
265
381
  rescue URI::InvalidURIError => e
@@ -267,12 +383,27 @@ class Iri
267
383
  @the_uri = URI('/')
268
384
  end
269
385
 
386
+ # Creates a new Iri object after modifying the underlying URI.
387
+ #
388
+ # This helper method clones the current URI, yields it to a block for modification,
389
+ # and then creates a new Iri object with the modified URI, preserving the local and safe flags.
390
+ #
391
+ # @yield [URI] The cloned URI object for modification
392
+ # @return [Iri] A new Iri instance with the modified URI
270
393
  def modify
271
394
  c = the_uri.clone
272
395
  yield c
273
396
  Iri.new(c, local: @local, safe: @safe)
274
397
  end
275
398
 
399
+ # Creates a new Iri object after modifying the query parameters.
400
+ #
401
+ # This helper method parses the current query string into a hash of parameter names
402
+ # to arrays of values, yields this hash for modification, and then encodes it back
403
+ # into a query string. It uses the modify method to create a new Iri object.
404
+ #
405
+ # @yield [Hash] The parsed query parameters for modification
406
+ # @return [Iri] A new Iri instance with the modified query string
276
407
  def modify_query
277
408
  modify do |c|
278
409
  params = CGI.parse(the_uri.query || '').map do |p, a|
data/test/test__helper.rb CHANGED
@@ -1,26 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2019-2025 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
3
+ # SPDX-FileCopyrightText: Copyright (c) 2019-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
22
5
 
23
6
  $stdout.sync = true
24
7
 
25
8
  require 'simplecov'
26
- SimpleCov.start
9
+ require 'simplecov-cobertura'
10
+ unless SimpleCov.running
11
+ SimpleCov.command_name('test')
12
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
13
+ [
14
+ SimpleCov::Formatter::HTMLFormatter,
15
+ SimpleCov::Formatter::CoberturaFormatter
16
+ ]
17
+ )
18
+ SimpleCov.minimum_coverage 100
19
+ SimpleCov.minimum_coverage_by_file 100
20
+ SimpleCov.start do
21
+ add_filter 'test/'
22
+ add_filter 'vendor/'
23
+ add_filter 'target/'
24
+ track_files 'lib/**/*.rb'
25
+ track_files '*.rb'
26
+ end
27
+ end
28
+
29
+ require 'minitest/autorun'
30
+ require 'minitest/reporters'
31
+ Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
data/test/test_iri.rb CHANGED
@@ -1,28 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # (The MIT License)
4
- #
5
- # Copyright (c) 2019-2025 Yegor Bugayenko
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy
8
- # of this software and associated documentation files (the 'Software'), to deal
9
- # in the Software without restriction, including without limitation the rights
10
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- # copies of the Software, and to permit persons to whom the Software is
12
- # furnished to do so, subject to the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be included in all
15
- # copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
- # SOFTWARE.
24
-
25
- require 'minitest/autorun'
3
+ # SPDX-FileCopyrightText: Copyright (c) 2019-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative '../test/test__helper'
26
7
  require_relative '../lib/iri'
27
8
 
28
9
  # Iri test.
@@ -203,4 +184,84 @@ class IriTest < Minitest::Test
203
184
  Iri.new('http://google/?a=1&b=2&c=3&a=33').over(a: 'hey').to_s
204
185
  )
205
186
  end
187
+
188
+ def test_rejects_nil_uri
189
+ assert_raises ArgumentError do
190
+ Iri.new(nil)
191
+ end
192
+ end
193
+
194
+ def test_rejects_nil_scheme
195
+ assert_raises ArgumentError do
196
+ Iri.new('http://google.com').scheme(nil)
197
+ end
198
+ end
199
+
200
+ def test_rejects_nil_host
201
+ assert_raises ArgumentError do
202
+ Iri.new('http://google.com').host(nil)
203
+ end
204
+ end
205
+
206
+ def test_rejects_nil_port
207
+ assert_raises ArgumentError do
208
+ Iri.new('http://google.com').port(nil)
209
+ end
210
+ end
211
+
212
+ def test_rejects_nil_path
213
+ assert_raises ArgumentError do
214
+ Iri.new('http://google.com').path(nil)
215
+ end
216
+ end
217
+
218
+ def test_rejects_nil_fragment
219
+ assert_raises ArgumentError do
220
+ Iri.new('http://google.com').fragment(nil)
221
+ end
222
+ end
223
+
224
+ def test_rejects_nil_query
225
+ assert_raises ArgumentError do
226
+ Iri.new('http://google.com').query(nil)
227
+ end
228
+ end
229
+
230
+ def test_rejects_nil_cut_path
231
+ assert_raises ArgumentError do
232
+ Iri.new('http://google.com/foo').cut(nil)
233
+ end
234
+ end
235
+
236
+ def test_rejects_nil_append_part
237
+ assert_raises ArgumentError do
238
+ Iri.new('http://google.com').append(nil)
239
+ end
240
+ end
241
+
242
+ def test_rejects_nil_add_hash
243
+ assert_raises ArgumentError do
244
+ Iri.new('http://google.com').add(nil)
245
+ end
246
+ end
247
+
248
+ def test_rejects_nil_over_hash
249
+ assert_raises ArgumentError do
250
+ Iri.new('http://google.com').over(nil)
251
+ end
252
+ end
253
+
254
+ def test_with_alias_for_add
255
+ assert_equal(
256
+ 'http://google.com?q=test&limit=10',
257
+ Iri.new('http://google.com').with(q: 'test', limit: 10).to_s
258
+ )
259
+ end
260
+
261
+ def test_without_alias_for_del
262
+ assert_equal(
263
+ 'http://google.com/?b=2',
264
+ Iri.new('http://google.com/?a=1&b=2&c=3').without(:a, :c).to_s
265
+ )
266
+ end
206
267
  end