net-imap 0.5.9 → 0.6.4

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.
@@ -3,6 +3,7 @@
3
3
  require_relative "config/attr_accessors"
4
4
  require_relative "config/attr_inheritance"
5
5
  require_relative "config/attr_type_coercion"
6
+ require_relative "config/attr_version_defaults"
6
7
 
7
8
  module Net
8
9
  class IMAP
@@ -141,15 +142,7 @@ module Net
141
142
  # Net::IMAP::Config[0.5] == Net::IMAP::Config[0.5r] # => true
142
143
  # Net::IMAP::Config["current"] == Net::IMAP::Config[:current] # => true
143
144
  # Net::IMAP::Config["0.5.6"] == Net::IMAP::Config[0.5r] # => true
144
- def self.version_defaults; @version_defaults end
145
- @version_defaults = Hash.new {|h, k|
146
- # NOTE: String responds to both so the order is significant.
147
- # And ignore non-numeric conversion to zero, because: "wat!?".to_r == 0
148
- (h.fetch(k.to_r, nil) || h.fetch(k.to_f, nil) if k.is_a?(Numeric)) ||
149
- (h.fetch(k.to_sym, nil) if k.respond_to?(:to_sym)) ||
150
- (h.fetch(k.to_r, nil) if k.respond_to?(:to_r) && k.to_r != 0r) ||
151
- (h.fetch(k.to_f, nil) if k.respond_to?(:to_f) && k.to_f != 0.0)
152
- }
145
+ def self.version_defaults; AttrVersionDefaults.version_defaults end
153
146
 
154
147
  # :call-seq:
155
148
  # Net::IMAP::Config[number] -> versioned config
@@ -189,6 +182,7 @@ module Net
189
182
  include AttrAccessors
190
183
  include AttrInheritance
191
184
  include AttrTypeCoercion
185
+ extend AttrVersionDefaults
192
186
 
193
187
  # The debug mode (boolean). The default value is +false+.
194
188
  #
@@ -200,7 +194,7 @@ module Net
200
194
  #
201
195
  # *NOTE:* Versioned default configs inherit #debug from Config.global, and
202
196
  # #load_defaults will not override #debug.
203
- attr_accessor :debug, type: :boolean
197
+ attr_accessor :debug, type: :boolean, default: false
204
198
 
205
199
  # method: debug?
206
200
  # :call-seq: debug? -> boolean
@@ -218,7 +212,7 @@ module Net
218
212
  # See Net::IMAP.new and Net::IMAP#starttls.
219
213
  #
220
214
  # The default value is +30+ seconds.
221
- attr_accessor :open_timeout, type: Integer
215
+ attr_accessor :open_timeout, type: Integer, default: 30
222
216
 
223
217
  # Seconds to wait until an IDLE response is received, after
224
218
  # the client asks to leave the IDLE state.
@@ -226,7 +220,7 @@ module Net
226
220
  # See Net::IMAP#idle and Net::IMAP#idle_done.
227
221
  #
228
222
  # The default value is +5+ seconds.
229
- attr_accessor :idle_response_timeout, type: Integer
223
+ attr_accessor :idle_response_timeout, type: Integer, default: 5
230
224
 
231
225
  # Whether to use the +SASL-IR+ extension when the server and \SASL
232
226
  # mechanism both support it. Can be overridden by the +sasl_ir+ keyword
@@ -240,9 +234,25 @@ module Net
240
234
  # Do not use +SASL-IR+, even when it is supported by the server and the
241
235
  # mechanism.
242
236
  #
237
+ # [+:when_capabilities_cached+]
238
+ # Use +SASL-IR+ when Net::IMAP#capabilities_cached? is +true+ and it is
239
+ # supported by the server and the mechanism, but do not send a
240
+ # +CAPABILITY+ command to discover the server capabilities.
241
+ #
242
+ # <em>(+:when_capabilities_cached+ option was added by +v0.6.0+)</em>
243
+ #
243
244
  # [+true+ <em>(default since +v0.4+)</em>]
244
245
  # Use +SASL-IR+ when it is supported by the server and the mechanism.
245
- attr_accessor :sasl_ir, type: :boolean
246
+ attr_accessor :sasl_ir, type: Enum[
247
+ false, :when_capabilities_cached, true
248
+ ], defaults: {
249
+ 0.0r => false,
250
+ 0.4r => true,
251
+ }
252
+
253
+ # :stopdoc:
254
+ alias sasl_ir? sasl_ir
255
+ # :startdoc:
246
256
 
247
257
  # Controls the behavior of Net::IMAP#login when the +LOGINDISABLED+
248
258
  # capability is present. When enforced, Net::IMAP will raise a
@@ -266,7 +276,44 @@ module Net
266
276
  #
267
277
  attr_accessor :enforce_logindisabled, type: Enum[
268
278
  false, :when_capabilities_cached, true
269
- ]
279
+ ], defaults: {
280
+ 0.0r => false,
281
+ 0.5r => true,
282
+ }
283
+
284
+ # The maximum bytesize for sending non-synchronizing literals, when the
285
+ # server supports them. To disable non-synchronizing literals, set the
286
+ # value to +-1+.
287
+ #
288
+ # Non-synchronizing literals are only sent when the server's
289
+ # capabilities[rdoc-ref:IMAP#capabilities] have been
290
+ # cached[rdoc-ref:IMAP#capabilities_cached?] and include either
291
+ # <tt>LITERAL+</tt> [RFC7888[https://www.rfc-editor.org/rfc/rfc7888]],
292
+ # <tt>LITERAL-</tt> [RFC7888[https://www.rfc-editor.org/rfc/rfc7888]], or
293
+ # +IMAP4rev2+ [RFC9051[https://www.rfc-editor.org/rfc/rfc9051]].
294
+ #
295
+ # For <tt>LITERAL+</tt>, this value is the only limit on whether a literal
296
+ # value is sent as non-synchronizing literals. For <tt>LITERAL-</tt> and
297
+ # <tt>IMAP4rev2</tt>, non-synchronizing literals must also be smaller than
298
+ # +4096+ bytes.
299
+ #
300
+ # Non-synchronizing literals avoid the latency of waiting for the server
301
+ # to allow continuation. However, if a client sends a non-synchronizing
302
+ # literal that is too large for the server, the server may need to close
303
+ # the connection. Because <tt>LITERAL+</tt> does not directly indicate
304
+ # the server's limits, it's best to avoid sending very large
305
+ # non-synchronized literals.
306
+ #
307
+ # ==== Versioned Defaults
308
+ #
309
+ # max_non_synchronizing_literal <em>was added in +v0.6.4+.</em>
310
+ #
311
+ # * original: +-1+ (_never_ send non-synchronizing literals)
312
+ # * +0.6+: 16 KiB
313
+ attr_accessor :max_non_synchronizing_literal, type: Integer?, defaults: {
314
+ 0.0r => -1,
315
+ 0.6r => 16 << 16, # 16 KiB
316
+ }
270
317
 
271
318
  # The maximum allowed server response size. When +nil+, there is no limit
272
319
  # on response size.
@@ -300,7 +347,10 @@ module Net
300
347
  #
301
348
  # * original: +nil+ <em>(no limit)</em>
302
349
  # * +0.5+: 512 MiB
303
- attr_accessor :max_response_size, type: Integer?
350
+ attr_accessor :max_response_size, type: Integer?, defaults: {
351
+ 0.0r => nil,
352
+ 0.5r => 512 << 20, # 512 MiB
353
+ }
304
354
 
305
355
  # Controls the behavior of Net::IMAP#responses when called without any
306
356
  # arguments (+type+ or +block+).
@@ -330,7 +380,11 @@ module Net
330
380
  # Note: #responses_without_args is an alias for #responses_without_block.
331
381
  attr_accessor :responses_without_block, type: Enum[
332
382
  :silence_deprecation_warning, :warn, :frozen_dup, :raise,
333
- ]
383
+ ], defaults: {
384
+ 0.0r => :silence_deprecation_warning,
385
+ 0.5r => :warn,
386
+ 0.6r => :frozen_dup,
387
+ }
334
388
 
335
389
  alias responses_without_args responses_without_block # :nodoc:
336
390
  alias responses_without_args= responses_without_block= # :nodoc:
@@ -340,66 +394,69 @@ module Net
340
394
  #
341
395
  # Alias for responses_without_block
342
396
 
343
- # Whether ResponseParser should use the deprecated UIDPlusData or
344
- # CopyUIDData for +COPYUID+ response codes, and UIDPlusData or
345
- # AppendUIDData for +APPENDUID+ response codes.
397
+ # **NOTE:** <em>+UIDPlusData+ has been removed since +v0.6.0+, and this
398
+ # config option only affects deprecation warnings.
399
+ # This config option will be **removed** in +v0.7.0+.</em>
346
400
  #
347
- # UIDPlusData stores its data in arrays of numbers, which is vulnerable to
348
- # a memory exhaustion denial of service attack from an untrusted or
349
- # compromised server. Set this option to +false+ to completely block this
350
- # vulnerability. Otherwise, parser_max_deprecated_uidplus_data_size
351
- # mitigates this vulnerability.
401
+ # ResponseParser always returns CopyUIDData for +COPYUID+ response codes,
402
+ # and AppendUIDData for +APPENDUID+ response codes. Previously, this
403
+ # option determined when UIDPlusData would be returned instead.
352
404
  #
353
- # AppendUIDData and CopyUIDData are _mostly_ backward-compatible with
354
- # UIDPlusData. Most applications should be able to upgrade with little
355
- # or no changes.
405
+ # Parser support for +UIDPLUS+ added in +v0.3.2+.
356
406
  #
357
- # <em>(Parser support for +UIDPLUS+ added in +v0.3.2+.)</em>
407
+ # Config option added in +v0.4.19+ and +v0.5.6+.
358
408
  #
359
- # <em>(Config option added in +v0.4.19+ and +v0.5.6+.)</em>
409
+ # <em>UIDPlusData removed in +v0.6.0+.</em>
360
410
  #
361
- # <em>UIDPlusData will be removed in +v0.6+ and this config setting will
362
- # be ignored.</em>
363
- #
364
- # ==== Valid options
411
+ # ==== Options
365
412
  #
366
413
  # [+true+ <em>(original default)</em>]
367
- # ResponseParser only uses UIDPlusData.
414
+ # <em>Since v0.6.0:</em>
415
+ # Prints a deprecation warning when parsing +COPYUID+ or +APPENDUID+.
368
416
  #
369
417
  # [+:up_to_max_size+ <em>(default since +v0.5.6+)</em>]
370
- # ResponseParser uses UIDPlusData when the +uid-set+ size is below
371
- # parser_max_deprecated_uidplus_data_size. Above that size,
372
- # ResponseParser uses AppendUIDData or CopyUIDData.
418
+ # <em>Since v0.6.0:</em>
419
+ # Prints a deprecation warning when parsing +COPYUID+ or +APPENDUID+.
373
420
  #
374
- # [+false+ <em>(planned default for +v0.6+)</em>]
375
- # ResponseParser _only_ uses AppendUIDData and CopyUIDData.
421
+ # [+false+ <em>(default since +v0.6.0+)</em>]
422
+ # This is the only supported option <em>(since v0.6.0)</em>.
376
423
  attr_accessor :parser_use_deprecated_uidplus_data, type: Enum[
377
424
  true, :up_to_max_size, false
378
- ]
425
+ ], defaults: {
426
+ 0.0r => true,
427
+ 0.5r => :up_to_max_size,
428
+ 0.6r => false,
429
+ }
379
430
 
380
- # The maximum +uid-set+ size that ResponseParser will parse into
381
- # deprecated UIDPlusData. This limit only applies when
382
- # parser_use_deprecated_uidplus_data is not +false+.
431
+ # **NOTE:** <em>+UIDPlusData+ has been removed since +v0.6.0+, and this
432
+ # config option is ignored.
433
+ # This config option will be **removed** in +v0.7.0+.</em>
383
434
  #
384
- # <em>(Parser support for +UIDPLUS+ added in +v0.3.2+.)</em>
435
+ # ResponseParser always returns CopyUIDData for +COPYUID+ response codes,
436
+ # and AppendUIDData for +APPENDUID+ response codes. Previously, this
437
+ # option determined when UIDPlusData would be returned instead.
385
438
  #
386
- # <em>Support for limiting UIDPlusData to a maximum size was added in
387
- # +v0.3.8+, +v0.4.19+, and +v0.5.6+.</em>
439
+ # Parser support for +UIDPLUS+ added in +v0.3.2+.
388
440
  #
389
- # <em>UIDPlusData will be removed in +v0.6+.</em>
441
+ # Support for limiting UIDPlusData to a maximum size was added in
442
+ # +v0.3.8+, +v0.4.19+, and +v0.5.6+.
390
443
  #
391
- # ==== Versioned Defaults
444
+ # <em>UIDPlusData was removed in +v0.6.0+.</em>
392
445
  #
393
- # Because this limit guards against a remote server causing catastrophic
394
- # memory exhaustion, the versioned default (used by #load_defaults) also
395
- # applies to versions without the feature.
446
+ # ==== Versioned Defaults
396
447
  #
397
448
  # * +0.3+ and prior: <tt>10,000</tt>
398
449
  # * +0.4+: <tt>1,000</tt>
399
450
  # * +0.5+: <tt>100</tt>
400
451
  # * +0.6+: <tt>0</tt>
401
452
  #
402
- attr_accessor :parser_max_deprecated_uidplus_data_size, type: Integer
453
+ attr_accessor :parser_max_deprecated_uidplus_data_size, type: Integer,
454
+ defaults: {
455
+ 0.0r => 10_000,
456
+ 0.4r => 1_000,
457
+ 0.5r => 100,
458
+ 0.6r => 0,
459
+ }
403
460
 
404
461
  # Creates a new config object and initialize its attribute with +attrs+.
405
462
  #
@@ -468,85 +525,150 @@ module Net
468
525
  # Returns all config attributes in a hash.
469
526
  def to_h; data.members.to_h { [_1, send(_1)] } end
470
527
 
528
+ # Returns a string representation of overriden config attributes and the
529
+ # inheritance chain.
530
+ #
531
+ # Attributes overridden by ancestors are also inspected, recursively.
532
+ # Attributes that are inherited from default configs are not shown (see
533
+ # Config@Versioned+defaults and Config@Named+defaults).
534
+ #
535
+ # # (Line breaks have been added to the example output for legibility.)
536
+ #
537
+ # Net::IMAP::Config.new(0.4)
538
+ # .new(open_timeout: 10, enforce_logindisabled: true)
539
+ # .inspect
540
+ # #=> "#<Net::IMAP::Config:0x0000745871125410 open_timeout=10 enforce_logindisabled=true
541
+ # # inherits from Net::IMAP::Config[0.4]
542
+ # # inherits from Net::IMAP::Config.global
543
+ # # inherits from Net::IMAP::Config.default>"
544
+ #
545
+ # Non-default attributes are listed after the ancestor config from which
546
+ # they are inherited.
547
+ #
548
+ # # (Line breaks have been added to the example output for legibility.)
549
+ #
550
+ # config = Net::IMAP::Config.global
551
+ # .new(open_timeout: 10, idle_response_timeout: 2)
552
+ # .new(enforce_logindisabled: :when_capabilities_cached, sasl_ir: false)
553
+ # config.inspect
554
+ # #=> "#<Net::IMAP::Config:0x00007ce2a1e20e40 sasl_ir=false enforce_logindisabled=:when_capabilities_cached
555
+ # # inherits from Net::IMAP::Config:0x00007ce2a1e20f80 open_timeout=10 idle_response_timeout=2
556
+ # # inherits from Net::IMAP::Config.global
557
+ # # inherits from Net::IMAP::Config.default>"
558
+ #
559
+ # Net::IMAP.debug = true
560
+ # config.inspect
561
+ # #=> "#<Net::IMAP::Config:0x00007ce2a1e20e40 sasl_ir=false enforce_logindisabled=:when_capabilities_cached
562
+ # # inherits from Net::IMAP::Config:0x00007ce2a1e20f80 open_timeout=10 idle_response_timeout=2
563
+ # # inherits from Net::IMAP::Config.global debug=true
564
+ # # inherits from Net::IMAP::Config.default>"
565
+ #
566
+ # Use +pp+ (see #pretty_print) to inspect _all_ config attributes,
567
+ # including default values.
568
+ #
569
+ # Use #to_h to inspect all config attributes ignoring inheritance.
570
+ def inspect;
571
+ "#<#{inspect_recursive}>"
572
+ end
573
+ alias to_s inspect
574
+
575
+ # Used by PP[https://docs.ruby-lang.org/en/master/PP.html] to create a
576
+ # string representation of all config attributes and the inheritance
577
+ # chain. Inherited attributes are listed with the ancestor config from
578
+ # which they are inherited.
579
+ #
580
+ # pp Config.new[0.4].new(open_timeout: 10, idle_response_timeout: 10)
581
+ # # #<Net::IMAP::Config:0x0000745871125410
582
+ # # open_timeout=10
583
+ # # idle_response_timeout=10
584
+ # # inherits from Net::IMAP::Config[0.4]
585
+ # # responses_without_block=:silence_deprecation_warning
586
+ # # max_response_size=nil
587
+ # # sasl_ir=true
588
+ # # enforce_logindisabled=false
589
+ # # parser_use_deprecated_uidplus_data=true
590
+ # # parser_max_deprecated_uidplus_data_size=1000
591
+ # # inherits from Net::IMAP::Config.global
592
+ # # inherits from Net::IMAP::Config.default
593
+ # # debug=false>
594
+ #
595
+ # Related: #inspect, #to_h.
596
+ def pretty_print(pp)
597
+ pp.group(2, "#<", ">") do
598
+ pretty_print_recursive(pp)
599
+ end
600
+ end
601
+
602
+ # :stopdoc:
603
+
471
604
  protected
472
605
 
473
- def defaults_hash
474
- to_h.reject {|k,v| DEFAULT_TO_INHERIT.include?(k) }
606
+ def named_default?
607
+ equal?(Config.default) ||
608
+ AttrVersionDefaults::VERSIONS.any? { equal? Config[_1] }
475
609
  end
476
610
 
477
- @default = new(
478
- debug: false,
479
- open_timeout: 30,
480
- idle_response_timeout: 5,
481
- sasl_ir: true,
482
- enforce_logindisabled: true,
483
- max_response_size: 512 << 20, # 512 MiB
484
- responses_without_block: :warn,
485
- parser_use_deprecated_uidplus_data: :up_to_max_size,
486
- parser_max_deprecated_uidplus_data_size: 100,
487
- ).freeze
488
-
489
- @global = default.new
490
-
491
- version_defaults[:default] = Config[default.send(:defaults_hash)]
492
-
493
- version_defaults[0r] = Config[:default].dup.update(
494
- sasl_ir: false,
495
- responses_without_block: :silence_deprecation_warning,
496
- enforce_logindisabled: false,
497
- max_response_size: nil,
498
- parser_use_deprecated_uidplus_data: true,
499
- parser_max_deprecated_uidplus_data_size: 10_000,
500
- ).freeze
501
- version_defaults[0.0r] = Config[0r]
502
- version_defaults[0.1r] = Config[0r]
503
- version_defaults[0.2r] = Config[0r]
504
- version_defaults[0.3r] = Config[0r]
505
-
506
- version_defaults[0.4r] = Config[0.3r].dup.update(
507
- sasl_ir: true,
508
- parser_max_deprecated_uidplus_data_size: 1000,
509
- ).freeze
510
-
511
- version_defaults[0.5r] = Config[0.4r].dup.update(
512
- enforce_logindisabled: true,
513
- max_response_size: 512 << 20, # 512 MiB
514
- responses_without_block: :warn,
515
- parser_use_deprecated_uidplus_data: :up_to_max_size,
516
- parser_max_deprecated_uidplus_data_size: 100,
517
- ).freeze
518
-
519
- version_defaults[0.6r] = Config[0.5r].dup.update(
520
- responses_without_block: :frozen_dup,
521
- parser_use_deprecated_uidplus_data: false,
522
- parser_max_deprecated_uidplus_data_size: 0,
523
- ).freeze
524
-
525
- version_defaults[0.7r] = Config[0.6r].dup.update(
526
- ).freeze
527
-
528
- # Safe conversions one way only:
529
- # 0.6r.to_f == 0.6 # => true
530
- # 0.6 .to_r == 0.6r # => false
531
- version_defaults.to_a.each do |k, v|
532
- next unless k in Rational
533
- version_defaults[k.to_f] = v
611
+ def name
612
+ if equal? Config.default then "#{Config}.default"
613
+ elsif equal? Config.global then "#{Config}.global"
614
+ elsif equal? Config[0.0r] then "#{Config}[:original]"
615
+ elsif (v = AttrVersionDefaults::VERSIONS.find { equal? Config[_1] })
616
+ "%s[%0.1f]" % [Config, v]
617
+ else
618
+ Kernel.instance_method(:to_s).bind_call(self).delete("<#>")
619
+ end
534
620
  end
535
621
 
536
- current = VERSION.to_r
537
- version_defaults[:original] = Config[0]
538
- version_defaults[:current] = Config[current]
539
- version_defaults[:next] = Config[current + 0.1r]
540
- version_defaults[:future] = Config[current + 0.2r]
622
+ def inspect_recursive(attrs = AttrAccessors.struct.members)
623
+ strings = [name]
624
+ assigned = assigned_attrs_hash(attrs)
625
+ strings.concat assigned.map { "%s=%p" % _1 }
626
+ if parent
627
+ if parent.equal?(Config.default)
628
+ inherited_overrides = []
629
+ elsif parent
630
+ inherited_overrides = attrs - assigned.keys
631
+ inherited_overrides &= DEFAULT_TO_INHERIT if parent.named_default?
632
+ end
633
+ strings << "inherits from #{parent.inspect_recursive(inherited_overrides)}"
634
+ end
635
+ strings.join " "
636
+ end
541
637
 
542
- version_defaults.freeze
638
+ def pretty_print_recursive(pp, attrs = AttrAccessors.struct.members)
639
+ pp.text name
640
+ assigned = assigned_attrs_hash(attrs)
641
+ pp.breakable
642
+ pp.seplist(assigned, ->{pp.breakable}) do |key, val|
643
+ pp.text key.to_s
644
+ pp.text "="
645
+ pp.pp val
646
+ end
647
+ if parent
648
+ pp.breakable if assigned.any?
649
+ pp.nest(2) do
650
+ pp.text "inherits from "
651
+ parent.pretty_print_recursive(pp, attrs - assigned.keys)
652
+ end
653
+ elsif assigned.empty?
654
+ pp.text "(overridden)"
655
+ end
656
+ end
543
657
 
544
- if ($VERBOSE || $DEBUG) && self[:current].to_h != self[:default].to_h
545
- warn "Misconfigured Net::IMAP::Config[:current] => %p,\n" \
546
- " not equal to Net::IMAP::Config[:default] => %p" % [
547
- self[:current].to_h, self[:default].to_h
548
- ]
658
+ def assigned_attrs_hash(attrs)
659
+ own_attrs = attrs.reject { inherited?(_1) }
660
+ own_attrs.to_h { [_1, data[_1]] }
661
+ end
662
+
663
+ def defaults_hash
664
+ to_h.reject {|k,v| DEFAULT_TO_INHERIT.include?(k) }
549
665
  end
666
+
667
+ Struct = AttrAccessors.struct
668
+ @default = AttrVersionDefaults.compile_default!
669
+ @global = default.new
670
+ AttrVersionDefaults.compile_version_defaults!
671
+
550
672
  end
551
673
  end
552
674
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Net
4
4
  class IMAP
5
- class ConnectionState < Net::IMAP::Data # :nodoc:
5
+ class ConnectionState < Data # :nodoc:
6
6
  def self.define(symbol, *attrs)
7
7
  symbol => Symbol
8
8
  state = super(*attrs)
@@ -155,57 +155,156 @@ module Net
155
155
 
156
156
  # Common validators of number and nz_number types
157
157
  module NumValidator # :nodoc
158
+ NUMBER_RE = /\A(?:0|[1-9]\d*)\z/
158
159
  module_function
159
160
 
160
- # Check is passed argument valid 'number' in RFC 3501 terminology
161
+ # Check if argument is a valid 'number' according to RFC 3501
162
+ # number = 1*DIGIT
163
+ # ; Unsigned 32-bit integer
164
+ # ; (0 <= n < 4,294,967,296)
161
165
  def valid_number?(num)
162
- # [RFC 3501]
163
- # number = 1*DIGIT
164
- # ; Unsigned 32-bit integer
165
- # ; (0 <= n < 4,294,967,296)
166
- num >= 0 && num < 4294967296
166
+ 0 <= num && num <= 0xffff_ffff
167
167
  end
168
168
 
169
- # Check is passed argument valid 'nz_number' in RFC 3501 terminology
169
+ # Check if argument is a valid 'nz-number' according to RFC 3501
170
+ # nz-number = digit-nz *DIGIT
171
+ # ; Non-zero unsigned 32-bit integer
172
+ # ; (0 < n < 4,294,967,296)
170
173
  def valid_nz_number?(num)
171
- # [RFC 3501]
172
- # nz-number = digit-nz *DIGIT
173
- # ; Non-zero unsigned 32-bit integer
174
- # ; (0 < n < 4,294,967,296)
175
- num != 0 && valid_number?(num)
174
+ 0 < num && num <= 0xffff_ffff
176
175
  end
177
176
 
178
- # Check is passed argument valid 'mod_sequence_value' in RFC 4551 terminology
177
+ # Check if argument is a valid 'number64' according to RFC 9051
178
+ # number64 = 1*DIGIT
179
+ # ; Unsigned 63-bit integer
180
+ # ; (0 <= n <= 9,223,372,036,854,775,807)
181
+ def valid_number64?(num)
182
+ 0 <= num && num <= 0x7fff_ffff_ffff_ffff
183
+ end
184
+
185
+ # Check if argument is a valid 'number64' according to RFC 9051
186
+ # nz-number64 = digit-nz *DIGIT
187
+ # ; Unsigned 63-bit integer
188
+ # ; (0 < n <= 9,223,372,036,854,775,807)
189
+ def valid_nz_number64?(num)
190
+ 0 < num && num <= 0x7fff_ffff_ffff_ffff
191
+ end
192
+
193
+ # Check if argument is a valid 'mod-sequence-value' according to RFC 4551
194
+ # mod-sequence-value = 1*DIGIT
195
+ # ; Positive unsigned 64-bit integer
196
+ # ; (mod-sequence)
197
+ # ; (1 <= n < 18,446,744,073,709,551,615)
179
198
  def valid_mod_sequence_value?(num)
180
- # mod-sequence-value = 1*DIGIT
181
- # ; Positive unsigned 64-bit integer
182
- # ; (mod-sequence)
183
- # ; (1 <= n < 18,446,744,073,709,551,615)
184
- num >= 1 && num < 18446744073709551615
199
+ 1 <= num && num < 0xffff_ffff_ffff_ffff
200
+ end
201
+
202
+ # Check if argument is a valid 'mod-sequence-valzer' according to RFC 4551
203
+ # mod-sequence-valzer = "0" / mod-sequence-value
204
+ def valid_mod_sequence_valzer?(num)
205
+ 0 <= num && num < 0xffff_ffff_ffff_ffff
185
206
  end
186
207
 
187
208
  # Ensure argument is 'number' or raise DataFormatError
188
209
  def ensure_number(num)
189
210
  return num if valid_number?(num)
190
-
191
- msg = "number must be unsigned 32-bit integer: #{num}"
192
- raise DataFormatError, msg
211
+ raise DataFormatError,
212
+ "number must be unsigned 32-bit integer: #{num}"
193
213
  end
194
214
 
195
- # Ensure argument is 'nz_number' or raise DataFormatError
215
+ # Ensure argument is 'nz-number' or raise DataFormatError
196
216
  def ensure_nz_number(num)
197
217
  return num if valid_nz_number?(num)
218
+ raise DataFormatError,
219
+ "nz-number must be non-zero unsigned 32-bit integer: #{num}"
220
+ end
221
+
222
+ # Ensure argument is 'number64' or raise DataFormatError
223
+ def ensure_number64(num)
224
+ return num if valid_number64?(num)
225
+ raise DataFormatError,
226
+ "number64 must be unsigned 63-bit integer: #{num}"
227
+ end
198
228
 
199
- msg = "nz_number must be non-zero unsigned 32-bit integer: #{num}"
200
- raise DataFormatError, msg
229
+ # Ensure argument is 'nz-number64' or raise DataFormatError
230
+ def ensure_nz_number64(num)
231
+ return num if valid_nz_number64?(num)
232
+ raise DataFormatError,
233
+ "nz-number64 must be non-zero unsigned 63-bit integer: #{num}"
201
234
  end
202
235
 
203
- # Ensure argument is 'mod_sequence_value' or raise DataFormatError
236
+ # Ensure argument is 'mod-sequence-value' or raise DataFormatError
204
237
  def ensure_mod_sequence_value(num)
205
238
  return num if valid_mod_sequence_value?(num)
239
+ raise DataFormatError,
240
+ "mod-sequence-value must be non-zero unsigned 64-bit integer: #{num}"
241
+ end
206
242
 
207
- msg = "mod_sequence_value must be unsigned 64-bit integer: #{num}"
208
- raise DataFormatError, msg
243
+ # Ensure argument is 'mod-sequence-valzer' or raise DataFormatError
244
+ def ensure_mod_sequence_valzer(num)
245
+ return num if valid_mod_sequence_valzer?(num)
246
+ raise DataFormatError,
247
+ "mod-sequence-valzer must be unsigned 64-bit integer: #{num}"
248
+ end
249
+
250
+ # Like #ensure_number, but usable with numeric String input.
251
+ def coerce_number(num)
252
+ case num
253
+ when Integer then ensure_number num
254
+ when NUMBER_RE then ensure_number Integer num
255
+ else
256
+ raise DataFormatError, "%p is not a valid number" % [num]
257
+ end
258
+ end
259
+
260
+ # Like #ensure_nz_number, but usable with numeric String input.
261
+ def coerce_nz_number(num)
262
+ case num
263
+ when Integer then ensure_nz_number num
264
+ when NUMBER_RE then ensure_nz_number Integer num
265
+ else
266
+ raise DataFormatError, "%p is not a valid nz-number" % [num]
267
+ end
268
+ end
269
+
270
+ # Like #ensure_number64, but usable with numeric String input.
271
+ def coerce_number64(num)
272
+ case num
273
+ when Integer then ensure_number64 num
274
+ when NUMBER_RE then ensure_number64 Integer num
275
+ else
276
+ raise DataFormatError, "%p is not a valid number64" % [num]
277
+ end
278
+ end
279
+
280
+ # Like #ensure_nz_number64, but usable with numeric String input.
281
+ def coerce_nz_number64(num)
282
+ case num
283
+ when Integer then ensure_nz_number64 num
284
+ when NUMBER_RE then ensure_nz_number64 Integer num
285
+ else
286
+ raise DataFormatError, "%p is not a valid nz-number64" % [num]
287
+ end
288
+ end
289
+
290
+ # Like #ensure_mod_sequence_value, but usable with numeric String input.
291
+ def coerce_mod_sequence_value(num)
292
+ case num
293
+ when Integer then ensure_mod_sequence_value num
294
+ when NUMBER_RE then ensure_mod_sequence_value Integer num
295
+ else
296
+ raise DataFormatError, "%p is not a valid mod-sequence-value" % [num]
297
+ end
298
+ end
299
+
300
+ # Like #ensure_mod_sequence_valzer, but usable with numeric String input.
301
+ def coerce_mod_sequence_valzer(num)
302
+ case num
303
+ when Integer then ensure_mod_sequence_valzer num
304
+ when NUMBER_RE then ensure_mod_sequence_valzer Integer num
305
+ else
306
+ raise DataFormatError, "%p is not a valid mod-sequence-valzer" % [num]
307
+ end
209
308
  end
210
309
 
211
310
  end