Class: ThinModels::LazyArray

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/thin_models/lazy_array.rb

Overview

Exposes Enumerable and a subset of the interface of Array, but is lazily evaluated.

The default constructor allows you to pass in an underlying Enumerable whose .each method will be used; or you can ignore this and override #each and #initialize yourself.

You should also consider overriding #length if you have an optimised mechanism for evaluating it without doing a full iteration via #each, and overriding #slice_from_start_and_length if you have an optimised mechanism for iterating over a slice/sub-range of the array. This will be used to supply optimised versions of #[] / #slice

Deliberately doesn’t expose any mutation methods - is not intended to be a mutable data structure.

Direct Known Subclasses

Mapped, MemoizedLength

Defined Under Namespace

Classes: Mapped, Memoized, MemoizedLength

Instance Method Summary collapse

Constructor Details

#initialize(enumerable = nil) ⇒ LazyArray

Returns a new instance of LazyArray.



16
17
18
# File 'lib/thin_models/lazy_array.rb', line 16

def initialize(enumerable=nil)
  @enumerable = enumerable
end

Instance Method Details

#[](index_or_range, length = nil) ⇒ Object Also known as: slice

behaviour is consistent with Array#[], except it doesn’t take negative indexes. uses slice_from_start_and_length to do the work.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/thin_models/lazy_array.rb', line 85

def [](index_or_range, length=nil)
  case index_or_range
  when Range
    start = index_or_range.begin
    length = index_or_range.end - start
    length += 1 unless index_or_range.exclude_end?
    slice_from_start_and_length(start, length)
  when Integer
    if length
      slice_from_start_and_length(index_or_range, length)
    else
      slice = slice_from_start_and_length(index_or_range, 1) and slice.first
    end
  else
    raise ArgumentError
  end
end

#each(&b) ⇒ Object



20
21
22
# File 'lib/thin_models/lazy_array.rb', line 20

def each(&b)
  @enumerable.each(&b)
end

#empty?Boolean

Returns:

  • (Boolean)


37
38
39
40
# File 'lib/thin_models/lazy_array.rb', line 37

def empty?
  each {return false}
  return true
end

#firstObject



105
106
107
# File 'lib/thin_models/lazy_array.rb', line 105

def first
  self[0]
end

#inspectObject



24
25
26
# File 'lib/thin_models/lazy_array.rb', line 24

def inspect
  "[ThinModels::LazyArray:...]"
end

#join(separator = $,) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/thin_models/lazy_array.rb', line 42

def join(separator=$,)
  result = ''; first = true
  each do |x|
    if first
      first = false
    else
      result << separator if separator
    end
    result << x.to_s
  end
  result
end

#lastObject



109
110
111
112
# File 'lib/thin_models/lazy_array.rb', line 109

def last
  l = length
  self[l-1] if l > 0
end

#lengthObject

We recommend overriding this #length implementation (which is based on #each) with an efficient implementation. #size will use your #length, and #count uses #size where available, hence will use it too.



31
32
33
# File 'lib/thin_models/lazy_array.rb', line 31

def length
  length = 0; each {length += 1}; length
end

#map(memoize = false, &b) ⇒ Object

map works lazily, resulting in a ThinModels::LazyArray::Mapped or a ThinModels::LazyArray::Memoized::Mapped (which additionally memoizes the mapped values)



116
117
118
# File 'lib/thin_models/lazy_array.rb', line 116

def map(memoize=false, &b)
  (memoize ? Memoized::Mapped : Mapped).new(self, &b)
end

#sizeObject



35
# File 'lib/thin_models/lazy_array.rb', line 35

def size; length; end

#slice_from_start_and_length(start, length) ⇒ Object

We recommend overriding this inefficient implementation (which uses #each to traverse from the start until it reaches the desired range) with an efficient implementation.

Returns an array for the requested slice; may return a slice shorter than requested where the array doesn’t extend that far, but if the start index is greater than the total length, must return nil. This is consistent with Array#slice/[] eg: [][1..10] == nil, but [][0..10] == []

Does not need to handle the other argument types (Range, single index) which Array#slice/[] takes.



71
72
73
74
75
76
77
78
79
80
81
# File 'lib/thin_models/lazy_array.rb', line 71

def slice_from_start_and_length(start, length)
  result = []
  stop = start + length
  index = 0
  each do |item|
    break if index >= stop
    result << item if index >= start
    index += 1
  end
  result if index >= start
end

#to_json(*p) ⇒ Object



58
59
60
# File 'lib/thin_models/lazy_array.rb', line 58

def to_json(*p)
  to_a.to_json(*p)
end