Class: Rigor::Type::IntegerRange
- Inherits:
-
Object
- Object
- Rigor::Type::IntegerRange
- Defined in:
- lib/rigor/type/integer_range.rb
Overview
A bounded integer range carrier. Each bound is either an ‘Integer` or one of the symbolic infinities `:neg_infinity` / `:pos_infinity`. Inspired by PHPStan’s ‘int<min, max>` family — the named aliases `positive-int` (1..), `non-negative-int` (0..), `negative-int` (..-1), `non-positive-int` (..0) all surface through this single carrier and are recovered in `describe` for human-friendly output.
Constraints on construction:
-
both bounds must be either ‘Integer` or one of the two infinity sentinels;
-
if both bounds are concrete, ‘min <= max` must hold;
-
the universal case ‘(-∞, +∞)` is structurally distinct from `Nominal` — it carries no extra information today but keeps the carrier closed under range narrowing.
Erasure to RBS is always “Integer”: RBS itself does not natively express bounded integer ranges.
Constant Summary collapse
- NEG_INFINITY =
:neg_infinity- POS_INFINITY =
:pos_infinity- INFINITIES =
[NEG_INFINITY, POS_INFINITY].freeze
- ALIAS_NAMES =
{ [NEG_INFINITY, POS_INFINITY] => "int", [1, POS_INFINITY] => "positive-int", [0, POS_INFINITY] => "non-negative-int", [NEG_INFINITY, -1] => "negative-int", [NEG_INFINITY, 0] => "non-positive-int" }.freeze
Instance Attribute Summary collapse
-
#max ⇒ Object
readonly
Returns the value of attribute max.
-
#min ⇒ Object
readonly
Returns the value of attribute min.
Instance Method Summary collapse
- #==(other) ⇒ Object (also: #eql?)
- #accepts(other, mode: :gradual) ⇒ Object
- #bot ⇒ Object
- #cardinality ⇒ Object
- #covers?(int) ⇒ Boolean
- #describe(_verbosity = :short) ⇒ Object
- #dynamic ⇒ Object
- #erase_to_rbs ⇒ Object
- #finite? ⇒ Boolean
- #generic_description ⇒ Object
- #hash ⇒ Object
-
#initialize(min, max) ⇒ IntegerRange
constructor
A new instance of IntegerRange.
- #inspect ⇒ Object
-
#lower ⇒ Object
Returns the lower bound as a numeric (with ‘-Float::INFINITY` for `:neg_infinity`).
- #top ⇒ Object
- #universal? ⇒ Boolean
- #upper ⇒ Object
Constructor Details
#initialize(min, max) ⇒ IntegerRange
Returns a new instance of IntegerRange.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/rigor/type/integer_range.rb', line 31 def initialize(min, max) validate_bound!(min, "min") validate_bound!(max, "max") if min.is_a?(Integer) && max.is_a?(Integer) && min > max raise ArgumentError, "IntegerRange requires min (#{min}) <= max (#{max})" end if min == POS_INFINITY || max == NEG_INFINITY raise ArgumentError, "IntegerRange bounds out of order: min=#{min.inspect}, max=#{max.inspect}" end @min = min @max = max freeze end |
Instance Attribute Details
#max ⇒ Object (readonly)
Returns the value of attribute max.
29 30 31 |
# File 'lib/rigor/type/integer_range.rb', line 29 def max @max end |
#min ⇒ Object (readonly)
Returns the value of attribute min.
29 30 31 |
# File 'lib/rigor/type/integer_range.rb', line 29 def min @min end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
114 115 116 |
# File 'lib/rigor/type/integer_range.rb', line 114 def ==(other) other.is_a?(IntegerRange) && min == other.min && max == other.max end |
#accepts(other, mode: :gradual) ⇒ Object
110 111 112 |
# File 'lib/rigor/type/integer_range.rb', line 110 def accepts(other, mode: :gradual) Inference::Acceptance.accepts(self, other, mode: mode) end |
#cardinality ⇒ Object
54 55 56 |
# File 'lib/rigor/type/integer_range.rb', line 54 def cardinality finite? ? (max - min + 1) : Float::INFINITY end |
#covers?(int) ⇒ Boolean
58 59 60 61 62 |
# File 'lib/rigor/type/integer_range.rb', line 58 def covers?(int) return false unless int.is_a?(Integer) int.between?(lower, upper) end |
#describe(_verbosity = :short) ⇒ Object
83 84 85 |
# File 'lib/rigor/type/integer_range.rb', line 83 def describe(_verbosity = :short) ALIAS_NAMES[[min, max]] || generic_description end |
#dynamic ⇒ Object
106 107 108 |
# File 'lib/rigor/type/integer_range.rb', line 106 def dynamic Trinary.no end |
#erase_to_rbs ⇒ Object
94 95 96 |
# File 'lib/rigor/type/integer_range.rb', line 94 def erase_to_rbs "Integer" end |
#finite? ⇒ Boolean
50 51 52 |
# File 'lib/rigor/type/integer_range.rb', line 50 def finite? min.is_a?(Integer) && max.is_a?(Integer) end |
#generic_description ⇒ Object
87 88 89 90 91 92 |
# File 'lib/rigor/type/integer_range.rb', line 87 def generic_description return "int<#{min}, max>" if max == POS_INFINITY return "int<min, #{max}>" if min == NEG_INFINITY "int<#{min}, #{max}>" end |
#hash ⇒ Object
119 120 121 |
# File 'lib/rigor/type/integer_range.rb', line 119 def hash [IntegerRange, min, max].hash end |
#inspect ⇒ Object
123 124 125 |
# File 'lib/rigor/type/integer_range.rb', line 123 def inspect "#<Rigor::Type::IntegerRange #{describe(:short)}>" end |
#lower ⇒ Object
Returns the lower bound as a numeric (with ‘-Float::INFINITY` for `:neg_infinity`). Use this in arithmetic comparisons; never compare `:neg_infinity` directly with an `Integer`.
67 68 69 |
# File 'lib/rigor/type/integer_range.rb', line 67 def lower min == NEG_INFINITY ? -Float::INFINITY : min end |
#universal? ⇒ Boolean
46 47 48 |
# File 'lib/rigor/type/integer_range.rb', line 46 def universal? min == NEG_INFINITY && max == POS_INFINITY end |
#upper ⇒ Object
71 72 73 |
# File 'lib/rigor/type/integer_range.rb', line 71 def upper max == POS_INFINITY ? Float::INFINITY : max end |