Class: Rigor::Type::IntegerRange

Inherits:
Object
  • Object
show all
Includes:
AcceptanceRouter, PlainLattice, ValueSemantics
Defined in:
lib/rigor/type/integer_range.rb,
sig/rigor/type.rbs

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[Integer] — 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 =

Returns:

  • (Symbol)
:neg_infinity
POS_INFINITY =

Returns:

  • (Symbol)
:pos_infinity
INFINITIES =
[NEG_INFINITY, POS_INFINITY].freeze
ALIAS_NAMES =
Ractor.make_shareable({
  [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"
})

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ValueSemantics

included

Constructor Details

#initialize(min, max) ⇒ IntegerRange

Returns a new instance of IntegerRange.

Parameters:

  • min (Integer, Symbol)
  • max (Integer, Symbol)


30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/rigor/type/integer_range.rb', line 30

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

#maxInteger, Symbol (readonly)

Returns the value of attribute max.

Returns:

  • (Integer, Symbol)


28
29
30
# File 'lib/rigor/type/integer_range.rb', line 28

def max
  @max
end

#minInteger, Symbol (readonly)

Returns the value of attribute min.

Returns:

  • (Integer, Symbol)


28
29
30
# File 'lib/rigor/type/integer_range.rb', line 28

def min
  @min
end

Instance Method Details

#==Boolean

Parameters:

  • other (Object)

Returns:

  • (Boolean)


103
# File 'sig/rigor/type.rbs', line 103

def ==: (untyped other) -> bool

#acceptsAcceptsResult

Parameters:

  • other (Type::t)
  • mode: (accepts_mode)

Returns:



102
# File 'sig/rigor/type.rbs', line 102

def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult

#botTrinary

Returns:



100
# File 'sig/rigor/type.rbs', line 100

def bot: () -> Trinary

#cardinalityInteger, Float

Returns:

  • (Integer, Float)


53
54
55
# File 'lib/rigor/type/integer_range.rb', line 53

def cardinality
  finite? ? (max - min + 1) : Float::INFINITY
end

#covers?(int) ⇒ Boolean

Parameters:

  • value (Object)

Returns:

  • (Boolean)


57
58
59
60
61
# File 'lib/rigor/type/integer_range.rb', line 57

def covers?(int)
  return false unless int.is_a?(Integer)

  int.between?(lower, upper)
end

#describe(_verbosity = :short) ⇒ String

Parameters:

  • verbosity (Symbol)

Returns:

  • (String)


87
88
89
# File 'lib/rigor/type/integer_range.rb', line 87

def describe(_verbosity = :short)
  ALIAS_NAMES[[min, max]] || generic_description
end

#dynamicTrinary

Returns:



101
# File 'sig/rigor/type.rbs', line 101

def dynamic: () -> Trinary

#erase_to_rbs"Integer"

Returns:

  • ("Integer")


98
99
100
# File 'lib/rigor/type/integer_range.rb', line 98

def erase_to_rbs
  "Integer"
end

#finite?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/rigor/type/integer_range.rb', line 49

def finite?
  min.is_a?(Integer) && max.is_a?(Integer)
end

#generic_descriptionString

Returns:

  • (String)


91
92
93
94
95
96
# File 'lib/rigor/type/integer_range.rb', line 91

def generic_description
  return "int<#{min}, max>" if max == POS_INFINITY
  return "int<min, #{max}>" if min == NEG_INFINITY

  "int<#{min}, #{max}>"
end

#hashInteger

Returns:

  • (Integer)


104
# File 'sig/rigor/type.rbs', line 104

def hash: () -> Integer

#inspectString

Returns:

  • (String)


110
111
112
# File 'lib/rigor/type/integer_range.rb', line 110

def inspect
  "#<Rigor::Type::IntegerRange #{describe(:short)}>"
end

#lowerInteger, Float

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.

Returns:

  • (Integer, Float)


65
66
67
68
69
70
# File 'lib/rigor/type/integer_range.rb', line 65

def lower
  m = min
  return m if m.is_a?(Integer)

  -Float::INFINITY
end

#topTrinary

Returns:



99
# File 'sig/rigor/type.rbs', line 99

def top: () -> Trinary

#universal?Boolean

Returns:

  • (Boolean)


45
46
47
# File 'lib/rigor/type/integer_range.rb', line 45

def universal?
  min == NEG_INFINITY && max == POS_INFINITY
end

#upperInteger, Float

Returns:

  • (Integer, Float)


72
73
74
75
76
77
# File 'lib/rigor/type/integer_range.rb', line 72

def upper
  m = max
  return m if m.is_a?(Integer)

  Float::INFINITY
end