Skip to content
/ ract Public

Ract is a lightweight Promise implementation for Ruby, simliar color promises in JavaScript

License

Notifications You must be signed in to change notification settings

thadeu/ract

Repository files navigation

Ract Logo

Ract

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!

CI Gem Version

Features

  • Thread-safe
  • Similar to JavaScript Promises
  • Clean and intuitive API
  • Easy to use

Installation

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

Usage

require 'ract'

Basic Usage

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

Handling Promise Resolution

Use .then to handle successful resolution:

promise = Ract.new { 42 }

promise.then do |value|
  puts "The answer is #{value}"
end

Error Handling

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}" }

Chaining Promises

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) }

Waiting for Resolution

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

Creating Pre-resolved Promises

Create already resolved or rejected promises:

# Already resolved promise
promise = Ract.resolve(42)

# Already rejected promise
promise = Ract.reject("Something went wrong")

Combining Multiple Promises

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)

Using block

You can use a block to receive result

tasks = [ ract { "mylogs" } ]

Ract.take(tasks) { p it }
# ["mylogs"]

This update properly explains that:

  1. By default, Ract.all will raise an error if any of the promises are rejected
  2. You can set raise_on_error: false to get all results regardless of whether they resolved or rejected
  3. Alternatively, you can use Ract.all_settled to get results for all promises whether they resolved or rejected

Immediate Execution

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}" }

Async/Await Pattern

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

Examples using many callable promises

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: {} }]

Development

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.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/thadeu/ract.

License

The gem is available as open source under the terms of the MIT License.

About

Ract is a lightweight Promise implementation for Ruby, simliar color promises in JavaScript

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published