brick

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 7, 2025 License: MIT Imports: 12 Imported by: 0

README

English | 中文

Brick

Brick is a lightweight and non-intrusive library designed for component-based configuration management and dependency injection. "Lightweight" means the library has a simple implementation and is easy to use. "Non-intrusive" means that Brick is not a framework but rather a library; you can easily leverage its dependency injection and configuration management features without modifying the logic of your existing code.

Unlike libraries that strive to maximize support for default behaviors, Brick prioritizes certainty for developers. It thoroughly checks for potential injection errors and throws a panic during startup to ensure they are addressed immediately. This allows you to use Brick confidently, without constantly needing to worry about hidden issues.

Getting Started

Creating a Brick Component

Any type that implements the Brick interface is considered a Brick component. You only need to implement the BrickTypeID method, which should return a globally unique constant string that serves as the type ID of the component.

type Brick1 struct {}

func (l *Brick1) BrickTypeID() string {
    return "EG7LGZ4SX2O9L7ZZHS64"
}
Injecting Other Brick Components

To inject other Brick components, simply add the brick tag to the field representing the dependency. Brick will automatically handle the injection.

type Brick2 struct {
    Brick1 *Brick1 `brick:""`
}

func (l *Brick2) BrickTypeID() string {
    return "QQZWZH166CJIKAAAFRHV"
}

Let's break down the meaning of this tag: brick indicates that the Brick library should automatically inject a dependency. The string after brick: specifies the liveID of the component instance to be injected. "" (an empty string) means that the default liveID (the default instance) for this component should be injected, which in this case is the TypeID of Brick1.

This is equivalent to:

type Brick2 struct {
    Brick1 *Brick1 `brick:"EG7LGZ4SX2O9L7ZZHS64"`
}

Of course, you can also specify a different globally unique liveID.

Parsing Configuration for Brick Instances

If a Brick component needs to read external configuration from a file, it must implement the BrickNewer interface. The NewBrick method of this interface parse the incoming JSON string representing the configuration and return a new instance of the Brick component.

type Brick2 struct {
    ConfigString string `json:"configString" yaml:"configString" toml:"configString"`
    Brick1 *Brick1 `brick:""`
}

func (l *Brick2) NewBrick(jsonConfig []byte) brick.Brick {
    var newBrick = &Brick2{}
    _ = json.Unmarshal(jsonConfig, newBrick)
    return newBrick
}

As you can see from the field tags, configuration files can use popular formats like JSON, YAML, and TOML.

Example configuration:

[
    {
        "metaData": {
            "name": "Brick2 Instances",
            "typeID": "QQZWZH166CJIKAAAFRHV"
        },
        "lives": [
            {
                "liveID": "QQZWZH166CJIKAAAFRHV",
                "config": {
                    "configString": "your config string"
                }
            }
        ]
    }
]

You also need to inform the Brick library about the location of your configuration file, like this:

err := brick.AddConfigFile("config.json")
Registering Brick Components

You need to call the Register method to register your top-level Brick components. Dependencies will automatically be scanned and registered.

brick.RegisterNewer[*Brick2]()
Getting Brick Component Instances

You can retrieve an instance of a Brick component using the Get or GetOrCreate methods:

brick1 := brick.Get[*Brick1]()
Example Code
package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/doraemonkeys/brick"
)

type Brick1 struct{}

func (l *Brick1) BrickTypeID() string {
	return "EG7LGZ4SX2O9L7ZZHS64"
}

func (l *Brick1) SayHello() string {
	return "Hello, Brick1"
}

type Brick2 struct {
	ConfigString string  `json:"configString" yaml:"configString" toml:"configString"`
	Brick1       *Brick1 `brick:""`
}

func (l *Brick2) BrickTypeID() string {
	return "QQZWZH166CJIKAAAFRHV"
}

func (l *Brick2) NewBrick(jsonConfig []byte) brick.Brick {
	var newBrick = &Brick2{}
	if len(jsonConfig) > 0 {
		if err := json.Unmarshal(jsonConfig, newBrick); err != nil {
			panic(fmt.Errorf("Brick2 config error: %w", err))
		}
	}
	return newBrick
}

func (l *Brick2) SayHello() {
	fmt.Println("Hello, Brick2")
	fmt.Println(l.Brick1.SayHello())
	fmt.Printf("Brick2 config: %v", l.ConfigString)
}

const JsonConfig = `
[
    {
        "metaData": {
            "name": "Brick2 Instances",
            "typeID": "QQZWZH166CJIKAAAFRHV"
        },
        "lives": [
            {
                "liveID": "QQZWZH166CJIKAAAFRHV",
                "config": {
                    "configString": "your config string"
                }
            }
        ]
    }
]
`

func init() {
	brick.RegisterNewer[*Brick2]()

	_ = os.WriteFile("config.json", []byte(JsonConfig), 0644)
	err := brick.AddConfigFile("config.json")
	if err != nil {
		panic(err)
	}

}

func main() {
	brick2 := brick.Get[*Brick2]()
	brick2.SayHello()
}
Thanks

This library draws inspiration from dot.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddConfigFile

func AddConfigFile(path string) error

AddConfigFile adds brick configurations from a file, supporting JSON and YAML formats.

func CloneConfig

func CloneConfig[T Brick](liveID ...string) (newLiveID string)

func Get

func Get[T Brick](liveID ...string) T

Get retrieves a brick instance, creating it if necessary. If liveID is not provided, it will use the typeID as the LiveID.

If an instance for the given liveID has never been created before, and this is an unknown liveID, the function will panic to prevent unexpected behavior. An unknown liveID is one that has not been declared in the configuration or tag, and has not been explicitly registered as a non-default liveID. The default instance's liveID is the same as the typeID.

When retrieving a non-pointer Brick instance, be aware of whether the type can be copied safely. No checks are performed for this.

func GetOrCreate

func GetOrCreate[T Brick](liveID ...string) T

GetOrCreate like Get, but it will create a new instance for unknown liveID.

func RandomLiveID

func RandomLiveID() string

func Register

func Register[T Brick]()

Register registers the brick type and recursively registers its all dependencies. It uses the BrickTypeID method of the provided type to determine the type ID. This method is used for bricks that do not require custom configuration parsing.

func RegisterLiveIDType

func RegisterLiveIDType[T Brick](liveID string)

RegisterLiveIDType registers the type of the liveID instance, allowing the actual type of liveID to be obtained when injecting a brick for an interface.

func RegisterLives

func RegisterLives[T BrickLives]()

RegisterLives like RegisterNewer, but it requires the brick to implement the BrickLives interface, which describes the specified instance's specified dependency relationship.

func RegisterNewer

func RegisterNewer[T BrickNewer]()

RegisterNewer like Register, but it also registers a factory for configuration parsing. The provided type must implement the BrickNewer interface, which includes the NewBrick method for parsing configurations.

func SetLiveIDConstraint

func SetLiveIDConstraint(constraint bool)

SetLiveIDConstraint sets the constraint that all instances of the same brick type must have one liveID set to typeID.

Types

type Brick

type Brick interface {
	// BrickTypeID returns a unique constant string for each brick type.
	BrickTypeID() string
}

Brick is the interface that all bricks must implement.

type BrickConfig

type BrickConfig struct {
	TypeID string
	LiveID string

	Config any
	// contains filtered or unexported fields
}

BrickConfig holds the configuration for a single brick instance.

type BrickFileConfig

type BrickFileConfig struct {
	MetaData struct {
		Name    string `json:"name" yaml:"name" toml:"name"`
		TypeID  string `json:"typeID" yaml:"typeID" toml:"typeID"`
		NoCheck bool   `json:"noCheck" yaml:"noCheck" toml:"noCheck"`
	} `json:"metaData" yaml:"metaData" toml:"metaData"`
	Lives []struct {
		LiveID string `json:"liveID" yaml:"liveID" toml:"liveID"`
		Config any    `json:"config" yaml:"config" toml:"config"`
	} `json:"lives" yaml:"lives" toml:"lives"`
}

BrickFileConfig defines the structure of a brick configuration file.

type BrickLives

type BrickLives interface {
	BrickNewer
	// Used when multiple different instances of a type depend on different instances of the same type.
	// The dependency relationship returned here will forcibly override the dependency relationship in the tag.
	BrickLives() []Live
}

type BrickManager

type BrickManager struct {
	// contains filtered or unexported fields
}

BrickManager manages brick configurations and instances.

func (*BrickManager) AddConfigFile

func (b *BrickManager) AddConfigFile(path string) error

AddConfigFile adds brick configurations from a file, supporting JSON and YAML formats.

func (*BrickManager) RegisterLiveIDType

func (b *BrickManager) RegisterLiveIDType(liveID string, reflectType reflect.Type)

type BrickNewer

type BrickNewer interface {
	Brick
	// NewBrick parses the configuration and returns a new instance of the brick.
	// If the configuration file does not provide the configuration for the component, jsonConfig is nil.
	//
	// To ensure that this method can be called even if receiver is nil, please create a new instance and return it.
	NewBrick(jsonConfig []byte) Brick
}

type Live

type Live struct {
	// TypeID string
	LiveID string
	// key:field name, value:liveID
	RelyLives map[string]string
}

type RegisterBrickParam

type RegisterBrickParam struct {
	TypeID       string
	ReflectType  reflect.Type
	Lives        []Live
	BrickFactory func(jsonConf []byte) Brick
}

type TypeLives

type TypeLives struct {
	TypeID string
	Lives  []Live
}

Directories

Path Synopsis
examples
simple command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL