range_extd 1.1.1 → 2.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.
@@ -1,31 +1,22 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
- ## Load required files.
4
- err1st = nil
5
- req_files = %w(lib/range_extd/infinity/infinity)
3
+ ## Load required files in this library. (At the end of this file, "range_extd/range" is also required.)
4
+ req_files = %w(range_extd/infinity range_extd/nowhere range_extd/nil_class)
6
5
  req_files.each do |req_file|
7
- while ! req_file.empty?
8
- begin
9
- require req_file
10
- rescue LoadError => errLoad
11
- err1st = errLoad if err1st.nil?
12
- if %r@/@ =~ req_file
13
- if req_file.sub!(%r@[^/]*/@, '').nil? # Will search for the next directory down.
14
- raise
15
- end
16
- else
17
- req_file = ''
18
- break
19
- end
20
- else
21
- break
22
- end
6
+ begin
7
+ require_relative req_file
8
+ rescue LoadError
9
+ require req_file
23
10
  end
24
- if req_file.empty?
25
- raise err1st
26
- end
27
- end # req_files.each do |req_file|
11
+ end
28
12
 
13
+ if $DEBUG
14
+ puts "NOTE: Library full paths:"
15
+ req_files.each do |elibbase|
16
+ ar = $LOADED_FEATURES.grep(/(^|\/)#{Regexp.quote(File.basename(elibbase))}(\.rb)?$/).uniq
17
+ print elibbase+": " if ar.empty?; p ar
18
+ end
19
+ end
29
20
 
30
21
  # =Class RangeExtd
31
22
  #
@@ -36,20 +27,22 @@ end # req_files.each do |req_file|
36
27
  #
37
28
  # Extended Range class that features:
38
29
  # 1. includes exclude_begin? (to exclude the "begin" boundary),
39
- # 2. allows open-ended range (to the infinity),
30
+ # 2. allows open-ended range to the infinity (very similar to beginless/endless Range),
40
31
  # 3. defines NONE and ALL constants,
41
32
  # 4. the first self-consistent logical structure,
42
- # 5. complete backward compatibility within the built-in Range.
33
+ # 5. complete compatibility with the built-in Range.
43
34
  #
44
35
  # The instance of this class is immutable, that is, you can not
45
36
  # alter the element once an instance is generated.
46
37
  #
38
+ # This class has some constants
39
+ #
47
40
  # What is valid is checked with the class method {RangeExtd.valid?}.
48
41
  # See the document of that method for the definition.
49
42
  #
50
- # To express open-ended ranges is simple; you just use either of
51
- # the two (negative and positive, or former and later) constants
52
- # in RangeExtd::Infinity class. See the document for detail.
43
+ # This class has two constants:
44
+ # {RangeExtd::NONE} representing an empty range and
45
+ # {RangeExtd::ALL} representing the entire range, both in the abstract sense.
53
46
  #
54
47
  # @example An instance of a range of 5 to 8 with both ends being exclusive is created as
55
48
  # r = RangeExtd(5...8, true)
@@ -93,7 +86,7 @@ class RangeExtd < Range
93
86
  # @option opts [Boolean] :exclude_end If specified, this has the highest priority, or false in default.
94
87
  #
95
88
  # @overload new(obj_begin, obj_end, [exclude_begin=false, [exclude_end=false]], opts)
96
- # @param obj_begin [Object] Any object that is {Comparable} with end
89
+ # @param obj_begin [Object] Any object that is +Comparable+ with end
97
90
  # @param obj_end [Object] Any object that is Comparable with begin
98
91
  # @param exclude_begin [Boolean] If specified, this has the lower priority, or false in default.
99
92
  # @param exclude_end [Boolean] If specified, this has the lower priority, or false in default.
@@ -101,9 +94,9 @@ class RangeExtd < Range
101
94
  # @option opts [Boolean] :exclude_end If specified, this has the higher priority, or false in default.
102
95
  #
103
96
  # @overload new(obj_begin, string_form, obj_end, [exclude_begin=false, [exclude_end=false]], opts)
104
- # @param obj_begin [Object] Any object that is {Comparable} with end
97
+ # @param obj_begin [Object] Any object that is +Comparable+ with end
105
98
  # @param string_form [Object] String form (without pre/postfix) of range expression set by {RangeExtd.middle_strings=}()
106
- # @param obj_end [Object] Any object that is Comparable with begin
99
+ # @param obj_end [Object] Any object that is +Comparable+ with begin
107
100
  # @param exclude_begin [Boolean] If specified, this has the lower priority, or false in default.
108
101
  # @param exclude_end [Boolean] If specified, this has the lower priority, or false in default.
109
102
  # @option opts [Boolean] :exclude_begin If specified, this has the higher priority, or false in default.
@@ -126,17 +119,31 @@ class RangeExtd < Range
126
119
  # @raise [ArgumentError] particularly if the range to be created is not {#valid?}.
127
120
  def initialize(*inar, **hsopt) # **k expression from Ruby 1.9?
128
121
 
122
+ # This is true only for RangeExtd::NONE,
123
+ # which is identical to +RangeExtd(nil, nil, true, true)+ without this.
124
+ @is_none = false
125
+
129
126
  if inar[4] == :Constant
130
- # Special case to create two Constants
131
- super(*inar[0..2])
127
+ # Special case to create two Constants (NONE and ALL)
132
128
  @rangepart = (inar[2] ? (inar[0]...inar[1]) : (inar[0]..inar[1]))
133
129
  @exclude_end, @exclude_begin = inar[2..3]
130
+
131
+ # In Ruby-2.7+ and hence RangeExtd Ver.2+, RangeExtd::NONE looks very similar to (nil...nil)
132
+ # except RangeExtd::NONE.@exclude_begin == true
133
+ #@is_none = (@rangepart.begin.nil? && @rangepart.end.nil? && @exclude_begin && @exclude_end)
134
+ @is_none = (@rangepart.begin.respond_to?(:nowhere?) &&
135
+ @rangepart.begin.nowhere? &&
136
+ @rangepart.end.respond_to?(:nowhere?) &&
137
+ @rangepart.end.nowhere? &&
138
+ @exclude_begin &&
139
+ @exclude_end)
140
+ raise(ArgumentError, "NONE has been already defined.") if @is_none && self.class.const_defined?(:NONE)
141
+ super(*inar[0..2])
134
142
  return
135
143
  end
136
144
 
137
- # Note: the order of exclude_begin? and end? is reversed from the input!
138
145
  arout = RangeExtd.send(:_get_init_args, *inar, **hsopt)
139
- # == [RangeBeginValue, RangeEndValue, exclude_end?, exclude_begin?]
146
+ # == [RangeBeginValue, RangeEndValue, exclude_begin?, exclude_end?]
140
147
 
141
148
  ### The following routine is obsolete.
142
149
  ### Users, if they wish, should call RangeExtd::Infinity.overwrite_compare() beforehand.
@@ -171,30 +178,27 @@ class RangeExtd < Range
171
178
  raise RangeError, "the combination of the arguments does not constitute a valid RangeExtd instance."
172
179
  end
173
180
 
181
+ @exclude_end = arout.pop
174
182
  @exclude_begin = arout.pop
175
- @exclude_end = arout[-1]
176
- @rangepart = Range.new(*arout)
177
- super(*arout)
178
-
179
- end # def initialize(*inar)
183
+ artmp = [arout[0], arout[1], @exclude_end]
184
+ @rangepart = Range.new(*artmp)
185
+ super(*artmp)
186
+ end # def initialize(*inar, **hsopt)
180
187
 
181
188
 
182
189
  # true if self is identical to {RangeExtd::NONE}.
190
+ #
191
+ # Overwriting {Range#is_none?}
183
192
  # This is different from {#==} method!
193
+ #
184
194
  # @example
185
- # RangeExtd(0,0,false,false) == RangeExtd::NONE # => true
186
- # RangeExtd(0,0,false,false).empty? # => true
187
- # RangeExtd(0,0,false,false).is_none? # => false
195
+ # RangeExtd(0,0,true,true).valid? # => true
196
+ # RangeExtd(0,0,true,true) == RangeExtd::NONE # => true
197
+ # RangeExtd(0,0,true,true).empty? # => true
198
+ # RangeExtd(0,0,true,true).is_none? # => false
188
199
  # RangeExtd::NONE.is_none? # => true
189
200
  def is_none?
190
- self.begin.nil? && self.end.nil? && @exclude_begin && @exclude_end # Direct comparison with object_id should be OK?
191
- end
192
-
193
- # true if self is identical to {RangeExtd::ALL} ({#==} does not mean it at all!)
194
- # @example
195
- # (RangeExtd::Infinity::NEGATIVE..RangeExtd::Infinity::POSITIVE).is_all? # => false
196
- def is_all?
197
- self.begin.object_id == Infinity::NEGATIVE.object_id && self.end.object_id == Infinity::POSITIVE.object_id && !@exclude_begin && !@exclude_end # Direct comparison with object_id should not work for this one!! (because users can create an identical one.)
201
+ @is_none
198
202
  end
199
203
 
200
204
 
@@ -217,11 +221,10 @@ class RangeExtd < Range
217
221
  # this returns true, regardless of their boundary values.
218
222
  # And any empty range is equal to RangeExtd::Infinity::NONE.
219
223
  #
220
- # Note the last example will return false for {#eql?} -- see {#eql?}
221
- #
222
- # See {#eql?}
224
+ # Note the last example will return false for +#eql?+
223
225
  #
224
226
  # @example
227
+ # (1...1) == RangeExtd::NONE # => false (b/c the Range is invalid)
225
228
  # (1<...1) == RangeExtd::NONE # => true
226
229
  # (?a<...?b) == RangeExtd::NONE # => true
227
230
  # (1<...1) == (2<...2) # => true
@@ -232,25 +235,27 @@ class RangeExtd < Range
232
235
  #
233
236
  # @return [Boolean]
234
237
  def ==(r)
235
- re_equal_core(r, :==)
238
+ _re_equal_core(r, :==)
236
239
  end # def ==(r)
237
240
 
238
- # The same as {#==} but it uses eql?() as each comparison.
239
- # For the empty ranges, it is similar to {#==}, except
240
- # the immediate class has to agree to return true.
241
- # Only the exception is the comparison with RangeExtd::Infinity::NONE.
242
- # Therefore,
243
- # @example
244
- # (1...5) == (1.0...5.0) # => true
245
- # (1...5).eql?(1.0...5.0) # => false
246
- # (1<...1).eql?( RangeExtd::NONE) # => true
247
- # (?a<...?b).eql?(RangeExtd::NONE) # => true
248
- # (1<...1).eql?( 3<...4) # => true
249
- # (1.0<...1.0).eql?(3<...4) # => false
250
- #
251
- def eql?(r)
252
- re_equal_core(r, :eql?)
253
- end # def eql?(r)
241
+ # Modification to {#eql?} is dropped in RangeExtd Ver.2
242
+ #
243
+ ## The same as {#==} but it uses eql?() as each comparison.
244
+ ## For the empty ranges, it is similar to {#==}, except
245
+ ## the immediate class has to agree to return true.
246
+ ## Only the exception is the comparison with RangeExtd::Infinity::NONE.
247
+ ## Therefore,
248
+ ## @example
249
+ ## (1...5) == (1.0...5.0) # => true
250
+ ## (1...5).eql?(1.0...5.0) # => false
251
+ ## (1<...1).eql?( RangeExtd::NONE) # => true
252
+ ## (?a<...?b).eql?(RangeExtd::NONE) # => true
253
+ ## (1<...1).eql?( 3<...4) # => true
254
+ ## (1.0<...1.0).eql?(3<...4) # => false
255
+ ##
256
+ #def eql?(r)
257
+ # _re_equal_core(r, :eql?)
258
+ #end # def eql?(r)
254
259
 
255
260
 
256
261
  # If the object is open-ended to the negative (Infinity),
@@ -264,7 +269,7 @@ class RangeExtd < Range
264
269
  # In the case of the former, after finite trials of [#succ] from ?c, it reaches the end (?z).
265
270
  # In the latter, after finit trials of [#succ] from the begin ?a, it reaches the end (?z).
266
271
  # Therefore it is theoretically possible to prove it (n.b., the actual
267
- # algorithm of built-in {Range#include?} is different and cheating!
272
+ # algorithm of built-in +Range#include?+ is different and cheating!
268
273
  # See below.).
269
274
  #
270
275
  # However, in the case of
@@ -276,11 +281,11 @@ class RangeExtd < Range
276
281
  #
277
282
  # Note
278
283
  # (?B..?z) === 'dd' # => false
279
- # as Ruby's {Range} knows the algorithm of {String#succ} and {String#<=>}
280
- # and specifically checks with it, before using {Enumerable#include?}.
284
+ # as Ruby's {Range} knows the algorithm of +String#succ+ and +String#<=>+
285
+ # and specifically checks with it, before using +Enumerable#include?+.
281
286
  # {https://github.com/ruby/ruby/blob/trunk/range.c}
282
287
  #
283
- # Therefore, even if you change the definition of {String#succ}
288
+ # Therefore, even if you change the definition of +String#succ+
284
289
  # so that 'B'.succ => 'dd', 'dd'.succ => 'z', as follows,
285
290
  # class String
286
291
  # alias :succ_orig :succ
@@ -294,7 +299,7 @@ class RangeExtd < Range
294
299
  # end
295
300
  # end
296
301
  # end
297
- # the resutl of {Range#===} will unchange;
302
+ # the resutl of +Range#===+ will unchange;
298
303
  # (?B..?z) === 'dd' # => false
299
304
  # (?B..?z).to_a # => ["B", "dd", "z"]
300
305
  #
@@ -307,29 +312,31 @@ class RangeExtd < Range
307
312
  def ===(obj)
308
313
  # ("a".."z")===("cc") # => false
309
314
 
310
- return false if is_none? # No need of null?(), supposedly!
315
+ return false if empty? # n.b, NONE includes nothing, even NOWHERE (because of exclude_begin/end)
311
316
 
312
- begin
313
- 1.0+(obj) # OK if Numeric.
317
+ rapart = _converted_rangepart
318
+ beg = rapart.begin
319
+ if beg.nil? && !beg.nowhere?
320
+ return rapart.send(__method__, obj)
321
+ end
314
322
 
323
+ begin
324
+ _ = 1.0+obj # OK if Numeric.
325
+ return cover?(obj) # This excludes begin() if need be.
315
326
  rescue TypeError
316
- # obj is not Numeric, hence runs brute-force check.
317
- beg = self.begin()
318
- if defined?(beg.infinity?) && beg.infinity? || beg == -Infinity::FLOAT_INFINITY
319
- return nil
320
- # raise TypeError "can't iterate from -Infinity"
321
- end
327
+ end
322
328
 
323
- each do |ei|
324
- if ei == obj
325
- return true
326
- end
327
- end
328
- false
329
+ # obj is not Numeric, hence runs brute-force check.
330
+ beg = self.begin()
331
+ if beg.respond_to?(:infinity?) && beg.infinity?
332
+ return nil
333
+ # raise TypeError "can't iterate from -Infinity"
334
+ end
329
335
 
330
- else
331
- cover?(obj)
336
+ each do |ei| # This excludes begin() if need be.
337
+ return true if ei == obj
332
338
  end
339
+ false
333
340
  end # def ===(obj)
334
341
 
335
342
  alias :include? :===
@@ -443,8 +450,8 @@ class RangeExtd < Range
443
450
  # (Rational(36,10)..5).bsearch{|i| ary[i] >= 11} => # TypeError: can't do binary search for Rational (Ruby 2.1)
444
451
  # (3..Rational(61,10)).bsearch{|i| ary[i] >= 11} => # TypeError: can't do binary search for Fixnum (Ruby 2.1)
445
452
  #
446
- # In short, bsearch works only with Integer and/or Float (as in Ruby 2.1).
447
- # If either of begin and end is an Float, the search is conducted in Float and the returned value will be Float, unless nil.
453
+ # +Range#bsearch+ works only with Integer and/or Float (as in Ruby 2.1), not even Rational (as in Ruby 3.1).
454
+ # If either of begin and end is a Float, the search is conducted in Float and the returned value will be a Float, unless nil.
448
455
  # If Float, it searches on the binary plane.
449
456
  # If Integer, the search is conducted on the descrete Integer points only,
450
457
  # and no search will be made in between the adjascent integers.
@@ -452,7 +459,7 @@ class RangeExtd < Range
452
459
  # Given that, {RangeExtd#bsearch} follows basically the same, even when exclude_begin? is true.
453
460
  # If either end is Float, it searches between begin*(1+Float::EPSILON) and end.
454
461
  # If both are Integer, it searches from begin+1.
455
- # When {#exclude_begin?} is false, {RangeExtd#bsearch} is identical to {Range#bsearch}.
462
+ # When {#exclude_begin?} is false, {RangeExtd#bsearch} is identical to +Range#bsearch+.
456
463
  #
457
464
  def bsearch(*rest, &bloc)
458
465
  if is_none? # No need of null?(), supposedly!
@@ -482,97 +489,110 @@ class RangeExtd < Range
482
489
  end # def bsearch(*rest, &bloc)
483
490
 
484
491
 
485
- # See {#include?} or {#===}, and {Range#cover?}
492
+ # This works without modification mostly.
493
+ #
494
+ # Presumably because Enumerable#count is called and #each is internally used.
495
+ # Exceptions are infinities and borderless (nil).
496
+ #
497
+ # (5..).count # => Float::INFINITY # exceptional case
498
+ # (..5).count # => Float::INFINITY # exceptional case
499
+ # (..nil).count # => Float::INFINITY # exceptional case
500
+ # (-Float::INFINITY..nil) # => Float::INFINITY # exceptional case
501
+ # (-Float::INFINITY..Float::INFINITY).count # raises (TypeError) "can't iterate from Float"
502
+ # (..5).count(4) # raises (TypeError)
503
+ # (..5).count{|i| i<3} # raises (TypeError)
504
+ # (1..).count{|i| i<3} # infinite loop!
505
+ #
506
+ # Here I define as another exceptional case:
507
+ # RangeExtd::ALL.count # => Float::INFINITY
508
+ #
509
+ # @return [Integer]
510
+ def count(*rest, &block)
511
+ return Float::INFINITY if self == RangeExtd::ALL
512
+ super
513
+ end
514
+
515
+
516
+ # See {#include?} or {#===}, and +Range#cover?+
486
517
  def cover?(i)
487
518
  # ("a".."z").cover?("cc") # => true
488
519
  # (?B..?z).cover?('dd') # => true (though 'dd'.succ would never reach ?z)
489
520
 
490
- return false if is_none? # No need of null?(), supposedly!
521
+ return false if empty? # equivalent to null? in this case because self is alwasy true==valid?
491
522
 
492
- if @exclude_begin
493
- if self.begin == i
494
- false
495
- else
496
- @rangepart.send(__method__, i)
497
- end
523
+ if @exclude_begin && self.begin == i
524
+ false
498
525
  else
499
526
  @rangepart.send(__method__, i)
500
527
  end
501
528
  end # def cover?(i)
502
529
 
503
530
 
504
- # @raise [TypeError] If {#exclude_begin?} is true, and {#begin}() or {#rangepart} does not have a method of [#succ], then even if no block is given, this method raises TypeError straightaway.
531
+ # slightly modified for {#exclude_begin?} being true
532
+ #
533
+ # @raise [TypeError] If {#exclude_begin?} is true, and {#begin}() (+@rangepart+) does not have a method of [#succ], then even if no block is given, this method raises TypeError straightaway.
505
534
  # @return [RangeExtd] self
506
535
  # @return [Enumerator] if block is not given.
507
- #
508
536
  def each(*rest, &bloc)
509
537
  # (1...3.5).each{|i|print i} # => '123' to STDOUT
510
538
  # (1.3...3.5).each # => #<Enumerator: 1.3...3.5:each>
511
539
  # (1.3...3.5).each{|i|print i} # => TypeError: can't iterate from Float
512
540
  # Note: If the block is not given and if @exclude_begin is true, the self in the returned Enumerator is not the same as self here.
513
- if @exclude_begin # including RangeExtd::NONE
514
- if defined? self.begin.succ
515
- ret = Range.new(self.begin.succ,self.end,exclude_end?).send(__method__, *rest, &bloc)
516
- if block_given?
517
- self
518
- else
519
- ret
520
- end
521
- elsif is_none?
522
- raise TypeError, "can't iterate for NONE range"
523
- else
524
- raise TypeError, "can't iterate from "+self.begin.class.name
525
- end
541
+
542
+ _step_each_core(__method__, *rest, &bloc)
543
+ end
544
+
545
+ # Core routine for {#each} and {#step}
546
+ #
547
+ # @raise [TypeError] If {#exclude_begin?} is true, and {#begin}() or {#rangepart} does not have a method of [#succ], then even if no block is given, this method raises TypeError straightaway.
548
+ # @return [RangeExtd] self
549
+ # @return [Enumerator] if block is not given.
550
+ def _step_each_core(method, *rest, &bloc)
551
+ raise TypeError, "can't iterate for NONE range" if is_none?
552
+
553
+ if block_given?
554
+ # when a block is given to {#each}, self should be returned.
555
+ _converted_rangepart(consider_exclude_begin: true, raises: true ).send(method, *rest, &bloc)
556
+ self
526
557
  else
527
- @rangepart.send(__method__, *rest, &bloc)
558
+ _converted_rangepart(consider_exclude_begin: true, raises: false).send(method, *rest)
528
559
  end
529
560
  end
561
+ private :_step_each_core
530
562
 
531
-
532
- # Like {Range#last}, if no argument is given, it behaves like {#begin}(), that is, it returns the initial value, regardless of {#exclude_begin?}.
533
- # However, if an argument is given (nb., acceptable since Ruby 1.9) when {#exclude_begin?} is true, it returns the array that starts from {#begin}().succ().
563
+ # Like +Range#last+, if no argument is given, it behaves like {#begin}(), that is, it returns the initial value, regardless of {#exclude_begin?}.
564
+ #
565
+ # If an argument is given (nb., acceptable since Ruby 1.9.2) when {#exclude_begin?} is true, it returns the array that starts from {#begin}().succ(), in the same way as +Range#last+ with {#exclude_end?} of +true+.
566
+ #
567
+ # The default behaviours are:
568
+ #
569
+ # (1...3.1).last # => 3.1
570
+ # (1...3.1).last(1) # => [3]
571
+ # (1...3.0).last(1) # => [2]
572
+ # (3.0..8).first(1) # raise: can't iterate from Float (TypeError)
573
+ #
534
574
  # @raise [TypeError] if the argument (Numeric) is given and if {#exclude_begin?} is true, yet if {#begin}().succ is not defined, or yet if {#is_none?}
535
- # @param rest [Integer] Optional. Must be non-negative. Consult {Range#first} for detail.
575
+ # @raise [RangeError] "cannot get the first element of beginless range" as per Range.
576
+ # @raise [ArgumentError] if more than 1 arguments are specified (delegated to {Range})
577
+ # @param rest [Integer] Optional. Must be non-negative. Consult +Range#first+ for detail.
536
578
  # @return [Object] if no argument is given, equivalent to {#end}.
537
579
  # @return [Array] if an argument is given.
538
580
  def first(*rest)
539
- # (1...3.1).last # => 3.1
540
- # (1...3.1).last(1) # => [3]
541
- if ! @exclude_begin # hence, not NONE.
542
- @rangepart.first(*rest)
543
- else
544
- case rest.size
545
- when 0
546
- self.begin
547
- when 1
548
- if (RUBY_VERSION < "1.9.1") && (1 == rest[0]) # Range#first() does not accept an argument in Ruby 1.8.
549
- raise ArgumentError, "wrong number of arguments (#{rest.size} for 0) (Use Ruby 1.9.2 or later)."
550
- end
551
-
552
- ## Check the argument.
553
- Array.new[ rest[0] ] # Check Type of rest[0] (if invalid, it should raise TypeError)
554
-
555
- begin
556
- if rest[0] < 0
557
- raise ArgumentError, "negative array size (or size too big)"
558
- end
559
- rescue NoMethodError
560
- # Should not happen, but just to play safe.
561
- end
562
-
563
- ## Main
564
- if ! defined? self.begin.succ
565
- raise TypeError, "can't iterate from "+self.begin.class.name
566
- end
581
+ if is_none?
582
+ raise RangeError, "cannot get the first element of RangeExtd::NONE"
583
+ end
567
584
 
568
- Range.new(self.begin.succ, self.end, exclude_end?).send(__method__, *rest)
569
- else
570
- raise ArgumentError, "wrong number of arguments (#{rest.size} for 0..1)"
571
- end
572
- end # if ! @exclude_begin
585
+ ran = _converted_rangepart(transform_to_nil: false, consider_exclude_begin: (1 == rest.size && exclude_begin?))
586
+ ran.send(__method__, *rest)
573
587
  end # def first(*rest)
574
588
 
575
589
 
590
+ # Redefines the hash definition
591
+ #
592
+ # Without re-definition, the hash value does NOT depend on {#exclude_begin?}
593
+ # presumably because the parent class method +Range#hash+ does not take it
594
+ # into account (of course).
595
+ #
576
596
  # When {#exclude_begin?} is true, the returned value is not strictly guaranteed to be unique, though in pracrtice it is most likely to be so.
577
597
  #
578
598
  def hash(*rest)
@@ -599,7 +619,8 @@ class RangeExtd < Range
599
619
  end
600
620
 
601
621
 
602
- # See {Range#last}.
622
+ # Updated version of +Range#last+, considering {#exclude_begin?}.
623
+ #
603
624
  # If either (let alone both) side of the edge is Infinity, you can not give
604
625
  # an argument in practice, the number of the members of the returned array.
605
626
  #
@@ -607,41 +628,55 @@ class RangeExtd < Range
607
628
  # @return [Object] if no argument is given, equivalent to {#end}.
608
629
  # @return [Array] if an argument is given.
609
630
  def last(*rest)
610
- return nil if null?
611
- nSize = rest.size
612
- case nSize
613
- when 0
614
- self.end
615
- when 1
616
- if (RUBY_VERSION < "1.9.1") && (1 == rest[0]) # Range#first() does not accept an argument in Ruby 1.8.
617
- raise ArgumentError, "wrong number of arguments (#{rest.size} for 0) (Use Ruby 1.9.2 or later)."
618
- end
631
+ if is_none?
632
+ raise RangeError, "cannot get the last element of RangeExtd::NONE"
633
+ end
619
634
 
620
- if defined?(self.begin.infinity?) && self.begin.infinity? || self.begin == -Infinity::FLOAT_INFINITY
621
- raise TypeError, "can't iterate from "+self.begin.to_s
622
- elsif defined?(self.end.infinity?) && self.end.infinity? || self.end == Infinity::FLOAT_INFINITY
623
- raise TypeError, "can't get elements to "+self.end.to_s
624
- elsif ! defined? self.begin.succ
625
- raise TypeError, "can't iterate from "+self.begin.class.name
626
- else
627
- @rangepart.send(__method__, *rest)
635
+ _converted_rangepart(transform_to_nil: false).send(__method__, *rest)
636
+ end # def last(*rest)
637
+
638
+
639
+ # Converts RangeExtd::Infinity to nil in @rangepart
640
+ #
641
+ # @param consider_exclude_begin [Boolean] If true (Default), and if {#exclude_begin?} is true, the first element is ignored. Note the resultant Range may be +invalid+.
642
+ # @param transform_to_nil [Boolean] If true (Default), {RangeExtd::Infinity} objects are transformed into nil when appropriate (i.e., {RangeExtd::Infinity::NEGATIVE} should be {RangeExtd#begin} and not at the end, and vice versa).
643
+ # @param raises [Boolean] If true (Def: false), and if {#exclude_begin?} is true but [#succ] is not defined for {#begin}, this routine raises an Exception as per (almost) Ruby default.
644
+ # @return [Range]
645
+ def _converted_rangepart(consider_exclude_begin: true, transform_to_nil: true, raises: false)
646
+ rbeg = @rangepart.begin
647
+ if consider_exclude_begin && exclude_begin?
648
+ if rbeg.respond_to? :succ
649
+ rbeg = rbeg.succ
650
+ elsif raises
651
+ if rbeg.nil?
652
+ raise RangeError, "cannot get the first element of beginless range"
653
+ elsif is_none? # maybe empty?() in some cases?
654
+ raise RangeError, "cannot get the first element of NONE range"
655
+ else
656
+ # This includes {RangeExtd::Infinity} class objects (RangeExtd::Infinity.infinity?(rbeg) == true) and Float::INFINITY.
657
+ raise TypeError, "can't iterate from "+self.begin.class.name
658
+ end
628
659
  end
629
- else
630
- raise ArgumentError, "wrong number of arguments (#{rest.size} for 0..1)"
631
660
  end
632
- end # def last(*rest)
633
661
 
662
+ rbeg = nil if RangeExtd::Infinity::NEGATIVE == rbeg && transform_to_nil
663
+ rend = @rangepart.end
664
+ rend = nil if RangeExtd::Infinity::POSITIVE == rend && transform_to_nil
665
+
666
+ Range.new(rbeg, rend, exclude_end?)
667
+ end
668
+ private :_converted_rangepart
634
669
 
635
670
  # See {#first} for the definition when {#exclude_begin?} is true.
636
671
  #
637
672
  def min(*rest, &bloc)
638
- re_min_max_core(__method__, *rest, &bloc)
673
+ _re_min_max_core(__method__, *rest, &bloc)
639
674
  end
640
675
 
641
676
  # See {#first} for the definition when {#exclude_begin?} is true.
642
677
  #
643
678
  def min_by(*rest, &bloc)
644
- re_min_max_core(__method__, *rest, &bloc)
679
+ _re_min_max_core(__method__, *rest, &bloc)
645
680
  end
646
681
 
647
682
 
@@ -652,7 +687,7 @@ class RangeExtd < Range
652
687
  # (1.3...5).minmax # => TypeError: can't iterate from Float
653
688
  # Note that max() for the same Range raises an exception.
654
689
  # In that sense, it is inconsistent!
655
- re_min_max_core(__method__, *rest, &bloc)
690
+ _re_min_max_core(__method__, *rest, &bloc)
656
691
  end
657
692
 
658
693
  # See {#first} for the definition when {#exclude_begin?} is true.
@@ -661,31 +696,31 @@ class RangeExtd < Range
661
696
  # (0...3.5).minmax # => [0, 3]
662
697
  # Note that max() for the same Range raises an exception.
663
698
  # In that sense, it is inconsistent!
664
- re_min_max_core(__method__, *rest, &bloc)
699
+ _re_min_max_core(__method__, *rest, &bloc)
665
700
  end
666
701
 
667
702
 
668
703
  # See {#first} for the definition when {#exclude_begin?} is true.
669
704
  #
670
705
  def max(*rest, &bloc)
671
- re_min_max_core(__method__, *rest, &bloc)
706
+ _re_min_max_core(__method__, *rest, &bloc)
672
707
  end
673
708
 
674
709
  # See {#first} for the definition when {#exclude_begin?} is true.
675
710
  #
676
711
  def max_by(*rest, &bloc)
677
- re_min_max_core(__method__, *rest, &bloc)
712
+ _re_min_max_core(__method__, *rest, &bloc)
678
713
  end
679
714
 
680
715
 
681
- # Implementation of {Range#size} to this class.
716
+ # Implementation of +Range#size+ to this class.
682
717
  #
683
718
  # It is essentially the same, but the behaviour when {#exclude_begin?} is true
684
719
  # may not always be natural.
685
720
  # See {#first} for the definition when {#exclude_begin?} is true.
686
721
  #
687
- # {Range#size} only works for Numeric ranges.
688
- # And in {Range#size}, the value is calculated when the initial value is
722
+ # +Range#size+ only works for Numeric ranges.
723
+ # And in +Range#size+, the value is calculated when the initial value is
689
724
  # non-Integer, by stepping by 1.0 from the {#begin} value, and the returned
690
725
  # value is an integer.
691
726
  # For example,
@@ -746,18 +781,19 @@ class RangeExtd < Range
746
781
  # (Float::INFINITY..Float::INFINITY).size
747
782
  #
748
783
  # has changed (I do not know in which Ruby version)!
749
- # It used to be 0. However, As of Ruby 2.6, it is +FloatDomainError: NaN+
784
+ # It used to be 0 (in Ruby-2.1). However, As of Ruby 2.6, it raises +FloatDomainError: NaN+
750
785
  # Again this class now follows Ruby's default ({RangeExtd} Ver.1.0 or later).
751
786
  #
752
787
  # @note When both ends n are the same INFINITY (of the same parity),
753
788
  # +(n..n).size+ used to be 0. As of Ruby 2.6, it is FloatDomainError: NaN.
754
789
  # This routine follows what Ruby produces, depending on Ruby's version it is run on.
755
790
  #
756
- # @see http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/49797 [ruby-list:49797] from matz for how {Range#size} behaves (in Japanese).
791
+ # @see http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/49797 [ruby-list:49797] from matz for how +Range#size+ behaves (in Japanese).
757
792
  #
758
793
  # @return [Integer] 0 if {RangeExtd::NONE}
759
794
  # @return [Float] Float::INFINITY if either (or both) the end is infinity, regardless of the class of the elements.
760
795
  # @return [nil] if the range is non-Numeric.
796
+ # @raise [FloatDomainError] (Infinity..Infinity).size (as in Ruby-3.1, though it used to be 0 in Ruby-2.1)
761
797
  def size(*rest)
762
798
  # (1..5).size # => 5
763
799
  # (1...5).size # => 4
@@ -770,92 +806,60 @@ class RangeExtd < Range
770
806
  # (1.5...4.5).size # => 3
771
807
  # (0...Float::INFINITY).size # => Infinity
772
808
 
773
- if is_none? # No need of null?(), supposedly!
774
- return 0
775
-
776
- ### (Infinity..Infinity) => 0 (as in Ruby 2.1)
777
- # elsif self.begin().infinity? || self.end().infinity?
778
- # return Infinity::FLOAT_INFINITY
779
-
780
- # Checking Infinity.
781
- # Note (Infinity..Infinity) => 0 (Range as in Ruby 2.1)
782
- # however,
783
- elsif (defined?(self.begin.infinity?) && self.begin.infinity? || self.begin == -Infinity::FLOAT_INFINITY) ||
784
- (defined?(self.end.infinity?) && self.end.infinity? || self.end == Infinity::FLOAT_INFINITY) ||
785
- (self.end.nil?) # RangeExtd#end can be nil only for Ruby-2.6
786
- if self.begin == self.end
787
- # This varies, depending on Ruby's version! It used to be 0. As of Ruby 2.6, it is FloatDomainError: NaN.
788
- return (Float::INFINITY..Float::INFINITY).size
789
- # return 0
790
- elsif self.end.nil?
791
- # Behaves as Ruby does -
792
- # Infinity::FLOAT_INFINITY for Numeric and nil for any other
793
- return (self.begin..nil).size
794
- else
795
- return Infinity::FLOAT_INFINITY
796
- end
809
+ return 0 if is_none? # No need of null?(), supposedly!
810
+
811
+ if self.begin.nil? || self.end.nil? # RangeExtd#begin/end can be nil only in Ruby-2.7+/2.6+
812
+ # Behaves as Ruby does -
813
+ # Infinity::FLOAT_INFINITY for Numeric and nil, but nil for any other
814
+ # {#exclude_end?} does not matter.
815
+ return (self.begin..self.end).size
816
+ end
797
817
 
798
- elsif @exclude_begin
818
+ rbeg = self.begin
819
+ rend = self.end
799
820
 
800
- begin
801
- _dummy = 1.0 + self.begin() # _dummy to suppress warning: possibly useless use of + in void context
821
+ # Either or both sides are (general or Float) Infinity
822
+ if RangeExtd::Infinity.infinite?(rbeg) || RangeExtd::Infinity.infinite?(rend)
823
+ return @rangepart.send(__method__, *rest) # delegates to {Range#size}
824
+ end
802
825
 
803
- # Numeric
804
- if defined? (self.begin().succ)
805
- Range.new(self.begin().succ, self.end, exclude_end?).send(__method__, *rest)
806
- else
807
- size_no_exclude = Range.new(self.begin, self.end).send(__method__, *rest) # exclude_end? == true, ie., Range with both ends inclusinve.
808
- diff = self.end - self.begin
809
- if diff.to_i == diff # Integer difference
810
- return size_no_exclude - 1 # At least exclude_begin?==true (so exclude_end? does not matter)
811
- else
812
- return size_no_exclude
813
- end
814
- end
815
- rescue TypeError
816
- # Non-Numeric
817
- if defined? self.begin().succ
818
- Range.new(self.begin().succ, self.end, exclude_end?).send(__method__, *rest) # => nil in Ruby 2.1
819
- else
820
- nil # See the line above.
821
- # raise TypeError, "can't iterate from "+self.begin.class.name
822
- end
826
+ return @rangepart.send(__method__, *rest) if !exclude_begin?
823
827
 
828
+ # Now, {#exclude_begin?} is true:
829
+ begin
830
+ _dummy = 1.0 + rbeg # _dummy to suppress warning: possibly useless use of + in void context
831
+ rescue TypeError
832
+ # Non-Numeric
833
+ if defined? rbeg.succ
834
+ return Range.new(rbeg.succ, rend, exclude_end?).send(__method__, *rest) # => nil in Ruby 2.1+
835
+ else
836
+ return nil # See the line above.
837
+ # raise TypeError, "can't iterate from "+self.begin.class.name
824
838
  end
839
+ end
825
840
 
841
+ # Numeric
842
+ if rbeg.respond_to? :succ
843
+ Range.new(rbeg.succ, rend, exclude_end?).send(__method__, *rest)
826
844
  else
827
- @rangepart.send(__method__, *rest)
845
+ size_no_exclude = Range.new(rbeg, rend).send(__method__, *rest) # exclude_end? == true, ie., Range with both ends inclusinve.
846
+ diff = self.end - self.begin
847
+ if diff.to_i == diff # Integer difference
848
+ return size_no_exclude - 1 # At least exclude_begin?==true (so exclude_end? does not matter)
849
+ else
850
+ return size_no_exclude
851
+ end
828
852
  end
829
853
  end # def size
830
854
 
831
855
 
832
856
  # See {#each}.
857
+ #
833
858
  # @raise [TypeError] If {#exclude_begin?} is true, and {#begin}() does not have the method [#succ], then even if no block is given, this method raises TypeError straightaway.
834
859
  # @return [RangeExtd] self
835
860
  # @return [Enumerator] if block is not given.
836
- #
837
861
  def step(*rest, &bloc)
838
- # (1...3.5).each{|i|print i} # => '123' to STDOUT
839
- # (1.3...3.5).each # => #<Enumerator: 1.3...3.5:each>
840
- # (1.3...3.5).each{|i|print i} # => TypeError: can't iterate from Float
841
- # Note: If the block is not given and if exclude_begin?() is true, the self in the returned Enumerator is not the same as self here.
842
-
843
- if @exclude_begin # including RangeExtd::NONE
844
- if defined? self.begin.succ
845
- ret = Range.new(self.begin.succ,self.end,exclude_end?).send(__method__, *rest, &bloc)
846
- if block_given?
847
- self
848
- else
849
- ret
850
- end
851
- elsif is_none? # No need of null?(), supposedly!
852
- raise TypeError, "can't iterate for NONE range"
853
- else
854
- raise TypeError, "can't iterate from "+self.begin.class.name
855
- end
856
- else
857
- @rangepart.send(__method__, *rest, &bloc)
858
- end
862
+ _step_each_core(__method__, *rest, &bloc)
859
863
  end
860
864
 
861
865
 
@@ -865,7 +869,15 @@ class RangeExtd < Range
865
869
 
866
870
  # Private class method to evaluate the arguments.
867
871
  #
872
+ # @note The specification changed from RangeExtd Ver.1 to Ver.2.
873
+ # In Ver.1 or earlier, this returns [begin, end, exclude_end, exclude_begin]
874
+ # In Ver.2+, this returns [begin, end, exclude_begin, exclude_end]
875
+ # Notice the third and fourth elements are swapped. Now it is in line
876
+ # with {RangeExtd.new}.
877
+ #
878
+ # @param (see RangeExtd#initialize) (or valid)
868
879
  # @raise [ArgumentError] if the input format is invalid (otherwise the caller may raise RangeError (it depends))
880
+ # @return [Array<Object, Object, Boolean, Boolean>] 4-compoents: [begin, end, exclude_begin, exclude_end]
869
881
  def self._get_init_args(*inar, **hsopt)
870
882
  nMin = 1; nMax = 5
871
883
  if inar.size < nMin || nMax < inar.size
@@ -903,8 +915,6 @@ class RangeExtd < Range
903
915
  end
904
916
 
905
917
  beginend = [inar[0].begin, inar[0].end]
906
- # arRet = [inar[0].begin, inar[0].end, exclude_end, exclude_begin]
907
- # @rangepart = Range.new(inar[0].begin, inar[0].end, exclude_end)
908
918
 
909
919
  when :object
910
920
  nMin = 2; nMax = 5
@@ -924,8 +934,8 @@ class RangeExtd < Range
924
934
  # Originally, defined?(inar[1].=~) seemed enough. But as of Ruby 2.6 (maybe even before),
925
935
  # Numeric has :=~ method as well!
926
936
  if (inar.size > 2 &&
927
- inar[1].class.method_defined?(:=~) &&
928
- inar[1].class.method_defined?(:to_str))
937
+ inar[1].respond_to?(:=~) &&
938
+ inar[1].respond_to?(:to_str))
929
939
  begin
930
940
  cmp = (inar[0] <=> inar[2]).abs
931
941
  rescue
@@ -936,16 +946,8 @@ class RangeExtd < Range
936
946
  # Hence all the default values are overwritten.
937
947
  beginend = [inar[0], inar[2]]
938
948
  hsFlag[:excl_offset] = 1
939
- if $1 == @@middle_strings[1]
940
- exclude_begin = false
941
- else
942
- exclude_begin = true
943
- end
944
- if $2 == @@middle_strings[4]
945
- exclude_end = true
946
- else
947
- exclude_end = false
948
- end
949
+ exclude_begin = ($1 != @@middle_strings[1])
950
+ exclude_end = ($2 == @@middle_strings[4])
949
951
  else
950
952
  nMin = 2; nMax = 4
951
953
  if inar.size > nMax
@@ -967,9 +969,6 @@ class RangeExtd < Range
967
969
  exclude_end = (true ^! inar[3+hsFlag[:excl_offset]]) # 4th or 5th argument
968
970
  end
969
971
 
970
- # arRet = [inar[0], inar[1], exclude_end, exclude_begin]
971
- # @rangepart = Range.new(inar[0], inar[1], exclude_end)
972
-
973
972
  else
974
973
  raise # (for coding safety)
975
974
  end # case hsFlag[:prm1st]
@@ -981,23 +980,23 @@ class RangeExtd < Range
981
980
  exclude_end = (hsopt[:exclude_end] && true)
982
981
  end
983
982
 
984
- # [RangeBeginValue, RangeEndValue, exclude_end?, exclude_begin?]
985
- _normalize_infinity_float(beginend) + [exclude_end, exclude_begin]
983
+ # [RangeBeginValue, RangeEndValue, exclude_begin?, exclude_end?]
984
+ _normalize_infinity_float(beginend) + [exclude_begin, exclude_end]
986
985
  end # def self._get_init_args(*inar)
987
986
  private_class_method :_get_init_args # From Ruby 1.8.7 (?)
988
987
 
989
988
  # Replaces {RangeExtd::Infinity} with {Float::INFINITY} when appropriate
990
989
  #
991
- # @param beginend [Array] 2-compoents
992
- # @return [Array] 2-compoents
990
+ # @param beginend [Array] 2-compoents(begin, end)
991
+ # @return [Array] 2-compoents(begin, end)
993
992
  def self._normalize_infinity_float(beginend)
994
993
  is_begin_inf = Infinity.infinity?(beginend[0])
995
994
  return beginend if is_begin_inf ^! Infinity.infinity?(beginend[1])
996
995
 
997
996
  # Now, only one of them is a {RangeExtd::Infinity} type object.
998
- if is_begin_inf && beginend[1].class.method_defined?(:divmod)
997
+ if is_begin_inf && beginend[1].respond_to?(:divmod)
999
998
  [_normalize_infinity_float_core(beginend[0]), beginend[1]] # "begin" is Infinity
1000
- elsif beginend[0].class.method_defined?(:divmod)
999
+ elsif beginend[0].respond_to?(:divmod)
1001
1000
  [beginend[0], _normalize_infinity_float_core(beginend[1])] # "end" is Infinity
1002
1001
  else
1003
1002
  beginend
@@ -1009,7 +1008,7 @@ class RangeExtd < Range
1009
1008
  # @return [RangeExtd::Infinity, Float] +/-Float::INFINITY if Float
1010
1009
  def self._normalize_infinity_float_core(inf)
1011
1010
  msg = 'RangeExtd component of the RangeExtd::Infinity object replaced with Float::INFINITY.'
1012
- warn msg if !$VERBOSE.nil?
1011
+ warn msg if $DEBUG || $VERBOSE
1013
1012
  (inf.positive? ? 1 : -1) * Float::INFINITY
1014
1013
  end
1015
1014
  private_class_method :_normalize_infinity_float_core # From Ruby 1.8.7 (?)
@@ -1018,7 +1017,7 @@ class RangeExtd < Range
1018
1017
  # Returns true if the range to be constructed (or given) is valid,
1019
1018
  # as a range, accepted in {RangeExtd}.
1020
1019
  #
1021
- # This routine is also impremented as a method in {Range},
1020
+ # This routine is also implemented as a method in {Range},
1022
1021
  # and accordingly its sub-classes.
1023
1022
  #
1024
1023
  # This routine is called from {RangeExtd.new}, hence
@@ -1028,23 +1027,31 @@ class RangeExtd < Range
1028
1027
  #
1029
1028
  # 1. The {#begin} and {#end} elements must be Comparable to each other,
1030
1029
  # and the comparison results must be consistent betwen the two.
1031
- # The two sole exceptions are {RangeExtd::NONE} and Endless Range
1032
- # introduced in Ruby 2.6 (see below for the exceptions), both of which are valid.
1033
- # For example, (nil..nil) is NOT valid (nb., it raised Exception in Ruby 1.8).
1034
- # 2. Except for {RangeExtd::NONE}, {#begin} must have the method +<=+.
1035
- # Therefore, some Endless Ranges (Ruby 2.6 and later) like (true..) are *not* valid.
1036
- # Note even "true" has the method +<=>+ and hence checking +<=+ is essential.
1037
- # 3. {#begin} must be smaller than or equal to {#end},
1030
+ # The three exceptions are {RangeExtd::NONE} and Beginless and Endless Ranges
1031
+ # introduced in Ruby 2.7 and 2.6, respectively (see below for the exceptions),
1032
+ # which are all valid. Accordingly, +(nil..nil)+ is
1033
+ # valid in {RangeExtd} Ver.1.0+ (nb., it used to raise Exception in Ruby 1.8).
1034
+ # 2. Except for {RangeExtd::NONE} and Beginless Range, {#begin} must have the method +<=+.
1035
+ # Therefore, some Endless Ranges (Ruby 2.6 and later) like +(true..)+ are *not* valid.
1036
+ # Note even "+true+" has the method +<=>+ and hence checking +<=+ is essential.
1037
+ # 3. Similarly, except for {RangeExtd::NONE} and Endless Range, {#end} must have the method +<=+.
1038
+ # Therefore, some Beginless Ranges (Ruby 2.7 and later) like +(..true)+ are *not* valid.
1039
+ # 4. {#begin} must be smaller than or equal to {#end},
1038
1040
  # that is, ({#begin} <=> {#end}) must be either -1 or 0.
1039
- # 4. If {#begin} is equal to {#end}, namely, ({#begin} <=> {#end}) == 0,
1040
- # the exclude status of the both ends must agree.
1041
- # That is, if the {#begin} is excluded, {#end} must be also excluded,
1041
+ # 5. If {#begin} is equal to {#end}, namely, ({#begin} <=> {#end}) == 0,
1042
+ # the exclude status of the both ends must agree, except for the cases
1043
+ # where both {#begin} and {#end} ani +nil+ (beginless and endless Range).
1044
+ # In other words, if the {#begin} is excluded, {#end} must be also excluded,
1042
1045
  # and vice versa.
1043
- # For example, (1...1) is NOT valid for that reason,
1046
+ # For example, +(1...1)+ is NOT valid for this reason,
1044
1047
  # because any built-in Range object has the exclude status
1045
- # of false (namely, inclusive) for {#begin}.
1048
+ # of +false+ (namely, inclusive) for {#begin}, whereas
1049
+ # +RangeExtd(1...1, true)+ is valid and equal (+==+) to
1050
+ # {RangeExtd::NONE}.
1051
+ # 6. If either or both of {#begin} and {#end} is {RangeExtd::Nowhere::NOWHERE},
1052
+ # the range has to be {RangeExtd::NONE}.
1046
1053
  #
1047
- # Note the last example may change in the future release.
1054
+ # Note the second last point may change in the future release.
1048
1055
  #
1049
1056
  # Note ([2]..[5]) is NOT valid, because Array does not include Comparable
1050
1057
  # for some reason, as of Ruby 2.1.1, even though it has the redefined
@@ -1053,8 +1060,10 @@ class RangeExtd < Range
1053
1060
  #
1054
1061
  # @example
1055
1062
  #
1056
- # RangeExtd.valid?(nil..nil) # => false
1057
- # RangeExtd.valid?(nil...nil) # => false
1063
+ # RangeExtd.valid?(nil..nil) # => true
1064
+ # RangeExtd.valid?(nil...nil) # => true
1065
+ # RangeExtd.valid?(nil<..nil) # => true
1066
+ # RangeExtd.valid?(nil<...nil) # => true
1058
1067
  # RangeExtd.valid?(0..0) # => true
1059
1068
  # RangeExtd.valid?(0...0) # => false
1060
1069
  # RangeExtd.valid?(0...) # => true
@@ -1068,6 +1077,7 @@ class RangeExtd < Range
1068
1077
  # RangeExtd.valid?(3..Float::INFINITY, true) # => true
1069
1078
  # RangeExtd.valid?(RangeExtd::Infinity::NEGATIVE..?d) # => true
1070
1079
  # RangeExtd.valid?(RangeExtd::Infinity::NEGATIVE..?d, true) # => true
1080
+ # RangeExtd.valid?(RangeExtd::Nowhere::NOWHERE..nil) # => false
1071
1081
  #
1072
1082
  # @note The flag of exclude_begin|end can be given in the arguments in a couple of ways.
1073
1083
  # If there is any duplication, those specified in the optional hash have the highest
@@ -1075,14 +1085,14 @@ class RangeExtd < Range
1075
1085
  # If not, the values embeded in the {Range} or {RangeExtd} object
1076
1086
  # in the parameter are used. In default, both of them are false.
1077
1087
  #
1078
- # @overload new(range, [exclude_begin=false, [exclude_end=false]])
1088
+ # @overload valid?(range, [exclude_begin=false, [exclude_end=false]])
1079
1089
  # @param range [Object] Instance of Range or its subclasses, including RangeExtd
1080
1090
  # @param exclude_begin [Boolean] If specified, this has the higher priority, or false in default.
1081
1091
  # @param exclude_end [Boolean] If specified, this has the higher priority, or false in default.
1082
1092
  #
1083
- # @overload new(obj_begin, obj_end, [exclude_begin=false, [exclude_end=false]])
1084
- # @param obj_begin [Object] Any object that is {Comparable} with end
1085
- # @param obj_end [Object] Any object that is Comparable with begin (or nil, for Ruby 2.6 onwards)
1093
+ # @overload valid?(obj_begin, obj_end, [exclude_begin=false, [exclude_end=false]])
1094
+ # @param obj_begin [Object] Any object that is +Comparable+ with end
1095
+ # @param obj_end [Object] Any object that is +Comparable+ with begin (or nil, for Ruby 2.6 onwards)
1086
1096
  # @param exclude_begin [Boolean] If specified, this has the lower priority, or false in default.
1087
1097
  # @param exclude_end [Boolean] If specified, this has the lower priority, or false in default.
1088
1098
  #
@@ -1090,21 +1100,32 @@ class RangeExtd < Range
1090
1100
  (vbeg, vend, exc_beg, exc_end) = _get_init_args(*inar)
1091
1101
 
1092
1102
  if defined?(inar[0].is_none?) && inar[0].is_none? && exc_beg && exc_end
1103
+ # inar[0] is RangeExtd::NONE
1104
+ return true
1105
+ elsif vbeg.nil? && vbeg.nowhere? || vend.nil? && vend.nowhere?
1106
+ # RangeExtd::Nowhere::NOWHERE should not reside anywhere but in RangeExtd::NONE
1107
+ return false
1108
+ elsif vbeg.nil? && vend.nil?
1093
1109
  return true
1094
1110
  end
1111
+
1112
+ return false if !vbeg.respond_to?(:<=>)
1095
1113
  begin
1096
1114
  t = (vbeg <=> vend)
1097
1115
  begin
1098
- if vend.nil?
1116
+ if vbeg.nil? # Beginless Range introduced in Ruby 2.7
1117
+ return vend.respond_to?(:<=)
1118
+ elsif vend.nil?
1099
1119
  begin
1100
1120
  _ = (vbeg..nil) # Endless Range introduced in Ruby 2.6
1101
- return vbeg.class.method_defined?(:<=)
1121
+ return vbeg.respond_to?(:<=)
1102
1122
  rescue ArgumentError
1103
1123
  # Before Ruby 2.6
1104
1124
  return false
1105
1125
  end
1106
1126
  end
1107
- return false if t != -1*(vend <=> vbeg) # false if not commutative, or possibly exception (such as -1*nil).
1127
+ return false if !vend.respond_to?(:<=>)
1128
+ return false if t != -1*(vend <=> vbeg) # false if not commutative (n.b., an exception should not happen).
1108
1129
  rescue NoMethodError, TypeError
1109
1130
  if (Float === vend && defined?(vbeg.infinity?) && vbeg.infinity?) ||
1110
1131
  (Float === vbeg && defined?(vend.infinity?) && vend.infinity?)
@@ -1112,7 +1133,8 @@ class RangeExtd < Range
1112
1133
  end
1113
1134
  return false # return
1114
1135
  end
1115
- rescue # NoMethodError
1136
+ rescue
1137
+ warn "This should not happen. Contact the code developer (warn01)."
1116
1138
  false # return
1117
1139
  else
1118
1140
  case t
@@ -1127,6 +1149,7 @@ class RangeExtd < Range
1127
1149
  when 1
1128
1150
  false
1129
1151
  else
1152
+ warn "This should not happen. Contact the code developer (warn02)."
1130
1153
  if (Float === vend && defined?(vbeg.infinity?) && vbeg.infinity?) ||
1131
1154
  (Float === vbeg && defined?(vend.infinity?) && vend.infinity?)
1132
1155
  warn self.const_get(:ERR_MSGS)[:infinity_compare] if !$VERBOSE.nil? # not tested so far?
@@ -1265,365 +1288,96 @@ class RangeExtd < Range
1265
1288
  end # def re_inspect_core_orig(method)
1266
1289
 
1267
1290
 
1268
- # Core routine for {#===} and {#eql?}
1291
+ # Core routine for {#===}
1292
+ #
1269
1293
  # @param [Object] r to compare.
1270
1294
  # @param [Symbol] method of the method name.
1271
- def re_equal_core(r, method)
1272
- if defined? r.empty?
1273
- is_r_empty = r.empty?
1274
- else
1275
- return false # Not Range family.
1276
- end
1277
- if ! defined? r.exclude_end?
1278
- false # Not Range family.
1279
- elsif is_none? && is_r_empty # RangeExtd::NONE
1280
- true
1281
- elsif empty? && defined?(r.is_none?) && r.is_none? # r is RangeExtd::NONE
1282
- true
1283
- elsif empty? && is_r_empty
1284
- if method == :eql?
1285
- # More strict
1286
- if self.begin().class == r.begin().class
1287
- true # (1<...1).eql? (2<...2) # => true (Fixnum <-> Fixnum) Yes!
1288
- else
1289
- false # (1.0<...1.0).eql? (2<...2) # => false (Float <-> Fixnum) No!
1290
- end
1291
- else
1292
- (self.begin.class.ancestors - self.begin.class.included_modules - [Object, BasicObject]).each do |ec|
1293
- if ec === r.begin
1294
- return true # (1.0<...1.0) == (2<...2) # (Float<Numeric <-> Fixnum<Numeric) Yes!
1295
- end
1295
+ def _re_equal_core(r, method=:==)
1296
+ return false if !r.respond_to? :exclude_end? # Not Range family.
1297
+ return false if !r.respond_to? :empty? # Not Range family.
1298
+ return false if !r.respond_to? :valid? # Not Range family.
1299
+
1300
+ return false if !r.valid? # always returns false with an invalid Range; n.b., RangeExtd#valid? is always true, hence they cannot be identical (eql?).
1301
+
1302
+ is_r_empty = r.empty?
1303
+ return !!is_r_empty if is_none? # RangeExtd::NONE==(1<...1); n.b. "!!" is redundant because r must be valid.
1304
+ return true if empty? && r.respond_to?(:is_none?) && r.is_none? # r is RangeExtd::NONE
1305
+ return false if !_both_same_nowhere_parity?(r) # inconsistent nil, non-nil, NOWHERE combination
1306
+
1307
+ if empty? && is_r_empty
1308
+ (self.begin.class.ancestors - self.begin.class.included_modules - [Object, BasicObject]).each do |ec|
1309
+ if ec === r.begin
1310
+ return true # (1.0<...1.0) == (2<...2) # (Float<Numeric <-> Fixnum<Numeric) Yes!
1296
1311
  end
1297
- false # (?a...?a) != (2<...2) # (String <-> Numeric) No!
1298
1312
  end
1313
+ return false # (?a...?a) != (2<...2) # (String <-> Numeric) No!
1314
+ end
1315
+
1316
+ return false if !(self.exclude_end? ^! r.exclude_end?)
1299
1317
 
1300
- elsif defined? r.exclude_begin?
1318
+ # Neither self nor r is guaranteed to be RangeExtd::NONE
1319
+ is_nil_equal = _both_eqleql_nil?(r, method)
1320
+
1321
+ if defined? r.exclude_begin? # r is RangeExtd
1301
1322
  (self.exclude_begin? ^! r.exclude_begin?) &&
1302
1323
  (self.exclude_end? ^! r.exclude_end?) &&
1303
- (self.begin.send(method, r.begin)) &&
1304
- (self.end.send( method, r.end))
1305
- # (self.begin == r.begin) &&
1306
- # (self.end == r.end)
1324
+ (self.begin.send(method, r.begin) && self.end.send(method, r.end) || is_nil_equal)
1307
1325
  else
1308
1326
  # r is Range
1309
1327
  if self.exclude_begin?
1310
1328
  false
1311
1329
  else
1312
- @rangepart.send(method, r) # Comparison as two Range-s.
1330
+ is_nil_equal || @rangepart.send(method, r) # Comparison as two Range-s.
1313
1331
  end
1314
1332
  end
1315
- end # def re_equal_core(r, method)
1333
+ end # def _re_equal_core(r, method)
1334
+ private :_re_equal_core
1316
1335
 
1317
1336
  # Core routine for {#min}, {#max}, {#minmax} etc.
1318
1337
  # @param method [Symbol] of the method name.
1319
1338
  # @param rest [Object]
1320
- def re_min_max_core(method, *rest, &bloc)
1339
+ def _re_min_max_core(method, *rest, &bloc)
1321
1340
  # (1...3.5).max # => TypeError: cannot exclude non Integer end value
1322
- if is_none?
1341
+ if is_none? || self.begin.nil? && self.begin.nowhere? || self.end.nil? && self.end.nowhere?
1342
+ # In fact, Range#minmax etc should be modified to deal with RangeExtd::Nowhere::NOWHERE (it is treated as nil at the moment)...
1323
1343
  raise TypeError, "no meaningful range."
1324
- elsif @exclude_begin
1325
- if defined?(self.begin.infinity?) && self.begin.infinity? || self.begin == -Infinity::FLOAT_INFINITY
1326
- raise TypeError, "can't exclude "+self.begin.to_s
1327
- elsif ! defined? self.begin.succ
1328
- raise TypeError, "can't iterate from "+self.begin.class.name
1329
- else
1330
- Range.new(self.begin.succ, self.end, exclude_end?).send(method, *rest, &bloc)
1331
- end
1332
- else
1333
- @rangepart.send(method, *rest)
1334
1344
  end
1335
- end # def re_min_max_core(method, *rest, &bloc)
1336
1345
 
1346
+ if !@exclude_begin ||
1347
+ [:max, :max_by].include?(method) ||
1348
+ self.begin.respond_to?(:succ) ||
1349
+ [:min_by, :minmax_by].include?(method) && !block_given?
1350
+ # For the last one, if Range starts from something uniterable, it returns
1351
+ # Enumerator (without errors); but once it is executed, it will raise TypeError
1352
+ # "can't iterate from Float" or RangeError "cannot get the minimum of beginless range"
1353
+ return _converted_rangepart(transform_to_nil: false).send(method, *rest, &bloc)
1354
+ end
1355
+
1356
+ # Now @exclude_begin is true, "begin" is not discrete, and block is given (if _by).
1357
+ raise TypeError, "can't exclude non-iterable begin value" #+self.begin.to_s
1358
+ end # def _re_min_max_core(method, *rest, &bloc)
1359
+ private :_re_min_max_core
1360
+
1361
+ self.remove_const :NONE if defined? self::NONE # tricky manoeuvre for documentation purposes... (see infinity.rb for the explanatory document)
1337
1362
  # No range.
1338
1363
  # In Ruby1.8, this causes ArgumentError: bad value for range (because (nil..nil) is unaccepted).
1339
- NONE = RangeExtd.new(nil, nil, true, true, :Constant)
1340
- #NONE= RangeExtd.new(nil...nil, true, true, :Constant)
1364
+ #NONE = RangeExtd.new(nil, nil, true, true, :Constant)
1365
+ NONE = RangeExtd.new(RangeExtd::Nowhere::NOWHERE, RangeExtd::Nowhere::NOWHERE, true, true, :Constant)
1341
1366
 
1367
+ self.remove_const :ALL if defined? self::ALL # tricky manoeuvre for documentation purposes... (see infinity.rb for the explanatory document)
1342
1368
  # Range covers everything.
1343
1369
  ALL = RangeExtd.new(Infinity::NEGATIVE, Infinity::POSITIVE, false, false, :Constant)
1344
- #ALL = RangeExtd.new(Infinity::NEGATIVE..Infinity::POSITIVE, false, false, :Constant)
1345
1370
 
1346
1371
  end # class RangeExtd < Range
1347
1372
 
1348
-
1349
- #= Class Range
1350
- #
1351
- #== Summary
1352
- #
1353
- # Modifies {#==}, {#eql?} and add methods of
1354
- # {#valid?}, {#empty?}, {#null?}, {#is_none?} and {#is_all?}.
1355
- #
1356
- class Range
1357
-
1358
- alias_method :equal_prerangeextd?, :== if ! self.method_defined?(:equal_prerangeextd?) # No overwriting.
1359
-
1360
- # It is extended to handle {RangeExtd} objects.
1361
- # For each element, that is, {#begin} and {#end},
1362
- # this uses their method of ==(). See {#eql?}.
1363
- #
1364
- # As long as the comparison is limited within {Range} objects,
1365
- # the returned value of this method has unchanged.
1366
- #
1367
- # A note of caution is, some ranges which the built-in Range accepts,
1368
- # are now regarded as NOT valid, such as, (1...1) and (nil..nil)
1369
- # (the latter was not permitted in Ruby 1.8), though you can still
1370
- # use them;
1371
- # (1...1).valid? # => false
1372
- # On the other hand, {RangeExtd} class does not accept or create
1373
- # any invalid range; for any {RangeExtd} object, RangeExtd#valid?
1374
- # returns true. For example, there is no {RangeExtd} object
1375
- # that is expressed as (1...1) (See {#valid?} for detail).
1376
- #
1377
- # For that reason, when those non-valid Range objects are compared
1378
- # with a {RangeExtd} object, the returned value may not be what
1379
- # you would expect. For example,
1380
- # (1...1) == RangeExtd(1, 1, true, true) # => false.
1381
- # The former is an invalid range, while the latter is
1382
- # a rigidly-defined empty range.
1383
- #
1384
- # Consult {#valid?} and {RangeExtd#==} for more detail.
1385
- def ==(r)
1386
- equal_core(r, :==, :equal_prerangeextd?)
1387
- end
1388
-
1389
-
1390
- alias :eql_prerangeextd? :eql? if ! self.method_defined?(:eql_prerangeextd?) # No overwriting.
1391
-
1392
- # Same as {#==}, but the comparison is made with eql?() method.
1393
- def eql?(r)
1394
- equal_core(r, :eql?, :eql_prerangeextd?)
1395
- end
1396
-
1397
-
1398
- # Returns true if self is valid as a comparable range.
1399
- #
1400
- # See {RangeExtd.valid?} for the definition of what is valid
1401
- # and more examples.
1402
- #
1403
- # See {#empty?} and {#null?}, too.
1404
- #
1405
- # @example
1406
- # (nil..nil).valid? # => false
1407
- # (0..0).valid? # => true
1408
- # (0...0).valid? # => false
1409
- # (2..-1).valid? # => false
1410
- # RangeExtd(0...0, true) # => true
1411
- # (3..Float::INFINITY).valid? # => true
1412
- # RangeExtd::NONE.valid? # => true
1413
- # RangeExtd::ALL.valid? # => true
1414
- #
1415
- # @note By definition, all the {RangeExtd} instances are valid,
1416
- # because {RangeExtd.new} checks the validity.
1417
- def valid?
1418
- RangeExtd.valid?(self)
1419
- end # def valid?
1420
-
1421
-
1422
- # Returns true if self is empty.
1423
- # Returns nil if self is not valid (nb., any RangeExtd instance is valid.)
1424
- # Otherwise false.
1425
- #
1426
- # The definition of what is empty is as follow.
1427
- #
1428
- # 1. the range must be valid: {#valid?} => true
1429
- # 2. if the range id discrete, that is, {#begin} has
1430
- # [#succ] method, there must be no member within the range:
1431
- # {#to_a}.empty? => true
1432
- # 3. if the range is continuous, that is, {#begin} does not have
1433
- # [#succ] method, {#begin} and {#end} must be equal
1434
- # (({#begin} <=> {#end}) => 0) and both the boundaries must
1435
- # be excluded: ({#exclude_begin?} && {#exclude_end?}) => true.
1436
- # Note that ranges with equal {#begin} and {#end} with
1437
- # inconsistent two exclude status are not valid, and the built-in
1438
- # Range always has the {#begin}-exclude status of false.
1439
- #
1440
- # In these conditions, none of Range instance would return true in {#empty?}.
1441
- #
1442
- # @example
1443
- # (nil..nil).empty? # => nil
1444
- # (1...1).empty? # => nil
1445
- # (1..1).empty? # => false
1446
- # RangeExtd(1...1, true).empty? # => true
1447
- # RangeExtd(1...2, true).empty? # => true
1448
- # RangeExtd(1.0...2, true).empty? # => false
1449
- # RangeExtd(?a...?b, true).empty? # => true
1450
- # RangeExtd::NONE.empty? # => true
1451
- #
1452
- # @note to check whether it is either empty or invalid, use {#null?}.
1453
- # See {#valid?} and {RangeExtd.valid?}, too.
1454
- #
1455
- # @return [Boolean, nil]
1456
- def empty?
1457
- # This is basically for the sake of sub-classes, as any built-in Range instance
1458
- # always returns either nil or false.
1459
-
1460
- if !valid?
1461
- return nil
1462
- elsif defined?(self.is_none?) && self.is_none?
1463
- return true
1464
- end
1465
-
1466
- t = (self.begin() <=> self.end())
1467
- case t
1468
- when -1
1469
- if (defined?(self.exclude_begin?)) &&
1470
- exclude_begin? &&
1471
- exclude_end? &&
1472
- defined?(self.begin().succ) &&
1473
- (self.begin().succ == self.end())
1474
- true # e.g., ("a"<..."b")
1475
- else
1476
- false
1477
- end
1478
- when 0
1479
- if defined?(self.boundary) && self.boundary.nil? # for RangeOpen
1480
- # RangeExtd::NONE or RangeExtd::All
1481
- if self.exclude_end?
1482
- true # RangeOpen::NONE
1483
- else
1484
- false # RangeOpen::ALL
1485
- end
1486
- else
1487
- if defined?(self.exclude_begin?)
1488
- t2 = self.exclude_begin?
1489
- else
1490
- t2 = false # == return false
1491
- end
1492
- (t2 && exclude_end?)
1493
- end
1494
- when 1
1495
- nil # redundant, as it should not be valid in the first place.
1496
- else
1497
- nil # redundant, as it should not be valid in the first place.
1498
- end
1499
- end # def empty?
1500
-
1501
-
1502
- # Returns true if it is either empty or invalid. false otherwise.
1503
- # See {#empty?} and {#valid?}.
1504
- def null?
1505
- (! valid?) || empty?
1506
- end
1507
-
1508
- # @return [FalseClass]
1509
- def is_none?
1510
- false
1511
- end
1512
-
1513
- # @return [FalseClass]
1514
- def is_all?
1515
- false
1516
- end
1517
-
1518
-
1519
- # Return true if self and the other are equivalent; if [#to_a] is defined, it is similar to
1520
- # (self.to_a == other.to_a)
1521
- # (though the ends are checked more rigorously), and if not, equivalent to
1522
- # (self == other)
1523
- #
1524
- # @example
1525
- # (3...7).equiv?(3..6) # => true
1526
- # (3...7).equiv?(3..6.0) # => false
1527
- # (3...7).equiv?(3.0..6.0) # => false
1528
- # (3...7).equiv?(3..6.5) # => false
1529
- # (3...7).equiv?(3.0...7.0) # => true
1530
- # (3...7.0).equiv?(3..6) # => true
1531
- # (3...7.0).equiv?(3.0..6) # => false
1532
- #
1533
- # @param other [Range, RangeExtd]
1534
- def equiv?(other)
1535
- t_or_f = (defined?(self.begin.succ) && defined?(other.begin.succ) && defined?(other.end) && defined?(other.exclude_end?))
1536
- if ! t_or_f
1537
- return(self == other) # succ() for begin is not defined.
1538
- else
1539
- # Checking the begins.
1540
- if defined?(other.exclude_begin?) && other.exclude_begin? # The other is RangeExtd with exclude_begin?==true.
1541
- if self.begin != other.begin.succ
1542
- return false
1543
- else
1544
- # Pass
1545
- end
1546
- elsif (self.begin != other.begin)
1547
- return false
1548
- end
1549
-
1550
- # Now, the begins agreed. Checking the ends.
1551
- if (self.end == other.end)
1552
- if (exclude_end? ^! other.exclude_end?)
1553
- return true
1554
- else
1555
- return false
1556
- end
1557
- else # if (self.end == other.end)
1558
- if (exclude_end? ^! other.exclude_end?)
1559
- return false
1560
- elsif ( exclude_end? && defined?(other.end.succ) && (self.end == other.end.succ)) ||
1561
- (other.exclude_end? && defined?( self.end.succ) && (self.end.succ == other.end))
1562
- return true
1563
- else
1564
- return false
1565
- end
1566
- end # if (self.end == other.end)
1567
- end # if ! t_or_f
1568
-
1569
- end # def equiv?(other)
1570
-
1571
-
1572
- ############## pravate methods of Range ##############
1573
-
1574
- private
1575
-
1576
- # True if obj is Comparable.
1577
- def is_comparable?(obj)
1578
- if defined?(obj.<=) # Comparable?
1579
- true
1580
- else
1581
- false
1582
- end
1583
- end
1584
-
1585
- # @param r [Object] to compare.
1586
- # @param method [Symbol] of the method name.
1587
- # @param method_pre [Symbol] of the backed-up original method name.
1588
- def equal_core(r, method, method_pre)
1589
- if (! defined? r.exclude_end?) || (! defined? r.is_none?) || (! defined? r.empty?)
1590
- false # Not Range family.
1591
- # elsif empty? && defined?(r.is_none?) && r.is_none? # r is RangeExtd::NONE
1592
- # true
1593
- # elsif empty? && r.empty?
1594
- # # None of built-in Range class object can be #empty?==true - This is for sub-class.
1595
- #
1596
- elsif defined? r.exclude_begin?
1597
- # Either RangeExtd or RangeOpen object.
1598
- if r.exclude_begin?
1599
- false # self(Range) has always the inclusive begin.
1600
- else
1601
- # It could do with a single line,
1602
- # self.begin.send(method_pre, r)
1603
- # if this was for RangeExtd===r, but not for RangeOpen.
1604
- if (self.exclude_end? ^ r.exclude_end?)
1605
- false
1606
- elsif (self.begin.send(method, r.begin) && self.end.send(method, r.end))
1607
- true
1608
- else
1609
- false
1610
- end
1611
- end
1612
- else
1613
- self.send(method_pre, r) # r is Range.
1614
- end
1615
- end # def equal_core(r, method, method_pre)
1616
-
1617
- end # class Range
1618
-
1373
+ # require Range; it is necessary to modify Range if in a backward-compatible way.
1374
+ require_relative "range_extd/range" if !Range.method_defined?(:eql_prerangeextd?)
1619
1375
 
1620
1376
  # Constant-form of {#RangeExtd}.
1621
- # #RangeExtd(*) is equivalent to {#RangeExtd.new}.
1622
1377
  #
1623
- # NOTE:
1624
- # "warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call"
1625
- # is raised if '**hs*' is completely omitted. I do not know how to
1626
- # deal with this, other than adding **hs.
1378
+ # +RangeExtd()+ is equivalent to {#RangeExtd.new}().
1379
+ #
1380
+ # @return [RangeExtd]
1627
1381
  def RangeExtd(*rest, **hs, &b)
1628
1382
  RangeExtd.new(*rest, **hs, &b)
1629
1383
  end