rangeary 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f7c7d46eca2e558f3a179b2d3f8210314ed9ec35
4
+ data.tar.gz: c98651d2dd0e8c1cb408a0e9b22ef71597f7888f
5
+ SHA512:
6
+ metadata.gz: d831b7e62d8bc12e3b2e4c824608ec777ba0e730a19c4293455da5d2a5390ed94c2e77ef0640fa260b6599b2268cab3f5caeb8aa968ef11bbd93bbc61ec85a68
7
+ data.tar.gz: fba332856a969680c8b9161cd801a0a6f44eff9de5473ae6ba3c61403b4f2189fc822f9d7ae6b936297a113053dee494c2e1f9e811e9c3495b9b05c3e4ff900e
data/ChangeLog ADDED
@@ -0,0 +1,5 @@
1
+ -----
2
+ (Version: 0.1.0)
3
+ 2014-05-09 Masa Sakano
4
+
5
+ * Initial commit of rangeary and first upload to RubyGems.
data/News ADDED
@@ -0,0 +1,3 @@
1
+ -----
2
+ (Version: 0.1.0) 2014-05-09
3
+ * First upload to RubyGems.
data/README.ja.rdoc ADDED
@@ -0,0 +1,456 @@
1
+
2
+ = Rangeary - Multiple Range(Extd) class
3
+
4
+ This package defines Rangeary class, which contains any multiple
5
+ 1-dimensional ranges ({RangeExtd} objects). For example, a multiple
6
+ range of
7
+ 0.5 < x <= 2.5, 6.0 <= x < 8.0, 10.0 <= x (<= Infinity)
8
+ for <tt>x</tt> can be defined in this class.
9
+
10
+ The element objects for {Rangeary} can be anthing that can form
11
+ {RangeExtd} objects; not only Numeric (or Real) but anything
12
+ Comparable. {Rangeary} accepts the built-in Range-class objects for
13
+ the elements in initialisation, too.
14
+
15
+ All the four standard logical operations, that is, negation
16
+ (<tt>~</tt>), conjunction (<tt>&</tt> or <tt>*</tt>), disjunction
17
+ (<tt>|</tt> or <tt>+</tt>) and exclusive disjunction (<tt>^</tt> or
18
+ <tt>xor</tt>) are defined, as well as subtraction (<tt>-</tt>).
19
+
20
+ {Rangeary} objects are immutable - once it is created, you can not
21
+ alter the contents.
22
+
23
+ Practically, {Rangeary} is a sub-class of Array, works as an array of
24
+ {RangeExtd}, and inherits most of the methods, hence you can apply most
25
+ operations to {Rangeary} that Array accpets, within the restriction of
26
+ immutability of {Rangeary}. In addition, {Rangeary} offers several
27
+ methods that directly work on its element as a range. In the above
28
+ example, <tt>#cover?(1.0)</tt> would return true, whereas
29
+ <tt>#cover?(9.0)</tt>, false.
30
+
31
+
32
+ With this class, logical operations of 1-dimensional range objects are
33
+ now possible and easy.
34
+ I hope you find it to be useful.
35
+
36
+
37
+ == Install
38
+
39
+ First, you need {RangeExtd} class library (basically, two files of pure ruby code), which is in gem:
40
+ gem install range_extd
41
+ Or, get it from
42
+ {https://rubygems.org/gems/range_extd}
43
+ if you have not yet installed it.
44
+
45
+ Then, install this library.
46
+ gem install rangeary
47
+
48
+ A file
49
+ rangeary/rangeary.rb
50
+ should be installed in one of your <tt>$LOAD_PATH</tt>.
51
+ Alternatively, get it from
52
+ {http://rubygems.org/gems/rangeary}
53
+
54
+ Then all you need to do is
55
+ require 'rangeary/rangeary'
56
+ or, possibly as follows, if you manually install it
57
+ require 'rangeary'
58
+ in your Ruby script (or irb). The library files like
59
+ <tt>range_extd/range_extd.rb</tt> for {RangeExtd} is automatically
60
+ loaded.
61
+
62
+ {Rangeary} itself may work in Ruby 1.8, but {RangeExtd} works in only
63
+ Ruby 2.0 (or maybe 1.9.3) and above, hence {Rangeary} does not work in
64
+ Ruby 1.8 or earlier.
65
+
66
+ Have fun!
67
+
68
+
69
+ == Simple Examples
70
+
71
+ === How to create a Rangeary instance
72
+
73
+ Here are some simple examples.
74
+
75
+ r1 = RangeExtd(?a...?d, true) # => a<...d
76
+ ra = Rangeary(?g..?h, r1) # => [a<...d, g..h]
77
+ Rangeary(RangeExtd::NONE) # => [RangeExtd::NONE]
78
+ Rangeary(RangeExtd::NONE, 1..5, 3...7) # => [1...7]
79
+ Rangeary(true..true) # => ArgumentError
80
+
81
+ Basically, <tt>Rangeary()</tt> or <tt>Rangeary.new()</tt> accepts
82
+ an arbitrary number of either {Range}, {RangeExtd}, {Rangeary}, or a
83
+ combination of them. Note Range objects that return false in
84
+ {Range#valid?} will raise an exception.
85
+
86
+ For more detail and examples, see {Rangeary.new}.
87
+
88
+
89
+ === Practical application examples
90
+
91
+ ra.to_a # => ["a"<..."d", "g".."h"]
92
+ ra.cover?("a") # => false
93
+ ra.cover?("b") # => true
94
+ ra.end # => "h"
95
+ ra.each do |i|
96
+ print i.begin
97
+ end # => self ( "ag" => STDOUT )
98
+ ra.each_element do |i|
99
+ print i
100
+ end # => self ( "bcgh" => STDOUT )
101
+
102
+ rb = Rangeary(6...9, 2..4) # => [2..4, 6...9]
103
+ rb + Rangeary(3..7) # => [2...9]
104
+ rb - Rangeary(3..7) # => [2...3, RangeExtd(7,'<...',9)]
105
+ rb * Rangeary(4..5, 8..10) # => [4..4, 8...9]
106
+ rb.negation # => [-Float::INFINITY...2, RangeExtd(4,'<...',6), 9..Float::INFINITY]
107
+
108
+ Most of the methods that are in the built-in Array can be used, as long as
109
+ it does not violate the immutability of {Rangeary} objects, such as
110
+ {Array#push}.
111
+
112
+
113
+ == Description
114
+
115
+ Once the file <tt>rangeary.rb</tt> is required, a class is defined, in
116
+ addtion to the two defined in the RangeExtd library
117
+ (<tt>RangeExtd</tt> and <tt>RangeExtd::Infinity</tt>).
118
+
119
+ * Rangeary
120
+
121
+
122
+ === Rangeary Class
123
+
124
+ {Rangeary} objects are immutable, the same as Range and RangeExtd.
125
+ Hence once an instance is created, it would not change.
126
+
127
+ How to create an instance is explained above (in the Examples
128
+ sections). Any attempt to try to create an instance with one of
129
+ elements being not "valid" as a range, that is, {Range#valid?} returns
130
+ false, raises an exception (<tt>ArgumentError</tt>), and fails.
131
+
132
+ Note users can supply negative and/or positive infinity objects in
133
+ initialising {Rangeary} object, corresponding to the range objects
134
+ they give. In default they are the type of either {Float::INFINITY} or
135
+ {RangeExtd::Infinity::POSITIVE}. See {Rangeary.new} for detail.
136
+
137
+ When multiple ranges are given in initialising, they are sorted in
138
+ storing, and if there is any overlap among any of the elements, they
139
+ are treated as disjunction (that is, simple summation). That means
140
+ the objects a {Rangeary} instance holds internally can be different from
141
+ the objects given in initialisation, that is, their {#object_id} may be
142
+ different. In particular, if built-in Range objects are given,
143
+ they are always converted into {RangeExtd} objects internally.
144
+
145
+ If any of the given range in the intialisation is empty, that is,
146
+ {Range#empty?} returns true, they are ignored, unless all of the
147
+ ranges given are empty ranges, in which case the "smallest" one will be
148
+ preserved.
149
+
150
+ If the result of the operation is empty, only the element of the
151
+ resultant {Rangeary} is {RangeExtd::NONE}, and hence
152
+ {Rangeary#empty_element?} will return true.
153
+
154
+ For any Rangeary objects, {Rangeary#to_a}.size is always
155
+ positive and not zero for that reason, or {Rangeary#empty?} returns
156
+ always false, as {Rangeary#empty?} is a method inherited from Array
157
+ (Use {Rangeary#empty_element?} instead to check if the instance is
158
+ empty or not as a range).
159
+ Rangeary(RangeExtd::NONE).empty? # => false
160
+ Rangeary(RangeExtd::NONE).empty_element? # => true
161
+
162
+ As mentioned above, all the methods of Array but a few are inherited
163
+ to this {Rangeary} class, and they work based on each element
164
+ {RangeExtd}. Four methods work differently: {Rangeary#+} and
165
+ {Rangeary#*} are the alias to {Rangeary#disjunction} and
166
+ {Rangeary#conjunction}, repectively. {Rangeary#===} performs
167
+ {Range#===} for all the Rangeary element ranges and return true if any
168
+ of them returns true. Therefore, {Rangeary#===}(RangeExtd(**))
169
+ returns always false. {Rangeary#flatten} returns the concatnated
170
+ array of {Rangeary#to_a} for all the range elements. Also, [#length]
171
+ and [#reverse] are undefined.
172
+
173
+ {Rangeary#==} and {Rangeary#eql?} work the same as Array, hence
174
+ [2..4, 6..8] == Rangeary(2..4, 6..8) # => true
175
+ But please note
176
+ [2..4, 6..8] == Rangeary(6..8, 2..4) # => true
177
+ [6..8, 2..4] == Rangeary(6..8, 2..4) # => false
178
+ In short the direct comparison with a standard Array is not recommended.
179
+ Instead compare with other {Rangeary} objects.
180
+
181
+ All the other methods operating on the element of ranges, rather than
182
+ on the ranges themselves, have a suffix of <tt>_element</tt>, if there
183
+ is the same method name in the built-in Array. For example,
184
+ {Rangeary#size} returns the number of {RangeExtd} objects it holds,
185
+ and {Rangeary#size_element} returns the total {Range#size} of all
186
+ the {RangeExtd} objects it holds.
187
+ Rangeary(1..3, 5..8).size # => 2
188
+ Rangeary(1..3, 5..8).size_element # => 7
189
+
190
+
191
+ == Known bugs
192
+
193
+ * None is known.
194
+
195
+ This library requires Ruby 2.0 or above (it may work all right with
196
+ Ruby 1.9.3, however I have never tested it).
197
+
198
+ Extensive tests have been performed, as included in the package.
199
+
200
+
201
+ == ToDo
202
+
203
+ Nothing planned.
204
+
205
+
206
+ == Final notes
207
+
208
+ This work is inspired by Ian Stewart, who developped a (numeric)
209
+ multiple-range library in Fortran90 for the SAS software package for
210
+ XMM-Newton telescope. I appreciate his work.
211
+
212
+ The implementation to Ruby was not straightforward, though, partly
213
+ because the built-in Range does not allow to exclude the begin
214
+ boundary, and partly because the infinity is not defined for general
215
+ objects but Numeric (Real) in Ruby. {RangeExtd} class I have developed
216
+ makes this library possible. I am glad the completeness of ranges in
217
+ the 1-dimensional space for arbitrary Comparable object is achieved now.
218
+
219
+ Enjoy.
220
+
221
+
222
+
223
+ == Miscellaneous
224
+
225
+ == Copyright etc
226
+
227
+ Author:: Masa Sakano < imagine a_t sakano dot co dot uk >
228
+ License:: MIT.
229
+ Warranty:: No warranty whatsoever.
230
+ Versions:: The versions of this package follow Semantic Versioning (2.0.0) http://semver.org/
231
+
232
+
233
+
234
+ = Rangeary - 複数Range(Extd)クラス
235
+
236
+ このパッケージは、1次元の任意の数のレンジ({RangeExtd} オブジェクト)を
237
+ 保持する Rangeary クラスを定義しています。たとえば、<tt>x</tt> に
238
+ 対する複数レンジの
239
+ 0.5 < x <= 2.5, 6.0 <= x < 8.0, 10.0 <= x (<= 無限大)
240
+ がこのクラスで定義できます。
241
+
242
+ {RangeExtd} の要素たり得るオブジェクトは全て {Rangeary} の要素となり
243
+ 得ます。Numeric(の実数)に限らず、Comparable であるオブジェクトは全て
244
+ 可能です。また、{Rangeary} は、組込Rangeクラスのオブジェクトも初期化に
245
+ 使えます。
246
+
247
+ 四つの標準論理演算全て、すなわち否定(negation; <tt>~</tt>)、論理積
248
+ (conjunction; <tt>&</tt> または <tt>*</tt>)、論理和(disjunction;
249
+ <tt>|</tt> または <tt>+</tt>)および排他的論理和(exclusive disjunction;
250
+ <tt>^</tt> または <tt>xor</tt>)、またそれに加えて引き算(subtraction;
251
+ <tt>-</tt>)が、定義されています。
252
+
253
+ {Rangeary} オブジェクトはイミュータブルです。すなわち、
254
+ 一度インスタンスが生成されると、要素を書換えることはできません。
255
+
256
+ 実用的には、{Rangeary} は、Arrayのサブクラスとなっていて、{RangeExtd}
257
+ の配列として振舞います。また、Arrayのほとんどのメソッドを継承していま
258
+ す。したがって、イミュータブルな{Rangeary}に許される限りにおいて、
259
+ Arrayに使えるほとんどの操作を{Rangeary}に適用できます。加えて、
260
+ {Rangeary}には、そのレンジの要素に直接働きかけるメソッドも幾つかあり
261
+ ます。上に挙げた例ならば、<tt>#cover?(1.0)</tt> は真を返し、
262
+ <tt>#cover?(9.0)</tt> は偽を返します。
263
+
264
+ このクラスにより、1次元レンジへの論理演算が可能かつ容易になりました。
265
+ これが有用なものであることを願ってここにリリースします。
266
+
267
+
268
+ == インストール
269
+
270
+ まず、{RangeExtd} クラスのライブラリ(純粋に rubyで書かれたファイル 2個
271
+ です)が必要です。gem を使ってインストールできます。
272
+ gem install range_extd
273
+ もしくは以下から入手して下さい。
274
+ https://rubygems.org/gems/range_extd
275
+
276
+ 次いで、このライブラリをインストールします。
277
+ gem install rangeary
278
+
279
+ ファイルが一つ、
280
+ rangeary/rangeary.rb
281
+ <tt>$LOAD_PATH</tt>上のどこかにインストールされるはずです。
282
+ あるいは以下から入手可能です。
283
+ http://rubygems.org/gems/rangeary
284
+
285
+ 後は、Ruby のコード(又は irb)から
286
+ require 'rangeary/rangeary'
287
+ とするだけです。もしくは、特に手でインストールした場合は、
288
+ require 'rangeary'
289
+ とする必要があるかも知れません。他のファイル({RangeExtd} 用の
290
+ <tt>range_extd/range_extd.rb</tt>)は、自動的に読込まれます。
291
+
292
+ {Rangeary} 自体は Ruby 1.8でも動作するかも知れません。しかし、
293
+ {RangeExtd} が Ruby 2.0 (ひょっとしたら 1.9.3)以上でしか動かないため、
294
+ 実質的には {Rangeary} は Ruby 1.8 以前のバージョンでは動作しません。
295
+
296
+ お楽しみあれ!
297
+
298
+
299
+ == 単純な使用例
300
+
301
+ === Rangeary インスタンスを作成する方法
302
+
303
+ 以下に幾つかの基本的な使用例を列挙します。
304
+
305
+ r1 = RangeExtd(?a...?d, true) # => a<...d
306
+ ra = Rangeary(?g..?h, r1) # => [a<...d, g..h]
307
+ Rangeary(RangeExtd::NONE) # => [RangeExtd::NONE]
308
+ Rangeary(RangeExtd::NONE, 1..5, 3...7) # => [1...7]
309
+ Rangeary(true..true) # => ArgumentError
310
+
311
+ 基本的に、<tt>Rangeary()</tt> または <tt>Rangeary.new()</tt> は、任意
312
+ の数の {Range}、{RangeExtd}、{Rangeary} あるいはその組合わせを引数とし
313
+ て取ります。ただし、{Range}クラスのオブジェクトで {Range#valid?} が偽
314
+ を返すものは、例外が発生します。
315
+
316
+ さらなる解説及び例は、{Rangeary.new}を参照して下さい。
317
+
318
+
319
+ === 実践例
320
+
321
+ ra.to_a # => ["a"<..."d", "g".."h"]
322
+ ra.cover?("a") # => false
323
+ ra.cover?("b") # => true
324
+ ra.end # => "h"
325
+ ra.each do |i|
326
+ print i.begin
327
+ end # => self ( "ag" => STDOUT )
328
+ ra.each_element do |i|
329
+ print i
330
+ end # => self ( "bcgh" => STDOUT )
331
+
332
+ rb = Rangeary(6...9, 2..4) # => [2..4, 6...9]
333
+ rb + Rangeary(3..7) # => [2...9]
334
+ rb - Rangeary(3..7) # => [2...3, RangeExtd(7,'<...',9)]
335
+ rb * Rangeary(4..5, 8..10) # => [4..4, 8...9]
336
+ rb.negation # => [-Float::INFINITY...2, RangeExtd(4,'<...',6), 9..Float::INFINITY]
337
+
338
+ 組込Arrayクラスに含まれるほとんどのメソッドが、たとえば{Array#push}のように
339
+ {Rangeary} がイミュータブルであることに抵触しない限りにおいて、使用可能です。
340
+
341
+
342
+ == 詳説
343
+
344
+ ファイル <tt>rangeary.rb</tt> が読まれた段階で、RangeExtd ライブラリで
345
+ 定義される二つのクラス(<tt>RangeExtd</tt> と
346
+ <tt>RangeExtd::Infinity</tt>)に加えて、クラス一つが定義されます。
347
+
348
+ * Rangeary
349
+
350
+
351
+ === Rangeary クラス
352
+
353
+ {Rangeary} オブジェクトは、Range や RangeExtd と同様、イミュータブルで
354
+ す。だから、一度インスタンスが生成されると、変化しません。
355
+
356
+ インスタンスの生成方法は上述の通りです(「使用例」の章)。レンジとして"valid"と見
357
+ なされないインスタンスを生成しようとすると、すなわち {Range#valid?} が
358
+ 偽を返すレンジを使おうとすると、例外(<tt>ArgumentError</tt>)が発生し、
359
+ 失敗します。
360
+
361
+ なお、ユーザーは、{Rangeary} インスタンス生成の時、レンジ要素に対応し
362
+ た正負の無限大オブジェクトを付加することができます。デフォルトでは、
363
+ {Float::INFINITY} または {RangeExtd::Infinity::POSITIVE} の類に
364
+ なります。詳しくは {Rangeary.new} を参照下さい。
365
+
366
+ 生成時に複数のレンジが引数として与えられた時、ソートされて保持されます。
367
+ その時、要素のどこかに重複する部分があった時は、論理和として扱われます
368
+ (つまり、単純に足し合わされます)。これはつまり、{Rangeary} が内部的に
369
+ 保持するオブジェクトは生成時に与えられたものとは異なる、すなわち
370
+ {#object_id} が異なるかも知れないことを意味します。特に、組込Rangeが引
371
+ 数として与えられた時は、常に {RangeExtd} オブジェクトに内部で変換されます。
372
+
373
+ もし生成時に与えられたレンジのどれかが空、すなわち {Range#empty?} が真
374
+ を返す場合、それらは無視されます。ただし、引数の全てのレンジが空であっ
375
+ た場合は、「最小」のものが残されます。
376
+
377
+ もし演算の結果として空の{Rangeary}が返される場合、その唯一の要素は
378
+ {RangeExtd::NONE}となり、したがって
379
+ {Rangeary#empty_element?} が真を返します。
380
+
381
+ そのため、どの Rangeary オブジェクトも、{Rangeary#to_a}.size は常に正
382
+ の値を返し、零を返すことはありません。あるいは、Array から継承した
383
+ {Rangeary#empty?} は常に偽を返します(オブジェクトがレンジとして空かど
384
+ うかをチェックするには、{Rangeary#empty_element?} を使って下さい)。
385
+ Rangeary(RangeExtd::NONE).empty? # => false
386
+ Rangeary(RangeExtd::NONE).empty_element? # => true
387
+
388
+ 前述のように、ごく一部を除いた全ての Arrayクラスのメソッドがこの
389
+ {Rangeary} クラスに継承されていて、それらは各{RangeExtd}要素に対して
390
+ 動作します。ただし、4個のメソッドの挙動が異なります。
391
+ {Rangeary#+} と {Rangeary#*} とは、それぞれ {Rangeary#disjunction} と
392
+ {Rangeary#conjunction} とへのエイリアスとなっています。{Rangeary#===}
393
+ は、全ての{RangeExtd}要素に対して{Range#===}を実行し、それらの一つでも
394
+ 真を返せば真を返します。したがって、{Rangeary#===}(RangeExtd(**))は常
395
+ に偽を返します。{Rangeary#flatten} は、全ての{RangeExtd}要素に対して
396
+ {Rangeary#to_a} を実行して、その結果を結合した配列を返します。
397
+ また、[#length] と [#reverse] とは未定義化されています。
398
+
399
+ {Rangeary#==} と {Rangeary#eql?} は、Arrayと同様に動作します。だから
400
+ [2..4, 6..8] == Rangeary(2..4, 6..8) # => true
401
+ も成り立ちます。しかし注意すべきは以下です。
402
+ [2..4, 6..8] == Rangeary(6..8, 2..4) # => true
403
+ [6..8, 2..4] == Rangeary(6..8, 2..4) # => false
404
+ 端的には、標準Arrayとの直接比較は推奨しません。代わりに、
405
+ {Rangeary} オブジェクトと比較して下さい。
406
+
407
+ レンジ要素に対してではなく、レンジを構成する要素に対して動作する他の
408
+ 全てのメソッドは、組込Arrayクラスに同名のメソッドが存在する場合、接尾辞
409
+ <tt>_element</tt> がつきます。たとえば、{Rangeary#size} は、保持する
410
+ {RangeExtd} オブジェクトの数を返し、一方、{Rangeary#size_element}は、
411
+ 保持するすべての {RangeExtd}オブジェクトに対して {Range#size} を行った
412
+ その総和を返します。
413
+ Rangeary(1..3, 5..8).size # => 2
414
+ Rangeary(1..3, 5..8).size_element # => 7
415
+
416
+
417
+ == 既知のバグ
418
+
419
+ * 無し。
420
+
421
+ このライブラリは Ruby 2.0 以上を必要とします(Ruby 1.9.3 では動くかも
422
+ 知れませんが、私は試したことがありません)。
423
+
424
+ パッケージに含まれている通り、網羅的なテストが実行されています。
425
+
426
+
427
+ == 未処理事項
428
+
429
+ 特になし。
430
+
431
+
432
+ == 終わりに
433
+
434
+ このライブラリは、イアン・スチュワート氏が開発した、XMM-Newton望遠鏡用の
435
+ SAS解析ソフトウェア・パッケージに含まれる(数値)複数レンジの
436
+ Fortran90ライブラリにアイデアを得たものです。彼の仕事に感謝します。
437
+
438
+ しかし、Rubyへの実装は、一筋縄ではいきませんでした。一つには組込Range
439
+ クラスでは始点を除外することができないこと、また一つには Rubyでは数値
440
+ を除いて一般オブジェクトに対しての無限大が定義されていないからです。
441
+ 小生の開発した {RangeExtd} によって初めてこのライブラリが可能となりま
442
+ した。これにより、今、比較可能な任意のオブジェクトについて、1次元上の
443
+ レンジの完全性が実現できたことを嬉しく思います。
444
+
445
+ お楽しみ下さい。
446
+
447
+
448
+ == その他
449
+
450
+ == 著作権他情報
451
+
452
+ 著者:: Masa Sakano < imagine a_t sakano dot co dot uk >
453
+ 利用許諾条項:: MIT.
454
+ 保証:: 一切無し。
455
+ バージョン:: Semantic Versioning (2.0.0) http://semver.org/
456
+
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
9
+