polyphony 0.99.5 → 1.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.
@@ -1,8 +1,289 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../core/global_api'
3
+ require_relative '../core/throttler'
4
4
 
5
5
  # Object extensions (methods available to all objects / call sites)
6
6
  class ::Object
7
- include Polyphony::GlobalAPI
7
+ # Spins up a fiber that will run the given block after sleeping for the
8
+ # given delay.
9
+ #
10
+ # @param interval [Number] delay in seconds before running the given block
11
+ # @return [Fiber] spun fiber
12
+ def after(interval, &block)
13
+ spin do
14
+ sleep interval
15
+ block.()
16
+ end
17
+ end
18
+
19
+ # Runs the given block after setting up a cancellation timer for
20
+ # cancellation. If the cancellation timer elapses, the execution will be
21
+ # interrupted with an exception defaulting to `Polyphony::Cancel`.
22
+ #
23
+ # This method should be used when a timeout should cause an exception to be
24
+ # propagated down the call stack or up the fiber tree.
25
+ #
26
+ # Example of normal use:
27
+ #
28
+ # def read_from_io_with_timeout(io)
29
+ # cancel_after(10) { io.read }
30
+ # rescue Polyphony::Cancel
31
+ # nil
32
+ # end
33
+ #
34
+ # The timeout period can be reset by passing a block that takes a single
35
+ # argument. The block will be provided with the canceller fiber. To reset
36
+ # the timeout, use `Fiber#reset`, as shown in the following example:
37
+ #
38
+ # cancel_after(10) do |timeout|
39
+ # loop do
40
+ # msg = socket.gets
41
+ # timeout.reset
42
+ # handle_msg(msg)
43
+ # end
44
+ # end
45
+ #
46
+ # @overload cancel_after(interval)
47
+ # @param interval [Number] timout in seconds
48
+ # @yield [Fiber] timeout fiber
49
+ # @return [any] block's return value
50
+ # @overload cancel_after(interval, with_exception: exception)
51
+ # @param interval [Number] timout in seconds
52
+ # @param with_exception [Class, Exception] exception or exception class
53
+ # @yield [Fiber] timeout fiber
54
+ # @return [any] block's return value
55
+ # @overload cancel_after(interval, with_exception: [klass, message])
56
+ # @param interval [Number] timout in seconds
57
+ # @param with_exception [Array] array containing class and message to use as exception
58
+ # @yield [Fiber] timeout fiber
59
+ # @return [any] block's return value
60
+ def cancel_after(interval, with_exception: Polyphony::Cancel, &block)
61
+ if block.arity > 0
62
+ cancel_after_with_optional_reset(interval, with_exception, &block)
63
+ else
64
+ Polyphony.backend_timeout(interval, with_exception, &block)
65
+ end
66
+ end
67
+
68
+ # Spins up a new fiber.
69
+ #
70
+ # @param tag [any] optional tag for the new fiber
71
+ # @return [Fiber] new fiber
72
+ def spin(tag = nil, &block)
73
+ Fiber.current.spin(tag, caller, &block)
74
+ end
75
+
76
+ # Spins up a new fiber, running the given block inside an infinite loop. If
77
+ # `rate:` or `interval:` parameters are given, the loop is throttled
78
+ # accordingly.
79
+ #
80
+ # @param tag [any] optional tag for the new fiber
81
+ # @param rate [Number, nil] loop rate (times per second)
82
+ # @param interval [Number, nil] interval between consecutive iterations in seconds
83
+ # @return [Fiber] new fiber
84
+ def spin_loop(tag = nil, rate: nil, interval: nil, &block)
85
+ if rate || interval
86
+ Fiber.current.spin(tag, caller) do
87
+ throttled_loop(rate: rate, interval: interval, &block)
88
+ end
89
+ else
90
+ spin_loop_without_throttling(tag, caller, block)
91
+ end
92
+ end
93
+
94
+ # Runs the given code, then waits for any child fibers of the current fibers
95
+ # to terminate.
96
+ #
97
+ # @return [any] given block's return value
98
+ def spin_scope(&block)
99
+ raise unless block
100
+
101
+ spin do
102
+ result = yield
103
+ Fiber.current.await_all_children
104
+ result
105
+ end.await
106
+ end
107
+
108
+ # Runs the given block in an infinite loop with a regular interval between
109
+ # consecutive iterations.
110
+ #
111
+ # @param interval [Number] interval between consecutive iterations in seconds
112
+ def every(interval, &block)
113
+ Polyphony.backend_timer_loop(interval, &block)
114
+ end
115
+
116
+ # Runs the given block after setting up a cancellation timer for
117
+ # cancellation. If the cancellation timer elapses, the execution will be
118
+ # interrupted with a `Polyphony::MoveOn` exception, which will be rescued,
119
+ # and with cause the operation to return the given value.
120
+ #
121
+ # This method should be used when a timeout is to be handled locally,
122
+ # without generating an exception that is to propagated down the call stack
123
+ # or up the fiber tree.
124
+ #
125
+ # Example of normal use:
126
+ #
127
+ # move_on_after(10) {
128
+ # sleep 60
129
+ # 42
130
+ # } #=> nil
131
+ #
132
+ # move_on_after(10, with_value: :oops) {
133
+ # sleep 60
134
+ # 42
135
+ # } #=> :oops
136
+ #
137
+ # The timeout period can be reset by passing a block that takes a single
138
+ # argument. The block will be provided with the canceller fiber. To reset
139
+ # the timeout, use `Fiber#reset`, as shown in the following example:
140
+ #
141
+ # move_on_after(10) do |timeout|
142
+ # loop do
143
+ # msg = socket.gets
144
+ # timeout.reset
145
+ # handle_msg(msg)
146
+ # end
147
+ # end
148
+ #
149
+ # @overload move_on_after(interval) { ... }
150
+ # @param interval [Number] timout in seconds
151
+ # @yield [Fiber] timeout fiber
152
+ # @return [any] block's return value
153
+ # @overload move_on_after(interval, with_value: value) { ... }
154
+ # @param interval [Number] timout in seconds
155
+ # @param with_value [any] return value in case of timeout
156
+ # @yield [Fiber] timeout fiber
157
+ # @return [any] block's return value
158
+ def move_on_after(interval, with_value: nil, &block)
159
+ if block.arity > 0
160
+ move_on_after_with_optional_reset(interval, with_value, &block)
161
+ else
162
+ Polyphony.backend_timeout(interval, nil, with_value, &block)
163
+ end
164
+ end
165
+
166
+ # Returns the first message from the current fiber's mailbox. If the mailbox
167
+ # is empty, blocks until a message is available.
168
+ #
169
+ # @return [any] received message
170
+ def receive
171
+ Fiber.current.receive
172
+ end
173
+
174
+ # Returns all messages currently pending on the current fiber's mailbox.
175
+ #
176
+ # @return [Array] array of received messages
177
+ def receive_all_pending
178
+ Fiber.current.receive_all_pending
179
+ end
180
+
181
+ # Supervises the current fiber's children. See `Fiber#supervise` for
182
+ # options.
183
+ #
184
+ # @param args [Array] positional parameters
185
+ # @param opts [Hash] named parameters
186
+ # @return [any]
187
+ def supervise(*args, **opts, &block)
188
+ Fiber.current.supervise(*args, **opts, &block)
189
+ end
190
+
191
+ # Sleeps for the given duration. If the duration is `nil`, sleeps
192
+ # indefinitely.
193
+ #
194
+ # @param duration [Number, nil] duration
195
+ # @return [any]
196
+ def sleep(duration = nil)
197
+ duration ?
198
+ Polyphony.backend_sleep(duration) : Polyphony.backend_wait_event(true)
199
+ end
200
+
201
+ # Starts a throttled loop with the given rate. If `count:` is given, the
202
+ # loop is run for the given number of times. Otherwise, the loop is
203
+ # infinite. The loop rate (times per second) can be given as the rate
204
+ # parameter. The throttling can also be controlled by providing an
205
+ # `interval:` or `rate:` named parameter.
206
+ #
207
+ # @param rate [Number, nil] loop rate (times per second)
208
+ # @option opts [Number] :rate loop rate (times per second)
209
+ # @option opts [Number] :interval loop interval in seconds
210
+ # @option opts [Number] :count number of iterations (nil for infinite)
211
+ # @return [any]
212
+ def throttled_loop(rate = nil, **opts, &block)
213
+ throttler = Polyphony::Throttler.new(rate || opts)
214
+ if opts[:count]
215
+ opts[:count].times { |_i| throttler.(&block) }
216
+ else
217
+ while true
218
+ throttler.(&block)
219
+ end
220
+ end
221
+ rescue LocalJumpError, StopIteration
222
+ # break called or StopIteration raised
223
+ end
224
+
225
+ private
226
+
227
+ # Helper method for performing a `cancel_after` with optional reset.
228
+ #
229
+ # @param interval [Number] timeout interval in seconds
230
+ # @param exception [Exception, Class, Array<class, message>] exception spec
231
+ # @return [any] block's return value
232
+ def cancel_after_with_optional_reset(interval, exception, &block)
233
+ fiber = Fiber.current
234
+ canceller = spin do
235
+ Polyphony.backend_sleep(interval)
236
+ exception = cancel_exception(exception)
237
+ exception.raising_fiber = Fiber.current
238
+ fiber.cancel(exception)
239
+ end
240
+ block.call(canceller)
241
+ ensure
242
+ canceller.stop
243
+ end
244
+
245
+ # Converts the given exception spec to an exception instance.
246
+ #
247
+ # @param exception [Exception, Class, Array<class, message>] exception spec
248
+ # @return [Exception] exception instance
249
+ def cancel_exception(exception)
250
+ case exception
251
+ when Class then exception.new
252
+ when Array then exception[0].new(exception[1])
253
+ else RuntimeError.new(exception)
254
+ end
255
+ end
256
+
257
+ # Helper method for performing `#spin_loop` without throttling. Spins up a
258
+ # new fiber in which to run the loop.
259
+ #
260
+ # @param tag [any] new fiber's tag
261
+ # @param caller [Array<String>] caller info
262
+ # @param block [Proc] code to run
263
+ # @return [any]
264
+ def spin_loop_without_throttling(tag, caller, block)
265
+ Fiber.current.spin(tag, caller) do
266
+ block.call while true
267
+ rescue LocalJumpError, StopIteration
268
+ # break called or StopIteration raised
269
+ end
270
+ end
271
+
272
+ # Helper method for performing `#move_on_after` with optional reset.
273
+ #
274
+ # @param interval [Number] timeout interval in seconds
275
+ # @param value [any] return value in case of timeout
276
+ # @return [any] return value of given block or timeout value
277
+ def move_on_after_with_optional_reset(interval, value, &block)
278
+ fiber = Fiber.current
279
+ canceller = spin do
280
+ sleep interval
281
+ fiber.move_on(value)
282
+ end
283
+ block.call(canceller)
284
+ rescue Polyphony::MoveOn => e
285
+ e.value
286
+ ensure
287
+ canceller.stop
288
+ end
8
289
  end
@@ -17,7 +17,6 @@ class ::OpenSSL::SSL::SSLSocket
17
17
  #
18
18
  # @param socket [TCPSocket] socket to wrap
19
19
  # @param context [OpenSSL::SSL::SSLContext] optional SSL context
20
- # @return [void]
21
20
  def initialize(socket, context = nil)
22
21
  socket = socket.respond_to?(:io) ? socket.io || socket : socket
23
22
  context ? orig_initialize(socket, context) : orig_initialize(socket)
@@ -155,7 +154,7 @@ class ::OpenSSL::SSL::SSLSocket
155
154
  #
156
155
  # @param maxlen [Integer] maximum bytes to receive
157
156
  # @yield [String] read data
158
- # @return [void]
157
+ # @return [OpenSSL::SSL::SSLSocket] self
159
158
  def read_loop(maxlen = 8192)
160
159
  while (data = sysread(maxlen))
161
160
  yield data
@@ -263,8 +262,9 @@ class ::OpenSSL::SSL::SSLServer
263
262
 
264
263
  # Accepts incoming connections in an infinite loop.
265
264
  #
265
+ # @param ignore_errors [boolean] whether to ignore IO and SSL errors
266
266
  # @yield [OpenSSL::SSL::SSLSocket] accepted socket
267
- # @return [void]
267
+ # @return [OpenSSL::SSL::SSLServer] self
268
268
  def accept_loop(ignore_errors = true)
269
269
  loop do
270
270
  yield accept
@@ -178,7 +178,7 @@ class Polyphony::Pipe
178
178
  #
179
179
  # @param maxlen [Integer] maximum bytes to read
180
180
  # @yield [String] read data
181
- # @return [void]
181
+ # @return [Polyphony::Pipe] self
182
182
  def read_loop(maxlen = 8192, &block)
183
183
  Polyphony.backend_read_loop(self, maxlen, &block)
184
184
  end
@@ -199,7 +199,7 @@ class Polyphony::Pipe
199
199
  #
200
200
  # @param receiver [any] receiver object
201
201
  # @param method [Symbol] method to call
202
- # @return [void]
202
+ # @return [Polyphony::Pipe] self
203
203
  def feed_loop(receiver, method = :call, &block)
204
204
  Polyphony.backend_feed_loop(self, receiver, method, &block)
205
205
  end
@@ -37,7 +37,7 @@ class ::Socket < ::BasicSocket
37
37
  # Accepts incoming connections in an infinite loop.
38
38
  #
39
39
  # @yield [Socket] accepted socket
40
- # @return [void]
40
+ # @return [nil]
41
41
  def accept_loop(&block)
42
42
  Polyphony.backend_accept_loop(self, TCPSocket, &block)
43
43
  end
@@ -109,7 +109,7 @@ class ::Socket < ::BasicSocket
109
109
  #
110
110
  # @param maxlen [Integer] maximum bytes to receive
111
111
  # @yield [String] received data
112
- # @return [void]
112
+ # @return [Socket] self
113
113
  def recv_loop(maxlen = 8192, &block)
114
114
  Polyphony.backend_recv_loop(self, maxlen, &block)
115
115
  end
@@ -131,7 +131,7 @@ class ::Socket < ::BasicSocket
131
131
  #
132
132
  # @param receiver [any] receiver object
133
133
  # @param method [Symbol] method to call
134
- # @return [void]
134
+ # @return [Socket] self
135
135
  def feed_loop(receiver, method = :call, &block)
136
136
  Polyphony.backend_recv_feed_loop(self, receiver, method, &block)
137
137
  end
@@ -376,7 +376,7 @@ class ::TCPSocket < ::IPSocket
376
376
  #
377
377
  # @param maxlen [Integer] maximum bytes to receive
378
378
  # @yield [String] received data
379
- # @return [void]
379
+ # @return [Socket] self
380
380
  def recv_loop(maxlen = 8192, &block)
381
381
  Polyphony.backend_recv_loop(self, maxlen, &block)
382
382
  end
@@ -398,7 +398,7 @@ class ::TCPSocket < ::IPSocket
398
398
  #
399
399
  # @param receiver [any] receiver object
400
400
  # @param method [Symbol] method to call
401
- # @return [void]
401
+ # @return [Socket] self
402
402
  def feed_loop(receiver, method = :call, &block)
403
403
  Polyphony.backend_recv_feed_loop(self, receiver, method, &block)
404
404
  end
@@ -494,7 +494,7 @@ class ::TCPServer < ::TCPSocket
494
494
  # Accepts incoming connections in an infinite loop.
495
495
  #
496
496
  # @yield [TCPSocket] accepted socket
497
- # @return [void]
497
+ # @return [nil]
498
498
  def accept_loop(&block)
499
499
  Polyphony.backend_accept_loop(@io, TCPSocket, &block)
500
500
  end
@@ -526,7 +526,7 @@ class ::UNIXServer < ::UNIXSocket
526
526
  # Accepts incoming connections in an infinite loop.
527
527
  #
528
528
  # @yield [UNIXSocket] accepted socket
529
- # @return [void]
529
+ # @return [nil]
530
530
  def accept_loop(&block)
531
531
  Polyphony.backend_accept_loop(self, UNIXSocket, &block)
532
532
  end
@@ -588,7 +588,7 @@ class ::UNIXSocket < ::BasicSocket
588
588
  #
589
589
  # @param maxlen [Integer] maximum bytes to receive
590
590
  # @yield [String] received data
591
- # @return [void]
591
+ # @return [Socket] self
592
592
  def recv_loop(maxlen = 8192, &block)
593
593
  Polyphony.backend_recv_loop(self, maxlen, &block)
594
594
  end
@@ -610,7 +610,7 @@ class ::UNIXSocket < ::BasicSocket
610
610
  #
611
611
  # @param receiver [any] receiver object
612
612
  # @param method [Symbol] method to call
613
- # @return [void]
613
+ # @return [Socket] self
614
614
  def feed_loop(receiver, method = :call, &block)
615
615
  Polyphony.backend_recv_feed_loop(self, receiver, method, &block)
616
616
  end
@@ -12,7 +12,6 @@ class ::Thread
12
12
 
13
13
  # Initializes the thread.
14
14
  # @param args [Array] arguments to pass to thread block
15
- # @return [void]
16
15
  def initialize(*args, &block)
17
16
  @join_wait_queue = []
18
17
  @finalization_mutex = Mutex.new
@@ -23,11 +22,12 @@ class ::Thread
23
22
 
24
23
  # Sets up the thread and its main fiber.
25
24
  #
26
- # @return [void]
25
+ # @return [Thread] self
27
26
  def setup
28
27
  @main_fiber = Fiber.current
29
28
  @main_fiber.setup_main_fiber
30
29
  setup_fiber_scheduling
30
+ self
31
31
  end
32
32
 
33
33
  # @!visibility private
@@ -133,7 +133,7 @@ class ::Thread
133
133
 
134
134
  # Runs the thread's block, handling any uncaught exceptions.
135
135
  #
136
- # @return [void]
136
+ # @return [any] thread result value
137
137
  def execute
138
138
  # backend must be created in the context of the new thread, therefore it
139
139
  # cannot be created in Thread#initialize
@@ -159,7 +159,6 @@ class ::Thread
159
159
  # Finalizes the thread.
160
160
  #
161
161
  # @param result [any] thread's return value
162
- # @return [void]
163
162
  def finalize(result)
164
163
  unless Fiber.current.children.empty?
165
164
  Fiber.current.shutdown_all_children
@@ -175,7 +174,6 @@ class ::Thread
175
174
  # Signals all fibers waiting for the thread to terminate.
176
175
  #
177
176
  # @param result [any] thread's return value
178
- # @return [void]
179
177
  def signal_waiters(result)
180
178
  @join_wait_queue.each { |w| w.signal(result) }
181
179
  end
data/lib/polyphony/net.rb CHANGED
@@ -57,7 +57,6 @@ module Polyphony
57
57
  #
58
58
  # @param context [SSLContext] SSL context
59
59
  # @param protocols [Array] array of supported protocols
60
- # @return [void]
61
60
  def setup_alpn(context, protocols)
62
61
  context.alpn_protocols = protocols
63
62
  context.alpn_select_cb = lambda do |peer_protocols|
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Polyphony
4
4
  # @!visibility private
5
- VERSION = '0.99.5'
5
+ VERSION = '1.0'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.99.5
4
+ version: '1.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-10 00:00:00.000000000 Z
11
+ date: 2023-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -144,9 +144,6 @@ files:
144
144
  - README.md
145
145
  - Rakefile
146
146
  - TODO.md
147
- - assets/echo-fibers.svg
148
- - assets/polyphony-logo.png
149
- - assets/sleeping-fiber.svg
150
147
  - bin/pdbg
151
148
  - bin/polyphony-debug
152
149
  - bin/stress.rb
@@ -154,15 +151,15 @@ files:
154
151
  - docs/_user-guide/all-about-timers.md
155
152
  - docs/_user-guide/index.md
156
153
  - docs/_user-guide/web-server.md
154
+ - docs/assets/echo-fibers.svg
155
+ - docs/assets/polyphony-logo.png
156
+ - docs/assets/sleeping-fiber.svg
157
157
  - docs/concurrency.md
158
158
  - docs/design-principles.md
159
159
  - docs/exception-handling.md
160
160
  - docs/extending.md
161
161
  - docs/faq.md
162
162
  - docs/fiber-scheduling.md
163
- - docs/index.md
164
- - docs/link_rewriter.rb
165
- - docs/main-concepts/index.md
166
163
  - docs/overview.md
167
164
  - docs/readme.md
168
165
  - docs/tutorial.md
@@ -335,7 +332,6 @@ files:
335
332
  - lib/polyphony/core/channel.rb
336
333
  - lib/polyphony/core/debug.rb
337
334
  - lib/polyphony/core/exceptions.rb
338
- - lib/polyphony/core/global_api.rb
339
335
  - lib/polyphony/core/resource_pool.rb
340
336
  - lib/polyphony/core/sync.rb
341
337
  - lib/polyphony/core/thread_pool.rb
data/docs/index.md DELETED
@@ -1,94 +0,0 @@
1
- ---
2
- layout: page
3
- title: Home
4
- nav_order: 1
5
- permalink: /
6
- next_title: Installing Polyphony
7
- ---
8
-
9
- <p align="center"><img src="{{ 'polyphony-logo.png' | absolute_url }}" /></p>
10
-
11
- # Polyphony
12
- {:.text-center .logo-title}
13
-
14
- ## Fine-grained concurrency for Ruby
15
- {:.text-center .logo-title}
16
-
17
- Polyphony is a library for building concurrent applications in Ruby. Polyphony
18
- implements a comprehensive
19
- [fiber](https://ruby-doc.org/core-2.5.1/Fiber.html)-based concurrency model,
20
- using [libev](https://github.com/enki/libev) as a high-performance event reactor
21
- for I/O, timers, and other asynchronous events.
22
-
23
- [Overview](getting-started/overview){: .btn .btn-green .text-gamma }
24
- [Take the tutorial](getting-started/tutorial){: .btn .btn-blue .text-gamma }
25
- [Source code](https://github.com/digital-fabric/polyphony){: .btn .btn-purple .text-gamma target="_blank" }
26
- {:.text-center .mt-6 .h-align-center }
27
-
28
- ## Focused on Developer Happiness
29
-
30
- Polyphony is designed to make concurrent Ruby programming feel natural and
31
- fluent. The Polyphony API is easy to use, easy to understand, and above all
32
- idiomatic.
33
-
34
- ## Optimized for High Performance
35
-
36
- Polyphony offers high performance for I/O bound Ruby apps. Distributing
37
- concurrent operations over fibers, instead of threads or processes, minimizes
38
- memory consumption and reduces the cost of context-switching.
39
-
40
- ## Designed for Interoperability
41
-
42
- With Polyphony you can use any of the stock Ruby classes and modules like `IO`,
43
- `Process`, `Socket` and `OpenSSL` in a concurrent multi-fiber environment. In
44
- addition, Polyphony provides a structured model for exception handling that
45
- builds on and enhances Ruby's exception handling system.
46
-
47
- ## A Growing Ecosystem
48
-
49
- Polyphony includes a full-blown HTTP server implementation with integrated
50
- support for HTTP 2, WebSockets, TLS/SSL termination and more. Polyphony also
51
- provides fiber-aware adapters for connecting to PostgreSQL and Redis. More
52
- adapters are being developed.
53
-
54
- ## Features
55
-
56
- * Co-operative scheduling of concurrent tasks using Ruby fibers.
57
- * High-performance event reactor for handling I/O events and timers.
58
- * Natural, sequential programming style that makes it easy to reason about
59
- concurrent code.
60
- * Abstractions and constructs for controlling the execution of concurrent code:
61
- supervisors, throttling, resource pools etc.
62
- * Code can use native networking classes and libraries, growing support for
63
- third-party gems such as `pg` and `redis`.
64
- * Use stdlib classes such as `TCPServer` and `TCPSocket` and `Net::HTTP`.
65
- * Competitive performance and scalability characteristics, in terms of both
66
- throughput and memory consumption.
67
-
68
- ## Prior Art
69
-
70
- Polyphony draws inspiration from the following, in no particular order:
71
-
72
- * [nio4r](https://github.com/socketry/nio4r/) and
73
- [async](https://github.com/socketry/async) (Polyphony's C-extension code
74
- started as a spinoff of
75
- [nio4r's](https://github.com/socketry/nio4r/tree/master/ext))
76
- * The [go scheduler](https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part2.html)
77
- * [EventMachine](https://github.com/eventmachine/eventmachine)
78
- * [Trio](https://trio.readthedocs.io/)
79
- * [Erlang supervisors](http://erlang.org/doc/man/supervisor.html) (and actually,
80
- Erlang in general)
81
-
82
- ## Developer Resources
83
-
84
- * [Tutorial](getting-started/tutorial)
85
- * [Main Concepts](main-concepts/concurrency/)
86
- * [User Guide](user-guide/all-about-timers/)
87
- * [API Reference](api-reference/exception/)
88
- * [Examples](https://github.com/digital-fabric/polyphony/tree/9e0f3b09213156bdf376ef33684ef267517f06e8/examples/README.md)
89
-
90
- ## Contributing to Polyphony
91
-
92
- Issues and pull requests will be gladly accepted. Please use the [Polyphony git
93
- repository](https://github.com/digital-fabric/polyphony) as your primary point
94
- of departure for contributing.
@@ -1,17 +0,0 @@
1
- require 'yard'
2
-
3
- # shamelessly copied from https://github.com/troessner/reek/blob/master/docs/yard_plugin.rb
4
-
5
- # Template helper to modify processing of links in HTML generated from our
6
- # markdown files.
7
- module LocalLinkHelper
8
- # Rewrites links to (assumed local) markdown files so they're processed as
9
- # {file: } directives.
10
- def resolve_links(text)
11
- text = text.gsub(%r{<a href="(docs/[^"]*.md)">([^<]*)</a>}, '{file:/\1 \2}')
12
- .gsub(%r{<img src="(assets/[^"]*)">}, '{rdoc-image:/\1}')
13
- super text
14
- end
15
- end
16
-
17
- YARD::Templates::Template.extra_includes << LocalLinkHelper
@@ -1,9 +0,0 @@
1
- ---
2
- layout: page
3
- title: Main Concepts
4
- has_children: true
5
- nav_order: 3
6
- ---
7
-
8
- # Main Concepts
9
- {: .no_toc }