lookaround-enumerable 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/Gemfile +6 -0
- data/README.md +57 -0
- data/Rakefile +6 -0
- data/lib/lookaround-enumerable.rb +728 -0
- data/lookaround-enumerable.gemspec +35 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0f7147396b91cb815e80a4c1e15db38736b9900e84a0f7e07f12e4564c54dfe5
|
4
|
+
data.tar.gz: b55b5655cbb962ccb2188a4a4346230122cddd220fe81490fed0d1cb5aee1210
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b65d153993c566a985d54e67d9c0b51a7a2dc2bf81cb04060166b8b6c2434eb4f1d85942194cdbad7314b5f07dd8d2309d0823e16a049cad1963f49eb7b61f10
|
7
|
+
data.tar.gz: 3a4298e88e9135a967e1780644460b9b2f59cf1aaa7bb92a4c7dfe2d126d2ee6cf3e0603e0a464e4e76a525554d6eac1dd6b1574d8fd97d21069990434195e09
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Lookaround Enumerable
|
2
|
+
|
3
|
+
When working with time series, it is common to perform operations that depend on a sliding window of values. Lookaround Enumerable adds two main methods, and several sub-helpers to assist with running map/collect, reduce/inject, and find_all/select queries that depend on the previous values (Enumerable#each_with_prev), or a whole window of values (Enumerable#each_with_window). This gem contains these methods as refinements.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'lookaround-enumerable'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install lookaround-enumerable
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'lookaround-enumerable'
|
25
|
+
using LookaroundEnum
|
26
|
+
```
|
27
|
+
|
28
|
+
The `LookaroundEnum` contains the refinements, so they can be targeted to selected areas of code.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
# Maps characters after a capital letter to "x"
|
32
|
+
"AbCdefgHiJKl".each_char.map_with_prev(1, filler: "a") {|x, previous| previous.upcase == previous ? "x" : x}.join
|
33
|
+
# => "AxCxefgHxJxx"
|
34
|
+
|
35
|
+
# select characters surrounded by > <, ignoring the bounds (crop)
|
36
|
+
"Ab>c<defg>h<i>j<kLm>n<op".each_char.select_with_window(-1..1, crop: true) { |left, item, right| left + right == "><" }.join
|
37
|
+
# => "cjhn"
|
38
|
+
```
|
39
|
+
|
40
|
+
* Set what beyond the Enumerable is with `filler:`
|
41
|
+
* Ignore all iterations that look beyond the Enumerable with `crop: true`
|
42
|
+
* Remove extra details from chains with `trim: true`
|
43
|
+
|
44
|
+
See the documentation spec tests under `spec/` for more examples.
|
45
|
+
|
46
|
+
|
47
|
+
### Wait, what are the proc's args?
|
48
|
+
|
49
|
+
That's a tricky question. By default, single left/right views _should_ just work, but you might have to play with the `expand` parameter or do a `p *args` to figure out more advanced usage, like chaining with memos or objects. The `each_with_prev` family does `|(*this), ((*previous1), ..., (*previous_n))|` with older/lower indexes to the right. The `each_with_window` family does `|((*previous_n), ..., (*previous1)), (*this), ((*next1), ..., (*next_n))|` with older/lower indexes on the left.
|
50
|
+
|
51
|
+
## Development
|
52
|
+
|
53
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` or `rspec` to run the tests.
|
54
|
+
|
55
|
+
## Contributing
|
56
|
+
|
57
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/byteit101/lookaround-enumerable.
|
data/Rakefile
ADDED
@@ -0,0 +1,728 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2020 Patrick Plenefisch <simonpatp@gmail.com>
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
7
|
+
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
9
|
+
|
10
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
11
|
+
|
12
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
13
|
+
=end
|
14
|
+
|
15
|
+
|
16
|
+
##
|
17
|
+
# Refinements for lookaround methods on Enumerable/Enumerator
|
18
|
+
#
|
19
|
+
# Use:
|
20
|
+
# using LookaroundEnum
|
21
|
+
#
|
22
|
+
# All methods are added to Enumerable
|
23
|
+
#
|
24
|
+
module LookaroundEnum
|
25
|
+
|
26
|
+
VERSION = "1.0.0"
|
27
|
+
|
28
|
+
# Refinements for Enumerable
|
29
|
+
refine Enumerable do
|
30
|
+
|
31
|
+
# See doc below, yard doesn't support refinements
|
32
|
+
def each_with_prev(size=1, crop: false, trim: false, filler: nil, expand: :single, &block)
|
33
|
+
raise ArgumentError, "previous size must not be negative" unless (0...2_000_000_000).include?(size)
|
34
|
+
raise ArgumentError, "Expand parameter isn't valid" unless [:none, :all, :single].include?(expand)
|
35
|
+
return to_enum(:__nbl_back_refinement_send, size, crop: crop, trim: trim, filler: filler, expand: expand) { __nbl_any_sized } unless block_given?
|
36
|
+
|
37
|
+
last = [filler] * size
|
38
|
+
skips = crop ? size : 0 # how many elements to skip
|
39
|
+
|
40
|
+
each do |*o| # call parent
|
41
|
+
issingle = o.length == 1
|
42
|
+
result = if skips != 0 # skip the first N if we don't want nil results
|
43
|
+
skips -= 1
|
44
|
+
nil
|
45
|
+
else
|
46
|
+
case expand
|
47
|
+
when :all then yield(*o, *last.dup)
|
48
|
+
when :none then yield(o, last.dup)
|
49
|
+
when :single
|
50
|
+
yield(LookaroundEnum.unwrap(o), LookaroundEnum.unwrap(last, size))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
# maintain the last values
|
54
|
+
last.pop
|
55
|
+
last.unshift(trim ? o.first : LookaroundEnum.unwrap(o))
|
56
|
+
|
57
|
+
# return yield result
|
58
|
+
result
|
59
|
+
end
|
60
|
+
#self
|
61
|
+
end
|
62
|
+
|
63
|
+
def each_with_window(view=(-1..1), crop: false, trim: false, filler: nil, expand: :single, &blk)
|
64
|
+
center_index = -view.min
|
65
|
+
raise ArgumentError, "window view minimum must not be positive" unless (0...2_000_000_000).include?(center_index)
|
66
|
+
raise ArgumentError, "window view maximum must not be negative" unless (0...2_000_000_000).include?(view.max)
|
67
|
+
raise ArgumentError, "Expand parameter isn't valid" unless [:none, :all, :single].include?(expand)
|
68
|
+
width = view.size - 1 # width - 1 as the main arg counts as +1
|
69
|
+
|
70
|
+
# no lookahead, just defer to straight neighbor call
|
71
|
+
if view.max == 0
|
72
|
+
return each_with_prev(width, crop: crop, trim: trim, expand: expand, filler: filler, &blk) # TODO: test arity
|
73
|
+
end
|
74
|
+
|
75
|
+
return to_enum(:__nbl_window_refinement_send, view, crop: crop, trim: trim, filler: filler, expand: expand) { __nbl_any_sized } unless blk
|
76
|
+
|
77
|
+
last_row = [filler] * view.size
|
78
|
+
skips = view.max
|
79
|
+
last_result = nil
|
80
|
+
|
81
|
+
# helper for each invocation to skip the left sides. Note: we are always view.max items behind in order to "lookahead"
|
82
|
+
process = lambda do
|
83
|
+
last_result = if skips != 0
|
84
|
+
skips -= 1
|
85
|
+
nil
|
86
|
+
else
|
87
|
+
center = last_row[center_index]
|
88
|
+
right = last_row[(center_index+1)..-1]
|
89
|
+
left = last_row[0...center_index]
|
90
|
+
case expand
|
91
|
+
when :none then blk.call(left, center, right)
|
92
|
+
when :all then blk.call(*left, center, *right) # look into splatting the center
|
93
|
+
when :single then
|
94
|
+
if center_index == 0
|
95
|
+
blk.call(center, LookaroundEnum.unwrap(right))
|
96
|
+
else
|
97
|
+
maxsize = [left.size, right.size].max
|
98
|
+
blk.call(LookaroundEnum.unwrap(left, maxsize), center, LookaroundEnum.unwrap(right, maxsize))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Process all the left hand sides
|
105
|
+
iresult = each_with_prev(width, crop: crop, trim: trim, filler: filler, expand: :none) do |arg, history|
|
106
|
+
rearg = arg.length == 1 ? arg : [arg] # keep multi-arguments together when reversing
|
107
|
+
last_row = (rearg + history).reverse # Could be done better
|
108
|
+
process.call
|
109
|
+
end
|
110
|
+
|
111
|
+
# and any remaining right hand sides
|
112
|
+
unless crop
|
113
|
+
view.max.times do |i|
|
114
|
+
last_row.shift
|
115
|
+
last_row << filler
|
116
|
+
process.call
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
return last_result
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
# map helpers and aliases
|
125
|
+
def map_with_prev(size=1, **kwargs, &block)
|
126
|
+
each_with_prev(size, **kwargs).map(&block)
|
127
|
+
end
|
128
|
+
alias_method :collect_with_prev, :map_with_prev
|
129
|
+
alias_method :pcollect, :map_with_prev
|
130
|
+
alias_method :pmap, :map_with_prev
|
131
|
+
|
132
|
+
# select helper and aliases
|
133
|
+
def select_with_prev(size=1, **kwargs, &block)
|
134
|
+
select.each_with_prev(size, **kwargs, &block)
|
135
|
+
end
|
136
|
+
|
137
|
+
alias_method :find_all_with_prev, :select_with_prev
|
138
|
+
alias_method :pfind_all, :select_with_prev
|
139
|
+
alias_method :pselect, :select_with_prev
|
140
|
+
|
141
|
+
# inject helper and aliases
|
142
|
+
def pinject(memo = NBL__PRIVATE_EMPTY, size=1, **kwargs, &block)
|
143
|
+
if memo.equal? NBL__PRIVATE_EMPTY
|
144
|
+
each_with_prev(size, **kwargs).reduce(&block)
|
145
|
+
else
|
146
|
+
each_with_prev(size, **kwargs).reduce(memo, &block) #T TODO: test
|
147
|
+
end
|
148
|
+
end
|
149
|
+
alias_method :reduce_with_prev, :pinject
|
150
|
+
alias_method :inject_with_prev, :pinject
|
151
|
+
alias_method :preduce, :pinject
|
152
|
+
|
153
|
+
# map helpers (windows) and aliases
|
154
|
+
def map_with_window(view=(-1..1), **kwargs, &block)
|
155
|
+
each_with_window(view, **kwargs).map(&block)
|
156
|
+
end
|
157
|
+
alias_method :collect_with_window, :map_with_window
|
158
|
+
alias_method :wcollect, :map_with_window
|
159
|
+
alias_method :wmap, :map_with_window
|
160
|
+
|
161
|
+
# select helpers (windows) and aliases
|
162
|
+
def select_with_window(view=(-1..1), **kwargs, &block)
|
163
|
+
map_with_window(view, **kwargs) do |*lcr|
|
164
|
+
a, b, c = *lcr
|
165
|
+
node = view.min == 0 ? a : b
|
166
|
+
[block.call(*lcr), node]
|
167
|
+
end.select{|(key, _)| key}.map{|_, value| value}
|
168
|
+
end
|
169
|
+
|
170
|
+
alias_method :find_all_with_window, :select_with_window
|
171
|
+
alias_method :wfind_all, :select_with_window
|
172
|
+
alias_method :wselect, :select_with_window
|
173
|
+
|
174
|
+
# inject helper and aliases
|
175
|
+
def winject(memo = NBL__PRIVATE_EMPTY, size=(-1..1), **kwargs, &block)
|
176
|
+
if memo.equal? NBL__PRIVATE_EMPTY
|
177
|
+
each_with_window(size, **kwargs).reduce(&block)
|
178
|
+
else
|
179
|
+
each_with_window(size, **kwargs).reduce(memo, &block)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
alias_method :reduce_with_window, :winject
|
183
|
+
alias_method :inject_with_window, :winject
|
184
|
+
alias_method :wreduce, :winject
|
185
|
+
|
186
|
+
|
187
|
+
private
|
188
|
+
# :nodoc:
|
189
|
+
# Helper to get the size, or nil if unsupported
|
190
|
+
def __nbl_any_sized
|
191
|
+
respond_to?(:size) ? size : nil
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
private
|
196
|
+
# :nodoc:
|
197
|
+
# Helper to unwrap a single element array
|
198
|
+
def self.unwrap(array, size=array.length)
|
199
|
+
case size
|
200
|
+
when 1 then array.first
|
201
|
+
else array.dup
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# :nodoc:
|
206
|
+
NBL__PRIVATE_EMPTY = {}
|
207
|
+
end
|
208
|
+
|
209
|
+
module Enumerable
|
210
|
+
using LookaroundEnum
|
211
|
+
# @api private
|
212
|
+
# @private
|
213
|
+
# @!visibility private
|
214
|
+
# Hack to support to_enum, which uses send, which doesn't work with refinements. This method is always monkey-patched in as a result
|
215
|
+
def __nbl_back_refinement_send(*args, **kwargs, &block)
|
216
|
+
each_with_prev(*args, **kwargs, &block)
|
217
|
+
end
|
218
|
+
# @api private
|
219
|
+
# @private
|
220
|
+
# @!visibility private
|
221
|
+
# Hack to support to_enum, which uses send, which doesn't work with refinements. This method is always monkey-patched in as a result
|
222
|
+
def __nbl_window_refinement_send(*args, **kwargs, &block)
|
223
|
+
each_with_window(*args, **kwargs, &block)
|
224
|
+
end
|
225
|
+
|
226
|
+
# Document via yard
|
227
|
+
|
228
|
+
|
229
|
+
##
|
230
|
+
# @!method each_with_prev
|
231
|
+
#
|
232
|
+
# @overload each_with_prev(size=1, crop: false, trim: false, filler: nil, expand: :single)
|
233
|
+
# @return [Enumerable] The parent Enumerable
|
234
|
+
# @yield [(*args), (*previous)]
|
235
|
+
# @overload each_with_prev(size=1, crop: false, trim: false, filler: nil, expand: :single)
|
236
|
+
# @return [Enumerator] The external Enumerator
|
237
|
+
#
|
238
|
+
# Calls <em>block</em> with two (or more, depending on the <em>expand</em>) arguments: the item and
|
239
|
+
# the values at earlier indexes.
|
240
|
+
#
|
241
|
+
# If no block is given, an enumerator is returned instead.
|
242
|
+
#
|
243
|
+
# @param size [Integer] The number of previous elements to iterate with
|
244
|
+
# @example Size Examples
|
245
|
+
# (1..3).each_with_prev(1).to_a # => [[1, nil], [2, 1], [3, 2]]
|
246
|
+
# (1..3).each_with_prev(2).to_a # => [[1, [nil, nil]], [2, [1, nil]], [3, [2, 1]]]
|
247
|
+
#
|
248
|
+
# @param crop: [Bool] true if the iteration should only include values with no empty previous (skips first <em>size</em> number of elements), false if all elements iterated
|
249
|
+
# @example Crop Examples
|
250
|
+
# (1..3).each_with_prev(1, crop: false).to_a # => [[1, nil], [2, 1], [3, 2]]
|
251
|
+
# (1..3).each_with_prev(1, crop: true).to_a # => [[2, 1], [3, 2]]
|
252
|
+
#
|
253
|
+
#
|
254
|
+
# @param trim: [Bool] true if the previous elements should only be the first item from lower level iterators, false if all values should be saved. Note that setting this value is only useful on Enumerators or Enumerables that have more than one value.
|
255
|
+
# @example Trim Examples
|
256
|
+
# (1..3).each_with_object({}).each_with_prev(1, trim: false, expand: :all).to_a
|
257
|
+
# # => [[1, {}, nil], [2, {}, [1, {}]], [3, {}, [2, {}]]]
|
258
|
+
# (1..3).each_with_object({}).each_with_prev(1, trim: true, expand: :all).to_a
|
259
|
+
# # => [[1, {}, nil], [2, {}, 1], [3, {}, 2]]
|
260
|
+
#
|
261
|
+
# @param filler: [Any] the value to use for empty/no-value history cells at the start of the iteration. Does nothing when <em>crop</em> is true.
|
262
|
+
# @example Filler Examples
|
263
|
+
# (1..3).each_with_prev(1, filler: nil).to_a # => [[1, nil], [2, 1], [3, 2]]
|
264
|
+
# (1..3).each_with_prev(1, filler: 0).to_a # => [[1, 0], [2, 1], [3, 2]]
|
265
|
+
#
|
266
|
+
# @param expand: [Symbol] What argument style the block expects. See the valid options above (html doc) or below (source)
|
267
|
+
#
|
268
|
+
# <code>expand:</code>::
|
269
|
+
# (Symbol) Valid options are:
|
270
|
+
#
|
271
|
+
# <code>:none</code>:: Never expands, block always takes two arguments, each an array
|
272
|
+
#
|
273
|
+
# (1..3).each_with_prev(expand: :none) {|(current), (prev)| }
|
274
|
+
# (1..3).each_with_object({}).each_with_prev(2, expand: :none) {|(current, obj), (prev, prev2)| }
|
275
|
+
#
|
276
|
+
# <code>:single</code>:: (default) Expands if only one element, block always takes two arguments, each an array or an object
|
277
|
+
#
|
278
|
+
# (1..3).each_with_prev(expand: :single) {|current, prev| }
|
279
|
+
# (1..3).each_with_prev(2, expand: :single) {|current, (prev, prev2)| }
|
280
|
+
# (1..3).each_with_object({}).each_with_prev(2, expand: :single) {|(current, obj), (prev, prev2)| }
|
281
|
+
#
|
282
|
+
# <code>:all</code>:: Expands all sides, block takes two or more arguments, each an object
|
283
|
+
#
|
284
|
+
# (1..3).each_with_prev(expand: :all) {|current, prev| }
|
285
|
+
# (1..3).each_with_prev(2, expand: :all) {|current, prev, prev2| }
|
286
|
+
# (1..3).each_with_object({}).each_with_prev(2, expand: :all) {|current, obj, prev, prev2| }
|
287
|
+
#
|
288
|
+
#
|
289
|
+
#
|
290
|
+
# @raise [ArgumentError] If the arguments are invalid
|
291
|
+
#
|
292
|
+
#
|
293
|
+
#
|
294
|
+
#
|
295
|
+
#
|
296
|
+
#
|
297
|
+
#
|
298
|
+
#
|
299
|
+
#
|
300
|
+
|
301
|
+
|
302
|
+
|
303
|
+
##
|
304
|
+
# @!method each_with_window
|
305
|
+
#
|
306
|
+
# @overload each_with_window(view=-1..1, crop: false, trim: false, filler: nil, expand: :single)
|
307
|
+
# @return [Enumerable] The parent Enumerable
|
308
|
+
# @yield [(*left), (*args), (*right)]
|
309
|
+
# @overload each_with_window(size=-1..1, crop: false, trim: false, filler: nil, expand: :single)
|
310
|
+
# @return [Enumerator] The external Enumerator
|
311
|
+
#
|
312
|
+
# Calls <em>block</em> with three (or more, depending on the <em>expand</em>) arguments: the item and
|
313
|
+
# the values at earlier and later indexes.
|
314
|
+
#
|
315
|
+
# If no block is given, an enumerator is returned instead.
|
316
|
+
#
|
317
|
+
# Important note: each_with_window is executed in a disjunct manner from the parent iterator. This can cause issues when chained with other Enumerators. Please use the built in helpers.
|
318
|
+
#
|
319
|
+
# @param view [Range] The number of items to look at to previous and upcoming indicies.
|
320
|
+
# @example View Examples
|
321
|
+
# ('a'..'d').each_with_window(-2..1).to_a # => [[[nil, nil], "a", ["b"]], [[nil, "a"], "b", ["c"]], [["a", "b"], "c", ["d"]], [["b", "c"], "d", [nil]]]
|
322
|
+
#
|
323
|
+
# @see each_with_prev For argument descriptions
|
324
|
+
#
|
325
|
+
# @raise [ArgumentError] If the arguments are invalid
|
326
|
+
#
|
327
|
+
#
|
328
|
+
#
|
329
|
+
#
|
330
|
+
#
|
331
|
+
#
|
332
|
+
#
|
333
|
+
#
|
334
|
+
#
|
335
|
+
|
336
|
+
# @!group Aliases
|
337
|
+
|
338
|
+
##
|
339
|
+
# @!method map_with_prev
|
340
|
+
# @overload map_with_prev(*args)
|
341
|
+
# @return [Object] The result of the map
|
342
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
343
|
+
# @overload map_with_prev(*args)
|
344
|
+
# @return [Enumerator] The external Enumerator
|
345
|
+
#
|
346
|
+
# Aliases for each_with_prev(*args).map
|
347
|
+
#
|
348
|
+
# @see each_with_prev
|
349
|
+
# @see collect_with_prev
|
350
|
+
# @see pmap
|
351
|
+
# @see pcollect
|
352
|
+
|
353
|
+
|
354
|
+
##
|
355
|
+
# @!method collect_with_prev
|
356
|
+
# @overload collect_with_prev(*args)
|
357
|
+
# @return [Object] The result of the map
|
358
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
359
|
+
# @overload collect_with_prev(*args)
|
360
|
+
# @return [Enumerator] The external Enumerator
|
361
|
+
#
|
362
|
+
# Aliases for each_with_prev(*args).map
|
363
|
+
#
|
364
|
+
# @see each_with_prev
|
365
|
+
# @see map_with_prev
|
366
|
+
# @see pmap
|
367
|
+
# @see pcollect
|
368
|
+
|
369
|
+
|
370
|
+
##
|
371
|
+
# @!method pmap
|
372
|
+
# @overload pmap(*args)
|
373
|
+
# @return [Object] The result of the map
|
374
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
375
|
+
# @overload pmap(*args)
|
376
|
+
# @return [Enumerator] The external Enumerator
|
377
|
+
#
|
378
|
+
# Aliases for each_with_prev(*args).map
|
379
|
+
#
|
380
|
+
# @see each_with_prev
|
381
|
+
# @see map_with_prev
|
382
|
+
# @see collect_with_prev
|
383
|
+
# @see pcollect
|
384
|
+
|
385
|
+
|
386
|
+
##
|
387
|
+
# @!method pcollect
|
388
|
+
# @overload pcollect(*args)
|
389
|
+
# @return [Object] The result of the map
|
390
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
391
|
+
# @overload pcollect(*args)
|
392
|
+
# @return [Enumerator] The external Enumerator
|
393
|
+
#
|
394
|
+
# Aliases for each_with_prev(*args).map
|
395
|
+
#
|
396
|
+
# @see each_with_prev
|
397
|
+
# @see map_with_prev
|
398
|
+
# @see collect_with_prev
|
399
|
+
# @see pmap
|
400
|
+
|
401
|
+
|
402
|
+
|
403
|
+
|
404
|
+
##
|
405
|
+
# @!method select_with_prev
|
406
|
+
# @overload select_with_prev(*args)
|
407
|
+
# @return [Object] The result of the map
|
408
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
409
|
+
# @overload select_with_prev(*args)
|
410
|
+
# @return [Enumerator] The external Enumerator
|
411
|
+
#
|
412
|
+
# Aliases for select.each_with_prev(*args)
|
413
|
+
#
|
414
|
+
# @see each_with_prev
|
415
|
+
# @see find_all_with_prev
|
416
|
+
# @see pselect
|
417
|
+
# @see pfind_all
|
418
|
+
|
419
|
+
|
420
|
+
##
|
421
|
+
# @!method find_all_with_prev
|
422
|
+
# @overload find_all_with_prev(*args)
|
423
|
+
# @return [Object] The result of the map
|
424
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
425
|
+
# @overload find_all_with_prev(*args)
|
426
|
+
# @return [Enumerator] The external Enumerator
|
427
|
+
#
|
428
|
+
# Aliases for select.each_with_prev(*args)
|
429
|
+
#
|
430
|
+
# @see each_with_prev
|
431
|
+
# @see select_with_prev
|
432
|
+
# @see pselect
|
433
|
+
# @see pfind_all
|
434
|
+
|
435
|
+
|
436
|
+
##
|
437
|
+
# @!method pselect
|
438
|
+
# @overload pselect(*args)
|
439
|
+
# @return [Object] The result of the map
|
440
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
441
|
+
# @overload pselect(*args)
|
442
|
+
# @return [Enumerator] The external Enumerator
|
443
|
+
#
|
444
|
+
# Aliases for select.each_with_prev(*args)
|
445
|
+
#
|
446
|
+
# @see each_with_prev
|
447
|
+
# @see select_with_prev
|
448
|
+
# @see find_all_with_prev
|
449
|
+
# @see pfind_all
|
450
|
+
|
451
|
+
|
452
|
+
##
|
453
|
+
# @!method pfind_all
|
454
|
+
# @overload pfind_all(*args)
|
455
|
+
# @return [Object] The result of the map
|
456
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
457
|
+
# @overload pfind_all(*args)
|
458
|
+
# @return [Enumerator] The external Enumerator
|
459
|
+
#
|
460
|
+
# Aliases for select.each_with_prev(*args)
|
461
|
+
#
|
462
|
+
# @see each_with_prev
|
463
|
+
# @see select_with_prev
|
464
|
+
# @see find_all_with_prev
|
465
|
+
# @see pselect
|
466
|
+
|
467
|
+
|
468
|
+
|
469
|
+
##
|
470
|
+
# @!method inject_with_prev
|
471
|
+
# @overload inject_with_prev(memo=first, *args)
|
472
|
+
# @return [Object] The result of the map
|
473
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
474
|
+
# @overload inject_with_prev(memo=first, *args)
|
475
|
+
# @return [Enumerator] The external Enumerator
|
476
|
+
#
|
477
|
+
# Aliases for inject(memo).each_with_prev(*args)
|
478
|
+
#
|
479
|
+
# @see each_with_prev
|
480
|
+
# @see reduce_with_prev
|
481
|
+
# @see pinject
|
482
|
+
# @see preduce
|
483
|
+
|
484
|
+
|
485
|
+
##
|
486
|
+
# @!method reduce_with_prev
|
487
|
+
# @overload reduce_with_prev(memo=first, *args)
|
488
|
+
# @return [Object] The result of the map
|
489
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
490
|
+
# @overload reduce_with_prev(memo=first, *args)
|
491
|
+
# @return [Enumerator] The external Enumerator
|
492
|
+
#
|
493
|
+
# Aliases for inject(memo).each_with_prev(*args)
|
494
|
+
#
|
495
|
+
# @see each_with_prev
|
496
|
+
# @see inject_with_prev
|
497
|
+
# @see pinject
|
498
|
+
# @see preduce
|
499
|
+
|
500
|
+
|
501
|
+
##
|
502
|
+
# @!method pinject
|
503
|
+
# @overload pinject(memo=first, *args)
|
504
|
+
# @return [Object] The result of the map
|
505
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
506
|
+
# @overload pinject(memo=first, *args)
|
507
|
+
# @return [Enumerator] The external Enumerator
|
508
|
+
#
|
509
|
+
# Aliases for inject(memo).each_with_prev(*args)
|
510
|
+
#
|
511
|
+
# @see each_with_prev
|
512
|
+
# @see inject_with_prev
|
513
|
+
# @see reduce_with_prev
|
514
|
+
# @see preduce
|
515
|
+
|
516
|
+
|
517
|
+
##
|
518
|
+
# @!method preduce
|
519
|
+
# @overload preduce(memo=first, *args)
|
520
|
+
# @return [Object] The result of the map
|
521
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_prev
|
522
|
+
# @overload preduce(memo=first, *args)
|
523
|
+
# @return [Enumerator] The external Enumerator
|
524
|
+
#
|
525
|
+
# Aliases for inject(memo).each_with_prev(*args)
|
526
|
+
#
|
527
|
+
# @see each_with_prev
|
528
|
+
# @see inject_with_prev
|
529
|
+
# @see reduce_with_prev
|
530
|
+
# @see pinject
|
531
|
+
|
532
|
+
|
533
|
+
|
534
|
+
##
|
535
|
+
# @!method map_with_window
|
536
|
+
# @overload map_with_window(*args)
|
537
|
+
# @return [Object] The result of the map
|
538
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
539
|
+
# @overload map_with_window(*args)
|
540
|
+
# @return [Enumerator] The external Enumerator
|
541
|
+
#
|
542
|
+
# Aliases for each_with_window(*args).map
|
543
|
+
#
|
544
|
+
# @see each_with_window
|
545
|
+
# @see collect_with_window
|
546
|
+
# @see wmap
|
547
|
+
# @see wcollect
|
548
|
+
|
549
|
+
|
550
|
+
##
|
551
|
+
# @!method collect_with_window
|
552
|
+
# @overload collect_with_window(*args)
|
553
|
+
# @return [Object] The result of the map
|
554
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
555
|
+
# @overload collect_with_window(*args)
|
556
|
+
# @return [Enumerator] The external Enumerator
|
557
|
+
#
|
558
|
+
# Aliases for each_with_window(*args).map
|
559
|
+
#
|
560
|
+
# @see each_with_window
|
561
|
+
# @see map_with_window
|
562
|
+
# @see wmap
|
563
|
+
# @see wcollect
|
564
|
+
|
565
|
+
|
566
|
+
##
|
567
|
+
# @!method wmap
|
568
|
+
# @overload wmap(*args)
|
569
|
+
# @return [Object] The result of the map
|
570
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
571
|
+
# @overload wmap(*args)
|
572
|
+
# @return [Enumerator] The external Enumerator
|
573
|
+
#
|
574
|
+
# Aliases for each_with_window(*args).map
|
575
|
+
#
|
576
|
+
# @see each_with_window
|
577
|
+
# @see map_with_window
|
578
|
+
# @see collect_with_window
|
579
|
+
# @see wcollect
|
580
|
+
|
581
|
+
|
582
|
+
##
|
583
|
+
# @!method wcollect
|
584
|
+
# @overload wcollect(*args)
|
585
|
+
# @return [Object] The result of the map
|
586
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
587
|
+
# @overload wcollect(*args)
|
588
|
+
# @return [Enumerator] The external Enumerator
|
589
|
+
#
|
590
|
+
# Aliases for each_with_window(*args).map
|
591
|
+
#
|
592
|
+
# @see each_with_window
|
593
|
+
# @see map_with_window
|
594
|
+
# @see collect_with_window
|
595
|
+
# @see wmap
|
596
|
+
|
597
|
+
|
598
|
+
|
599
|
+
|
600
|
+
##
|
601
|
+
# @!method select_with_window
|
602
|
+
# @overload select_with_window(*args)
|
603
|
+
# @return [Object] The result of the map
|
604
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
605
|
+
# @overload select_with_window(*args)
|
606
|
+
# @return [Enumerator] The external Enumerator
|
607
|
+
#
|
608
|
+
# Aliases for select.each_with_window(*args)
|
609
|
+
#
|
610
|
+
# @see each_with_window
|
611
|
+
# @see find_all_with_window
|
612
|
+
# @see wselect
|
613
|
+
# @see wfind_all
|
614
|
+
|
615
|
+
|
616
|
+
##
|
617
|
+
# @!method find_all_with_window
|
618
|
+
# @overload find_all_with_window(*args)
|
619
|
+
# @return [Object] The result of the map
|
620
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
621
|
+
# @overload find_all_with_window(*args)
|
622
|
+
# @return [Enumerator] The external Enumerator
|
623
|
+
#
|
624
|
+
# Aliases for select.each_with_window(*args)
|
625
|
+
#
|
626
|
+
# @see each_with_window
|
627
|
+
# @see select_with_window
|
628
|
+
# @see wselect
|
629
|
+
# @see wfind_all
|
630
|
+
|
631
|
+
|
632
|
+
##
|
633
|
+
# @!method wselect
|
634
|
+
# @overload wselect(*args)
|
635
|
+
# @return [Object] The result of the map
|
636
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
637
|
+
# @overload wselect(*args)
|
638
|
+
# @return [Enumerator] The external Enumerator
|
639
|
+
#
|
640
|
+
# Aliases for select.each_with_window(*args)
|
641
|
+
#
|
642
|
+
# @see each_with_window
|
643
|
+
# @see select_with_window
|
644
|
+
# @see find_all_with_window
|
645
|
+
# @see wfind_all
|
646
|
+
|
647
|
+
|
648
|
+
##
|
649
|
+
# @!method wfind_all
|
650
|
+
# @overload wfind_all(*args)
|
651
|
+
# @return [Object] The result of the map
|
652
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
653
|
+
# @overload wfind_all(*args)
|
654
|
+
# @return [Enumerator] The external Enumerator
|
655
|
+
#
|
656
|
+
# Aliases for select.each_with_window(*args)
|
657
|
+
#
|
658
|
+
# @see each_with_window
|
659
|
+
# @see select_with_window
|
660
|
+
# @see find_all_with_window
|
661
|
+
# @see wselect
|
662
|
+
|
663
|
+
|
664
|
+
|
665
|
+
##
|
666
|
+
# @!method inject_with_window
|
667
|
+
# @overload inject_with_window(memo=first, *args)
|
668
|
+
# @return [Object] The result of the map
|
669
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
670
|
+
# @overload inject_with_window(memo=first, *args)
|
671
|
+
# @return [Enumerator] The external Enumerator
|
672
|
+
#
|
673
|
+
# Aliases for inject(memo).each_with_window(*args)
|
674
|
+
#
|
675
|
+
# @see each_with_window
|
676
|
+
# @see reduce_with_window
|
677
|
+
# @see winject
|
678
|
+
# @see wreduce
|
679
|
+
|
680
|
+
|
681
|
+
##
|
682
|
+
# @!method reduce_with_window
|
683
|
+
# @overload reduce_with_window(memo=first, *args)
|
684
|
+
# @return [Object] The result of the map
|
685
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
686
|
+
# @overload reduce_with_window(memo=first, *args)
|
687
|
+
# @return [Enumerator] The external Enumerator
|
688
|
+
#
|
689
|
+
# Aliases for inject(memo).each_with_window(*args)
|
690
|
+
#
|
691
|
+
# @see each_with_window
|
692
|
+
# @see inject_with_window
|
693
|
+
# @see winject
|
694
|
+
# @see wreduce
|
695
|
+
|
696
|
+
|
697
|
+
##
|
698
|
+
# @!method winject
|
699
|
+
# @overload winject(memo=first, *args)
|
700
|
+
# @return [Object] The result of the map
|
701
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
702
|
+
# @overload winject(memo=first, *args)
|
703
|
+
# @return [Enumerator] The external Enumerator
|
704
|
+
#
|
705
|
+
# Aliases for inject(memo).each_with_window(*args)
|
706
|
+
#
|
707
|
+
# @see each_with_window
|
708
|
+
# @see inject_with_window
|
709
|
+
# @see reduce_with_window
|
710
|
+
# @see wreduce
|
711
|
+
|
712
|
+
|
713
|
+
##
|
714
|
+
# @!method wreduce
|
715
|
+
# @overload wreduce(memo=first, *args)
|
716
|
+
# @return [Object] The result of the map
|
717
|
+
# @yield [(*args), (*previous)] See the `expand` parameter of each_with_window
|
718
|
+
# @overload wreduce(memo=first, *args)
|
719
|
+
# @return [Enumerator] The external Enumerator
|
720
|
+
#
|
721
|
+
# Aliases for inject(memo).each_with_window(*args)
|
722
|
+
#
|
723
|
+
# @see each_with_window
|
724
|
+
# @see inject_with_window
|
725
|
+
# @see reduce_with_window
|
726
|
+
# @see winject
|
727
|
+
|
728
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "lookaround-enumerable"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "lookaround-enumerable"
|
8
|
+
spec.version = LookaroundEnum::VERSION
|
9
|
+
spec.authors = ["Patrick Plenefisch"]
|
10
|
+
spec.email = ["simonpatp@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Look around at neighbor elements in Enumerable methods}
|
13
|
+
spec.description = %q{Lookaround Enumerable allows acccessing previous and upcoming elements in Enumerable methods, so that computations can depend on a window of values. Particularly useful for dragged state, time series, and other semi-stateful computations.}
|
14
|
+
spec.homepage = "https://github.com/byteit101/lookaround-enumerable"
|
15
|
+
spec.license = "BSD-3-Clause"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
21
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
22
|
+
else
|
23
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
24
|
+
"public gem pushes."
|
25
|
+
end
|
26
|
+
|
27
|
+
# Specify which files should be added to the gem when it is released.
|
28
|
+
spec.files = [".rspec", "Gemfile", "README.md", "Rakefile", "lib/lookaround-enumerable.rb", "lookaround-enumerable.gemspec"]
|
29
|
+
|
30
|
+
spec.require_paths = ["lib"]
|
31
|
+
|
32
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
33
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
34
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lookaround-enumerable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Patrick Plenefisch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-10-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: Lookaround Enumerable allows acccessing previous and upcoming elements
|
56
|
+
in Enumerable methods, so that computations can depend on a window of values. Particularly
|
57
|
+
useful for dragged state, time series, and other semi-stateful computations.
|
58
|
+
email:
|
59
|
+
- simonpatp@gmail.com
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- ".rspec"
|
65
|
+
- Gemfile
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- lib/lookaround-enumerable.rb
|
69
|
+
- lookaround-enumerable.gemspec
|
70
|
+
homepage: https://github.com/byteit101/lookaround-enumerable
|
71
|
+
licenses:
|
72
|
+
- BSD-3-Clause
|
73
|
+
metadata:
|
74
|
+
homepage_uri: https://github.com/byteit101/lookaround-enumerable
|
75
|
+
source_code_uri: https://github.com/byteit101/lookaround-enumerable
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubygems_version: 3.0.3
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: Look around at neighbor elements in Enumerable methods
|
95
|
+
test_files: []
|