async-enumerable 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.standard.yml +5 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +416 -0
- data/Rakefile +127 -0
- data/benchmark/async_all.yaml +38 -0
- data/benchmark/async_any.yaml +39 -0
- data/benchmark/async_each.yaml +51 -0
- data/benchmark/async_find.yaml +37 -0
- data/benchmark/async_map.yaml +50 -0
- data/benchmark/async_select.yaml +31 -0
- data/benchmark/early_termination/any_early.yaml +17 -0
- data/benchmark/early_termination/any_late.yaml +17 -0
- data/benchmark/early_termination/find_middle.yaml +17 -0
- data/benchmark/size_comparison/map_10.yaml +17 -0
- data/benchmark/size_comparison/map_100.yaml +17 -0
- data/benchmark/size_comparison/map_1000.yaml +20 -0
- data/benchmark/size_comparison/map_10000.yaml +23 -0
- data/docs/reference/README.md +43 -0
- data/docs/reference/concurrency_bounder.md +234 -0
- data/docs/reference/enumerable.md +258 -0
- data/docs/reference/enumerator.md +221 -0
- data/docs/reference/methods/converters.md +97 -0
- data/docs/reference/methods/predicates.md +254 -0
- data/docs/reference/methods/transformers.md +104 -0
- data/lib/async/enumerable/comparable.rb +26 -0
- data/lib/async/enumerable/concurrency_bounder.rb +37 -0
- data/lib/async/enumerable/configurable.rb +140 -0
- data/lib/async/enumerable/methods/aggregators.rb +40 -0
- data/lib/async/enumerable/methods/converters.rb +21 -0
- data/lib/async/enumerable/methods/each.rb +39 -0
- data/lib/async/enumerable/methods/iterators.rb +27 -0
- data/lib/async/enumerable/methods/predicates/all.rb +47 -0
- data/lib/async/enumerable/methods/predicates/any.rb +47 -0
- data/lib/async/enumerable/methods/predicates/find.rb +55 -0
- data/lib/async/enumerable/methods/predicates/find_index.rb +50 -0
- data/lib/async/enumerable/methods/predicates/include.rb +23 -0
- data/lib/async/enumerable/methods/predicates/none.rb +27 -0
- data/lib/async/enumerable/methods/predicates/one.rb +48 -0
- data/lib/async/enumerable/methods/predicates.rb +29 -0
- data/lib/async/enumerable/methods/slicers.rb +34 -0
- data/lib/async/enumerable/methods/transformers/compact.rb +18 -0
- data/lib/async/enumerable/methods/transformers/filter_map.rb +19 -0
- data/lib/async/enumerable/methods/transformers/flat_map.rb +20 -0
- data/lib/async/enumerable/methods/transformers/map.rb +22 -0
- data/lib/async/enumerable/methods/transformers/reject.rb +19 -0
- data/lib/async/enumerable/methods/transformers/select.rb +21 -0
- data/lib/async/enumerable/methods/transformers/sort.rb +18 -0
- data/lib/async/enumerable/methods/transformers/sort_by.rb +19 -0
- data/lib/async/enumerable/methods/transformers/uniq.rb +18 -0
- data/lib/async/enumerable/methods/transformers.rb +35 -0
- data/lib/async/enumerable/methods.rb +26 -0
- data/lib/async/enumerable/version.rb +10 -0
- data/lib/async/enumerable.rb +72 -0
- data/lib/async/enumerator.rb +33 -0
- data/lib/enumerable/async.rb +38 -0
- data/scripts/debug_config.rb +26 -0
- data/scripts/debug_config2.rb +34 -0
- data/scripts/sketch.rb +30 -0
- data/scripts/test_aggregators.rb +66 -0
- data/scripts/test_ancestors.rb +12 -0
- data/scripts/test_async_chaining.rb +30 -0
- data/scripts/test_direct_method_calls.rb +53 -0
- data/scripts/test_example.rb +37 -0
- data/scripts/test_issue_7.rb +69 -0
- data/scripts/test_method_source.rb +15 -0
- metadata +145 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
# Methods that convert enumerables to other types.
|
7
|
+
module Converters
|
8
|
+
def self.included(base) = base.include(Configurable) # Dependency for collection resolution
|
9
|
+
|
10
|
+
# Converts enumerable to array.
|
11
|
+
# @return [Array] Array representation
|
12
|
+
def to_a
|
13
|
+
source = __async_enumerable_collection
|
14
|
+
# If source is self, we need to use super to avoid infinite recursion
|
15
|
+
(source == self) ? super : source.to_a
|
16
|
+
end
|
17
|
+
alias_method :sync, :to_a
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Each
|
7
|
+
def self.included(base)
|
8
|
+
base.include(::Enumerable) # Dependency
|
9
|
+
base.include(ConcurrencyBounder) # Dependency
|
10
|
+
base.include(Configurable) # Dependency for collection resolution
|
11
|
+
end
|
12
|
+
|
13
|
+
# Executes block for each element in parallel.
|
14
|
+
#
|
15
|
+
# This is the core of Async::Enumerable, as most of the enumerable
|
16
|
+
# methods _require_ #each in order to function. This definition of each
|
17
|
+
# is automatically included when `Async::Enumerable` is included, but it
|
18
|
+
# can be overridden by the including class. Here be dragons, though.
|
19
|
+
#
|
20
|
+
# @yield [item] Block to run for each element
|
21
|
+
# @return [self, Enumerator] Self for chaining or Enumerator without block
|
22
|
+
def each(&block)
|
23
|
+
return enum_for(__method__) unless block_given?
|
24
|
+
|
25
|
+
__async_enumerable_bounded_concurrency do |barrier|
|
26
|
+
__async_enumerable_collection.each do |item|
|
27
|
+
barrier.async do
|
28
|
+
block.call(item)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return self to allow chaining, like standard each
|
34
|
+
self
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
# Iterators module for enumerable iteration helper methods.
|
7
|
+
#
|
8
|
+
# Iteration helper methods are inherited from the standard Enumerable
|
9
|
+
# module. When used with async enumerables, these methods build on our
|
10
|
+
# async #each implementation, though some maintain sequential semantics
|
11
|
+
# where required by their nature.
|
12
|
+
#
|
13
|
+
# Methods available through Enumerable:
|
14
|
+
# - each_with_index: Iterates with index (block executes async)
|
15
|
+
# - each_with_object: Iterates with an accumulator object (block executes async)
|
16
|
+
# - each_cons: Iterates over consecutive n-element slices (maintains order)
|
17
|
+
# - each_slice: Iterates over n-element slices (block executes async per slice)
|
18
|
+
# - cycle: Cycles through elements repeatedly (block executes async)
|
19
|
+
# - with_index: Adds index to any enumerator
|
20
|
+
module Iterators
|
21
|
+
def self.included(base) = base.include(Each) # Dependency
|
22
|
+
# This module is intentionally empty as iteration methods are
|
23
|
+
# inherited from Enumerable
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Predicates
|
7
|
+
module All
|
8
|
+
def self.included(base)
|
9
|
+
base.include(::Enumerable) # Dependency
|
10
|
+
base.include(Configurable) # Dependency for collection resolution
|
11
|
+
base.include(ConcurrencyBounder) # Dependency
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns true if all elements satisfy the condition (parallel, early termination).
|
15
|
+
# @yield [item] Test condition for each element
|
16
|
+
# @return [Boolean] true if all elements match
|
17
|
+
def all?(pattern = nil, &block)
|
18
|
+
# Delegate pattern/no-block cases to wrapped enumerable to avoid break issues
|
19
|
+
if pattern
|
20
|
+
return __async_enumerable_collection.all?(pattern)
|
21
|
+
elsif !block_given?
|
22
|
+
return __async_enumerable_collection.all?
|
23
|
+
end
|
24
|
+
|
25
|
+
failed = Concurrent::AtomicBoolean.new(false)
|
26
|
+
|
27
|
+
__async_enumerable_bounded_concurrency(early_termination: true) do |barrier|
|
28
|
+
__async_enumerable_collection.each do |item|
|
29
|
+
break if failed.true?
|
30
|
+
|
31
|
+
barrier.async do
|
32
|
+
unless block.call(item)
|
33
|
+
failed.make_true
|
34
|
+
# Stop the barrier early when we find a failure
|
35
|
+
barrier.stop
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
!failed.true?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Predicates
|
7
|
+
module Any
|
8
|
+
def self.included(base)
|
9
|
+
base.include(::Enumerable) # Dependency
|
10
|
+
base.include(Configurable) # Dependency for collection resolution
|
11
|
+
base.include(ConcurrencyBounder) # Dependency
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns true if any element satisfies the condition (parallel, early termination).
|
15
|
+
# @yield [item] Test condition for each element
|
16
|
+
# @return [Boolean] true if any element matches
|
17
|
+
def any?(pattern = nil, &block)
|
18
|
+
# Delegate pattern/no-block cases to wrapped enumerable to avoid break issues
|
19
|
+
if pattern
|
20
|
+
return __async_enumerable_collection.any?(pattern)
|
21
|
+
elsif !block_given?
|
22
|
+
return __async_enumerable_collection.any?
|
23
|
+
end
|
24
|
+
|
25
|
+
found = Concurrent::AtomicBoolean.new(false)
|
26
|
+
|
27
|
+
__async_enumerable_bounded_concurrency(early_termination: true) do |barrier|
|
28
|
+
__async_enumerable_collection.each do |item|
|
29
|
+
break if found.true?
|
30
|
+
|
31
|
+
barrier.async do
|
32
|
+
if block.call(item)
|
33
|
+
found.make_true
|
34
|
+
# Stop the barrier early when we find a match
|
35
|
+
barrier.stop
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
found.true?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Predicates
|
7
|
+
module Find
|
8
|
+
def self.included(base)
|
9
|
+
base.include(::Enumerable) # Dependency
|
10
|
+
base.include(Configurable) # Dependency for collection resolution
|
11
|
+
base.include(ConcurrencyBounder) # Dependency
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns first element that satisfies condition (parallel, early termination).
|
15
|
+
# @note Returns the **fastest completing** match, not necessarily the first by position.
|
16
|
+
# Due to parallel execution, whichever element completes evaluation first will be returned.
|
17
|
+
# Use synchronous `find` if positional order matters.
|
18
|
+
# @yield [item] Test condition for each element
|
19
|
+
# @return [Object, nil] First matching element or nil
|
20
|
+
def find(ifnone = nil, &block)
|
21
|
+
return super unless block_given?
|
22
|
+
|
23
|
+
result = Concurrent::AtomicReference.new(nil)
|
24
|
+
|
25
|
+
__async_enumerable_bounded_concurrency(early_termination: true) do |barrier|
|
26
|
+
__async_enumerable_collection.each do |item|
|
27
|
+
break unless result.get.nil?
|
28
|
+
|
29
|
+
barrier.async do
|
30
|
+
if block.call(item)
|
31
|
+
# Use compare_and_set to ensure only the first match wins
|
32
|
+
if result.compare_and_set(nil, item)
|
33
|
+
# Stop the barrier early when we find a match
|
34
|
+
barrier.stop
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
found = result.get
|
42
|
+
if found.nil? && ifnone
|
43
|
+
ifnone.call
|
44
|
+
else
|
45
|
+
found
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Alias for find.
|
50
|
+
alias_method :detect, :find
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Predicates
|
7
|
+
module FindIndex
|
8
|
+
def self.included(base)
|
9
|
+
base.include(::Enumerable) # Dependency
|
10
|
+
base.include(Configurable) # Dependency for collection resolution
|
11
|
+
base.include(ConcurrencyBounder) # Dependency
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns index of first matching element (parallel, early termination).
|
15
|
+
# @note Returns the index of the **fastest completing** match, not necessarily the first by position.
|
16
|
+
# Due to parallel execution, whichever element completes evaluation first will have its index returned.
|
17
|
+
# Use synchronous `find_index` if positional order matters.
|
18
|
+
# @param value [Object] Value to find or omit for block form
|
19
|
+
# @return [Integer, nil] Index of first match or nil
|
20
|
+
def find_index(value = (no_value = true), &block)
|
21
|
+
if no_value && !block_given?
|
22
|
+
return enum_for(__method__)
|
23
|
+
end
|
24
|
+
|
25
|
+
result_index = Concurrent::AtomicReference.new(nil)
|
26
|
+
|
27
|
+
__async_enumerable_bounded_concurrency(early_termination: true) do |barrier|
|
28
|
+
__async_enumerable_collection.each_with_index do |item, index|
|
29
|
+
break unless result_index.get.nil?
|
30
|
+
|
31
|
+
barrier.async do
|
32
|
+
match = no_value ? block.call(item) : (item == value)
|
33
|
+
if match
|
34
|
+
# Use compare_and_set to ensure only the first match wins
|
35
|
+
if result_index.compare_and_set(nil, index)
|
36
|
+
# Stop the barrier early when we find a match
|
37
|
+
barrier.stop
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
result_index.get
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Predicates
|
7
|
+
module Include
|
8
|
+
def self.included(base) = base.include(Any) # Dependency
|
9
|
+
|
10
|
+
# Checks if enumerable includes the object (parallel, early termination).
|
11
|
+
# @param obj Object to search for
|
12
|
+
# @return [Boolean] true if found
|
13
|
+
def include?(obj)
|
14
|
+
any? { |item| item == obj }
|
15
|
+
end
|
16
|
+
|
17
|
+
# Alias for include?.
|
18
|
+
alias_method :member?, :include?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Predicates
|
7
|
+
module None
|
8
|
+
def self.included(base) = base.include(Any) # Dependency
|
9
|
+
|
10
|
+
# Returns true if no elements satisfy the condition (parallel, early termination).
|
11
|
+
# @yield [item] Test condition for each element
|
12
|
+
# @return [Boolean] true if no elements match
|
13
|
+
def none?(pattern = nil, &block)
|
14
|
+
# Delegate pattern/no-block cases to wrapped enumerable to avoid break issues
|
15
|
+
if pattern
|
16
|
+
return __async_enumerable_collection.none?(pattern)
|
17
|
+
elsif !block_given?
|
18
|
+
return __async_enumerable_collection.none?
|
19
|
+
end
|
20
|
+
# For blocks, use our async any? and negate
|
21
|
+
!any?(&block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Predicates
|
7
|
+
module One
|
8
|
+
def self.included(base)
|
9
|
+
base.include(::Enumerable) # Dependency
|
10
|
+
base.include(Configurable) # Dependency for collection resolution
|
11
|
+
base.include(ConcurrencyBounder) # Dependency
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns true if exactly one element satisfies the condition (parallel).
|
15
|
+
# @yield [item] Test condition for each element
|
16
|
+
# @return [Boolean] true if exactly one element matches
|
17
|
+
def one?(pattern = nil, &block)
|
18
|
+
# Delegate pattern/no-block cases to wrapped enumerable to avoid break issues
|
19
|
+
if pattern
|
20
|
+
return __async_enumerable_collection.one?(pattern)
|
21
|
+
elsif !block_given?
|
22
|
+
return __async_enumerable_collection.one?
|
23
|
+
end
|
24
|
+
|
25
|
+
count = Concurrent::AtomicFixnum.new(0)
|
26
|
+
|
27
|
+
__async_enumerable_bounded_concurrency(early_termination: true) do |barrier|
|
28
|
+
__async_enumerable_collection.each do |item|
|
29
|
+
break if count.value > 1
|
30
|
+
|
31
|
+
barrier.async do
|
32
|
+
if block.call(item)
|
33
|
+
if count.increment > 1
|
34
|
+
# Stop the barrier early when we have too many matches
|
35
|
+
barrier.stop
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
count.value == 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "async/enumerable/methods/predicates/all"
|
4
|
+
require "async/enumerable/methods/predicates/any"
|
5
|
+
require "async/enumerable/methods/predicates/find"
|
6
|
+
require "async/enumerable/methods/predicates/find_index"
|
7
|
+
require "async/enumerable/methods/predicates/include"
|
8
|
+
require "async/enumerable/methods/predicates/none"
|
9
|
+
require "async/enumerable/methods/predicates/one"
|
10
|
+
|
11
|
+
module Async
|
12
|
+
module Enumerable
|
13
|
+
module Methods
|
14
|
+
# Predicates contains async implementations of enumerable predicate methods
|
15
|
+
# that can terminate early when their condition is met or violated.
|
16
|
+
module Predicates
|
17
|
+
def self.included(base)
|
18
|
+
base.include All
|
19
|
+
base.include Any
|
20
|
+
base.include Find
|
21
|
+
base.include FindIndex
|
22
|
+
base.include Include
|
23
|
+
base.include None
|
24
|
+
base.include One
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
# Slicers module for enumerable slicing and filtering methods.
|
7
|
+
#
|
8
|
+
# Slicing and filtering methods are inherited from the standard Enumerable
|
9
|
+
# module. When used with async enumerables, methods that accept blocks
|
10
|
+
# automatically benefit from parallel execution through our async #each
|
11
|
+
# implementation.
|
12
|
+
#
|
13
|
+
# Methods available through Enumerable:
|
14
|
+
# - drop/drop_while: Drops elements from the beginning (block executes async)
|
15
|
+
# - take/take_while: Takes elements from the beginning (delegated for efficiency)
|
16
|
+
# - grep/grep_v: Filters elements matching/not matching a pattern (block executes async)
|
17
|
+
# - partition: Splits into two arrays based on a predicate (block executes async)
|
18
|
+
# - chunk/chunk_while: Groups consecutive elements (maintains order)
|
19
|
+
# - slice_before/slice_after/slice_when: Slices based on conditions (block executes async)
|
20
|
+
module Slicers
|
21
|
+
def self.included(base)
|
22
|
+
base.include(Each) # Dependency
|
23
|
+
base.include(Configurable) # Dependency for collection resolution
|
24
|
+
|
25
|
+
# Delegate non-parallelizable slicer methods directly to the collection
|
26
|
+
base.extend(Forwardable)
|
27
|
+
base.def_delegators :__async_enumerable_collection, :first, :take, :take_while
|
28
|
+
end
|
29
|
+
# This module is intentionally empty as slicing methods are
|
30
|
+
# inherited from Enumerable and automatically use our async #each
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Transformers
|
7
|
+
module Compact
|
8
|
+
def self.included(base) = base.include(Each) # Dependency
|
9
|
+
|
10
|
+
# Async version of compact that returns an Async::Enumerator for chaining
|
11
|
+
def compact
|
12
|
+
Async::Enumerator.new(super, __async_enumerable_config)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Transformers
|
7
|
+
module FilterMap
|
8
|
+
def self.included(base) = base.include(Each) # Dependency
|
9
|
+
|
10
|
+
# Async version of filter_map that returns an Async::Enumerator for chaining
|
11
|
+
def filter_map(&block)
|
12
|
+
return enum_for(__method__) unless block_given?
|
13
|
+
Async::Enumerator.new(super, __async_enumerable_config)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Transformers
|
7
|
+
module FlatMap
|
8
|
+
def self.included(base) = base.include(Each) # Dependency
|
9
|
+
|
10
|
+
# Async version of flat_map that returns an Async::Enumerator for chaining
|
11
|
+
def flat_map(&block)
|
12
|
+
return enum_for(__method__) unless block_given?
|
13
|
+
Async::Enumerator.new(super, __async_enumerable_config)
|
14
|
+
end
|
15
|
+
alias_method :collect_concat, :flat_map
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Transformers
|
7
|
+
module Map
|
8
|
+
def self.included(base) = base.include(Each) # Dependency
|
9
|
+
|
10
|
+
# Maps elements in parallel, returns async enumerator.
|
11
|
+
# @yield [item] Transform for each element
|
12
|
+
# @return [Async::Enumerator] Transformed collection
|
13
|
+
def map(&block)
|
14
|
+
return enum_for(__method__) unless block_given?
|
15
|
+
Async::Enumerator.new(super, __async_enumerable_config)
|
16
|
+
end
|
17
|
+
alias_method :collect, :map
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Transformers
|
7
|
+
module Reject
|
8
|
+
def self.included(base) = base.include(Each) # Dependency
|
9
|
+
|
10
|
+
# Async version of reject that returns an Async::Enumerator for chaining
|
11
|
+
def reject(&block)
|
12
|
+
return enum_for(__method__) unless block_given?
|
13
|
+
Async::Enumerator.new(super, __async_enumerable_config)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Transformers
|
7
|
+
module Select
|
8
|
+
def self.included(base) = base.include(Each) # Dependency
|
9
|
+
|
10
|
+
# Async version of select that returns an Async::Enumerator for chaining
|
11
|
+
def select(&block)
|
12
|
+
return enum_for(__method__) unless block_given?
|
13
|
+
Async::Enumerator.new(super, __async_enumerable_config)
|
14
|
+
end
|
15
|
+
alias_method :filter, :select
|
16
|
+
alias_method :find_all, :select
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Transformers
|
7
|
+
module Sort
|
8
|
+
def self.included(base) = base.include(Each) # Dependency
|
9
|
+
|
10
|
+
# Async version of sort that returns an Async::Enumerator for chaining
|
11
|
+
def sort(&block)
|
12
|
+
Async::Enumerator.new(super, __async_enumerable_config)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Transformers
|
7
|
+
module SortBy
|
8
|
+
def self.included(base) = base.include(Each) # Dependency
|
9
|
+
|
10
|
+
# Async version of sort_by that returns an Async::Enumerator for chaining
|
11
|
+
def sort_by(&block)
|
12
|
+
return enum_for(__method__) unless block_given?
|
13
|
+
Async::Enumerator.new(super, __async_enumerable_config)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Async
|
4
|
+
module Enumerable
|
5
|
+
module Methods
|
6
|
+
module Transformers
|
7
|
+
module Uniq
|
8
|
+
def self.included(base) = base.include(Each) # Dependency
|
9
|
+
|
10
|
+
# Async version of uniq that returns an Async::Enumerator for chaining
|
11
|
+
def uniq(&block)
|
12
|
+
Async::Enumerator.new(super, __async_enumerable_config)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "async/enumerable/methods/transformers/compact"
|
4
|
+
require "async/enumerable/methods/transformers/filter_map"
|
5
|
+
require "async/enumerable/methods/transformers/flat_map"
|
6
|
+
require "async/enumerable/methods/transformers/map"
|
7
|
+
require "async/enumerable/methods/transformers/reject"
|
8
|
+
require "async/enumerable/methods/transformers/select"
|
9
|
+
|
10
|
+
require "async/enumerable/methods/transformers/sort"
|
11
|
+
require "async/enumerable/methods/transformers/sort_by"
|
12
|
+
require "async/enumerable/methods/transformers/uniq"
|
13
|
+
|
14
|
+
module Async
|
15
|
+
module Enumerable
|
16
|
+
module Methods
|
17
|
+
# Transformers contains async implementations of enumerable transformation methods
|
18
|
+
# that transform collections into new collections.
|
19
|
+
module Transformers
|
20
|
+
def self.included(base)
|
21
|
+
base.include Compact
|
22
|
+
base.include FilterMap
|
23
|
+
base.include FlatMap
|
24
|
+
base.include Map
|
25
|
+
base.include Reject
|
26
|
+
base.include Select
|
27
|
+
|
28
|
+
base.include Sort
|
29
|
+
base.include SortBy
|
30
|
+
base.include Uniq
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|