range_extd 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 +7 -0
- data/ChangeLog +14 -0
- data/README.en.rdoc +317 -0
- data/README.ja.rdoc +300 -0
- data/Rakefile +9 -0
- data/lib/range_extd/infinity/infinity.rb +386 -0
- data/lib/range_extd/range_extd.rb +1137 -0
- data/range_extd.gemspec +47 -0
- data/test/test_range_extd.rb +1253 -0
- metadata +61 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ddcd6d0416bca878881275877c7b388867fbd51d
|
4
|
+
data.tar.gz: 68631346bbd9735b6362e179294b854429a36d47
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0b0b845ea47998f05ffdbcbf4adddafd129ba25418df63fdaaefb21748aa84d9a133618e880edd2009701141a9e1209ca6b67194f57b4c07da2fde4cc1a2c7b3
|
7
|
+
data.tar.gz: cfccffebf7081da3260b93f939a25e7c4f0c7374437a1a264786b727b5bfa7a362b41285d94bc04e868ef36eb44c264a4187351c08d08144011cae5f0b727887
|
data/ChangeLog
ADDED
data/README.en.rdoc
ADDED
@@ -0,0 +1,317 @@
|
|
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
|
+
|
data/README.ja.rdoc
ADDED
@@ -0,0 +1,300 @@
|
|
1
|
+
|
2
|
+
= RangeExtd - 拡張Rangeクラス - exclude_begin と無限大に開いた範囲と
|
3
|
+
|
4
|
+
このパッケージは、Range を拡張した RangeExtd クラスを定義しています。
|
5
|
+
以下の特徴を持ちます。
|
6
|
+
|
7
|
+
1. メソッド exclude_begin? の導入 (レンジの始点を除外できる),
|
8
|
+
2. (無限大に)開いたレンジ
|
9
|
+
3. NONE (空レンジ) と EVERYTHING (全範囲レンジ)定数の導入
|
10
|
+
4. 初めて自己論理的に完結したレンジ構造の達成
|
11
|
+
5. 組込Rangeとの完全後方互換性
|
12
|
+
|
13
|
+
組込Rangeにある exclude_end に加えて、exclude_beginを導入したこと、及
|
14
|
+
び無限大へ開いた範囲を許可したことで、一次元上の範囲の論理的完全性を実
|
15
|
+
現しました。
|
16
|
+
|
17
|
+
これにより、レンジの有効性を厳密に定義しています。それに従って、数個の
|
18
|
+
メソッドを Range及び(自然に)そのサブクラスに追加しました。なかでも特徴的なのが、
|
19
|
+
{Range#valid?} と {Range#empty?} です。
|
20
|
+
|
21
|
+
たとえば、<tt>(3...3).valid?</tt> は偽を返します。要素の 3 が、始点と
|
22
|
+
しては含まれているのに対し、終点としては除外されていて、これは相互に矛
|
23
|
+
盾しているためです。ここで導入する RangeExtdクラスにおいては、以下のよ
|
24
|
+
うにこれが有効なレンジとして定義できます。
|
25
|
+
* RangeExtd.new(3, 3, true, true) # => 空レンジ
|
26
|
+
* RangeExtd.new(3, 3, false, false) # => 一点レンジ (3..3)
|
27
|
+
|
28
|
+
しかしながら、組込Rangeの範囲内に収まっている限り、何も変わっていませ
|
29
|
+
ん。つまり、標準の Rubyとの完全な後方互換性を実現しています。
|
30
|
+
|
31
|
+
無限に開いたレンジを表すのは簡単です。単に {RangeExtd::Infinity}クラスで
|
32
|
+
定義されている二つの定数(無限大または無現小、あるいは無限前と無限後)の
|
33
|
+
いずれかを用います。
|
34
|
+
* RangeExtd::Infinity::NEGATIVE
|
35
|
+
* RangeExtd::Infinity::POSITIVE
|
36
|
+
|
37
|
+
これらは基本的に <tt>Float::INFINITY</tt> を全ての Comparableであるオ
|
38
|
+
ブジェクトに一般化したものです。たとえば、
|
39
|
+
("a"..RangeExtd::Infinity::POSITIVE).each
|
40
|
+
は、"a"から始まる <tt>String#succ</tt> を使った無限のイテレーターを与えます
|
41
|
+
(だから、どこかで必ず breakするようにコードを書きましょう!)。
|
42
|
+
|
43
|
+
組込 Rangeは大変有用なクラスであり、Rubyユーザーに容易なプログラミングを可能にす
|
44
|
+
るツールでした。しかし、始点を除外することができないのが玉に瑕でありました。
|
45
|
+
|
46
|
+
ただし、それにはれっきとした理由があることは分かります。Rubyの Rangeは、Numeric
|
47
|
+
(厳密にはその実数を表現したもの)だけに限ったものではありません。 <tt>succ()</tt> メソッ
|
48
|
+
ドを持つオブジェクトによる Rangeは極めて有用です。一方、<tt>succ()</tt> の逆に相
|
49
|
+
当するメソッドは一般的には定義されていません。そういう意味で、Rangeは本質的に非
|
50
|
+
対称です。加えて、よく使われる Rangeオブジェクトのうちあるもの(たとえば Float)は
|
51
|
+
連続的なのに対し、そうでないものも普通です(たとえば Integer や String)。この状況
|
52
|
+
が厳密な定義をする時の混乱に拍車をかけています。
|
53
|
+
|
54
|
+
ここで始点を除外可能としたことは、そういう意味で、道筋が100パーセント明らかなも
|
55
|
+
のではありませんでした。ここで私が採用した RangeExtdクラスの定義は、おそらく、考え
|
56
|
+
られる唯一のものではないでしょう。とはいえ、個人的には満足のいくものに仕上がりま
|
57
|
+
したし、このレンジという枠内での論理的完全性をうまく達成できたと思います。
|
58
|
+
|
59
|
+
このクラスが少なからぬ人に有用なものであることを願ってここにリリースします。
|
60
|
+
|
61
|
+
|
62
|
+
== インストール
|
63
|
+
|
64
|
+
gem install range_extd
|
65
|
+
|
66
|
+
により、ファイルが 2個、
|
67
|
+
range_extd/range_extd.rb
|
68
|
+
range_extd/infinity/infinity.rb
|
69
|
+
<tt>$LOAD_PATH</tt> の一カ所にインストールされるはずです。
|
70
|
+
|
71
|
+
あるいは、パッケージを以下から入手できます。
|
72
|
+
http://rubygems.org/gems/range_extd
|
73
|
+
|
74
|
+
後は、Ruby のコード(又は irb)から
|
75
|
+
require 'range_extd/range_extd'
|
76
|
+
とするだけです。もしくは、特に手でインストールした場合は、
|
77
|
+
require 'range_extd'
|
78
|
+
とする必要があるかも知れません。もう一方のファイル
|
79
|
+
range_extd/infinity/infinity.rb
|
80
|
+
は、自動的に読み込まれます。
|
81
|
+
|
82
|
+
お楽しみあれ!
|
83
|
+
|
84
|
+
|
85
|
+
== 単純な使用例
|
86
|
+
|
87
|
+
=== RangeExtd インスタンスを作成する方法
|
88
|
+
|
89
|
+
以下に幾つかの基本的な使用例を列挙します。
|
90
|
+
|
91
|
+
r = RangeExtd(?a...?d, true) # => a<...d
|
92
|
+
r.exclude_begin? # => true
|
93
|
+
r.to_a # => ["b", "c"]
|
94
|
+
RangeExtd(1...2) == (1...2) # => true
|
95
|
+
RangeExtd(1, 2, false, true)== (1...2) # => true
|
96
|
+
RangeExtd(1, 1, false, false)==(1..1) # => true
|
97
|
+
RangeExtd(1, 1, true, true) == RangeExtd::NONE # => true
|
98
|
+
RangeExtd(1, 1, false, true) # => ArgumentError
|
99
|
+
(RangeExtd::Infinity::NEGATIVE..RangeExtd::Infinity::POSITIVE) \
|
100
|
+
== RangeExtd::EVERYTHING # => true
|
101
|
+
|
102
|
+
インスタンスを作成するのには、二通りあります。
|
103
|
+
|
104
|
+
RangeExtd(range, [exclude_begin=false, [exclude_end=false]])
|
105
|
+
RangeExtd(obj_begin, obj_end, [exclude_begin=false, [exclude_end=false]])
|
106
|
+
|
107
|
+
後ろの二つのパラメーターが、それぞれ始点と終点とを除外する(true)、または含む
|
108
|
+
(false)を指示します。もし、その二つのパラメーターが最初のパラメーターのレンジ
|
109
|
+
(Range or RangeExtd) と矛盾する場合は、ここで与えた二つのパラメーターが優先され
|
110
|
+
ます。 <tt>RangeExtd.new()</tt> も上と同意味です。
|
111
|
+
|
112
|
+
|
113
|
+
=== 少し上級編
|
114
|
+
|
115
|
+
(1..RangeExtd::Infinity::POSITIVE).each do |i|
|
116
|
+
print i
|
117
|
+
break if i >= 9
|
118
|
+
end # => self ( "123456789" => STDOUT )
|
119
|
+
(nil..nil).valid? # => false
|
120
|
+
(1...1).valid? # => false
|
121
|
+
(1...1).null? # => true
|
122
|
+
RangeExtd.valid?(1...1) # => false
|
123
|
+
RangeExtd(1, 1, true, true).valid? # => true
|
124
|
+
RangeExtd(1, 1, true, true).empty? # => true
|
125
|
+
RangeExtd(?a, ?b, true, true).to_a? # => []
|
126
|
+
RangeExtd(?a, ?b, true, true).empty? # => true
|
127
|
+
RangeExtd(?a, ?e, true, true).to_a? # => ["b", "c", "d"]
|
128
|
+
RangeExtd(?a, ?e, true, true).empty? # => false
|
129
|
+
RangeExtd::NONE.is_none? # => true
|
130
|
+
RangeExtd::EVERYTHING.is_everything? # => true
|
131
|
+
|
132
|
+
組込Rangeに含まれる全てのメソッドが使用可能です。
|
133
|
+
|
134
|
+
|
135
|
+
== 詳説
|
136
|
+
|
137
|
+
ファイル range_extd.rb が読まれた段階で、次の二つのクラスが定義されます。
|
138
|
+
|
139
|
+
* RangeExtd
|
140
|
+
* RangeExtd::Infinity
|
141
|
+
|
142
|
+
加えて、Range クラスに数個のメソッドが追加また改訂されます。Rangeクラスに加えら
|
143
|
+
れる改変は、全て後方互換性を保っています。
|
144
|
+
|
145
|
+
=== RangeExtd::Infinity クラス
|
146
|
+
|
147
|
+
{RangeExtd::Infinity} クラスは、基本、定数二つのみを保持するものです。
|
148
|
+
|
149
|
+
* RangeExtd::Infinity::NEGATIVE
|
150
|
+
* RangeExtd::Infinity::POSITIVE
|
151
|
+
|
152
|
+
これらは、 <tt>Float::INFINITY</tt> を全ての Comparable なオブジェクトに一般化し
|
153
|
+
たものです。メソッド <tt><=></tt> と <tt>succ</tt> が定義されています。
|
154
|
+
|
155
|
+
これらは、他のオブジェクトと同様に普通に使用可能です。たとえば、
|
156
|
+
("k"..RangeExtd::Infinity::POSITIVE)
|
157
|
+
とはいえ、他には何もメソッドを持っていないため、 Range型のクラスの中以外での使用
|
158
|
+
はおそらく意味がないでしょう。
|
159
|
+
|
160
|
+
なお、Numericのオブジェクトに対しては、原則として <tt>Float::INFINITY</tt> の方
|
161
|
+
を使って下さい。
|
162
|
+
|
163
|
+
ユーザー定義のどの Comparable なクラスに属するどのオブジェクトも、これら二定数と
|
164
|
+
可換的に比較可能です。その際、同クラスに置ける比較メソッドがマナー良く書かれてあ
|
165
|
+
る、という前提で。
|
166
|
+
|
167
|
+
さらに詳しくは、マニュアルを参照して下さい(YARD または RDoc形式で書かれた文書が
|
168
|
+
コード内部に埋込まれていますし、それが RubyGemsのウェブサイトでも閲覧できます。
|
169
|
+
|
170
|
+
|
171
|
+
=== RangeExtd クラス
|
172
|
+
|
173
|
+
RangeExtd のインスタンスは、 Rangeと同じくイミュータブルです。だから、一度インス
|
174
|
+
タンスが生成されると、変化しません。
|
175
|
+
|
176
|
+
インスタンスの生成方法は上述の通りです(「使用例」の章)。レンジとして"valid"(後述)と見
|
177
|
+
なされないインスタンスを生成しようとすると、例外(<tt>ArgumentError</tt>)が発生し、
|
178
|
+
失敗します。
|
179
|
+
|
180
|
+
このクラスには、二つの定数が定義されています。
|
181
|
+
|
182
|
+
* RangeExtd::NONE
|
183
|
+
* RangeExtd::EVERYTHING
|
184
|
+
|
185
|
+
前者は、空レンジを表し、後者は全てを含むレンジ、すなわち正負両方向に開いたレンジを表します。
|
186
|
+
|
187
|
+
Rangeクラスの通常のメソッド全てに加え、以下が RangeExtd と Rangeクラス両方に加え
|
188
|
+
られています。詳細は、各メソッドのマニュアルを参照下さい(注: 幾つかのメソッドは
|
189
|
+
Rangeクラスのみで定義されていて、 RangeExtd はそれを継承しています)。
|
190
|
+
|
191
|
+
* <tt>exclude_begin?</tt>
|
192
|
+
* <tt>valid?</tt>
|
193
|
+
* <tt>empty?</tt>
|
194
|
+
* <tt>null?</tt>
|
195
|
+
* <tt>is_none?</tt>
|
196
|
+
* <tt>is_everything?</tt>
|
197
|
+
|
198
|
+
インスタンスメソッドの <tt>valid?</tt> に等価なクラスメソッドも一つあります。
|
199
|
+
* <tt>RangeExtd.valid?</tt>
|
200
|
+
|
201
|
+
何がレンジとして有効 (<tt>#valid?</tt> => true) かの定義は以下です。
|
202
|
+
|
203
|
+
1. 始点と終点とが互いに Comparable であり、かつその比較結果に矛盾がないこと。
|
204
|
+
この唯一の例外は {RangeExtd::NONE} で、これは valid です。
|
205
|
+
たとえば、<tt>(nil..nil)</tt> は valid では「ありません」(参考までに、この例は
|
206
|
+
Ruby 1.8 では例外を生じていました)。
|
207
|
+
2. 始点は終点と等しい(<tt>==</tt>)か小さくなければなりません。すなわし、
|
208
|
+
<tt>(begin <=> end)</tt> は、-1 または 0 を返すこと。
|
209
|
+
3. もし始点と終点とが等しい時、すなわち <tt>(begin <=> end) == 0</tt>ならば、
|
210
|
+
端を除外するかどうかのフラグは両端で一致していなければなりません。
|
211
|
+
すなわち、もし始点が除外ならば、終点も除外されていなくてはならず、逆も真です。
|
212
|
+
その一例として、 <tt>(1...1)</tt> は、"valid" では「ありません」。なぜならば
|
213
|
+
組込レンジでは、始点を常に含むからです。
|
214
|
+
|
215
|
+
さらなる詳細は {RangeExtd.valid?} と {Range#valid?} のマニュアルを
|
216
|
+
参照して下さい。
|
217
|
+
|
218
|
+
何がレンジとして空(<tt>#empty?</tt> => true)かの定義は以下の通りです。
|
219
|
+
|
220
|
+
1. レンジは、valid であること: <tt>valid?</tt> => true
|
221
|
+
2. もしレンジの要素が離散的であれば、すなわち始点の要素がメソッド <tt>succ</tt>
|
222
|
+
を持っていれば、レンジ内部に要素が一つも無いことが条件(当然、始点のフラグ
|
223
|
+
は除外になっていなければなりません): <tt>to_a.empty?</tt> => true
|
224
|
+
3. もしレンジが連続的であれば、すなわち始点の要素がメソッド <tt>succ</tt> を持っ
|
225
|
+
ていなければ、始点と終点とが等しく (<tt>(begin <=> end)</tt> => 0)、かつ両端
|
226
|
+
のフラグが除外になっていること: <tt>(exclude_begin? && exclude_end?)</tt> => true.
|
227
|
+
|
228
|
+
なお、始点と終点とが等しい一方でその除外フラグが一致しない場合は、前節で述べたよ
|
229
|
+
うに "valid"ではありません。組込レンジは、始点除外フラグが常に偽(<tt>false</tt>)で
|
230
|
+
す。そのため、組込Rangeのオブジェクトで、<tt>empty?</tt> が真(<tt>true</tt>)にな
|
231
|
+
ることはありません。
|
232
|
+
|
233
|
+
さらなる詳細は {Range#empty?} のマニュアルを
|
234
|
+
参照して下さい。
|
235
|
+
|
236
|
+
|
237
|
+
最後、 {Range#null?} は、「<tt>empty?</tt> または "valid"でない」ことに等
|
238
|
+
価です。従って、 RangeExtd オブジェクトにとっては、<tt>null?</tt> は
|
239
|
+
<tt>empty?</tt> に等価です。
|
240
|
+
|
241
|
+
RangeExtd と別の RangeExtd または Rangeの比較 (<tt><=></tt>) においては、これら
|
242
|
+
の定義が考慮されます。そのうちの幾つかは、上の「使用例」の項に示されています。
|
243
|
+
さらなる詳細は {Range#==}、{RangeExtd#==} および
|
244
|
+
<tt>#eql?</tt> のマニュアルを参照して下さい。
|
245
|
+
|
246
|
+
なお、処理が Rangeオブジェクト内部で閉じている限り、その振舞いは標準 Rubyと同一
|
247
|
+
で、互換性を保っています。したがって、このライブラリを読込むことで既存のコードに
|
248
|
+
影響を与えることは原理的にないはずです。
|
249
|
+
|
250
|
+
|
251
|
+
== 既知のバグ
|
252
|
+
|
253
|
+
* <tt>hash()</tt> メソッドは、等しい RangeExtdオブジェに対して常に唯一で排他的な
|
254
|
+
数値を返すことが保証されていません。ただし、現実的にそれが破られることは、まず
|
255
|
+
ありません。
|
256
|
+
|
257
|
+
このライブラリは Ruby 1.8 およびそれ以前のバージョンでは動作しません。
|
258
|
+
Ruby 1.9.3 ではおそらく大丈夫でしょうが、私は試したことがありません。
|
259
|
+
|
260
|
+
パッケージに含まれている通り、網羅的なテストが実行されています。
|
261
|
+
|
262
|
+
|
263
|
+
== 未処理事項
|
264
|
+
|
265
|
+
特になし。
|
266
|
+
|
267
|
+
|
268
|
+
== 終わりに
|
269
|
+
|
270
|
+
RangeExtd内部に閉じた(Rangeでなく)挙動、たとえば RangeExtd同士の比較などは、
|
271
|
+
全てユーザーにとって自然なもののはずです(と期待します?)。少なくとも、RangeExtdに
|
272
|
+
よってレンジの論理構造が完結した今、これはよく定義されかつ自己矛盾が無いものと言
|
273
|
+
えましょう。ただ、端の無限に開いた、あるいは始点が除外されたレンジの挙動には、
|
274
|
+
一瞬ぎょっとするものが無くはないかも知れないことに注意して下さい。たとえば、
|
275
|
+
片端が小さい方向に無限に開いて離散的な要素を持つレンジに対してメソッド
|
276
|
+
<tt>member?(obj)</tt> を実行すると、 <tt>nil</tt>が返ります。これは、無限(小)に
|
277
|
+
は実質的な意味を持つ <tt>succ()</tt> メソッドが定義されていないためで、したがっ
|
278
|
+
て与えられた objがレンジの要素(member)かどうかを調べることが、一般論としては理論
|
279
|
+
的に不可能だからです。これはちょっと不思議に思うかも知れませんが、それはつまり定
|
280
|
+
命の私たちには無限という概念を計り知るのが容易でない、というだけの話でしょう!
|
281
|
+
|
282
|
+
一方、RangeExtd と Range との比較は、それ以上に驚くことがあるかも知れません。こ
|
283
|
+
れは、組込Rangeクラスで許容されているレンジの一部は、始点を除外することを認めた
|
284
|
+
枠組の中では、前述のように最早有効(valid)と見なされないからです。この枠組に慣れるに
|
285
|
+
したがって、それらが自然だと思えるようになればいいのですが。保証しますが、一旦こ
|
286
|
+
れに慣れてしまえば、論理的不完全さ極まる混沌とした世界、つまりは Rangeの現在の挙
|
287
|
+
動には二度と戻りたくなくなることでしょう!
|
288
|
+
|
289
|
+
お楽しみ下さい。
|
290
|
+
|
291
|
+
|
292
|
+
== その他
|
293
|
+
|
294
|
+
== 著作権他情報
|
295
|
+
|
296
|
+
著者:: Masa Sakano < imagine a_t sakano dot co dot uk >
|
297
|
+
利用許諾条項:: MIT.
|
298
|
+
保証:: 一切無し。
|
299
|
+
バージョン:: Semantic Versioning (2.0.0) http://semver.org/
|
300
|
+
|