Skip to content

Commit 28001e1

Browse files
committed
Updating readme, adding CI
1 parent 317aa21 commit 28001e1

3 files changed

Lines changed: 282 additions & 1 deletion

File tree

.github/dependabot.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "gomod"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
open-pull-requests-limit: 10
8+
9+
- package-ecosystem: "github-actions"
10+
directory: "/"
11+
schedule:
12+
interval: "weekly"
13+
open-pull-requests-limit: 5

.github/workflows/ci.yml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
name: Test
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Go
18+
uses: actions/setup-go@v5
19+
with:
20+
go-version: '1.21'
21+
check-latest: true
22+
cache: true
23+
24+
- name: Get dependencies
25+
run: go mod download
26+
27+
- name: Run tests
28+
run: go test -v ./...
29+
30+
build-example:
31+
name: Build and run example
32+
runs-on: ubuntu-latest
33+
needs: test
34+
steps:
35+
- name: Checkout code
36+
uses: actions/checkout@v4
37+
38+
- name: Set up Go
39+
uses: actions/setup-go@v5
40+
with:
41+
go-version: '1.21'
42+
check-latest: true
43+
cache: true
44+
45+
- name: Get dependencies
46+
run: go mod download
47+
48+
- name: Build example
49+
run: cd example && go build -v .
50+
51+
- name: Test example executable
52+
run: |
53+
cd example
54+
# Run the example app in the background and give it 5 seconds to start
55+
./$(basename $(pwd)) &
56+
APP_PID=$!
57+
sleep 5
58+
# Check if process is still running (successful start)
59+
if ps -p $APP_PID > /dev/null; then
60+
echo "Example app started successfully"
61+
kill $APP_PID
62+
exit 0
63+
else
64+
echo "Example app failed to start"
65+
exit 1
66+
fi

README.md

Lines changed: 203 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,206 @@ Modular Go
44
[![Go Reference](https://pkg.go.dev/badge/github.com/GoCodeAlone/modular.svg)](https://pkg.go.dev/github.com/GoCodeAlone/modular)
55

66
## Overview
7-
Modular is a package that provides a way to create modular applications in Go. It allows you to create modules that can be easily added or removed from the application. It also provides a way to manage dependencies between modules.
7+
Modular is a package that provides a structured way to create modular applications in Go. It allows you to build applications as collections of modules that can be easily added, removed, or replaced. Key features include:
8+
9+
- **Module lifecycle management**: Initialize, start, and gracefully stop modules
10+
- **Dependency management**: Automatically resolve and order module dependencies
11+
- **Service registry**: Register and retrieve application services
12+
- **Configuration management**: Handle configuration for modules and services
13+
- **Dependency injection**: Inject required services into modules
14+
15+
## Installation
16+
17+
```go
18+
go get github.com/GoCodeAlone/modular
19+
```
20+
21+
## Usage
22+
23+
### Basic Application
24+
25+
```go
26+
package main
27+
28+
import (
29+
"github.com/GoCodeAlone/modular"
30+
"log/slog"
31+
"os"
32+
)
33+
34+
func main() {
35+
// Create a logger
36+
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
37+
38+
// Create config provider with application configuration
39+
config := &AppConfig{
40+
Name: "MyApp",
41+
Version: "1.0.0",
42+
}
43+
configProvider := modular.NewStdConfigProvider(config)
44+
45+
// Create the application
46+
app := modular.NewApplication(configProvider, logger)
47+
48+
// Register modules
49+
app.RegisterModule(NewDatabaseModule())
50+
app.RegisterModule(NewAPIModule())
51+
52+
// Run the application (this will block until the application is terminated)
53+
if err := app.Run(); err != nil {
54+
logger.Error("Application error", "error", err)
55+
os.Exit(1)
56+
}
57+
}
58+
```
59+
60+
### Creating a Module
61+
62+
```go
63+
type DatabaseModule struct {
64+
db *sql.DB
65+
config *DatabaseConfig
66+
}
67+
68+
func NewDatabaseModule() modular.Module {
69+
return &DatabaseModule{}
70+
}
71+
72+
// RegisterConfig registers the module's configuration
73+
func (m *DatabaseModule) RegisterConfig(app *modular.Application) {
74+
m.config = &DatabaseConfig{
75+
DSN: "postgres://user:password@localhost:5432/dbname",
76+
}
77+
app.RegisterConfigSection("database", modular.NewStdConfigProvider(m.config))
78+
}
79+
80+
// Name returns the module's unique name
81+
func (m *DatabaseModule) Name() string {
82+
return "database"
83+
}
84+
85+
// Dependencies returns other modules this module depends on
86+
func (m *DatabaseModule) Dependencies() []string {
87+
return []string{} // No dependencies
88+
}
89+
90+
// Init initializes the module
91+
func (m *DatabaseModule) Init(app *modular.Application) error {
92+
// Initialize database connection
93+
db, err := sql.Open("postgres", m.config.DSN)
94+
if err != nil {
95+
return err
96+
}
97+
m.db = db
98+
return nil
99+
}
100+
101+
// ProvidesServices returns services provided by this module
102+
func (m *DatabaseModule) ProvidesServices() []modular.ServiceProvider {
103+
return []modular.ServiceProvider{
104+
{
105+
Name: "database",
106+
Description: "Database connection",
107+
Instance: m.db,
108+
},
109+
}
110+
}
111+
112+
// RequiresServices returns services required by this module
113+
func (m *DatabaseModule) RequiresServices() []modular.ServiceDependency {
114+
return []modular.ServiceDependency{} // No required services
115+
}
116+
117+
// Start starts the module
118+
func (m *DatabaseModule) Start(ctx context.Context) error {
119+
return nil // Database is already connected
120+
}
121+
122+
// Stop stops the module
123+
func (m *DatabaseModule) Stop(ctx context.Context) error {
124+
return m.db.Close()
125+
}
126+
```
127+
128+
### Service Dependencies
129+
130+
```go
131+
// A module that depends on another service
132+
func (m *APIModule) RequiresServices() []modular.ServiceDependency {
133+
return []modular.ServiceDependency{
134+
{
135+
Name: "database",
136+
Required: true, // Application won't start if this service is missing
137+
},
138+
{
139+
Name: "cache",
140+
Required: false, // Optional dependency
141+
},
142+
}
143+
}
144+
145+
// Using constructor injection
146+
func (m *APIModule) Constructor() modular.ModuleConstructor {
147+
return func(app *modular.Application, services map[string]any) (modular.Module, error) {
148+
// Services that were requested in RequiresServices() are available here
149+
db := services["database"].(*sql.DB)
150+
151+
// Create a new module instance with injected services
152+
return &APIModule{
153+
db: db,
154+
}, nil
155+
}
156+
}
157+
```
158+
159+
### Configuration Management
160+
161+
```go
162+
// Define your configuration struct
163+
type AppConfig struct {
164+
Name string `json:"name" yaml:"name"`
165+
Version string `json:"version" yaml:"version"`
166+
}
167+
168+
// Implement ConfigSetup interface if needed
169+
func (c *AppConfig) Setup() error {
170+
// Validate configuration or set defaults
171+
if c.Name == "" {
172+
c.Name = "DefaultApp"
173+
}
174+
return nil
175+
}
176+
```
177+
178+
## Key Interfaces
179+
180+
### Module
181+
182+
The core interface that all modules must implement:
183+
184+
```go
185+
type Module interface {
186+
RegisterConfig(app *Application)
187+
Init(app *Application) error
188+
Start(ctx context.Context) error
189+
Stop(ctx context.Context) error
190+
Name() string
191+
Dependencies() []string
192+
ProvidesServices() []ServiceProvider
193+
RequiresServices() []ServiceDependency
194+
}
195+
```
196+
197+
### ConfigProvider
198+
199+
Interface for configuration providers:
200+
201+
```go
202+
type ConfigProvider interface {
203+
GetConfig() any
204+
}
205+
```
206+
207+
## License
208+
209+
[MIT License](LICENSE)

0 commit comments

Comments
 (0)