async-promise 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/changelog.md +48 -0
- data/lib/async/promise.rb +279 -0
- data/readme.md +35 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 763599aeac2aaa69d7c7d102d442d1bf684ab07f2d75fc6d51701eeb98c46724
|
4
|
+
data.tar.gz: faaf3deb61d7a62ded3d5173705838be52d783add35a5d4a6cb9c41caccf013a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3c8b6e6bdb75ea524ea3e686bbfe5d60d2732c05f28961285c720417c6e87bea6a1d8fb74c2cab55db13706eb0d92b60d360b28a451964b1881a57482bf32673
|
7
|
+
data.tar.gz: 00f1697f14ec5843ff253c78ea21faec67d52dca78fc98d4d629596398e1c89e03fb964037d0b887d910187da91ede9c93cb0cda02d4901a769b65cd9a24f52e
|
data/changelog.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
## [Unreleased]
|
2
|
+
|
3
|
+
|
4
|
+
## [0.1.0] - 2024-10-03
|
5
|
+
|
6
|
+
### Summary
|
7
|
+
- Initial release
|
8
|
+
|
9
|
+
### Added
|
10
|
+
- Ability to create Javascript ES6 like [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) via the `Async::Promise` class.
|
11
|
+
- Add the following `Promise` instance methods:
|
12
|
+
- `#status(): "pending" | "fulfilled" | "rejected"`
|
13
|
+
- get the status of a promise, which can either be `"pending"`, `"fulfilled"`, or `"rejected"`.
|
14
|
+
- when a promise is either `"fulfilled"` or `"rejected"`, we say that it has been *settled*.
|
15
|
+
- `#resolve(value?: T): void`
|
16
|
+
- resolve a `"pending"` promise with the given `value`, and set the `#status` of the promise to `"fulfilled"`.
|
17
|
+
- an already settled promise cannot be resolved nor rejected again.
|
18
|
+
- `#reject(reason?: String | StandardException): void`
|
19
|
+
- reject a `"pending"` promise with the given `reason`, and set the `#status` of the promise to `"rejected"`.
|
20
|
+
- an already settled promise cannot be resolved nor rejected again.
|
21
|
+
- `#then(on_resolve?: nil | ((value: T) => (V | Promise<V>)), on_reject?: nil | ((reason: String | StandardException) => (V | Promise<V>))): Promise<V>`
|
22
|
+
- chain the current promise with an `on_resolve` and an `on_reject` function, which shall be called when the current promise is resolved.
|
23
|
+
- the returned value is another promise, that is resolved once either the `on_resolve` or `on_reject` are ran successfully.
|
24
|
+
- when either the `on_resolve` or `on_reject` functions are `nil`, the supposed `value`/`reason` they are to receive will be passed onto the dependent promises of the returned promise.
|
25
|
+
in a way, it will behave as if `on_resolve = ->(value) { return value }` and `on_reject = ->(reason) { raise reason }`.
|
26
|
+
- `#catch(on_reject?: nil | ((reason: String | StandardException) => (V | Promise<V>)))`
|
27
|
+
- catch any raised exceptions that have occurred in preceding chain of promises.
|
28
|
+
- this is functionally equivalent to `some_promise.then(nil, ->(reason){ "take care of the error" })`
|
29
|
+
- `#wait(): T`
|
30
|
+
- wait for a promise to settle, similar to how one can await a promise in javascript via `await some_promise`.
|
31
|
+
- the returned value will be the resolved value of the promise (i.e. when the status is `"fulfilled"`), or it will raise an error if the promise was rejected (i.e. when the status is `"rejected"`).
|
32
|
+
- Add the following `Promise` class methods:
|
33
|
+
- `.resolve(value?: T): Promise<T>`
|
34
|
+
- creates an already resolved promise.
|
35
|
+
- `.reject(reason?: String | StandardException): Promise<T>`
|
36
|
+
- creates an already rejected promise.
|
37
|
+
- `.all(promises: Array<Promise<T>>): Promise<Array<T>>`
|
38
|
+
- create a new promise that resolves when all of its input promises have been resolved, and rejects when any single input promise is rejected.
|
39
|
+
- `.race(promises: Array<Promise<T>>): Promise<T>`
|
40
|
+
- create a new promise that either rejects or resolves based on whichever encompassing promise settles first.
|
41
|
+
- `.timeout(resolve_in: Float, reject_in: Float, resolve: T, reject: String, StandardError): Promise<T>`
|
42
|
+
- create a promise that either resolves or rejects after a given timeout.
|
43
|
+
|
44
|
+
### Dependency
|
45
|
+
- Add dependency on the [async](https://github.com/socketry/async) gem.
|
46
|
+
More specifically, the library depends on the following two constructs of the said gem:
|
47
|
+
- `Async` Kernel block
|
48
|
+
- `Async::Variable` Class
|
@@ -0,0 +1,279 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "async"
|
4
|
+
require "async/variable"
|
5
|
+
|
6
|
+
module Async
|
7
|
+
# An Asynchronous Promise (of generic type `T`) holds necessary information about what should be executed when the promise is resolved or rejected,
|
8
|
+
# and which child Promise nodes to propagate the output values of the resolver/rejector to.
|
9
|
+
class Promise < Async::Variable
|
10
|
+
VERSION = "0.1.0"
|
11
|
+
|
12
|
+
alias_method :async_resolve, :resolve # rename the `Async::Variable.resolve` instance method to `async_resolve`, since we will be using the same method name for our own logic of resolving values.
|
13
|
+
alias_method :async_wait, :wait # rename the `Async::Variable.wait` instance method to `async_wait`, since we will need to tap into the waiting process to raise any errors that may have occurred during the process.
|
14
|
+
|
15
|
+
# @param on_resolve [(value) => next_value_or_promise, nil] the function to call when the promise is resolved with a value.
|
16
|
+
# @param on_reject [(reason) => next_value_or_promise, nil] the function to call when the promise is rejected (either manually or due to a raised error).
|
17
|
+
def initialize(on_resolve = nil, on_reject = nil)
|
18
|
+
super()
|
19
|
+
# @type ["pending", "fulfilled", "rejected"] Represents the current state of this Promise node.
|
20
|
+
@status = "pending"
|
21
|
+
# @type [Array<Promise>] An array of child [Promise] nodes that will be notified when this promise resolves.
|
22
|
+
# the resulting structure is a tree-like, and we shall traverse them in DFS (depth first search).
|
23
|
+
@children = []
|
24
|
+
# @type [Any] the value of type `T` that will be assigned to this node when it resolves.
|
25
|
+
# this value is kept purely for the sake of providing latecomer-then calls with a resolve value (if the `@status` was "fulfilled")
|
26
|
+
# a latecomer is when a call to the [then] or [catch] method is made after the promise has already been "fulfilled".
|
27
|
+
@value = nil
|
28
|
+
# @type [String, StandardError] the error reason that will be assigned to this node when it is rejected.
|
29
|
+
# this value is kept purely for the sake of providing latecomer-then calls with a rejection reason (if the `@status` was "rejected")
|
30
|
+
# a latecomer is when a call to the [then] or [catch] method is made after the promise has already been "rejected".
|
31
|
+
@reason = nil
|
32
|
+
@on_resolve = on_resolve
|
33
|
+
@on_reject = on_reject
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create a new Promise that is already resolved with the provided [value] of type `T`.
|
37
|
+
# @param value [T, Promise<T>] Generic value of type `T`.
|
38
|
+
# return [Promise<T>] The newly created (and resolved) promise is returned.
|
39
|
+
# TODO: create unit test, and maybe reduce the amount of pre-resolved promises you create in your tests through the use of this
|
40
|
+
def self.resolve(value = nil)
|
41
|
+
new_promise = new()
|
42
|
+
new_promise.resolve(value)
|
43
|
+
new_promise
|
44
|
+
end
|
45
|
+
|
46
|
+
# Create a new Promise that is already rejected with the provided [reason].
|
47
|
+
# WARNING: Do not pass a `nil` as the reason, because it will break the error handling logic, since it will seem to it like there was no error.
|
48
|
+
# @param reason [String, StandardError] Give the reason for rejection.
|
49
|
+
# return [Promise<nil>] The newly created (and rejected) promise is returned.
|
50
|
+
# TODO: create unit test, and maybe reduce the amount of pre-resolved rejects you create in your tests through the use of this
|
51
|
+
def self.reject(reason = "Promise error")
|
52
|
+
new_promise = new()
|
53
|
+
new_promise.reject(reason)
|
54
|
+
new_promise
|
55
|
+
end
|
56
|
+
|
57
|
+
# Create a new Promise that resolves when all of its input promises have been resolved, and rejects when any single input promise is rejected.
|
58
|
+
# @param promises [Array<[T, Promise<T>]>] Provide all of the input T or Promise<T> to wait for, in order to resolve.
|
59
|
+
# return [Promise<Array<T>>] Returns a Promise which, when resolved, contains the array of all resolved values.
|
60
|
+
# TODO: create unit test
|
61
|
+
def self.all(promises = [])
|
62
|
+
# we must return early on if no promises we given, since nothing will then resolve the new_promise.
|
63
|
+
return self.resolve([]) if promises.empty?
|
64
|
+
# next, we make sure that all values within the `promises` array are actual `Promise`s. the ones that aren't, are converted to a resolved promise.
|
65
|
+
promises = promises.map { |p| p.is_a?(Promise) ? p : self.resolve(p) }
|
66
|
+
resolved_values = []
|
67
|
+
remaining_promises = promises.length
|
68
|
+
new_promise = new()
|
69
|
+
|
70
|
+
# The following may not be the prettiest implementation. TODO: consider if you can use a Array.map for this function
|
71
|
+
promises.each_with_index { |promise, index|
|
72
|
+
promise.then(->(value) {
|
73
|
+
resolved_values[index] = value
|
74
|
+
remaining_promises -= 1
|
75
|
+
if remaining_promises == 0
|
76
|
+
new_promise.resolve(resolved_values)
|
77
|
+
end
|
78
|
+
}, ->(reason) {
|
79
|
+
# if there is any rejected dependency promise, we should immediately reject our new_promise
|
80
|
+
# note that this is somewhat of a error-racing scenario, since the new promise will be rejected due to the first error it encounters.
|
81
|
+
# i.e. its order can vary from time to time, possibly resulting in different kinds of rejection reasons
|
82
|
+
new_promise.reject(reason)
|
83
|
+
})
|
84
|
+
}
|
85
|
+
new_promise
|
86
|
+
end
|
87
|
+
|
88
|
+
# TODO: implement `Promise.allSettled` static method
|
89
|
+
|
90
|
+
# Create a new Promise that either rejects or resolves based on whichever encompassing promise settles first.
|
91
|
+
# The value it either resolves or rejects with, will be inherited by the promise that wins the race.
|
92
|
+
# @param promises [Array<[T, Promise<T>]>] Provide all of the input Promise<T> to wait for, in order to resolve.
|
93
|
+
# return [Promise<Array<T>>] Returns a Promise which, when resolved, contains the array of all resolved values.
|
94
|
+
def self.race(promises)
|
95
|
+
# if any of the promises happens to be a regular value (i.e. not an Promise), then we will just return that (whichever one that we encounter first)
|
96
|
+
promises.each { |p|
|
97
|
+
unless p.is_a?(Promise)
|
98
|
+
return self.resolve(p)
|
99
|
+
end
|
100
|
+
}
|
101
|
+
new_promise = new()
|
102
|
+
# in the racing condition, there is no need to check if `new_promise` was already settled, because the `resolve` and `reject` methods already ignore requests made after the resolve/reject.
|
103
|
+
# thus it is ok for our each loop to mindlessly and rapidly call `new_promise.resolve` and `new_promise.reject` with no consequences (might affect performance? probably just a micro optimization).
|
104
|
+
promises.each { |promise|
|
105
|
+
promise.then(
|
106
|
+
->(value) { new_promise.resolve(value) },
|
107
|
+
->(reason) { new_promise.reject(reason) },
|
108
|
+
)
|
109
|
+
}
|
110
|
+
new_promise
|
111
|
+
end
|
112
|
+
|
113
|
+
# Create a promise that either resolves or rejects after a given timeout.
|
114
|
+
# @param resolve_in [Float, nil] The time in seconds to wait before resolving with keyword-value `resolve` (if provided).
|
115
|
+
# @param reject_in [Float, nil] The time in seconds to wait before rejecting with keyword-reason `reject` (if provided).
|
116
|
+
# @param resolve [Any] The value to resolve with after `resolve_in` seconds.
|
117
|
+
# @param reject [String, StandardError] The reason to reject after `reject_in` seconds.
|
118
|
+
def self.timeout(resolve_in = nil, reject_in = nil, resolve: nil, reject: "Promise timeout")
|
119
|
+
new_promise = new
|
120
|
+
# if both timers are `nil`, then we will just return a never resolving promise (at least not from here. but it can be resolved externally)
|
121
|
+
return new_promise if resolve_in.nil? && reject_in.nil?
|
122
|
+
Async do
|
123
|
+
# determine the shorter timeout and take the action of either resolving or rejecting after the timeout
|
124
|
+
if (reject_in.nil?) || ((not resolve_in.nil?) && (resolve_in <= reject_in))
|
125
|
+
sleep(resolve_in)
|
126
|
+
new_promise.resolve(resolve)
|
127
|
+
else
|
128
|
+
sleep(reject_in)
|
129
|
+
new_promise.reject(reject)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
new_promise
|
133
|
+
end
|
134
|
+
|
135
|
+
# Resolve the value of this Promise node.
|
136
|
+
# @param value [T, Promise<T>] Generic value of type `T`.
|
137
|
+
# return [void] nothing is returned.
|
138
|
+
def resolve(value = nil)
|
139
|
+
return nil if @status != "pending" # if the promise is already fulfilled or rejected, return immediately
|
140
|
+
|
141
|
+
Async do |task|
|
142
|
+
if value.is_a?(Promise)
|
143
|
+
# if the provided value itself is a promise, then this (self) promise will need to become dependant on it.
|
144
|
+
value.then(
|
145
|
+
->(resolved_value) { self.resolve(resolved_value); resolved_value },
|
146
|
+
->(rejection_reason) { self.reject(rejection_reason); rejection_reason },
|
147
|
+
)
|
148
|
+
else
|
149
|
+
# otherwise, since we have an actual resolved value at hand, we may now pass it onto the dependent children.
|
150
|
+
begin
|
151
|
+
value = @on_resolve.nil? \
|
152
|
+
? value
|
153
|
+
: @on_resolve.call(value) # it's ok if `@on_resolve` returns another promise object, because the children will then lach on to its promise when their `resolve` method is called.
|
154
|
+
rescue => error_reason
|
155
|
+
# some uncaught error occurred while running the `@on_resolve` function. we should now reject this (self) promise, and pass the responsibility of handling to the children (if any).
|
156
|
+
self.handle_imminent_reject(error_reason)
|
157
|
+
else
|
158
|
+
# no errors occurred after running the `@on_resolve` function. we may now resolve the children.
|
159
|
+
self.handle_imminent_resolve(value)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
nil
|
165
|
+
end
|
166
|
+
|
167
|
+
# Reject the value of this Promise node with an optional error reason.
|
168
|
+
# WARNING: Do not pass a `nil` as the reason, because it will break the error handling logic, since it will seem to it like there was no error.
|
169
|
+
# @param reason [String, StandardError] The error to pass on to the next series of dependant promises.
|
170
|
+
# return [void] nothing is returned.
|
171
|
+
def reject(reason = "Promise error")
|
172
|
+
return nil if @status != "pending" # if the promise is already fulfilled or rejected, return immediately
|
173
|
+
|
174
|
+
Async do |task|
|
175
|
+
# since there has been an error, we must call the `@on_reject` method to see if it handles it appropriately (by not raising another error and giving a return value).
|
176
|
+
# if there is no `on_reject` available, we will just have to continue with the error propagation to the children.
|
177
|
+
if @on_reject.nil?
|
178
|
+
# no rejection handler exists, thus the children must bear the responsibility of handling the error
|
179
|
+
self.handle_imminent_reject(reason)
|
180
|
+
else
|
181
|
+
# an `@on_reject` handler exists, so lets see if it can reolve the current error with a value.
|
182
|
+
new_handled_value = nil
|
183
|
+
begin
|
184
|
+
new_handled_value = @on_reject.call(reason)
|
185
|
+
rescue => new_error_reason
|
186
|
+
# a new error occurred in the `@on_reject` handler, resulting in no resolvable value.
|
187
|
+
# we must now pass on the responsibility of handling it to the children.
|
188
|
+
self.handle_imminent_reject(new_error_reason)
|
189
|
+
else
|
190
|
+
# the `@on_reject` function handled the error appropriately and returned a value, so we may now resolve the children with that new value.
|
191
|
+
self.handle_imminent_resolve(new_handled_value)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
nil
|
197
|
+
end
|
198
|
+
|
199
|
+
# @param on_resolve [(value) => next_value_or_promise, nil] the function to call when the promise is resolved with a value.
|
200
|
+
# @param on_reject [(reason) => next_value_or_promise, nil] the function to call when the promise is rejected (either manually or due to a raised error).
|
201
|
+
# @return [Promise] returns a new promise, so that multiple [then] and [catch] calls can be chained.
|
202
|
+
def then(on_resolve = nil, on_reject = nil)
|
203
|
+
chainable_promise = self.class.new(on_resolve, on_reject)
|
204
|
+
|
205
|
+
Async do |task|
|
206
|
+
case @status
|
207
|
+
when "pending"
|
208
|
+
# add the new promise as a child to the currently pending promise. once this promise resolves, the new child will be notified.
|
209
|
+
@children << chainable_promise
|
210
|
+
when "fulfilled"
|
211
|
+
# this promise has already been fulfilled, so the child must be notified of the resolved value immediately.
|
212
|
+
chainable_promise.resolve(@value)
|
213
|
+
when "rejected"
|
214
|
+
# this promise has already been rejected, so the child must be notified of the rejection reason immediately.
|
215
|
+
chainable_promise.reject(@reason)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
chainable_promise
|
220
|
+
end
|
221
|
+
|
222
|
+
# A catch method is supposed to rescue any rejections that are made by the parent promise.
|
223
|
+
# it is syntactically equivalent to a `self.then(nil, on_reject)` call.
|
224
|
+
# @param on_reject [(reason) => next_value_or_promise, nil] the function to call when the promise is rejected (either manually or due to a raised error).
|
225
|
+
# @return [Promise] returns a new promise, so that multiple [then] and [catch] calls can be chained.
|
226
|
+
def catch(on_reject = nil)
|
227
|
+
self.then(nil, on_reject)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Wait for the Promise to be resolved, or rejected.
|
231
|
+
# If the Promise was rejected, and you wait for it, then it will raise an error, which you will have to rescue externally.
|
232
|
+
# @returns [Any] The resolved value of type `T`.
|
233
|
+
# @raise [String, StandardError] The error/reason for the rejection of this Promise.
|
234
|
+
def wait
|
235
|
+
value = self.async_wait()
|
236
|
+
# if an error had existed for this promise, then we shall raise it now.
|
237
|
+
raise @reason unless @reason.nil?
|
238
|
+
# if `value` is a promise object, then we will have to await for it to resolve
|
239
|
+
return value.wait() if value.is_a?(Promise)
|
240
|
+
value
|
241
|
+
end
|
242
|
+
|
243
|
+
# Get the status of the this Promise.
|
244
|
+
# This should be used for debugging purposes only. your application logic MUST NOT depend on it, at all.
|
245
|
+
# @return ["pending", "fulfilled", "rejected"] Represents the current state of this Promise node.
|
246
|
+
def status
|
247
|
+
@status
|
248
|
+
end
|
249
|
+
|
250
|
+
# Provide a final resolved value for this promise node.
|
251
|
+
# @param value [Any] the final resolved value to commit to.
|
252
|
+
private def handle_imminent_resolve(value)
|
253
|
+
@status = "fulfilled"
|
254
|
+
@value = value
|
255
|
+
Async do |task|
|
256
|
+
@children.each { |child_promise| child_promise.resolve(value) }
|
257
|
+
end
|
258
|
+
self.async_resolve(value) # Ensure the underlying `Async::Variable` is resolved, so that the async library can stop waiting for it.
|
259
|
+
nil
|
260
|
+
end
|
261
|
+
|
262
|
+
# Provide a final rejection reason/error for this promise node.
|
263
|
+
# @param value [String, StandardError] the final error/reason for rejection to commit to.
|
264
|
+
private def handle_imminent_reject(reason)
|
265
|
+
@status = "rejected"
|
266
|
+
@reason = reason
|
267
|
+
# we are not going to raise the error here, irrespective of whether or not child promises are available.
|
268
|
+
# the error is intended to be ONLY risen when a rejected promise is awaited for via our overloaded `wait` method.
|
269
|
+
unless @children.empty?
|
270
|
+
# if there are child promises, we will pass the reason for rejection to each of them (and each must handle it, otherwise error exceptions will be raised when they are awaited for).
|
271
|
+
Async do |task|
|
272
|
+
@children.each { |child_promise| child_promise.reject(reason) }
|
273
|
+
end
|
274
|
+
end
|
275
|
+
self.async_resolve(nil) # Ensure the underlying `Async::Variable` is resolved with a `nil`, so that the async library can stop waiting for it.
|
276
|
+
nil
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
data/readme.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Async::Promise
|
2
|
+
|
3
|
+
TODO: Delete this and the text below, and describe your gem
|
4
|
+
|
5
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/async/promise`. To experiment with that code, run `bin/console` for an interactive prompt.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
|
10
|
+
|
11
|
+
Install the gem and add to the application's Gemfile by executing:
|
12
|
+
|
13
|
+
```bash
|
14
|
+
bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
|
15
|
+
```
|
16
|
+
|
17
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
18
|
+
|
19
|
+
```bash
|
20
|
+
gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
|
21
|
+
```
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
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](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/omar-azmi/async-promise-ruby.
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: async-promise
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Omar Azmi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-10-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: async
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.17'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.17'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '13.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '13.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.65'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.65'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: solargraph
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.50.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.50.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sus
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.31.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.31.0
|
83
|
+
description: An Asynchronous Promise library for Ruby, built over the *async* gem,
|
84
|
+
providing Javascript ES6 style Promises.Also includes utilities like ES6-style *fetch*
|
85
|
+
that return a Promise.
|
86
|
+
email:
|
87
|
+
- 64020006+omar-azmi@users.noreply.github.com
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- changelog.md
|
93
|
+
- lib/async/promise.rb
|
94
|
+
- readme.md
|
95
|
+
homepage: https://github.com/omar-azmi/async-promise-ruby
|
96
|
+
licenses:
|
97
|
+
- CC-BY-NC-SA-4.0
|
98
|
+
metadata:
|
99
|
+
allowed_push_host: https://rubygems.org
|
100
|
+
homepage_uri: https://github.com/omar-azmi/async-promise-ruby
|
101
|
+
source_code_uri: https://github.com/omar-azmi/async-promise-ruby.git
|
102
|
+
changelog_uri: https://github.com/omar-azmi/async-promise-ruby/blob/main/changelog.md
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: 3.1.1
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubygems_version: 3.5.16
|
119
|
+
signing_key:
|
120
|
+
specification_version: 4
|
121
|
+
summary: Asynchronous Javascript style Promises for Ruby.
|
122
|
+
test_files: []
|