libtmux-async 0.1.0.alpha.2 → 0.1.0.alpha.3

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: 1ea540b90e8bd302c36602c0d1b3db74136a60773deb92bb5358b3c7bc48e3f0
4
- data.tar.gz: cf67c1667785062c2c29a6c27732e3bf6012d4edd17ff62a4679e55429aeda91
3
+ metadata.gz: e64f6117feba9404d8cd8fabcdacbdf1ef098f3b1bdc6226c4f03c66a2581fbc
4
+ data.tar.gz: 9ff7ca35a31683ccdf6ba76562ec4ff156aaf2eb75e9e13e1e1a197abefbdbc4
5
5
  SHA512:
6
- metadata.gz: e99804e99791d37c02fb54b374f9a29fcad90b5296da46bc5f333e5d20fedd3796a9796e2103a52c690b76981b806826ea18c0c2da7916b4fa72100e8496c541
7
- data.tar.gz: 93ddf5982950f17a2afd0199186fde93ecf590006dc4fbaf84e76458405cb0092d28b4378914e481ac710b55012d056867a03b9b436e99e74f2e4f88444f1172
6
+ metadata.gz: cb9f3e5f40e3ad10061c168a68728d33a19a6917071bf4853f63a83f122427c7b9caa43312a120aa2d30fa4abaeb83bfd36457717099a06a484479b135f015f7
7
+ data.tar.gz: df18e0b035473957c327faf618798fd1dbd2e12e4e19aa5fc423ce5426442d5842d2637e6246ea345f9a9b833b387ae2805c35e2cba04b8cc2e373f280f01567
data/README.md CHANGED
@@ -11,68 +11,135 @@
11
11
 
12
12
  # libtmux-async
13
13
 
14
- Run libtmux operations inside an application-owned Async task. This
15
- gem provides a subprocess facade, ordered mapping, control replies and event
16
- subscriptions. Imports start no scheduler, tmux server or background task.
14
+ Run libtmux operations inside an application-owned Async task: a
15
+ [subprocess facade][async-server], [ordered mapping][async-scope-map],
16
+ [control replies][guardedreply] and
17
+ [event subscriptions][async-controlsubscription].
18
+
19
+ [API reference](https://libtmux.org/en/ruby/latest/reference/libtmux-async/) ·
20
+ [Guide](https://libtmux.org/en/ruby/latest/guides/async/) ·
21
+ [RubyGems](https://rubygems.org/gems/libtmux-async)
17
22
 
18
23
  </div>
19
24
 
20
- Requires tmux 3.3a or newer. The Async facade dispatches through a
21
- version-checked core server and carries the same daemon release check.
25
+ Part of [libtmux for Ruby](https://github.com/libtmux/libtmux-ruby#readme).
26
+ Built on [libtmux](https://github.com/libtmux/libtmux-ruby/tree/master/gems/libtmux).
27
+
28
+ Imports start no scheduler, tmux server or background task. A scope borrows a
29
+ core [`Server`][server] and leaves its daemon running when the scope exits.
22
30
 
23
- Install the alpha with `gem install libtmux-async --pre`.
31
+ **Contents** — [Quick start](#quick-start) ·
32
+ [Cancel](#cancel-a-request-without-stalling-the-others) ·
33
+ [Map](#keep-results-ordered-and-bounded) ·
34
+ [Control](#read-control-events-in-a-scope) ·
35
+ [Leaves out](#what-it-leaves-out) · [Support](#support-and-status) ·
36
+ [Documentation](#documentation)
24
37
 
25
- The [complete program](../../examples/async_cancel.rb) owns an isolated server
26
- and its cleanup. This excerpt uses that server and creates the Async root:
38
+ ## Quick start
27
39
 
28
- <!-- example: async_cancel/main -->
40
+ Install the alpha. It needs Ruby 3.3 or newer and tmux 3.3a or newer on
41
+ `PATH`:
42
+
43
+ ```console
44
+ $ gem install libtmux-async --pre
45
+ ```
46
+
47
+ Open a scope over a core server with [`LibTmux::Async.open`][async-open], then
48
+ capture every pane concurrently with [`Scope#map`][async-scope-map]. The outer
49
+ [`Server.start`][server-start] block only supplies a server for the scope to
50
+ borrow:
51
+
52
+ <!-- example: api_async_scope/main -->
29
53
  ```ruby
30
- Async do |parent|
31
- LibTmux::Async.open(parent: parent, server: server) do |scope|
32
- waiting = parent.async do
33
- scope.server.run(["wait-for", "-S", "ready", ";", "wait-for", "held"], timeout: 0.5)
34
- rescue LibTmux::Cancelled => error
35
- error
54
+ require "libtmux"
55
+ require "libtmux/async"
56
+
57
+ LibTmux::Server.start do |server|
58
+ server.new_session(name: "work", command: ["/bin/cat"])
59
+ server.new_session(name: "logs", command: ["/bin/cat"])
60
+ Async do |parent|
61
+ LibTmux::Async.open(parent: parent, server: server) do |scope|
62
+ refs = scope.server.list_panes.map(&:ref)
63
+ screens = scope.map(refs, concurrency: 2) { |ref| scope.server.pane(ref).capture }
64
+ puts "captured panes: #{screens.length}"
65
+ puts "all succeeded: #{screens.all?(&:success?)}"
36
66
  end
37
- scope.server.wait_for("ready", timeout: 0.5)
38
- Example.check(scope.diagnostics.fetch(:active_process_slots) == 1, "waiting client lost its slot")
39
- captures = scope.map(scope.server.list_panes.map(&:ref), concurrency: 2) do |ref|
40
- scope.server.pane(ref).capture
67
+ end.wait
68
+ end
69
+ ```
70
+ <!-- /example -->
71
+
72
+ It prints:
73
+
74
+ ```text
75
+ captured panes: 2
76
+ all succeeded: true
77
+ ```
78
+
79
+ - Leave out `parent:` to use the current Async task.
80
+ - A scope rejects use from another thread, process or scheduler, so create one
81
+ scope for each scheduler thread.
82
+ - Scope exit retires its clients and joins its owned tasks.
83
+
84
+ ## Cancel a request without stalling the others
85
+
86
+ ### [`Async::Server#run`][async-server-run]: cancel a request that is waiting
87
+
88
+ `scope.server.run` waits for a tmux command in a task. Cancel that task and
89
+ the scope retires its client, while sibling requests keep running.
90
+
91
+ [`wait_for`][async-server-wait_for] returns once the request has signalled
92
+ that it is running, so the cancel arrives while it waits:
93
+
94
+ <!-- example: api_async_run/main -->
95
+ ```ruby
96
+ require "libtmux"
97
+ require "libtmux/async"
98
+
99
+ LibTmux::Server.start do |server|
100
+ server.new_session(name: "work", command: ["/bin/cat"])
101
+ Async do |parent|
102
+ LibTmux::Async.open(parent: parent, server: server) do |scope|
103
+ waiting = parent.async do
104
+ scope.server.run(["wait-for", "-S", "ready", ";", "wait-for", "held"], timeout: 5)
105
+ rescue LibTmux::Cancelled => error
106
+ error
107
+ end
108
+ scope.server.wait_for("ready", timeout: 5)
109
+ waiting.cancel
110
+ failure = waiting.wait
111
+ puts "request: #{failure.class}"
112
+ puts "delivery: #{failure.delivery}"
41
113
  end
42
- Example.check(captures.all?(&:success?), "sibling captures stalled")
43
- waiting.cancel
44
- failure = waiting.wait
45
- Example.check(failure.is_a?(LibTmux::Cancelled), "cancellation lost")
46
- Example.check(failure.delivery == :possibly_sent, "cancelled dispatch claimed no effects")
47
- Example.raises(Errno::ECHILD) { Process.waitpid(failure.pid, Process::WNOHANG) }
48
- Example.check(scope.server.diagnostics.fetch(:admitted_requests).zero?, "cancelled client remains admitted")
49
- end
50
- end.wait
114
+ end.wait
115
+ end
51
116
  ```
52
117
  <!-- /example -->
53
118
 
54
- Omitting `parent:` uses the existing current Async task. The source server must
55
- outlive the scope. References keep their source binding identity. Scope exit
56
- retires its clients and joins its owned tasks; it leaves the borrowed daemon
57
- alive. A scope rejects use from another thread, process or scheduler. Create a
58
- separate scope for each scheduler thread. Interactive terminal attachment stays
59
- on the blocking core facade and raises `UnsupportedFeatureError` on this facade.
60
-
61
- `scope.server.run` returns the same binary `CommandResult` as core. Its stdin,
62
- stdout and stderr are owned by scheduler tasks. A bounded native helper observes
63
- and reaps each child only after its final signalling handoff. Cancelling the
64
- calling task retires its client and raises `Cancelled` with `:not_sent` or
65
- `:possibly_sent` delivery. An already observed exit completes its bounded drain.
66
- Repeated cancellation does not restart cleanup deadlines or replace an earlier
67
- operation failure. Deadlines cannot undo tmux effects.
68
-
69
- `scope.map` returns a frozen Array in input order; independent requests may
70
- complete out of order. It caps retained items at 1024 and accounts payload bytes
71
- in strings, primitive values, `CommandResult`, Arrays and Hashes. Cycles and
72
- excessive nesting are refused. Application-defined results require an explicit
73
- `result_bytes:` callable returning a nonnegative Integer. Keep measured values
74
- unchanged until the map returns. These payload limits complement item counts;
75
- they are not exact Ruby heap measurements.
119
+ It prints:
120
+
121
+ ```text
122
+ request: LibTmux::Cancelled
123
+ delivery: possibly_sent
124
+ ```
125
+
126
+ - `run` returns the same binary [`CommandResult`][commandresult] as the core.
127
+ - [`Cancelled`][cancelled] carries `delivery` as `:not_sent` or
128
+ `:possibly_sent`. A deadline cannot undo tmux effects.
129
+ - Interactive terminal attachment stays on the blocking core and raises
130
+ [`UnsupportedFeatureError`][unsupportedfeatureerror] here.
131
+
132
+ The [complete program](../../examples/async_cancel.rb) also keeps capturing
133
+ while the request waits, and checks that the cancelled client is reaped. The
134
+ contract is in [Async scope][behavior-async-scope].
135
+
136
+ ## Keep results ordered and bounded
137
+
138
+ ### [`Scope#map`][async-scope-map]: input order, capped payloads
139
+
140
+ `map` runs a block for each item, up to `concurrency:` at a time, and returns a
141
+ frozen Array in input order. The quick start is a `map`. These limits apply to
142
+ every scope:
76
143
 
77
144
  | Scope limit | Default |
78
145
  | --- | --- |
@@ -84,23 +151,134 @@ they are not exact Ruby heap measurements.
84
151
  | Control connections | 4 |
85
152
  | Ordinary command deadline | 5 seconds |
86
153
 
87
- Control connections use their own request, reply and subscriber limits. Obtain
88
- one with `scope.server.open_control(session: ref)`. `exchange` returns guarded
89
- `GuardedReply` blocks with `:boundary_window` attribution. It makes no claim of
90
- final command completion. Outside-block events arrive through `events.next` or
91
- an explicit `subscribe`; consumer callbacks run outside the parser. Reliable
92
- subscriptions raise on overflow. Tail subscriptions report dropped ranges.
93
- Cancelling a dispatched, undrained exchange closes that connection.
94
-
95
- `pause_output(pane_id:)` and `resume_output(pane_id:)` retain guarded evidence
96
- and report possible output loss through gap events. A requested-action gap
97
- does not prove that the action took effect. Close a connection before passing
98
- it as `reconnect:` to `scope.server.open_control`; the replacement stays owned
99
- by that scope and reports a new generation plus a gap with unknown loss.
100
- Subscriptions expose their `generation`; prior subscriptions stay closed.
101
- Reconnect and resume never replay requests or missed output.
102
-
103
- The development bundle pins Async 2.46 and io-event 1.22. The
104
- [compatibility workflow](https://github.com/libtmux/libtmux-ruby/actions/workflows/compatibility.yml)
105
- exercises the selected Ruby/tmux versions on Linux and macOS and retains
106
- per-revision results. Package builds and tests do not publish this gem.
154
+ - Independent requests may complete out of order, and the result is still in
155
+ input order.
156
+ - `map` caps retained items and counts payload bytes of strings, primitive
157
+ values, [`CommandResult`][commandresult], Arrays and Hashes. Cycles and deep
158
+ nesting are refused.
159
+ - An application-defined result needs a `result_bytes:` callable that returns
160
+ a nonnegative Integer.
161
+ - Keep measured values unchanged until the map returns. The counts cover
162
+ payload bytes and do not measure the Ruby heap.
163
+
164
+ The contract is in [Async map][behavior-async-map].
165
+
166
+ ## Read control events in a scope
167
+
168
+ ### [`Async::Server#open_control`][async-server-open_control]: replies and events
169
+
170
+ A control connection has its own request, reply and subscriber limits.
171
+ [`exchange`][async-controlconnection-exchange] runs one command, and
172
+ [`events`][async-controlconnection-events] yields what tmux reports outside a
173
+ reply:
174
+
175
+ <!-- example: api_async_control/main -->
176
+ ```ruby
177
+ require "libtmux"
178
+ require "libtmux/async"
179
+
180
+ LibTmux::Server.start do |server|
181
+ session = server.new_session(name: "work", command: ["/bin/cat"])
182
+ window = session.list_windows.fetch(0)
183
+ Async do |parent|
184
+ LibTmux::Async.open(parent: parent, server: server) do |scope|
185
+ scope.server.open_control(session: session.ref) do |control|
186
+ reply = control.exchange("display-message -p ready", timeout: 5)
187
+ puts "reply: #{reply.blocks.last.body.strip}"
188
+ events = control.events
189
+ window.rename("renamed")
190
+ event = events.next(timeout: 5) until event&.raw&.start_with?("%window-renamed")
191
+ puts "event: #{event.raw.strip}"
192
+ end
193
+ end
194
+ end.wait
195
+ end
196
+ ```
197
+ <!-- /example -->
198
+
199
+ It prints:
200
+
201
+ ```text
202
+ reply: ready
203
+ event: %window-renamed @0 renamed
204
+ ```
205
+
206
+ - `exchange` answers a [`GuardedReply`][guardedreply] with `:boundary_window`
207
+ attribution. It makes no claim that the command finished.
208
+ - Events arrive through `events.next` or an explicit
209
+ [`subscribe`][async-controlconnection-subscribe]. Consumer callbacks run
210
+ outside the parser.
211
+ - A reliable subscription raises on overflow, and a tail subscription reports
212
+ the dropped range.
213
+ - Cancelling a dispatched exchange that is not drained closes the connection.
214
+ - [`pause_output`][async-controlconnection-pause_output] and
215
+ [`resume_output`][async-controlconnection-resume_output] report possible
216
+ loss through gap events. A gap does not show that the action took effect.
217
+ - To reconnect, close the connection and pass it as `reconnect:`. The
218
+ replacement stays owned by the scope, has a new generation, and starts with
219
+ a gap of unknown loss. Nothing is replayed.
220
+
221
+ The contract is in [Control connections][behavior-control].
222
+
223
+ ## What it leaves out
224
+
225
+ - **Terminal attachment.** `attach` stays on the blocking core and raises
226
+ [`UnsupportedFeatureError`][unsupportedfeatureerror] on this facade.
227
+ - **Replay.** Reconnect and resume never replay requests or missed output. See
228
+ [Control connections][behavior-control].
229
+ - **A scheduler.** Imports start no scheduler or background task, and your
230
+ application owns the Async root task. See [Execution modes][doc-modes].
231
+ - **Cross-thread scopes.** A scope belongs to the thread, process and
232
+ scheduler that opened it. See [Async scope][behavior-async-scope].
233
+
234
+ ## Support and status
235
+
236
+ **Alpha.** APIs may change between releases.
237
+
238
+ - **Ruby 3.3 or newer** and **tmux 3.3a or newer.** The facade dispatches
239
+ through a version-checked core server, so it carries the same daemon release
240
+ check.
241
+ - **Control connections need tmux 3.7 or newer.**
242
+ [`open_control`][async-server-open_control] refuses an older daemon before a
243
+ control client attaches.
244
+ - **Async 2.46.** The gem depends on `async` ~> 2.46.0 and the same version of
245
+ `libtmux`.
246
+ - **Linux, including WSL, and macOS.** The [compatibility workflow][compat]
247
+ runs Ruby 3.3, 3.4 and 4.0 with tmux 3.3a through 3.8 on Ubuntu 24.04 and retains
248
+ per-revision results. macOS is supported on a best-effort basis, and CI
249
+ coverage for it is highly limited.
250
+
251
+ ## Documentation
252
+
253
+ | | |
254
+ | --- | --- |
255
+ | [Reference](https://libtmux.org/en/ruby/latest/reference/libtmux-async/) | The Async classes, one page each |
256
+ | [Async guide](https://libtmux.org/en/ruby/latest/guides/async/) | Running concurrent commands within an owned scope |
257
+ | [Execution modes][doc-modes] | Blocking calls, Async tasks and control subscriptions |
258
+ | [Recipes][doc-recipes] | Complete programs with checked excerpts |
259
+ | [Public behavior][behavior-async-scope] | Scheduling, ownership and limits of a scope |
260
+
261
+ [async-controlconnection-events]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-controlconnection-events/
262
+ [async-controlconnection-exchange]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-controlconnection-exchange/
263
+ [async-controlconnection-pause_output]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-controlconnection-pause_output/
264
+ [async-controlconnection-resume_output]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-controlconnection-resume_output/
265
+ [async-controlconnection-subscribe]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-controlconnection-subscribe/
266
+ [async-controlsubscription]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-controlsubscription/
267
+ [async-open]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-open/
268
+ [async-scope-map]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-scope-map/
269
+ [async-server]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-server/
270
+ [async-server-open_control]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-server-open_control/
271
+ [async-server-run]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-server-run/
272
+ [async-server-wait_for]: https://libtmux.org/en/ruby/latest/reference/libtmux-async-server-wait_for/
273
+ [behavior-async-map]: ../../docs/reference/behavior.md#async-map
274
+ [behavior-async-scope]: ../../docs/reference/behavior.md#async-scope
275
+ [behavior-control]: ../../docs/reference/behavior.md#control-connections
276
+ [cancelled]: https://libtmux.org/en/ruby/latest/reference/libtmux-cancelled/
277
+ [commandresult]: https://libtmux.org/en/ruby/latest/reference/libtmux-commandresult/
278
+ [compat]: https://github.com/libtmux/libtmux-ruby/actions/workflows/compatibility.yml
279
+ [doc-modes]: ../../docs/modes.md
280
+ [doc-recipes]: ../../docs/recipes.md
281
+ [guardedreply]: https://libtmux.org/en/ruby/latest/reference/libtmux-guardedreply/
282
+ [server]: https://libtmux.org/en/ruby/latest/reference/libtmux-server/
283
+ [server-start]: https://libtmux.org/en/ruby/latest/reference/libtmux-server-start/
284
+ [unsupportedfeatureerror]: https://libtmux.org/en/ruby/latest/reference/libtmux-unsupportedfeatureerror/
@@ -23,30 +23,34 @@ module LibTmux
23
23
  raise ArgumentError, "timeout must be finite and nonnegative"
24
24
  end
25
25
  deadline = timeout && clock + timeout
26
- loop do
27
- @mutex.synchronize do
28
- if @gap
29
- gap, @gap = @gap, nil
30
- return gap
31
- end
32
- unless @queue.empty?
33
- event = @queue.shift
34
- @bytes -= event.bytesize
35
- return event
26
+ # Kernel#loop would swallow the StopIteration that ends the stream and
27
+ # return nil from next.
28
+ while true
29
+ begin
30
+ @mutex.synchronize do
31
+ if @gap
32
+ gap, @gap = @gap, nil
33
+ return gap
34
+ end
35
+ unless @queue.empty?
36
+ event = @queue.shift
37
+ @bytes -= event.bytesize
38
+ return event
39
+ end
40
+ raise @failure if @failure
41
+ raise StopIteration if @closed
36
42
  end
37
- raise @failure if @failure
38
- raise StopIteration if @closed
39
- end
40
- remaining = deadline && deadline - clock
41
- raise DeadlineExceeded.new("control event deadline elapsed", phase: :subscription) if remaining && remaining <= 0
43
+ remaining = deadline && deadline - clock
44
+ raise DeadlineExceeded.new("control event deadline elapsed", phase: :subscription) if remaining && remaining <= 0
42
45
 
43
- if remaining
44
- ::Async::Task.current.with_timeout(remaining) { @changed.wait }
45
- else
46
- @changed.wait
46
+ if remaining
47
+ ::Async::Task.current.with_timeout(remaining) { @changed.wait }
48
+ else
49
+ @changed.wait
50
+ end
51
+ rescue ::Async::TimeoutError
52
+ raise DeadlineExceeded.new("control event deadline elapsed", phase: :subscription)
47
53
  end
48
- rescue ::Async::TimeoutError
49
- raise DeadlineExceeded.new("control event deadline elapsed", phase: :subscription)
50
54
  end
51
55
  end
52
56
 
@@ -60,6 +64,7 @@ module LibTmux
60
64
  class ControlConnection < LibTmux::ControlConnection
61
65
  def initialize(scope:, binding:, session_id:, reconnect: nil, **limits)
62
66
  @scope = scope
67
+ @release = binding.release
63
68
  @writer_changed = ::Async::Notification.new
64
69
  @startup_changed = ::Async::Notification.new
65
70
  @exchanges, @exchange_changed = {}, ::Async::Notification.new
@@ -81,6 +86,7 @@ module LibTmux
81
86
  end
82
87
  raise CapacityError.new("control command exceeds its byte limit", phase: :admission) if line.bytesize > @max_command
83
88
 
89
+ Internal::NativeGuard.check_line(line, @release)
84
90
  deadline = clock + timeout
85
91
  request = admit(line, cancel, flow: flow)
86
92
  @exchanges[request.id] = true
@@ -186,6 +186,7 @@ module LibTmux
186
186
 
187
187
  def open_control(binding:, session_id:, **options)
188
188
  ensure_open
189
+ Internal::TmuxVersion.require_control(binding.release)
189
190
  @controls.reject!(&:closed?)
190
191
  raise CapacityError.new("Async control capacity is exhausted", phase: :admission) if @controls.length >= @max_controls
191
192
 
@@ -12,14 +12,7 @@ module LibTmux
12
12
  end
13
13
 
14
14
  def run(argv, input: "".b, timeout: 5.0, cancel: nil)
15
- ensure_owner
16
- ensure_open
17
- validate_argv(argv)
18
- raise ArgumentError, "raw commands cannot override endpoint flags" if argv.first.start_with?("-")
19
-
20
- fence, marker = Internal::TmuxVersion.fence(@release)
21
- result = @scope.__send__(:execute, @pin.command_prefix + fence + argv, input: input, timeout: timeout, cancel: cancel)
22
- Internal::TmuxVersion.check_fence(result, marker, @release)
15
+ dispatch(argv, input: input, timeout: timeout, cancel: cancel)
23
16
  end
24
17
 
25
18
  def close
@@ -66,6 +59,18 @@ module LibTmux
66
59
 
67
60
  private
68
61
 
62
+ def dispatch(argv, input: "".b, timeout: 5.0, cancel: nil, repaired_break: false)
63
+ ensure_owner
64
+ ensure_open
65
+ validate_argv(argv)
66
+ raise ArgumentError, "raw commands cannot override endpoint flags" if argv.first.start_with?("-")
67
+
68
+ Internal::NativeGuard.check(argv, @release, repaired_break: repaired_break)
69
+ fence, marker = Internal::TmuxVersion.fence(@release)
70
+ result = @scope.__send__(:execute, @pin.command_prefix + fence + argv, input: input, timeout: timeout, cancel: cancel)
71
+ Internal::TmuxVersion.check_fence(result, marker, @release)
72
+ end
73
+
69
74
  def ensure_owner
70
75
  @scope.__send__(:ensure_owner)
71
76
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module LibTmux
4
4
  module Async
5
- VERSION = "0.1.0.alpha.2"
5
+ VERSION = "0.1.0.alpha.3"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libtmux-async
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.alpha.2
4
+ version: 0.1.0.alpha.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - libtmux contributors
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.1.0.alpha.2
18
+ version: 0.1.0.alpha.3
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.1.0.alpha.2
25
+ version: 0.1.0.alpha.3
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: async
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -59,7 +59,7 @@ licenses:
59
59
  - MIT
60
60
  metadata:
61
61
  source_code_uri: https://github.com/libtmux/libtmux-ruby
62
- documentation_uri: https://libtmux.org/en/ruby/v0.1.0.alpha.2/reference/
62
+ documentation_uri: https://libtmux.org/en/ruby/v0.1.0.alpha.3/reference/
63
63
  rdoc_options: []
64
64
  require_paths:
65
65
  - lib