range_extd 0.1.0 → 0.1.1
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 +4 -4
- data/ChangeLog +7 -1
- data/README.ja.rdoc +318 -0
- data/lib/range_extd/infinity/infinity.rb +17 -16
- data/lib/range_extd/range_extd.rb +36 -32
- data/range_extd.gemspec +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c920255a38ca8b0805d5cfe50d4fbabd4718417f
|
4
|
+
data.tar.gz: 47fa8995de09e68a381144751fffe86e42082804
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf51ff3e606ec3b1955fe0978a407ec60130eacf0591fb3c5f85f927f890043e4adc6bd88a094ab14e19d954f40bef24e94048e0078ac8cfcbe0fcb775fccb3a
|
7
|
+
data.tar.gz: c8ac4fb7471a7246b5d238b3acbc7a97355e59d4addf10e8075c3376edfcdcdb8291b631921c76cac5b099ac21ca538dc07f30dddb87e7162844de71f5eb7099
|
data/ChangeLog
CHANGED
data/README.ja.rdoc
CHANGED
@@ -1,4 +1,322 @@
|
|
1
1
|
|
2
|
+
= RangeExtd - Extended Range class with exclude_begin and open-ends
|
3
|
+
|
4
|
+
This package contains RangeExtd class, the Extended Range class that features:
|
5
|
+
|
6
|
+
1. includes exclude_begin? (to exclude the "begin" boundary),
|
7
|
+
2. allows open-ended range (to the infinity),
|
8
|
+
3. defines NONE and EVERYTHING constants,
|
9
|
+
4. the first self-consistent logical structure,
|
10
|
+
5. complete backward-compatibility within the built-in Range.
|
11
|
+
|
12
|
+
With the introduction of the excluded status of begin, in addition
|
13
|
+
to the end as in built-in Range, and open-ended feature,
|
14
|
+
the logical completeness of the 1-dimensional range is realised.
|
15
|
+
|
16
|
+
Then the validity of range is strictly defined now.
|
17
|
+
Following that, this package adds a few methods, most notably
|
18
|
+
{Range#valid?} and {Range#empty?}
|
19
|
+
to Range, and accordingly its any sub-classes,
|
20
|
+
|
21
|
+
For example, <tt>(3...3).valid?</tt> returns false, because the element 3 is
|
22
|
+
inclusive for the begin boundary, yet exclusive for the end boundary,
|
23
|
+
which are contradictory to each other. With this RangeExtd class,
|
24
|
+
it is expressed as a valid range,
|
25
|
+
* RangeExtd.new(3, 3, true, true) # => an empty range
|
26
|
+
* RangeExtd.new(3, 3, false, false) # => a single-point range (3..3)
|
27
|
+
|
28
|
+
However, as long as it is within built-in Range, nothing has changed,
|
29
|
+
so it is completely compatible with the standard Ruby.
|
30
|
+
|
31
|
+
To express open-ended ranges is simple; you just use either of
|
32
|
+
the two (negative and positive, or former and later) constants
|
33
|
+
defined in the class {RangeExtd::Infinity}
|
34
|
+
* RangeExtd::Infinity::NEGATIVE
|
35
|
+
* RangeExtd::Infinity::POSITIVE
|
36
|
+
|
37
|
+
They are basically the object that generalised <tt>Float::INFINITY</tt> to
|
38
|
+
any Comparable object. For example,
|
39
|
+
("a"..RangeExtd::Infinity::POSITIVE).each
|
40
|
+
gives an infinite iterator with <tt>String#succ</tt>, starting from "a"
|
41
|
+
(therefore, make sure to code so it breaks the iterator at one stage!).
|
42
|
+
|
43
|
+
|
44
|
+
The built-in Range class is very useful, and has given Ruby users
|
45
|
+
a power to make easy coding. Yet, the lack of definition of
|
46
|
+
exclusive begin boundary is a nuisance in some cases.
|
47
|
+
|
48
|
+
Having said that, there is a definite and understandable reason;
|
49
|
+
Range in Ruby is not limited at all to Numeric (or strictly speaking,
|
50
|
+
Real number or its representative). Range with any object that has a method
|
51
|
+
of <tt>succ()</tt> is found to be useful, whereas there is no reverse method for
|
52
|
+
<tt>succ()</tt> in general.
|
53
|
+
In that sense Range is inherently not symmetric. In addition
|
54
|
+
some regular Range objects are continuous (like Float), while others are discrete
|
55
|
+
(like Integer or String). That may add some confusion to the strict definition.
|
56
|
+
|
57
|
+
To add the feature of the exclusive begin boundary is in that sense
|
58
|
+
not 100 per cent trivial. The definition I adopt for the behaviour of
|
59
|
+
RangeExtd is probably not the only solution. Personally, I am content
|
60
|
+
with it, and I think it achieves the good logical completeness within the frame.
|
61
|
+
|
62
|
+
I hope you find it to be useful.
|
63
|
+
|
64
|
+
|
65
|
+
== Install
|
66
|
+
|
67
|
+
gem install range_extd
|
68
|
+
|
69
|
+
Two files
|
70
|
+
range_extd/range_extd.rb
|
71
|
+
range_extd/infinity/infinity.rb
|
72
|
+
should be installed in one of your <tt>$LOAD_PATH</tt>
|
73
|
+
|
74
|
+
Alternatively get it from
|
75
|
+
http://rubygems.org/gems/range_extd
|
76
|
+
|
77
|
+
Then all you need to do is
|
78
|
+
require 'range_extd/range_extd'
|
79
|
+
or, possibly as follows, if you manually install it
|
80
|
+
require 'range_extd'
|
81
|
+
in your Ruby script (or irb). The other file
|
82
|
+
range_extd/infinity/infinity.rb
|
83
|
+
is called (required) from it automatically.
|
84
|
+
|
85
|
+
Have fun!
|
86
|
+
|
87
|
+
|
88
|
+
== Simple Examples
|
89
|
+
|
90
|
+
=== How to create a RangeExtd instance
|
91
|
+
|
92
|
+
Here are some simple examples.
|
93
|
+
|
94
|
+
r = RangeExtd(?a...?d, true) # => a<...d
|
95
|
+
r.exclude_begin? # => true
|
96
|
+
r.to_a # => ["b", "c"]
|
97
|
+
RangeExtd(1...2) == (1...2) # => true
|
98
|
+
RangeExtd(1, 2, false, true)== (1...2) # => true
|
99
|
+
RangeExtd(1, 1, false, false)==(1..1) # => true
|
100
|
+
RangeExtd(1, 1, true, true) == RangeExtd::NONE # => true
|
101
|
+
RangeExtd(1, 1, false, true) # => ArgumentError
|
102
|
+
(RangeExtd::Infinity::NEGATIVE..RangeExtd::Infinity::POSITIVE) \
|
103
|
+
== RangeExtd::EVERYTHING # => true
|
104
|
+
|
105
|
+
Basically, there are two forms:
|
106
|
+
|
107
|
+
RangeExtd(range, [exclude_begin=false, [exclude_end=false]])
|
108
|
+
RangeExtd(obj_begin, obj_end, [exclude_begin=false, [exclude_end=false]])
|
109
|
+
|
110
|
+
The last two parameters specify the respective boundary to be excluded if true,
|
111
|
+
or included if false (Default). If they contradict to the first
|
112
|
+
parameter of the range (Range or RangeExtd), those latter two parameters are used.
|
113
|
+
<tt>RangeExtd.new()</tt> is the same thing.
|
114
|
+
|
115
|
+
=== Slightly more advanced uses
|
116
|
+
|
117
|
+
(1..RangeExtd::Infinity::POSITIVE).each do |i|
|
118
|
+
print i
|
119
|
+
break if i >= 9
|
120
|
+
end # => self ( "123456789" => STDOUT )
|
121
|
+
(nil..nil).valid? # => false
|
122
|
+
(1...1).valid? # => false
|
123
|
+
(1...1).null? # => true
|
124
|
+
RangeExtd.valid?(1...1) # => false
|
125
|
+
RangeExtd(1, 1, true, true).valid? # => true
|
126
|
+
RangeExtd(1, 1, true, true).empty? # => true
|
127
|
+
RangeExtd(?a, ?b, true, true).to_a? # => []
|
128
|
+
RangeExtd(?a, ?b, true, true).empty? # => true
|
129
|
+
RangeExtd(?a, ?e, true, true).to_a? # => ["b", "c", "d"]
|
130
|
+
RangeExtd(?a, ?e, true, true).empty? # => false
|
131
|
+
RangeExtd::NONE.is_none? # => true
|
132
|
+
RangeExtd::EVERYTHING.is_everything? # => true
|
133
|
+
|
134
|
+
All the methods that are in the built-in Range can be used.
|
135
|
+
|
136
|
+
|
137
|
+
== Description
|
138
|
+
|
139
|
+
Once the file range_extd.rb is required, the two classes are defined:
|
140
|
+
|
141
|
+
* RangeExtd
|
142
|
+
* RangeExtd::Infinity
|
143
|
+
|
144
|
+
Also, several methods are added or altered in Range class.
|
145
|
+
All the changes made in Range are backward-compatible with the original.
|
146
|
+
|
147
|
+
=== RangeExtd::Infinity Class
|
148
|
+
|
149
|
+
Class {RangeExtd::Infinity} has basically only two constant instances.
|
150
|
+
|
151
|
+
* RangeExtd::Infinity::NEGATIVE
|
152
|
+
* RangeExtd::Infinity::POSITIVE
|
153
|
+
|
154
|
+
They are the objects that generalise the concept of
|
155
|
+
<tt>Float::INFINITY</tt>
|
156
|
+
to any Comparable objects. The methods <tt><=></tt> and <tt>succ</tt> are defined.
|
157
|
+
|
158
|
+
You can use them the same as other objects, such as,
|
159
|
+
("k"..RangeExtd::Infinity::POSITIVE)
|
160
|
+
However as they do not have any other methods,
|
161
|
+
the use out of Range-type class is probably meaningless.
|
162
|
+
|
163
|
+
Note for any Numeric object, please use <tt>Float::INFINITY</tt> instead in principle.
|
164
|
+
|
165
|
+
Any objects in any user-defined Comparable class are commutatively comparable with
|
166
|
+
those two constants, as long as the cmp method of the class is written
|
167
|
+
politely.
|
168
|
+
|
169
|
+
For more detail, see its documents (YARD or RDoc-style
|
170
|
+
documents embedded in the code, or see RubyGems webpage).
|
171
|
+
|
172
|
+
|
173
|
+
=== RangeExtd Class
|
174
|
+
|
175
|
+
RangeExtd objects are immutable, the same as Range.
|
176
|
+
Hence once an instance is created, it would not change.
|
177
|
+
|
178
|
+
How to create an instance is explained above (in the Examples
|
179
|
+
sections). Any attempt to try to create an instance that is not
|
180
|
+
"valid" as a range (see below) raises an exception (<tt>ArgumentError</tt>), and fails.
|
181
|
+
|
182
|
+
There are two constants defined in this class:
|
183
|
+
|
184
|
+
* RangeExtd::NONE
|
185
|
+
* RangeExtd::EVERYTHING
|
186
|
+
|
187
|
+
The former represents the empty range and the latter does the range
|
188
|
+
covers everything, namely open-ended for the both negative and
|
189
|
+
positive directions.
|
190
|
+
|
191
|
+
In addition to all the standard methods of Range, the following
|
192
|
+
methods are added to both RangeExtd and Range classes.
|
193
|
+
See the document of each method for detail (some are defined only in
|
194
|
+
Range class, as RangeExtd inherits it).
|
195
|
+
|
196
|
+
* <tt>exclude_begin?</tt>
|
197
|
+
* <tt>valid?</tt>
|
198
|
+
* <tt>empty?</tt>
|
199
|
+
* <tt>null?</tt>
|
200
|
+
* <tt>is_none?</tt>
|
201
|
+
* <tt>is_everything?</tt>
|
202
|
+
|
203
|
+
There is a class method, which is equivalent to the instance
|
204
|
+
method <tt>valid?</tt>.
|
205
|
+
* <tt>RangeExtd.valid?</tt>
|
206
|
+
|
207
|
+
What is valid (<tt>#valid?</tt> => true) as a range is defined as follows.
|
208
|
+
|
209
|
+
1. Both <tt>begin</tt> and <tt>end</tt> elements must be Comparable to each other,
|
210
|
+
and the comparison results must be consistent between the two.
|
211
|
+
The sole exception is {RangeExtd::NONE}, which is valid.
|
212
|
+
For example, <tt>(nil..nil)</tt> is NOT valid (nb., it raised Exception in Ruby 1.8).
|
213
|
+
2. begin must be smaller than or equal (<tt>==</tt>) to end,
|
214
|
+
that is, <tt>(begin <=> end)</tt> must be either -1 or 0.
|
215
|
+
3. If begin is equal to end, namely, <tt>(begin <=> end) == 0</tt>,
|
216
|
+
the exclude status of the both ends must agree.
|
217
|
+
That is, if the <tt>begin</tt> is excluded, <tt>end</tt> must be also excluded,
|
218
|
+
and vice versa.
|
219
|
+
For example, <tt>(1...1)</tt> is NOT valid for that reason,
|
220
|
+
because any built-in Range object has the exclude status
|
221
|
+
of false (namely, inclusive) for <tt>begin</tt>.
|
222
|
+
|
223
|
+
For more detail and examples see the documents of
|
224
|
+
{RangeExtd.valid?} and {Range#valid?}
|
225
|
+
|
226
|
+
The definition of what is empty (<tt>#empty?</tt> => true) as a range is as follows;
|
227
|
+
|
228
|
+
1. the range must be valid: <tt>valid?</tt> => true
|
229
|
+
2. if the range id discrete, that is, begin has
|
230
|
+
<tt>succ</tt> method, there must be no member within the range
|
231
|
+
(which means the begin must be excluded, too):
|
232
|
+
<tt>to_a.empty?</tt> => true
|
233
|
+
3. if the range is continuous, that is, begin does not have
|
234
|
+
<tt>succ</tt> method, begin and end must be equal
|
235
|
+
(<tt>(begin <=> end)</tt> => 0) and both the boundaries must
|
236
|
+
be excluded: <tt>(exclude_begin? && exclude_end?)</tt> => true.
|
237
|
+
|
238
|
+
Note that ranges with equal <tt>begin</tt> and <tt>end</tt> with inconsistent two
|
239
|
+
exclude status are not valid, as mentioned in the previous paragraph.
|
240
|
+
The built-in Range always has the begin-exclude status of
|
241
|
+
<tt>false</tt>. For that reason, no instance of built-in Range
|
242
|
+
has the status of <tt>empty?</tt> of <tt>true</tt>.
|
243
|
+
|
244
|
+
For more detail and examples see the documents of
|
245
|
+
{Range#empty?}
|
246
|
+
|
247
|
+
Finally, {Range#null?} is equivalent to "either empty or not valid".
|
248
|
+
Therefore, for RangeExtd objects <tt>null?</tt> is equivalent to
|
249
|
+
<tt>empty?</tt>.
|
250
|
+
|
251
|
+
In comparison (<tt><=></tt>) between a RangeExtd and another RangeExtd or Range
|
252
|
+
object, those definitions are taken into account.
|
253
|
+
Some of them are shown in the above Examples section.
|
254
|
+
For more detail, see {Range#==}> and {RangeExtd#==}>, as
|
255
|
+
well as <tt>#eql?</tt>.
|
256
|
+
|
257
|
+
Note that as long as the operation is within Range objects, the
|
258
|
+
behaviour is identical to the standard Ruby -- it is completely
|
259
|
+
compatible. Therefore, requiring this library would not affect any
|
260
|
+
existing code in principle.
|
261
|
+
|
262
|
+
|
263
|
+
== Known bugs
|
264
|
+
|
265
|
+
* <tt>hash()</tt> method does not always guarantee to return a unique
|
266
|
+
and exclusive number for the equal RangeExtd object, though such an
|
267
|
+
exception is extremely unlikely to happen in reality.
|
268
|
+
|
269
|
+
Note this library does not work in Ruby 1.8 or earlier.
|
270
|
+
For Ruby 1.9.3 it is probably all right, however I have never tested
|
271
|
+
it.
|
272
|
+
|
273
|
+
Extensive tests have been performed, as included in the package.
|
274
|
+
|
275
|
+
|
276
|
+
== ToDo
|
277
|
+
|
278
|
+
Nothing planned.
|
279
|
+
|
280
|
+
|
281
|
+
== Final notes
|
282
|
+
|
283
|
+
All the behaviours within RangeExtd (not Range), such as
|
284
|
+
any comparison between two RangeExtd, should be (or hopefully?)
|
285
|
+
natural for you. At least it is well-defined and self-consistent, as
|
286
|
+
the logical structure of the ranges is now complete with RangeExtd.
|
287
|
+
Note some behaviours for open-ended or begin-excluded ranges may
|
288
|
+
give you a little shock at first. For example, the method
|
289
|
+
<tt>member?(obj)</tt> for an open-ended range for the negative direction with
|
290
|
+
discrete elements returns <tt>nil</tt>. That is because no meaningful method
|
291
|
+
of <tt>succ()</tt> is defined for the (negative) infinity, hence it is
|
292
|
+
theoretically impossible in general to check whether the given obj is a member of
|
293
|
+
the range or not. You may find it to be weird, but that just means
|
294
|
+
the concept of the infinity is unfamiliar to us mortals!
|
295
|
+
|
296
|
+
On the other hand, the comparison between RangeExtd and Range may have
|
297
|
+
more occasional surprises. That is because some of the accepted
|
298
|
+
ranges by built-in Range class are no longer valid in this framework with the
|
299
|
+
inclusion of exclude-status of the begin boundary, as explained.
|
300
|
+
Hopefully you will feel it to be natural as you get accustomed to it.
|
301
|
+
And I bet once you have got accustomed to it, you will never want to
|
302
|
+
go back to the messy world of logical incompleteness, that is, the
|
303
|
+
current behaviour of Range!
|
304
|
+
|
305
|
+
Enjoy.
|
306
|
+
|
307
|
+
|
308
|
+
|
309
|
+
== Miscellaneous
|
310
|
+
|
311
|
+
== Copyright etc
|
312
|
+
|
313
|
+
Author:: Masa Sakano < imagine a_t sakano dot co dot uk >
|
314
|
+
License:: MIT.
|
315
|
+
Warranty:: No warranty whatsoever.
|
316
|
+
Versions:: The versions of this package follow Semantic Versioning (2.0.0) http://semver.org/
|
317
|
+
|
318
|
+
|
319
|
+
|
2
320
|
= RangeExtd - 拡張Rangeクラス - exclude_begin と無限大に開いた範囲と
|
3
321
|
|
4
322
|
このパッケージは、Range を拡張した RangeExtd クラスを定義しています。
|
@@ -31,17 +31,17 @@ class RangeExtd < Range
|
|
31
31
|
# respectively, than any other Comparable objects (1 or -1 by i{#<=>}(obj))
|
32
32
|
# except for infinities with the same polarity, that is, positive or negative,
|
33
33
|
# in which case 0 is returned.
|
34
|
-
# See the document of the method
|
34
|
+
# See the document of the method {#==} for the definition of "infinity".
|
35
35
|
# Also, {#succ} is defined, which just returns self.
|
36
36
|
#
|
37
37
|
# There is a note of caution.
|
38
38
|
# The method {#<=>} is defined in this class as mentioned above.
|
39
|
-
#
|
39
|
+
# However any operator is, by Ruby's definition, not commutative,
|
40
40
|
# unless both the classes define so.
|
41
41
|
#
|
42
42
|
# There are only two built-in classes that are Comparable: String and Numeric
|
43
43
|
# (except for Complex).
|
44
|
-
# For String class objects, the
|
44
|
+
# For String class objects, the [#<=>] operator work as expected
|
45
45
|
# in the commutative way.
|
46
46
|
# ?z <=> RangeExtd::Infinity::POSITIVE # => nil
|
47
47
|
# RangeExtd::Infinity::POSITIVE <=> ?z # => 1.
|
@@ -66,7 +66,7 @@ class RangeExtd < Range
|
|
66
66
|
# whether you or authors of libraries.
|
67
67
|
# The comparison with {RangeExtd::Infinity} instances are
|
68
68
|
# implemented in {Object#<=>} in this library. Hence, as long as
|
69
|
-
# the method
|
69
|
+
# the method [#<=>] in the classes is written sensibly, that is, if it
|
70
70
|
# respects the method of the super-class when it does not know
|
71
71
|
# how to deal with an unknown object, there is no need for
|
72
72
|
# modification. Any object in your class (say, YourComparable)
|
@@ -84,11 +84,11 @@ class RangeExtd < Range
|
|
84
84
|
# For that sort of circumstances,
|
85
85
|
# the class method {RangeExtd::Infinity.overwrite_compare} provides
|
86
86
|
# a convenient way to overcome this problem to make
|
87
|
-
# the operator
|
87
|
+
# the operator [#<=>] commutative for a given Comparable class.
|
88
88
|
#
|
89
89
|
# Note {RangeExtd::Infinity.overwrite_compare} does nothing for the classes
|
90
90
|
# registered in the Class constant Array {RangeExtd::Infinity::CLASSES_ACCEPTABLE}.
|
91
|
-
# So, if you want to avoid such modification of the method
|
91
|
+
# So, if you want to avoid such modification of the method [#<=>], perhaps
|
92
92
|
# by some other end users, you can register the class in that array.
|
93
93
|
#
|
94
94
|
# Only the methods defined in this class are
|
@@ -129,7 +129,7 @@ class RangeExtd < Range
|
|
129
129
|
|
130
130
|
# Always -1 or 1 except for itself and the corresponding infinities (== 0). See {#==}.
|
131
131
|
# Or, nil (as defined by Object), if the argument is not Comparable, such as, nil and IO.
|
132
|
-
# @return [Integer
|
132
|
+
# @return [Integer, nil]
|
133
133
|
def <=>(c)
|
134
134
|
if c.nil?
|
135
135
|
super
|
@@ -189,7 +189,7 @@ class RangeExtd < Range
|
|
189
189
|
alias :to_s :inspect
|
190
190
|
|
191
191
|
|
192
|
-
# Overwrite
|
192
|
+
# Overwrite [#<=>] method of the given class, if necessary,
|
193
193
|
# to make its instances be comparable with RangeExtd::Infinity objects (constants).
|
194
194
|
# For example,
|
195
195
|
# RangeExtd::Infinity::NEGATIVE.<=>(any_comparable)
|
@@ -199,7 +199,7 @@ class RangeExtd < Range
|
|
199
199
|
# Therefore, this function (Class method) provides a convenient
|
200
200
|
# way to overcome it, that is, if the given class
|
201
201
|
# (or the class of the given object) is Comparable,
|
202
|
-
# its
|
202
|
+
# its [#<=>] method is modified (and true is returned),
|
203
203
|
# unless it has been already done so, or some classes as listed below,
|
204
204
|
# such as Numeric and String, in which case nil is returned.
|
205
205
|
# If it is not Comparable, false is returned.
|
@@ -214,7 +214,7 @@ class RangeExtd < Range
|
|
214
214
|
# the class in the array.
|
215
215
|
#
|
216
216
|
# @param obj [Object] Either Class or its object.
|
217
|
-
# @return [Boolean
|
217
|
+
# @return [Boolean, nil] (see the description).
|
218
218
|
def self.overwrite_compare(obj)
|
219
219
|
if defined? obj.instance_methods
|
220
220
|
klass = obj
|
@@ -315,21 +315,21 @@ end # class RangeExtd < Range
|
|
315
315
|
#
|
316
316
|
# = class Object
|
317
317
|
#
|
318
|
-
# Overwrite Object#<=>() so all its sub-classes can be
|
319
|
-
# aware of RangeExtd::Infinity objects (the two constants).
|
318
|
+
# Overwrite {Object#<=>}() so all its sub-classes can be
|
319
|
+
# aware of {RangeExtd::Infinity} objects (the two constants).
|
320
320
|
#
|
321
321
|
class Object
|
322
322
|
alias :compare_obj_before_infinity :== if ! self.method_defined?(:compare_obj_before_infinity) # No overwriting.
|
323
323
|
|
324
|
-
# Overwrite
|
324
|
+
# Overwrite {Object#<=>}(). Then, all its sub-classes can be
|
325
325
|
# aware of RangeExtd::Infinity objects (the two constants).
|
326
326
|
#
|
327
|
-
# In this definition of
|
328
|
-
# (by judging whether it has the method
|
327
|
+
# In this definition of {#<=>}, if self is Comparable
|
328
|
+
# (by judging whether it has the method [#<=]),
|
329
329
|
# it always returns, unless infinity? and positive? are set
|
330
330
|
# accordingly, either -1 or 1, depending which of
|
331
331
|
# RangeExtd::Infinity::(NEGATIVE|POSITIVE)
|
332
|
-
# is compared. If self is not Comparable, the original
|
332
|
+
# is compared. If self is not Comparable, the original [#<=>]
|
333
333
|
# is called, which should return nil (unless both the object_id
|
334
334
|
# agree, eg., nil and nil, in which case 0 is returned).
|
335
335
|
#
|
@@ -337,6 +337,7 @@ class Object
|
|
337
337
|
# define the method "<=>" as follows, as in the standard practice
|
338
338
|
# when you redefine a method that exists in a superclass;
|
339
339
|
#
|
340
|
+
# @example A method definition of user-defined Comparable class
|
340
341
|
# class MyComparableClass
|
341
342
|
# include Comparable
|
342
343
|
# # alias :cmp_orig :<=> if !self.method_defined?(:cmp_orig) # if you want
|
@@ -71,10 +71,7 @@ end
|
|
71
71
|
# the two (negative and positive, or former and later) constants
|
72
72
|
# in RangeExtd::Infinity class. See the document for detail.
|
73
73
|
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
# An instance of a range of 5 to 8 with both ends being exclusive is created as
|
77
|
-
#
|
74
|
+
# @example An instance of a range of 5 to 8 with both ends being exclusive is created as
|
78
75
|
# r = RangeExtd(5...8, true)
|
79
76
|
# r.exclude_begin? # => true
|
80
77
|
#
|
@@ -145,6 +142,7 @@ class RangeExtd < Range
|
|
145
142
|
|
146
143
|
# true if self is identical to {RangeExtd::NONE}.
|
147
144
|
# This is different from {#==} method!
|
145
|
+
# @example
|
148
146
|
# RangeExtd(0,0,false,false) == RangeExtd::NONE # => true
|
149
147
|
# RangeExtd(0,0,false,false).empty? # => true
|
150
148
|
# RangeExtd(0,0,false,false).is_none? # => false
|
@@ -153,7 +151,8 @@ class RangeExtd < Range
|
|
153
151
|
self.begin.nil? && self.end.nil? && @exclude_begin && @exclude_end # Direct comparison with object_id should be OK?
|
154
152
|
end
|
155
153
|
|
156
|
-
# true if self is identical to RangeExtd::EVERYTHING ({#==} does not mean it at all!)
|
154
|
+
# true if self is identical to {RangeExtd::EVERYTHING} ({#==} does not mean it at all!)
|
155
|
+
# @example
|
157
156
|
# (RangeExtd::Infinity::NEGATIVE..RangeExtd::Infinity::POSITIVE).is_everything? # => false
|
158
157
|
def is_everything?
|
159
158
|
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.)
|
@@ -179,7 +178,11 @@ class RangeExtd < Range
|
|
179
178
|
# this returns true, regardless of their boundary values.
|
180
179
|
# And any empty range is equal to RangeExtd::Infinity::NONE.
|
181
180
|
#
|
182
|
-
#
|
181
|
+
# Note the last example will return false for {#eql?} -- see {#eql?}
|
182
|
+
#
|
183
|
+
# See {#eql?}
|
184
|
+
#
|
185
|
+
# @example
|
183
186
|
# (1<...1) == RangeExtd::NONE # => true
|
184
187
|
# (?a<...?b) == RangeExtd::NONE # => true
|
185
188
|
# (1<...1) == (2<...2) # => true
|
@@ -188,9 +191,6 @@ class RangeExtd < Range
|
|
188
191
|
# (1<...1) != (?c<...?c) # - because of Fixnum and String
|
189
192
|
# (1.0<...1.0) == (3<...4) # => true
|
190
193
|
#
|
191
|
-
# Note the last example will return false for {#eql?} -- see {#eql?}
|
192
|
-
#
|
193
|
-
# See {#eql?}
|
194
194
|
# @return [Boolean]
|
195
195
|
def ==(r)
|
196
196
|
re_equal_core(r, :==)
|
@@ -201,6 +201,7 @@ class RangeExtd < Range
|
|
201
201
|
# the immediate class has to agree to return true.
|
202
202
|
# Only the exception is the comparison with RangeExtd::Infinity::NONE.
|
203
203
|
# Therefore,
|
204
|
+
# @example
|
204
205
|
# (1...5) == (1.0...5.0) # => true
|
205
206
|
# (1...5).eql?(1.0...5.0) # => false
|
206
207
|
# (1<...1).eql?( RangeExtd::NONE) # => true
|
@@ -221,15 +222,15 @@ class RangeExtd < Range
|
|
221
222
|
# In the standard Range, this checks whether the given object is a member, hence,
|
222
223
|
# (?D..?z) === ?c # => true
|
223
224
|
# (?a..?z) === "cc" # => false
|
224
|
-
# In the case of the former, after finite trials of succ
|
225
|
-
# In the latter, after finit trials of succ
|
225
|
+
# In the case of the former, after finite trials of [#succ] from ?c, it reaches the end (?z).
|
226
|
+
# In the latter, after finit trials of [#succ] from the begin ?a, it reaches the end (?z).
|
226
227
|
# Therefore it is theoretically possible to prove it (n.b., the actual
|
227
228
|
# algorithm of built-in {Range#include?} is different and cheating!
|
228
229
|
# See below.).
|
229
230
|
#
|
230
231
|
# However, in the case of
|
231
232
|
# (?D..Infinity) === ?c
|
232
|
-
# it can never prove ?c is a member after infinite trials of succ
|
233
|
+
# it can never prove ?c is a member after infinite trials of [#succ],
|
233
234
|
# whether it starts the trials from the begin (?D) or the object (?c).
|
234
235
|
#
|
235
236
|
# For anything but Numeric, use {#cover?} instead.
|
@@ -238,7 +239,7 @@ class RangeExtd < Range
|
|
238
239
|
# (?B..?z) === 'dd' # => false
|
239
240
|
# as Ruby's {Range} knows the algorithm of {String#succ} and {String#<=>}
|
240
241
|
# and specifically checks with it, before using {Enumerable#include?}.
|
241
|
-
#
|
242
|
+
# {https://github.com/ruby/ruby/blob/trunk/range.c}
|
242
243
|
#
|
243
244
|
# Therefore, even if you change the definition of {String#succ}
|
244
245
|
# so that 'B'.succ => 'dd', 'dd'.succ => 'z', as follows,
|
@@ -262,7 +263,8 @@ class RangeExtd < Range
|
|
262
263
|
# (?X..?z).each do |i| print i;end # => "XYZ[\]^_`abcdefghijklmnopqrstuvwxyz"
|
263
264
|
# ?Z.succ # => 'AA'
|
264
265
|
#
|
265
|
-
# @param
|
266
|
+
# @param [Object] obj If this Object is a member?
|
267
|
+
# @return [Boolean]
|
266
268
|
def ===(obj)
|
267
269
|
# ("a".."z")===("cc") # => false
|
268
270
|
|
@@ -337,7 +339,7 @@ class RangeExtd < Range
|
|
337
339
|
# If Integer, the search is conducted on the descrete Integer points only,
|
338
340
|
# and no search will be made in between the adjascent integers.
|
339
341
|
#
|
340
|
-
# Given that, RangeExtd#bsearch follows basically the same, even when exclude_begin? is true.
|
342
|
+
# Given that, {RangeExtd#bsearch} follows basically the same, even when exclude_begin? is true.
|
341
343
|
# If either end is Float, it searches between begin*(1+Float::EPSILON) and end.
|
342
344
|
# If both are Integer, it searches from begin+1.
|
343
345
|
# When {#exclude_begin?} is false, {RangeExtd#bsearch} is identical to {Range#bsearch}.
|
@@ -420,8 +422,9 @@ class RangeExtd < Range
|
|
420
422
|
# Like {Range#last}, if no argument is given, it behaves like {#begin()}, that is, it returns the initial value, regardless of {#exclude_begin?}.
|
421
423
|
# 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().
|
422
424
|
# @raise [TypeError] if the argument (Numeric) is given and if {#exclude_begin?} is true, yet if {#begin}().succ is not defined, or yet if {#none}?
|
423
|
-
# @param [
|
424
|
-
#
|
425
|
+
# @param [Integer] Optional. Must be non-negative. Consult {Range#first} for detail.
|
426
|
+
# @return [Object] if no argument is given, equivalent to {#end}.
|
427
|
+
# @return [Array] if an argument is given.
|
425
428
|
def first(*rest)
|
426
429
|
# (1...3.1).last # => 3.1
|
427
430
|
# (1...3.1).last(1) # => [3]
|
@@ -491,7 +494,8 @@ class RangeExtd < Range
|
|
491
494
|
# an argument in practice, the number of the members of the returned array.
|
492
495
|
#
|
493
496
|
# @raise [TypeError] If self.begin.succ is not defined, or if either side is Infinity.
|
494
|
-
# @return [Object] if no argument is given, equivalent to {#end}.
|
497
|
+
# @return [Object] if no argument is given, equivalent to {#end}.
|
498
|
+
# @return [Array] if an argument is given.
|
495
499
|
def last(*rest)
|
496
500
|
return nil if null?
|
497
501
|
nSize = rest.size
|
@@ -568,7 +572,8 @@ class RangeExtd < Range
|
|
568
572
|
# See {#first} for the definition when {#exclude_begin?} is true.
|
569
573
|
# @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).
|
570
574
|
#
|
571
|
-
# @return [Integer]
|
575
|
+
# @return [Integer] 0 if {RangeExtd::NONE}
|
576
|
+
# @return [nil] if the range is non-Numeric.
|
572
577
|
def size(*rest)
|
573
578
|
# (1..5).size # => 5
|
574
579
|
# (1...5).size # => 4
|
@@ -744,7 +749,9 @@ class RangeExtd < Range
|
|
744
749
|
# because any built-in Range object has the exclude status
|
745
750
|
# of false (namely, inclusive) for {#begin}.
|
746
751
|
#
|
747
|
-
#
|
752
|
+
# Note the last example may change in the future release.
|
753
|
+
#
|
754
|
+
# @example
|
748
755
|
#
|
749
756
|
# RangeExtd.valid?(nil..nil) # => false
|
750
757
|
# RangeExtd.valid?(nil...nil) # => false
|
@@ -760,8 +767,6 @@ class RangeExtd < Range
|
|
760
767
|
# RangeExtd.valid?(RangeExtd::Infinity::NEGATIVE..?d) # => true
|
761
768
|
# RangeExtd.valid?(RangeExtd::Infinity::NEGATIVE..?d, true) # => true
|
762
769
|
#
|
763
|
-
# Note the last example may change in the future release.
|
764
|
-
#
|
765
770
|
# @overload new(range, [exclude_begin=false, [exclude_end=false]])
|
766
771
|
# @param [Object] range Instance of Range or its subclasses, including RangeExtd
|
767
772
|
# @param exclude_begin [Object] true or false(Default) or any
|
@@ -821,8 +826,7 @@ class RangeExtd < Range
|
|
821
826
|
private
|
822
827
|
|
823
828
|
# Core routine for {#inspect} and {#to_s}
|
824
|
-
# @param
|
825
|
-
# @param method [Symbol] of the method name.
|
829
|
+
# @param [Symbol] method the method name.
|
826
830
|
def re_inspect_core(method)
|
827
831
|
if @exclude_end
|
828
832
|
midStr = "..."
|
@@ -840,8 +844,8 @@ class RangeExtd < Range
|
|
840
844
|
|
841
845
|
|
842
846
|
# Core routine for {#===} and {#eql?}
|
843
|
-
# @param
|
844
|
-
# @param
|
847
|
+
# @param [Object] r to compare.
|
848
|
+
# @param [Symbol] method of the method name.
|
845
849
|
def re_equal_core(r, method)
|
846
850
|
if defined? r.empty?
|
847
851
|
is_r_empty = r.empty?
|
@@ -964,9 +968,10 @@ class Range
|
|
964
968
|
#
|
965
969
|
# See {RangeExtd.valid?} for the definition of what is valid
|
966
970
|
# and more examples.
|
971
|
+
#
|
972
|
+
# See {#empty?} and {#null?}, too.
|
967
973
|
#
|
968
|
-
#
|
969
|
-
#
|
974
|
+
# @example
|
970
975
|
# (nil..nil).valid? # => false
|
971
976
|
# (0..0).valid? # => true
|
972
977
|
# (0...0).valid? # => false
|
@@ -975,8 +980,6 @@ class Range
|
|
975
980
|
# (3..Float::INFINITY).valid? # => true
|
976
981
|
# RangeExtd::NONE.valid? # => true
|
977
982
|
# RangeExtd::EVERYTHING.valid? # => true
|
978
|
-
#
|
979
|
-
# See {#empty?} and {#null?}, too.
|
980
983
|
#
|
981
984
|
# @note By definition, all the {RangeExtd} instances are valid,
|
982
985
|
# because {RangeExtd#new} checks the validity.
|
@@ -1005,8 +1008,7 @@ class Range
|
|
1005
1008
|
#
|
1006
1009
|
# In these conditions, none of Range instance would return true in {#empty}.
|
1007
1010
|
#
|
1008
|
-
#
|
1009
|
-
#
|
1011
|
+
# @example
|
1010
1012
|
# (nil..nil).empty? # => nil
|
1011
1013
|
# (1...1).empty? # => nil
|
1012
1014
|
# (1..1).empty? # => false
|
@@ -1018,6 +1020,8 @@ class Range
|
|
1018
1020
|
#
|
1019
1021
|
# @note to check whether it is either empty or invalid, use {#null?}.
|
1020
1022
|
# See {#valid?} and {RangeExtd.valid}, too.
|
1023
|
+
#
|
1024
|
+
# @return [Boolean, nil]
|
1021
1025
|
def empty?
|
1022
1026
|
# This is basically for the sake of sub-classes, as any built-in Range instance
|
1023
1027
|
# always returns either nil or false.
|
data/range_extd.gemspec
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{range_extd}
|
5
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.1"
|
6
6
|
# s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
7
7
|
# s.executables << 'hola'
|
8
8
|
# s.bindir = 'bin'
|
9
9
|
s.authors = ["Masa Sakano"]
|
10
|
-
s.date = %q{2014-04-
|
10
|
+
s.date = %q{2014-04-28}
|
11
11
|
s.summary = %q{RangeExtd - Extended Range class with exclude_begin and open-ends}
|
12
12
|
s.description = %q{This defines a subclass of Range, RangeExtd and its subclass, RangeExtd::Infinity. The former defines a range that enables an exclusion of the begin boundary, in addition to the end boundary as in the built-in Range, and accepts open-ended ranges to infinity for either (or both) positive/negative direction. The latter has the two constant objects, POSITIVE and NEGATIVE, and they are a generalised Infinity of Float::INFINITY to any Comparable objects.}
|
13
13
|
# s.email = %q{abc@example.com}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: range_extd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masa Sakano
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: This defines a subclass of Range, RangeExtd and its subclass, RangeExtd::Infinity. The
|
14
14
|
former defines a range that enables an exclusion of the begin boundary, in addition
|