rangeary 0.3.0 → 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.gitignore +55 -0
- data/ChangeLog +10 -0
- data/Makefile +23 -0
- data/News +4 -0
- data/README.ja.rdoc +326 -80
- data/lib/rangeary/rangeary.rb +791 -358
- data/test/test_rangeary.rb +158 -32
- metadata +11 -11
- data/rangeary.gemspec +0 -48
data/lib/rangeary/rangeary.rb
CHANGED
@@ -43,64 +43,127 @@ end
|
|
43
43
|
# Class to express the multiple ranges.
|
44
44
|
#
|
45
45
|
# The library package <tt>range_extd</tt> is required.
|
46
|
-
#
|
46
|
+
# https://rubygems.org/gems/range_extd
|
47
|
+
#
|
48
|
+
# An arbitrary number of {Rangeary},
|
49
|
+
# {RangeExtd}[http://rubygems.org/gems/range_extd] or Range objects (or its
|
50
|
+
# descendant classes) can be supplied for the constructor {#initialize}.
|
51
|
+
# Then, an operation of disjunction is performed to get the clean Array of
|
52
|
+
# RangeExtd, none of which overlaps with the range.
|
53
|
+
#
|
54
|
+
# Once it is constructed, {Rangeary} objects are immutable. Any subsequent
|
55
|
+
# operations return a new {Rangeary} object. All but few methods of {Array}
|
56
|
+
# are inherited, though some methods, such as +push+ do not work because of
|
57
|
+
# immutability of {Rangeary} objects.
|
47
58
|
#
|
48
59
|
class Rangeary < Array
|
49
60
|
undef_method :*, :+, :length, :reverse
|
50
61
|
|
51
|
-
# Hash with the keys of :negative and :positive
|
52
|
-
attr_reader :infinities
|
62
|
+
# # Hash with the keys of :negative and :positive => becomes a method in Ver.1
|
63
|
+
# attr_reader :infinities
|
53
64
|
|
65
|
+
# Constructor
|
54
66
|
#
|
55
67
|
# Arbitrary (positive) number of arguments can be given.
|
56
68
|
# (r1, [r2, ...])
|
57
69
|
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
70
|
+
# == Algorithm about the infinity
|
71
|
+
#
|
72
|
+
# In {Rangeary} operations, "infinity" is essential. Without it, negation
|
73
|
+
# could not be definied. To determine what the positive and negative
|
74
|
+
# infinities for the given elements is not a trivial task.
|
75
|
+
#
|
76
|
+
# Callers can supply user-defined infinity objects for both or either
|
77
|
+
# positive and negative infinity and in that case they are accepted
|
78
|
+
# as the infinities with the highest priority, though ArgumentError might be
|
79
|
+
# issued if they contradict the elements; for example, if a {Rangeary}
|
80
|
+
# instance consists of an array of Integer Ranges (RangeExtd) like (3..8),
|
81
|
+
# and yet if String "abc" is specified as an infinity, it *contradicts*
|
82
|
+
# with the elements in the sense they are not comparable.
|
83
|
+
#
|
84
|
+
# Alternatively, if the main argument contains one or moer {Rangeary}
|
85
|
+
# instances, their infinities are inherited. If their infinities are not
|
86
|
+
# identical to one another, warning may be issued if $VERBOSE is true, and
|
87
|
+
# the infinities are selected in the following priority order:
|
88
|
+
#
|
89
|
+
# 1. If one or more user-supplied infinities are found, the smallest and
|
90
|
+
# largest ones are accepted for the positive and negative infinities.
|
91
|
+
# Note the consistency is not checked; that is, even if one or more of
|
92
|
+
# the provided Range elements from which a {Rangeary} instance is about
|
93
|
+
# to be constructed exceed the infinities, this does not warn. Obviously
|
94
|
+
# subsequent operations may result in some unexpected result. Be warned.
|
95
|
+
# 2. Float::INFINITY.
|
96
|
+
# 3. RangeExtd::Infinity instances (RangeExtd::Infinity::POSITIVE
|
97
|
+
# and RangeExtd::Infinity::NEGATIVE)
|
98
|
+
#
|
99
|
+
# If none of the main arguments contains {Rangeary}, the elements of each
|
100
|
+
# Range are checked whether they have any comparable Numeric instances
|
101
|
+
# like Integer (but not Complex), and if so, Float::INFINITY is set
|
102
|
+
# as the infinities. Otherwise, it falls back to the defaults of
|
103
|
+
# the RangeExtd::Infinity instances.
|
62
104
|
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
105
|
+
# The registered infinities for each instance is obtained as a Hash with
|
106
|
+
# two keys of +:positive+ and +negative+ with the method {#infinities};
|
107
|
+
# for example,
|
108
|
+
#
|
109
|
+
# ran.infinities # => { :positive => RangeExtd::Infinity::POSITIVE,
|
110
|
+
# # :negative => "aa" }
|
111
|
+
#
|
112
|
+
# === Note for Developers about the infinity
|
113
|
+
#
|
114
|
+
# Instance variable @infinities (Hash) is defined. The elements can be nil;
|
115
|
+
# for example, when only the element is RangeExtd::NONE.
|
116
|
+
# So, it is recommended to access with the {#infinities} method rather
|
117
|
+
# than accessing @infinities directly.
|
118
|
+
#
|
119
|
+
# At the moment, the infinities are guessed from the elements of the Range
|
120
|
+
# it contains and set (+guess_strict: false+ is given to {#_get_infinities}).
|
121
|
+
# If +guess_strict: true+ is given, unless a Range contains literally
|
122
|
+
# +Float::INFINITY+ etc, (the element of) @infinities is not set (remains nil).
|
123
|
+
# I hope it would work even if +guess_strict: true+ is given. However,
|
124
|
+
# it is not tested properly! Anyway, to check the consistency of
|
125
|
+
# the infinities is desirable, which is performed now, thanks to
|
126
|
+
# +guess_strict: false+ given to {#_get_infinities}.
|
127
|
+
#
|
128
|
+
# @param inarall [Object] An arbitrary number of either {Rangeary}, RangeExtd or Range objects (or its subclasses).
|
129
|
+
# @option **opts [Object] :positive Object for positive infinity. In default Float::INFINITY for comparable Numeric or else {RangeExtd::Infinity::POSITIVE}.
|
130
|
+
# @option **opts [Object] :negative Object for negative infinity. In default -Float::INFINITY for comparable Numeric or else {RangeExtd::Infinity::NEGATIVE}.
|
66
131
|
def initialize(*inarall, **opts)
|
132
|
+
@infinities = { :negative => nil, :positive => nil }
|
67
133
|
|
68
134
|
if inarall.size < 1
|
69
|
-
|
135
|
+
super [RangeExtd::NONE] # Since Ver.1
|
136
|
+
return
|
137
|
+
# raise ArgumentError, "wrong number of arguments (#{inarall.size} for 1 or more)."
|
70
138
|
end
|
71
139
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
inarall = inarall.map{|i|
|
76
|
-
if defined?(i.first_element) && defined?(i.infinities)
|
77
|
-
begin
|
78
|
-
[:negative, :positive].each do |nega_posi|
|
79
|
-
hsInheritedAry[nega_posi].push( i.infinities[nega_posi])
|
80
|
-
hsInheritedClass[nega_posi].push(i.infinities[nega_posi].class)
|
81
|
-
end
|
82
|
-
rescue
|
83
|
-
warn "warning: Rangeary#infinities looks wrong in the input (#{i})."
|
84
|
-
end
|
85
|
-
i.to_a
|
86
|
-
else
|
87
|
-
i
|
88
|
-
end
|
140
|
+
# Unfold Rangeary into Array of Arrays and convert Range-s into RangeExtd-s
|
141
|
+
in_ranges = inarall.map{|i|
|
142
|
+
self.class.send(:is_rangeary_type?, i) ? i.to_a : i
|
89
143
|
}.flatten.map{|j|
|
90
144
|
if (defined? j.exclude_begin?)
|
91
145
|
j
|
92
146
|
else
|
93
147
|
begin
|
94
148
|
RangeExtd.new(j)
|
95
|
-
rescue ArgumentError
|
149
|
+
rescue ArgumentError, RangeError # Just to change the error message.
|
96
150
|
raise ArgumentError, "invalid parameter for RangeExtd, hence for Rangeary (#{j.inspect})."
|
97
151
|
end
|
98
152
|
end
|
99
153
|
}
|
100
154
|
|
101
|
-
#
|
155
|
+
# NOTE: Simple map(&:infinities) is not ideal here, because map(&:infinities) tries to
|
156
|
+
# supplement when the value is nil. However, in self.conjunction(), it uses map(&:infinities),
|
157
|
+
# which is not ideal.
|
158
|
+
inherited_infs = inarall.find_all{|i| self.class.send(:is_rangeary_type?, i)}.map{ |ec|
|
159
|
+
ec.instance_variable_get(:@infinities)
|
160
|
+
}
|
161
|
+
|
162
|
+
@infinities = _get_infinities(in_ranges, inherited_infs: inherited_infs, guess_strict: false, **opts) # set @infinities (wherever possible)
|
163
|
+
|
164
|
+
# Call _merge_overlaps
|
102
165
|
begin
|
103
|
-
arRange = _merge_overlaps( convert2range(
|
166
|
+
arRange = _merge_overlaps( convert2range(in_ranges) )
|
104
167
|
rescue => err
|
105
168
|
# Trap just to change the type of the exception.
|
106
169
|
raise ArgumentError, err.message, err.backtrace
|
@@ -111,87 +174,7 @@ class Rangeary < Array
|
|
111
174
|
end
|
112
175
|
|
113
176
|
## Setting @infinities[:negative, :positive]
|
114
|
-
|
115
|
-
# Check inherited objects if there is any, namely if the argument includes any RangeAry object.
|
116
|
-
# Priority: Float > Others > RangeExtd::Infinity
|
117
|
-
if hsInheritedAry[:negative].size > 0
|
118
|
-
[:negative, :positive].each do |es|
|
119
|
-
iFloat = hsInheritedClass[es].find_index(Float)
|
120
|
-
if iFloat.nil?
|
121
|
-
iElse = hsInheritedClass[es].find_index{|i| (i != RangeExtd::Infinity) && (i != Float)}
|
122
|
-
if iElse.nil?
|
123
|
-
iRangeInf = hsInheritedClass[es].find_index(RangeExtd::Infinity)
|
124
|
-
if iRangeInf.nil?
|
125
|
-
raise "Rangeary#infinities is not set in the input." # Should not happen, as Rangeary#infinities must be set always.
|
126
|
-
else
|
127
|
-
hsInheritedObj[es] = hsInheritedAry[es][iRangeInf]
|
128
|
-
end
|
129
|
-
else
|
130
|
-
hsInheritedObj[es] = hsInheritedAry[es][iElse]
|
131
|
-
end
|
132
|
-
else
|
133
|
-
hsInheritedObj[es] = hsInheritedAry[es][iFloat]
|
134
|
-
end # if iFloat.nil?
|
135
|
-
end # [:negative, :positive].each do |es|
|
136
|
-
end # if hsInheritedAry.size > 0
|
137
|
-
|
138
|
-
hsFlag = { :found => {:negative => false, :positive => false} }
|
139
|
-
hsCand = { :negative => arRange[0].begin, :positive => arRange[-1].end }
|
140
|
-
infDef = { :negative => RangeExtd::Infinity::NEGATIVE, :positive => RangeExtd::Infinity::POSITIVE }
|
141
|
-
@infinities={ :negative => nil, :positive => nil }
|
142
|
-
[:negative, :positive].each do |es|
|
143
|
-
if (infDef[es] == hsCand[es]) # Can be Float or whatever.
|
144
|
-
@infinities[es] = hsCand[es] # highest priority
|
145
|
-
hsFlag[:found][:negative] = true
|
146
|
-
else
|
147
|
-
strtmp = ""
|
148
|
-
[opts[es], hsInheritedObj[es]].each do |opts_or_inherited|
|
149
|
-
@infinities[es] ||= opts_or_inherited # uses ots[:****tive] or hsInheritedObj[:****tive] if not set.
|
150
|
-
# Now, checking the compatibility of the infinity value specified (or inherited) with the given range.
|
151
|
-
if (! opts_or_inherited.nil?) && (opts_or_inherited == @infinities[es]) && (! arRange[0].is_none?)
|
152
|
-
begin
|
153
|
-
_ = 0 * (opts_or_inherited <=> hsCand[es])
|
154
|
-
rescue TypeError
|
155
|
-
raise ArgumentError, "invalid #{strtmp}parameter for :#{es} => (#{opts_or_inherited.inspect}), incompatible with the range with begin=(#{hsCand[es].inspect})."
|
156
|
-
end
|
157
|
-
end
|
158
|
-
strtmp = "inherited "
|
159
|
-
end # [opts[es], hsInheritedObj[es]].each do |opts_or_inherited|
|
160
|
-
end # if (infDef[es] == hsCand[es]) # else
|
161
|
-
end # [:negative, :positive].each do |es|
|
162
|
-
|
163
|
-
if ! (@infinities[:negative] && @infinities[:positive])
|
164
|
-
# Either or both @infinities[:negative, :positive] is not set, yet.
|
165
|
-
# Need to set it now. The possibilities are,
|
166
|
-
# (1) arRange[0].null? && no opts/inheritance given.
|
167
|
-
# (2) one of them is given by either arRange or opts or inheritance, but not the other.
|
168
|
-
# (3) neither of them is given by arRange nor opts nor inheritance.
|
169
|
-
if arRange[0].null?
|
170
|
-
[:negative, :positive].each do |es|
|
171
|
-
@infinities[es] ||= infDef[es]
|
172
|
-
end
|
173
|
-
else
|
174
|
-
# There must be a non-infinity object - we will find it out.
|
175
|
-
if hsFlag[:found][:negative]
|
176
|
-
obj2refer = arRange[0].end
|
177
|
-
else
|
178
|
-
obj2refer = arRange[-1].begin
|
179
|
-
end
|
180
|
-
|
181
|
-
# Now, if Numeric === obj2refer, Float::INFINITY is the default.
|
182
|
-
begin
|
183
|
-
_dummy = (1.0 < obj2refer)
|
184
|
-
rescue ArgumentError
|
185
|
-
# Not Numeric, hence the current infDef is used as it is.
|
186
|
-
else
|
187
|
-
# Numeric
|
188
|
-
infDef = { :negative => -Float::INFINITY, :positive => Float::INFINITY }
|
189
|
-
end
|
190
|
-
[:negative, :positive].each do |es|
|
191
|
-
@infinities[es] ||= infDef[es] # uses default infinity if not set.
|
192
|
-
end
|
193
|
-
end # if arRange[0].null?
|
194
|
-
end # if ! (@infinities[:negative] && @infinities[:positive])
|
177
|
+
# set_infinities_legacy(arRange, hsInheritedObj, hsInheritedAry, hsInheritedClass, **opts)
|
195
178
|
|
196
179
|
super(arRange)
|
197
180
|
self.freeze
|
@@ -199,13 +182,38 @@ class Rangeary < Array
|
|
199
182
|
|
200
183
|
alias_method :triple_equals_orig, :=== if ! self.method_defined?(:triple_equals_orig)
|
201
184
|
|
185
|
+
# Returns @infinities where nil values are replaced with something significant.
|
186
|
+
#
|
187
|
+
# Best guess approach is taken.
|
188
|
+
#
|
189
|
+
# @return [Hash] keys of :positive and :negative. The values are never nil.
|
190
|
+
def infinities
|
191
|
+
defhs = {
|
192
|
+
:positive => RangeExtd::Infinity::POSITIVE,
|
193
|
+
:negative => RangeExtd::Infinity::NEGATIVE,
|
194
|
+
}
|
195
|
+
hsret = {}.merge @infinities
|
196
|
+
if hsret[:positive].nil?
|
197
|
+
return defhs if hsret[:negative].nil?
|
198
|
+
hsret[:positive] = (is_num_type?(hsret[:negative]) ? Float::INFINITY : defhs[:positive])
|
199
|
+
return hsret
|
200
|
+
end
|
201
|
+
if hsret[:negative].nil?
|
202
|
+
hsret[:negative] = (is_num_type?(hsret[:positive]) ? -Float::INFINITY : defhs[:negative])
|
203
|
+
return hsret
|
204
|
+
end
|
205
|
+
|
206
|
+
hsret
|
207
|
+
end
|
208
|
+
|
202
209
|
# If self covers the entire range?
|
203
210
|
#
|
204
211
|
def all?
|
205
212
|
rfirst = self[0]
|
206
213
|
((1 == size) &&
|
207
|
-
|
208
|
-
(
|
214
|
+
!rfirst.is_none? &&
|
215
|
+
(infinities[:negative] == rfirst.begin) &&
|
216
|
+
((infinities[:positive] == rfirst.end) || rfirst.end.nil?) && # Ruby 2.6 Endless Range
|
209
217
|
(!rfirst.exclude_begin?) &&
|
210
218
|
(!rfirst.exclude_end?))
|
211
219
|
end
|
@@ -359,13 +367,13 @@ class Rangeary < Array
|
|
359
367
|
#
|
360
368
|
# @return [Array]
|
361
369
|
# @raise [TypeError] if any of the ranges has no iteration defined, such as, starting from Float.
|
362
|
-
# @example
|
370
|
+
# @example
|
363
371
|
# Rangeary(2...4, 5..6, 8..9).to_a # => [2...4, 5..6, 8..9]
|
364
372
|
# Rangeary(2...4, 5..6, 8..9).flatten # => [2, 3, 5, 6, 8, 9]
|
365
373
|
# Rangeary(2...4, 5..6, 8..9).flatten.reduce(:+) # => 33
|
366
|
-
def
|
374
|
+
def flatten_element
|
367
375
|
to_a.reduce([]){|a,b| a+=b.to_a}
|
368
|
-
end
|
376
|
+
end
|
369
377
|
|
370
378
|
|
371
379
|
# @return [String]
|
@@ -515,7 +523,7 @@ class Rangeary < Array
|
|
515
523
|
alias_method :*, :conjunction
|
516
524
|
|
517
525
|
|
518
|
-
# Negation.
|
526
|
+
# Negation (class method).
|
519
527
|
#
|
520
528
|
# @param r [Rangeary, RangeExtd, Range]
|
521
529
|
# @return [Rangeary]
|
@@ -533,7 +541,8 @@ class Rangeary < Array
|
|
533
541
|
end
|
534
542
|
|
535
543
|
arran = []
|
536
|
-
prevend = nil
|
544
|
+
prevend = nil # if "end" is nil, this is substituted with Infinity.
|
545
|
+
prevend_orig = Object # For Endless Range (Ruby 2.6), this can be nil.
|
537
546
|
prevst = nil
|
538
547
|
to_a.each do |eachr|
|
539
548
|
|
@@ -546,7 +555,7 @@ class Rangeary < Array
|
|
546
555
|
_beg = 1.0 * eachr.begin
|
547
556
|
return (-Float::INFINITY..Float::INFINITY)
|
548
557
|
rescue TypeError # XXXX can't be coerced into Float
|
549
|
-
return Rangeary.new(
|
558
|
+
return Rangeary.new(infinities[:negative]..infinities[:positive])
|
550
559
|
end
|
551
560
|
end
|
552
561
|
|
@@ -556,22 +565,34 @@ class Rangeary < Array
|
|
556
565
|
else
|
557
566
|
if prevend.nil?
|
558
567
|
# The returned first range starts from the negative infinity.
|
559
|
-
|
568
|
+
ran_tmp = normalized_range_for_negation(infinities[:negative], eachr.begin)
|
569
|
+
if RangeExtd::NONE != ran_tmp
|
570
|
+
# Avoid (inf..inf) type, which would cause RangeError (in Ruby 2.6) anyway.
|
571
|
+
arran.push( RangeExtd(ran_tmp, :exclude_end => (! eachr.exclude_begin?)) )
|
572
|
+
end
|
560
573
|
else
|
561
|
-
arran.push( RangeExtd(
|
574
|
+
arran.push( RangeExtd(prevend_orig, eachr.begin, :exclude_begin => (! prevst), :exclude_end => (! eachr.exclude_begin?)) )
|
575
|
+
# arran.push( RangeExtd(prevend, eachr.begin, :exclude_begin => (! prevst), :exclude_end => (! eachr.exclude_begin?)) )
|
562
576
|
end
|
563
577
|
end # if (eachr.begin == -Float::INFINITY) || (RangeExtd::NONE == eachr.begin)
|
564
|
-
|
578
|
+
prevend_orig = eachr.end
|
579
|
+
prevend = _comparable_end(eachr) # For Ruby-2.6 Endless Range
|
565
580
|
prevst = eachr.exclude_end?
|
566
581
|
end # to_a.each do |eachr|
|
567
582
|
|
568
583
|
if (RangeExtd::Infinity::POSITIVE == prevend) # Including Float::INFINITY and other general positive infinities (nb., [#==] is not commutative!).
|
569
584
|
## Do nothing
|
570
585
|
else
|
571
|
-
|
586
|
+
rbeg = (prevend_orig || prevend)
|
587
|
+
ran_tmp = normalized_range_for_negation(rbeg, infinities[:positive])
|
588
|
+
|
589
|
+
if RangeExtd::NONE != ran_tmp
|
590
|
+
# Avoid (inf..inf) type, which would cause RangeError (in Ruby 2.6) anyway.
|
591
|
+
arran.push( RangeExtd.new(ran_tmp, :exclude_begin => (! prevst)) )
|
592
|
+
end
|
572
593
|
end
|
573
594
|
|
574
|
-
Rangeary.new(arran, :positive =>
|
595
|
+
Rangeary.new(arran, :positive => infinities[:positive], :negative => infinities[:negative])
|
575
596
|
end # def negation()
|
576
597
|
|
577
598
|
alias_method :~@, :negation
|
@@ -585,7 +606,7 @@ class Rangeary < Array
|
|
585
606
|
#
|
586
607
|
# @param r1 [Rangeary, RangeExtd, Range]
|
587
608
|
# @param r2 [Rangeary, RangeExtd, Range]
|
588
|
-
# @return [Rangeary]
|
609
|
+
# @return [Rangeary]
|
589
610
|
def self.conjunction(r1, r2)
|
590
611
|
|
591
612
|
r1 = Rangeary.new(r1) if ! defined? r1.first_element
|
@@ -595,20 +616,8 @@ class Rangeary < Array
|
|
595
616
|
return Rangeary.new(r2) if r1.all?
|
596
617
|
|
597
618
|
# Getting inherited options (if Rangeary is given) for the later use.
|
598
|
-
hsInherited =
|
599
|
-
[
|
600
|
-
hsInherited[ei] = [r1.infinities[ei], r2.infinities[ei]].map{|j|
|
601
|
-
(RangeExtd::Infinity === j) ? nil : j
|
602
|
-
}.compact.sort{|a,b|
|
603
|
-
if a.class == Float
|
604
|
-
-1
|
605
|
-
elsif b.class == Float
|
606
|
-
1
|
607
|
-
else
|
608
|
-
0
|
609
|
-
end
|
610
|
-
}[0]
|
611
|
-
end
|
619
|
+
hsInherited = _validate_select_infinities [r1, r2].map(&:infinities)
|
620
|
+
# hsInherited = _best_inherited_infinities [r1, r2].map(&:infinities)
|
612
621
|
|
613
622
|
# Initialisation
|
614
623
|
a1 = r1.to_a
|
@@ -633,8 +642,14 @@ class Rangeary < Array
|
|
633
642
|
a1.each_with_index do |ea1, ind|
|
634
643
|
# A bit of trick just to avoid unnecessary process
|
635
644
|
next if ind < last_a1index # skip
|
636
|
-
|
637
|
-
|
645
|
+
|
646
|
+
# For Ruby-2.6 Endless Range, comparable_end() is employed.
|
647
|
+
# Note: this comparison ignores @infinities even if set,
|
648
|
+
# because @infinities may not be defined in the arguments!
|
649
|
+
# Anyway, nothing should be larger than the upper limit (as tested below),
|
650
|
+
# and so this should be fine.
|
651
|
+
break if comparable_end(ea2) < ea1.begin # Completely out of range
|
652
|
+
if comparable_end(ea1) < ea2.begin # Completely out of range
|
638
653
|
last_a1index = ind if last_a1index < ind
|
639
654
|
next
|
640
655
|
end
|
@@ -652,6 +667,54 @@ class Rangeary < Array
|
|
652
667
|
end # def self.conjunction(r1, r2)
|
653
668
|
|
654
669
|
|
670
|
+
# Returns the infinity "end" that is comparable.
|
671
|
+
#
|
672
|
+
# Since Ruby-2.6, the Endless Range is introduced.
|
673
|
+
# In Ruby definition, the Endless Range er takes a form of er=(5..nil),
|
674
|
+
# and accordingly its "end" (or +last+) is nil:
|
675
|
+
#
|
676
|
+
# (5..nil).end # => nil
|
677
|
+
#
|
678
|
+
# Then, when you compare the "ends" of two Ranges with the method +<=>+,
|
679
|
+
# the result too is nil.
|
680
|
+
#
|
681
|
+
# In fact, in Ruby, two Range objects are not comparable with eath other,
|
682
|
+
# though the operator (or method) +<=>+ is defined for Range:
|
683
|
+
#
|
684
|
+
# (3..6) <=> (8..9) # => nil
|
685
|
+
#
|
686
|
+
# (Note this default behaviour is not unreasonable given what one compares
|
687
|
+
# is equivocal for Ranges, for example, the size, start or end?
|
688
|
+
# Indeed Range does not have a method +Range<=+ and hence +<=>+ is meaningless.)
|
689
|
+
#
|
690
|
+
# Then, when Range#end returns just nil, which should be interpreted
|
691
|
+
# as *Endless* in Range's context, it does not matter for Range.
|
692
|
+
# However, it is inconvenient for this class, {Rangeary}!
|
693
|
+
# The heart of comparison in {Rangeary} is +<=>+ for the begin first,
|
694
|
+
# and then the end if the first comparison results in equal.
|
695
|
+
#
|
696
|
+
# This method converts Range#end into something comparable when possible.
|
697
|
+
# More specifically, if the "end" of the given Range is nil, this returns
|
698
|
+
# Infinity (either +Float::INFINITY+ or +RangeExtd::Infinity::POSITIVE+),
|
699
|
+
# unless both begin and end are nil (RangeExtd::NONE, nil..nil, nil...nil),
|
700
|
+
# in which case nil is returned, and else returns simply +Range#end+.
|
701
|
+
#
|
702
|
+
# @param ran [Range, RangeExtd]
|
703
|
+
# @return [Object]
|
704
|
+
def self.comparable_end(ran)
|
705
|
+
if ran.class.method_defined?(:is_none?) && ran.is_none?
|
706
|
+
nil
|
707
|
+
elsif ran.end.nil? && ran.begin.nil?
|
708
|
+
nil
|
709
|
+
elsif ! ran.end.nil?
|
710
|
+
ran.end # Before Ruby 2.6, this is always the case.
|
711
|
+
elsif ran.begin.class.method_defined? :to_int
|
712
|
+
Float::INFINITY
|
713
|
+
else
|
714
|
+
RangeExtd::Infinity::POSITIVE
|
715
|
+
end
|
716
|
+
end
|
717
|
+
|
655
718
|
# Returns the array sorted, based on (1) the begin objects and their boundary state,
|
656
719
|
# (2) then the end objects and their boundary state.
|
657
720
|
# {RangeExtd::NONE} comes first, if included in the input array.
|
@@ -661,6 +724,16 @@ class Rangeary < Array
|
|
661
724
|
def self.sort_ranges(*ar)
|
662
725
|
ar.flatten.sort{ |a,b|
|
663
726
|
err_msg_ab = "invalid parameter (#{a.inspect} or #{b.inspect})."
|
727
|
+
|
728
|
+
# Since Ruby-2.6, the end can be nil (Endless Range).
|
729
|
+
# Before Ruby-2.6, they used to raise Exception (ArgumentError) in Range
|
730
|
+
# and so they would not have sneaked in to RangeExtd, either.
|
731
|
+
# The following is in that sense meaningful only for Ruby 2.6 and later.
|
732
|
+
ends = { :a => a, :b => b }
|
733
|
+
ends.each_pair do |k, v|
|
734
|
+
ends[k] = comparable_end(v)
|
735
|
+
end
|
736
|
+
|
664
737
|
ret = a.begin <=> b.begin
|
665
738
|
case ret
|
666
739
|
when -1, 1
|
@@ -675,7 +748,7 @@ class Rangeary < Array
|
|
675
748
|
-1
|
676
749
|
end
|
677
750
|
else # <= (a.exclude_begin? == b.exclude_begin?)
|
678
|
-
ret = a
|
751
|
+
ret = ends[:a] <=> ends[:b]
|
679
752
|
case ret
|
680
753
|
when -1, 1
|
681
754
|
ret
|
@@ -690,18 +763,18 @@ class Rangeary < Array
|
|
690
763
|
when nil
|
691
764
|
# This should not happen for Range, let alone RangeExtd.
|
692
765
|
# But could be the case for a user-defined class.
|
693
|
-
if a.
|
766
|
+
if ends[:a].nil? && ends[:b].nil?
|
694
767
|
0
|
695
|
-
elsif a.
|
768
|
+
elsif ends[:a].nil?
|
696
769
|
-1
|
697
|
-
elsif b.
|
770
|
+
elsif ends[:b].nil?
|
698
771
|
1
|
699
772
|
else
|
700
773
|
raise(TypeError, err_msg_ab)
|
701
774
|
end
|
702
|
-
else # case ret # a
|
775
|
+
else # case ret # ends[:a] <=> ends[:b]
|
703
776
|
raise(TypeError, err_msg_ab)
|
704
|
-
end # case ret # a
|
777
|
+
end # case ret # ends[:a] <=> ends[:b]
|
705
778
|
end # if (a.exclude_begin? ^ b.exclude_begin?)
|
706
779
|
when nil # case ret #(a.begin <=> b.begin)
|
707
780
|
if a.begin.nil? && b.begin.nil?
|
@@ -720,7 +793,6 @@ class Rangeary < Array
|
|
720
793
|
end # def self.sort_ranges(ar)
|
721
794
|
|
722
795
|
|
723
|
-
|
724
796
|
####################
|
725
797
|
private
|
726
798
|
####################
|
@@ -742,8 +814,362 @@ class Rangeary < Array
|
|
742
814
|
}
|
743
815
|
end
|
744
816
|
|
817
|
+
# Get the instance variable (Hash) @infinities
|
818
|
+
#
|
819
|
+
# @param in_infs [Hash] infinities template with keys: :positive, :negative
|
820
|
+
# @param arin [Array<Range, RangeExtd, Rangeary>]
|
821
|
+
# @param strict: [Boolean] if true (Def: false), set only when the value satisfies RangeExtd::Infinity.infinite?
|
822
|
+
# @param leave_existing: [Boolean] if true (Def: false), the existing non-nil values are not updated.
|
823
|
+
# @return [Array] Best guess for @infinities
|
824
|
+
def _best_guessed_infinities(in_infs, arin, strict: false, leave_existing: false)
|
825
|
+
reths = {}.merge in_infs
|
826
|
+
# Making the best effort to guess.
|
827
|
+
ar_rae = [RangeExtd::Infinity::NEGATIVE, RangeExtd::Infinity::POSITIVE]
|
828
|
+
ar_num = [-Float::INFINITY, Float::INFINITY]
|
829
|
+
[arin].flatten.each do |ea|
|
830
|
+
hs = { negative: ea.begin, positive: ea.end }
|
831
|
+
reths.each_key do |ek|
|
832
|
+
errmsg = "Contradictory reference value #{hs[ek].inspect} for infinity (Existent: #{reths[ek].inspect}) is found, but ignored."
|
833
|
+
next if !hs[ek]
|
834
|
+
case reths[ek]
|
835
|
+
when nil
|
836
|
+
reths[ek] = _guessed_infinity(ek, hs[ek], strict: strict)
|
837
|
+
next
|
838
|
+
when *ar_rae
|
839
|
+
reths[ek] = (_guessed_infinity(ek, hs[ek], strict: strict) || reths[ek]) if !leave_existing # Update whatever.
|
840
|
+
next
|
841
|
+
when *ar_num
|
842
|
+
# Once Float::INFINITY is set, it will unchange.
|
843
|
+
next if ar_num.include? _guessed_infinity(ek, hs[ek]) # Consistent
|
844
|
+
next if ar_rae.include? _guessed_infinity(ek, hs[ek]) # Inconsistent, but ignore (Prev: Range::Inf, Given: Float::INF)
|
845
|
+
warn errmsg if !$VERBOSE.nil?
|
846
|
+
next
|
847
|
+
else
|
848
|
+
# Once User's value is set, it will unchange.
|
849
|
+
next if ar_rae.include? _guessed_infinity(ek, hs[ek]) # Inconsistent, but ignore (Prev: User, Given: Infinity)
|
850
|
+
warn errmsg if !$VERBOSE.nil?
|
851
|
+
next
|
852
|
+
end
|
853
|
+
end
|
854
|
+
end
|
855
|
+
reths
|
856
|
+
end
|
857
|
+
private :_best_guessed_infinities
|
858
|
+
|
859
|
+
# Instance method version
|
860
|
+
#
|
861
|
+
# where @infinities are taken into account.
|
862
|
+
#
|
863
|
+
# @param ran [Range, RangeExtd]
|
864
|
+
# @return [Object]
|
865
|
+
def _comparable_end(ran)
|
866
|
+
if ran.class.method_defined?(:is_none?) && ran.is_none?
|
867
|
+
nil
|
868
|
+
elsif ran.end.nil? && ran.begin.nil?
|
869
|
+
nil
|
870
|
+
elsif ! ran.end.nil?
|
871
|
+
ran.end # Before Ruby 2.6, this is always the case.
|
872
|
+
else
|
873
|
+
infinities[:positive] || RangeExtd::Infinity::POSITIVE
|
874
|
+
end
|
875
|
+
end
|
876
|
+
private :_comparable_end
|
877
|
+
|
878
|
+
# Same as {#_comparable_end} but for begin
|
879
|
+
#
|
880
|
+
# Beyond the current Ruby (2.6).
|
881
|
+
# Needed for {#negation}.
|
882
|
+
#
|
883
|
+
# @param rbeg [Object]
|
884
|
+
# @param rend [Object]
|
885
|
+
# @return [Object]
|
886
|
+
def _comparable_begin(rbeg, rend)
|
887
|
+
if rend.nil? && rbeg.nil?
|
888
|
+
nil
|
889
|
+
elsif ! rbeg.nil?
|
890
|
+
rbeg
|
891
|
+
elsif rend.class.method_defined? :to_int
|
892
|
+
-Float::INFINITY
|
893
|
+
else
|
894
|
+
RangeExtd::Infinity::NEGATIVE
|
895
|
+
end
|
896
|
+
end
|
897
|
+
private :_comparable_begin
|
898
|
+
|
899
|
+
|
900
|
+
# Get the instance variable (Hash) @infinities
|
901
|
+
#
|
902
|
+
# @param arin [Array<Range, RangeExtd, Rangeary>]
|
903
|
+
# @param inherited_infs [Array<Hash<Infinity, nil>>] Inherited infinities from the input Rangeary-s
|
904
|
+
# @param guess_strict [Boolean] if true, make only strict guess for infinities, namely, unless the existing elements contain "infinity"-type objects, leave it nil; it is passed to {#_best_guessed_infinities}(strict: false)
|
905
|
+
# @option **opts [Object] :positive Object for positive infinity. In default {Float::INFINITY} for Numeric Comparable or else {RangeExtd::Infinity::POSITIVE}.
|
906
|
+
# @option **opts [Object] :negative Object for negative infinity. In default -{Float::INFINITY} for Numeric Comparable or else {RangeExtd::Infinity::NEGATIVE}.
|
907
|
+
# @return [Array] guessed @infinities
|
908
|
+
def _get_infinities(arin, inherited_infs: [], guess_strict: false, **opts)
|
909
|
+
# Explicitly specified?
|
910
|
+
reths = _get_infinities_from_opts(opts)
|
911
|
+
if reths
|
912
|
+
_validate_opts_infinities(arin, infs: reths)
|
913
|
+
# return reths if (reths.all?{ |i| i[1] })
|
914
|
+
end
|
915
|
+
leave_existing = !!reths
|
916
|
+
|
917
|
+
hs = {}.merge(@infinities)
|
918
|
+
hs.each_key {|k| hs[k] = nil } # :positive, :negative => nil
|
919
|
+
reths ||= hs
|
920
|
+
|
921
|
+
# Read @infinities from Rangeary-s in arin, if exits
|
922
|
+
reths = self.class.send(:_validate_select_infinities, inherited_infs, reths)
|
923
|
+
|
924
|
+
return reths if (reths.all?{ |i| i[1] })
|
925
|
+
leave_existing ||= reths.any?{ |i| i[1] }
|
926
|
+
|
927
|
+
_best_guessed_infinities(reths, arin, strict: guess_strict, leave_existing: leave_existing)
|
928
|
+
end
|
929
|
+
private :_get_infinities
|
930
|
+
|
931
|
+
# Returns @infinities from the options.
|
932
|
+
#
|
933
|
+
# If not specified actually, returns nil.
|
934
|
+
#
|
935
|
+
# @param opts [Hash]
|
936
|
+
# @return [Hash, nil]
|
937
|
+
def _get_infinities_from_opts(opts)
|
938
|
+
hsret = {}
|
939
|
+
if opts.keys.include?(:positive) || opts.keys.include?(:negative)
|
940
|
+
if opts[:positive]
|
941
|
+
hsret[:positive] = opts[:positive]
|
942
|
+
opts[:negative] = -Float::INFINITY if is_num_type? opts[:positive]
|
943
|
+
hsret[:negative] ||= opts[:negative]
|
944
|
+
return hsret
|
945
|
+
elsif opts[:negative]
|
946
|
+
hsret[:negative] = opts[:negative]
|
947
|
+
opts[:positive] = Float::INFINITY if is_num_type? opts[:negative]
|
948
|
+
return hsret
|
949
|
+
end
|
950
|
+
end
|
951
|
+
return nil
|
952
|
+
end
|
953
|
+
private :_get_infinities_from_opts
|
954
|
+
|
955
|
+
# Returns the best guess Infinity from a given value (like 5.2 or "a")
|
956
|
+
#
|
957
|
+
# @param key [Symbol] either :positive or :negative
|
958
|
+
# @param val [Object] from which Infinity is guessed.
|
959
|
+
# @param strict [Boolean] if strict, unless the value is a kind of Infinite, return nil
|
960
|
+
# @return [Hash<Array>] keys (:positive and :negative) Array#size may not agree between them.
|
961
|
+
def _guessed_infinity(key, val, strict: false)
|
962
|
+
return nil if !val
|
963
|
+
return(RangeExtd::Infinity.infinite?(val) ? val : nil) if strict
|
964
|
+
return(((key == :positive) ? 1 : -1) * Float::INFINITY) if is_num_type? val
|
965
|
+
((key == :positive) ? RangeExtd::Infinity::POSITIVE : RangeExtd::Infinity::NEGATIVE)
|
966
|
+
end
|
967
|
+
private :_guessed_infinity
|
968
|
+
|
969
|
+
|
970
|
+
# Instance method version
|
971
|
+
def is_num_type?(obj)
|
972
|
+
self.class.send(__method__, obj)
|
973
|
+
end
|
974
|
+
private :is_num_type?
|
975
|
+
|
976
|
+
# Normalize a Range, which is about to be used for new {Rangeary}
|
977
|
+
#
|
978
|
+
# @param rbeg [Object]
|
979
|
+
# @param rend [Object]
|
980
|
+
# @return [Range, RangeExtd::NONE]
|
981
|
+
def normalized_range_for_negation(rbeg, rend)
|
982
|
+
begin
|
983
|
+
ret = rbeg..rend # Range
|
984
|
+
rescue RangeError
|
985
|
+
# the begin must be nil, after being converted from an Endless Range as in Ruby 2.6
|
986
|
+
ret = (_comparable_begin(rbeg, rend)..rend) # Range
|
987
|
+
# rescue ArgumentError
|
988
|
+
## NOTE: If this happens, something is gone wrong!!
|
989
|
+
end
|
990
|
+
return RangeExtd::NONE if same_infinities?(ret.begin, ret.end)
|
991
|
+
ret
|
992
|
+
end
|
993
|
+
private :normalized_range_for_negation
|
994
|
+
|
995
|
+
# True if both are infinities and in the same parity
|
996
|
+
#
|
997
|
+
# @param c1 [Object]
|
998
|
+
# @param c2 [Object]
|
999
|
+
def same_infinities?(c1, c2)
|
1000
|
+
arin = [c1, c2]
|
1001
|
+
arin.all?{ |ec| RangeExtd::Infinity.infinite?(ec) } &&
|
1002
|
+
(arin.all?(&:positive?) || arin.all?(&:negative?))
|
1003
|
+
end
|
1004
|
+
private :same_infinities?
|
1005
|
+
|
1006
|
+
# Validate @infinities from the options.
|
1007
|
+
#
|
1008
|
+
# If fails, raise Exception.
|
1009
|
+
#
|
1010
|
+
# @param arin [Array<Range, RangeExtd, Rangeary>]
|
1011
|
+
# @param infs [Hash]
|
1012
|
+
# @return [void]
|
1013
|
+
# @raise [ArgumentError]
|
1014
|
+
def _validate_opts_infinities(arin, infs: @infinities)
|
1015
|
+
infs.each_pair do |ek, my_inf|
|
1016
|
+
next if !my_inf #|| RangeExtd::Infinity.infinite?(my_inf)
|
1017
|
+
arin.flatten.each do |er|
|
1018
|
+
[er.begin, er.end].each do |ev|
|
1019
|
+
next if !ev
|
1020
|
+
next if (is_num_type?(ev) && is_num_type?(my_inf))
|
1021
|
+
begin
|
1022
|
+
case my_inf <=> ev
|
1023
|
+
when -1, 0, 1
|
1024
|
+
next
|
1025
|
+
else # nil
|
1026
|
+
end
|
1027
|
+
rescue # NoMethodError
|
1028
|
+
end
|
1029
|
+
msg = "invalid parameter for :#{ek} => (#{my_inf.inspect}), incompatible with the range with Range=(#{er.inspect})."
|
1030
|
+
raise ArgumentError, msg
|
1031
|
+
end
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
end
|
1035
|
+
private :_validate_opts_infinities
|
1036
|
+
|
1037
|
+
|
1038
|
+
# Legacy routine to set the instance variable (Hash) @infinities
|
1039
|
+
#
|
1040
|
+
# Maybe more complete?
|
1041
|
+
#
|
1042
|
+
# @param [Array]
|
1043
|
+
# @param [Hash]
|
1044
|
+
# @param [Hash]
|
1045
|
+
# @param [Hash]
|
1046
|
+
# @return [void]
|
1047
|
+
def set_infinities_old(arRange, hsInheritedObj, hsInheritedAry, hsInheritedClass, **opts)
|
1048
|
+
|
1049
|
+
### The following is required in the caller before calling this routine
|
1050
|
+
## inarall is the arguement received by initialize()
|
1051
|
+
#
|
1052
|
+
#
|
1053
|
+
# hsInheritedObj = {:negative =>nil, :positive =>nil}
|
1054
|
+
# hsInheritedAry = {:negative => [], :positive => []}
|
1055
|
+
# hsInheritedClass = {:negative => [], :positive => []}
|
1056
|
+
# inarall = inarall.map{|i|
|
1057
|
+
# if defined?(i.first_element) && defined?(i.infinities)
|
1058
|
+
# begin
|
1059
|
+
# [:negative, :positive].each do |nega_posi|
|
1060
|
+
# hsInheritedAry[nega_posi].push( i.infinities[nega_posi])
|
1061
|
+
# hsInheritedClass[nega_posi].push(i.infinities[nega_posi].class)
|
1062
|
+
# end
|
1063
|
+
# rescue
|
1064
|
+
# warn "warning: Rangeary#infinities looks wrong in the input (#{i})."
|
1065
|
+
# end
|
1066
|
+
# i.to_a
|
1067
|
+
# else
|
1068
|
+
# i
|
1069
|
+
# end
|
1070
|
+
# }.flatten.map{|j|
|
1071
|
+
# if (defined? j.exclude_begin?)
|
1072
|
+
# j
|
1073
|
+
# else
|
1074
|
+
# begin
|
1075
|
+
# RangeExtd.new(j)
|
1076
|
+
# rescue ArgumentError, RangeError # Just to change the error message.
|
1077
|
+
# raise ArgumentError, "invalid parameter for RangeExtd, hence for Rangeary (#{j.inspect})."
|
1078
|
+
# end
|
1079
|
+
# end
|
1080
|
+
# }
|
1081
|
+
|
1082
|
+
# Check inherited objects if there is any, namely if the argument includes any RangeAry object.
|
1083
|
+
# Priority: Float > Others > RangeExtd::Infinity
|
1084
|
+
if hsInheritedAry[:negative].size > 0
|
1085
|
+
[:negative, :positive].each do |es|
|
1086
|
+
iFloat = hsInheritedClass[es].find_index(Float)
|
1087
|
+
if iFloat.nil?
|
1088
|
+
iElse = hsInheritedClass[es].find_index{|i| (i != RangeExtd::Infinity) && (i != Float)}
|
1089
|
+
if iElse.nil?
|
1090
|
+
iRangeInf = hsInheritedClass[es].find_index(RangeExtd::Infinity)
|
1091
|
+
if iRangeInf.nil?
|
1092
|
+
raise "Rangeary#infinities is not set in the input." # Should not happen, as Rangeary#infinities must be set always.
|
1093
|
+
else
|
1094
|
+
hsInheritedObj[es] = hsInheritedAry[es][iRangeInf]
|
1095
|
+
end
|
1096
|
+
else
|
1097
|
+
hsInheritedObj[es] = hsInheritedAry[es][iElse]
|
1098
|
+
end
|
1099
|
+
else
|
1100
|
+
hsInheritedObj[es] = hsInheritedAry[es][iFloat]
|
1101
|
+
end # if iFloat.nil?
|
1102
|
+
end # [:negative, :positive].each do |es|
|
1103
|
+
end # if hsInheritedAry.size > 0
|
1104
|
+
|
1105
|
+
# Determines what the infinities are: either Float::INFINITY or RangeExtd::Infinity::(POSI|NEGA)TIVE
|
1106
|
+
hsFlag = { :found => {:negative => false, :positive => false} }
|
1107
|
+
hsCand = {
|
1108
|
+
:negative => arRange[0].begin,
|
1109
|
+
:positive => _comparable_end(arRange[-1]),
|
1110
|
+
# :pos_orig => arRange[-1].end, # may be nil in Ruby-2.6
|
1111
|
+
}
|
1112
|
+
infDef = { :negative => RangeExtd::Infinity::NEGATIVE, :positive => RangeExtd::Infinity::POSITIVE }
|
1113
|
+
@infinities={ :negative => nil, :positive => nil }
|
1114
|
+
[:negative, :positive].each do |es|
|
1115
|
+
if (infDef[es] == hsCand[es]) # Can be Float or whatever.
|
1116
|
+
@infinities[es] = hsCand[es] # highest priority
|
1117
|
+
hsFlag[:found][:negative] = true
|
1118
|
+
else
|
1119
|
+
strtmp = ""
|
1120
|
+
[opts[es], hsInheritedObj[es]].each do |opts_or_inherited|
|
1121
|
+
@infinities[es] ||= opts_or_inherited # uses ots[:****tive] or hsInheritedObj[:****tive] if not set.
|
1122
|
+
# Now, checking the compatibility of the infinity value specified (or inherited) with the given range.
|
1123
|
+
if (! opts_or_inherited.nil?) && (opts_or_inherited == @infinities[es]) && (! arRange[0].is_none?)
|
1124
|
+
begin
|
1125
|
+
_ = 0 * (opts_or_inherited <=> hsCand[es])
|
1126
|
+
rescue TypeError
|
1127
|
+
raise ArgumentError, "invalid #{strtmp}parameter for :#{es} => (#{opts_or_inherited.inspect}), incompatible with the range with begin=(#{hsCand[es].inspect})."
|
1128
|
+
end
|
1129
|
+
end
|
1130
|
+
strtmp = "inherited "
|
1131
|
+
end # [opts[es], hsInheritedObj[es]].each do |opts_or_inherited|
|
1132
|
+
end # if (infDef[es] == hsCand[es]) # else
|
1133
|
+
end # [:negative, :positive].each do |es|
|
1134
|
+
|
1135
|
+
if ! (@infinities[:negative] && @infinities[:positive])
|
1136
|
+
# Either or both @infinities[:negative, :positive] is not set, yet.
|
1137
|
+
# Need to set it now. The possibilities are,
|
1138
|
+
# (1) arRange[0].null? && no opts/inheritance given.
|
1139
|
+
# (2) one of them is given by either arRange or opts or inheritance, but not the other.
|
1140
|
+
# (3) neither of them is given by arRange nor opts nor inheritance.
|
1141
|
+
if arRange[0].null?
|
1142
|
+
[:negative, :positive].each do |es|
|
1143
|
+
@infinities[es] ||= infDef[es]
|
1144
|
+
end
|
1145
|
+
else
|
1146
|
+
# There must be a non-infinity object - we will find it out.
|
1147
|
+
if hsFlag[:found][:negative]
|
1148
|
+
obj2refer = _comparable_end(arRange[0]) # For Ruby-2.6 Endless Range
|
1149
|
+
# obj2refer = arRange[0].end
|
1150
|
+
else
|
1151
|
+
obj2refer = arRange[-1].begin
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
# Now, if Numeric === obj2refer, Float::INFINITY is the default.
|
1155
|
+
begin
|
1156
|
+
_dummy = (1.0 < obj2refer)
|
1157
|
+
rescue ArgumentError
|
1158
|
+
# Not Numeric, hence the current infDef is used as it is.
|
1159
|
+
else
|
1160
|
+
# Numeric
|
1161
|
+
infDef = { :negative => -Float::INFINITY, :positive => Float::INFINITY }
|
1162
|
+
end
|
1163
|
+
[:negative, :positive].each do |es|
|
1164
|
+
@infinities[es] ||= infDef[es] # uses default infinity if not set.
|
1165
|
+
end
|
1166
|
+
end # if arRange[0].null?
|
1167
|
+
end # if ! (@infinities[:negative] && @infinities[:positive])
|
1168
|
+
end
|
1169
|
+
private :set_infinities_old
|
745
1170
|
|
746
1171
|
# Called from {Rangeary#initialize}.
|
1172
|
+
#
|
747
1173
|
# Process the array of RangeExtd and return the new one, in which
|
748
1174
|
# overlapped ranges are merged accordingly.
|
749
1175
|
#
|
@@ -751,6 +1177,9 @@ class Rangeary < Array
|
|
751
1177
|
# As a priority, an empty range with a definite class is left,
|
752
1178
|
# but if there is none, RangeExtd::NONE will be left.
|
753
1179
|
#
|
1180
|
+
# Note that (Inf..Inf) or (-Inf..-Inf) is replaced with +RangeExtd::NONE+,
|
1181
|
+
# which then will be truncated.
|
1182
|
+
#
|
754
1183
|
# @param inAr [Array<RangeExtd,Range>]
|
755
1184
|
# @return [Array]
|
756
1185
|
def _merge_overlaps(inAr)
|
@@ -760,7 +1189,7 @@ class Rangeary < Array
|
|
760
1189
|
#[st means status.]
|
761
1190
|
#(0) (prev[0]) and (prev[0].status) unchanged.
|
762
1191
|
#(1) if (now[-1]< prev[-1]), do nothing. [Totally inclusive]
|
763
|
-
# I---* => I---*
|
1192
|
+
# I---* => I---*
|
764
1193
|
# *--*
|
765
1194
|
#(2) if (now[-1]== prev[-1])
|
766
1195
|
# (2-1) AND if (now[-1].st? || prev[-1].st?), prev[-1].st=T [Nearly inclusive]
|
@@ -787,8 +1216,8 @@ class Rangeary < Array
|
|
787
1216
|
# *--*
|
788
1217
|
#
|
789
1218
|
|
790
|
-
|
791
|
-
inRanges = self.class.sort_ranges(
|
1219
|
+
inRanges = _replace_inf_inf(inAr) # Replace meaningless inf..inf etc.
|
1220
|
+
inRanges = self.class.sort_ranges(inRanges).map{|i| (RangeExtd === i) ? i : RangeExtd(i) } # => Rangeary.sort_ranges(ar)
|
792
1221
|
|
793
1222
|
if inRanges.size < 1
|
794
1223
|
return inRanges
|
@@ -798,8 +1227,14 @@ class Rangeary < Array
|
|
798
1227
|
|
799
1228
|
inRanges[1..-1].each do |eachr|
|
800
1229
|
prev = newRanges[-1]
|
801
|
-
|
802
|
-
|
1230
|
+
|
1231
|
+
# To deal with Ruby-2.6 Endless Range like (5..) (=(5..nil))
|
1232
|
+
# *.end is guaranteed not to be false.
|
1233
|
+
eachr_end = _comparable_end(eachr)
|
1234
|
+
prev_end = _comparable_end(prev)
|
1235
|
+
|
1236
|
+
case eachr_end <=> prev_end
|
1237
|
+
when -1 # aka, eachr_end < prev_end
|
803
1238
|
# Do nothing [Totally inclusive]
|
804
1239
|
when 0
|
805
1240
|
if (!eachr.exclude_end?) && prev.exclude_end?
|
@@ -808,8 +1243,8 @@ class Rangeary < Array
|
|
808
1243
|
else
|
809
1244
|
# Do nothing [Totally inclusive]
|
810
1245
|
end
|
811
|
-
when 1 # aka,
|
812
|
-
case eachr.begin <=>
|
1246
|
+
when 1 # aka, eachr_end > prev_end
|
1247
|
+
case eachr.begin <=> prev_end
|
813
1248
|
when -1 # Connect by combining
|
814
1249
|
newRanges[-1] = RangeExtd.new(prev.begin, eachr.end, :exclude_begin => prev.exclude_begin?, :exclude_end => eachr.exclude_end?)
|
815
1250
|
when 0
|
@@ -824,12 +1259,12 @@ class Rangeary < Array
|
|
824
1259
|
newRanges.push(eachr) # must be RangeExtd::NONE (or user-defined equivalent)
|
825
1260
|
else
|
826
1261
|
raise
|
827
|
-
end # case eachr.begin <=>
|
828
|
-
when nil # aka,
|
1262
|
+
end # case eachr.begin <=> prev_end
|
1263
|
+
when nil # aka, eachr_end > prev_end
|
829
1264
|
newRanges.push(eachr) # must be RangeExtd::NONE (or user-defined equivalent)
|
830
1265
|
else
|
831
1266
|
raise
|
832
|
-
end # case
|
1267
|
+
end # case eachr_end <=> prev_end
|
833
1268
|
|
834
1269
|
end # inRanges[1..-1].each do |eachr|
|
835
1270
|
|
@@ -885,11 +1320,43 @@ class Rangeary < Array
|
|
885
1320
|
|
886
1321
|
private :_merge_overlaps
|
887
1322
|
|
1323
|
+
# Replaces the invalid inf..inf Range with NONE
|
1324
|
+
#
|
1325
|
+
# @param arin [Array<Range, RangeExtd>]
|
1326
|
+
# @return [Array]
|
1327
|
+
def _replace_inf_inf(arin)
|
1328
|
+
arin.map{ |er|
|
1329
|
+
raise 'contact the code developer' if !defined? er.exclude_end? # Sanity check.
|
1330
|
+
arran = [er.begin, er.end] # to_a raises RangeError for Ruby 2.6 Endless Range
|
1331
|
+
if (( arran.all?{ |ea| RangeExtd::Infinity.infinite?(ea) } &&
|
1332
|
+
(arran.all?(&:positive?) || arran.all?(&:negative?)) ) ||
|
1333
|
+
(arran.all?(&:nil?)))
|
1334
|
+
RangeExtd::NONE
|
1335
|
+
else
|
1336
|
+
er
|
1337
|
+
end
|
1338
|
+
}
|
1339
|
+
end
|
1340
|
+
private :_replace_inf_inf
|
888
1341
|
|
889
1342
|
####################
|
890
1343
|
# private_class_method
|
891
1344
|
####################
|
892
1345
|
|
1346
|
+
# Sort infinities obtained from inherited objects and returns the best one
|
1347
|
+
#
|
1348
|
+
# RangeExtd::Infinity is ignored. Float::INFINITY has the lowest priority.
|
1349
|
+
#
|
1350
|
+
# @param *ar_infs [Array] of Infinities Hash (inherited)
|
1351
|
+
# @return [Hash] each key (:(posi|nega)tive) contains a single value (potentially null) for infinity.
|
1352
|
+
def self._best_inherited_infinities(*ar_infs)
|
1353
|
+
hsar = _sort_inherited_infinities_all( _get_cand_infinities(ar_infs.flatten) )
|
1354
|
+
hsar.map{ |k, ev|
|
1355
|
+
[k, ev[0]]
|
1356
|
+
}.to_h # Ruby 2.1 or later
|
1357
|
+
end
|
1358
|
+
private_class_method :_best_inherited_infinities
|
1359
|
+
|
893
1360
|
#== Logical conjunction of two RangeExtd
|
894
1361
|
#
|
895
1362
|
# To assure this logical conjunction meaningful,
|
@@ -948,7 +1415,6 @@ class Rangeary < Array
|
|
948
1415
|
end
|
949
1416
|
|
950
1417
|
r = *( sort_ranges([RangeExtd(r1), RangeExtd(r2)]) ) # => Rangeary.sort_ranges
|
951
|
-
# r = *( sort_arrange([RangeExtd(r1), RangeExtd(r2)]) )
|
952
1418
|
|
953
1419
|
## Note: the end product will be (cBeg(:stBeg), cEnd(:stEnd))
|
954
1420
|
# where :stBeg and :stEnd mean exclude_(begin|end)?
|
@@ -961,14 +1427,20 @@ class Rangeary < Array
|
|
961
1427
|
stBeg = r[1].exclude_begin?
|
962
1428
|
end
|
963
1429
|
|
964
|
-
# Set the candidate end value.
|
965
|
-
|
966
|
-
|
1430
|
+
# Set the candidate end value. (comparable_end() for Ruby-2.6 Endless Range)
|
1431
|
+
# Note: this comparison ignores @infinities even if set,
|
1432
|
+
# because @infinities may not be defined in the arguments!
|
1433
|
+
# Anyway, nothing should be larger than the upper limit
|
1434
|
+
# and so this should be fine.
|
1435
|
+
if comparable_end(r[0]) == comparable_end(r[1])
|
1436
|
+
cEndOrig = r[1].end
|
1437
|
+
cEnd = comparable_end(r[1])
|
967
1438
|
stEnd = (r[0].exclude_end? || r[1].exclude_end?)
|
968
1439
|
else
|
969
|
-
a = [[r[0]
|
1440
|
+
a = [[comparable_end(r[0]), 0, r[0].end], [comparable_end(r[1]), 1, r[1].end]].min
|
970
1441
|
cEnd = a[0]
|
971
1442
|
cEndIndex = a[1] # r[cEndIndex] == RangeExtd obj that gives the end of the resultant range.
|
1443
|
+
cEndOrig = a[2]
|
972
1444
|
stEnd = nil
|
973
1445
|
end
|
974
1446
|
|
@@ -992,219 +1464,180 @@ class Rangeary < Array
|
|
992
1464
|
# # Already defined.
|
993
1465
|
end # if stEnd.nil?
|
994
1466
|
|
995
|
-
RangeExtd(cBeg,
|
1467
|
+
RangeExtd(cBeg, cEndOrig, :exclude_begin => stBeg, :exclude_end => stEnd)
|
996
1468
|
else
|
997
1469
|
raise
|
998
1470
|
end # case cBeg <=> cEnd
|
999
1471
|
|
1000
1472
|
end # def self.conjunctionRangeExtd(r1, r2)
|
1001
|
-
|
1002
1473
|
private_class_method :conjunctionRangeExtd
|
1003
1474
|
|
1004
|
-
|
1005
|
-
# Logical conjunction of two Rangeary
|
1006
|
-
#
|
1007
|
-
#===Algorithm
|
1008
|
-
#
|
1009
|
-
# r1 == [p1, p2, p3, ...] # Array of RangeExtd
|
1010
|
-
# r2 == [q1, q2, q3, ...]
|
1011
|
-
# rc = [] # Initial value of Conjunction r1*r2
|
1012
|
-
# 1. q1 = r2.shift
|
1013
|
-
# 2. r1.delete_if(pi.end<q1.begin) -> (r1==[P1,P2(>q1),P3,...])
|
1014
|
-
# 3. make conjunction between RangeExtd P1*q1 => pq1
|
1015
|
-
# 4. rc+=Rangeary.new(pq1)
|
1016
|
-
# 5a. if q1.end<P1.end, will do P1<->q2 next, hence return to 1 (will do r2.shift).
|
1017
|
-
# *--* => *--* + nil
|
1018
|
-
# *--* *--* .... *--*
|
1019
|
-
# *---* => .O--* + -*
|
1020
|
-
# *---* *--* ..... *--* ...-* ----
|
1021
|
-
# 5b. if q1.end==P1.end, r1.shift, return to 1 (will do r2.shift).
|
1022
|
-
# *--* *-- => .... *-- + ---* ---
|
1023
|
-
# *---* *--* ..... *--* .---* ----
|
1024
|
-
# 5c. if q1.end>P1.end, will do P2<->q1, hence r1.shift, return to 2.
|
1025
|
-
# *---* *-- => ..... *--
|
1026
|
-
# *---- .O---
|
1475
|
+
# Returns the candidate @infinities from the input Rangeary
|
1027
1476
|
#
|
1028
|
-
#
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
0
|
1046
|
-
end
|
1047
|
-
}[0]
|
1048
|
-
end
|
1049
|
-
|
1050
|
-
# Initialisation
|
1051
|
-
a1 = r1.to_a
|
1052
|
-
a2 = r2.to_a
|
1053
|
-
rc = Rangeary.new( RangeExtd::NONE, hsInherited )
|
1054
|
-
|
1055
|
-
if a1.empty? || a2.empty?
|
1056
|
-
return rc
|
1477
|
+
# If there is any Rangeary in the input.
|
1478
|
+
#
|
1479
|
+
# Example return:
|
1480
|
+
# { :positive => [nil, Float::INFINITY],
|
1481
|
+
# :negative => [nil, -Float::INFINITY] }
|
1482
|
+
#
|
1483
|
+
# Note the standard @infinities is a Hash, but NOT a Hash of Array.
|
1484
|
+
# This method returns the candidates.
|
1485
|
+
#
|
1486
|
+
# @param arin [Array<Hash<Infinity, nil>>] Inherited infinities from the input Rangeary-s
|
1487
|
+
# @return [Hash<Array>] keys (:positive and :negative) Array#size may not agree between them.
|
1488
|
+
def self._get_cand_infinities(arin)
|
1489
|
+
hsret = { positive: [], negative: [] }
|
1490
|
+
arin.each do |ec|
|
1491
|
+
hsret.each_key do |k|
|
1492
|
+
hsret[k] << ec[k]
|
1493
|
+
end
|
1057
1494
|
end
|
1495
|
+
hsret
|
1496
|
+
end
|
1497
|
+
private_class_method :_get_cand_infinities
|
1058
1498
|
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
q1 = a2.shift
|
1065
|
-
else
|
1066
|
-
break
|
1067
|
-
end
|
1068
|
-
end
|
1069
|
-
index_valid = a1.find_index{|i| i.begin >= q1.begin }
|
1070
|
-
if (! index_valid.nil?) && index_valid > 1
|
1071
|
-
a1.shift(index_valid)
|
1072
|
-
end
|
1499
|
+
# True if object is a type of Rangeary
|
1500
|
+
def self.is_rangeary_type?(obj)
|
1501
|
+
obj.respond_to?(:infinities) && obj.class.method_defined?(:first_element)
|
1502
|
+
end
|
1503
|
+
private_class_method :is_rangeary_type?
|
1073
1504
|
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1505
|
+
# True if object is a type of Numeric and comparable
|
1506
|
+
def self.is_num_type?(obj)
|
1507
|
+
Numeric === obj && obj.respond_to?(:between?) && obj.class.method_defined?(:<)
|
1508
|
+
end
|
1509
|
+
private_class_method :is_num_type?
|
1078
1510
|
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1511
|
+
# Sort infinities obtained from inherited objects
|
1512
|
+
#
|
1513
|
+
# RangeExtd::Infinity is ignored. Float::INFINITY has the lowest priority.
|
1514
|
+
#
|
1515
|
+
# @param hs_inherit [Hash<Array>] :positive => Array, etc (From Rangeary-s in the main Array given)
|
1516
|
+
# @return [Hash<Array>] each key (:(posi|nega)tive) contains the sorted candidate Array.
|
1517
|
+
def self._sort_inherited_infinities_all(hs_inherit)
|
1518
|
+
hs_inherit.map do |ek, ev|
|
1519
|
+
[ek, _sort_inherited_infinities_each(ev, key=ek)]
|
1520
|
+
end.to_h # Ruby 2.1 or later
|
1521
|
+
end
|
1522
|
+
private_class_method :_sort_inherited_infinities_all
|
1082
1523
|
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
end
|
1099
|
-
hsFlag[:a2shift] = false
|
1524
|
+
# Sort infinities obtained from inherited objects
|
1525
|
+
#
|
1526
|
+
# RangeExtd::Infinity is ignored. Float::INFINITY has the lowest priority.
|
1527
|
+
#
|
1528
|
+
# @param ar_infs [Array] of Infinities (inherited)
|
1529
|
+
# @param key [Symbol] :positive or :negative
|
1530
|
+
# @return [Array]
|
1531
|
+
def self._sort_inherited_infinities_each(ar_infs, key=:positive)
|
1532
|
+
ar_infs.map {|j|
|
1533
|
+
(RangeExtd::Infinity === j) ? nil : j
|
1534
|
+
}.compact.sort{|a,b|
|
1535
|
+
if is_num_type?(a) && RangeExtd::Infinity.infinite?(a)
|
1536
|
+
-1
|
1537
|
+
elsif is_num_type?(b) && RangeExtd::Infinity.infinite?(b)
|
1538
|
+
1
|
1100
1539
|
else
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1540
|
+
begin
|
1541
|
+
(key == :positive) ? (a<=>b) : (b<=>a)
|
1542
|
+
rescue
|
1543
|
+
0
|
1544
|
+
end
|
1545
|
+
end
|
1546
|
+
}
|
1106
1547
|
end
|
1107
|
-
private_class_method :
|
1108
|
-
|
1548
|
+
private_class_method :_sort_inherited_infinities_each
|
1109
1549
|
|
1110
|
-
#
|
1111
|
-
|
1550
|
+
# Validate the infinities by Options and inherited and select the best
|
1551
|
+
#
|
1552
|
+
# If Option is specified, that has the priority.
|
1553
|
+
# Among the inherited, the youngest non-nil one has the highest priority.
|
1554
|
+
#
|
1555
|
+
# If there are any inconsistencies, issue a warning message, if $VERBOSE==true.
|
1556
|
+
#
|
1557
|
+
# Note this method does not look at the contents of the Range Array given.
|
1558
|
+
#
|
1559
|
+
# @param ar_inherit [Array<Hash<Infinity, nil>>] Inherited infinities from the input Rangeary-s
|
1560
|
+
# @param hs_opts [Hash, nil] :positive, :negative, specified by the option to {Rangeary.initialize}
|
1561
|
+
# @return [Hash] keys (:positive and :negative) with a single value for each
|
1562
|
+
def self._validate_select_infinities(ar_inherit, hs_opts=nil)
|
1563
|
+
hs_inherit = _get_cand_infinities(ar_inherit)
|
1564
|
+
if !hs_opts
|
1565
|
+
hs_opts = hs_inherit.map{ |ek, ev|
|
1566
|
+
[hs_inherit[ek], nil]
|
1567
|
+
}.to_h # Ruby 2.1 or later
|
1568
|
+
end
|
1569
|
+
# e.g., hs_inherit[:positive] == [ "z"(From-Option), nil(Inherited), "y"(Inherited), INFINITY(inherited) ]
|
1570
|
+
|
1571
|
+
# Selection
|
1572
|
+
hsret = _sort_inherited_infinities_all( hs_inherit ).map{ |ek, ev|
|
1573
|
+
[ek, ([hs_opts[ek]]+ev).compact[0]]
|
1574
|
+
}.to_h # Ruby 2.1 or later
|
1575
|
+
|
1576
|
+
# Validation (for warning, issued when $VERBOSE==true)
|
1577
|
+
hs_inherit.each_pair do |ek, ev|
|
1578
|
+
ev_uniq = ([hs_opts[ek]]+ev).compact.uniq
|
1579
|
+
msg = "Inconsistent %s infinities are found: %s (=> %s is used)"%[ek, ev_uniq.inspect, hsret[ek]]
|
1580
|
+
#warn msg if $VERBOSE && (ev_uniq.size > 2) && (!ev_uniq.all?{ |c| RangeExtd::Infinity.infinite?(c) })
|
1581
|
+
warn msg if (ev_uniq.size > 1) && (!ev_uniq.all?{ |c| RangeExtd::Infinity.infinite?(c) })
|
1582
|
+
end
|
1112
1583
|
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
# (1-1) if (now[-1] < prev[0]), do nothing. [Totally exclusive]
|
1117
|
-
# *--* => *--*
|
1118
|
-
# *--*
|
1119
|
-
# (1-2) if (now[-1] == prev[0])
|
1120
|
-
# (1-2-1) AND if (now[-1].in?)&&(prev[-1].in?), Change prev[0].ex?=T [Nearly exclusive]
|
1121
|
-
# I--* => O--*
|
1122
|
-
# *--I
|
1123
|
-
# (1-2-1) ELSE, do nothing. [Totally inclusive]
|
1124
|
-
# O--* => *--*
|
1125
|
-
# *--I
|
1126
|
-
# *--* => *--*
|
1127
|
-
# *--o
|
1128
|
-
# (1-3) if (now[-1] > prev[0])
|
1129
|
-
# (1-3-1) if (now[-1] < prev[-1]), => (now[-1],Prev[-1]).
|
1130
|
-
# *---* => ..*-*
|
1131
|
-
# *--*
|
1132
|
-
# (1-3-2) if (now[-1] == prev[-1]), => (now[-1],Prev[-1]).
|
1133
|
-
# (1-3-2-1) if (now[-1].ex?)&&(prev[-1].in?), (Prev[-1],Prev[-1])(Single_number)
|
1134
|
-
# *---I => ....I
|
1135
|
-
# *----O
|
1136
|
-
# (1-3-2-2) ELSE, none.
|
1137
|
-
# *---O => .....
|
1138
|
-
# *----*
|
1139
|
-
# *---* => .....
|
1140
|
-
# *----I
|
1141
|
-
# (1-3-3) if (now[-1] > prev[-1]), none
|
1142
|
-
# *---* => .....
|
1143
|
-
# *-----*
|
1144
|
-
#(2) if (now[0] == prev[0])
|
1145
|
-
# (2A-1) if (now[0].ex?)&&(prev[0].in?), => (Prev[0],Prev[0])(Single_number) + Any?
|
1146
|
-
# I--- => I???
|
1147
|
-
# O---
|
1148
|
-
# (2A-2) ELSE, none for the first part.
|
1149
|
-
# O--- => .???
|
1150
|
-
# *---
|
1151
|
-
# *--- => .???
|
1152
|
-
# I---
|
1153
|
-
# (2B) Follow (1) to get the New Array.
|
1154
|
-
#(3) if (now[0] > prev[0])
|
1155
|
-
# (3-1) if (now[-1] < prev[-1]), 2 Rangeary (Prev[0],now[0]),(now[-1],prev[-1])
|
1156
|
-
# *-----* => *-*.*-*
|
1157
|
-
# *-*
|
1158
|
-
# (3-2) if (now[-1] == prev[-1])
|
1159
|
-
# (3-2-1) if (now[-1].ex?)&&(prev[-1].in?), => (Prev[0],now[0]),(prev[-1],prev[-1])
|
1160
|
-
# *----I => *-*...I
|
1161
|
-
# *--O
|
1162
|
-
# (3-2-2) ELSE, => (Prev[0],now[0])
|
1163
|
-
# *----I => *-*....
|
1164
|
-
# *--I
|
1165
|
-
# *----O => *-*....
|
1166
|
-
# *--*
|
1167
|
-
# (3-3) if (now[-1] > prev[-1])
|
1168
|
-
# (3-3-1) if (now[0] < prev[-1]), => (Prev[0],now[0]),(prev[-1],prev[-1])
|
1169
|
-
# *---* => *-*....
|
1170
|
-
# *---*
|
1171
|
-
# (3-3-2) if (now[0] == prev[-1])
|
1172
|
-
# (3-3-2-1) if (now[0].in?)&&(prev[0].in?), => (Prev[0],prev[-1].ex)
|
1173
|
-
# *--I => *--O
|
1174
|
-
# I--*
|
1175
|
-
# (3-3-2-2) ELSE, unchanged.
|
1176
|
-
# *--* => *--*
|
1177
|
-
# O--*
|
1178
|
-
# *--O => *--O
|
1179
|
-
# *--*
|
1180
|
-
# (3-3-3) if (now[0] > prev[-1]), unchanged.
|
1181
|
-
# *--* => *--*
|
1182
|
-
# *--*
|
1183
|
-
#
|
1584
|
+
hsret
|
1585
|
+
end
|
1586
|
+
private_class_method :_validate_select_infinities
|
1184
1587
|
|
1185
|
-
|
1186
|
-
# sort_arrange(arRng).map{ |er|
|
1187
|
-
if er.end < r2sub.begin
|
1188
|
-
er
|
1189
|
-
elsif er.begin < r2sub.begin && er.end < r2sub.end
|
1190
|
-
(er.begin .. (r2sub.begin-1))
|
1191
|
-
elsif er.begin < r2sub.begin && r2sub.end < er.end
|
1192
|
-
[er.begin .. (r2sub.begin-1),
|
1193
|
-
(r2sub.end+1) .. er.end ]
|
1194
|
-
elsif r2sub.begin <= er.begin && er.end <= r2sub.end
|
1195
|
-
nil
|
1196
|
-
elsif r2sub.begin <= er.begin && er.begin <= r2sub.end && r2sub.end < er.end
|
1197
|
-
(r2sub.end+1) .. er.end
|
1198
|
-
elsif r2sub.end < er.begin
|
1199
|
-
er
|
1200
|
-
else
|
1201
|
-
raise "This should not happen."
|
1202
|
-
end
|
1203
|
-
}.flatten.compact
|
1204
|
-
end # def self.subtractRange(arRng, r2sub)
|
1205
|
-
private_class_method :subtractRange
|
1588
|
+
end # class Rangeary < Array
|
1206
1589
|
|
1590
|
+
# Overwrites its equal operator
|
1591
|
+
class Array
|
1592
|
+
alias_method :equals_before_rangeary, :== if ! self.method_defined?(:equals_before_rangeary)
|
1207
1593
|
|
1208
|
-
|
1594
|
+
# Updated Array#==
|
1595
|
+
#
|
1596
|
+
# This returns true even if the standard #{==} is false, if both are *practically* empty,
|
1597
|
+
# that is, if +#empty_element?+ and/or +empty?+ are true for both, they are equal.
|
1598
|
+
# Also, this equates the "end" of Endless Range (Ruby 2.6) with Float::INFINITY or
|
1599
|
+
# RangeExtd::Infinity::POSITIVE.
|
1600
|
+
# Note by definition, it would appear at the last element in Rangeary only,
|
1601
|
+
# if it does.
|
1602
|
+
#
|
1603
|
+
# @param other [Object]
|
1604
|
+
def ==(other)
|
1605
|
+
return true if equals_before_rangeary other
|
1606
|
+
return false if !other.class.method_defined?(:to_ary)
|
1607
|
+
return false if !self.class.method_defined?(:empty_element?) && !other.class.method_defined?(:empty_element?)
|
1608
|
+
|
1609
|
+
# It was false. Is it?
|
1610
|
+
# eg., (Rangeary[RangeExtd::NONE] == []) is true,
|
1611
|
+
# because Rangeary[] with zero components does not exist!
|
1612
|
+
# Now either other or self is guranteed to be Rangeary.
|
1613
|
+
self_empt = (respond_to?(:empty_element?) ? empty_element? : empty?)
|
1614
|
+
other_empt = (other.respond_to?(:empty_element?) ? other.empty_element? : other.empty?)
|
1615
|
+
return true if self_empt && other_empt
|
1616
|
+
return false if self_empt ^ other_empt
|
1617
|
+
# return false if size != other.size # evaluated at the beginning.
|
1618
|
+
return false if size >= 2 && self[0..-2] != other[0..-2]
|
1619
|
+
return false if !self[-1].respond_to?(:exclude_end?) || !other[-1].respond_to?(:exclude_end?)
|
1620
|
+
|
1621
|
+
# Now, both are guaranteed to have the same number of non-zero elements,
|
1622
|
+
# all their elements except for the last one are equal,
|
1623
|
+
# and their last elements are Range-type instances.
|
1624
|
+
# Yet, the standard "equal" operator has failed.
|
1625
|
+
# Only the potential they may be equal is their last elements differ
|
1626
|
+
# between Endless Range (Ruby 2.6) and Infinity.
|
1627
|
+
c_self = Rangeary.comparable_end self[-1]
|
1628
|
+
c_other = Rangeary.comparable_end other[-1]
|
1629
|
+
return false if c_self != c_other
|
1630
|
+
|
1631
|
+
if !c_self.class.method_defined?(:infinite?) && !c_self.class.method_defined?(:infinity?)
|
1632
|
+
# :infinite? for Float::INFINITY, :infinity? is defined in RangeExtd::Infinity
|
1633
|
+
warn "sanity check failed. c_self should be infinite (#{c_self.inspect}). The result is not guranteed. Contact the code developer."
|
1634
|
+
end
|
1209
1635
|
|
1636
|
+
# The end of their last elements are both positive Infinity.
|
1637
|
+
# How about "begin"?
|
1638
|
+
self_flag = (self[-1].class.method_defined?(:exclude_begin?) ? self[-1].exclude_begin? : false)
|
1639
|
+
other_flag = (other[-1].class.method_defined?(:exclude_begin?) ? other[-1].exclude_begin? : false)
|
1640
|
+
(self[-1].begin == other[-1].begin) && (self_flag == other_flag)
|
1641
|
+
end
|
1642
|
+
end # class Array
|
1210
1643
|
|