Module: RangeUtils
- Extended by:
- RangeUtils
- Included in:
- RangeUtils
- Defined in:
- lib/range_utils.rb,
lib/range_utils/version.rb
Constant Summary collapse
- NegativeRangeSpan =
Class.new(ArgumentError)
- VERSION =
'2.0.0'
Instance Method Summary collapse
-
#intersection_of(range_a, range_b) ⇒ Object
Returns the intersection of two given Ranges or ‘nil` if they do not intersect.
-
#range_for_size_of(number_of_items) ⇒ Object
Creates a Range that can be used to grab N first elements from, say, an Array or a String.
-
#range_includes_item?(range, item) ⇒ Boolean
Tells whether the
item
is included in therange
, without enumerating through therange
(performing a quick bounds check). -
#ranges_of_offfsets_for_size(number_of_items, chunk_size) ⇒ Object
(also: #http_ranges_for_size)
Returns ranges for the given size.
-
#size_from_range(range) ⇒ Object
Returns the number of members of the given Range.
-
#splice(ranges) ⇒ Object
Combine ranges with adjacent or overlapping values (create a union range).
-
#split_range_into_subranges_of(range, size) ⇒ Object
Splits the given Range into subranges of
size
. -
#take(from_range, n_items) ⇒ Object
Take N items from the range, and return two Ranges the first being the range containing N items requested, and the other containing the remainder take(4..514, 3) #=> [4..6, 7..514] If the range is too small for the number of items requested, the range itself and
nil
will be returned instead:.
Instance Method Details
#intersection_of(range_a, range_b) ⇒ Object
Returns the intersection of two given Ranges or ‘nil` if they do not intersect. Adjacent ranges do not get merged.
intersection_of(0..456, 26..12889) #=> 26..456
intersection_of(0..456, 7811..12889) #=> nil
intersection_of(0..0, 1..1) #=> nil
Range members and n_items must support arithmetic with integers
121 122 123 124 125 126 127 |
# File 'lib/range_utils.rb', line 121 def intersection_of(range_a, range_b) range_a, range_b = [range_a, range_b].sort_by(&:begin) return if range_a.end < range_b.begin heads_and_tails = [range_a.begin, range_b.begin, range_a.end, range_b.end].sort middle = heads_and_tails[1..-2] middle[0]..middle[1] end |
#range_for_size_of(number_of_items) ⇒ Object
Creates a Range that can be used to grab N first elements from, say, an Array or a String.
range_for_size(14) #=> 0..13
"abcd"[range_for_size(2)] #=> "ab"
number_of_items
should be >= 0. For the number_of_items
a special Range of 0..-1 will be returned (note that this Range cannot fetch anything).
61 62 63 64 |
# File 'lib/range_utils.rb', line 61 def range_for_size_of(number_of_items) raise ArgumentError, "Number of items should be at least 0, was #{number_of_items}" if number_of_items < 0 (0..(number_of_items - 1)) end |
#range_includes_item?(range, item) ⇒ Boolean
Tells whether the item
is included in the range
, without enumerating through the range
(performing a quick bounds check). The first value of the range and the item
have to support <=>
9 10 11 |
# File 'lib/range_utils.rb', line 9 def range_includes_item?(range, item) range.begin <= item && item <= range.end end |
#ranges_of_offfsets_for_size(number_of_items, chunk_size) ⇒ Object Also known as: http_ranges_for_size
Returns ranges for the given size. The returned ranges start at zero. Can be used to split a Content-Length of an HTTP resource into ranges usable in Range: header for instance.
Since the initial offset is 0 the resulting ranges will always end at size - 1
ranges_of_offfsets_for_size(3, 1) #=> [0..0, 1..1, 2..2]
ranges_of_offfsets_for_size(3, 2) #=> [0..1, 2..2]
Range members must support <=> and arithmetic with integers. size
has to be > 0.
49 50 51 52 |
# File 'lib/range_utils.rb', line 49 def ranges_of_offfsets_for_size(number_of_items, chunk_size) raise ArgumentError, "Chunk size should be > 0, was #{chunk_size}" unless chunk_size > 0 split_range_into_subranges_of(range_for_size_of(number_of_items), chunk_size) end |
#size_from_range(range) ⇒ Object
Returns the number of members of the given Range.
size_from_range(0..0) #=> 1
size_from_range(12..123) #=> 112
Range members must support arithmetic with integers.
91 92 93 94 95 |
# File 'lib/range_utils.rb', line 91 def size_from_range(range) size = range.end - range.begin + 1 raise NegativeRangeSpan, "The resulting size for range #{range} is negative" if size < 0 size end |
#splice(ranges) ⇒ Object
Combine ranges with adjacent or overlapping values (create a union range).
splice([0..0, 0..4, 5..14, 16..20]) #=> [0..14, 16..20]
Range members must support <=> and arithmetic with integers.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/range_utils.rb', line 69 def splice(ranges) ranges.sort_by(&:begin).inject([]) do |spliced, r| if spliced.empty? spliced + [r] else last = spliced.pop if last.end >= (r.begin - 1) ends = [last.end, last.begin, r.begin, r.end].sort new_end = ends.shift new_begin = ends.pop spliced + [(new_end..new_begin)] else spliced + [last, r] end end end end |
#split_range_into_subranges_of(range, size) ⇒ Object
Splits the given Range into subranges of size
.
split_range_into_subranges_of(0..7, 3) #=> [0..2, 3..5, 5..7]
Range members must support <=> and arithmetic with integers. size
has to be > 0.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/range_utils.rb', line 19 def split_range_into_subranges_of(range, size) raise ArgumentError, "Chunk size should be > 0, was #{size}" unless size > 0 ranges = [] at = range.begin loop do if at > range.end return ranges else end_of_chunk = (at + size - 1) current = at..(end_of_chunk > range.end ? range.end : end_of_chunk) at = (at + size) ranges << current yield(current) if block_given? end end end |
#take(from_range, n_items) ⇒ Object
Take N items from the range, and return two Ranges the first being the range containing N items requested, and the other containing the remainder
take(4..514, 3) #=> [4..6, 7..514]
If the range is too small for the number of items requested, the range itself and nil
will be returned instead:
take(4..514, 1024) #=> [4..514, nil]
Range members and n_items must support arithmetic with integers
107 108 109 110 111 |
# File 'lib/range_utils.rb', line 107 def take(from_range, n_items) end_at = from_range.begin + (n_items - 1) return [from_range, nil] if end_at >= from_range.end [from_range.begin..end_at, end_at.succ..from_range.end] end |