ract 0.2.0 → 0.3.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 +4 -4
- data/.rubocop.yml +84 -0
- data/README.md +17 -5
- data/lib/ract/class_methods.rb +53 -0
- data/lib/ract/configuration.rb +21 -0
- data/lib/ract/executor/isolated_abstract.rb +15 -0
- data/lib/ract/executor/isolated_thread.rb +52 -0
- data/lib/ract/ract.rb +1 -1
- data/lib/ract/settled.rb +3 -5
- data/lib/ract/version.rb +1 -1
- data/lib/ract.rb +4 -2
- metadata +7 -4
- data/lib/ract/batch.rb +0 -50
- data/lib/ract/singleton_methods.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ecff096a9e2b43c0c289ba25728a9948b768feb5c9b58d1921d012b4f753b5d
|
4
|
+
data.tar.gz: 5e68a831315a19d56823f8ebace7b3e1b3da916d98fc5bd36cf3afb9e19b8d42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0fa3ffc6fbbc2d5e593847de4b1cff4624f8bece56c3e2ca327ff1a45bb0e21d786a395447045f1740edc8a166a959a34ccadefa071ffef10527e41cca828e6
|
7
|
+
data.tar.gz: 6bf63a41dc25fe9699417f675bdcbfc89164973f17e6562d98f5f2dbd8c9691755684839f2e37d1cba4f39d3379ed93b08b877af7c767708d5598dc9442bd095
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
AllCops:
|
2
|
+
DisabledByDefault: false
|
3
|
+
NewCops: enable
|
4
|
+
TargetRubyVersion: 3.4
|
5
|
+
Exclude:
|
6
|
+
- 'vendor/**/*'
|
7
|
+
- 'bin/**/*'
|
8
|
+
- 'db/**/*'
|
9
|
+
- 'tmp/**/*'
|
10
|
+
- 'node_modules/**/*'
|
11
|
+
|
12
|
+
# Layout
|
13
|
+
Layout/LineLength:
|
14
|
+
Max: 120
|
15
|
+
|
16
|
+
Layout/EmptyLinesAroundModuleBody:
|
17
|
+
Enabled: true
|
18
|
+
|
19
|
+
Layout/EmptyLinesAroundClassBody:
|
20
|
+
Enabled: true
|
21
|
+
|
22
|
+
Layout/EmptyLinesAroundMethodBody:
|
23
|
+
Enabled: true
|
24
|
+
|
25
|
+
Layout/EmptyLinesAroundBlockBody:
|
26
|
+
Enabled: true
|
27
|
+
|
28
|
+
# Style
|
29
|
+
Style/Documentation:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Style/DocumentationMethod:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Style/StringLiterals:
|
36
|
+
EnforcedStyle: single_quotes
|
37
|
+
Enabled: true
|
38
|
+
|
39
|
+
Style/SymbolArray:
|
40
|
+
EnforcedStyle: brackets
|
41
|
+
Enabled: true
|
42
|
+
|
43
|
+
Style/WordArray:
|
44
|
+
EnforcedStyle: brackets
|
45
|
+
Enabled: true
|
46
|
+
|
47
|
+
Style/FrozenStringLiteralComment:
|
48
|
+
Enabled: true
|
49
|
+
SafeAutoCorrect: true
|
50
|
+
|
51
|
+
Style/TrailingCommaInArrayLiteral:
|
52
|
+
EnforcedStyleForMultiline: consistent_comma
|
53
|
+
|
54
|
+
Style/TrailingCommaInHashLiteral:
|
55
|
+
EnforcedStyleForMultiline: consistent_comma
|
56
|
+
|
57
|
+
# Metrics
|
58
|
+
Metrics/AbcSize:
|
59
|
+
Max: 20
|
60
|
+
|
61
|
+
Metrics/BlockLength:
|
62
|
+
Exclude:
|
63
|
+
- 'spec/**/*'
|
64
|
+
- '*.gemspec'
|
65
|
+
|
66
|
+
Metrics/ClassLength:
|
67
|
+
Max: 150
|
68
|
+
|
69
|
+
Metrics/MethodLength:
|
70
|
+
Max: 15
|
71
|
+
|
72
|
+
Metrics/CyclomaticComplexity:
|
73
|
+
Max: 8
|
74
|
+
|
75
|
+
# Naming
|
76
|
+
Naming/VariableName:
|
77
|
+
EnforcedStyle: snake_case
|
78
|
+
|
79
|
+
Naming/MethodName:
|
80
|
+
EnforcedStyle: snake_case
|
81
|
+
|
82
|
+
# Bundler
|
83
|
+
Bundler/OrderedGems:
|
84
|
+
Enabled: true
|
data/README.md
CHANGED
@@ -6,11 +6,15 @@
|
|
6
6
|
|
7
7
|
Ract is a lightweight Promise implementation for Ruby, simliar color promises in JavaScript providing a clean and intuitive way to handle asynchronous operations.
|
8
8
|
|
9
|
-
> [!NOTE]
|
10
|
-
>
|
9
|
+
> [!NOTE]
|
10
|
+
>
|
11
|
+
> This gem don't use Ractor, we just Threads/Fibers to handle async operations
|
12
|
+
>
|
11
13
|
> Enjoy with us!
|
12
14
|
|
15
|
+
|
13
16
|
[](https://github.com/thadeu/ract/actions/workflows/ci.yml)
|
17
|
+
[](https://badge.fury.io/rb/ract)
|
14
18
|
|
15
19
|
# Features
|
16
20
|
|
@@ -59,7 +63,11 @@ Create a new promise with a block that will be executed asynchronously:
|
|
59
63
|
# Create a promise that resolves with a value
|
60
64
|
promise = Ract.new { 42 } # or just Ract { 42 }
|
61
65
|
|
62
|
-
#
|
66
|
+
# Also use can you without .new
|
67
|
+
# IMO, That's is more readable
|
68
|
+
promise = Ract { 42 }
|
69
|
+
|
70
|
+
# Create a promise that might reject with an error inside de block
|
63
71
|
promise = Ract.new do
|
64
72
|
if success_condition
|
65
73
|
"Success result"
|
@@ -69,6 +77,9 @@ promise = Ract.new do
|
|
69
77
|
end
|
70
78
|
```
|
71
79
|
|
80
|
+
If you only create a IVar with `Ract`, it will be a pending promise, this promise will never resolve or reject itself,
|
81
|
+
you need to resolve it using `.then`, `.await`, `Ract#take`, `Ract#all`, `Ract#all_settled`
|
82
|
+
|
72
83
|
### Handling Promise Resolution
|
73
84
|
|
74
85
|
Use `.then` to handle successful resolution:
|
@@ -133,10 +144,11 @@ Wait for multiple promises to complete:
|
|
133
144
|
```ruby
|
134
145
|
# Wait for all promises to resolve (will raise an error if any promise rejects)
|
135
146
|
promises = [Ract.new { task1 }, Ract.new { task2 }]
|
136
|
-
|
147
|
+
|
148
|
+
combined = Ract.take(promises)
|
137
149
|
|
138
150
|
# Wait for all promises to resolve (will not raise errors, returns results with status)
|
139
|
-
combined = Ract.
|
151
|
+
combined = Ract.take(promises, raise_on_error: false)
|
140
152
|
|
141
153
|
# Get results when all are settled (resolved or rejected)
|
142
154
|
results = Ract.all_settled(promises)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true # :rdoc
|
2
|
+
|
3
|
+
class Ract
|
4
|
+
module ClassMethods
|
5
|
+
def resolve(value = nil, auto_execute: false)
|
6
|
+
new(auto_execute: true) { value }.await
|
7
|
+
end
|
8
|
+
|
9
|
+
def reject(reason = nil, auto_execute: false)
|
10
|
+
new(auto_execute: true) { raise Rejected, reason }.await
|
11
|
+
end
|
12
|
+
|
13
|
+
def all(array = [], raise_on_error: true, &block)
|
14
|
+
return [] if array.empty?
|
15
|
+
|
16
|
+
result = Settled.new(
|
17
|
+
array,
|
18
|
+
type: :all,
|
19
|
+
executor: executor,
|
20
|
+
raise_on_error: raise_on_error
|
21
|
+
).run!
|
22
|
+
|
23
|
+
block.call(result.value) if block_given?
|
24
|
+
|
25
|
+
result.value
|
26
|
+
end
|
27
|
+
alias take all
|
28
|
+
|
29
|
+
def all_settled(array = [], &block)
|
30
|
+
return [] if array.empty?
|
31
|
+
|
32
|
+
result = Settled.new(
|
33
|
+
array,
|
34
|
+
type: :all_settled,
|
35
|
+
executor: executor,
|
36
|
+
raise_on_error: false
|
37
|
+
).run!
|
38
|
+
|
39
|
+
block.call(result.value) if block_given?
|
40
|
+
|
41
|
+
result.value
|
42
|
+
end
|
43
|
+
|
44
|
+
def executor
|
45
|
+
case Ract.config.isolation_level
|
46
|
+
in :thread then Executor::IsolatedThread
|
47
|
+
else
|
48
|
+
raise ArgumentError, "Unknown executor: #{Ract.config.isolation_level}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
private :executor
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true # :rdoc:
|
2
|
+
|
3
|
+
class Ract
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :isolation_level
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@isolation_level = :thread
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def config
|
14
|
+
@config ||= Configuration.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def configure
|
18
|
+
yield config
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true # :rdoc
|
2
|
+
|
3
|
+
class Ract
|
4
|
+
class Executor
|
5
|
+
class IsolatedThread < IsolatedAbstract
|
6
|
+
attr_reader :promises, :remaining
|
7
|
+
|
8
|
+
def initialize(promises)
|
9
|
+
@promises = promises.keep_if { |promise| promise.is_a?(Ract) }
|
10
|
+
@queue = Thread::Queue.new
|
11
|
+
@remaining = promises.size
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(&block)
|
15
|
+
return if @promises.empty?
|
16
|
+
|
17
|
+
enqueue
|
18
|
+
dequeue(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def enqueue
|
22
|
+
@promises.each_with_index do |promise, index|
|
23
|
+
Thread.new do
|
24
|
+
try_block!(promise)
|
25
|
+
|
26
|
+
promise.then do |value|
|
27
|
+
@queue << [:success, index, value]
|
28
|
+
end&.rescue do |reason|
|
29
|
+
@queue << [:error, index, reason]
|
30
|
+
end
|
31
|
+
rescue StandardError => e
|
32
|
+
@queue << [:error, index, e]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def dequeue(&block)
|
38
|
+
while @remaining.positive?
|
39
|
+
block.call(@queue.pop)
|
40
|
+
@remaining -= 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def try_block!(arr)
|
45
|
+
return unless arr.respond_to?(:execute_block)
|
46
|
+
return unless arr.state == Ract::PENDING
|
47
|
+
|
48
|
+
arr.execute_block
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/ract/ract.rb
CHANGED
data/lib/ract/settled.rb
CHANGED
@@ -4,17 +4,15 @@ class Ract
|
|
4
4
|
class Settled
|
5
5
|
attr_reader :type, :raise_on_error
|
6
6
|
|
7
|
-
def initialize(promises, type: :all, raise_on_error: true)
|
7
|
+
def initialize(promises, executor: Executor::IsolatedThread, type: :all, raise_on_error: true)
|
8
8
|
@results = Array.new(promises.size)
|
9
|
-
@
|
9
|
+
@executor = executor.new(promises)
|
10
10
|
@type = type
|
11
11
|
@raise_on_error = raise_on_error
|
12
12
|
end
|
13
13
|
|
14
14
|
def run!
|
15
|
-
|
16
|
-
|
17
|
-
@batch.run! do |type, index, value|
|
15
|
+
@executor.run do |type, index, value|
|
18
16
|
case type
|
19
17
|
when :success
|
20
18
|
@results[index] = success_row(value)
|
data/lib/ract/version.rb
CHANGED
data/lib/ract.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'ract/version'
|
4
|
-
require 'ract/
|
4
|
+
require 'ract/executor/isolated_abstract'
|
5
|
+
require 'ract/executor/isolated_thread'
|
6
|
+
require 'ract/class_methods'
|
7
|
+
require 'ract/configuration'
|
5
8
|
require 'ract/result'
|
6
9
|
require 'ract/settled'
|
7
10
|
require 'ract/async'
|
8
|
-
require 'ract/singleton_methods'
|
9
11
|
require 'ract/ract'
|
10
12
|
|
11
13
|
# A lightweight Promise implementation for Ruby
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ract
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thadeu Esteves Jr
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-04-
|
10
|
+
date: 2025-04-18 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
description: A simple and lightweight gem to wrapper Threads(Promises) like JavaScript
|
13
13
|
in Ruby, adding a color to Ruby Threads
|
@@ -19,6 +19,7 @@ extra_rdoc_files: []
|
|
19
19
|
files:
|
20
20
|
- ".editorconfig"
|
21
21
|
- ".rspec"
|
22
|
+
- ".rubocop.yml"
|
22
23
|
- ".ruby-version"
|
23
24
|
- CHANGELOG.md
|
24
25
|
- Gemfile
|
@@ -30,11 +31,13 @@ files:
|
|
30
31
|
- images/ract-no-bg.png
|
31
32
|
- lib/ract.rb
|
32
33
|
- lib/ract/async.rb
|
33
|
-
- lib/ract/
|
34
|
+
- lib/ract/class_methods.rb
|
35
|
+
- lib/ract/configuration.rb
|
36
|
+
- lib/ract/executor/isolated_abstract.rb
|
37
|
+
- lib/ract/executor/isolated_thread.rb
|
34
38
|
- lib/ract/ract.rb
|
35
39
|
- lib/ract/result.rb
|
36
40
|
- lib/ract/settled.rb
|
37
|
-
- lib/ract/singleton_methods.rb
|
38
41
|
- lib/ract/version.rb
|
39
42
|
homepage: https://github.com/thadeu/ract
|
40
43
|
licenses:
|
data/lib/ract/batch.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true # :rdoc
|
2
|
-
|
3
|
-
class Ract
|
4
|
-
class Batch
|
5
|
-
attr_reader :promises, :remaining
|
6
|
-
|
7
|
-
def initialize(promises)
|
8
|
-
@promises = promises.keep_if { |promise| promise.is_a?(Ract) }
|
9
|
-
@queue = Thread::Queue.new
|
10
|
-
@remaining = promises.size
|
11
|
-
end
|
12
|
-
|
13
|
-
def run!(&block)
|
14
|
-
return if @promises.empty?
|
15
|
-
|
16
|
-
create_threads
|
17
|
-
process_results(&block)
|
18
|
-
end
|
19
|
-
|
20
|
-
def create_threads
|
21
|
-
@promises.each_with_index do |promise, index|
|
22
|
-
Thread.new do
|
23
|
-
try_block!(promise)
|
24
|
-
|
25
|
-
promise.then do |value|
|
26
|
-
@queue << [:success, index, value]
|
27
|
-
end&.rescue do |reason|
|
28
|
-
@queue << [:error, index, reason]
|
29
|
-
end
|
30
|
-
rescue StandardError => e
|
31
|
-
@queue << [:error, index, e]
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def process_results(&block)
|
37
|
-
while @remaining.positive?
|
38
|
-
block.call(@queue.pop)
|
39
|
-
@remaining -= 1
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def try_block!(promise)
|
44
|
-
return unless promise.respond_to?(:execute_block)
|
45
|
-
return unless promise.state == Ract::PENDING
|
46
|
-
|
47
|
-
promise.execute_block
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true # :rdoc
|
2
|
-
|
3
|
-
class Ract
|
4
|
-
module SingletonMethods
|
5
|
-
def resolve(value = nil, auto_execute: false)
|
6
|
-
new(auto_execute: true) { value }.await
|
7
|
-
end
|
8
|
-
|
9
|
-
def reject(reason = nil, auto_execute: false)
|
10
|
-
new(auto_execute: true) { raise Rejected, reason }.await
|
11
|
-
end
|
12
|
-
|
13
|
-
def all(promises, raise_on_error: true, auto_execute: false, &block)
|
14
|
-
return [] if promises.empty?
|
15
|
-
|
16
|
-
result = Settled.new(promises, raise_on_error: raise_on_error).run!
|
17
|
-
|
18
|
-
block.call(result.value) if block_given?
|
19
|
-
|
20
|
-
result.value
|
21
|
-
end
|
22
|
-
alias take all
|
23
|
-
|
24
|
-
def all_settled(promises, auto_execute: false, &block)
|
25
|
-
return [] if promises.empty?
|
26
|
-
|
27
|
-
result = Settled.new(promises, type: :all_settled).run!
|
28
|
-
|
29
|
-
block.call(result.value) if block_given?
|
30
|
-
|
31
|
-
result.value
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|