Skip to content

Commit a17b2e2

Browse files
committed
godoc: improving godoc
Signed-off-by: Filip Petrov <lombert.p.v@gmail.com>
1 parent ccc19b3 commit a17b2e2

File tree

13 files changed

+149
-76
lines changed

13 files changed

+149
-76
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
# autowire
1+
# 🔌 autowire [![GoDoc][doc-img]][doc] [![Github release][release-img]][release] [![Go Report Card][report-card-img]][report-card]
2+
3+
[doc-img]: http://img.shields.io/badge/GoDoc-Reference-blue.svg
4+
[doc]: https://godoc.org/github.com/go-autowire/autowire
5+
6+
[release-img]: https://img.shields.io/github/release/go-autowire/autowire.svg
7+
[release]: https://github.com/go-autowire/autowire
8+
9+
[report-card-img]: https://goreportcard.com/badge/github.com/go-autowire/autowire
10+
[report-card]: https://goreportcard.com/report/github.com/go-autowire/autowire

atesting/testing.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,39 @@ import (
88
"unicode"
99
)
1010

11+
// Spy Function is replacing object field with the one provided in the function as a second argument.
12+
// Spy Function detects automatically which field could be replaced with the provided one.
13+
// Important note: In order to traverse fields of the unexported fields we need to implement Getters.
14+
// As shown inside example package, we are replacing AuditClient with our mock implementation and in order to reach this
15+
// field we need Getter.
16+
// Example:
17+
// atesting.Spy(application, &TestAuditClient{})
18+
// Or this is equivalent of
19+
// application.UserSvc().SetAuditClient(&TestAuditClient{})
20+
// Getter UserSvc() is used to access userSvc field, which is unexported. For more information take a look at example package.
21+
//Parameters of Spy function:
22+
// - `v` : pointer to structure inside which spy object will be applied
23+
// - `dependency` : pointer to structure which will be injected
1124
func Spy(v interface{}, dependency interface{}) {
1225
slice := []interface{}{dependency}
1326
Spies(v, slice)
1427
}
1528

29+
// Spies Function is replacing object fields with the list of provided dependencies in the function as a second argument.
30+
// Spy Function detects automatically which field could be replaced with the provided one in the list of dependencies.
31+
// Important note: In order to traverse fields of the unexported fields we need to implement Getters.
32+
// As shown inside example package, we are replacing AuditClient with our mock implementation and in order to reach this
33+
// field we need Getter.
34+
// Example:
35+
// atesting.Spies(application, []interface{}{&TestPaymentServiceTest{}, &TestAuditClient{}})
36+
// Or this is equivalent of
37+
// application.UserSvc().SetAuditClient(&TestAuditClient{})
38+
// application.UserSvc().PaymentSvc = &TestPaymentServiceTest{}
39+
// Getter UserSvc() is used to access userSvc field, which is unexported. In case of PaymentSvc it is not required as field PaymentSvc is exported.
40+
// Parameters of Spies function:
41+
// - `v` : structure inside which spy objects will be applied
42+
// - `dependencies` : list of dependencies which will be injected
43+
// For more information take a look at example package.
1644
func Spies(v interface{}, dependencies []interface{}) {
1745
queue := list.New()
1846
queue.PushBack(v)
@@ -38,7 +66,7 @@ func Spies(v interface{}, dependencies []interface{}) {
3866
t := reflect.New(dependValue.Type())
3967
log.Println("Injecting Spy on dependency by tag " + tag + " will be used " + t.Type().String())
4068
autowire.Autowire(dependency)
41-
setValue(value, elem, i, dependency)
69+
setFieldValue(value, elem, i, dependency)
4270
}
4371
}
4472
}
@@ -61,7 +89,7 @@ func Spies(v interface{}, dependencies []interface{}) {
6189
}
6290
}
6391

64-
func setValue(value reflect.Value, elem reflect.Value, i int, dependency interface{}) bool {
92+
func setFieldValue(value reflect.Value, elem reflect.Value, i int, dependency interface{}) bool {
6593
runeName := []rune(elem.Type().Field(i).Name)
6694
exported := unicode.IsUpper(runeName[0])
6795
if exported {

autowire.go

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var dependencies map[string]interface{}
1515
var currentProfile = getProfile()
1616
var ch = make(chan os.Signal)
1717

18+
// Tag name
1819
const Tag = "autowire"
1920

2021
func init() {
@@ -36,40 +37,49 @@ func InitProd(initFunc func()) {
3637
// In order dependencies to be injected the desired struct fields should be marked with
3738
// autowire tag.
3839
//
39-
// Injection of concrete type
40+
// Concrete type Injection
4041
//
4142
// Currently both type of fields exported and unexported are supported.
43+
//
44+
// Unexported field
45+
//
4246
// Following snippet shows injecting dependencies inside private structure fields using `autowire:""` tag:
4347
// type Application struct {
4448
// config *configuration.ApplicationConfig `autowire:""`
4549
// }
4650
// func (a *Application) SetConfig(config *configuration.ApplicationConfig) {
4751
// a.config = config
4852
// }
49-
// If we need dependency to be injected into unexported field Set<FieldName> function is required, as show above.
53+
// If we need given dependency to be injected into unexported field Setter function(Set<FieldName>) is required, as show above.
54+
// If you have a field called config (lower case, unexported), the setter method should be called SetConfig (upper case, exported), not Setconfig.
55+
//
56+
// Exported field
57+
//
58+
// The use of upper-case names of the struct fields indicated field is exported.
5059
// type Application struct {
5160
// Config *configuration.ApplicationConfig `autowire:""`
5261
// }
53-
// Injection of dependency into exported is supported also and there is no need to provide additional Setter.
62+
// Dependency injection of exported field is supported with the difference that we don`t provide additional Setter function.
5463
//
55-
// Injection of interface
64+
// Interface Injection
5665
//
5766
// Often it`s better to rely on interface instead of concrete type, in order to accomplish this decoupling we specify
5867
// interfaces as a type of struct fields. The following snippet demonstrate that
5968
// type UserService struct {
60-
// userRoleRepository UserRoleRepository `autowire:"service/InMemoryUserRoleRepository"`
69+
// userRoleRepository UserRoleRepository `autowire:"repository/InMemoryUserRoleRepository"`
6170
// }
6271
// func (u *UserService) SetUserRoleRepository(userRoleRepository UserRoleRepository) {
6372
// u.userRoleRepository = userRoleRepository
6473
// }
6574
// UserRoleRepository is simply an interface and InMemoryUserRoleRepository is a struct, which implements this interface.
6675
// As it`s done dependency injection on unexported field, providing Setter is required. Just to highlight unexported fields
67-
// needs Setter while exported not. For more information take a look at example package.
76+
// needs Setter while exported not. For more information take a look at example#https://github.com/go-autowire/autowire/tree/main/example package.
77+
// Example:
78+
//
79+
//
6880
func Autowire(v interface{}) {
6981
value := reflect.ValueOf(v)
7082
switch value.Kind() {
71-
case reflect.Invalid:
72-
log.Println("invalid reflection type")
7383
case reflect.Ptr:
7484
structType := getStructPtrFullPath(value)
7585
_, ok := dependencies[structType]
@@ -80,6 +90,8 @@ func Autowire(v interface{}) {
8090
autowireDependencies(value)
8191
dependencies[structType] = v
8292
}
93+
case reflect.Invalid:
94+
log.Panicln("invalid reflection type")
8395
default: // reflect.Array, reflect.Struct, reflect.Interface
8496
log.Println(value.Type().String() + " value")
8597
}
@@ -95,8 +107,6 @@ func Autowired(v interface{}) interface{} {
95107
value := reflect.ValueOf(v)
96108
var path string
97109
switch value.Kind() {
98-
case reflect.Invalid:
99-
log.Println("invalid")
100110
case reflect.Struct:
101111
path = getFullPath(value.Type().PkgPath(), value.Type().String())
102112
case reflect.Ptr:
@@ -150,18 +160,7 @@ func autowireDependencies(value reflect.Value) {
150160
t = reflect.New(elem.Type().Field(i).Type.Elem())
151161
dependency, found := dependencies[getStructPtrFullPath(t)]
152162
if found {
153-
runeName := []rune(elem.Type().Field(i).Name)
154-
exported := unicode.IsUpper(runeName[0])
155-
if exported {
156-
elem.Field(i).Set(reflect.ValueOf(dependency))
157-
} else {
158-
runeName[0] = unicode.ToUpper(runeName[0])
159-
methodName := "Set" + string(runeName)
160-
method := value.MethodByName(methodName)
161-
if method.IsValid() {
162-
method.Call([]reflect.Value{reflect.ValueOf(dependency)})
163-
}
164-
}
163+
setValue(value, elem, i, dependency)
165164
}
166165
}
167166
}
@@ -197,11 +196,11 @@ func findDependency(tagDependencyType string) []interface{} {
197196
// which implements io.Closer interface will be invoked Call() function, so currently active
198197
//occupied resources(connections, channels, etc.) could be released.
199198
func Run(function func()) {
200-
defer close()
199+
defer closeAll()
201200
function()
202201
}
203202

204-
func close() {
203+
func closeAll() {
205204
log.Println("Closing...")
206205
for _, dependency := range dependencies {
207206
valueDepend := reflect.ValueOf(dependency)

doc.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Package Autowire is a framework that makes dependency injection in Golang.
2+
//
3+
// Autowire applications use dependency injection framework to eliminate usage
4+
// of globals without the tedious approach to manually wiring all the
5+
// dependencies together. Current approach of Autowire framework to accomplish
6+
// dependency injection is via using struct tags.
7+
//
8+
// Basic usage is explained in the package-level example below. If you're new
9+
// to Autowire, start there!
10+
//
11+
// Testing of Autowire Applications
12+
//
13+
// To write end-to-end tests of your application, you can use functions provided
14+
//by atesting package https://godoc.org/github.com/go-autowire/autowire/atesting
15+
package autowire

example/app/application.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ type Application struct {
1717
userSvc *service.UserService `autowire:""`
1818
}
1919

20+
// Start method is starting application
2021
func (a Application) Start() {
21-
log.Println("Config Kind : " + a.config.Kind())
22+
log.Println("Config ApiKey : " + a.config.ApiKey()[:3] + "****")
2223
userId := "serviceaccount@demo.com"
2324
balance, err := a.userSvc.Balance(userId)
2425
if err != nil {
@@ -27,14 +28,17 @@ func (a Application) Start() {
2728
fmt.Println("Current balance is " + balance.String())
2829
}
2930

31+
// SetConfig method is a Setter of private field config
3032
func (a *Application) SetConfig(config *configuration.ApplicationConfig) {
3133
a.config = config
3234
}
3335

36+
// SetUserSvc method is a Setter of private field userSvc
3437
func (a *Application) SetUserSvc(userSvc *service.UserService) {
3538
a.userSvc = userSvc
3639
}
3740

41+
// UserSvc method is a Getter of private field userSvc
3842
func (a *Application) UserSvc() *service.UserService {
3943
return a.userSvc
4044
}

example/autowire_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,12 @@ func (TestPaymentServiceTest) Balance() *big.Float {
2121
type TestAuditClient struct {
2222
}
2323

24-
func (TestAuditClient) Send(event string) {
24+
func (TestAuditClient) Send(_ string) {
2525
log.Printf("Test event delivered")
2626
}
2727

2828
func TestAutowire(t *testing.T) {
29-
app := autowire.Autowired(app.Application{}).(*app.Application)
30-
app.UserSvc().PaymentSvc = &TestPaymentServiceTest{}
31-
atesting.Spies(app, []interface{}{&TestPaymentServiceTest{}, &TestAuditClient{}})
32-
app.Start()
29+
application := autowire.Autowired(app.Application{}).(*app.Application)
30+
atesting.Spies(application, []interface{}{&TestPaymentServiceTest{}, &TestAuditClient{}})
31+
application.Start()
3332
}

example/configuration/application_config.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@ func init() {
88
autowire.Autowire(New("default"))
99
}
1010

11+
// A ApplicationConfig represents name struct, which hold application configuration
1112
type ApplicationConfig struct {
12-
kind string
13+
apiKey string
1314
}
1415

15-
func New(kind string) *ApplicationConfig {
16-
return &ApplicationConfig{kind: kind}
16+
// New returns new ApplicationConfig
17+
func New(apiKey string) *ApplicationConfig {
18+
return &ApplicationConfig{apiKey: apiKey}
1719
}
1820

19-
func (a ApplicationConfig) Kind() string {
20-
return a.kind
21+
// ApiKey is a Setter, which returns apiKey value
22+
func (a ApplicationConfig) ApiKey() string {
23+
return a.apiKey
2124
}

example/repository/user_repo.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,29 @@ func init() {
66
autowire.Autowire(&InMemoryUserRoleRepository{})
77
}
88

9+
// UserRole type
910
type UserRole string
1011

1112
const (
13+
// OwnerRole
1214
OwnerRole UserRole = "owner"
1315
)
1416

17+
// A String returns UserRole as a string
1518
func (u UserRole) String() string {
1619
return string(u)
1720
}
1821

22+
// A UserRoleRepository represents interface containing roles related function: GetAllRoles
1923
type UserRoleRepository interface {
2024
GetAllRoles(userId string) ([]UserRole, error)
2125
}
2226

27+
// A InMemoryUserRoleRepository represents struct, which implements UserRoleRepository interface
2328
type InMemoryUserRoleRepository struct {
2429
}
2530

31+
// GetAllRoles returns all roles of the user
2632
func (i InMemoryUserRoleRepository) GetAllRoles(_ string) ([]UserRole, error) {
2733
return []UserRole{OwnerRole}, nil
2834
}

example/service/audit_client.go

Lines changed: 0 additions & 22 deletions
This file was deleted.

example/service/audit_service.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package service
2+
3+
import (
4+
"log"
5+
)
6+
7+
// A EventSender represents interface
8+
type EventSender interface {
9+
// Send function is simply dispatching event
10+
Send(event string)
11+
}
12+
13+
// A AuditService represents a named struct
14+
type AuditService struct {
15+
Type string
16+
}
17+
18+
// A Send is dispatching the event
19+
func (AuditService) Send(event string) {
20+
log.Printf("auditClient Event %s sent", event)
21+
}

0 commit comments

Comments
 (0)