range_extd 1.0 → 2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,84 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ $stdout.sync=true
4
+ $stderr.sync=true
5
+ # print '$LOAD_PATH=';p $LOAD_PATH
6
+ arlibbase = %w(range_extd range_extd/nowhere.rb) # range_extd/nowhere.rb is actually loaded from range_extd. But by writing here, the absolute path will be displayed.
7
+
8
+ arlibrelbase = arlibbase.map{|i| "../lib/"+i}
9
+
10
+ arlibrelbase.each do |elibbase|
11
+ require_relative elibbase
12
+ end
13
+
14
+ print "NOTE: Running: "; p File.basename(__FILE__)
15
+ print "NOTE: Library relative paths: "; p arlibrelbase
16
+ arlibbase4full = arlibbase.map{|i| i.sub(%r@^(../)+@, "")}+%w(range_extd)
17
+ puts "NOTE: Library full paths for #{arlibbase4full.inspect}: "
18
+ arlibbase4full.each do |elibbase|
19
+ ar = $LOADED_FEATURES.grep(/(^|\/)#{Regexp.quote(File.basename(elibbase))}(\.rb)?$/).uniq
20
+ print elibbase+": " if ar.empty?; p ar
21
+ end
22
+
23
+
24
+ #################################################
25
+ # Unit Test
26
+ #################################################
27
+
28
+ require 'rational' if !defined?(Rational) # For Ruby 1.8
29
+
30
+ gem "minitest"
31
+ require 'minitest/autorun'
32
+
33
+ class TestUnitNowhere < MiniTest::Test
34
+ T = true
35
+ F = false
36
+
37
+ def setup
38
+ end
39
+
40
+ def teardown
41
+ end
42
+
43
+ def test_nowhere
44
+ nowhere = RangeExtd::Nowhere::NOWHERE
45
+ assert(RangeExtd::Nowhere.instance.eql?(nowhere), "Const.id=#{RangeExtd::Nowhere::NOWHERE.__id__} nowhere.id=#{nowhere.__id__}; nil=#{RangeExtd::Nowhere::NOWHERE.nil?.inspect}=#{nowhere.nil?.inspect}; nowhere?=#{RangeExtd::Nowhere::NOWHERE.nowhere?.inspect}=#{nowhere.nowhere?.inspect}; hash=#{RangeExtd::Nowhere::NOWHERE.hash}=#{nowhere.hash}")
46
+ refute(nowhere.eql?(nil))
47
+ assert( nowhere == nil )
48
+ assert_equal 0, ( nowhere <=> nil )
49
+
50
+ assert nowhere.nowhere?
51
+ assert_equal RangeExtd::Nowhere, nowhere.class_raw
52
+ assert_equal NilClass, nowhere.class
53
+
54
+ assert( nowhere ) # Unfortunately, there is no way in Ruby to make the object behave like false/nil in the conditional statement: see <https://stackoverflow.com/a/14449380/3577922>
55
+ assert( nowhere.nil? )
56
+ refute RangeExtd.valid?(RangeExtd::Nowhere::NOWHERE..nil), 'NOWHERE cannot reside in other than RangeExtd::NONE'
57
+ end # def test_nowhere
58
+
59
+ # 'nil_class.rb' is always required, and so these should hold.
60
+ def test_nil_class
61
+ nowhere = RangeExtd::Nowhere::NOWHERE
62
+ refute(nil.eql?(nowhere))
63
+ assert( nil == nowhere )
64
+ assert_equal 0, ( nil <=> nowhere )
65
+
66
+ refute nil.nowhere?
67
+ assert_equal NilClass, nil.class_raw
68
+ assert_equal NilClass, nil.class
69
+ end # def test_nil_class
70
+
71
+ ## when 'nil_class.rb' is not required, these are the cases.
72
+ #def test_nil_class
73
+ # nowhere = RangeExtd::Nowhere::NOWHERE
74
+ # refute(nil.eql?(nowhere))
75
+ #
76
+ # refute( nil == nowhere )
77
+ # assert_nil( nil <=> nowhere )
78
+ #
79
+ # refute nil.respond_to?(:nowhere?)
80
+ # refute nil.respond_to?(:class_raw)
81
+ # assert_equal NilClass, nil.class
82
+ #end # def test_nil_class
83
+ end # class TestUnitNowhere < MiniTest::Test
84
+
metadata CHANGED
@@ -1,22 +1,24 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: range_extd
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.0'
4
+ version: '2.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masa Sakano
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-30 00:00:00.000000000 Z
11
+ date: 2022-09-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Package for a subclass of Range, RangeExtd and RangeExtd::Infinity. The
14
- former defines a range that enables an exclusion of the begin boundary, in addition
15
- to the end boundary as in the built-in Range, and accepts open-ended ranges to infinity
16
- for either (or both) positive/negative direction. The latter has the two constant
17
- objects, POSITIVE and NEGATIVE, and they are a generalised Infinity of Float::INFINITY
18
- to any Comparable objects.
19
- email:
13
+ description: Package for a subclass of Range, RangeExtd, containing RangeExtd::Infinity
14
+ and RangeExtd::Nowhere. RangeExtd defines ranges that enable an exclusion of the
15
+ begin boundary, in addition to the end boundary as in the built-in Range, and accepts
16
+ open-ended ranges to infinity for either (or both) positive/negative direction. The
17
+ open-ended boundaries are represented by two constant objects, POSITIVE and NEGATIVE
18
+ of RangeExtd::Infinity, and they are a generalised Infinity of Float::INFINITY to
19
+ any Comparable objects, which are in practice similar to built-in beginless/endless
20
+ Ranges.
21
+ email:
20
22
  executables: []
21
23
  extensions: []
22
24
  extra_rdoc_files:
@@ -30,15 +32,24 @@ files:
30
32
  - README.en.rdoc
31
33
  - README.ja.rdoc
32
34
  - Rakefile
33
- - lib/range_extd/infinity/infinity.rb
34
- - lib/range_extd/range_extd.rb
35
+ - lib/range_extd.rb
36
+ - lib/range_extd/infinity.rb
37
+ - lib/range_extd/load_all.rb
38
+ - lib/range_extd/nil_class.rb
39
+ - lib/range_extd/nowhere.rb
40
+ - lib/range_extd/numeric.rb
41
+ - lib/range_extd/object.rb
42
+ - lib/range_extd/range.rb
43
+ - range_extd.gemspec
44
+ - test/all_required_test.rb
35
45
  - test/test_range_extd.rb
46
+ - test/test_range_extd_nowhere.rb
36
47
  homepage: https://www.wisebabel.com
37
48
  licenses:
38
49
  - MIT
39
50
  metadata:
40
51
  yard.run: yri
41
- post_install_message:
52
+ post_install_message:
42
53
  rdoc_options:
43
54
  - "--charset=UTF-8"
44
55
  require_paths:
@@ -47,16 +58,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
47
58
  requirements:
48
59
  - - ">="
49
60
  - !ruby/object:Gem::Version
50
- version: '2.0'
61
+ version: '2.7'
51
62
  required_rubygems_version: !ruby/object:Gem::Requirement
52
63
  requirements:
53
64
  - - ">="
54
65
  - !ruby/object:Gem::Version
55
66
  version: '0'
56
67
  requirements: []
57
- rubygems_version: 3.0.3
58
- signing_key:
68
+ rubygems_version: 3.3.7
69
+ signing_key:
59
70
  specification_version: 4
60
71
  summary: RangeExtd - Extended Range class with exclude_begin and open-ends
61
72
  test_files:
73
+ - test/all_required_test.rb
62
74
  - test/test_range_extd.rb
75
+ - test/test_range_extd_nowhere.rb
@@ -1,392 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- if ! defined?(Rational)
4
- require 'rational' # For Ruby 1.8
5
- end
6
-
7
- # This file is required from range_open/range_open.rb
8
- class RangeExtd < Range
9
- #
10
- # =Class RangeExtd::Infinity
11
- #
12
- # Authors:: Masa Sakano
13
- # License:: MIT
14
- #
15
- # ==Summary
16
- #
17
- # Class to hold just two constants:
18
- # * RangeExtd::Infinity::NEGATIVE
19
- # * RangeExtd::Infinity::POSITIVE
20
- # and two more:
21
- # * FLOAT_INFINITY (OBSOLETE; workaround for Ruby 1.8 to represent Float::INFINITY)
22
- # * CLASSES_ACCEPTABLE (see below)
23
- #
24
- # There is no other object in this class (you can not create a new one).
25
- #
26
- # This class includes Comparable module.
27
- #
28
- # ==Description
29
- #
30
- # Both the two constant are an abstract value which is always smaller/larger,
31
- # respectively, than any other Comparable objects (1 or -1 by i{#<=>}(obj))
32
- # except for infinities with the same polarity, that is, positive or negative,
33
- # in which case 0 is returned.
34
- # See the document of the method {#==} for the definition of "infinity".
35
- # Also, {#succ} is defined, which just returns self.
36
- #
37
- # There is a note of caution.
38
- # The method {#<=>} is defined in this class as mentioned above.
39
- # However any operator is, by Ruby's definition, not commutative,
40
- # unless both the classes define so.
41
- #
42
- # There are only three built-in classes that are Comparable: String, Time and Numeric
43
- # (except for Complex).
44
- # Note Date and DateTime objects are so, too, however practically
45
- # they need "require", hence are (and must be) treated, the same as any other class.
46
- # For String and Time class objects, the [#<=>] operator work as expected
47
- # in the commutative way.
48
- # ?z <=> RangeExtd::Infinity::POSITIVE # => nil
49
- # RangeExtd::Infinity::POSITIVE <=> ?z # => 1.
50
- #
51
- # For Numeric, it does not.
52
- # 50 <=> RangeExtd::Infinity::POSITIVE # => nil
53
- # RangeExtd::Infinity::POSITIVE <=> 50 # => 1.
54
- #
55
- # For that reason, for example,
56
- # ( 50 .. RangeExtd::Infinity::POSITIVE)
57
- # raises an exception, because the Numeric instance 50 does not
58
- # know how to compare itself with a RangeExtd::Infinity instance,
59
- # and Range class does not allow such a case.
60
- #
61
- # For Numeric, this is deliberately so.
62
- # Please use {Float::INFINITY} instead in principle;
63
- # it will be a lot faster in run-time, though it is
64
- # perfectly possible for you to implement the feature
65
- # in Numeric sub-classes, if need be.
66
- #
67
- # Any other Comparable classes are defined by users by definition,
68
- # whether you or authors of libraries.
69
- # The comparison with {RangeExtd::Infinity} instances are
70
- # implemented in {Object#<=>} in this library. Hence, as long as
71
- # the method [#<=>] in the classes is written sensibly, that is, if it
72
- # respects the method of the super-class when it does not know
73
- # how to deal with an unknown object, there is no need for
74
- # modification. Any object in your class (say, YourComparable)
75
- # is immediately comparable with the {RangeExtd::Infinity} instances,
76
- # YourComparable.new <=> RangeExtd::Infinity::POSITIVE # => -1
77
- # RangeExtd::Infinity::POSITIVE <=> YourComparable.new # => 1
78
- # except for the infinity inscances in YourComparable (see {#==}).
79
- #
80
- # See the document in {Object#<=>} in this code/package for detail.
81
- #
82
- # However, some existing Comparable classes, perhaps written by some
83
- # one else may not be so polite, and has disabled comparison
84
- # with any object but those intended. Unlucky you!
85
- # For example, the classes like Date and DateTime are one of them.
86
- #
87
- # For that sort of circumstances,
88
- # the class method {RangeExtd::Infinity.overwrite_compare} provides
89
- # a convenient way to overcome this problem to make
90
- # the operator [#<=>] commutative for a given Comparable class.
91
- #
92
- # Note {RangeExtd::Infinity.overwrite_compare} does nothing for the classes
93
- # registered in the Class constant Array {RangeExtd::Infinity::CLASSES_ACCEPTABLE}.
94
- # So, if you want to avoid such modification of the method [#<=>], perhaps
95
- # by some other end users, you can register the class in that array.
96
- #
97
- # Only the methods defined in this class are
98
- # {#===}, {#==}, {#<=>}, {#succ}, {#to_s}, {#inspect},
99
- # {#infinity?}, {#positive?} and {#negative?}.
100
- #
101
- # Note that the unary operand [#-@] is not defined.
102
- #
103
- class Infinity
104
-
105
- include Comparable
106
-
107
- # Obsolete Constant FLOAT_INFINITY (for the sake of Ruby 1.8 or earlier).
108
- # Please do not use it - it will be removed some time in the future.
109
- # n.b., Module#private_constant is introduced in Ruby 1.9.3.
110
- begin
111
- FLOAT_INFINITY = Float::INFINITY
112
- rescue # Ruby 1.8 or earlier.
113
- FLOAT_INFINITY = 1/0.0
114
- end
115
-
116
- # Class that accept to be compared with Infinity instances.
117
- CLASSES_ACCEPTABLE = [self, Float, Integer, Rational, Numeric, String] # Fixnum, Bignum deprecated now.
118
- # CLASSES_ACCEPTABLE = [self, Float, Fixnum, Bignum, Rational, Numeric, String] # , BigFloat
119
- CLASSES_ACCEPTABLE.push BigFloat if defined? BigFloat
120
-
121
- def infinity?
122
- true
123
- end
124
-
125
- def positive?
126
- @positive
127
- end
128
-
129
- def negative?
130
- !@positive
131
- end
132
-
133
- alias_method :cmp_before_rangeextd_infinity?, :== if ! self.method_defined?(:cmp_before_rangeextd_infinity?) # No overwriting.
134
-
135
- # Always -1 or 1 except for itself and the corresponding infinities (== 0). See {#==}.
136
- # Or, nil (as defined by Object), if the argument is not Comparable, such as, nil and IO.
137
- # @return [Integer, nil]
138
- def <=>(c)
139
- if c.nil?
140
- super
141
- elsif !defined?(c.<=) # Not Comparable?
142
- super
143
- elsif @positive
144
- if self == c
145
- 0
146
- else
147
- 1
148
- end
149
- else # aka negative
150
- if self == c
151
- 0
152
- else
153
- -1
154
- end
155
- end
156
- end
157
-
158
- # Always false except for itself and the corresponding {Float::INFINITY}
159
- # and those that have methods of {#infinity?} and {#positive?}
160
- # with the corresponding true/false values, in which case this returns true.
161
- def ==(c)
162
- if (Infinity === c)
163
- (@positive ^! c.positive?) # It should be OK to compare object_id?
164
- elsif c == FLOAT_INFINITY && @positive
165
- true
166
- elsif c == -FLOAT_INFINITY && !@positive
167
- true
168
- elsif defined?(c.infinity?) && defined?(c.positive?)
169
- (c.infinity? && (@positive ^! c.positive?))
170
- else
171
- false
172
- end
173
- end
174
-
175
- # Equivalent to {#==}
176
- def ===(c)
177
- self == c
178
- end
179
-
180
- # @return [Infinity] self
181
- def succ
182
- self
183
- end
184
-
185
- # @return [String]
186
- def inspect
187
- if @positive
188
- "INFINITY"
189
- else
190
- "-INFINITY"
191
- end
192
- end
193
-
194
- alias_method :to_s, :inspect
195
-
196
-
197
- # Overwrite [#<=>] method of the given class, if necessary,
198
- # to make its instances be comparable with RangeExtd::Infinity objects (constants).
199
- # For example,
200
- # RangeExtd::Infinity::NEGATIVE.<=>(any_comparable)
201
- # always gives back -1 (except for same infinities). However the other way around,
202
- # SomeClass.new.<=>(RangeExtd::Infinity::NEGATIVE)
203
- # usually returns nil, which is not handy.
204
- # Therefore, this function (Class method) provides a convenient
205
- # way to overcome it, that is, if the given class
206
- # (or the class of the given object) is Comparable,
207
- # its [#<=>] method is modified (and true is returned),
208
- # unless it has been already done so, or some classes as listed below,
209
- # such as Numeric and String, in which case nil is returned.
210
- # If it is not Comparable, false is returned.
211
- # The judgement whether it is Comparable or not is based
212
- # whether the class has an instance method ThatClass#<=
213
- #
214
- # In processing, this method first looks up at an Array
215
- # {RangeExtd::Infinity::CLASSES_ACCEPTABLE},
216
- # and if the given class is registered in it,
217
- # it does nothing. If not, and if all the othe conditions
218
- # are met, it overwrites its <=> method and register
219
- # the class in the array.
220
- #
221
- # @param obj [Object] Either Class or its object.
222
- # @return [Boolean, nil] (see the description).
223
- def self.overwrite_compare(obj)
224
- if defined? obj.instance_methods
225
- klass = obj
226
- else
227
- klass = obj.class
228
-
229
- begin
230
- _ = 1.0 + obj # Use "rescue ArgumentError" if using "1.0<obj"
231
- return nil # No change for Numeric
232
- rescue TypeError
233
- end
234
- end # if defined? obj.instance_methods
235
-
236
- # [Numeric, Fixnum, Bignum, Float, Rational, String, Complex].each do |i| # , BigFloat
237
- (self::CLASSES_ACCEPTABLE+[self]).each do |i| # , BigFloat
238
- # The class itself (RangeExtd::Infinity) must be rejected!
239
- # Otherwise the rewrites itself, and may cause an infinite loop.
240
- # In fact it is pre-defined in RangeExtd::Infinity, so the above addition is a duplication - just to make sure.
241
- return nil if i == klass # No change for Numeric etc
242
- # Built-in String, Numeric etc try to flip over "<=>" if it doesn't know the object!
243
- end
244
- self::CLASSES_ACCEPTABLE.push(klass) # The class is registered, so it would not come here again for the class.
245
-
246
- a = klass.instance_methods
247
- if !a.include?( :<= ) # NOT Comparable
248
- return false
249
- elsif a.include?(:compare_before_infinity)
250
- return nil
251
- else
252
- # Overwrite the definition of "<=>" so that it is fliped over for Infinity.
253
-
254
- code = <<__EOF__
255
- alias_method :compare_before_infinity, :<=> if ! self.method_defined?(:compare_before_infinity)
256
- def <=>(c)
257
- if defined?(self.<=) && RangeExtd::Infinity === c
258
- if defined?(self.infinity?) && defined?(self.positive?)
259
- if (self.positive? ^! c.positive?)
260
- 0
261
- elsif self.positive?
262
- 1
263
- else
264
- -1
265
- end
266
- else
267
- if c.positive?
268
- -1
269
- else
270
- 1
271
- end
272
- end
273
- else
274
- compare_before_infinity(c)
275
- end
276
- end
277
- __EOF__
278
- #<<__EOF__ # for Emacs hilit.
279
-
280
- klass.class_eval(code)
281
-
282
- true
283
- end
284
- end # def self.overwrite_compare(obj)
285
-
286
-
287
- private
288
-
289
- def initialize(t)
290
- @positive = (t && true)
291
- end
292
-
293
- NEGATIVE = new(false)
294
- POSITIVE = new(true)
295
-
296
- #NEGATIVE.freeze
297
- #POSITIVE.freeze
298
-
299
- end # class Infinity
300
-
301
-
302
- class Infinity
303
- # Disable new() so no other object will be created.
304
- private_class_method :new
305
-
306
- warn_level = $VERBOSE
307
- begin
308
- $VERBOSE = nil # Suppress the warning in the following line.
309
- remove_method :initialize
310
- ensure
311
- $VERBOSE = warn_level
312
- end
313
- #undef_method :initialize
314
-
315
- end # class Infinity
316
-
317
- end # class RangeExtd < Range
318
-
319
-
320
- #
321
- # = class Object
322
- #
323
- # Overwrite {Object#<=>}() so all its sub-classes can be
324
- # aware of {RangeExtd::Infinity} objects (the two constants).
325
- #
326
- class Object
327
- alias_method :compare_obj_before_infinity, :<=> if ! self.method_defined?(:compare_obj_before_infinity) # No overwriting.
328
-
329
- # Overwrite {Object#<=>}(). Then, all its sub-classes can be
330
- # aware of RangeExtd::Infinity objects (the two constants).
331
- #
332
- # In this definition of {#<=>}, if self is Comparable
333
- # (by judging whether it has the method [#<=]),
334
- # it always returns, unless infinity? and positive? are set
335
- # accordingly, either -1 or 1, depending which of
336
- # RangeExtd::Infinity::(NEGATIVE|POSITIVE)
337
- # is compared. If self is not Comparable, the original [#<=>]
338
- # is called, which should return nil (unless both the object_id
339
- # agree, eg., nil and nil, in which case 0 is returned).
340
- #
341
- # If you define your own class, which is Comparable, you should
342
- # define the method "<=>" as follows, as in the standard practice
343
- # when you redefine a method that exists in a superclass;
344
- #
345
- # @example A method definition of user-defined Comparable class
346
- # class MyComparableClass
347
- # include Comparable
348
- # # alias :cmp_orig :<=> if !self.method_defined?(:cmp_orig) # if you want
349
- # def <=>(c)
350
- # if c._is_what_i_expect?
351
- # # Write your definition.
352
- # else # When self does not know what to do with c.
353
- # super # to call Object#<=>
354
- # end
355
- # end
356
- # end
357
- #
358
- def <=>(c)
359
- if defined?(self.<=) && RangeExtd::Infinity === c
360
- # if defined?(self.<=) && defined?(c.infinity?) && defined?(c.positive?)
361
- # NOTE: Duck-typing is inappropriate here.
362
- # Only the objects that self wants to deal with here are
363
- # the instances of RangeExtd::Infinity, and not other
364
- # "infinity" object, such as, Float::INFINITY. So,
365
- # (self <=> RangeExtd::Infinity::POSITIVE) # => -1
366
- # (self <=> Float::INFINITY) # => nil
367
- # in default.
368
- if defined?(self.infinity?) && defined?(self.positive?)
369
- if (self.positive? ^! c.positive?)
370
- 0
371
- elsif self.positive?
372
- 1
373
- else
374
- -1
375
- end
376
- else
377
- # (c <=> self) * (-1)
378
- if c.positive?
379
- -1
380
- else
381
- 1
382
- end
383
- end
384
- elsif object_id == c.object_id # (nil <=> nil) # => 0
385
- 0
386
- else
387
- nil
388
- end # if defined?(self.<=) && RangeExtd::Infinity === c
389
- end # def <=>(c)
390
- end # class Object
391
-
392
-