range_extd 1.1.1 → 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.
- checksums.yaml +4 -4
- data/ChangeLog +16 -0
- data/Makefile +7 -3
- data/News +4 -0
- data/README.en.rdoc +1146 -270
- data/README.ja.rdoc +1146 -270
- data/Rakefile +11 -5
- data/lib/range_extd/infinity.rb +426 -0
- data/lib/range_extd/load_all.rb +19 -0
- data/lib/range_extd/nil_class.rb +41 -0
- data/lib/range_extd/nowhere.rb +135 -0
- data/lib/range_extd/numeric.rb +160 -0
- data/lib/range_extd/object.rb +53 -0
- data/lib/range_extd/range.rb +401 -0
- data/lib/{range_extd/range_extd.rb → range_extd.rb} +387 -633
- data/range_extd.gemspec +50 -0
- data/test/all_required_test.rb +173 -0
- data/test/test_range_extd.rb +482 -148
- data/test/test_range_extd_nowhere.rb +84 -0
- metadata +29 -16
- data/lib/range_extd/infinity/infinity.rb +0 -600
    
        data/README.ja.rdoc
    CHANGED
    
    | @@ -1,135 +1,470 @@ | |
| 1 1 |  | 
| 2 2 | 
             
            = RangeExtd - Extended Range class with exclude_begin and open-ends
         | 
| 3 3 |  | 
| 4 | 
            +
            == Introduction
         | 
| 5 | 
            +
             | 
| 4 6 | 
             
            This package contains RangeExtd class, the Extended Range class that features:
         | 
| 5 7 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 8 | 
            +
            1. includes exclude_begin? (to exclude the "begin" boundary),
         | 
| 9 | 
            +
            2. allows open-ended range to the infinity (*not* undefined ends, i.e., +nil+),
         | 
| 10 | 
            +
            3. defines NONE and ALL constants,
         | 
| 11 | 
            +
            4. the first self-consistent logical range structure in Ruby,
         | 
| 12 | 
            +
            5. complete compatibility within the built-in Range.
         | 
| 11 13 |  | 
| 12 14 | 
             
            With the introduction of the excluded status of begin, in addition
         | 
| 13 15 | 
             
            to the end as in built-in Range, and open-ended feature,
         | 
| 14 16 | 
             
            the logical completeness of the 1-dimensional range is realised.
         | 
| 15 17 |  | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
            { | 
| 19 | 
            -
            to  | 
| 18 | 
            +
            A major pro of this library is application to logical operations of multiple ranges,
         | 
| 19 | 
            +
            most typically Float and/or Rational.
         | 
| 20 | 
            +
            {Rangeary}[https://rubygems.org/gems/rangeary] uses this library to
         | 
| 21 | 
            +
            fullest to realise the concept of logical range operations. In doing
         | 
| 22 | 
            +
            them, the concept of potentially open-ended Ranges with potential
         | 
| 23 | 
            +
            exclusions of begin and end is essential.  For example, the negation
         | 
| 24 | 
            +
            of Range +(?a..?d)+ is a pair of Ranges +(-"Infinity-Character"...3)+ and
         | 
| 25 | 
            +
            +(?d(exclusive).."Infinity-Character")+ and its negation is back to
         | 
| 26 | 
            +
            the original +(?a..?d)+.  Such operations are possible only with this
         | 
| 27 | 
            +
            class +RangeExtd+ 
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            Rangeary: {https://rubygems.org/gems/rangeary}
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            The built-in Range class is very useful, and has given Ruby users
         | 
| 32 | 
            +
            a power to make easy coding.  Yet, the lack of definition of
         | 
| 33 | 
            +
            exclusive begin boundary is a nuisance in some cases.
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            Having said that, there is a definite and understandable reason;
         | 
| 36 | 
            +
            Range in Ruby is not limited at all to Numeric (or strictly speaking,
         | 
| 37 | 
            +
            Real numbers or their representatives).  Range with any object that has a method
         | 
| 38 | 
            +
            of <tt>succ()</tt> is found to be useful, whereas there is no reverse method for
         | 
| 39 | 
            +
            <tt>succ()</tt> in general.
         | 
| 40 | 
            +
            In that sense Range is inherently not symmetric.  In addition,
         | 
| 41 | 
            +
            some regular Range objects are continuous (like Float), while others are discrete
         | 
| 42 | 
            +
            (like Integer or String).  That may add some confusion to the strict definition.
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            To add the feature of the exclusive-begin boundary is in that sense
         | 
| 45 | 
            +
            not 100 per cent trivial.  The definition I adopt for the behaviour of
         | 
| 46 | 
            +
            {RangeExtd} is probably not the only solution.  Personally, I am content
         | 
| 47 | 
            +
            with it, and I think it achieves the good logical completeness within the frame.
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            I hope you find this package to be useful.
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            === Validity of a Range
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            Ruby built-in Range is very permissive for the elements (members).  For example,
         | 
| 54 | 
            +
            +(true...true)+ is a valid Range whatever it means, although its use
         | 
| 55 | 
            +
            is highly limited because you cannot iterate over it, that is,
         | 
| 56 | 
            +
            methods like +each+ with an associated iterator and +to_a+ would raise an Exception (+TypeError+).
         | 
| 20 57 |  | 
| 21 | 
            -
             | 
| 58 | 
            +
            With this library, the validity of a Range is strictly defined.
         | 
| 59 | 
            +
            This library adds a few methods, most notably
         | 
| 60 | 
            +
            {Range#valid?}, {Range#null?} and {Range#empty?}
         | 
| 61 | 
            +
            to Range class, which would take immediate effect in any of its sub-classes.
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            As an example, <tt>(3...3).valid?</tt>  returns false, because the element 3 is
         | 
| 22 64 | 
             
            inclusive for the begin boundary, yet exclusive for the end boundary,
         | 
| 23 65 | 
             
            which are contradictory to each other.  With this RangeExtd class,
         | 
| 24 | 
            -
             | 
| 66 | 
            +
            the following two are regarded as valid ranges,
         | 
| 25 67 |  | 
| 26 | 
            -
            * RangeExtd.new(3, 3, true,  true)   # => an empty range
         | 
| 27 | 
            -
            * RangeExtd.new(3, 3, false, false)  # => a single-point range (3..3)
         | 
| 68 | 
            +
              * RangeExtd.new(3, 3, true,  true)   # => an empty range
         | 
| 69 | 
            +
              * RangeExtd.new(3, 3, false, false)  # => a single-point range (3..3)
         | 
| 28 70 |  | 
| 29 | 
            -
            However, as long as  | 
| 71 | 
            +
            However, as long as the use is closed within the built-in Range, nothing has changed,
         | 
| 30 72 | 
             
            so it is completely compatible with the standard Ruby.
         | 
| 31 73 |  | 
| 32 | 
            -
             | 
| 74 | 
            +
            === Open-ended ranges to infinity
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            Ruby 2.6 and 2.7 have introduced endless and beginless Ranges, respectively.
         | 
| 77 | 
            +
            The difference between borderless Ranges and open-ended ranges to infinity
         | 
| 78 | 
            +
            introduced in this library is subtle and perhaps more
         | 
| 79 | 
            +
            conceptual or philosophical than meaningful in the practical term (see Section "Background"
         | 
| 80 | 
            +
            for detail).  Fear not, though. In practical applications, they are
         | 
| 81 | 
            +
            compatible and you do not have to be aware of them.  In short, you can
         | 
| 82 | 
            +
            mostly use built-in borderless Ranges unless you want otherwise.
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            To express open-ended ranges defined in this library, you use either of
         | 
| 33 85 | 
             
            the two (negative and positive, or former and later) constants
         | 
| 34 86 | 
             
            defined in the class {RangeExtd::Infinity}
         | 
| 35 87 |  | 
| 36 | 
            -
            * RangeExtd::Infinity::NEGATIVE
         | 
| 37 | 
            -
            * RangeExtd::Infinity::POSITIVE
         | 
| 88 | 
            +
            * {RangeExtd::Infinity::NEGATIVE}
         | 
| 89 | 
            +
            * {RangeExtd::Infinity::POSITIVE}
         | 
| 38 90 |  | 
| 39 | 
            -
            They are basically the  | 
| 91 | 
            +
            They are basically the objects that *generalize* <tt>Float::INFINITY</tt> to
         | 
| 40 92 | 
             
            any Comparable object.  For example,
         | 
| 41 93 |  | 
| 42 94 | 
             
               ("a"..RangeExtd::Infinity::POSITIVE).each
         | 
| 43 95 |  | 
| 44 96 | 
             
            gives an infinite iterator with <tt>String#succ</tt>, starting from "a"
         | 
| 45 97 | 
             
            (therefore, make sure to code so it breaks the iterator at one stage!).
         | 
| 98 | 
            +
            In this case it work in an identical way to (a Ruby-2.6 form of)
         | 
| 46 99 |  | 
| 100 | 
            +
               ("a"..).each
         | 
| 47 101 |  | 
| 48 | 
            -
             | 
| 49 | 
            -
            a power to make easy coding.  Yet, the lack of definition of
         | 
| 50 | 
            -
            exclusive begin boundary is a nuisance in some cases.
         | 
| 102 | 
            +
            === News: Library locations and support of beginless Ranges
         | 
| 51 103 |  | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
            <tt>succ()</tt> in general.
         | 
| 57 | 
            -
            In that sense Range is inherently not symmetric.  In addition
         | 
| 58 | 
            -
            some regular Range objects are continuous (like Float), while others are discrete
         | 
| 59 | 
            -
            (like Integer or String).  That may add some confusion to the strict definition.
         | 
| 104 | 
            +
            **IMPORTANT**: The paths for the libraries are moved up by one
         | 
| 105 | 
            +
            directory in {RangeExtd} Ver.2 from Ver.1 in order that their
         | 
| 106 | 
            +
            locations follow the Ruby Gems convention.  In short, the standard way
         | 
| 107 | 
            +
            to require is +require "range_extd"+, the path of which used to be "range_extd/range_extd"
         | 
| 60 108 |  | 
| 61 | 
            -
             | 
| 62 | 
            -
            not 100 per cent trivial.  The definition I adopt for the behaviour of
         | 
| 63 | 
            -
            RangeExtd is probably not the only solution.  Personally, I am content
         | 
| 64 | 
            -
            with it, and I think it achieves the good logical completeness within the frame.
         | 
| 109 | 
            +
            Version of {RangeExtd} is now 2.0.
         | 
| 65 110 |  | 
| 66 | 
            -
             | 
| 111 | 
            +
            Here is a brief summary of other significant changes in recent
         | 
| 112 | 
            +
            upgrades. For more extensive information, see History section in this doc.
         | 
| 67 113 |  | 
| 68 | 
            -
             | 
| 114 | 
            +
            ==== News: Beginless Range supported
         | 
| 69 115 |  | 
| 70 | 
            -
             | 
| 71 | 
            -
            introduced in Ruby 2.6.  It is released as Version 1.* finally!
         | 
| 116 | 
            +
            Ruby 2.7 supports {Beginless range}[https://rubyreferences.github.io/rubychanges/2.7.html#beginless-range].
         | 
| 72 117 |  | 
| 73 | 
            -
             | 
| 118 | 
            +
            +RangeExtd+ also supports it now.
         | 
| 119 | 
            +
            With this, there are important changes in specification.
         | 
| 74 120 |  | 
| 75 | 
            -
             | 
| 76 | 
            -
            ( | 
| 77 | 
            -
            { | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 121 | 
            +
            First, {RangeExtd::NONE} is now in practice
         | 
| 122 | 
            +
            +RangeExtd((RangeExtd::Nowhere::NOWHERE...RangeExtd::Nowhere::NOWHERE), true)+,
         | 
| 123 | 
            +
            that is, both ends are {RangeExtd::Nowhere::NOWHERE} and both ends ({RangeExtd#begin} and
         | 
| 124 | 
            +
            {RangeExtd#end}) are exclusive.
         | 
| 125 | 
            +
            In the previous versions, both ends of {RangeExtd::NONE} used to have
         | 
| 126 | 
            +
            +nil+. Range +(nil..nil)+ did not use to be allowed in Ruby-2.6 or earlier,
         | 
| 127 | 
            +
            and hence it was unique to {RangeExtd::NONE}, conveniently.
         | 
| 128 | 
            +
            However, Ruby-2.7 and later now accepts nil to nil Range.  Then,
         | 
| 129 | 
            +
            +(nil..nil)+ is perfectly valid and it has in practice
         | 
| 130 | 
            +
            no difference from +RangeExtd((nil...nil), true)+, which used to be
         | 
| 131 | 
            +
            the form of {RangeExtd::NONE}, despite the fact
         | 
| 132 | 
            +
            the former is a completely different object that is close to {RangeExtd::ALL} except
         | 
| 133 | 
            +
            for the exclusion flags.  That is why this change is required.
         | 
| 134 | 
            +
             | 
| 135 | 
            +
            Having said that, this change is majorly conceptual and there is almost no
         | 
| 136 | 
            +
            change from users' point of view. The begin and end value for {RangeExtd::NONE},
         | 
| 137 | 
            +
            {RangeExtd::Nowhere::NOWHERE}, behaves almost exactly like {NilClass}
         | 
| 138 | 
            +
            (see Description below for detail). Given that the value was literally +nil+ in {RangeExtd}
         | 
| 139 | 
            +
            Ver.1 and earlier, the use of {RangeExtd::Nowhere::NOWHERE} in
         | 
| 140 | 
            +
            {RangeExtd::NONE} in Ver.2 should not demand any changes in the existing code
         | 
| 141 | 
            +
            that use {RangeExtd::NONE}. The recommended way to check whether an
         | 
| 142 | 
            +
            object is {RangeExtd::NONE} or not with use of {RangeExtd#is_none?} (as
         | 
| 143 | 
            +
            it always has been) (do not be confused with +Enumerable#none?+). Or, in most practical cases, {Range#null?} is
         | 
| 144 | 
            +
            likely to be what a user wants (n.b., a potential caveat is
         | 
| 145 | 
            +
            +(true..true).null?+ returns +false+; see subsection "RangeExtd Class"
         | 
| 146 | 
            +
            in "Description" in this doc for detail).
         | 
| 84 147 |  | 
| 85 | 
            -
             | 
| 148 | 
            +
            Second, +RangeExtd.valid?(nil..)+ now returns +true+, which used to be +false+, and it
         | 
| 149 | 
            +
            is equal to {RangeExtd::ALL}.
         | 
| 150 | 
            +
             | 
| 151 | 
            +
            For example, +"abc"[nil..]+ is a perfectly valid Ruby
         | 
| 152 | 
            +
            expression in Ruby-2.7 and later, though it used to be invalid or even
         | 
| 153 | 
            +
            SyntaxError in earlier versions of Ruby. Hence it would be strange if +RangeExtd+ considered it invalid.
         | 
| 154 | 
            +
             | 
| 155 | 
            +
            Note that +RangeExtd.valid?(true..)+ still returns +false+.
         | 
| 156 | 
            +
             | 
| 157 | 
            +
            Other major changes in specification include:
         | 
| 158 | 
            +
             | 
| 159 | 
            +
            * +RangeExtd::Infinity#succ+ is now undefined, in line with Float.
         | 
| 160 | 
            +
            * Extensions for +Object+ and +Numeric+ are now not in default and optional.
         | 
| 161 | 
            +
            * +RangeExtd#eql?+ follows the Ruby default behaviour (comparison based on [#hash]), eliminating special cases in comparison with {RangeExtd::NONE}.
         | 
| 162 | 
            +
            * Fixed a bug where +RangeExtd#min_by+ (and +max_by+ and +minmax_by+) did not work correctly.
         | 
| 163 | 
            +
             | 
| 164 | 
            +
            ==== News: Endless Range supported
         | 
| 165 | 
            +
             | 
| 166 | 
            +
            Now, as of 2019 October, this fully supports {Endless Range}[https://rubyreferences.github.io/rubychanges/2.6.html#endless-range-1]
         | 
| 167 | 
            +
            introduced in Ruby 2.6.  It is released as Version 1.* finally!
         | 
| 86 168 |  | 
| 87 169 | 
             
            ==== NOTE: Relationship with Rangesmaller
         | 
| 88 170 |  | 
| 89 171 | 
             
            This package RangeExtd supersedes the obsolete {Rangesmaller}[https://rubygems.org/gems/rangesmaller] package and class,
         | 
| 90 | 
            -
            with the added open-ended feature | 
| 172 | 
            +
            with the added open-ended feature and different interfaces in
         | 
| 91 173 | 
             
            creating a new instance.
         | 
| 92 | 
            -
            https://rubygems.org/gems/rangesmaller
         | 
| 174 | 
            +
            {https://rubygems.org/gems/rangesmaller}
         | 
| 175 | 
            +
             | 
| 176 | 
            +
             | 
| 177 | 
            +
            == Background
         | 
| 178 | 
            +
             | 
| 179 | 
            +
            === Endless and Beginless Ranges
         | 
| 180 | 
            +
             | 
| 181 | 
            +
            {Endless Range}[https://rubyreferences.github.io/rubychanges/2.6.html#endless-range-1] and
         | 
| 182 | 
            +
            {Beginless Range}[https://rubyreferences.github.io/rubychanges/2.7.html#beginless-range]
         | 
| 183 | 
            +
            were introduced in Ruby 2.6 and 2.7, respectively, released in Decembers 2018
         | 
| 184 | 
            +
            and 2019.
         | 
| 185 | 
            +
             | 
| 186 | 
            +
            Thanks to them, the Ruby built-in +Range+ has achieved part of the
         | 
| 187 | 
            +
            functionalities and concept of what +RangeExtd+ provides.
         | 
| 188 | 
            +
            However, there are still some differences, some of which are clear but
         | 
| 189 | 
            +
            some are more obscured.
         | 
| 190 | 
            +
             | 
| 191 | 
            +
            The most clear advantage of this library is the support for +exclude_begin?+ (to exclude the "begin" boundary).
         | 
| 192 | 
            +
             | 
| 193 | 
            +
            As for the boundary-less Ranges, this library offers, in a word,
         | 
| 194 | 
            +
            the abstraction of open-ended range (to the infinity).
         | 
| 195 | 
            +
            A major conceptual difference is that Ruby's built-in beginless/endless +Range+
         | 
| 196 | 
            +
            provides *undefined* boundaries, whereas +RangeExtd+ does *infinite* boundaries.
         | 
| 197 | 
            +
             | 
| 198 | 
            +
            The difference is subtle but significant.
         | 
| 199 | 
            +
            Let us take a look at some examples of the standard Ruby, particularly
         | 
| 200 | 
            +
            Numeric, because Ruby Ranges for Numeric practically provide both
         | 
| 201 | 
            +
            functionalities. These examples highlight the difference:
         | 
| 202 | 
            +
             | 
| 203 | 
            +
              "abcdef"[..2]   # => "abc"
         | 
| 204 | 
            +
              "abcdef"[..2.0] # => "abc"
         | 
| 205 | 
            +
              "abcdef"[(-Float::INFINITY)..2]  # raise (RangeError)
         | 
| 206 | 
            +
              "abcdef"[(-1)..2] # => ""
         | 
| 207 | 
            +
              "abcdef"[(-6)..2] # => "abc"
         | 
| 208 | 
            +
              "abcdef"[(-7)..2] # => nil
         | 
| 209 | 
            +
              (-Float::INFINITY..5).first(1) # raise: can't iterate from Float (TypeError)
         | 
| 210 | 
            +
              (-Float::INFINITY..5).first    # => -Infinity
         | 
| 211 | 
            +
              (-Float::INFINITY..5).begin    # => -Infinity
         | 
| 212 | 
            +
              (..5).first   # raise: cannot get the first element of beginless range (RangeError)
         | 
| 213 | 
            +
              (..5).begin   # => nil
         | 
| 214 | 
            +
             | 
| 215 | 
            +
            The first (and second) examples use a beginless Range, where the begin
         | 
| 216 | 
            +
            value is *undefined*. Then, String class *interprets* the "begin value"
         | 
| 217 | 
            +
            as 0.  By contrast, the third example raises an Exception; it is
         | 
| 218 | 
            +
            understandable because the begin value is defined but infinitely negative.
         | 
| 219 | 
            +
            Indeed, a negative value for the index for a String has a special
         | 
| 220 | 
            +
            meaning as demonstrated in the 4th to 6th examples.
         | 
| 221 | 
            +
             | 
| 222 | 
            +
            The last five examples are interesting. +Range#begin+ simply returns
         | 
| 223 | 
            +
            the begin-boundary value always. +Range#first+ returns the first
         | 
| 224 | 
            +
            "element" when no argument is given;
         | 
| 225 | 
            +
            +(Float::INFINITY..5)+ has the first element and so it is returned. A beginless
         | 
| 226 | 
            +
            {Range} is a different story; it does not have a defined first element
         | 
| 227 | 
            +
            and hence +Range#first+ raises +RangeError+. By contrast,
         | 
| 228 | 
            +
            When an argument +n+ is given to +Range#first+, an Array of
         | 
| 229 | 
            +
            +n+ elements should be returned.  Since counting from any Float is undefined, the Range
         | 
| 230 | 
            +
            from the negative infinity raises +TypeError+.  It makes sense?
         | 
| 231 | 
            +
             | 
| 232 | 
            +
            By the way, I note that +(5..8.6).last(2)+ is valid and returns +[7, 8]+ and +(2.2..8.6).size+
         | 
| 233 | 
            +
            is also valid, to add confusion.
         | 
| 234 | 
            +
             | 
| 235 | 
            +
            Another point is, although the infinity has a clear mathematical
         | 
| 236 | 
            +
            definition, not all Ranges accept it. Let us consider your own
         | 
| 237 | 
            +
            subset class where each instance has only a single lower-case alphabet
         | 
| 238 | 
            +
            character and where a Range of instances can be defined in the same
         | 
| 239 | 
            +
            way as the String class. Then, the minimum begin value and maximum end
         | 
| 240 | 
            +
            value the Range can have are "+a+" and "+z+", respectively. In this
         | 
| 241 | 
            +
            case, what would the positive (or negative) infinities mean?  Perhaps,
         | 
| 242 | 
            +
            in the strictest term, the infinities for the Range should be invalid?
         | 
| 243 | 
            +
            Or, the positive infinity should be interpreted as the index for "+z+"
         | 
| 244 | 
            +
            in this case, or else?
         | 
| 245 | 
            +
             | 
| 246 | 
            +
            Conceptually, the inclusive interpretation is more convenient.
         | 
| 247 | 
            +
            Indeed, {Rangeary}[https://rubygems.org/gems/rangeary] uses
         | 
| 248 | 
            +
            +RangeExtd+ in such a way, that is,
         | 
| 249 | 
            +
            the negation of the Range is actively used for logical operations of
         | 
| 250 | 
            +
            Arrays of Ranges.  However, you cannot force each application to
         | 
| 251 | 
            +
            accept the definition.
         | 
| 252 | 
            +
             | 
| 253 | 
            +
            In summary, *undefined* boundaries are undefined by definition and
         | 
| 254 | 
            +
            their interpretations are up to each application, whereas positive or
         | 
| 255 | 
            +
            negative infinities may have clear definitions although more
         | 
| 256 | 
            +
            flexible interpretations may be preferred in practical applications.
         | 
| 257 | 
            +
             | 
| 258 | 
            +
            Given all these, {RangeExtd::Infinity::NEGATIVE} and {RangeExtd::Infinity::POSITIVE}
         | 
| 259 | 
            +
            in this library behaves like +nil+, though it is possible for users to
         | 
| 260 | 
            +
            distinguish them.
         | 
| 261 | 
            +
             | 
| 262 | 
            +
             | 
| 263 | 
            +
            === Behaviours of endless and beginless Ranges
         | 
| 264 | 
            +
             | 
| 265 | 
            +
            The behaviours of the built-in Endless/Beginless Range can be a little confusing.
         | 
| 266 | 
            +
            In addition, it seems there are bugs for +Range#size+
         | 
| 267 | 
            +
            ({Bug #18983}[https://bugs.ruby-lang.org/issues/18983] and
         | 
| 268 | 
            +
             {Bug #18993}[https://bugs.ruby-lang.org/issues/18993])
         | 
| 269 | 
            +
            or at least points that contradict the specification described in the
         | 
| 270 | 
            +
            official doc, which adds confusion.
         | 
| 271 | 
            +
             | 
| 272 | 
            +
            In the Ruby implementation, the begin and end values of a beginless and endless Ranges
         | 
| 273 | 
            +
            are both interpreted as +nil+.  In Ruby, +nil == nil+ is true and
         | 
| 274 | 
            +
            therefore 
         | 
| 275 | 
            +
             | 
| 276 | 
            +
              (?a..).end == (5..).end
         | 
| 277 | 
            +
             | 
| 278 | 
            +
            is also +true+, whereas 
         | 
| 279 | 
            +
             | 
| 280 | 
            +
              (?a..).end == (5..Float::INFINITY).end
         | 
| 281 | 
            +
             | 
| 282 | 
            +
            is +false+.  Below is a more extended set of examples.
         | 
| 283 | 
            +
             | 
| 284 | 
            +
              (-Float::INFINITY..Float::INFINITY).size  # => Infinity
         | 
| 285 | 
            +
              ( Float::INFINITY..Float::INFINITY).size  # raises FloatDomainError
         | 
| 286 | 
            +
              num1 = (5..Float::INFINITY)
         | 
| 287 | 
            +
              num2 = (5..)
         | 
| 288 | 
            +
              num1.end != num2.end  # => true
         | 
| 289 | 
            +
              num1.size              # => Infinity
         | 
| 290 | 
            +
              num2.size              # => Infinity
         | 
| 291 | 
            +
             | 
| 292 | 
            +
              str1 = (?a..)
         | 
| 293 | 
            +
              str1.end != num1.end   # => true
         | 
| 294 | 
            +
              str1.end == num2.end   # => true (because both are nil)
         | 
| 295 | 
            +
              str1.size              # => nil  (because Range#size is defined for Numeric only)
         | 
| 296 | 
            +
              (..?z).size            # => Infinity  (contradicting the specification?)
         | 
| 297 | 
            +
             | 
| 298 | 
            +
              (..3).to_s    => "..3"
         | 
| 299 | 
            +
              (3..).to_s    => "3.."
         | 
| 300 | 
            +
              (3..nil).to_s => "3.."
         | 
| 301 | 
            +
              (nil..3).to_s => "..3"
         | 
| 93 302 |  | 
| 303 | 
            +
              (nil..) == (..nil)   # => true
         | 
| 304 | 
            +
              (nil..) != (...nil)  # => true  (because exclude_end? differ)
         | 
| 305 | 
            +
              "abcdef"[..nil]      # => "abcdef" (i.e., it is interpreted as (0..IntegerInfinity)
         | 
| 306 | 
            +
                                   #    (n.b., nil.to_i==0; Integer(nil) #=> TypeError))
         | 
| 307 | 
            +
              "abcdef"[..?a]       # raise: no implicit conversion of String into Integer (TypeError)
         | 
| 308 | 
            +
              "abcdef"[0..100]     # => "abcdef"
         | 
| 309 | 
            +
              "abcdef"[-100..100]  # => nil
         | 
| 310 | 
            +
             | 
| 311 | 
            +
              (..nil).size   # => Float::INFINITY
         | 
| 312 | 
            +
             | 
| 313 | 
            +
              (..nil).begin  # => nil
         | 
| 314 | 
            +
              (..nil).first  # raise: cannot get the first element of beginless range (RangeError)
         | 
| 315 | 
            +
              (..nil).last   # raise: cannot get the last element of endless range (RangeError)
         | 
| 316 | 
            +
              (..nil).end    # => nil
         | 
| 317 | 
            +
             | 
| 318 | 
            +
              (..nil).cover? 5    # => true
         | 
| 319 | 
            +
              (..nil).cover? ?a   # => true
         | 
| 320 | 
            +
              (..nil).cover? [?a] # => true
         | 
| 321 | 
            +
              (..nil).cover? nil  # => true
         | 
| 322 | 
            +
             | 
| 323 | 
            +
            For Integer,
         | 
| 324 | 
            +
             | 
| 325 | 
            +
              num1 = (5..Float::INFINITY)
         | 
| 326 | 
            +
              num2 = (5..)
         | 
| 327 | 
            +
              num1.end != num2.end  # => true (because (Float::INFINITY != nil))
         | 
| 328 | 
            +
              num1.size              # => Float::INFINITY
         | 
| 329 | 
            +
              num2.size              # => Float::INFINITY
         | 
| 330 | 
            +
             | 
| 331 | 
            +
              (3...) == (3...nil)    # => true
         | 
| 332 | 
            +
              (3..)  != (3...nil)    # => true  (because exclude_end? differ)
         | 
| 333 | 
            +
             | 
| 334 | 
            +
              (3..).size   # => Float::INFINITY
         | 
| 335 | 
            +
              (..3).begin  # => nil
         | 
| 336 | 
            +
              (..3).first  # raise: cannot get the first element of beginless range (RangeError)
         | 
| 337 | 
            +
              (3..).last   # raise: cannot get the last element of endless range (RangeError)
         | 
| 338 | 
            +
              (3..).end    # => nil
         | 
| 339 | 
            +
              (..3).each{} # raise: `each': can't iterate from NilClass (TypeError)
         | 
| 340 | 
            +
              (..3).to_a   # raise: `each': can't iterate from NilClass (TypeError)
         | 
| 341 | 
            +
              (3..).to_a   # raise: `to_a': cannot convert endless range to an array (RangeError)
         | 
| 342 | 
            +
              (3..Float::INFINITY).to_a  # Infinite loop!
         | 
| 343 | 
            +
             | 
| 344 | 
            +
              (-Float::INFINITY..4).first    # => -Float::INFINITY
         | 
| 345 | 
            +
              (4..Float::INFINITY).last      # =>  Float::INFINITY
         | 
| 346 | 
            +
              (-Float::INFINITY..4).first(2) # raise: can't iterate from Float (TypeError)
         | 
| 347 | 
            +
              (4..Float::INFINITY).last(2)   # Infinite loop!
         | 
| 348 | 
            +
             | 
| 349 | 
            +
            For String (or any user-defined class?),
         | 
| 350 | 
            +
             | 
| 351 | 
            +
              (?a..).end   == (5..).end   # => true (because both are nil)
         | 
| 352 | 
            +
              (?a..).end   != (5..Float::INFINITY).end      # => true
         | 
| 353 | 
            +
              (..?a).begin == (..5).begin # => true (because both are nil)
         | 
| 354 | 
            +
              (..?a).begin != ((-Float::INFINITY)..5).begin # => true
         | 
| 355 | 
            +
              (..?a).size  # => Float::INFINITY
         | 
| 356 | 
            +
              (?a..).size  # => nil
         | 
| 357 | 
            +
             | 
| 358 | 
            +
              (..?a).begin  # => nil
         | 
| 359 | 
            +
              (..?a).first  # raise: cannot get the first element of beginless range (RangeError)
         | 
| 360 | 
            +
              (?a..).last   # raise: cannot get the last element of endless range (RangeError)
         | 
| 361 | 
            +
              (?a..).end    # => nil
         | 
| 362 | 
            +
              (..?a).each{} # raise: `each': can't iterate from NilClass (TypeError)
         | 
| 363 | 
            +
              (..?a).to_a   # raise: `each': can't iterate from NilClass (TypeError)
         | 
| 364 | 
            +
              (?a..).to_a   # raise: `to_a': cannot convert endless range to an array (RangeError)
         | 
| 365 | 
            +
              (?a..Float::INFINITY).to_a  # raise: bad value for range (ArgumentError)  # b/c it is not String!
         | 
| 366 | 
            +
             | 
| 367 | 
            +
            === Comment on Range#size
         | 
| 368 | 
            +
             | 
| 369 | 
            +
            The behaviour of +Range#size+ is highly confusing.
         | 
| 370 | 
            +
            According to {Official doc}[https://ruby-doc.org/core-3.1.2/Range.html#method-i-size],
         | 
| 371 | 
            +
             | 
| 372 | 
            +
              Returns the count of elements in self if both begin and end values are numeric;
         | 
| 373 | 
            +
              otherwise, returns nil
         | 
| 374 | 
            +
             | 
| 375 | 
            +
            But actually Ruby does not necessarily behaves in this way (see examples above).
         | 
| 376 | 
            +
            In addition, the meaning of "elements" in the doc for general Numeric is
         | 
| 377 | 
            +
            ambiguous. The following demonstrates it (reported as {Bug #18993}[https://bugs.ruby-lang.org/issues/18993]):
         | 
| 378 | 
            +
             | 
| 379 | 
            +
              (5.quo(3)...5).size      # => 3
         | 
| 380 | 
            +
              (5.quo(3).to_f...5).size # => 4
         | 
| 381 | 
            +
              (5.quo(3)..5).size       # => 4
         | 
| 382 | 
            +
              (5.quo(3).to_f..5).size  # => 4
         | 
| 383 | 
            +
             | 
| 384 | 
            +
            === Comment on Range#count
         | 
| 385 | 
            +
             | 
| 386 | 
            +
            The behaviour of +Range#count+ is mostly understandable, but those of
         | 
| 387 | 
            +
            borderless or with infinities are not trivial.
         | 
| 388 | 
            +
             | 
| 389 | 
            +
              (5..).count             # => Float::INFINITY
         | 
| 390 | 
            +
              (..5).count             # => Float::INFINITY
         | 
| 391 | 
            +
              (..nil).count           # => Float::INFINITY
         | 
| 392 | 
            +
              (-Float::INFINITY..nil) # => Float::INFINITY
         | 
| 393 | 
            +
              (-Float::INFINITY..Float::INFINITY).count  # raises (TypeError) "can't iterate from Float"
         | 
| 394 | 
            +
              (..5).count(4)          # raises (TypeError)
         | 
| 395 | 
            +
              (..5).count{|i| i<3}    # raises (TypeError)
         | 
| 396 | 
            +
              (1..).count(4)          # infinite loop!
         | 
| 397 | 
            +
              (1..).count{|i| i<3}    # infinite loop!
         | 
| 398 | 
            +
             | 
| 399 | 
            +
            Basically, in some limited cases, the method returns Infinity, which
         | 
| 400 | 
            +
            are special cases.
         | 
| 401 | 
            +
             | 
| 402 | 
            +
            Given these, +RangeExtd::ALL.count+ returns +Float::INFINITY+ as
         | 
| 403 | 
            +
            another special case.
         | 
| 94 404 |  | 
| 95 405 | 
             
            == Install
         | 
| 96 406 |  | 
| 97 407 | 
             
              gem install range_extd
         | 
| 98 408 |  | 
| 99 | 
            -
             | 
| 409 | 
            +
            installs several files including
         | 
| 100 410 |  | 
| 101 | 
            -
              range_extd | 
| 102 | 
            -
              range_extd/infinity | 
| 411 | 
            +
              range_extd.rb
         | 
| 412 | 
            +
              range_extd/infinity.rb
         | 
| 103 413 |  | 
| 104 | 
            -
             | 
| 414 | 
            +
            in one of your <tt>$LOAD_PATH</tt> 
         | 
| 105 415 |  | 
| 106 | 
            -
            Alternatively get it from
         | 
| 416 | 
            +
            Alternatively get it from {http://rubygems.org/gems/range_extd}
         | 
| 107 417 |  | 
| 108 | 
            -
             | 
| 418 | 
            +
            Or, if you manually install it, place all the Ruby files under +lib/+
         | 
| 419 | 
            +
            directory under one of your +RUBYLIB+ directory paths, preserving the
         | 
| 420 | 
            +
            directory structure. Note that +range_extd.rb+ must be directly under
         | 
| 421 | 
            +
            the library directory.
         | 
| 109 422 |  | 
| 110 423 | 
             
            Then all you need to do is
         | 
| 111 424 |  | 
| 112 | 
            -
              require  | 
| 425 | 
            +
              require "range_extd/load_all"
         | 
| 426 | 
            +
             | 
| 427 | 
            +
            Or, if you only want minimum functions of this library, you can instead
         | 
| 113 428 |  | 
| 114 | 
            -
             | 
| 429 | 
            +
              require "range_extd"
         | 
| 115 430 |  | 
| 116 | 
            -
             | 
| 431 | 
            +
            Basically, "+range_extd/load_all.rb+" is a wrapper Ruby file, which requires the following files:
         | 
| 117 432 |  | 
| 118 | 
            -
             | 
| 433 | 
            +
              require "range_extd"
         | 
| 434 | 
            +
              require "range_extd/numeric"
         | 
| 435 | 
            +
              require "range_extd/object"
         | 
| 436 | 
            +
              require "range_extd/infinity"
         | 
| 437 | 
            +
              require "range_extd/nowhere"
         | 
| 438 | 
            +
              require "range_extd/range"
         | 
| 439 | 
            +
              require "range_extd/nil_class"
         | 
| 119 440 |  | 
| 120 | 
            -
             | 
| 441 | 
            +
            Among these, the first three files are independent, whereas the last
         | 
| 442 | 
            +
            four files are inseparable from the first one and are automatically
         | 
| 443 | 
            +
            require-d from the first one.
         | 
| 121 444 |  | 
| 122 | 
            -
             | 
| 445 | 
            +
            The second and third files are a set of utility libraries; if your code
         | 
| 446 | 
            +
            requires them, some methods are added or some existing methods are slightly altered in the
         | 
| 447 | 
            +
            existing Ruby built-in classes: +Object+ and +Numeric+
         | 
| 448 | 
            +
            (including +Float+ and +Integer+).
         | 
| 449 | 
            +
            How they are modified are backward-compatible; simply a few
         | 
| 450 | 
            +
            new features are added.  Their use is highly recommended; otherwise,
         | 
| 451 | 
            +
            the use of this library would be very limited.  For example,
         | 
| 452 | 
            +
            the comparison operator +<=>+ would not be commutative without them,
         | 
| 453 | 
            +
            which might result in some nasty surprises.  For detail, refer to the
         | 
| 454 | 
            +
            individual references.
         | 
| 123 455 |  | 
| 124 456 | 
             
            Have fun!
         | 
| 125 457 |  | 
| 126 458 |  | 
| 127 459 | 
             
            == Simple Examples
         | 
| 128 460 |  | 
| 461 | 
            +
            In the following, I assume all the files are required.
         | 
| 462 | 
            +
             | 
| 129 463 | 
             
            === How to create a RangeExtd instance
         | 
| 130 464 |  | 
| 131 465 | 
             
            Here are some simple examples.
         | 
| 132 466 |  | 
| 467 | 
            +
               require "range_extd/load_all"
         | 
| 133 468 | 
             
               r = RangeExtd(?a...?d, true)  # => a<...d
         | 
| 134 469 | 
             
               r.exclude_begin?              # => true 
         | 
| 135 470 | 
             
               r.to_a                        # => ["b", "c"]
         | 
| @@ -141,20 +476,21 @@ Here are some simple examples. | |
| 141 476 | 
             
               (RangeExtd::Infinity::NEGATIVE..RangeExtd::Infinity::POSITIVE) \
         | 
| 142 477 | 
             
                == RangeExtd::ALL  # => true
         | 
| 143 478 |  | 
| 144 | 
            -
             | 
| 479 | 
            +
            +RangeExtd+ provides three forms for initialization (hint: the first
         | 
| 480 | 
            +
            form is probably the handiest with least typing and is the easiest to remember):
         | 
| 145 481 |  | 
| 146 | 
            -
               RangeExtd(range, [exclude_begin=false, [exclude_end=false]] | 
| 147 | 
            -
               RangeExtd(obj_begin, obj_end, [exclude_begin=false, [exclude_end=false]] | 
| 148 | 
            -
               RangeExtd(obj_begin, string_form, obj_end, [exclude_begin=false, [exclude_end=false]] | 
| 482 | 
            +
               RangeExtd(range, [exclude_begin=false, [exclude_end=false]])
         | 
| 483 | 
            +
               RangeExtd(obj_begin, obj_end, [exclude_begin=false, [exclude_end=false]])
         | 
| 484 | 
            +
               RangeExtd(obj_begin, string_form, obj_end, [exclude_begin=false, [exclude_end=false]])
         | 
| 149 485 |  | 
| 150 | 
            -
            The two parameters in the brackets specify the respective  | 
| 151 | 
            -
            or included if false (Default).  If they contradict  | 
| 152 | 
            -
            parameter of the range (Range or RangeExtd),  | 
| 153 | 
            -
             | 
| 154 | 
            -
            and <tt>:exclude_end</tt>, which have the highest priority | 
| 155 | 
            -
            The <tt>string_form</tt> in the third form is like ".." and "<..." | 
| 156 | 
            -
             | 
| 157 | 
            -
            the most visibly | 
| 486 | 
            +
            The two parameters in the square-brackets specify the respective boundaries to be excluded if true,
         | 
| 487 | 
            +
            or included if false (Default).  If they contradict the first
         | 
| 488 | 
            +
            parameter of the range (+Range+ or +RangeExtd+), the latter two parameters have priorities.
         | 
| 489 | 
            +
            Alternatively, you can specify the same parameters as the options <tt>:exclude_begin</tt>
         | 
| 490 | 
            +
            and <tt>:exclude_end</tt>, which have the highest priority if specified.
         | 
| 491 | 
            +
            The <tt>string_form</tt> in the third form is like ".." (including both ends) and "<..." (excluding both ends),
         | 
| 492 | 
            +
            set by users (see {RangeExtd.middle_strings=}() for detail), and is arguably
         | 
| 493 | 
            +
            the most visibly-recognisable way to specify any range with <tt>exclude_begin=true</tt>.
         | 
| 158 494 |  | 
| 159 495 | 
             
            <tt>RangeExtd.new()</tt> is the same thing.
         | 
| 160 496 | 
             
            For more detail and examples, see {RangeExtd.initialize}.
         | 
| @@ -162,102 +498,106 @@ For more detail and examples, see {RangeExtd.initialize}. | |
| 162 498 |  | 
| 163 499 | 
             
            === Slightly more advanced uses
         | 
| 164 500 |  | 
| 165 | 
            -
               ( | 
| 501 | 
            +
               RangeExtd((0..), true).each do |i|
         | 
| 166 502 | 
             
                 print i
         | 
| 167 503 | 
             
                 break if i >= 9
         | 
| 168 | 
            -
               end    # => self | 
| 169 | 
            -
             | 
| 504 | 
            +
               end    # => self;  "123456789" => STDOUT
         | 
| 505 | 
            +
                      # *NOT* "012..."
         | 
| 506 | 
            +
               (nil..nil).valid?  # => true
         | 
| 170 507 | 
             
               (1...1).valid?     # => false
         | 
| 171 508 | 
             
               (1...1).null?      # => true
         | 
| 172 509 | 
             
               RangeExtd.valid?(1...1)              # => false
         | 
| 173 510 | 
             
               RangeExtd(1, 1, true, true).valid?   # => true
         | 
| 174 511 | 
             
               RangeExtd(1, 1, true, true).empty?   # => true
         | 
| 175 512 | 
             
               RangeExtd(?a, ?b, true, true).to_a?  # => []
         | 
| 176 | 
            -
               RangeExtd(?a, ?b, true, true). | 
| 513 | 
            +
               RangeExtd(?a, ?b, true, true).null?  # => true  (empty? is same in this case)
         | 
| 177 514 | 
             
               RangeExtd(?a, ?e, true, true).to_a?  # => ["b", "c", "d"]
         | 
| 178 | 
            -
               RangeExtd(?a, ?e, true, true). | 
| 515 | 
            +
               RangeExtd(?a, ?e, true, true).null?  # => false
         | 
| 179 516 | 
             
               RangeExtd::NONE.is_none?             # => true
         | 
| 517 | 
            +
               RangeExtd(1...1, true) == RangeExtd::NONE # => true
         | 
| 180 518 | 
             
               RangeExtd::ALL.is_all?               # => true
         | 
| 519 | 
            +
               (nil..nil).is_all?                   # => false
         | 
| 520 | 
            +
               (-Float::INFINITY..Float::INFINITY).is_all?    # => false
         | 
| 521 | 
            +
               (nil..nil).equiv_all?                # => true
         | 
| 522 | 
            +
               (-Float::INFINITY..Float::INFINITY).equiv_all? # => true
         | 
| 181 523 | 
             
               (3...7).equiv?(3..6)    # => true
         | 
| 524 | 
            +
               (nil..nil).equiv?(RangeExtd::ALL)    # => true
         | 
| 182 525 |  | 
| 183 | 
            -
            All the methods that are in the built-in Range can be used | 
| 526 | 
            +
            All the methods that are in the built-in Range can be used in
         | 
| 527 | 
            +
            {RangeExtd}, which is a child class of {Range}.
         | 
| 184 528 |  | 
| 185 529 |  | 
| 186 530 | 
             
            == Description
         | 
| 187 531 |  | 
| 188 | 
            -
            Once the file +range_extd | 
| 532 | 
            +
            Once the file +range_extd.rb+ is required, the three classes are defined:
         | 
| 189 533 |  | 
| 190 534 | 
             
            * RangeExtd
         | 
| 191 535 | 
             
            * RangeExtd::Infinity
         | 
| 536 | 
            +
            * RangeExtd::Nowhere
         | 
| 192 537 |  | 
| 193 | 
            -
            Also, several methods are added or altered in Range class.
         | 
| 194 | 
            -
            All the changes made in  | 
| 538 | 
            +
            Also, several methods are added or altered in {Range} class and {NilClass}.
         | 
| 539 | 
            +
            All the changes made in them are backward-compatible with the original.
         | 
| 540 | 
            +
             | 
| 541 | 
            +
            Note that whereas the changes in {Range} could be in principle separable
         | 
| 542 | 
            +
            from {RangeExtd}, if no one would likely want to use them separately, those
         | 
| 543 | 
            +
            in {NilClass} are unavoidable.  Without them, {RangeExtd::NONE} could
         | 
| 544 | 
            +
            not be defined, for +ArgumentError+ (bad value for range) would be
         | 
| 545 | 
            +
            raised in the initialization due to the way Ruby built-in Range is
         | 
| 546 | 
            +
            implemented.
         | 
| 547 | 
            +
             | 
| 548 | 
            +
            See {discussion at Stackoverflow}[https://stackoverflow.com/a/14449380/3577922].
         | 
| 195 549 |  | 
| 196 550 | 
             
            === RangeExtd::Infinity Class
         | 
| 197 551 |  | 
| 198 | 
            -
            Class {RangeExtd::Infinity} has  | 
| 552 | 
            +
            Class {RangeExtd::Infinity} has only two constant instances.
         | 
| 199 553 |  | 
| 200 554 | 
             
            * RangeExtd::Infinity::NEGATIVE
         | 
| 201 555 | 
             
            * RangeExtd::Infinity::POSITIVE
         | 
| 202 556 |  | 
| 203 | 
            -
            They are the objects that  | 
| 557 | 
            +
            They are the objects that generalize the concept of
         | 
| 204 558 | 
             
            <tt>Float::INFINITY</tt> 
         | 
| 205 | 
            -
            to any Comparable objects.  The methods <tt><=></tt>  | 
| 559 | 
            +
            to any Comparable objects.  The methods <tt><=></tt> are defined.
         | 
| 206 560 |  | 
| 207 | 
            -
            You can use them the same as other objects, such as,
         | 
| 561 | 
            +
            You can use them in the same way as other objects, such as,
         | 
| 208 562 |  | 
| 209 | 
            -
              ( | 
| 563 | 
            +
              (RangeExtd::Infinity::NEGATIVE.."k")
         | 
| 210 564 |  | 
| 211 | 
            -
            However  | 
| 212 | 
            -
            the use out of Range- | 
| 565 | 
            +
            However, since they do not have any other methods,
         | 
| 566 | 
            +
            the use of them out of Range or its sub-classes is probably meaningless.
         | 
| 213 567 |  | 
| 214 | 
            -
            Note for any Numeric object,  | 
| 568 | 
            +
            Note for any Numeric object, you probably would like to use <tt>Float::INFINITY</tt> instead in principle.
         | 
| 215 569 |  | 
| 216 570 | 
             
            Any objects in any user-defined Comparable class are commutatively comparable with
         | 
| 217 571 | 
             
            those two constants, as long as the cmp method of the class is written
         | 
| 218 | 
            -
             | 
| 572 | 
            +
            in the *standard* way, that is, delegating the cmp method to the
         | 
| 573 | 
            +
            parent class, ultimately +Object+, when they encounter an object of a
         | 
| 574 | 
            +
            class they don't know.
         | 
| 219 575 |  | 
| 220 | 
            -
            For more detail, see  | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 223 | 
            -
            **Note1:** +RangeExtd::Infinity::POSITIVE+ is practically the same as
         | 
| 224 | 
            -
            {Endless Range}[https://rubyreferences.github.io/rubychanges/2.6.html#endless-range-1]
         | 
| 225 | 
            -
            introduced in Ruby 2.6 released in 2018 December!!  In other words,
         | 
| 226 | 
            -
            the official Ruby has finally implement a part of this library!
         | 
| 227 | 
            -
            However, +RangeExtd::Infinity::NEGATIVE+ is not yet implemented in the
         | 
| 228 | 
            -
            official Ruby Range (it has no "boundless begin"), and hence this library still has some use, which
         | 
| 229 | 
            -
            supplements the mathematical incompleteness of the standard Range in
         | 
| 230 | 
            -
            the official Ruby.
         | 
| 576 | 
            +
            For more detail, see the document at {RubyGems webpage}[http://rubygems.org/gems/range_extd],
         | 
| 577 | 
            +
            which is generated from the source-code annotation with YARD.
         | 
| 231 578 |  | 
| 232 | 
            -
             | 
| 233 | 
            -
            As of Ver.1.1, the +RangeExtd::Infinity+ class instances are not
         | 
| 234 | 
            -
            comparable with +Float::INFINITY+; for example,
         | 
| 579 | 
            +
            === RangeExtd::Nowhere Class
         | 
| 235 580 |  | 
| 236 | 
            -
             | 
| 581 | 
            +
            Class {RangeExtd::Nowhere} is a Singleton class, which mimics
         | 
| 582 | 
            +
            {NilClass}. The sole instance is available as
         | 
| 237 583 |  | 
| 238 | 
            -
             | 
| 239 | 
            -
            hence they should not be *equal*.  See the reference of
         | 
| 240 | 
            -
            {RangeExtd::Infinity} for detail.  Note, the behaviour of Endless Range from Ruby 2.6
         | 
| 241 | 
            -
            may feel a little odd, as follows:
         | 
| 584 | 
            +
            * RangeExtd::Nowhere::NOWHERE
         | 
| 242 585 |  | 
| 243 | 
            -
             | 
| 244 | 
            -
             | 
| 245 | 
            -
              num1.end != rnum2.end  # => true
         | 
| 246 | 
            -
              num1.size              # => Infinity
         | 
| 247 | 
            -
              num2.size              # => Infinity
         | 
| 586 | 
            +
            This instance returns, for example, true for +nil?+ and the same
         | 
| 587 | 
            +
            object-ID for +object_id+ as +nil+ and equal (+==+) to nil.  It is used to constitute {RangeExtd::NONE}.
         | 
| 248 588 |  | 
| 249 | 
            -
             | 
| 250 | 
            -
              str1.end == num2.end   # => true (because both are nil)
         | 
| 251 | 
            -
              str1.size              # => nil
         | 
| 589 | 
            +
            It is not, however, recognised as the false value in conditional statements.
         | 
| 252 590 |  | 
| 591 | 
            +
            Also, a Range containing {RangeExtd::Nowhere::NOWHERE} is *not* "valid"
         | 
| 592 | 
            +
            as a Range (see below), except for {RangeExtd::NONE}.
         | 
| 253 593 |  | 
| 254 594 | 
             
            === RangeExtd Class
         | 
| 255 595 |  | 
| 256 | 
            -
            RangeExtd objects are immutable, the same as Range.
         | 
| 257 | 
            -
            Hence once an instance  | 
| 596 | 
            +
            {RangeExtd} objects are immutable, the same as {Range}.
         | 
| 597 | 
            +
            Hence once an instance has been created, it would not change.
         | 
| 258 598 |  | 
| 259 599 | 
             
            How to create an instance is explained above (in the Examples
         | 
| 260 | 
            -
            sections).  Any attempt to try to create an instance that is not
         | 
| 600 | 
            +
            sections).  Any attempt to try to create an instance of {RangeExtd} that is not
         | 
| 261 601 | 
             
            "valid" as a range (see below) raises an exception (<tt>ArgumentError</tt>), and fails.
         | 
| 262 602 |  | 
| 263 603 | 
             
            There are two constants defined in this class:
         | 
| @@ -266,7 +606,7 @@ There are two constants defined in this class: | |
| 266 606 | 
             
            * RangeExtd::ALL
         | 
| 267 607 |  | 
| 268 608 | 
             
            The former represents the empty range and the latter does the range
         | 
| 269 | 
            -
            covers everything, namely open-ended for the both negative and
         | 
| 609 | 
            +
            that covers everything, namely open-ended for the both negative and
         | 
| 270 610 | 
             
            positive directions.
         | 
| 271 611 |  | 
| 272 612 | 
             
            In addition to all the standard methods of {Range}, the following
         | 
| @@ -278,7 +618,7 @@ See the document of each method for detail (some are defined only in | |
| 278 618 | 
             
            * <tt>valid?</tt> 
         | 
| 279 619 | 
             
            * <tt>empty?</tt> 
         | 
| 280 620 | 
             
            * <tt>null?</tt> 
         | 
| 281 | 
            -
            * <tt>is_none?</tt> | 
| 621 | 
            +
            * <tt>is_none?</tt>
         | 
| 282 622 | 
             
            * <tt>is_all?</tt> 
         | 
| 283 623 | 
             
            * <tt>equiv?</tt> 
         | 
| 284 624 |  | 
| @@ -289,65 +629,93 @@ to the instance method <tt>valid?</tt>: | |
| 289 629 | 
             
            * <tt>RangeExtd.middle_strings=(ary)</tt> 
         | 
| 290 630 | 
             
            * <tt>RangeExtd.middle_strings</tt> 
         | 
| 291 631 |  | 
| 632 | 
            +
            ==== Details about validity, emptiness, and nullness
         | 
| 633 | 
            +
             | 
| 292 634 | 
             
            What is valid (<tt>#valid?</tt> => true) as a range is defined as follows.
         | 
| 293 635 |  | 
| 294 636 | 
             
            1. Both <tt>begin</tt> and <tt>end</tt> elements must be Comparable to each other,
         | 
| 295 637 | 
             
               and the comparison results must be consistent between the two.
         | 
| 296 | 
            -
               The  | 
| 297 | 
            -
                | 
| 298 | 
            -
             | 
| 638 | 
            +
               The three exceptions are {RangeExtd::NONE} and Beginless and Endless Ranges
         | 
| 639 | 
            +
               (introduced in Ruby 2.7 and 2.6, respectively),
         | 
| 640 | 
            +
               which are all valid.  Accordingly, +(nil..nil)+ is
         | 
| 641 | 
            +
               valid in {RangeExtd} Ver.2.0+ (nb., it used to raise Exception in Ruby 1.8).
         | 
| 642 | 
            +
            2. Except for {RangeExtd::NONE} and Beginless Range, the object of +Range#begin+ must have the method +<=+.
         | 
| 643 | 
            +
               Therefore, some Endless Ranges (Ruby 2.6 and later) like +(true..)+ are *not* valid.
         | 
| 644 | 
            +
               Note even "+true+" has the method +<=>+ and hence checking +<=+ is essential.
         | 
| 645 | 
            +
            3. Similarly, except for {RangeExtd::NONE} and Endless Range, +Range#end+ must have the method +<=+.
         | 
| 646 | 
            +
               Therefore, some Beginless Ranges (Ruby 2.7 and later) like +(..true)+ are *not* valid.
         | 
| 647 | 
            +
            4. *begin* must be smaller than or equal (<tt>==</tt>) to *end*,
         | 
| 299 648 | 
             
               that is, <tt>(begin <=> end)</tt> must be either -1 or 0.
         | 
| 300 | 
            -
             | 
| 301 | 
            -
               the exclude status of the both ends must agree | 
| 302 | 
            -
                | 
| 649 | 
            +
            5. If *begin* is equal to *end*, namely, <tt>(begin <=> end) == 0</tt>,
         | 
| 650 | 
            +
               the exclude status of the both ends must agree, except for the cases
         | 
| 651 | 
            +
               where both +begin+ and +end+ are +nil+ (beginless and endless Range).
         | 
| 652 | 
            +
               In other words, if the +begin+ is excluded, +end+ must be also excluded,
         | 
| 303 653 | 
             
               and vice versa.
         | 
| 304 | 
            -
               For example,  | 
| 654 | 
            +
               For example, +(1...1)+ is NOT valid for this reason,
         | 
| 305 655 | 
             
               because any built-in Range object has the exclude status
         | 
| 306 | 
            -
               of false (namely, inclusive) for  | 
| 656 | 
            +
               of +false+ (namely, inclusive) for +begin+, whereas
         | 
| 657 | 
            +
               +RangeExtd(1...1, true)+ is valid and equal (<tt>==</tt>) to {RangeExtd::NONE}.
         | 
| 658 | 
            +
            6. Range containing {RangeExtd::Nowhere::NOWHERE} except for
         | 
| 659 | 
            +
               {RangeExtd::NONE} is *not* valid.
         | 
| 307 660 |  | 
| 308 | 
            -
            For more detail and examples see the documents of
         | 
| 661 | 
            +
            For more detail and examples, see the documents of
         | 
| 309 662 | 
             
            {RangeExtd.valid?} and {Range#valid?} 
         | 
| 310 663 |  | 
| 311 | 
            -
            The definition of what is empty ( | 
| 664 | 
            +
            The definition of what is empty ({Range#empty?} == +true+) as a range is as follows;
         | 
| 312 665 |  | 
| 313 666 | 
             
            1. the range must be valid: <tt>valid?</tt> => true
         | 
| 314 | 
            -
            2. if the range id discrete, that is, begin has
         | 
| 667 | 
            +
            2. if the range id discrete, that is, +begin+ has the
         | 
| 315 668 | 
             
               <tt>succ</tt> method, there must be no member within the range
         | 
| 316 669 | 
             
               (which means the begin must be excluded, too): 
         | 
| 317 670 | 
             
               <tt>to_a.empty?</tt> => true
         | 
| 318 | 
            -
            3. if the range is continuous, that is, begin does not have
         | 
| 319 | 
            -
               <tt>succ</tt> method, begin and end must be equal
         | 
| 320 | 
            -
               (<tt>(begin <=> end)</tt> | 
| 671 | 
            +
            3. if the range is continuous, that is, begin does not have the
         | 
| 672 | 
            +
               <tt>succ</tt> method, +begin+ and +end+ must be equal
         | 
| 673 | 
            +
               (<tt>(begin <=> end) == 0</tt>) and both the boundaries must
         | 
| 321 674 | 
             
               be excluded: <tt>(exclude_begin? && exclude_end?)</tt> => true.
         | 
| 322 675 |  | 
| 323 676 | 
             
            Note that ranges with equal <tt>begin</tt> and <tt>end</tt> with inconsistent two
         | 
| 324 677 | 
             
            exclude status are not valid, as mentioned in the previous paragraph.
         | 
| 325 678 | 
             
            The built-in Range always has the begin-exclude status of
         | 
| 326 | 
            -
            <tt>false</tt>.  For that reason, no  | 
| 327 | 
            -
             | 
| 679 | 
            +
            <tt>false</tt>.  For that reason, no instances of built-in Range 
         | 
| 680 | 
            +
            have the status of <tt>empty?</tt> of <tt>true</tt>.
         | 
| 328 681 |  | 
| 329 682 | 
             
            For more detail and examples see the documents of
         | 
| 330 683 | 
             
            {Range#empty?} 
         | 
| 331 684 |  | 
| 332 685 | 
             
            Finally, {Range#null?} is equivalent to "either empty or not valid".
         | 
| 333 686 | 
             
            Therefore, for RangeExtd objects <tt>null?</tt> is equivalent to
         | 
| 334 | 
            -
            <tt>empty?</tt>.
         | 
| 687 | 
            +
            <tt>empty?</tt>.  In most practical cases, {Range#null?} will be
         | 
| 688 | 
            +
            perhaps more useful than {Range#empty?}.
         | 
| 335 689 |  | 
| 336 690 | 
             
            In comparison (<tt><=></tt>) between a RangeExtd and another RangeExtd or Range
         | 
| 337 | 
            -
            object,  | 
| 691 | 
            +
            object, these definitions are taken into account.
         | 
| 338 692 | 
             
            Some of them are shown in the above Examples section.
         | 
| 339 | 
            -
            For more detail, see {Range | 
| 340 | 
            -
            well as <tt>#eql?</tt>.
         | 
| 693 | 
            +
            For more detail, see {Range#<=>} and {RangeExtd#<=>}.
         | 
| 341 694 |  | 
| 342 695 | 
             
            Note that as long as the operation is within Range objects, the
         | 
| 343 696 | 
             
            behaviour is identical to the standard Ruby -- it is completely
         | 
| 344 | 
            -
            compatible.  Therefore, requiring this library  | 
| 697 | 
            +
            backward-compatible.  Therefore, requiring this library should not affect any
         | 
| 345 698 | 
             
            existing code in principle.
         | 
| 346 699 |  | 
| 700 | 
            +
            ==== equality
         | 
| 701 | 
            +
             | 
| 702 | 
            +
            The method +eql?+ checks the equality of the hash values according to
         | 
| 703 | 
            +
            Ruby's specification and hence every parameter must agree. By
         | 
| 704 | 
            +
            contrast, <tt>==</tt> makes a more rough comparison and if the two
         | 
| 705 | 
            +
            objects are broadly the same, returns +true+.
         | 
| 706 | 
            +
             | 
| 707 | 
            +
              RaE(0...0, true) == RaE(?a...?a, true)  # => false
         | 
| 708 | 
            +
              RaE(0...1, true) == RaE(5...6, true)    # => true
         | 
| 347 709 |  | 
| 348 710 | 
             
            == Known bugs
         | 
| 349 711 |  | 
| 350 | 
            -
            *  | 
| 712 | 
            +
            * Although {RangeExtd::Nowhere::NOWHERE} cannot be used in the context of 
         | 
| 713 | 
            +
              {RangeExtd} (because it is not {Range#valid?}), users could still
         | 
| 714 | 
            +
              use it within just the built-in Range framework.
         | 
| 715 | 
            +
              Perhaps, {RangeExtd::Nowhere::NOWHERE} should be redefined as a
         | 
| 716 | 
            +
              non-nil object?
         | 
| 717 | 
            +
            * This library of Version 2+ does not work in Ruby 2.6 or earlier.
         | 
| 718 | 
            +
            * This library of Version 1 does not work in Ruby 1.8 or earlier.
         | 
| 351 719 | 
             
              For Ruby 1.9.3 it is probably all right, though I have never tested it.
         | 
| 352 720 | 
             
            * Some unusual (rare) boundary conditions are found to vary from
         | 
| 353 721 | 
             
              version to version in Ruby, such as an implementation of +Hash#=>+.
         | 
| @@ -358,24 +726,88 @@ existing code in principle. | |
| 358 726 | 
             
            * {RangeExtd#hash} method does not theoretically guarantee to return a unique
         | 
| 359 727 | 
             
              number for a {RangeExtd} object, though to encounter a hash number that is
         | 
| 360 728 | 
             
              used elsewhere is extremely unlikely to happen in reality.
         | 
| 729 | 
            +
            * +RangeExtd::NONE.inspect+ and +RangeExtd::NONE.to_s+ return "Null<...Null", but it is
         | 
| 730 | 
            +
              displayed as "nil...nil" in Ruby +irb+ and hence it is not easily
         | 
| 731 | 
            +
              recognizable in +irb+.
         | 
| 361 732 |  | 
| 362 733 | 
             
            Extensive tests have been performed, as included in the package.
         | 
| 363 734 |  | 
| 364 735 | 
             
            == ToDo
         | 
| 365 736 |  | 
| 366 | 
            -
             | 
| 737 | 
            +
            * If {RangeExtd::Infinity::POSITIVE} (and NEGATIVE) behaves like
         | 
| 738 | 
            +
              +nil+ (in the same way as {RangeExtd::Nowhere::NOWHERE}, it may be useful.
         | 
| 739 | 
            +
              However, a range containing such objects would not work with String
         | 
| 740 | 
            +
              like <tt>"abcde"[my_nil..]</tt>, for it seems the String class makes
         | 
| 741 | 
            +
              a pretty rigorous check about +nil+.  So, I guess the practical
         | 
| 742 | 
            +
              applicability would not be improved so much, as far as the built-in
         | 
| 743 | 
            +
              Ruby classes are concerned.
         | 
| 744 | 
            +
            * A method like "+similar+" may be useful. For example,
         | 
| 745 | 
            +
              +(-Float::INFINITY..Float::INFINITY)+ and +(-Float::INFINITYnil...Float::INFINITY)+
         | 
| 746 | 
            +
              have no mathematical difference, because excluding an infinity is
         | 
| 747 | 
            +
              meaningless. Indeed it makes no difference in the results of operations with
         | 
| 748 | 
            +
              non-infinite Range/Rangeary.
         | 
| 367 749 |  | 
| 368 750 | 
             
            == History memo
         | 
| 369 751 |  | 
| 370 752 | 
             
            * <tt>((?a..?z) === "cc")</tt> would give false with Ruby 2.6.x or earlier, but true if later.
         | 
| 753 | 
            +
            * <tt>(Float::INFINITY..Float::INFINITY).size</tt> used to return 0
         | 
| 754 | 
            +
              (in Ruby-2.1 at least) but raises +FloatDomainError: NaN+ as of
         | 
| 755 | 
            +
              Ruby-2.6 and later, including Ruby 3. I do not know in which version
         | 
| 756 | 
            +
              the behaviour changed.
         | 
| 757 | 
            +
             | 
| 758 | 
            +
             | 
| 759 | 
            +
            === RangeExtd Ver.2
         | 
| 760 | 
            +
             | 
| 761 | 
            +
            * The paths for the libraries are moved up by one directory in {RangeExtd} Ver.2 from Ver.1 in order that their locations follow the Ruby Gems convention.
         | 
| 762 | 
            +
            * Compatible with Beginless Range introduced in Ruby-2.7.
         | 
| 763 | 
            +
            * +RangeExtd::Infinity#succ+ is now undefined, in line with Float.
         | 
| 764 | 
            +
            * Extensions for +Object+ and +Numeric+ are not in default anymore and are optional.
         | 
| 765 | 
            +
            * +RangeExtd#eql?+ follows the Ruby default behaviour (comparison based on [#hash]), eliminating special cases in comparison with {RangeExtd::NONE}.
         | 
| 766 | 
            +
            * Fixed a bug where +RangeExtd#min_by+ (and +max_by+ and +minmax_by+) did not work correctly.
         | 
| 767 | 
            +
             | 
| 768 | 
            +
            === RangeExtd Ver.1.1
         | 
| 769 | 
            +
             | 
| 770 | 
            +
            As of Ver.1.1, the +RangeExtd::Infinity+ class instances are not
         | 
| 771 | 
            +
            comparable with +Float::INFINITY+; for example,
         | 
| 772 | 
            +
             | 
| 773 | 
            +
              RangeExtd::Infinity::POSITIVE != Float::INFINITY  # => true
         | 
| 774 | 
            +
             | 
| 775 | 
            +
            Conceptionally, the former is a generalized object of the latter and
         | 
| 776 | 
            +
            hence they should not be *equal*.  See the reference of
         | 
| 777 | 
            +
            {RangeExtd::Infinity} for detail.  Note, the behaviour of Endless Range from Ruby 2.6
         | 
| 778 | 
            +
            may feel a little odd, as follows:
         | 
| 779 | 
            +
             | 
| 780 | 
            +
              num1 = (5..Float::INFINITY)
         | 
| 781 | 
            +
              num2 = (5..)
         | 
| 782 | 
            +
              num1.end != num2.end  # => true
         | 
| 783 | 
            +
              num1.size              # => Infinity
         | 
| 784 | 
            +
              num2.size              # => Infinity
         | 
| 785 | 
            +
             | 
| 786 | 
            +
              str1 = (?a..)
         | 
| 787 | 
            +
              str1.end == num2.end   # => true (because both are nil)
         | 
| 788 | 
            +
              str1.size              # => nil
         | 
| 789 | 
            +
             | 
| 790 | 
            +
            === RangeExtd Ver.1.0
         | 
| 791 | 
            +
             | 
| 792 | 
            +
            +RangeExtd::Infinity::POSITIVE+ is practically the same as
         | 
| 793 | 
            +
            {Endless Range}[https://rubyreferences.github.io/rubychanges/2.6.html#endless-range-1]
         | 
| 794 | 
            +
            introduced in Ruby 2.6 released in 2018 December!!  In other words,
         | 
| 795 | 
            +
            the official Ruby has finally implement a part of this library!
         | 
| 796 | 
            +
            However, +RangeExtd::Infinity::NEGATIVE+ was not yet implemented (at
         | 
| 797 | 
            +
            the time) in the
         | 
| 798 | 
            +
            official Ruby Range (it has no "boundless begin").
         | 
| 799 | 
            +
             | 
| 371 800 |  | 
| 372 801 | 
             
            == Final notes
         | 
| 373 802 |  | 
| 374 803 | 
             
            All the behaviours within RangeExtd (not Range), such as
         | 
| 375 804 | 
             
            any comparison between two RangeExtd, should be (or hopefully?)
         | 
| 376 805 | 
             
            natural for you.  At least it is well-defined and self-consistent, as
         | 
| 377 | 
            -
            the logical structure of the ranges is now complete with RangeExtd.
         | 
| 378 | 
            -
             | 
| 806 | 
            +
            the logical structure of the ranges is now complete with {RangeExtd}.
         | 
| 807 | 
            +
             | 
| 808 | 
            +
            In this section in the earlier versions, I wrote:
         | 
| 809 | 
            +
             | 
| 810 | 
            +
            > Note that some behaviours for open-ended or begin-excluded ranges may
         | 
| 379 811 | 
             
            give you a little shock at first.  For example, the method
         | 
| 380 812 | 
             
            <tt>member?(obj)</tt> for an open-ended range for the negative direction with
         | 
| 381 813 | 
             
            discrete elements returns <tt>nil</tt>.  That is because no meaningful method
         | 
| @@ -384,11 +816,15 @@ theoretically impossible in general to check whether the given obj is a member o | |
| 384 816 | 
             
            the range or not.  You may find it to be weird, but that just means
         | 
| 385 817 | 
             
            the concept of the infinity is unfamiliar to us mortals!
         | 
| 386 818 |  | 
| 387 | 
            -
             | 
| 388 | 
            -
             | 
| 819 | 
            +
            Now, interestingly, the introduction of "beginless Range" in Ruby
         | 
| 820 | 
            +
            means every Ruby programmer must be familiar with the concept!
         | 
| 821 | 
            +
            I would call it a progress.
         | 
| 822 | 
            +
             | 
| 823 | 
            +
            Still, comparisons between RangeExtd and Range may give you
         | 
| 824 | 
            +
            occasional surprises.  This is because some of the accepted
         | 
| 389 825 | 
             
            ranges by built-in Range class are no longer valid in this framework with the
         | 
| 390 826 | 
             
            inclusion of exclude-status of the begin boundary, as explained.
         | 
| 391 | 
            -
            Hopefully you will feel it  | 
| 827 | 
            +
            Hopefully you will feel it natural as you get accustomed to it.
         | 
| 392 828 | 
             
            And I bet once you have got accustomed to it, you will never want to
         | 
| 393 829 | 
             
            go back to the messy world of logical incompleteness, that is, the
         | 
| 394 830 | 
             
            current behaviour of Range!
         | 
| @@ -396,9 +832,6 @@ current behaviour of Range! | |
| 396 832 | 
             
            Enjoy.
         | 
| 397 833 |  | 
| 398 834 |  | 
| 399 | 
            -
             | 
| 400 | 
            -
            == Miscellaneous
         | 
| 401 | 
            -
             | 
| 402 835 | 
             
            == Copyright etc
         | 
| 403 836 |  | 
| 404 837 | 
             
            Author::  Masa Sakano < info a_t wisebabel dot com >
         | 
| @@ -410,130 +843,459 @@ Versions:: The versions of this package follow Semantic Versioning (2.0.0) http: | |
| 410 843 |  | 
| 411 844 | 
             
            = RangeExtd - 拡張Rangeクラス - exclude_begin と無限大に開いた範囲と
         | 
| 412 845 |  | 
| 846 | 
            +
            == はじめに
         | 
| 847 | 
            +
             | 
| 413 848 | 
             
            このパッケージは、Range を拡張した RangeExtd クラスを定義しています。
         | 
| 414 849 | 
             
            以下の特徴を持ちます。
         | 
| 415 850 |  | 
| 416 | 
            -
             | 
| 417 | 
            -
             | 
| 418 | 
            -
             | 
| 419 | 
            -
             | 
| 420 | 
            -
             | 
| 851 | 
            +
            1. メソッド exclude_begin? の導入 (レンジの始点を除外できる),
         | 
| 852 | 
            +
            2. (無限大に)開いたレンジ(+nil+のように*未定義*のレンジではない)
         | 
| 853 | 
            +
            3. NONE (空レンジ) と ALL (全範囲レンジ)定数の導入
         | 
| 854 | 
            +
            4. Rubyで初めて自己論理的に完結したレンジ構造の達成
         | 
| 855 | 
            +
            5. 組込Rangeとの完全後方互換性
         | 
| 421 856 |  | 
| 422 857 | 
             
            組込Rangeにある exclude_end に加えて、exclude_beginを導入したこと、及
         | 
| 423 858 | 
             
            び無限大へ開いた範囲を許可したことで、一次元上の範囲の論理的完全性を実
         | 
| 424 859 | 
             
            現しました。
         | 
| 425 860 |  | 
| 426 | 
            -
             | 
| 427 | 
            -
             | 
| 428 | 
            -
             | 
| 861 | 
            +
            このライブラリの最大の利点は、FloatやRationalのような数で応用場面の多
         | 
| 862 | 
            +
            い複数レンジの論理演算が可能になったことです。
         | 
| 863 | 
            +
            Gem {Rangeary}[https://rubygems.org/gems/rangeary] は本ライブラリをフ
         | 
| 864 | 
            +
            ルに用いて、レンジの論理演算の概念を実現しています。そのためには、無限
         | 
| 865 | 
            +
            に開いた可能性がありまた始端と終端のいずれもが除外されている可能性がある
         | 
| 866 | 
            +
            レンジの概念が不可欠でした。たとえば、
         | 
| 867 | 
            +
            レンジ +(?a..?d)+ の否定(あるいは補集合)が2つのレンジ +(-"Infinity-Character"...3)+ と
         | 
| 868 | 
            +
            +(?d(exclusive).."Infinity-Character")+ であり、その否定が元の
         | 
| 869 | 
            +
            +(?a..?d)+ になります。このような演算は、本 +RangeExtd+ クラスを用いる
         | 
| 870 | 
            +
            ことで初めて可能になります。
         | 
| 871 | 
            +
             | 
| 872 | 
            +
            Rangeary: {https://rubygems.org/gems/rangeary}
         | 
| 873 | 
            +
             | 
| 874 | 
            +
            組込 Rangeは大変有用なクラスであり、Rubyユーザーに容易なプログラミングを可能にす
         | 
| 875 | 
            +
            るツールでした。しかし、始点を除外することができないのが玉に瑕でありました。
         | 
| 876 | 
            +
             | 
| 877 | 
            +
            ただし、それにはれっきとした理由があることは分かります。Rubyの Rangeは、Numeric
         | 
| 878 | 
            +
            (厳密にはその実数を表現したもの)だけに限ったものではありません。 <tt>succ()</tt> メソッ
         | 
| 879 | 
            +
            ドを持つオブジェクトによる Rangeは極めて有用です。一方、<tt>succ()</tt> の逆に相
         | 
| 880 | 
            +
            当するメソッドは一般的には定義されていません。そういう意味で、Rangeは本質的に非
         | 
| 881 | 
            +
            対称です。加えて、よく使われる Rangeオブジェクトのうちあるもの(たとえば Float)は
         | 
| 882 | 
            +
            連続的なのに対し、そうでないものも普通です(たとえば Integer や String)。この状況
         | 
| 883 | 
            +
            が厳密な定義をする時の混乱に拍車をかけています。
         | 
| 884 | 
            +
             | 
| 885 | 
            +
            ここで始点を除外可能としたことは、そういう意味で、道筋が100パーセント明らかなも
         | 
| 886 | 
            +
            のではありませんでした。ここで私が採用した {RangeExtd}クラスの定義は、おそらく、考え
         | 
| 887 | 
            +
            られる唯一のものではないでしょう。とはいえ、個人的には満足のいくものに仕上がりま
         | 
| 888 | 
            +
            したし、このレンジという枠内での論理的完全性をうまく達成できたと思います。
         | 
| 889 | 
            +
             | 
| 890 | 
            +
            このクラスが少なからぬ人に有用なものであることを願ってここにリリースします。
         | 
| 891 | 
            +
             | 
| 892 | 
            +
            === Rangeの正当性
         | 
| 893 | 
            +
             | 
| 894 | 
            +
            Rubyの組込みRangeは、メンバーに許されるものに対してとても慣用です。た
         | 
| 895 | 
            +
            とえば、+(true...true)+ は、それが何を意味するのかはともかく、完全に正
         | 
| 896 | 
            +
            当なRangeです。もっとも、イテレーターを伴う+each+や+to_a+ といったメソッ
         | 
| 897 | 
            +
            ドを使おうとすると例外(+TypeError+)が発生ますし、利用価値はごく限られ
         | 
| 898 | 
            +
            るでしょうが。
         | 
| 899 | 
            +
             | 
| 900 | 
            +
            本ライブラリにより、Rangeの「正当性」が厳密に定義されます。本ライブラ
         | 
| 901 | 
            +
            リは、Rangeクラスに{Range#valid?}, {Range#null?} and {Range#empty?}を
         | 
| 902 | 
            +
            はじめとするいつくつかのメソッドを追加します。それらはもちろん、すべて
         | 
| 903 | 
            +
            の子クラスにも継承されます。
         | 
| 904 | 
            +
             | 
| 905 | 
            +
            一例として、 <tt>(3...3).valid?</tt> は偽(false)を返します。なぜならば、
         | 
| 906 | 
            +
            要素3は始端では含まれるのに終端では除外されているため、相互に矛盾してい
         | 
| 907 | 
            +
            るからです。このRangeExtd クラスでは、次の2つが正当なレンジと見做され
         | 
| 908 | 
            +
            ます。
         | 
| 429 909 |  | 
| 430 | 
            -
             | 
| 431 | 
            -
             | 
| 432 | 
            -
            盾しているためです。ここで導入する RangeExtdクラスにおいては、以下のよ
         | 
| 433 | 
            -
            うにこれが有効なレンジとして定義できます。
         | 
| 910 | 
            +
              * RangeExtd.new(3, 3, true,  true)   # => an empty range
         | 
| 911 | 
            +
              * RangeExtd.new(3, 3, false, false)  # => a single-point range (3..3)
         | 
| 434 912 |  | 
| 435 | 
            -
             | 
| 436 | 
            -
             | 
| 913 | 
            +
            ただし、もし組込みRangeに閉じて使う限りは、何も変わりません。つまり、
         | 
| 914 | 
            +
            標準Rubyと完全に互換性を保っています。
         | 
| 437 915 |  | 
| 438 | 
            -
             | 
| 439 | 
            -
            ん。つまり、標準の Rubyとの完全な後方互換性を実現しています。
         | 
| 916 | 
            +
            === 無限に開いたレンジ
         | 
| 440 917 |  | 
| 441 | 
            -
             | 
| 918 | 
            +
            Ruby 2.6 と 2.7 でそれぞれ終端および始端のないRangeが導入されました。
         | 
| 919 | 
            +
            これら境界のないRangeと本ライブラリの無限に開いたRangeとの違いは
         | 
| 920 | 
            +
            少々難解で、現実の場面で実用的というよりは、概念的哲学的なものといって
         | 
| 921 | 
            +
            いいでしょう(詳しくは「背景」の章を参照)。しかし、気にすることはありま
         | 
| 922 | 
            +
            せん。実用という意味では、両者は互換であり、それほど気を遣うことはあり
         | 
| 923 | 
            +
            ません。端的には、特に不満がない限りは、組込みの境界のないRangeを使え
         | 
| 924 | 
            +
            ばよいでしょう。
         | 
| 925 | 
            +
             | 
| 926 | 
            +
            無限に開いたレンジを表すのは以下のようにします。{RangeExtd::Infinity}クラスで
         | 
| 442 927 | 
             
            定義されている二つの定数(無限大または無現小、あるいは無限前と無限後)の
         | 
| 443 928 | 
             
            いずれかを用います。
         | 
| 444 929 |  | 
| 445 930 | 
             
            * RangeExtd::Infinity::NEGATIVE
         | 
| 446 931 | 
             
            * RangeExtd::Infinity::POSITIVE
         | 
| 447 932 |  | 
| 448 | 
            -
            これらは基本的に <tt>Float::INFINITY</tt> を全ての Comparable | 
| 449 | 
            -
             | 
| 933 | 
            +
            これらは基本的に <tt>Float::INFINITY</tt> を全ての Comparable
         | 
| 934 | 
            +
            であるオブジェクトに*一般化*したものです。たとえば、
         | 
| 450 935 |  | 
| 451 936 | 
             
               ("a"..RangeExtd::Infinity::POSITIVE).each
         | 
| 452 937 |  | 
| 453 938 | 
             
            は、"a"から始まる <tt>String#succ</tt> を使った無限のイテレーターを与えます
         | 
| 454 939 | 
             
            (だから、どこかで必ず breakするようにコードを書きましょう!)。
         | 
| 940 | 
            +
            この例の場合、Ruby-2.6以上の以下とまったく同じように動きます。
         | 
| 455 941 |  | 
| 456 | 
            -
             | 
| 457 | 
            -
            るツールでした。しかし、始点を除外することができないのが玉に瑕でありました。
         | 
| 942 | 
            +
               ("a"..).each
         | 
| 458 943 |  | 
| 459 | 
            -
             | 
| 460 | 
            -
            (厳密にはその実数を表現したもの)だけに限ったものではありません。 <tt>succ()</tt> メソッ
         | 
| 461 | 
            -
            ドを持つオブジェクトによる Rangeは極めて有用です。一方、<tt>succ()</tt> の逆に相
         | 
| 462 | 
            -
            当するメソッドは一般的には定義されていません。そういう意味で、Rangeは本質的に非
         | 
| 463 | 
            -
            対称です。加えて、よく使われる Rangeオブジェクトのうちあるもの(たとえば Float)は
         | 
| 464 | 
            -
            連続的なのに対し、そうでないものも普通です(たとえば Integer や String)。この状況
         | 
| 465 | 
            -
            が厳密な定義をする時の混乱に拍車をかけています。
         | 
| 944 | 
            +
            === News: Libraryの場所他
         | 
| 466 945 |  | 
| 467 | 
            -
             | 
| 468 | 
            -
             | 
| 469 | 
            -
             | 
| 470 | 
            -
             | 
| 946 | 
            +
            **重要**: ライブラリのパスが{RangeExtd} Ver.1 から Ver.2 で、
         | 
| 947 | 
            +
            ディレクトリの階層一つ上がりました。これは、Ruby Gemの慣用にそうように
         | 
| 948 | 
            +
            するためです。端的には、標準的方法は、+require "range_extd"+ です。
         | 
| 949 | 
            +
            以前のパスは、"range_extd/range_extd" でした。
         | 
| 471 950 |  | 
| 472 | 
            -
             | 
| 951 | 
            +
            それに伴い、{RangeExtd} のバージョンを2.0にあげました。
         | 
| 473 952 |  | 
| 953 | 
            +
            以下が、その主な変更点です。詳しくは、「履歴メモ」章を参照ください。
         | 
| 474 954 |  | 
| 475 | 
            -
             | 
| 955 | 
            +
            ==== News: Beginless Range サポートしました
         | 
| 476 956 |  | 
| 477 | 
            -
             | 
| 478 | 
            -
             | 
| 957 | 
            +
            Ruby 2.7 で始端のない {Beginless range}[https://rubyreferences.github.io/rubychanges/2.7.html#beginless-range]
         | 
| 958 | 
            +
            がサポートされました。
         | 
| 959 | 
            +
            +RangeExtd+ も今やサポートします。この影響で、仕様に重要な変更があります。
         | 
| 960 | 
            +
             | 
| 961 | 
            +
            まず、{RangeExtd::NONE} は、事実上
         | 
| 962 | 
            +
            +RangeExtd((RangeExtd::Nowhere::NOWHERE...RangeExtd::Nowhere::NOWHERE), true)+
         | 
| 963 | 
            +
            になりました。すなわち、両端が
         | 
| 964 | 
            +
            {RangeExtd::Nowhere::NOWHERE} であり、
         | 
| 965 | 
            +
            両端({RangeExtd#begin} と {RangeExtd#end})とも除外されています。
         | 
| 966 | 
            +
            以前のバージョンでは、{RangeExtd::NONE} の両端は +nil+ でした。
         | 
| 967 | 
            +
            Range +(nil..nil)+ は、Ruby-2.6 およびそれ以前ではそもそも許されていな
         | 
| 968 | 
            +
            くて、そのために{RangeExtd::NONE}に独特な表記として幸便だったものです。
         | 
| 969 | 
            +
            しかし、Ruby-2.7 以降では nil から nil のRangeが許容されます。つまり、
         | 
| 970 | 
            +
            +(nil..nil)+ は完全に正当であり、それは {RangeExtd::NONE} を表していた
         | 
| 971 | 
            +
            +RangeExtd((nil...nil), true)+ と事実上同じになってしまいます。前者は、
         | 
| 972 | 
            +
            後者とはまったく異なるオブジェクトであり、(除外フラグをのぞけば)むしろ
         | 
| 973 | 
            +
            {RangeExtd::ALL} に極めて近いにも拘らずです。だから、変更が必要になったのです。
         | 
| 974 | 
            +
             | 
| 975 | 
            +
            もっとも、この変更は概念的なものであり、ユーザー視点ではほぼ変更は見えません。
         | 
| 976 | 
            +
            {RangeExtd::NONE}の始端と終端である {RangeExtd::Nowhere::NOWHERE} は、
         | 
| 977 | 
            +
            {NilClass} とほぼまったく同じように振る舞います(以下の「詳説」章を参照)。
         | 
| 978 | 
            +
            {RangeExtd} Ver.1以前でその値はまさに +nil+ だったことを考えれば、
         | 
| 979 | 
            +
            Ver.2で{RangeExtd::Nowhere::NOWHERE} が{RangeExtd::NONE}
         | 
| 980 | 
            +
            に使われるようになったと言っても、今まで動いていたコードには何の変更も必要ないはずです。
         | 
| 981 | 
            +
            オブジェクトが{RangeExtd::NONE} かどうかをチェックする推奨方法は、
         | 
| 982 | 
            +
            今までもずっとそうだったように、{RangeExtd#is_none?} です
         | 
| 983 | 
            +
            (+Enumerable#none?+とは異なるのでご注意)。実用的には、
         | 
| 984 | 
            +
            {Range#null?} がユーザーが希望する挙動であることが大半でしょう
         | 
| 985 | 
            +
            (注: +(true..true).null?+ は偽(+false+)を返すことに注意。
         | 
| 986 | 
            +
            本マニュアルの「詳説」章の「RangeExtd Class」を参照)。
         | 
| 987 | 
            +
             | 
| 988 | 
            +
            次に、+RangeExtd.valid?(nil..)+ は、真(+true+)を返すようになりました。
         | 
| 989 | 
            +
            以前は、偽を返していました。そしてそれは {RangeExtd::ALL} に等しいです。
         | 
| 990 | 
            +
             | 
| 991 | 
            +
            たとえば、+"abc"[nil..]+ は以前のバージョンでは不正もしくは文法エラー
         | 
| 992 | 
            +
            さえ出ていましたが、Ruby-2.7以降では完全に正当なRuby表現です。
         | 
| 993 | 
            +
            したがって、もし仮に+RangeExtd+ がそれらを正当でないと見做したならば、
         | 
| 994 | 
            +
            不自然に受け取られるでしょう。
         | 
| 479 995 |  | 
| 480 | 
            -
             | 
| 996 | 
            +
            +RangeExtd.valid?(true..)+ は、依然 +false+ を返します。
         | 
| 481 997 |  | 
| 482 | 
            -
             | 
| 483 | 
            -
            {Rangeary}[https://rubygems.org/gems/rangeary] は、本ライブラリを使い
         | 
| 484 | 
            -
            切っています。Rangeを実現するためには、始端と終端との両方で開いた可能
         | 
| 485 | 
            -
            性があるRangeを扱うことが必須だからです。例えば、
         | 
| 486 | 
            -
            Range +(?a..?d)+ の否定は、複数Range +(-"Infinity(文字)"...3)+ と
         | 
| 487 | 
            -
            +(?d(始端除外).."Infinity(文字)")+ であり、その否定は、元の +(?a..?d)+
         | 
| 488 | 
            -
            です。このような演算は、+RangeExtd+ があって初めて可能になります。
         | 
| 998 | 
            +
            他の大きな変更には以下があります。
         | 
| 489 999 |  | 
| 490 | 
            -
             | 
| 1000 | 
            +
            * +RangeExtd::Infinity#succ+ はFloatクラスに合わせて未定義になりました。
         | 
| 1001 | 
            +
            * +Object+ と +Numeric+ クラスの拡張はデフォルトではなく、オプション(ユーザーの選択)となりました。
         | 
| 1002 | 
            +
            * +RangeExtd#eql?+ はRubyの標準([#hash]値を比較)にそうようにし、今まであった{RangeExtd::NONE}との特別な比較ルーチンを削除しました。
         | 
| 1003 | 
            +
            * +RangeExtd#min_by+ (+max_by+ と +minmax_by+) のバグを修正しました。
         | 
| 1004 | 
            +
             | 
| 1005 | 
            +
            ==== News: Endless Range サポートしました
         | 
| 1006 | 
            +
             | 
| 1007 | 
            +
            2019年10月より、本パッケージは、Ruby 2.6 で導入された {Endless Range}[https://rubyreferences.github.io/rubychanges/2.6.html#endless-range-1]
         | 
| 1008 | 
            +
            (終端のない Range)を正式サポートしました。よって、Version 1.0 をリリースしました!
         | 
| 1009 | 
            +
             | 
| 1010 | 
            +
            Ruby 2.7 では、{Beginless range}[https://rubyreferences.github.io/rubychanges/2.7.html#beginless-range] が導入されました.
         | 
| 491 1011 |  | 
| 492 1012 | 
             
            ==== 注: Rangesmallerとの関係
         | 
| 493 1013 |  | 
| 494 1014 | 
             
            このパッケージは、(今やサポートされていない) {Rangesmaller}[https://rubygems.org/gems/rangesmaller] パッケージ及びクラスを
         | 
| 495 1015 | 
             
            後継するものです。同クラスの機能に、無限に開いた範囲を許す機能が加わり、また、オ
         | 
| 496 1016 | 
             
            ブジェクト生成時のインターフェースが変更されています。
         | 
| 497 | 
            -
            https://rubygems.org/gems/rangesmaller
         | 
| 1017 | 
            +
            {https://rubygems.org/gems/rangesmaller}
         | 
| 1018 | 
            +
             | 
| 1019 | 
            +
             | 
| 1020 | 
            +
            == 背景
         | 
| 1021 | 
            +
             | 
| 1022 | 
            +
            === Endless Range と Beginless Range
         | 
| 1023 | 
            +
             | 
| 1024 | 
            +
            {Endless Range}[https://rubyreferences.github.io/rubychanges/2.6.html#endless-range-1]
         | 
| 1025 | 
            +
            (終端のないRange)と
         | 
| 1026 | 
            +
            {Beginless Range}[https://rubyreferences.github.io/rubychanges/2.7.html#beginless-range]
         | 
| 1027 | 
            +
            (始端のないRange)はそれぞれ
         | 
| 1028 | 
            +
            2018年12月および2019年12月リリースの Ruby 2.6 と 2.7 で導入されました。
         | 
| 1029 | 
            +
             | 
| 1030 | 
            +
            そのおかげで、Rubyの組込み+Range+ は、+RangeExtd+ が提供していた機能の
         | 
| 1031 | 
            +
            いくつかを持つようになりました。
         | 
| 1032 | 
            +
            ただし、今でも、明快なものも微妙なものも含めていくつかの違いがあります。
         | 
| 1033 | 
            +
             | 
| 1034 | 
            +
            本ライブラリのはっきりとした利点は、+exclude_begin?+ (つまり始端を除外する)機能です。
         | 
| 1035 | 
            +
             | 
| 1036 | 
            +
            境界のないRangeについては、本ライブラリが提供するものは、一言で言えば、
         | 
| 1037 | 
            +
            抽象的な意味で無限に開いたレンジです。
         | 
| 1038 | 
            +
            概念的な主な違いは、Rubyの組込み+Range+ は*未定義*の境界を表すのに対し、
         | 
| 1039 | 
            +
            +RangeExtd+ は*無限に開いた*境界を表します。
         | 
| 1040 | 
            +
             | 
| 1041 | 
            +
            この違いは微妙ながら、はっきりとした意味があります。
         | 
| 1042 | 
            +
            以下に、標準Rubyの特にNumericのRangeを例示します。というのも、Numeric
         | 
| 1043 | 
            +
            はこの両方を提供しているために、違いがわかりやすいのです。
         | 
| 1044 | 
            +
             | 
| 1045 | 
            +
              "abcdef"[..2]   # => "abc"
         | 
| 1046 | 
            +
              "abcdef"[..2.0] # => "abc"
         | 
| 1047 | 
            +
              "abcdef"[(-Float::INFINITY)..2]  # raise (RangeError)
         | 
| 1048 | 
            +
              "abcdef"[(-1)..2] # => ""
         | 
| 1049 | 
            +
              "abcdef"[(-6)..2] # => "abc"
         | 
| 1050 | 
            +
              "abcdef"[(-7)..2] # => nil
         | 
| 1051 | 
            +
              (-Float::INFINITY..5).first(1) # raise: can't iterate from Float (TypeError)
         | 
| 1052 | 
            +
              (-Float::INFINITY..5).first    # => -Infinity
         | 
| 1053 | 
            +
              (-Float::INFINITY..5).begin    # => -Infinity
         | 
| 1054 | 
            +
              (..5).first   # raise: cannot get the first element of beginless range (RangeError)
         | 
| 1055 | 
            +
              (..5).begin   # => nil
         | 
| 1056 | 
            +
             | 
| 1057 | 
            +
            最初、そして2番目の式に出てくるのが始端のないRangeで、始端が未定義です。
         | 
| 1058 | 
            +
            Stringクラスは、その「始点の値」を0だと*解釈*しています。
         | 
| 1059 | 
            +
            対照的に、3番目の式では、例外が発生しています。この仕様は、
         | 
| 1060 | 
            +
            始点の値が定義されていて、でも負の無限大だから、と考えれば、理解できます。
         | 
| 1061 | 
            +
            実際、Stringの場合、負の数の添字は、(4番目、6番目の例にあるように)
         | 
| 1062 | 
            +
            特別な意味を持っていますからね。
         | 
| 1063 | 
            +
             | 
| 1064 | 
            +
            最後の5つの例は、興味深いです。
         | 
| 1065 | 
            +
            +Range#begin+ は単純に始点の値を返します。
         | 
| 1066 | 
            +
            +Range#first+ は引数が与えられなければ、最初の「要素」を返します。
         | 
| 1067 | 
            +
            +(Float::INFINITY..5)+ には最初の要素があるため、それが返されます。
         | 
| 1068 | 
            +
            しかしbeginless {Range} では話が異なります。定義された最初の要素がないため、
         | 
| 1069 | 
            +
            +Range#first+ は、+RangeError+ 例外を発生させます。対照的に、
         | 
| 1070 | 
            +
            引数 +n+ が +Range#first+ に与えられた時は、+n+個の要素を持つ配列
         | 
| 1071 | 
            +
            (Array)が返されなければなりません。Floatから値を数えるのは未定義であるため、
         | 
| 1072 | 
            +
            負の無限大からのRangeの場合は、+TypeError+ 例外が発生します。
         | 
| 1073 | 
            +
            筋が通っていると思いませんか?
         | 
| 1074 | 
            +
             | 
| 1075 | 
            +
            ところで、補足すると、+(5..8.6).last(2)+ は正当であって配列 +[7, 8]+
         | 
| 1076 | 
            +
            を返します。また、+(2.2..8.6).size+ も(なぜか?)正当です。混乱しますね……。
         | 
| 1077 | 
            +
             | 
| 1078 | 
            +
            別のポイントとして、無限大には明快な数学的定義がありますが、
         | 
| 1079 | 
            +
            すべてのRangeがそれを認めるわけではありません。たとえば、
         | 
| 1080 | 
            +
            自作クラスで、アルファベット小文字1文字だけを持ち、
         | 
| 1081 | 
            +
            Stringクラスと同様にRangeが定義できる例を考えてみます。
         | 
| 1082 | 
            +
            すると、最小の始端と最大の終端は、それぞれ"+a+"と"+z+"です。
         | 
| 1083 | 
            +
            この場合、「無限大」(あるいは無限小)とは何を意味するでしょうか?
         | 
| 1084 | 
            +
            厳密な意味では、それは不正とすべきでしょうか。あるいは、
         | 
| 1085 | 
            +
            この場合の無限大は"+z+"を表す数と解釈すべきでしょうか?
         | 
| 1086 | 
            +
            それとも別のなにか?
         | 
| 1087 | 
            +
             | 
| 1088 | 
            +
            概念としては、包括的な解釈のほうが便利です。実際、
         | 
| 1089 | 
            +
            {Rangeary}[https://rubygems.org/gems/rangeary] ライブラリは、
         | 
| 1090 | 
            +
            +RangeExtd+ をそのように利用しています。すなわち、
         | 
| 1091 | 
            +
            Range の「否定」(補集合)を積極的に用いて、複数Ranges
         | 
| 1092 | 
            +
            の論理演算を実現しています。しかし、
         | 
| 1093 | 
            +
            すべてのアプリケーションにそう解釈することを強要することはできません。
         | 
| 1094 | 
            +
             | 
| 1095 | 
            +
            まとめると、*未定義*境界は定義上未定義であり、その解釈はアプリケーション任せになるのに対し、
         | 
| 1096 | 
            +
            正負の無限大境界は明快な定義はあるかも知れないけれど、実際の応用では柔軟な解釈が望ましい場合もあるかもしれない、
         | 
| 1097 | 
            +
            というところです。
         | 
| 1098 | 
            +
             | 
| 1099 | 
            +
            これらを考慮し、本ライブラリの
         | 
| 1100 | 
            +
            {RangeExtd::Infinity::NEGATIVE} と {RangeExtd::Infinity::POSITIVE}
         | 
| 1101 | 
            +
            とは、事実上 +nil+ のように振る舞うようにデザインされています。ただし、
         | 
| 1102 | 
            +
            ユーザーが別扱いすることは可能です。
         | 
| 1103 | 
            +
             | 
| 1104 | 
            +
            === endless and beginless Rangesの振舞い
         | 
| 1105 | 
            +
             | 
| 1106 | 
            +
            組込み Endless/Beginless Range の振舞いは幾分混乱するところがあります。
         | 
| 1107 | 
            +
            加えて、+Range#size+にはバグが複数あるようです
         | 
| 1108 | 
            +
            ({Bug #18983}[https://bugs.ruby-lang.org/issues/18983] と
         | 
| 1109 | 
            +
             {Bug #18993}[https://bugs.ruby-lang.org/issues/18993])。
         | 
| 1110 | 
            +
            少なくとも、公式マニュアルに記載されている仕様とは矛盾する振舞いがあり、
         | 
| 1111 | 
            +
            混乱に拍車をかけます。
         | 
| 1112 | 
            +
             | 
| 1113 | 
            +
            Rubyの実装では、beginless/endless Rangesの始端と終端の値は、
         | 
| 1114 | 
            +
            +nil+ と解釈されます。 Rubyでは +nil == nil+ が真であるために、
         | 
| 1115 | 
            +
             | 
| 1116 | 
            +
              (?a..).end == (5..).end
         | 
| 1117 | 
            +
             | 
| 1118 | 
            +
            も真です。一方、
         | 
| 1119 | 
            +
             | 
| 1120 | 
            +
              (?a..).end == (5..Float::INFINITY).end
         | 
| 1121 | 
            +
             | 
| 1122 | 
            +
            は偽(+false+)です。以下が幅広い例です。
         | 
| 1123 | 
            +
             | 
| 1124 | 
            +
              (-Float::INFINITY..Float::INFINITY).size  # => Infinity
         | 
| 1125 | 
            +
              ( Float::INFINITY..Float::INFINITY).size  # raises FloatDomainError
         | 
| 1126 | 
            +
              num1 = (5..Float::INFINITY)
         | 
| 1127 | 
            +
              num2 = (5..)
         | 
| 1128 | 
            +
              num1.end != num2.end  # => true
         | 
| 1129 | 
            +
              num1.size              # => Infinity
         | 
| 1130 | 
            +
              num2.size              # => Infinity
         | 
| 1131 | 
            +
             | 
| 1132 | 
            +
              str1 = (?a..)
         | 
| 1133 | 
            +
              str1.end != num1.end   # => true
         | 
| 1134 | 
            +
              str1.end == num2.end   # => true (because both are nil)
         | 
| 1135 | 
            +
              str1.size              # => nil  (because Range#size is defined for Numeric only)
         | 
| 1136 | 
            +
              (..?z).size            # => Infinity  (contradicting the specificatin?)
         | 
| 1137 | 
            +
             | 
| 1138 | 
            +
              (..3).to_s    => "..3"
         | 
| 1139 | 
            +
              (3..).to_s    => "3.."
         | 
| 1140 | 
            +
              (3..nil).to_s => "3.."
         | 
| 1141 | 
            +
              (nil..3).to_s => "..3"
         | 
| 1142 | 
            +
             | 
| 1143 | 
            +
              (nil..) == (..nil)   # => true
         | 
| 1144 | 
            +
              (nil..) != (...nil)  # => true  (because exclude_end? differ)
         | 
| 1145 | 
            +
              "abcdef"[..nil]      # => "abcdef" (i.e., it is interpreted as (0..IntegerInfinity)
         | 
| 1146 | 
            +
                                   #    (n.b., nil.to_i==0; Integer(nil) #=> TypeError))
         | 
| 1147 | 
            +
              "abcdef"[..?a]       # raise: no implicit conversion of String into Integer (TypeError)
         | 
| 1148 | 
            +
              "abcdef"[0..100]     # => "abcdef"
         | 
| 1149 | 
            +
              "abcdef"[-100..100]  # => nil
         | 
| 1150 | 
            +
             | 
| 1151 | 
            +
              (..nil).size   # => Float::INFINITY
         | 
| 1152 | 
            +
             | 
| 1153 | 
            +
              (..nil).begin  # => nil
         | 
| 1154 | 
            +
              (..nil).first  # raise: cannot get the first element of beginless range (RangeError)
         | 
| 1155 | 
            +
              (..nil).last   # raise: cannot get the last element of endless range (RangeError)
         | 
| 1156 | 
            +
              (..nil).end    # => nil
         | 
| 1157 | 
            +
             | 
| 1158 | 
            +
              (..nil).cover? 5    # => true
         | 
| 1159 | 
            +
              (..nil).cover? ?a   # => true
         | 
| 1160 | 
            +
              (..nil).cover? [?a] # => true
         | 
| 1161 | 
            +
              (..nil).cover? nil  # => true
         | 
| 1162 | 
            +
             | 
| 1163 | 
            +
            Integerクラスならば、
         | 
| 1164 | 
            +
             | 
| 1165 | 
            +
              num1 = (5..Float::INFINITY)
         | 
| 1166 | 
            +
              num2 = (5..)
         | 
| 1167 | 
            +
              num1.end != num2.end  # => true (because (Float::INFINITY != nil))
         | 
| 1168 | 
            +
              num1.size              # => Float::INFINITY
         | 
| 1169 | 
            +
              num2.size              # => Float::INFINITY
         | 
| 1170 | 
            +
             | 
| 1171 | 
            +
              (3...) == (3...nil)    # => true
         | 
| 1172 | 
            +
              (3..)  != (3...nil)    # => true  (because exclude_end? differ)
         | 
| 1173 | 
            +
             | 
| 1174 | 
            +
              (3..).size   # => Float::INFINITY
         | 
| 1175 | 
            +
              (..3).begin  # => nil
         | 
| 1176 | 
            +
              (..3).first  # raise: cannot get the first element of beginless range (RangeError)
         | 
| 1177 | 
            +
              (3..).last   # raise: cannot get the last element of endless range (RangeError)
         | 
| 1178 | 
            +
              (3..).end    # => nil
         | 
| 1179 | 
            +
              (..3).each{} # raise: `each': can't iterate from NilClass (TypeError)
         | 
| 1180 | 
            +
              (..3).to_a   # raise: `each': can't iterate from NilClass (TypeError)
         | 
| 1181 | 
            +
              (3..).to_a   # raise: `to_a': cannot convert endless range to an array (RangeError)
         | 
| 1182 | 
            +
              (3..Float::INFINITY).to_a  # Infinite loop!
         | 
| 1183 | 
            +
             | 
| 1184 | 
            +
              (-Float::INFINITY..4).first    # => -Float::INFINITY
         | 
| 1185 | 
            +
              (4..Float::INFINITY).last      # =>  Float::INFINITY
         | 
| 1186 | 
            +
              (-Float::INFINITY..4).first(2) # raise: can't iterate from Float (TypeError)
         | 
| 1187 | 
            +
              (4..Float::INFINITY).last(2)   # Infinite loop!
         | 
| 1188 | 
            +
             | 
| 1189 | 
            +
            Stringクラス(あるいはユーザー定義クラス?)ならば、
         | 
| 1190 | 
            +
             | 
| 1191 | 
            +
              (?a..).end   == (5..).end   # => true (because both are nil)
         | 
| 1192 | 
            +
              (?a..).end   != (5..Float::INFINITY).end      # => true
         | 
| 1193 | 
            +
              (..?a).begin == (..5).begin # => true (because both are nil)
         | 
| 1194 | 
            +
              (..?a).begin != ((-Float::INFINITY)..5).begin # => true
         | 
| 1195 | 
            +
              (..?a).size  # => Float::INFINITY
         | 
| 1196 | 
            +
              (?a..).size  # => nil
         | 
| 1197 | 
            +
             | 
| 1198 | 
            +
              (..?a).begin  # => nil
         | 
| 1199 | 
            +
              (..?a).first  # raise: cannot get the first element of beginless range (RangeError)
         | 
| 1200 | 
            +
              (?a..).last   # raise: cannot get the last element of endless range (RangeError)
         | 
| 1201 | 
            +
              (?a..).end    # => nil
         | 
| 1202 | 
            +
              (..?a).each{} # raise: `each': can't iterate from NilClass (TypeError)
         | 
| 1203 | 
            +
              (..?a).to_a   # raise: `each': can't iterate from NilClass (TypeError)
         | 
| 1204 | 
            +
              (?a..).to_a   # raise: `to_a': cannot convert endless range to an array (RangeError)
         | 
| 1205 | 
            +
              (?a..Float::INFINITY).to_a  # raise: bad value for range (ArgumentError)  # b/c it is not String!
         | 
| 1206 | 
            +
             | 
| 1207 | 
            +
            === Range#size についての注記
         | 
| 1208 | 
            +
             | 
| 1209 | 
            +
            +Range#size+ の振舞いはとてもわかりにくいです。
         | 
| 1210 | 
            +
            {公式マニュアル}[https://ruby-doc.org/core-3.1.2/Range.html#method-i-size] によれば、
         | 
| 1211 | 
            +
             | 
| 1212 | 
            +
              Returns the count of elements in self if both begin and end values are numeric;
         | 
| 1213 | 
            +
              otherwise, returns nil
         | 
| 1214 | 
            +
             | 
| 1215 | 
            +
            しかし、実際のRubyの挙動は必ずしもこの通りではありません(上述の例参照)。
         | 
| 1216 | 
            +
            加えて、一般のNumeric に対して"elements"が一体何かは不明瞭です。
         | 
| 1217 | 
            +
            だから、Stringならば必ずnilが買える
         | 
| 1218 | 
            +
            以下が一例です({Bug #18993}[https://bugs.ruby-lang.org/issues/18993] として報告済):
         | 
| 1219 | 
            +
             | 
| 1220 | 
            +
              (5.quo(3)...5).size      # => 3
         | 
| 1221 | 
            +
              (5.quo(3).to_f...5).size # => 4
         | 
| 1222 | 
            +
              (5.quo(3)..5).size       # => 4
         | 
| 1223 | 
            +
              (5.quo(3).to_f..5).size  # => 4
         | 
| 1224 | 
            +
             | 
| 1225 | 
            +
            === Range#count についての注記
         | 
| 1226 | 
            +
             | 
| 1227 | 
            +
            +Range#count+ の振舞いの大半は理解できます。しかし、
         | 
| 1228 | 
            +
            境界のないものや無限大関係は自明ではありません。
         | 
| 1229 | 
            +
             | 
| 1230 | 
            +
              (5..).count             # => Float::INFINITY
         | 
| 1231 | 
            +
              (..5).count             # => Float::INFINITY
         | 
| 1232 | 
            +
              (..nil).count           # => Float::INFINITY
         | 
| 1233 | 
            +
              (-Float::INFINITY..nil) # => Float::INFINITY
         | 
| 1234 | 
            +
              (-Float::INFINITY..Float::INFINITY).count  # raises (TypeError) "can't iterate from Float"
         | 
| 1235 | 
            +
              (..5).count(4)          # raises (TypeError)
         | 
| 1236 | 
            +
              (..5).count{|i| i<3}    # raises (TypeError)
         | 
| 1237 | 
            +
              (1..).count(4)          # infinite loop!
         | 
| 1238 | 
            +
              (1..).count{|i| i<3}    # infinite loop!
         | 
| 1239 | 
            +
             | 
| 1240 | 
            +
            端的には、一部の特別なケースについては、同メソッドは Infinity (無限大)を返します。
         | 
| 1241 | 
            +
             | 
| 1242 | 
            +
            これを考慮して本ライブラリの+RangeExtd::ALL.count+ は、特別なケースとして、
         | 
| 1243 | 
            +
            returns +Float::INFINITY+ を返します。
         | 
| 1244 | 
            +
             | 
| 498 1245 |  | 
| 499 1246 | 
             
            == インストール
         | 
| 500 1247 |  | 
| 501 1248 | 
             
              gem install range_extd
         | 
| 502 1249 |  | 
| 503 | 
            -
             | 
| 1250 | 
            +
            により、
         | 
| 504 1251 |  | 
| 505 | 
            -
              range_extd | 
| 506 | 
            -
              range_extd/infinity | 
| 1252 | 
            +
              range_extd.rb
         | 
| 1253 | 
            +
              range_extd/infinity.rb
         | 
| 507 1254 |  | 
| 508 | 
            -
             | 
| 1255 | 
            +
            をはじめとした数個のファイルが<tt>$LOAD_PATH</tt> の一カ所にインストールされるはずです。
         | 
| 509 1256 |  | 
| 510 | 
            -
             | 
| 511 | 
            -
             | 
| 512 | 
            -
              http://rubygems.org/gems/range_extd
         | 
| 1257 | 
            +
            あるいは、パッケージを{http://rubygems.org/gems/range_extd}から入手できます。
         | 
| 513 1258 |  | 
| 514 1259 | 
             
            後は、Ruby のコード(又は irb)から
         | 
| 515 1260 |  | 
| 516 | 
            -
              require  | 
| 517 | 
            -
             | 
| 518 | 
            -
            とするだけです。もしくは、特に手でインストールした場合は、
         | 
| 1261 | 
            +
              require "range_extd/load_all"
         | 
| 519 1262 |  | 
| 520 | 
            -
             | 
| 1263 | 
            +
            とするだけです。もしくは、本ライブラリのの最小限セットだけ使う場合は、
         | 
| 521 1264 |  | 
| 522 | 
            -
             | 
| 1265 | 
            +
              require "range_extd"
         | 
| 523 1266 |  | 
| 524 | 
            -
             | 
| 1267 | 
            +
            でもいいです。
         | 
| 1268 | 
            +
            端的には "+range_extd/load_all.rb+" は、ラッパーであり、以下のファイルを読み込みます:
         | 
| 525 1269 |  | 
| 526 | 
            -
             | 
| 1270 | 
            +
              require "range_extd"
         | 
| 1271 | 
            +
              require "range_extd/numeric"
         | 
| 1272 | 
            +
              require "range_extd/object"
         | 
| 1273 | 
            +
              require "range_extd/infinity"
         | 
| 1274 | 
            +
              require "range_extd/nowhere"
         | 
| 1275 | 
            +
              require "range_extd/range"
         | 
| 1276 | 
            +
              require "range_extd/nil_class"
         | 
| 527 1277 |  | 
| 528 | 
            -
             | 
| 1278 | 
            +
            このうち、最初の3つは独立で、下の4つは一番上のファイルと必ず一緒に使われるもので、最初のファイルを読めば自動的に読み込まれます。
         | 
| 529 1279 |  | 
| 1280 | 
            +
            2番目と3番目のファイルは、ユーティリティライブラリです。読み込めば、
         | 
| 1281 | 
            +
            Ruby組込みクラスの +Object+ と +Numeric+ (+Float+ と +Integer+を含む)
         | 
| 1282 | 
            +
            にいくつかのメソッドが追加されたり機能が追加されます。
         | 
| 1283 | 
            +
            追加された機能はすべて後方互換であり、単に既存のクラスに機能を追加するだけです。
         | 
| 1284 | 
            +
            これらの読み込みを強く推奨します。もし読み込まない場合は、本ライブラリ
         | 
| 1285 | 
            +
            のパワーがごく限られてしまいます。たとえば、比較演算子+<=>+
         | 
| 1286 | 
            +
            が可換でないため、驚くような挙動になることがあるでしょう。
         | 
| 1287 | 
            +
            具体的な追加機能はそれぞれのマニュアルを参照ください。
         | 
| 530 1288 |  | 
| 531 1289 | 
             
            == 単純な使用例
         | 
| 532 1290 |  | 
| 1291 | 
            +
            以下の例では、ライブラリのすべてのファイルが読み込まれている(require)
         | 
| 1292 | 
            +
            と仮定します。
         | 
| 1293 | 
            +
             | 
| 533 1294 | 
             
            === RangeExtd インスタンスを作成する方法
         | 
| 534 1295 |  | 
| 535 1296 | 
             
            以下に幾つかの基本的な使用例を列挙します。
         | 
| 536 1297 |  | 
| 1298 | 
            +
               require "range_extd/load_all"
         | 
| 537 1299 | 
             
               r = RangeExtd(?a...?d, true)  # => a<...d
         | 
| 538 1300 | 
             
               r.exclude_begin?              # => true 
         | 
| 539 1301 | 
             
               r.to_a                        # => ["b", "c"]
         | 
| @@ -545,7 +1307,8 @@ https://rubygems.org/gems/rangesmaller | |
| 545 1307 | 
             
               (RangeExtd::Infinity::NEGATIVE..RangeExtd::Infinity::POSITIVE) \
         | 
| 546 1308 | 
             
                == RangeExtd::ALL  # => true
         | 
| 547 1309 |  | 
| 548 | 
            -
             | 
| 1310 | 
            +
            +RangeExtd+ のインスタンスを作成する方法が3通りあります(おそらく
         | 
| 1311 | 
            +
            最初のやり方が最も単純でタイプ量が少なく、かつ覚えやすいでしょう)。
         | 
| 549 1312 |  | 
| 550 1313 | 
             
               RangeExtd(range, [exclude_begin=false, [exclude_end=false]], opts)
         | 
| 551 1314 | 
             
               RangeExtd(obj_begin, obj_end, [exclude_begin=false, [exclude_end=false]], opts)
         | 
| @@ -553,7 +1316,7 @@ https://rubygems.org/gems/rangesmaller | |
| 553 1316 |  | 
| 554 1317 | 
             
            大括弧の中の二つのパラメーターが、それぞれ始点と終点とを除外する(true)、または含む
         | 
| 555 1318 | 
             
            (false)を指示します。もし、その二つのパラメーターが最初のパラメーターのレンジ
         | 
| 556 | 
            -
            (Range  | 
| 1319 | 
            +
            (+Range+ または +RangeExtd+) と矛盾する場合は、ここで与えた二つのパラメーターが優先され
         | 
| 557 1320 | 
             
            ます。同じパラメーターをオプションHash
         | 
| 558 1321 | 
             
            (<tt>:exclude_begin</tt> と <tt>:exclude_end</tt>)で指定することもできて、
         | 
| 559 1322 | 
             
            もし指定されればそれらが最高の優先度を持ちます。
         | 
| @@ -567,36 +1330,53 @@ https://rubygems.org/gems/rangesmaller | |
| 567 1330 |  | 
| 568 1331 | 
             
            === 少し上級編
         | 
| 569 1332 |  | 
| 570 | 
            -
               ( | 
| 1333 | 
            +
               RangeExtd((0..), true).each do |i|
         | 
| 571 1334 | 
             
                 print i
         | 
| 572 1335 | 
             
                 break if i >= 9
         | 
| 573 | 
            -
               end    # => self | 
| 574 | 
            -
             | 
| 1336 | 
            +
               end    # => self;  "123456789" => STDOUT
         | 
| 1337 | 
            +
                      # *NOT* "012..."
         | 
| 1338 | 
            +
               (nil..nil).valid?  # => true
         | 
| 575 1339 | 
             
               (1...1).valid?     # => false
         | 
| 576 1340 | 
             
               (1...1).null?      # => true
         | 
| 577 1341 | 
             
               RangeExtd.valid?(1...1)              # => false
         | 
| 578 1342 | 
             
               RangeExtd(1, 1, true, true).valid?   # => true
         | 
| 579 1343 | 
             
               RangeExtd(1, 1, true, true).empty?   # => true
         | 
| 580 1344 | 
             
               RangeExtd(?a, ?b, true, true).to_a?  # => []
         | 
| 581 | 
            -
               RangeExtd(?a, ?b, true, true). | 
| 1345 | 
            +
               RangeExtd(?a, ?b, true, true).null?  # => true  (empty? is same in this case)
         | 
| 582 1346 | 
             
               RangeExtd(?a, ?e, true, true).to_a?  # => ["b", "c", "d"]
         | 
| 583 | 
            -
               RangeExtd(?a, ?e, true, true). | 
| 1347 | 
            +
               RangeExtd(?a, ?e, true, true).null?  # => false
         | 
| 584 1348 | 
             
               RangeExtd::NONE.is_none?             # => true
         | 
| 1349 | 
            +
               RangeExtd(1...1, true) == RangeExtd::NONE # => true
         | 
| 585 1350 | 
             
               RangeExtd::ALL.is_all?               # => true
         | 
| 1351 | 
            +
               (nil..nil).is_all?                   # => false
         | 
| 1352 | 
            +
               (-Float::INFINITY..Float::INFINITY).is_all?    # => false
         | 
| 1353 | 
            +
               (nil..nil).equiv_all?                # => true
         | 
| 1354 | 
            +
               (-Float::INFINITY..Float::INFINITY).equiv_all? # => true
         | 
| 586 1355 | 
             
               (3...7).equiv?(3..6)    # => true
         | 
| 1356 | 
            +
               (nil..nil).equiv?(RangeExtd::ALL)    # => true
         | 
| 587 1357 |  | 
| 588 | 
            -
            組込Range | 
| 1358 | 
            +
            組込Rangeに含まれる全てのメソッドが、(子クラスである){RangeExtd}で使用可能です。
         | 
| 589 1359 |  | 
| 590 1360 |  | 
| 591 1361 | 
             
            == 詳説
         | 
| 592 1362 |  | 
| 593 | 
            -
            ファイル +range_extd | 
| 1363 | 
            +
            ファイル +range_extd.rb+ が読まれた段階で、次の3つのクラスが定義されます。
         | 
| 594 1364 |  | 
| 595 1365 | 
             
            * RangeExtd
         | 
| 596 1366 | 
             
            * RangeExtd::Infinity
         | 
| 1367 | 
            +
            * RangeExtd::Nowhere
         | 
| 1368 | 
            +
             | 
| 1369 | 
            +
            加えて、{Range} クラスと {NilClass}に数個のメソッドが追加また改訂されます。
         | 
| 1370 | 
            +
            これらに加えられる改訂は、全て後方互換性を保っています。
         | 
| 597 1371 |  | 
| 598 | 
            -
             | 
| 599 | 
            -
             | 
| 1372 | 
            +
            この時、{Range} の改訂は、原理的には{RangeExtd}と分離可能だと思います
         | 
| 1373 | 
            +
            (分離したい人がいるとは思えませんが!)が、{NilClass} の方は不可避です。
         | 
| 1374 | 
            +
            というのも、それなしには{RangeExtd::NONE}が定義不可能だからです。 
         | 
| 1375 | 
            +
            具体的には、初期化の時に+ArgumentError+ (bad value for range)
         | 
| 1376 | 
            +
            の例外が出てしまいます。Rubyの組込みのRangeの仕様のためです。
         | 
| 1377 | 
            +
             | 
| 1378 | 
            +
            {Stackoverflow上の議論}[https://stackoverflow.com/a/14449380/3577922]
         | 
| 1379 | 
            +
            を参考にあげておきます。
         | 
| 600 1380 |  | 
| 601 1381 | 
             
            === RangeExtd::Infinity クラス
         | 
| 602 1382 |  | 
| @@ -606,42 +1386,54 @@ https://rubygems.org/gems/rangesmaller | |
| 606 1386 | 
             
            * RangeExtd::Infinity::POSITIVE
         | 
| 607 1387 |  | 
| 608 1388 | 
             
            これらは、 <tt>Float::INFINITY</tt> を全ての Comparable なオブジェクトに一般化し
         | 
| 609 | 
            -
            たものです。メソッド <tt><=></tt | 
| 1389 | 
            +
            たものです。メソッド <tt><=></tt>が定義されています。
         | 
| 610 1390 |  | 
| 611 1391 | 
             
            これらは、他のオブジェクトと同様に普通に使用可能です。たとえば、
         | 
| 612 | 
            -
             | 
| 1392 | 
            +
             | 
| 1393 | 
            +
              (RangeExtd::Infinity::NEGATIVE.."k")
         | 
| 1394 | 
            +
             | 
| 613 1395 | 
             
            とはいえ、他には何もメソッドを持っていないため、 Range型のクラスの中以外での使用
         | 
| 614 1396 | 
             
            はおそらく意味がないでしょう。
         | 
| 615 1397 |  | 
| 616 1398 | 
             
            なお、Numericのオブジェクトに対しては、原則として <tt>Float::INFINITY</tt> の方
         | 
| 617 1399 | 
             
            を使って下さい。
         | 
| 618 1400 |  | 
| 619 | 
            -
            ユーザー定義のどの Comparable  | 
| 620 | 
            -
             | 
| 621 | 
            -
             | 
| 1401 | 
            +
            ユーザー定義のどの Comparable なクラスに属するどのオブジェクトも、比較
         | 
| 1402 | 
            +
            演算子が*標準的な方法で*実装されているという条件付きで、これら二定数と
         | 
| 1403 | 
            +
            可換的に比較可能です。「標準的」とは自分の知らないオブジェクトと比較す
         | 
| 1404 | 
            +
            る際には、上位クラス、究極的には+Object+クラスに判断を委譲する、という
         | 
| 1405 | 
            +
            意味です。
         | 
| 622 1406 |  | 
| 623 1407 | 
             
            さらに詳しくは、マニュアルを参照して下さい(YARD または RDoc形式で書かれた文書が
         | 
| 624 1408 | 
             
            コード内部に埋込まれていますし、{RubyGemsのウェブサイト}[http://rubygems.org/gems/range_extd]でも閲覧できます。
         | 
| 625 1409 |  | 
| 626 | 
            -
             | 
| 627 | 
            -
             | 
| 628 | 
            -
            { | 
| 629 | 
            -
             | 
| 630 | 
            -
             | 
| 631 | 
            -
             | 
| 632 | 
            -
             | 
| 1410 | 
            +
            === RangeExtd::Nowhere クラス
         | 
| 1411 | 
            +
             | 
| 1412 | 
            +
            {RangeExtd::Nowhere} は{NilClass}のように振舞うシングルトンクラスです。
         | 
| 1413 | 
            +
            唯一のインスタンスが
         | 
| 1414 | 
            +
             | 
| 1415 | 
            +
            * RangeExtd::Nowhere::NOWHERE
         | 
| 1416 | 
            +
             | 
| 1417 | 
            +
            として定義されています。このインスタンスは、たとえば +nil?+ に真を返し、
         | 
| 1418 | 
            +
            また+nil+ と同じ object-ID を +object_id+ で返し、nil と等しい(+==+)
         | 
| 1419 | 
            +
            です。これは、{RangeExtd::NONE} を構成するために使われます。
         | 
| 633 1420 |  | 
| 1421 | 
            +
            なお、Rubyの条件文では、このインスタンスは真(true)であり、偽(false)
         | 
| 1422 | 
            +
            ではありません。
         | 
| 1423 | 
            +
             | 
| 1424 | 
            +
            また、{RangeExtd::NONE} を除き、{RangeExtd::Nowhere::NOWHERE} を含む
         | 
| 1425 | 
            +
            Range は、"valid"では*ない*と判断されます(後述)。
         | 
| 634 1426 |  | 
| 635 1427 | 
             
            === RangeExtd クラス
         | 
| 636 1428 |  | 
| 637 | 
            -
            RangeExtd のインスタンスは、 Range | 
| 638 | 
            -
             | 
| 1429 | 
            +
            {RangeExtd} のインスタンスは、 {Range}と同じくイミュータブルです。だから、一度
         | 
| 1430 | 
            +
            インスタンスが生成されると、変化しません。
         | 
| 639 1431 |  | 
| 640 | 
            -
            インスタンスの生成方法は上述の通りです(「使用例」の章)。レンジとして"valid"(後述) | 
| 641 | 
            -
             | 
| 1432 | 
            +
            インスタンスの生成方法は上述の通りです(「使用例」の章)。レンジとして"valid"(後述)と
         | 
| 1433 | 
            +
            見なされない{RangeExtd} インスタンスを生成しようとすると、例外(<tt>ArgumentError</tt>)が発生し、
         | 
| 642 1434 | 
             
            失敗します。
         | 
| 643 1435 |  | 
| 644 | 
            -
             | 
| 1436 | 
            +
            このクラスには、2つの定数が定義されています。
         | 
| 645 1437 |  | 
| 646 1438 | 
             
            * RangeExtd::NONE
         | 
| 647 1439 | 
             
            * RangeExtd::ALL
         | 
| @@ -656,7 +1448,7 @@ RangeExtd のインスタンスは、 Rangeと同じくイミュータブルで | |
| 656 1448 | 
             
            * <tt>valid?</tt> 
         | 
| 657 1449 | 
             
            * <tt>empty?</tt> 
         | 
| 658 1450 | 
             
            * <tt>null?</tt> 
         | 
| 659 | 
            -
            * <tt>is_none?</tt> | 
| 1451 | 
            +
            * <tt>is_none?</tt>
         | 
| 660 1452 | 
             
            * <tt>is_all?</tt> 
         | 
| 661 1453 | 
             
            * <tt>equiv?</tt> 
         | 
| 662 1454 |  | 
| @@ -667,24 +1459,37 @@ RangeExtd のインスタンスは、 Rangeと同じくイミュータブルで | |
| 667 1459 | 
             
            * <tt>RangeExtd.middle_strings=(ary)</tt> 
         | 
| 668 1460 | 
             
            * <tt>RangeExtd.middle_strings</tt> 
         | 
| 669 1461 |  | 
| 670 | 
            -
             | 
| 1462 | 
            +
            ==== 正当性、空かどうか、ヌルかどうかについての詳説
         | 
| 1463 | 
            +
             | 
| 1464 | 
            +
            何がレンジとして正当または有効 (<tt>#valid?</tt> => true) かの定義は以下です。
         | 
| 671 1465 |  | 
| 672 1466 | 
             
            1. 始点と終点とが互いに Comparable であり、かつその比較結果に矛盾がないこと。
         | 
| 673 | 
            -
                | 
| 674 | 
            -
                | 
| 1467 | 
            +
               この例外が3つあって、{RangeExtd::NONE}、(Ruby-2.7/2.6で導入された)Beginless/Endless Ranges で、
         | 
| 1468 | 
            +
               これらはすべて valid です。
         | 
| 1469 | 
            +
               たとえば、<tt>(nil..nil)</tt> は{RangeExtd} Ver.2.0+では valid です(参考までに、この例は
         | 
| 675 1470 | 
             
               Ruby 1.8 では例外を生じていました)。
         | 
| 676 | 
            -
            2.  | 
| 1471 | 
            +
            2. {RangeExtd::NONE} と Beginless Rangeを除き +Range#begin+ のオブジェクトはメソッド +<=+
         | 
| 1472 | 
            +
               を持たなければなりません。ゆえに、+(true..)+のようなEndless Ranges
         | 
| 1473 | 
            +
               (Ruby 2.6以上)はvalidでは*ありません*。
         | 
| 1474 | 
            +
               なお、"+true+" もメソッド +<=>+ を持っているため、+<=+ メソッドによる確認が不可欠です。
         | 
| 1475 | 
            +
            3. 同様に、{RangeExtd::NONE} と Endless Rangeを除き +Range#end+ のオブジェクトはメソッド +<=+
         | 
| 1476 | 
            +
               を持たなければなりません。ゆえに、+(..true)+のようなBeginless Ranges
         | 
| 1477 | 
            +
               (Ruby 2.7以上)はvalidでは*ありません*。
         | 
| 1478 | 
            +
            4. 始点は終点と等しい(<tt>==</tt>)か小さくなければなりません。すなわち、
         | 
| 677 1479 | 
             
               <tt>(begin <=> end)</tt> は、-1 または 0 を返すこと。
         | 
| 678 | 
            -
             | 
| 1480 | 
            +
            5. もし始点と終点とが等しい時、すなわち <tt>(begin <=> end) == 0</tt>ならば、
         | 
| 679 1481 | 
             
               端を除外するかどうかのフラグは両端で一致していなければなりません。
         | 
| 680 1482 | 
             
               すなわち、もし始点が除外ならば、終点も除外されていなくてはならず、逆も真です。
         | 
| 681 1483 | 
             
               その一例として、 <tt>(1...1)</tt> は、"valid" では「ありません」。なぜならば
         | 
| 682 1484 | 
             
               組込レンジでは、始点を常に含むからです。
         | 
| 1485 | 
            +
               +RangeExtd(1...1, true)+ は validで、{RangeExtd::NONE}と等しい(<tt>==</tt>)です。
         | 
| 1486 | 
            +
            6. {RangeExtd::NONE} 以外で{RangeExtd::Nowhere::NOWHERE} を含むRange
         | 
| 1487 | 
            +
               は、validでは*ありません*。
         | 
| 683 1488 |  | 
| 684 1489 | 
             
            さらなる詳細は {RangeExtd.valid?} と {Range#valid?} のマニュアルを
         | 
| 685 1490 | 
             
            参照して下さい。
         | 
| 686 1491 |  | 
| 687 | 
            -
            何がレンジとして空( | 
| 1492 | 
            +
            何がレンジとして空({Range#empty?} == +true+)かの定義は以下の通りです。
         | 
| 688 1493 |  | 
| 689 1494 | 
             
            1. レンジは、valid であること: <tt>valid?</tt> => true
         | 
| 690 1495 | 
             
            2. もしレンジの要素が離散的であれば、すなわち始点の要素がメソッド <tt>succ</tt>
         | 
| @@ -705,21 +1510,35 @@ RangeExtd のインスタンスは、 Rangeと同じくイミュータブルで | |
| 705 1510 |  | 
| 706 1511 | 
             
            最後、 {Range#null?} は、「<tt>empty?</tt> または "valid"でない」ことに等
         | 
| 707 1512 | 
             
            価です。従って、 RangeExtd オブジェクトにとっては、<tt>null?</tt> は
         | 
| 708 | 
            -
            <tt>empty?</tt>  | 
| 1513 | 
            +
            <tt>empty?</tt> に等価です。実用的には、ほとんどのケースにおいて、
         | 
| 1514 | 
            +
            {Range#null?} の方が、{Range#empty?}よりも有用でしょう。
         | 
| 709 1515 |  | 
| 710 1516 | 
             
            RangeExtd と別の RangeExtd または Rangeの比較 (<tt><=></tt>) においては、これら
         | 
| 711 1517 | 
             
            の定義が考慮されます。そのうちの幾つかは、上の「使用例」の項に示されています。
         | 
| 712 | 
            -
            さらなる詳細は {Range | 
| 713 | 
            -
            <tt>#eql?</tt> のマニュアルを参照して下さい。
         | 
| 1518 | 
            +
            さらなる詳細は {Range#<=>}、{RangeExtd#<=>} のマニュアルを参照して下さい。
         | 
| 714 1519 |  | 
| 715 1520 | 
             
            なお、処理が Rangeオブジェクト内部で閉じている限り、その振舞いは標準 Rubyと同一
         | 
| 716 1521 | 
             
            で、互換性を保っています。したがって、このライブラリを読込むことで既存のコードに
         | 
| 717 1522 | 
             
            影響を与えることは原理的にないはずです。
         | 
| 718 1523 |  | 
| 1524 | 
            +
            ==== 等価性
         | 
| 1525 | 
            +
             | 
| 1526 | 
            +
            メソッド +eql?+ は、Ruby標準ではハッシュ値を比較して等価性を判断するため、
         | 
| 1527 | 
            +
            基本的にオブジェクトのすべてのパラメーターが一致する必要があります。
         | 
| 1528 | 
            +
            一方、 <tt>==</tt> はもっと大雑把な比較を行います。以下が一例。
         | 
| 1529 | 
            +
             | 
| 1530 | 
            +
              RaE(0...0, true) == RaE(?a...?a, true)  # => false
         | 
| 1531 | 
            +
              RaE(0...1, true) == RaE(5...6, true)    # => true
         | 
| 1532 | 
            +
             | 
| 719 1533 |  | 
| 720 1534 | 
             
            == 既知のバグ
         | 
| 721 1535 |  | 
| 722 | 
            -
            *  | 
| 1536 | 
            +
            * {RangeExtd::Nowhere::NOWHERE} は、{RangeExtd} の文脈では使えません
         | 
| 1537 | 
            +
              (なぜならば{Range#valid?}が偽を返す)が、ユーザーは、Ruby組込み
         | 
| 1538 | 
            +
              {Range}の枠組み内だけで用いることは以前可能です。
         | 
| 1539 | 
            +
              {RangeExtd::Nowhere::NOWHERE} をnil以外の値として再定義した方が良いかも?
         | 
| 1540 | 
            +
            * このライブラリ Version 2+ は Ruby 2.6 およびそれ以前のバージョンでは動作しません。
         | 
| 1541 | 
            +
            * このライブラリ Version 1は Ruby 1.8 およびそれ以前のバージョンでは動作しません。
         | 
| 723 1542 | 
             
              Ruby 1.9.3 ではおそらく大丈夫でしょうが、私は試したことがありません。
         | 
| 724 1543 | 
             
            * いくつかの極めて稀な境界条件に於ける挙動は、Rubyのバージョンごとにあ
         | 
| 725 1544 | 
             
              る程度変化しています。例えば、Float::INFINITY 同士の比較などの挙動が
         | 
| @@ -729,35 +1548,94 @@ RangeExtd と別の RangeExtd または Rangeの比較 (<tt><=></tt>) におい | |
| 729 1548 | 
             
            * {RangeExtd#hash} メソッドは、ある RangeExtdオブジェに対して常に唯一で排他的な
         | 
| 730 1549 | 
             
              数値を返すことが理論保証はされていません。ただし、現実的にそれが破られることは、まず
         | 
| 731 1550 | 
             
              ありません。
         | 
| 1551 | 
            +
            * +RangeExtd::NONE.inspect+ と +RangeExtd::NONE.to_s+ はいずれも "Null<...Null"
         | 
| 1552 | 
            +
              を返すのだが、Ruby +irb+ では "nil...nil" と表示されてしまうために、
         | 
| 1553 | 
            +
              とても紛らわしい……。
         | 
| 732 1554 |  | 
| 733 1555 | 
             
            パッケージに含まれている通り、網羅的なテストが実行されています。
         | 
| 734 1556 |  | 
| 735 1557 |  | 
| 736 1558 | 
             
            == 開発項目
         | 
| 737 1559 |  | 
| 738 | 
            -
             | 
| 1560 | 
            +
            * もし {RangeExtd::Infinity::POSITIVE} (と NEGATIVE) が
         | 
| 1561 | 
            +
              ({RangeExtd::Nowhere::NOWHERE}が振舞うように)+nil+のように振る舞えば、
         | 
| 1562 | 
            +
              便利かも知れない。ただし、そのようなオブジェクトを含むRangeは、
         | 
| 1563 | 
            +
              Stringクラスに対してはたとえば<tt>"abcde"[my_nil..]</tt>などで、
         | 
| 1564 | 
            +
              同じようには動かない。Stringクラスは、+nil+について何か厳密なチェックを行っている
         | 
| 1565 | 
            +
              のだろう。だから、仮にそうデザインし直しても、Ruby組込みクラスとの
         | 
| 1566 | 
            +
              相性という意味では、使い勝手がずっと向上するということにはなりそうもない。
         | 
| 1567 | 
            +
            * "+similar+" というようなメソッドを定義すれば有用かもしれない。たとえば、
         | 
| 1568 | 
            +
              +(-Float::INFINITY..Float::INFINITY)+ と +(-Float::INFINITYnil...Float::INFINITY)+
         | 
| 1569 | 
            +
              とは、無限大(無限小)を除外することが無意味であるから、数学的に完全に同一である。
         | 
| 1570 | 
            +
              実際、これらと無限大を含まないRange/Rangearyとの演算の結果には何も影響を
         | 
| 1571 | 
            +
              及ぼすことがない。
         | 
| 739 1572 |  | 
| 740 1573 |  | 
| 741 1574 | 
             
            == 履歴メモ
         | 
| 742 1575 |  | 
| 743 1576 | 
             
            * <tt>((?a..?z) === "cc")</tt> は、Ruby 2.6.x 以前は false を返していたが、2.7 以降は true を返す。
         | 
| 1577 | 
            +
            * <tt>(Float::INFINITY..Float::INFINITY).size</tt> は以前は 0を返して
         | 
| 1578 | 
            +
              いた(少なくともRuby-2.1)が、少なくともRuby-2.6以降(Ruby 3含む)では、例外 +FloatDomainError: NaN+
         | 
| 1579 | 
            +
              を発生する。どのバージョンで変化したのかは私は知らない。
         | 
| 1580 | 
            +
             | 
| 1581 | 
            +
            === RangeExtd Ver.2
         | 
| 1582 | 
            +
             | 
| 1583 | 
            +
            * {RangeExtd} Ver.2において、Ver.1から、ライブラリのパスがディレクトリ
         | 
| 1584 | 
            +
             の階層一つ上がった。Ruby Gems の慣用にそうため。
         | 
| 1585 | 
            +
            * Ruby-2.7で導入されたBeginless Rangeに対応。
         | 
| 1586 | 
            +
            * +RangeExtd::Infinity#succ+ は未定義になった。Floatに合わせた。
         | 
| 1587 | 
            +
            * +Object+ と +Numeric+ クラスの拡張はデフォルトではなく、オプション化
         | 
| 1588 | 
            +
            * +RangeExtd#eql?+ は、Ruby標準(ハッシュ値[#hash]比較)にそうように未定化。{RangeExtd::NONE}を特別扱いすることを廃止。
         | 
| 1589 | 
            +
            * +RangeExtd#min_by+ (+max_by+ と +minmax_by+)のバグ修正。
         | 
| 1590 | 
            +
             | 
| 1591 | 
            +
            === RangeExtd Ver.1.1
         | 
| 1592 | 
            +
             | 
| 1593 | 
            +
            {RangeExtd} Ver.1.1 の時点で、the +RangeExtd::Infinity+ クラスの
         | 
| 1594 | 
            +
            インスタンスは +Float::INFINITY+ とは比較できない。
         | 
| 1595 | 
            +
             | 
| 1596 | 
            +
              RangeExtd::Infinity::POSITIVE != Float::INFINITY  # => true
         | 
| 1597 | 
            +
             | 
| 1598 | 
            +
            概念として、前者は後者よりもさらに一般化された概念であるから、*等しく*
         | 
| 1599 | 
            +
            あるべきでない。詳しくは {RangeExtd::Infinity} マニュアル参照。
         | 
| 1600 | 
            +
            Ruby 2.6以上のEndless Range の振舞いは、以下のように一部奇妙に感じるところがある。
         | 
| 1601 | 
            +
             | 
| 1602 | 
            +
              num1 = (5..Float::INFINITY)
         | 
| 1603 | 
            +
              num2 = (5..)
         | 
| 1604 | 
            +
              num1.end != num2.end  # => true
         | 
| 1605 | 
            +
              num1.size              # => Infinity
         | 
| 1606 | 
            +
              num2.size              # => Infinity
         | 
| 1607 | 
            +
             | 
| 1608 | 
            +
              str1 = (?a..)
         | 
| 1609 | 
            +
              str1.end == num2.end   # => true (because both are nil)
         | 
| 1610 | 
            +
              str1.size              # => nil
         | 
| 1611 | 
            +
             | 
| 1612 | 
            +
            === RangeExtd Ver.1.0
         | 
| 1613 | 
            +
             | 
| 1614 | 
            +
            **(注)** +RangeExtd::Infinity::POSITIVE+ は、
         | 
| 1615 | 
            +
            2018年12月に公式リリースされたRuby 2.6で導入された
         | 
| 1616 | 
            +
            {Endless Range}[https://rubyreferences.github.io/rubychanges/2.6.html#endless-range-1]
         | 
| 1617 | 
            +
            (終端のないRange)で実用上同一です!! 言葉を替えれば、公式Rubyがついに本
         | 
| 1618 | 
            +
            ライブラリの一部をサポートしました! ただし、公式Rubyには、
         | 
| 1619 | 
            +
            +RangeExtd::Infinity::NEGATIVE+ は依然ありません(始端のないRangeがない)。
         | 
| 1620 | 
            +
             | 
| 744 1621 |  | 
| 745 1622 | 
             
            == 終わりに
         | 
| 746 1623 |  | 
| 747 1624 | 
             
            RangeExtd内部に閉じた(Rangeでなく)挙動、たとえば RangeExtd同士の比較などは、
         | 
| 748 | 
            -
            全てユーザーにとって自然なもののはずです(と期待します?)。少なくとも、RangeExtdに
         | 
| 1625 | 
            +
            全てユーザーにとって自然なもののはずです(と期待します?)。少なくとも、{RangeExtd}に
         | 
| 749 1626 | 
             
            よってレンジの論理構造が完結した今、これはよく定義されかつ自己矛盾が無いものと言
         | 
| 750 | 
            -
             | 
| 751 | 
            -
             | 
| 752 | 
            -
             | 
| 753 | 
            -
             | 
| 754 | 
            -
             | 
| 755 | 
            -
             | 
| 756 | 
            -
             | 
| 757 | 
            -
             | 
| 758 | 
            -
             | 
| 759 | 
            -
             | 
| 760 | 
            -
             | 
| 1627 | 
            +
            えましょう。
         | 
| 1628 | 
            +
             | 
| 1629 | 
            +
            以前の版のこの章では、以下のように記述していました。
         | 
| 1630 | 
            +
             | 
| 1631 | 
            +
            > ただ、端の無限に開いた、あるいは始点が除外されたレンジの挙動には、一瞬ぎょっとするものが無くはないかも知れないことに注意して下さい。たとえば、片端が小さい方向に無限に開いて離散的な要素を持つレンジに対してメソッド<tt>member?(obj)</tt> を実行すると、 <tt>nil</tt>が返ります。これは、無限(小)には実質的な意味を持つ <tt>succ()</tt> メソッドが定義されていないためで、したがって与えられた objがレンジの要素(member)かどうかを調べることが、一般論としては理論的に不可能だからです。これはちょっと不思議に思うかも知れませんが、それはつまり定命の私たちには無限という概念を計り知るのが容易でない、というだけの話でしょう!
         | 
| 1632 | 
            +
             | 
| 1633 | 
            +
            ところが今や、Ruby本家に"beginless Range"組込まれたことで、すべての
         | 
| 1634 | 
            +
            Rubyプログラマーがこの概念に親しむことになりました。
         | 
| 1635 | 
            +
            これは進化と呼びたいです。
         | 
| 1636 | 
            +
             | 
| 1637 | 
            +
            とはいえ、RangeExtd と Range との比較は、時には驚きがあるかも知れません。
         | 
| 1638 | 
            +
            これは、組込Rangeクラスで許容されているレンジの一部は、始点を除外することを認めた
         | 
| 761 1639 | 
             
            枠組の中では、前述のように最早有効(valid)と見なされないからです。この枠組に慣れるに
         | 
| 762 1640 | 
             
            したがって、それらが自然だと思えるようになればいいのですが。保証しますが、一旦こ
         | 
| 763 1641 | 
             
            れに慣れてしまえば、論理的不完全さ極まる混沌とした世界、つまりは Rangeの現在の挙
         | 
| @@ -766,8 +1644,6 @@ RangeExtd内部に閉じた(Rangeでなく)挙動、たとえば RangeExtd同士 | |
| 766 1644 | 
             
            お楽しみ下さい。
         | 
| 767 1645 |  | 
| 768 1646 |  | 
| 769 | 
            -
            == その他
         | 
| 770 | 
            -
             | 
| 771 1647 | 
             
            == 著作権他情報
         | 
| 772 1648 |  | 
| 773 1649 | 
             
            著者::  Masa Sakano < info a_t wisebabel dot com >
         |