Skip to content

Commit 3b2ccdd

Browse files
committed
More documentation + documentation coverage.
1 parent 713ecbc commit 3b2ccdd

16 files changed

+204
-20
lines changed

Diff for: .github/workflows/documentation-coverage.yaml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Documentation Coverage
2+
3+
on: [push, pull_request]
4+
5+
permissions:
6+
contents: read
7+
8+
env:
9+
CONSOLE_OUTPUT: XTerm
10+
COVERAGE: PartialSummary
11+
12+
jobs:
13+
validate:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: ruby/setup-ruby@v1
19+
with:
20+
ruby-version: "3.3"
21+
bundler-cache: true
22+
23+
- name: Validate coverage
24+
timeout-minutes: 5
25+
run: bundle exec bake decode:index:coverage lib

Diff for: .github/workflows/coverage.yaml renamed to .github/workflows/test-coverage.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Coverage
1+
name: Test Coverage
22

33
on: [push, pull_request]
44

Diff for: gems.rb

+7-3
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@
1919
end
2020

2121
group :test do
22+
gem "sus"
23+
gem "covered"
24+
gem "decode"
25+
26+
gem "sus-fixtures-async"
27+
2228
gem "bake-test"
2329
gem "bake-test-external"
30+
2431
gem "benchmark-ips"
25-
gem "covered"
26-
gem "sus"
27-
gem "sus-fixtures-async"
2832
end

Diff for: lib/async.rb

+1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
require_relative "kernel/async"
1111
require_relative "kernel/sync"
1212

13+
# Asynchronous programming framework.
1314
module Async
1415
end

Diff for: lib/async/condition.rb

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module Async
1111
# A synchronization primitive, which allows fibers to wait until a particular condition is (edge) triggered.
1212
# @public Since `stable-v1`.
1313
class Condition
14+
# Create a new condition.
1415
def initialize
1516
@waiting = List.new
1617
end

Diff for: lib/async/idler.rb

+18
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,38 @@
44
# Copyright, 2024, by Samuel Williams.
55

66
module Async
7+
# A load balancing mechanism that can be used process work when the system is idle.
78
class Idler
9+
# Create a new idler.
10+
# @public Since `stable-v2`.
11+
#
12+
# @parameter maximum_load [Numeric] The maximum load before we start shedding work.
13+
# @parameter backoff [Numeric] The initial backoff time, used for delaying work.
14+
# @parameter parent [Interface(:async) | Nil] The parent task to use for async operations.
815
def initialize(maximum_load = 0.8, backoff: 0.01, parent: nil)
916
@maximum_load = maximum_load
1017
@backoff = backoff
1118
@parent = parent
1219
end
1320

21+
# Wait until the system is idle, then execute the given block in a new task.
22+
#
23+
# @asynchronous Executes the given block concurrently.
24+
#
25+
# @parameter arguments [Array] The arguments to pass to the block.
26+
# @parameter parent [Interface(:async) | Nil] The parent task to use for async operations.
27+
# @parameter options [Hash] The options to pass to the task.
28+
# @yields {|task| ...} When the system is idle, the block will be executed in a new task.
1429
def async(*arguments, parent: (@parent or Task.current), **options, &block)
1530
wait
1631

1732
# It is crucial that we optimistically execute the child task, so that we prevent a tight loop invoking this method from consuming all available resources.
1833
parent.async(*arguments, **options, &block)
1934
end
2035

36+
# Wait until the system is idle, according to the maximum load specified.
37+
#
38+
# If the scheduler is overloaded, this method will sleep for an exponentially increasing amount of time.
2139
def wait
2240
scheduler = Fiber.scheduler
2341
backoff = nil

Diff for: lib/async/list.rb

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def initialize
1313
@size = 0
1414
end
1515

16-
# Print a short summary of the list.
16+
# @returns [String] A short summary of the list.
1717
def to_s
1818
sprintf("#<%s:0x%x size=%d>", self.class.name, object_id, @size)
1919
end
@@ -36,12 +36,13 @@ def to_a
3636
return items
3737
end
3838

39-
# Points at the end of the list.
39+
# @attribute [Node | Nil] Points at the end of the list.
4040
attr_accessor :head
4141

42-
# Points at the start of the list.
42+
# @attribute [Node | Nil] Points at the start of the list.
4343
attr_accessor :tail
4444

45+
# @attribute [Integer] The number of nodes in the list.
4546
attr :size
4647

4748
# A callback that is invoked when an item is added to the list.
@@ -64,6 +65,7 @@ def append(node)
6465
return added(node)
6566
end
6667

68+
# Prepend a node to the start of the list.
6769
def prepend(node)
6870
if node.head
6971
raise ArgumentError, "Node is already in a list!"
@@ -224,6 +226,7 @@ def last
224226
return nil
225227
end
226228

229+
# Shift the first node off the list, if it is not empty.
227230
def shift
228231
if node = first
229232
remove!(node)

Diff for: lib/async/node.rb

+16
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
module Async
1313
# A list of children tasks.
1414
class Children < List
15+
# Create an empty list of children tasks.
1516
def initialize
1617
super
1718
@transient_count = 0
@@ -109,6 +110,9 @@ def transient?
109110
@transient
110111
end
111112

113+
# Annotate the node with a description.
114+
#
115+
# @parameter annotation [String] The description to annotate the node with.
112116
def annotate(annotation)
113117
if block_given?
114118
begin
@@ -123,6 +127,9 @@ def annotate(annotation)
123127
end
124128
end
125129

130+
# A description of the node, including the annotation and object name.
131+
#
132+
# @returns [String] The description of the node.
126133
def description
127134
@object_name ||= "#{self.class}:#{format '%#018x', object_id}#{@transient ? ' transient' : nil}"
128135

@@ -135,10 +142,14 @@ def description
135142
end
136143
end
137144

145+
# Provides a backtrace for nodes that have an active execution context.
146+
#
147+
# @returns [Array(Thread::Backtrace::Locations) | Nil] The backtrace of the node, if available.
138148
def backtrace(*arguments)
139149
nil
140150
end
141151

152+
# @returns [String] A description of the node.
142153
def to_s
143154
"\#<#{self.description}>"
144155
end
@@ -255,10 +266,15 @@ def stop(later = false)
255266
end
256267
end
257268

269+
# Whether the node has been stopped.
258270
def stopped?
259271
@children.nil?
260272
end
261273

274+
# Print the hierarchy of the task tree from the given node.
275+
#
276+
# @parameter out [IO] The output stream to write to.
277+
# @parameter backtrace [Boolean] Whether to print the backtrace of each node.
262278
def print_hierarchy(out = $stdout, backtrace: true)
263279
self.traverse do |node, level|
264280
indent = "\t" * level

Diff for: lib/async/notification.rb

+2
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,7 @@ def transfer
2929
end
3030
end
3131
end
32+
33+
private_constant :Signal
3234
end
3335
end

Diff for: lib/async/queue.rb

+40-2
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,44 @@ module Async
1111
# A queue which allows items to be processed in order.
1212
# @public Since `stable-v1`.
1313
class Queue < Notification
14+
# Create a new queue.
15+
#
16+
# @parameter parent [Interface(:async) | Nil] The parent task to use for async operations.
1417
def initialize(parent: nil)
1518
super()
1619

1720
@items = []
1821
@parent = parent
1922
end
2023

24+
# @attribute [Array] The items in the queue.
2125
attr :items
2226

27+
# @returns [Integer] The number of items in the queue.
2328
def size
2429
@items.size
2530
end
26-
31+
32+
# @returns [Boolean] Whether the queue is empty.
2733
def empty?
2834
@items.empty?
2935
end
3036

37+
# Add an item to the queue.
3138
def <<(item)
3239
@items << item
3340

3441
self.signal unless self.empty?
3542
end
3643

44+
# Add multiple items to the queue.
3745
def enqueue(*items)
3846
@items.concat(items)
3947

4048
self.signal unless self.empty?
4149
end
4250

51+
# Remove and return the next item from the queue.
4352
def dequeue
4453
while @items.empty?
4554
self.wait
@@ -48,21 +57,34 @@ def dequeue
4857
@items.shift
4958
end
5059

60+
# Process each item in the queue.
61+
#
62+
# @asynchronous Executes the given block concurrently for each item.
63+
#
64+
# @parameter arguments [Array] The arguments to pass to the block.
65+
# @parameter parent [Interface(:async) | Nil] The parent task to use for async operations.
66+
# @parameter options [Hash] The options to pass to the task.
67+
# @yields {|task| ...} When the system is idle, the block will be executed in a new task.
5168
def async(parent: (@parent or Task.current), **options, &block)
5269
while item = self.dequeue
5370
parent.async(item, **options, &block)
5471
end
5572
end
5673

74+
# Enumerate each item in the queue.
5775
def each
5876
while item = self.dequeue
5977
yield item
6078
end
6179
end
6280
end
6381

82+
# A queue which limits the number of items that can be enqueued.
6483
# @public Since `stable-v1`.
6584
class LimitedQueue < Queue
85+
# Create a new limited queue.
86+
#
87+
# @parameter limit [Integer] The maximum number of items that can be enqueued.
6688
def initialize(limit = 1, **options)
6789
super(**options)
6890

@@ -71,13 +93,19 @@ def initialize(limit = 1, **options)
7193
@full = Notification.new
7294
end
7395

96+
# @attribute [Integer] The maximum number of items that can be enqueued.
7497
attr :limit
7598

7699
# @returns [Boolean] Whether trying to enqueue an item would block.
77100
def limited?
78101
@items.size >= @limit
79102
end
80103

104+
# Add an item to the queue.
105+
#
106+
# If the queue is full, this method will block until there is space available.
107+
#
108+
# @parameter item [Object] The item to add to the queue.
81109
def <<(item)
82110
while limited?
83111
@full.wait
@@ -86,7 +114,12 @@ def <<(item)
86114
super
87115
end
88116

89-
def enqueue *items
117+
# Add multiple items to the queue.
118+
#
119+
# If the queue is full, this method will block until there is space available.
120+
#
121+
# @parameter items [Array] The items to add to the queue.
122+
def enqueue(*items)
90123
while !items.empty?
91124
while limited?
92125
@full.wait
@@ -99,6 +132,11 @@ def enqueue *items
99132
end
100133
end
101134

135+
# Remove and return the next item from the queue.
136+
#
137+
# If the queue is empty, this method will block until an item is available.
138+
#
139+
# @returns [Object] The next item in the queue.
102140
def dequeue
103141
item = super
104142

Diff for: lib/async/reactor.rb

+2
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ def self.run(...)
1515
Async(...)
1616
end
1717

18+
# Initialize the reactor and assign it to the current Fiber scheduler.
1819
def initialize(...)
1920
super
2021

2122
Fiber.set_scheduler(self)
2223
end
2324

25+
# Close the reactor and remove it from the current Fiber scheduler.
2426
def scheduler_close
2527
self.close
2628
end

0 commit comments

Comments
 (0)