Ract is a lightweight Promise implementation for Ruby, simliar color promises in JavaScript providing a clean and intuitive way to handle asynchronous operations.
Note
This gem don't use Ractor, we just Threads/Fibers to handle async operations
Enjoy with us!
- Thread-safe
- Similar to JavaScript Promises
- Clean and intuitive API
- Easy to use
Install the gem and add to the application's Gemfile by executing:
gem 'ract'
And then execute:
$ bundle install
or using add
$ bundle add ract
Or install it yourself as:
$ gem install ract
require 'ract'
Create a new promise with a block that will be executed asynchronously:
# Create a promise that resolves with a value
promise = Ract.new { 42 } # or just Ract { 42 }
# Also use can you without .new
# IMO, That's is more readable
promise = Ract { 42 }
# Create a promise that might reject with an error inside de block
promise = Ract.new do
if success_condition
"Success result"
else
raise "Something went wrong"
end
end
If you only create a IVar with Ract
, it will be a pending promise, this promise will never resolve or reject itself,
you need to resolve it using .then
, .await
, Ract#take
, Ract#all
, Ract#all_settled
Use .then
to handle successful resolution:
promise = Ract.new { 42 }
promise.then do |value|
puts "The answer is #{value}"
end
Use .rescue
(or its alias .catch
) to handle rejections:
promise = Ract.new { raise "Something went wrong" }
promise
.then { |value| puts "This won't be called" }
.rescue { |error| puts "Error: #{error.message}" }
Promises can be chained for sequential asynchronous operations:
Ract.new { fetch_user(user_id) }
.then { |user| fetch_posts(user.id) }
.and_then { |posts| render_posts(posts) }
.rescue { |error| handle_error(error) }
.catch { |error| handle_error(error) }
If you need to wait for a promise to resolve, use .await
:
promise = Ract.new { time_consuming_operation }
result = promise.await # Blocks until the promise resolves
Create already resolved or rejected promises:
# Already resolved promise
promise = Ract.resolve(42)
# Already rejected promise
promise = Ract.reject("Something went wrong")
Wait for multiple promises to complete:
# Wait for all promises to resolve (will raise an error if any promise rejects)
promises = [Ract.new { task1 }, Ract.new { task2 }]
combined = Ract.take(promises)
# Wait for all promises to resolve (will not raise errors, returns results with status)
combined = Ract.take(promises, raise_on_error: false)
# Get results when all are settled (resolved or rejected)
results = Ract.all_settled(promises)
You can use a block to receive result
tasks = [ ract { "mylogs" } ]
Ract.take(tasks) { p it }
# ["mylogs"]
This update properly explains that:
- By default,
Ract.all
will raise an error if any of the promises are rejected - You can set
raise_on_error: false
to get all results regardless of whether they resolved or rejected - Alternatively, you can use
Ract.all_settled
to get results for all promises whether they resolved or rejected
If you need to execute a block immediately with the current value, regardless of the promise state:
promise = Ract.new { 42 }
promise.then { |value| puts "Current value: #{value}" }
Ract supports an async/await pattern similar to JavaScript:
# Define an async method
async def fetch_data
user = fetch_user(user_id)
posts = fetch_posts(user.id)
comments = fetch_comments(posts.first.id)
return { user: user, posts: posts, comments: comments }
end
# Use the async method
result = fetch_data.await
class Dynamo
async def self.get_item(table, key)
{ Item: {} }
end
end
tasks = [
Dynamo.get_item_async('users', 1),
Dynamo.get_item_async('posts', 1),
Dynamo.get_item_async('comments', 1)
]
result_all = Ract.all(tasks, raise_on_error: false)
result_taken = Ract.take(tasks, raise_on_error: false)
p result_all
# [{ Item: {} }, { Item: {} }, { Item: {} }]
p result_taken
# [{ Item: {} }, { Item: {} }, { Item: {} }]
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/thadeu/ract.
The gem is available as open source under the terms of the MIT License.