polyphony 0.99 → 0.99.1

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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -1
  3. data/.rubocop.yml +3 -3
  4. data/.yardopts +30 -0
  5. data/CHANGELOG.md +4 -0
  6. data/LICENSE +1 -1
  7. data/README.md +63 -29
  8. data/Rakefile +1 -5
  9. data/TODO.md +0 -4
  10. data/docs/{main-concepts/concurrency.md → concurrency.md} +2 -9
  11. data/docs/{main-concepts/design-principles.md → design-principles.md} +3 -9
  12. data/docs/{main-concepts/exception-handling.md → exception-handling.md} +2 -9
  13. data/docs/{main-concepts/extending.md → extending.md} +2 -9
  14. data/docs/faq.md +3 -16
  15. data/docs/{main-concepts/fiber-scheduling.md → fiber-scheduling.md} +1 -9
  16. data/docs/link_rewriter.rb +16 -0
  17. data/docs/{getting-started/overview.md → overview.md} +1 -30
  18. data/docs/{getting-started/tutorial.md → tutorial.md} +3 -28
  19. data/docs/{_posts/2020-07-26-polyphony-0.44.md → whats-new.md} +3 -1
  20. data/examples/adapters/redis_client.rb +3 -2
  21. data/examples/io/echo_server.rb +1 -1
  22. data/examples/io/echo_server_plain_ruby.rb +26 -0
  23. data/ext/polyphony/backend_io_uring.c +154 -9
  24. data/ext/polyphony/backend_io_uring_context.c +21 -12
  25. data/ext/polyphony/backend_io_uring_context.h +12 -7
  26. data/ext/polyphony/backend_libev.c +1 -1
  27. data/ext/polyphony/extconf.rb +24 -8
  28. data/ext/polyphony/fiber.c +79 -2
  29. data/ext/polyphony/io_extensions.c +53 -0
  30. data/ext/polyphony/pipe.c +42 -2
  31. data/ext/polyphony/polyphony.c +345 -31
  32. data/ext/polyphony/polyphony.h +9 -2
  33. data/ext/polyphony/queue.c +181 -0
  34. data/ext/polyphony/ring_buffer.c +0 -1
  35. data/ext/polyphony/runqueue.c +8 -1
  36. data/ext/polyphony/runqueue_ring_buffer.c +13 -0
  37. data/ext/polyphony/runqueue_ring_buffer.h +2 -1
  38. data/ext/polyphony/socket_extensions.c +6 -0
  39. data/ext/polyphony/thread.c +34 -2
  40. data/lib/polyphony/adapters/process.rb +11 -1
  41. data/lib/polyphony/adapters/sequel.rb +1 -1
  42. data/lib/polyphony/core/channel.rb +2 -0
  43. data/lib/polyphony/core/debug.rb +1 -1
  44. data/lib/polyphony/core/global_api.rb +25 -24
  45. data/lib/polyphony/core/resource_pool.rb +7 -6
  46. data/lib/polyphony/core/sync.rb +2 -2
  47. data/lib/polyphony/core/thread_pool.rb +3 -3
  48. data/lib/polyphony/core/timer.rb +8 -8
  49. data/lib/polyphony/extensions/exception.rb +2 -0
  50. data/lib/polyphony/extensions/fiber.rb +15 -13
  51. data/lib/polyphony/extensions/io.rb +127 -5
  52. data/lib/polyphony/extensions/kernel.rb +20 -2
  53. data/lib/polyphony/extensions/openssl.rb +100 -11
  54. data/lib/polyphony/extensions/pipe.rb +103 -7
  55. data/lib/polyphony/extensions/process.rb +13 -1
  56. data/lib/polyphony/extensions/socket.rb +93 -27
  57. data/lib/polyphony/extensions/thread.rb +9 -1
  58. data/lib/polyphony/extensions/timeout.rb +1 -1
  59. data/lib/polyphony/version.rb +2 -1
  60. data/lib/polyphony.rb +27 -7
  61. data/polyphony.gemspec +1 -8
  62. data/test/stress.rb +1 -1
  63. data/test/test_global_api.rb +45 -7
  64. data/test/test_socket.rb +96 -0
  65. data/test/test_timer.rb +5 -5
  66. metadata +17 -40
  67. data/docs/_config.yml +0 -64
  68. data/docs/_includes/head.html +0 -40
  69. data/docs/_includes/title.html +0 -1
  70. data/docs/_sass/custom/custom.scss +0 -10
  71. data/docs/_sass/overrides.scss +0 -0
  72. data/docs/api-reference/exception.md +0 -31
  73. data/docs/api-reference/fiber.md +0 -425
  74. data/docs/api-reference/index.md +0 -9
  75. data/docs/api-reference/io.md +0 -36
  76. data/docs/api-reference/object.md +0 -99
  77. data/docs/api-reference/polyphony-baseexception.md +0 -33
  78. data/docs/api-reference/polyphony-cancel.md +0 -26
  79. data/docs/api-reference/polyphony-moveon.md +0 -24
  80. data/docs/api-reference/polyphony-net.md +0 -20
  81. data/docs/api-reference/polyphony-process.md +0 -28
  82. data/docs/api-reference/polyphony-resourcepool.md +0 -59
  83. data/docs/api-reference/polyphony-restart.md +0 -18
  84. data/docs/api-reference/polyphony-terminate.md +0 -18
  85. data/docs/api-reference/polyphony-threadpool.md +0 -67
  86. data/docs/api-reference/polyphony-throttler.md +0 -77
  87. data/docs/api-reference/polyphony.md +0 -36
  88. data/docs/api-reference/thread.md +0 -88
  89. data/docs/favicon.ico +0 -0
  90. data/docs/getting-started/index.md +0 -10
  91. data/docs/getting-started/installing.md +0 -34
  92. /data/{docs/assets/img → assets}/echo-fibers.svg +0 -0
  93. /data/{docs → assets}/polyphony-logo.png +0 -0
  94. /data/{docs/assets/img → assets}/sleeping-fiber.svg +0 -0
@@ -8,7 +8,7 @@ module Polyphony
8
8
  # Initializes a new resource pool.
9
9
  #
10
10
  # @param opts [Hash] options
11
- # @param &block [Proc] allocator block
11
+ # @yield [] allocator block
12
12
  def initialize(opts, &block)
13
13
  @allocator = block
14
14
  @limit = opts[:limit] || 4
@@ -36,7 +36,7 @@ module Polyphony
36
36
  # db.query(sql).to_a
37
37
  # end
38
38
  #
39
- # @param &block [Proc] code to run
39
+ # @yield [any] code to run
40
40
  # @return [any] return value of block
41
41
  def acquire(&block)
42
42
  fiber = Fiber.current
@@ -54,13 +54,14 @@ module Polyphony
54
54
  # }
55
55
  #
56
56
  # @param sym [Symbol] method name
57
- # @param *args [Array<any>] method arguments
58
- # @param &block [Proc] block passed to method
57
+ # @param args [Array<any>] method arguments
58
+ # @yield [any] block passed to method
59
+ # @return [any] result of method call
59
60
  def method_missing(sym, *args, &block)
60
61
  acquire { |r| r.send(sym, *args, &block) }
61
62
  end
62
63
 
63
- # :no-doc:
64
+ # @!visibility private
64
65
  def respond_to_missing?(*_args)
65
66
  true
66
67
  end
@@ -87,7 +88,7 @@ module Polyphony
87
88
  # Acquires a resource from stock, yielding it to the given block.
88
89
  #
89
90
  # @param fiber [Fiber] the fiber the resource will be associated with
90
- # @param &block [Proc] given block
91
+ # @yield [any] given block
91
92
  # @return [any] return value of block
92
93
  def acquire_from_stock(fiber)
93
94
  add_to_stock if (@stock.empty? || @stock.pending?) && @size < @limit
@@ -17,7 +17,7 @@ module Polyphony
17
17
  # This method is re-entrant. Recursive calls from the given block will not
18
18
  # block.
19
19
  #
20
- # @param &block [Proc] code to run
20
+ # @yield [] code to run
21
21
  # @return [any] return value of block
22
22
  def synchronize(&block)
23
23
  return yield if @holding_fiber == Fiber.current
@@ -140,7 +140,7 @@ module Polyphony
140
140
  # Waits for the condition variable to be signalled.
141
141
  #
142
142
  # @param mutex [Polyphony::Mutex] mutex to release while waiting for signal
143
- # @param timeout [Number, nil] timeout in seconds (currently not implemented)
143
+ # @param _timeout [Number, nil] timeout in seconds (currently not implemented)
144
144
  # @return [void]
145
145
  def wait(mutex, _timeout = nil)
146
146
  mutex.conditional_release
@@ -12,7 +12,7 @@ module Polyphony
12
12
 
13
13
  # Runs the given block on an available thread from the default thread pool.
14
14
  #
15
- # @param &block [Proc] given block
15
+ # @yield [] given block
16
16
  # @return [any] return value of given block
17
17
  def self.process(&block)
18
18
  @default_pool ||= new
@@ -41,7 +41,7 @@ module Polyphony
41
41
 
42
42
  # Runs the given block on an available thread from the pool.
43
43
  #
44
- # @param &block [Proc] given block
44
+ # @yield [] given block
45
45
  # @return [any] return value of block
46
46
  def process(&block)
47
47
  setup unless @task_queue
@@ -55,7 +55,7 @@ module Polyphony
55
55
  # method does not block. The task will be performed once a thread becomes
56
56
  # available.
57
57
  #
58
- # @param &block [Proc] given block
58
+ # @yield [] given block
59
59
  # @return [Polyphony::ThreadPool] self
60
60
  def cast(&block)
61
61
  setup unless @task_queue
@@ -11,7 +11,7 @@ module Polyphony
11
11
  # Initializes a new timer with the given resolution.
12
12
  #
13
13
  # @param tag [any] tag to use for the timer's fiber
14
- # @param resolution: [Number] timer granularity in seconds or fractions thereof
14
+ # @param resolution [Number] timer granularity in seconds or fractions thereof
15
15
  def initialize(tag = nil, resolution:)
16
16
  @fiber = spin_loop(tag, interval: resolution) { update }
17
17
  @timeouts = {}
@@ -43,8 +43,8 @@ module Polyphony
43
43
  # Spins up a fiber that will run the given block after sleeping for the
44
44
  # given delay.
45
45
  #
46
- # @param delay [Number] delay in seconds before running the given block
47
- # @param &block [Proc] block to run
46
+ # @param interval [Number] delay in seconds before running the given block
47
+ # @yield [] block to run
48
48
  # @return [Fiber] spun fiber
49
49
  def after(interval, &block)
50
50
  spin do
@@ -57,7 +57,7 @@ module Polyphony
57
57
  # consecutive iterations.
58
58
  #
59
59
  # @param interval [Number] interval between consecutive iterations in seconds
60
- # @param &block [Proc] block to run
60
+ # @yield [] block to run
61
61
  # @return [void]
62
62
  def every(interval)
63
63
  fiber = Fiber.current
@@ -109,8 +109,8 @@ module Polyphony
109
109
  # end
110
110
  #
111
111
  # @param interval [Number] timout in seconds
112
- # @param with_exception: [Class, Exception] exception or exception class
113
- # @param &block [Proc] block to execute
112
+ # @param with_exception [Class, Exception] exception or exception class
113
+ # @yield [Canceller] block to execute
114
114
  # @return [any] block's return value
115
115
  def cancel_after(interval, with_exception: Polyphony::Cancel)
116
116
  fiber = Fiber.current
@@ -163,8 +163,8 @@ module Polyphony
163
163
  # end
164
164
  #
165
165
  # @param interval [Number] timout in seconds
166
- # @param with_value: [any] return value in case of timeout
167
- # @param &block [Proc] block to execute
166
+ # @param with_value [any] return value in case of timeout
167
+ # @yield [Fiber] block to execute
168
168
  # @return [any] block's return value
169
169
  def move_on_after(interval, with_value: nil)
170
170
  fiber = Fiber.current
@@ -18,6 +18,7 @@ class ::Exception
18
18
  # Set to the fiber from which the exception was raised.
19
19
  attr_accessor :raising_fiber
20
20
 
21
+ # @!visibility private
21
22
  alias_method :orig_initialize, :initialize
22
23
 
23
24
  # Initializes the exception with the given arguments.
@@ -26,6 +27,7 @@ class ::Exception
26
27
  orig_initialize(*args)
27
28
  end
28
29
 
30
+ # @!visibility private
29
31
  alias_method :orig_backtrace, :backtrace
30
32
 
31
33
  # Returns the backtrace for the exception. If
@@ -116,7 +116,7 @@ module Polyphony
116
116
  # operation will be resumed. This API is experimental and might be removed
117
117
  # in the future.
118
118
  #
119
- # @param &block [Proc] given block
119
+ # @yield [any] given block
120
120
  # @return [Fiber] self
121
121
  def interject(&block)
122
122
  raise Polyphony::Interjection.new(block)
@@ -132,7 +132,7 @@ module Polyphony
132
132
 
133
133
  private
134
134
 
135
- # :no-doc:
135
+ # @!visibility private
136
136
  def error_from_raise_args(args)
137
137
  case (arg = args.shift)
138
138
  when String then RuntimeError.new(arg)
@@ -171,10 +171,11 @@ module Polyphony
171
171
  #
172
172
  # This method blocks indefinitely.
173
173
  #
174
- # @param *fibers [Array<Fiber>] fibers to supervise
175
- # @param on_done: [Proc, nil] proc to call when a supervised fiber is terminated
176
- # @param on_error: [Proc, nil] proc to call when a supervised fiber is terminated with an exception
177
- # @param restart: [:always, :on_error, nil] whether to restart terminated fibers
174
+ # @param fibers [Array<Fiber>] fibers to supervise
175
+ # @option opts [Proc, nil] :on_done proc to call when a supervised fiber is terminated
176
+ # @option opts [Proc, nil] :on_error proc to call when a supervised fiber is terminated with an exception
177
+ # @option opts [:always, :on_error, nil] :restart whether to restart terminated fibers
178
+ # @yield [] supervisor block
178
179
  # @return [void]
179
180
  def supervise(*fibers, **opts, &block)
180
181
  block ||= supervise_opts_to_block(opts)
@@ -198,7 +199,7 @@ module Polyphony
198
199
 
199
200
  private
200
201
 
201
- # :no-doc:
202
+ # @!visibility private
202
203
  def supervise_opts_to_block(opts)
203
204
  block = opts[:on_done] || opts[:on_error]
204
205
  restart = opts[:restart]
@@ -228,7 +229,7 @@ module Polyphony
228
229
  # terminates with an uncaught exception, `Fiber.await` will await all the
229
230
  # other fibers to terminate, then reraise the exception.
230
231
  #
231
- # @param *fibers [Array<Fiber>] fibers to wait for
232
+ # @param fibers [Array<Fiber>] fibers to wait for
232
233
  # @return [Array<any>] return values of given fibers
233
234
  def await(*fibers)
234
235
  return [] if fibers.empty?
@@ -267,7 +268,7 @@ module Polyphony
267
268
  # array containing the first terminated fiber and its return value. If an
268
269
  # exception occurs in one of the given fibers, it will be reraised.
269
270
  #
270
- # @param *fibers [Array<Fiber>] Fibers to wait for
271
+ # @param fibers [Array<Fiber>] Fibers to wait for
271
272
  # @return [Array] Array containing the first terminated fiber and its return value
272
273
  def select(*fibers)
273
274
  return nil if fibers.empty?
@@ -301,7 +302,7 @@ module Polyphony
301
302
  # also be scheduled with priority. This method is mainly used trapping
302
303
  # signals (see also the patched `Kernel#trap`)
303
304
  #
304
- # @param &block [Proc] given block
305
+ # @yield [] given block
305
306
  # @return [void]
306
307
  def schedule_priority_oob_fiber(&block)
307
308
  oob_fiber = Fiber.new do
@@ -322,7 +323,7 @@ module Polyphony
322
323
 
323
324
  private
324
325
 
325
- # :no-doc:
326
+ # @!visibility private
326
327
  def prepare_oob_fiber(fiber, block)
327
328
  fiber.oob = true
328
329
  fiber.tag = :oob
@@ -348,7 +349,7 @@ module Polyphony
348
349
  #
349
350
  # @param tag [any] child fiber's tag
350
351
  # @param orig_caller [Array<String>] caller to set for fiber
351
- # @param &block [Proc] child fiber's block
352
+ # @yield [any] child fiber's block
352
353
  # @return [Fiber] child fiber
353
354
  def spin(tag = nil, orig_caller = Kernel.caller, &block)
354
355
  f = Fiber.new { |v| f.run(v) }
@@ -456,10 +457,11 @@ module Polyphony
456
457
 
457
458
  # Removes a child fiber reference. Used internally.
458
459
  #
459
- # @param parent [Fiber] new parent
460
+ # @param child_fiber [Fiber] child fiber to be removed
460
461
  # @return [Fiber] self
461
462
  def remove_child(child_fiber)
462
463
  @children.delete(child_fiber) if @children
464
+ self
463
465
  end
464
466
  end
465
467
 
@@ -5,9 +5,10 @@ require 'open3'
5
5
  # IO extensions
6
6
  class ::IO
7
7
  class << self
8
+ # @!visibility private
8
9
  alias_method :orig_binread, :binread
9
10
 
10
- # TODO: add docs to all methods in this file
11
+ # @!visibility private
11
12
  def binread(name, length = nil, offset = nil)
12
13
  File.open(name, 'rb:ASCII-8BIT') do |f|
13
14
  f.seek(offset) if offset
@@ -15,7 +16,10 @@ class ::IO
15
16
  end
16
17
  end
17
18
 
19
+ # @!visibility private
18
20
  alias_method :orig_binwrite, :binwrite
21
+
22
+ # @!visibility private
19
23
  def binwrite(name, string, offset = nil)
20
24
  File.open(name, 'wb:ASCII-8BIT') do |f|
21
25
  f.seek(offset) if offset
@@ -23,13 +27,14 @@ class ::IO
23
27
  end
24
28
  end
25
29
 
30
+ # @!visibility private
26
31
  EMPTY_HASH = {}.freeze
27
32
 
33
+ # @!visibility private
28
34
  alias_method :orig_foreach, :foreach
29
- def foreach(name, sep = $/, limit = nil, getline_args = EMPTY_HASH, &block)
30
- # IO.orig_read(name).each_line(&block)
31
- # raise NotImplementedError
32
35
 
36
+ # @!visibility private
37
+ def foreach(name, sep = $/, limit = nil, getline_args = EMPTY_HASH, &block)
33
38
  if sep.is_a?(Integer)
34
39
  sep = $/
35
40
  limit = sep
@@ -39,7 +44,10 @@ class ::IO
39
44
  end
40
45
  end
41
46
 
47
+ # @!visibility private
42
48
  alias_method :orig_read, :read
49
+
50
+ # @!visibility private
43
51
  def read(name, length = nil, offset = nil, opt = EMPTY_HASH)
44
52
  if length.is_a?(Hash)
45
53
  opt = length
@@ -58,7 +66,10 @@ class ::IO
58
66
  # end
59
67
  # end
60
68
 
69
+ # @!visibility private
61
70
  alias_method :orig_write, :write
71
+
72
+ # @!visibility private
62
73
  def write(name, string, offset = nil, opt = EMPTY_HASH)
63
74
  File.open(name, opt[:mode] || 'w') do |f|
64
75
  f.seek(offset) if offset
@@ -66,22 +77,44 @@ class ::IO
66
77
  end
67
78
  end
68
79
 
80
+ # @!visibility private
69
81
  alias_method :orig_popen, :popen
82
+
83
+
84
+ # @!visibility private
70
85
  def popen(cmd, mode = 'r')
71
86
  return orig_popen(cmd, mode) unless block_given?
72
87
 
73
88
  Open3.popen2(cmd) { |_i, o, _t| yield o }
74
89
  end
75
90
 
91
+ # Splices from one IO to another IO. At least one of the IOs must be a pipe.
92
+ #
93
+ # @param src [IO, Polyphony::Pipe] source to splice from
94
+ # @param dest [IO, Polyphony::Pipe] destination to splice to
95
+ # @param maxlen [Integer] maximum bytes to splice
96
+ # @return [Integer] bytes spliced
76
97
  def splice(src, dest, maxlen)
77
98
  Polyphony.backend_splice(src, dest, maxlen)
78
99
  end
79
100
 
80
101
  if RUBY_PLATFORM =~ /linux/
102
+ # Creates a pipe and splices data between the two given IOs using the
103
+ # pipe, splicing until EOF.
104
+ #
105
+ # @param src [IO, Polyphony::Pipe] source to splice from
106
+ # @param dest [IO, Polyphony::Pipe] destination to splice to
107
+ # @return [Integer] total bytes spliced
81
108
  def double_splice(src, dest)
82
109
  Polyphony.backend_double_splice(src, dest)
83
110
  end
84
111
 
112
+ # Tees data from the source to the desination.
113
+ #
114
+ # @param src [IO, Polyphony::Pipe] source to tee from
115
+ # @param dest [IO, Polyphony::Pipe] destination to tee to
116
+ # @param maxlen [Integer] maximum bytes to tee
117
+ # @return [Integer] total bytes teed
85
118
  def tee(src, dest, maxlen)
86
119
  Polyphony.backend_tee(src, dest, maxlen)
87
120
  end
@@ -91,10 +124,12 @@ end
91
124
 
92
125
  # IO instance method patches
93
126
  class ::IO
127
+ # @!visibility private
94
128
  def __read_method__
95
129
  :backend_read
96
130
  end
97
131
 
132
+ # @!visibility private
98
133
  def __write_method__
99
134
  :backend_write
100
135
  end
@@ -113,13 +148,21 @@ class ::IO
113
148
  # def each_codepoint
114
149
  # end
115
150
 
151
+ # @!visibility private
116
152
  alias_method :orig_getbyte, :getbyte
153
+
154
+
155
+ # @!visibility private
117
156
  def getbyte
118
157
  char = getc
119
158
  char ? char.getbyte(0) : nil
120
159
  end
121
160
 
161
+ # @!visibility private
122
162
  alias_method :orig_getc, :getc
163
+
164
+
165
+ # @!visibility private
123
166
  def getc
124
167
  return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
125
168
 
@@ -130,6 +173,7 @@ class ::IO
130
173
  nil
131
174
  end
132
175
 
176
+ # @!visibility private
133
177
  def ungetc(c)
134
178
  c = c.chr if c.is_a?(Integer)
135
179
  if @read_buffer
@@ -140,7 +184,11 @@ class ::IO
140
184
  end
141
185
  alias_method :ungetbyte, :ungetc
142
186
 
187
+ # @!visibility private
143
188
  alias_method :orig_read, :read
189
+
190
+
191
+ # @!visibility private
144
192
  def read(len = nil, buf = nil, buf_pos = 0)
145
193
  return '' if len == 0
146
194
 
@@ -157,7 +205,10 @@ class ::IO
157
205
  already_read
158
206
  end
159
207
 
208
+ # @!visibility private
160
209
  alias_method :orig_readpartial, :read
210
+
211
+ # @!visibility private
161
212
  def readpartial(len, str = +'', buffer_pos = 0, raise_on_eof = true)
162
213
  result = Polyphony.backend_read(self, str, len, false, buffer_pos)
163
214
  raise EOFError if !result && raise_on_eof
@@ -165,18 +216,27 @@ class ::IO
165
216
  result
166
217
  end
167
218
 
219
+ # @!visibility private
168
220
  alias_method :orig_write, :write
221
+
222
+ # @!visibility private
169
223
  def write(str, *args)
170
224
  Polyphony.backend_write(self, str, *args)
171
225
  end
172
226
 
227
+ # @!visibility private
173
228
  alias_method :orig_write_chevron, :<<
229
+
230
+ # @!visibility private
174
231
  def <<(str)
175
232
  Polyphony.backend_write(self, str)
176
233
  self
177
234
  end
178
-
235
+
236
+ # @!visibility private
179
237
  alias_method :orig_gets, :gets
238
+
239
+ # @!visibility private
180
240
  def gets(sep = $/, _limit = nil, _chomp: nil)
181
241
  if sep.is_a?(Integer)
182
242
  sep = $/
@@ -197,6 +257,7 @@ class ::IO
197
257
  return nil
198
258
  end
199
259
 
260
+ # @!visibility private
200
261
  def each_line(sep = $/, limit = nil, chomp: false)
201
262
  if sep.is_a?(Integer)
202
263
  limit = sep
@@ -230,10 +291,15 @@ class ::IO
230
291
  # def putc(obj)
231
292
  # end
232
293
 
294
+ # @!visibility private
233
295
  LINEFEED = "\n"
296
+ # @!visibility private
234
297
  LINEFEED_RE = /\n$/.freeze
235
298
 
299
+ # @!visibility private
236
300
  alias_method :orig_puts, :puts
301
+
302
+ # @!visibility private
237
303
  def puts(*args)
238
304
  if args.empty?
239
305
  write LINEFEED
@@ -268,24 +334,66 @@ class ::IO
268
334
  # def readlines(sep = $/, limit = nil, chomp: nil)
269
335
  # end
270
336
 
337
+ # @!visibility private
271
338
  alias_method :orig_write_nonblock, :write_nonblock
339
+
340
+ # @!visibility private
272
341
  def write_nonblock(string, _options = {})
273
342
  write(string)
274
343
  end
275
344
 
345
+ # @!visibility private
276
346
  alias_method :orig_read_nonblock, :read_nonblock
347
+
348
+ # @!visibility private
277
349
  def read_nonblock(maxlen, buf = nil, _options = nil)
278
350
  buf ? readpartial(maxlen, buf) : readpartial(maxlen)
279
351
  end
280
352
 
353
+ # call-seq:
354
+ # io.read_loop { |data| ... }
355
+ # io.read_loop(maxlen) { |data| ... }
356
+ #
357
+ # Reads up to `maxlen` bytes at a time in an infinite loop. Read data
358
+ # will be passed to the given block.
359
+ #
360
+ # @param maxlen [Integer] maximum bytes to receive
361
+ # @yield [String] handler block
362
+ # @return [void]
281
363
  def read_loop(maxlen = 8192, &block)
282
364
  Polyphony.backend_read_loop(self, maxlen, &block)
283
365
  end
284
366
 
367
+ # call-seq:
368
+ # io.feed_loop(receiver, method)
369
+ # io.feed_loop(receiver, method) { |result| ... }
370
+ #
371
+ # Receives data from the io in an infinite loop, passing the data to the given
372
+ # receiver using the given method. If a block is given, the result of the
373
+ # method call to the receiver is passed to the block.
374
+ #
375
+ # This method can be used to feed data into parser objects. The following
376
+ # example shows how to feed data from a io directly into a MessagePack
377
+ # unpacker:
378
+ #
379
+ # unpacker = MessagePack::Unpacker.new
380
+ # buffer = []
381
+ # reader = spin do
382
+ # io.feed_loop(unpacker, :feed_each) { |msg| handle_msg(msg) }
383
+ # end
384
+ #
385
+ # @param receiver [any] receiver object
386
+ # @param method [Symbol] method to call
387
+ # @yield [any] block to handle result of method call to receiver
388
+ # @return [void]
285
389
  def feed_loop(receiver, method = :call, &block)
286
390
  Polyphony.backend_feed_loop(self, receiver, method, &block)
287
391
  end
288
392
 
393
+ # Waits for the IO to become readable, with an optional timeout.
394
+ #
395
+ # @param timeout [Integer, nil] optional timeout in seconds.
396
+ # @return [IO] self
289
397
  def wait_readable(timeout = nil)
290
398
  return self if @read_buffer && @read_buffer.size > 0
291
399
 
@@ -300,6 +408,10 @@ class ::IO
300
408
  end
301
409
  end
302
410
 
411
+ # Waits for the IO to become writeable, with an optional timeout.
412
+ #
413
+ # @param timeout [Integer, nil] optional timeout in seconds.
414
+ # @return [IO] self
303
415
  def wait_writable(timeout = nil)
304
416
  if timeout
305
417
  move_on_after(timeout) do
@@ -312,11 +424,21 @@ class ::IO
312
424
  end
313
425
  end
314
426
 
427
+ # Splices data from the given IO.
428
+ #
429
+ # @param src [IO, Polpyhony::Pipe] source to splice from
430
+ # @param maxlen [Integer] maximum bytes to splice
431
+ # @return [Integer] bytes spliced
315
432
  def splice_from(src, maxlen)
316
433
  Polyphony.backend_splice(src, self, maxlen)
317
434
  end
318
435
 
319
436
  if RUBY_PLATFORM =~ /linux/
437
+ # Tees data from the given IO.
438
+ #
439
+ # @param src [IO, Polpyhony::Pipe] source to tee from
440
+ # @param maxlen [Integer] maximum bytes to tee
441
+ # @return [Integer] bytes teed
320
442
  def tee_from(src, maxlen)
321
443
  Polyphony.backend_tee(src, self, maxlen)
322
444
  end
@@ -4,11 +4,13 @@ require 'open3'
4
4
 
5
5
  # Kernel extensions (methods available to all objects / call sites)
6
6
  module ::Kernel
7
+ # @!visibility private
7
8
  alias_method :orig_sleep, :sleep
8
9
 
10
+ # @!visibility private
9
11
  alias_method :orig_backtick, :`
10
12
 
11
- # TODO: add docs to all methods in this file
13
+ # @!visibility private
12
14
  def `(cmd)
13
15
  Open3.popen3(cmd) do |i, o, e, _t|
14
16
  i.close
@@ -18,6 +20,7 @@ module ::Kernel
18
20
  end
19
21
  end
20
22
 
23
+ # @!visibility private
21
24
  ARGV_GETS_LOOP = proc do |calling_fiber|
22
25
  while (fn = ARGV.shift)
23
26
  File.open(fn, 'r') do |f|
@@ -31,7 +34,10 @@ module ::Kernel
31
34
  calling_fiber.transfer(e)
32
35
  end
33
36
 
37
+ # @!visibility private
34
38
  alias_method :orig_gets, :gets
39
+
40
+ # Reads a single line from STDIN
35
41
  def gets(*_args)
36
42
  if !ARGV.empty? || @gets_fiber
37
43
  @gets_fiber ||= Fiber.new(&ARGV_GETS_LOOP)
@@ -45,7 +51,10 @@ module ::Kernel
45
51
  $stdin.gets
46
52
  end
47
53
 
54
+ # @!visibility private
48
55
  alias_method :orig_p, :p
56
+
57
+ # @!visibility private
49
58
  def p(*args)
50
59
  strs = args.inject([]) do |m, a|
51
60
  m << a.inspect << "\n"
@@ -54,13 +63,19 @@ module ::Kernel
54
63
  args.size == 1 ? args.first : args
55
64
  end
56
65
 
66
+ # @!visibility private
57
67
  alias_method :orig_system, :system
68
+
69
+ # @!visibility private
58
70
  def system(*args)
59
71
  Kernel.system(*args)
60
72
  end
61
73
 
62
74
  class << self
75
+ # @!visibility private
63
76
  alias_method :orig_system, :system
77
+
78
+ # @!visibility private
64
79
  def system(*args)
65
80
  waiter = nil
66
81
  Open3.popen2(*args) do |i, o, t|
@@ -74,7 +89,10 @@ module ::Kernel
74
89
  end
75
90
  end
76
91
 
92
+ # @!visibility private
77
93
  alias_method :orig_trap, :trap
94
+
95
+ # @!visibility private
78
96
  def trap(sig, command = nil, &block)
79
97
  return orig_trap(sig, command) if command.is_a? String
80
98
 
@@ -93,7 +111,7 @@ module ::Kernel
93
111
 
94
112
  private
95
113
 
96
- # :no-doc:
114
+ # @!visibility private
97
115
  def pipe_to_eof(src, dest)
98
116
  src.read_loop { |data| dest << data }
99
117
  end