Skip to content

Commit

Permalink
feat: registries groups (#75)
Browse files Browse the repository at this point in the history
## Description
After few feedback on `v1.0.0-rc1`, a solution for grouping registries
and have built-ins groups are requested, this pull request implement the
logic of group, keep it simple as possible to prevent add complexity for
nothing.

## Changes
- Add `AddGroups` on `Defaulthandler`
- Add `WithGroups` handler option
- Add `group` folder to hold all built-ins group and add two `all` and
`hermetic`

## Resolves #73 #49 

## Checklist
- [x] I have read the **CONTRIBUTING.md** document.
- [x] My code follows the code style of this project.
- [x] I have added tests to cover my changes.
- [x] All new and existing tests passed.
- [x] I have updated the documentation accordingly.
- [x] This change requires a change to the documentation on the website.

---------

Signed-off-by: Atomys <contact@atomys.fr>
  • Loading branch information
42atomys authored Nov 5, 2024
1 parent 1c34c3a commit 692013c
Show file tree
Hide file tree
Showing 21 changed files with 721 additions and 90 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ You can track our progress towards Sprout v1.0 by following the documentation pa
- [Creating a Handler](#creating-a-handler)
- [Customizing the Handler](#customizing-the-handler)
- [Working with Registries](#working-with-registries)
- [Working with Registries Groups](#working-with-registries-groups)
- [Building Function Maps](#building-function-maps)
- [Working with Templates](#working-with-templates)
- [Usage: Quick Example (code only)](#usage-quick-example)
Expand Down Expand Up @@ -118,6 +119,23 @@ handler.AddRegistries(
)
```

### Working with Registries Groups
In some cases, you can use a group of registries to add multiple registries at once.

You can retrieve all built-ins registries groups under [Registry Groups](https://docs.atom.codes/sprout/groups/list-of-all-registry-groups).

```go
import (
"github.com/go-sprout/sprout/group/all"
)

//...

handler.AddGroup(
all.RegistryGroup(),
)
```

### Building Function Maps

To use Sprout with templating engines like `html/template` or `text/template`, you need to build the function map:
Expand Down
8 changes: 8 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
## Features

* [Loader System (Registry)](features/loader-system-registry.md)
* [Loader System (Registry Group)](features/loader-system-registry-group.md)
* [Function Aliases](features/function-aliases.md)
* [Function Notices](features/function-notices.md)
* [Safe Functions](features/safe-functions.md)
Expand Down Expand Up @@ -40,10 +41,17 @@
* [Time](registries/time.md)
* [Uniqueid](registries/uniqueid.md)

## Groups

* [List of all registry groups](groups/list-of-all-registry-groups.md)
* [All](groups/all.md)
* [Hermetic](groups/hermetic.md)

## Advanced

* [How to create a handler](advanced/how-to-create-a-handler.md)
* [How to create a registry](advanced/how-to-create-a-registry.md)
* [How to create a registry group](advanced/how-to-create-a-registry-group.md)

## Links

Expand Down
38 changes: 38 additions & 0 deletions docs/advanced/how-to-create-a-registry-group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# How to create a registry group

## File Naming Conventions

* `{{registry_group_name}}.go`: This file defines the registry group, including key components like structs, interfaces, constants, and variables.
* `{{registry_group_name}}_test.go`: Includes tests for the registry group to ensure it functions as expected.

{% hint style="info" %}
This structure ensures consistency and maintainability across different registries, making it easier for developers to contribute and collaborate effectively.\
\
For the rest of conventions please read [templating-conventions.md](../introduction/templating-conventions.md "mention").
{% endhint %}


## Creating a Registry Group

1. **New Repository**: You can start by creating a new repository on your GitHub account or organization. This will house your registry group functions.
2. **Contributing to Official Registry**: To add a new registry group to the official registry, submit a pull request (PR) after a discussion inside an issue. The official registry groups are organized under the `group/` folder.

To start, in your `{{registry_group_name}}.go` file, create a function called `RegistryGroup` respecting the following signature:

```go
func RegistryGroup() *sprout.RegistryGroup {
return sprout.NewRegistryGroup(
// Add your registries here
// registry.NewRegistry(),
)
}
```

You can also create a group directly in your codebase without the need to create a new package. This is useful when you want to group registries that are specific to a project or a use case.
```go
group := sprout.NewRegistryGroup(registry.NewRegistry())

handler.AddGroups(group)
```

Once your group is defined, you can start using it in your projects. 🎉
170 changes: 85 additions & 85 deletions docs/advanced/how-to-create-a-registry.md
Original file line number Diff line number Diff line change
@@ -1,85 +1,85 @@
# How to create a registry

## File Naming Conventions

- `{{registry_name}}.go`: This file defines the registry, including key components like structs, interfaces, constants, and variables.
- `functions.go`: Contains the implementation of exported functions, making them accessible to other developers.
- `functions_test.go`: Includes tests for the exported functions to ensure they function as expected.
- `helpers.go`: Contains internal helper functions that support the registry but are not exposed for public use.
- `helpers_test.go`: Holds tests for the helper functions to validate their reliability.

{% hint style="info" %}
This structure ensures consistency and maintainability across different registries, making it easier for developers to contribute and collaborate effectively.\
\
For the rest of conventions please read [templating-conventions.md](../introduction/templating-conventions.md "mention").
{% endhint %}

## Creating a Registry

1. **New Repository**: You can start by creating a new repository on your GitHub account or organization. This will house your registry functions.
2. **Contributing to Official Registry**: To add your functions to the official registry, submit a pull request (PR). The official registries are organized under the `registry/` folder.

{% hint style="info" %}
You can found an example of a registry under `registry/_example`.
{% endhint %}

To start, in your `{{registry_name}}.go` file, start by creating a struct that implements the `Registry` interface. This struct will manage your custom functions and connect them to the handler.

```go
package ownregistry

import (
"github.com/go-sprout/sprout"
)

// OwnRegistry struct implements the Registry interface, embedding the Handler to access shared functionalities.
type OwnRegistry struct {
handler sprout.Handler // Embedding Handler for shared functionality
}

// NewRegistry initializes and returns a new instance of your registry.
func NewRegistry() *OwnRegistry {
return &OwnRegistry{}
}

// UID provides a unique identifier for your registry.
func (or *OwnRegistry) UID() string {
return "organization/repo.ownregistry" // Ensure this identifier is unique and uses lowercase, prefixed by your handler/repo separated with a dot.
}

// LinkHandler connects the Handler to your registry, enabling runtime functionalities.
func (or *OwnRegistry) LinkHandler(fh sprout.Handler) error {
or.handler = fh
return nil
}

// RegisterFunctions adds the provided functions into the given function map.
// This method is called by an Handler to register all functions of a registry.
func (or *OwnRegistry) RegisterFunctions(funcsMap sprout.FunctionMap) {
// Example of registering a function
sprout.AddFunction(funcsMap, "yourFunction", or.YourFunction)
}

// OPTIONAL: Your registry don't needs to register aliases to work.
// RegisterAliases adds the provided aliases into the given alias map.
// method is called by an Handler to register all aliases of a registry.
func (or *OwnRegistry) RegisterAliases(aliasMap sprout.FunctionAliasMap) error {
// Example of registering an alias
sprout.AddAlias(aliasMap, "yourFunction", "yourAlias")
}
```

After create your registry structure and implement the `Registry` interface, you can start to define your functions in `functions.go`, you can access all features of the handler through

```go
// YourFunction is an example function that returns a string and an error.
func (or *OwnRegistry) YourFunction() (string, error) {
return "Hello, World!", nil
}
```

{% hint style="danger" %}
**Important:** Make sure to write tests for your functions in `functions_test.go` to validate their functionality.
{% endhint %}

Once your registry is defined and functions are implemented, you can start using it in your projects. 🎉
# How to create a registry

## File Naming Conventions

- `{{registry_name}}.go`: This file defines the registry, including key components like structs, interfaces, constants, and variables.
- `functions.go`: Contains the implementation of exported functions, making them accessible to other developers.
- `functions_test.go`: Includes tests for the exported functions to ensure they function as expected.
- `helpers.go`: Contains internal helper functions that support the registry but are not exposed for public use.
- `helpers_test.go`: Holds tests for the helper functions to validate their reliability.

{% hint style="info" %}
This structure ensures consistency and maintainability across different registries, making it easier for developers to contribute and collaborate effectively.\
\
For the rest of conventions please read [templating-conventions.md](../introduction/templating-conventions.md "mention").
{% endhint %}

## Creating a Registry

1. **New Repository**: You can start by creating a new repository on your GitHub account or organization. This will house your registry functions.
2. **Contributing to Official Registry**: To add your functions to the official registry, submit a pull request (PR). The official registries are organized under the `registry/` folder.

{% hint style="info" %}
You can found an example of a registry under `registry/_example`.
{% endhint %}

To start, in your `{{registry_name}}.go` file, start by creating a struct that implements the `Registry` interface. This struct will manage your custom functions and connect them to the handler.

```go
package ownregistry

import (
"github.com/go-sprout/sprout"
)

// OwnRegistry struct implements the Registry interface, embedding the Handler to access shared functionalities.
type OwnRegistry struct {
handler sprout.Handler // Embedding Handler for shared functionality
}

// NewRegistry initializes and returns a new instance of your registry.
func NewRegistry() *OwnRegistry {
return &OwnRegistry{}
}

// UID provides a unique identifier for your registry.
func (or *OwnRegistry) UID() string {
return "organization/repo.ownregistry" // Ensure this identifier is unique and uses lowercase, prefixed by your handler/repo separated with a dot.
}

// LinkHandler connects the Handler to your registry, enabling runtime functionalities.
func (or *OwnRegistry) LinkHandler(fh sprout.Handler) error {
or.handler = fh
return nil
}

// RegisterFunctions adds the provided functions into the given function map.
// This method is called by an Handler to register all functions of a registry.
func (or *OwnRegistry) RegisterFunctions(funcsMap sprout.FunctionMap) {
// Example of registering a function
sprout.AddFunction(funcsMap, "yourFunction", or.YourFunction)
}

// OPTIONAL: Your registry don't needs to register aliases to work.
// RegisterAliases adds the provided aliases into the given alias map.
// method is called by an Handler to register all aliases of a registry.
func (or *OwnRegistry) RegisterAliases(aliasMap sprout.FunctionAliasMap) error {
// Example of registering an alias
sprout.AddAlias(aliasMap, "yourFunction", "yourAlias")
}
```

After create your registry structure and implement the `Registry` interface, you can start to define your functions in `functions.go`, you can access all features of the handler through

```go
// YourFunction is an example function that returns a string and an error.
func (or *OwnRegistry) YourFunction() (string, error) {
return "Hello, World!", nil
}
```

{% hint style="danger" %}
**Important:** Make sure to write tests for your functions in `functions_test.go` to validate their functionality.
{% endhint %}

Once your registry is defined and functions are implemented, you can start using it in your projects. 🎉
5 changes: 0 additions & 5 deletions docs/features/function-safe.md

This file was deleted.

41 changes: 41 additions & 0 deletions docs/features/loader-system-registry-group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
description: 'Managing multiple registries can be simplified with RegistryGroup feature.'
---

# Loader System (Registry Groups)

## Introduction

The `RegistryGroup` struct enables the grouping of multiple registries, simplifying their management and enhancing modularity within the `Handler`. This approach promotes cleaner code organization and facilitates the reuse of registry configurations across different projects.

{% hint style="info" %}
**Considerations**

Using a `RegistryGroup` can help you manage multiple registries. But can lead to registering undesired functions if you are not careful. Be sure to review the functions in each registry to avoid conflicts or unexpected behavior.
{% endhint %}

## How to use a registry group

If you have creted a `RegistryGroup` or want to use a built-in group, you can add it to your handler using the `AddGroups` method:

```go
err := handler.AddGroups(group1, group2)
if err != nil {
// Handle error
}
```
You can also use the option to add registries when initializing the handler:

```go
handler := sprout.New(
sprout.WithGroups(group1, group2),
)
```

In this example, `group1` and `group2` are added to the `handler`, allowing all registries within these groups to be registered collectively.



## How to create a registry group

To show how to create your own registry group, go to [how-to-create-a-registry-group.md](../advanced/how-to-create-a-registry-group.md "mention")
4 changes: 4 additions & 0 deletions docs/features/loader-system-registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ handler := sprout.New(

This code sets up your project to utilize the functions from your custom registry, making it easy to integrate and extend functionality.

## You have too many registries to manage?

You can use the [loader-system-registry-group.md](./loader-system-registry-group.md) feature to manage multiple registries at once or use built-in groups.

## How to create a registry

To show how to create your own registry, go to [how-to-create-a-registry.md](../advanced/how-to-create-a-registry.md "mention")
35 changes: 35 additions & 0 deletions docs/groups/all.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
description: >-
The All registry group includes all the registries available in Sprout,
excluding deprecated and experimental registries.
---

# All

{% hint style="info" %}
You can easily import group from the <mark style="color:yellow;">`all`</mark> group by including the following import statement in your code

```go
import "github.com/go-sprout/sprout/group/all"
```
{% endhint %}

### List of registries

* [**checksum**](checksum.md): Tools to generate and verify checksums for data integrity.
* [**conversion**](conversion.md): Functions to convert between different data types within templates.
* [**encoding**](encoding.md): Methods for encoding and decoding data in various formats.
* [**env**](env.md): Access and manipulate environment variables within templates.
* [**filesystem**](filesystem.md): Functions for interacting with the file system.
* [**maps**](maps.md): Tools to manipulate and interact with map data structures.
* [**network**](network.md): Functions to interact with network resources.
* [**numeric**](numeric.md): Utilities for numerical operations and calculations.
* [**random**](random.md): Functions to generate random numbers, strings, and other data.
* [**reflect**](reflect.md): Tools to inspect and manipulate data types using reflection.
* [**regexp**](regexp.md): Regular expression functions for pattern matching and string manipulation.
* [**semver**](semver.md): Functions to handle semantic versioning and comparison.
* [**slices**](slices.md): Utilities for slice operations, including filtering, sorting, and transforming.
* [**std**](std.md): Standard functions for common operations.
* [**strings**](strings.md): Functions for string manipulation, including formatting, splitting, and joining.
* [**time**](time.md): Tools to handle dates, times, and time-related calculations.
* [**uniqueid**](uniqueid.md): Functions to generate unique identifiers, such as UUIDs.
33 changes: 33 additions & 0 deletions docs/groups/hermetic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
description: >-
The Hermetic registry group includes all the registries available in Sprout,
excluding registries that depend on external services or are influenced by the
environment where the application is running.
---

# All

{% hint style="info" %}
You can easily import group from the <mark style="color:yellow;">`all`</mark> group by including the following import statement in your code

```go
import "github.com/go-sprout/sprout/group/hermetic"
```
{% endhint %}

### List of registries

* [**checksum**](checksum.md): Tools to generate and verify checksums for data integrity.
* [**conversion**](conversion.md): Functions to convert between different data types within templates.
* [**encoding**](encoding.md): Methods for encoding and decoding data in various formats.
* [**filesystem**](filesystem.md): Functions for interacting with the file system.
* [**maps**](maps.md): Tools to manipulate and interact with map data structures.
* [**numeric**](numeric.md): Utilities for numerical operations and calculations.
* [**reflect**](reflect.md): Tools to inspect and manipulate data types using reflection.
* [**regexp**](regexp.md): Regular expression functions for pattern matching and string manipulation.
* [**semver**](semver.md): Functions to handle semantic versioning and comparison.
* [**slices**](slices.md): Utilities for slice operations, including filtering, sorting, and transforming.
* [**std**](std.md): Standard functions for common operations.
* [**strings**](strings.md): Functions for string manipulation, including formatting, splitting, and joining.
* [**time**](time.md): Tools to handle dates, times, and time-related calculations.
* [**uniqueid**](uniqueid.md): Functions to generate unique identifiers, such as UUIDs.
Loading

0 comments on commit 692013c

Please sign in to comment.