Skip to content

Commit 9623d3c

Browse files
committed
100% documentation coverage.
1 parent 49d7b9c commit 9623d3c

File tree

7 files changed

+108
-0
lines changed

7 files changed

+108
-0
lines changed

lib/async/service.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@
66
require_relative "service/configuration"
77
require_relative "service/controller"
88
require_relative "service/version"
9+
10+
# @namespace
11+
module Async
12+
# @namespace
13+
module Service
14+
end
15+
end

lib/async/service/configuration.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ module Service
1313
#
1414
# Environments are key-value maps with lazy value resolution. An environment can inherit from a parent environment, which can provide defaults
1515
class Configuration
16+
# Build a configuration using a block.
17+
# @parameter root [String] The root directory for loading files.
18+
# @yields {|loader| ...} A loader instance for configuration.
19+
# @returns [Configuration] A new configuration instance.
1620
def self.build(root: Dir.pwd, &block)
1721
configuration = self.new
1822

@@ -22,6 +26,9 @@ def self.build(root: Dir.pwd, &block)
2226
return configuration
2327
end
2428

29+
# Load configuration from file paths.
30+
# @parameter paths [Array(String)] File paths to load, defaults to `ARGV`.
31+
# @returns [Configuration] A new configuration instance.
2532
def self.load(paths = ARGV)
2633
configuration = self.new
2734

@@ -32,6 +39,9 @@ def self.load(paths = ARGV)
3239
return configuration
3340
end
3441

42+
# Create configuration from environments.
43+
# @parameter environments [Array] Environment instances.
44+
# @returns [Configuration] A new configuration instance.
3545
def self.for(*environments)
3646
self.new(environments)
3747
end
@@ -43,6 +53,8 @@ def initialize(environments = [])
4353

4454
attr :environments
4555

56+
# Check if the configuration is empty.
57+
# @returns [Boolean] True if no environments are configured.
4658
def empty?
4759
@environments.empty?
4860
end

lib/async/service/container_service.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,23 @@
88

99
module Async
1010
module Service
11+
# A service that runs in a container with built-in health checking and process title formatting.
12+
#
13+
# This is the recommended base class for most services.
1114
class ContainerService < Async::Service::Generic
1215
include Async::Service::Formatting
1316

1417
private def format_title(evaluator, server)
1518
"#{evaluator.name} #{server.to_s}"
1619
end
1720

21+
# Run the service logic.
22+
#
23+
# Override this method to implement your service. Return an object that represents the running service (e.g., a server, task, or worker pool) for health checking.
24+
#
25+
# @parameter instance [Object] The container instance.
26+
# @parameter evaluator [Environment::Evaluator] The environment evaluator.
27+
# @returns [Object] The service object (server, task, etc.)
1828
def run(instance, evaluator)
1929
Async do
2030
sleep
@@ -37,12 +47,15 @@ def preload!
3747
Console.warn(self, "Service preload failed!", error)
3848
end
3949

50+
# Start the service, including preloading resources.
4051
def start
4152
preload!
4253

4354
super
4455
end
4556

57+
# Set up the container with health checking and process title formatting.
58+
# @parameter container [Async::Container] The container to configure.
4659
def setup(container)
4760
super
4861

lib/async/service/controller.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@
77

88
module Async
99
module Service
10+
# Controls multiple services and their lifecycle.
11+
#
12+
# The controller manages starting, stopping, and monitoring multiple services
13+
# within containers. It extends Async::Container::Controller to provide
14+
# service-specific functionality.
1015
class Controller < Async::Container::Controller
16+
# Warm up the Ruby process by preloading gems and running GC.
1117
def self.warmup
1218
begin
1319
require "bundler"
@@ -24,6 +30,9 @@ def self.warmup
2430
end
2531
end
2632

33+
# Run a configuration of services.
34+
# @parameter configuration [Configuration] The service configuration to run.
35+
# @parameter options [Hash] Additional options for the controller.
2736
def self.run(configuration, **options)
2837
controller = Async::Service::Controller.new(configuration.services.to_a, **options)
2938

@@ -32,10 +41,17 @@ def self.run(configuration, **options)
3241
controller.run
3342
end
3443

44+
# Create a controller for the given services.
45+
# @parameter services [Array(Generic)] The services to control.
46+
# @parameter options [Hash] Additional options for the controller.
47+
# @returns [Controller] A new controller instance.
3548
def self.for(*services, **options)
3649
self.new(services, **options)
3750
end
3851

52+
# Initialize a new controller with services.
53+
# @parameter services [Array(Generic)] The services to manage.
54+
# @parameter options [Hash] Options passed to the parent controller.
3955
def initialize(services, **options)
4056
super(**options)
4157

lib/async/service/environment.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,17 @@
55

66
module Async
77
module Service
8+
# Represents a service configuration with lazy evaluation and module composition.
9+
#
10+
# Environments store configuration as methods that can be overridden and composed using Ruby modules. They support lazy evaluation through evaluators.
811
class Environment
12+
# A builder for constructing environments using a DSL.
913
class Builder < BasicObject
14+
# Create a new environment with facets and values.
15+
# @parameter facets [Array(Module)] Modules to include in the environment.
16+
# @parameter values [Hash] Key-value pairs to define as methods.
17+
# @parameter block [Proc] A block for additional configuration.
18+
# @returns [Module] The constructed environment module.
1019
def self.for(*facets, **values, &block)
1120
top = ::Module.new
1221

@@ -46,10 +55,14 @@ def self.for(*facets, **values, &block)
4655
return top
4756
end
4857

58+
# Initialize a new builder.
59+
# @parameter facet [Module] The module to build into, defaults to a new `Module`.
4960
def initialize(facet = ::Module.new)
5061
@facet = facet
5162
end
5263

64+
# Include a module or other includable object into the environment.
65+
# @parameter target [Module] The module to include.
5366
def include(target)
5467
if target.class == ::Module
5568
@facet.include(target)
@@ -60,6 +73,10 @@ def include(target)
6073
end
6174
end
6275

76+
# Define methods dynamically on the environment.
77+
# @parameter name [Symbol] The method name to define.
78+
# @parameter argument [Object] The value to return from the method.
79+
# @parameter block [Proc] A block to use as the method implementation.
6380
def method_missing(name, argument = nil, &block)
6481
if block
6582
@facet.define_method(name, &block)
@@ -68,15 +85,25 @@ def method_missing(name, argument = nil, &block)
6885
end
6986
end
7087

88+
# Always respond to missing methods for dynamic method definition.
89+
# @parameter name [Symbol] The method name.
90+
# @parameter include_private [Boolean] Whether to include private methods.
91+
# @returns [Boolean] Always true to enable dynamic method definition.
7192
def respond_to_missing?(name, include_private = false)
7293
true
7394
end
7495
end
7596

97+
# Build a new environment using the builder DSL.
98+
# @parameter arguments [Array] Arguments passed to Builder.for
99+
# @returns [Environment] A new environment instance.
76100
def self.build(...)
77101
Environment.new(Builder.for(...))
78102
end
79103

104+
# Initialize a new environment.
105+
# @parameter facet [Module] The facet module containing the configuration methods.
106+
# @parameter parent [Environment | Nil] The parent environment for inheritance.
80107
def initialize(facet = ::Module.new, parent = nil)
81108
unless facet.class == ::Module
82109
raise ArgumentError, "Facet must be a module!"
@@ -92,21 +119,32 @@ def initialize(facet = ::Module.new, parent = nil)
92119
# @attribute [Environment | Nil] The parent environment, if any.
93120
attr :parent
94121

122+
# Include this environment's facet into a target module.
123+
# @parameter target [Module] The target module to include into.
95124
def included(target)
96125
@parent&.included(target)
97126
target.include(@facet)
98127
end
99128

129+
# Create a new environment with additional configuration.
130+
# @parameter arguments [Array] Arguments passed to Environment.build.
131+
# @returns [Environment] A new environment with this as parent.
100132
def with(...)
101133
return self.class.new(Builder.for(...), self)
102134
end
103135

136+
# Check if this environment implements a given interface.
137+
# @parameter interface [Module] The interface to check.
138+
# @returns [Boolean] True if this environment implements the interface.
104139
def implements?(interface)
105140
@facet <= interface
106141
end
107142

108143
# An evaluator is lazy read-only view of an environment. It memoizes all method calls.
109144
class Evaluator
145+
# Create an evaluator wrapper for an environment.
146+
# @parameter environment [Environment] The environment to wrap.
147+
# @returns [Evaluator] A new evaluator instance.
110148
def self.wrap(environment)
111149
evaluator = ::Class.new(self)
112150

@@ -137,14 +175,19 @@ def self.wrap(environment)
137175
return evaluator.new
138176
end
139177

178+
# Initialize a new evaluator.
140179
def initialize
141180
@cache = {}
142181
end
143182

183+
# Inspect representation of the evaluator.
184+
# @returns [String] A string representation of the evaluator with its keys.
144185
def inspect
145186
"#<#{Evaluator} #{self.keys}>"
146187
end
147188

189+
# Convert the evaluator to a hash.
190+
# @returns [Hash] A hash with all evaluated keys and values.
148191
def to_h
149192
# Ensure all keys are evaluated:
150193
self.keys.each do |name|
@@ -154,25 +197,38 @@ def to_h
154197
return @cache
155198
end
156199

200+
# Convert the evaluator to JSON.
201+
# @parameter arguments [Array] Arguments passed to to_json.
202+
# @returns [String] A JSON representation of the evaluator.
157203
def to_json(...)
158204
self.to_h.to_json(...)
159205
end
160206

207+
# Get value for a given key.
208+
# @parameter key [Symbol] The key to look up.
209+
# @returns [Object, nil] The value for the key, or nil if not found.
161210
def [](key)
162211
if self.key?(key)
163212
self.__send__(key)
164213
end
165214
end
166215

216+
# Check if a key is available.
217+
# @parameter key [Symbol] The key to check.
218+
# @returns [Boolean] True if the key exists.
167219
def key?(key)
168220
self.keys.include?(key)
169221
end
170222
end
171223

224+
# Create an evaluator for this environment.
225+
# @returns [Evaluator] A lazy evaluator for this environment.
172226
def evaluator
173227
return Evaluator.wrap(self)
174228
end
175229

230+
# Convert the environment to a hash.
231+
# @returns [Hash] A hash representation of the environment.
176232
def to_h
177233
evaluator.to_h
178234
end

lib/async/service/generic.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ def initialize(environment, evaluator = environment.evaluator)
3333
# @attribute [Environment] The environment which is used to configure the service.
3434
attr :environment
3535

36+
# Convert the service evaluator to a hash.
37+
# @returns [Hash] A hash representation of the evaluator.
3638
def to_h
3739
@evaluator.to_h
3840
end

lib/async/service/loader.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ def self.load_file(configuration, path)
3838
loader.instance_eval(File.read(path), path)
3939
end
4040

41+
# Load a file relative to the loader's root directory.
42+
# @parameter path [String] The path to the file to load.
4143
def load_file(path)
4244
Loader.load_file(@configuration, File.expand_path(path, @root))
4345
end

0 commit comments

Comments
 (0)