From d64a48ef7bae9d2eb91c7ac6d2d315c1e89e4062 Mon Sep 17 00:00:00 2001 From: Atomys Date: Wed, 3 Apr 2024 02:29:23 +0200 Subject: [PATCH] =?UTF-8?q?chore:=20readme=20refactor=20=F0=9F=8C=B1=20(#4?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request juste refactor the repository README to match the vision and others readme of my projects. --- .github/codecov.yml | 20 ++ .github/profile/images/logo_landing_dark.png | Bin 0 -> 16394 bytes .github/profile/images/logo_landing_light.png | Bin 0 -> 16506 bytes .github/workflows/test.yaml | 9 +- .gitignore | 2 + Makefile | 2 +- README.md | 195 +++++++++++++----- 7 files changed, 179 insertions(+), 49 deletions(-) create mode 100644 .github/codecov.yml create mode 100755 .github/profile/images/logo_landing_dark.png create mode 100755 .github/profile/images/logo_landing_light.png diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 0000000..c279ff5 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,20 @@ +coverage: + precision: 1 + range: "75...90" + status: + project: + default: + target: 80% + threshold: 2% + patch: + default: + target: 80% + threshold: 2% +github_checks: + annotations: true +ignore: + - benchmark/** + - docs/** +comment: + behavior: new + require_changes: true diff --git a/.github/profile/images/logo_landing_dark.png b/.github/profile/images/logo_landing_dark.png new file mode 100755 index 0000000000000000000000000000000000000000..ae6e9d7ab622ebdfe178f2184a33cde8317ebc2c GIT binary patch literal 16394 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%0A#7RiVJ+_GFdy)uaH22ZioyM>m~ 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 a^(89ADfg+vGw=aB-jl~#%J7F)k^c|(UEW&& literal 0 HcmV?d00001 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 27e1d78..412f5c6 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -9,10 +9,15 @@ jobs: runs-on: ${{ matrix.platform }} steps: - name: Install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Test run: make test + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + codecov_yml_path: .github/codecov.yml diff --git a/.gitignore b/.gitignore index ecca56a..b83e811 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ vendor/ /.glide + +coverage.out diff --git a/Makefile b/Makefile index 7a1f90f..93d1181 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,2 @@ test: - go test ./... + go test -coverprofile=coverage.out ./... diff --git a/README.md b/README.md index 604567a..8f9cb84 100644 --- a/README.md +++ b/README.md @@ -1,98 +1,201 @@ -# Sprout 🌱 +
+ + + + Sprout Logo + +
+
+ +
+ + +Code Climate maintainability +Codecov +GitHub release (latest by date) +GitHub contributors +GitHub Repo stars +Go Reference +
+

Official Documentation

+
+
> [!NOTE] > Sprout is an evolved variant of the [Masterminds/sprig](https://github.com/Masterminds/sprig) library, reimagined for modern Go versions. It introduces fresh functionalities and commits to maintaining the library, picking up where Sprig left off. Notably, Sprig had not seen updates for two years and was not compatible beyond Golang 1.13, necessitating the creation of Sprout. +## Motivation + +Sprout was born out of the need for a modernized, maintained, and performant template function library. Sprig, the predecessor to Sprout, had not seen updates for two years and was not optimized for later versions of Golang. Sprout aims to fill this gap by providing a library that is actively maintained, compatible with the latest Go versions, and optimized for performance. + +## Roadmap to Sprout v1.0 + +You can track our progress towards Sprout v1.0 by following the documentation page +[here](https://docs.atom.codes/sprout/roadmap-to-sprout-v1.0). + ## Table of Contents -- [Table of Contents](#table-of-contents) +- [Motivation](#motivation) +- [Roadmap to Sprout v1.0](#roadmap-to-sprout-v10) - [Transitioning from Sprig](#transitioning-from-sprig) -- [Performence Benchmarks](#performence-benchmarks) - - [Sprig v3.2.3 vs Sprout v0.1](#sprig-v323-vs-sprout-v01) - [Usage](#usage) - - [Integrating the Sprout Library](#integrating-the-sprout-library) - - [Template Function Invocation](#template-function-invocation) + - [Usage: Logger](#usage-logger) + - [Usage: Alias](#usage-alias) + - [Usage: Error Handling](#usage-error-handling) + - [Default Value](#default-value) + - [Panic](#panic) + - [Error Channel](#error-channel) +- [Performence Benchmarks](#performence-benchmarks) + - [Sprig v3.2.3 vs Sprout v0.2](#sprig-v323-vs-sprout-v02) - [Development Philosophy (Currently in reflexion to create our)](#development-philosophy-currently-in-reflexion-to-create-our) + ## Transitioning from Sprig -For those looking to switch from Sprig to Sprout, the process is straightforward and involves just a couple of steps: -1. Ensure your project uses Sprig's last version (v3.2.3). -2. Update your import statements and package references as shown below: +Sprout is designed to be a drop-in replacement for Sprig in the v1.0, with the same function names and behavior. To use Sprout in your project, simply replace the Sprig import with Sprout: + ```diff import ( - "github.com/Masterminds/sprig/v3" + "github.com/42atomys/sprout" - - "html/template" ) tpl := template.Must( template.New("base"). - Funcs(sprig.FuncMap()). + Funcs(sprout.FuncMap()). - ParseGlob("*.html") + ParseGlob("*.tmpl") ) ``` -## Performence Benchmarks +## Usage -To see all the benchmarks, please refer to the [benchmarks](benchmarks/README.md) directory. +To use Sprout in your project, import the library and use the `FuncMap` function to add the template functions to your template: -### Sprig v3.2.3 vs Sprout v0.1 +```go +import ( + "github.com/42atomys/sprout" + "text/template" +) + +tpl := template.Must( + template.New("base"). + Funcs(sprout.FuncMap()). + ParseGlob("*.tmpl") +) ``` -goos: linux -goarch: amd64 -pkg: sprout_benchmarks -cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz -BenchmarkSprig-12 1 3869134593 ns/op 45438616 B/op 24098 allocs/op -BenchmarkSprout-12 1 1814126036 ns/op 38284040 B/op 11627 allocs/op -PASS -ok sprout_benchmarks 5.910s + +You can customize the behavior of Sprout by creating a `FunctionHandler` and passing it to the `FuncMap` function or using the configuration functions provided by Sprout: + +```go +handler := sprout.NewFunctionHandler( + // Add your logger to the handler to log errors and debug information using the + // standard slog package or any other logger that implements the slog.Logger interface. + // By default, Sprout uses a slog.TextHandler. + sprout.WithLogger(slogLogger), + // Set the error handling behavior for the handler. By default, Sprout returns the default value of the return type without crashes or panics. + sprout.WithErrHandling(sprout.ErrHandlingReturnDefaultValue), + // Set the error channel for the handler. By default, Sprout does not use an error channel. If you set an error channel, Sprout will send errors to it. + // This options is only used when the error handling behavior is set to + // `ErrHandlingErrorChannel` + sprout.WithErrorChannel(errChan), + // Set the alias for a function. By default, Sprout use alias for some functions for backward compatibility with Sprig. + sprout.WithAlias("hello", "hi"), +) + +// Use the handler with the FuncMap function. The handler will be used to handle all template functions. +tpl := template.Must( + template.New("base"). + Funcs(sprout.FuncMap(sprout.WithFunctionHandler(handler))). + ParseGlob("*.tmpl") +) ``` +### Usage: Logger -**Time improvement**: 53.1% -**Memory improvement**: 15.7% +Sprout uses the `slog` package for logging. You can pass your logger +to the `WithLogger` configuration function to log errors and debug information: -So, Sprout v0.1 is approximately 53.1% faster and uses 15.7% less memory than Sprig v3.2.3. 🚀 +```go +// Create a new logger using the slog package. +logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) +// Use the handler with the FuncMap function. +tpl := template.Must( + template.New("base"). + Funcs(sprout.FuncMap(sprout.WithLogger(logger))). + ParseGlob("*.tmpl") +) +``` -## Usage +### Usage: Alias -**For Template Creators**: Refer to the comprehensive function guide in Sprig's documentation for detailed instructions and examples across over 100 template functions. +Sprout provides the ability to set an alias for a function. This feature is useful for backward compatibility with Sprig. You can set an alias for a function using the `WithAlias` or `WithAliases` configuration functions. -**For Go Developers**: Integrate Sprout into your applications by consulting our API documentation available on GoDoc.org. +See more about the alias in the [documentation](https://docs.atom.codes/sprout/function-aliases). -For general library usage, proceed as follows. +```go +sprout.NewFunctionHandler( + sprout.WithAlias("hello", "hi"), +) +``` -### Integrating the Sprout Library -To utilize Sprout's functions within your templates: +### Usage: Error Handling +Sprout provides three error handling behaviors: +- `ErrHandlingReturnDefaultValue`: Sprout returns the default value of the return type without crashes or panics. +- `ErrHandlingPanic`: Sprout panics when an error occurs. +- `ErrHandlingErrorChannel`: Sprout sends errors to the error channel. -```golang -import ( - "github.com/42atomys/sprout" - "html/template" -) +You can set the error handling behavior using the `WithErrHandling` configuration function: -// Ensure the FuncMap is set before loading the templates. -tpl := template.Must( - template.New("base").Funcs(sprout.FuncMap()).ParseGlob("*.html") +```go +sprout.NewFunctionHandler( + sprout.WithErrHandling(sprout.ErrHandlingReturnDefaultValue), ) ``` -### Template Function Invocation -Adhering to Go's conventions, all Sprout functions are lowercase, differing from method naming which employs TitleCase. For instance, this template snippet: +#### Default Value + +If you set the error handling behavior to `ErrHandlingReturnDefaultValue`, Sprout will return the default value of the return type without crashes or panics to ensure a smooth user experience when an error occurs. + +#### Panic +If you set the error handling behavior to `ErrHandlingPanic`, Sprout will panic when an error occurs to ensure that the error is not ignored and sended back to template execution. -```golang -{{ "hello!" | upper | repeat 5 }} +#### Error Channel + +If you set the error handling behavior to `ErrHandlingErrorChannel`, you can pass an error channel to the `WithErrorChannel` configuration function. Sprout will send errors to the error channel: + +```go +errChan := make(chan error) + +sprout.NewFunctionHandler( + sprout.WithErrHandling(sprout.ErrHandlingErrorChannel), + sprout.WithErrorChannel(errChan), +) ``` -Will output: + +## Performence Benchmarks + +To see all the benchmarks, please refer to the [benchmarks](benchmarks/README.md) directory. + +### Sprig v3.2.3 vs Sprout v0.2 ``` -HELLO!HELLO!HELLO!HELLO!HELLO! +goos: linux +goarch: amd64 +pkg: sprout_benchmarks +cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz +BenchmarkSprig-12 1 3869134593 ns/op 45438616 B/op 24098 allocs/op +BenchmarkSprout-12 1 1814126036 ns/op 38284040 B/op 11627 allocs/op +PASS +ok sprout_benchmarks 5.910s ``` +**Time improvement**: 53.1% +**Memory improvement**: 15.7% + +So, Sprout v0.2 is approximately 53.1% faster and uses 15.7% less memory than Sprig v3.2.3. 🚀 + ## Development Philosophy (Currently in reflexion to create our) Our approach to extending and refining Sprout was guided by several key principles: