Module: External::Chunkable

Included in:
Base, Io
Defined in:
lib/external/chunkable.rb

Overview

The Chunkable mixin provides methods for organizing a span or range into chunks no larger than a specified block size. For reference:

span    an array like: [start, length]
range   a Range like: start..end or start...(end - 1)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#default_blksizeObject

The default block size for chunking a chunkable object; default_blksize must be set by the object.



17
18
19
# File 'lib/external/chunkable.rb', line 17

def default_blksize
  @default_blksize
end

#lengthObject

The length of the chunkable object; length must be set by the object.



13
14
15
# File 'lib/external/chunkable.rb', line 13

def length
  @length
end

Class Method Details

.range_begin_and_end(range_or_span) ⇒ Object

Returns the begining and end of a range or span.

range_begin_and_end(0..10)    # => [0, 10]
range_begin_and_end(0...10)   # => [0, 9]
range_begin_and_end([0, 10])  # => [0, 10]

Raises:

  • (ArgumentError)


111
112
113
114
115
116
117
# File 'lib/external/chunkable.rb', line 111

def range_begin_and_end(range_or_span)
  rbegin, rend = range_or_span.kind_of?(Range) ? split_range(range_or_span) : split_span(range_or_span)
  raise ArgumentError.new("negative offset specified: #{PP.singleline_pp(range_or_span,'')}") if rbegin < 0
  rend += rbegin
  
  [rbegin, rend]
end

.split_range(range) ⇒ Object

Converts a range into an offset and length. Negative values are counted back from self.length

length                # => 10
split_range(0..9)     # => [0,10]
split_range(0...9)    # => [0,9]

split_range(-1..9)    # => [9,1]
split_range(0..-1)    # => [0,10]


85
86
87
88
89
90
91
# File 'lib/external/chunkable.rb', line 85

def split_range(range)
  start, finish = range.begin, range.end
  start += length if start < 0
  finish += length if finish < 0
  
  [start, finish - start - (range.exclude_end? ? 1 : 0)]
end

.split_span(span) ⇒ Object

The compliment to split_range; returns the span with a negative start index counted back from self.length.

length                # => 10
split_span([0, 10])   # => [0,10]
split_span([-1, 1])   # => [9,1]


100
101
102
103
# File 'lib/external/chunkable.rb', line 100

def split_span(span)
  span[0] += self.length if span[0] < 0
  span
end

Instance Method Details

#chunk(range_or_span = default_span, blksize = default_blksize) {|rbegin, rend - rbegin| ... } ⇒ Object

Breaks the input range or span into chunks of blksize or less.

The offset and length of each chunk will be provided to the block, if given.

blksize           # => 100
chunk(0..250)     # => [[0,100],[100,100],[200,50]]

results = []
chunk([10,190]) {|offset, length| results << [offset, length]}
results           # => [[10,100],[110,90]]

Yields:

  • (rbegin, rend - rbegin)


35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/external/chunkable.rb', line 35

def chunk(range_or_span=default_span, blksize=default_blksize)
  return collect_results(:chunk, range_or_span) unless block_given?
  
  rbegin, rend = range_begin_and_end(range_or_span)
  
  # chunk the final range to make sure that no chunks  
  # greater than blksize are returned
  while rend - rbegin > blksize 
    yield(rbegin, blksize)
    rbegin += blksize
  end
  yield(rbegin, rend - rbegin) if rend - rbegin > 0
end

#default_spanObject

Returns the default span: [0, length]



20
21
22
# File 'lib/external/chunkable.rb', line 20

def default_span
  [0, length]
end

#reverse_chunk(range_or_span = default_span, blksize = default_blksize) {|rbegin, rend - rbegin| ... } ⇒ Object

Breaks the input range or span into chunks of blksize or less, beginning from the end of the interval. The offset and length of each chunk will be provided to the block, if given.

blksize                   # => 100
reverse_chunk(0..250)     # => [[150,100],[50,100],[0,50]]

results = []
reverse_chunk([10,190]) {|offset, length| results << [offset, length]}
results                   # => [[100,100],[10,90]]

Yields:

  • (rbegin, rend - rbegin)


60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/external/chunkable.rb', line 60

def reverse_chunk(range_or_span=default_span, blksize=default_blksize)
  return collect_results(:reverse_chunk, range_or_span) unless block_given?

  rbegin, rend = range_begin_and_end(range_or_span)

  # chunk the final range to make sure that no chunks  
  # greater than blksize are returned
  while rend - rbegin > blksize 
    rend -= blksize
    yield(rend, blksize)
  end
  yield(rbegin, rend - rbegin) if rend - rbegin > 0
end