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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bdcd0b50628836af0d73557e4ed0b80f0830c7640dca4a135a66ab4df3ac2d3d
4
- data.tar.gz: a578255030f0f2dc32da32f74ed1f25ee87c30cea681d18ea54916b3f543e810
3
+ metadata.gz: 3ecff096a9e2b43c0c289ba25728a9948b768feb5c9b58d1921d012b4f753b5d
4
+ data.tar.gz: 5e68a831315a19d56823f8ebace7b3e1b3da916d98fc5bd36cf3afb9e19b8d42
5
5
  SHA512:
6
- metadata.gz: 533bd81a23a4c29c62ccbb740e28f7373231f7d8b09dec4717d6967a191eb49d5e30a7eba6a1b20ba1859cb6f55002cec2b4301f0558b22bcde9124188518252
7
- data.tar.gz: c42e55c294a61562c2c60255a31c01216faa27cab97730495e42cd2c24ceba2d7def0ce01a0de34fd70181ccff013bdacce01a00fbb3fcbc56ed33fb1b879ae2
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
- > This is dont use Ractor, we just Threads to handle async operations
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
  [![CI](https://github.com/thadeu/ract/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/thadeu/ract/actions/workflows/ci.yml)
17
+ [![Gem Version](https://badge.fury.io/rb/ract.svg)](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
- # Create a promise that might reject with an error
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
- combined = Ract.all(promises)
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.all(promises, raise_on_error: false)
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,15 @@
1
+ # frozen_string_literal: true # :rdoc
2
+
3
+ class Ract
4
+ class Executor
5
+ class IsolatedAbstract
6
+ def initialize(...)
7
+ raise NotImplementedError
8
+ end
9
+
10
+ def run(&block)
11
+ raise NotImplementedError
12
+ end
13
+ end
14
+ end
15
+ 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
@@ -113,7 +113,7 @@ class Ract
113
113
  alias catch rescue
114
114
 
115
115
  class << self
116
- include SingletonMethods
116
+ include ClassMethods
117
117
  end
118
118
 
119
119
  private
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
- @batch = Batch.new(promises)
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
- return Result.new([]) if @batch.promises.empty?
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true # :rdoc
2
2
 
3
3
  class Ract
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
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/batch'
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.2.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-17 00:00:00.000000000 Z
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/batch.rb
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