Skip to content

Commit

Permalink
debt: Minor refactoring to improve code readability and maintainabili…
Browse files Browse the repository at this point in the history
…ty. (#39)
  • Loading branch information
mprimeaux authored Dec 7, 2024
1 parent 83b2ddf commit 40e0f1c
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 50 deletions.
15 changes: 14 additions & 1 deletion CHANGELOG/CHANGELOG-1.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ Date format: `YYYY-MM-DD`
### Fixed
### Security

---
## [1.21.0] - 2024-12-07

### Added
### Changed
- **debt**: Minor refactoring to improve code readability and maintainability.

### Deprecated
### Removed
### Fixed
### Security

---
## [1.20.1] - 2024-11-24

Expand Down Expand Up @@ -488,7 +500,8 @@ Date format: `YYYY-MM-DD`
### Fixed
### Security

[Unreleased]: https://github.com/sixafter/nanoid/compare/v1.20.1...HEAD
[Unreleased]: https://github.com/sixafter/nanoid/compare/v1.21.0...HEAD
[1.21.0]: https://github.com/sixafter/nanoid/compare/v1.20.1...v1.21.0
[1.20.1]: https://github.com/sixafter/nanoid/compare/v1.20.0...v1.20.1
[1.20.0]: https://github.com/sixafter/nanoid/compare/v1.19.0...v1.20.0
[1.19.0]: https://github.com/sixafter/nanoid/compare/v1.18.1...v1.19.0
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ package main

import (
"fmt"

"github.com/sixafter/nanoid"
)

Expand Down Expand Up @@ -92,6 +93,7 @@ package main

import (
"fmt"

"github.com/sixafter/nanoid"
)

Expand Down Expand Up @@ -120,6 +122,7 @@ package main
import (
"fmt"
"io"

"github.com/sixafter/nanoid"
)

Expand Down
14 changes: 7 additions & 7 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"unicode/utf8"
)

// ConfigOptions holds the configurable options for the Generator.
// ConfigOptions holds the configurable options for the Interface.
// It is used with the Function Options pattern.
type ConfigOptions struct {
// RandReader is the source of randomness used for generating IDs.
Expand Down Expand Up @@ -134,12 +134,12 @@ type Configuration interface {
Config() Config
}

// Option defines a function type for configuring the Generator.
// Option defines a function type for configuring the Interface.
// It allows for flexible and extensible configuration by applying
// various settings to the ConfigOptions during Generator initialization.
// various settings to the ConfigOptions during Interface initialization.
type Option func(*ConfigOptions)

// WithAlphabet sets a custom alphabet for the Generator.
// WithAlphabet sets a custom alphabet for the Interface.
// The provided alphabet string defines the set of characters that will be
// used to generate Nano IDs. This allows users to customize the character set
// according to their specific requirements, such as using only alphanumeric
Expand All @@ -160,8 +160,8 @@ func WithAlphabet(alphabet string) Option {
}
}

// WithRandReader sets a custom random reader for the Generator.
// By default, the Generator uses a cryptographically secure random number
// WithRandReader sets a custom random reader for the Interface.
// By default, the Interface uses a cryptographically secure random number
// generator (e.g., crypto/rand.Reader). However, in some cases, users might
// want to provide their own source of randomness, such as for testing purposes
// or to integrate with a different entropy source.
Expand All @@ -184,7 +184,7 @@ func WithRandReader(reader io.Reader) Option {
}

// WithLengthHint sets the hint of the intended length of the IDs to be generated.
// Providing a length hint allows the Generator to optimize internal configurations,
// Providing a length hint allows the Interface to optimize internal configurations,
// such as buffer sizes and scaling factors, based on the expected ID length. This
// can enhance performance and efficiency, especially when generating a large number
// of IDs with similar lengths.
Expand Down
2 changes: 1 addition & 1 deletion config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestGetConfig(t *testing.T) {

// Assert that generator implements Configuration interface
config, ok := gen.(Configuration)
is.True(ok, "Generator should implement Configuration interface")
is.True(ok, "Interface should implement Configuration interface")

runtimeConfig := config.Config()

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ go 1.23

require (
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.29.0
golang.org/x/crypto v0.30.0
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/sys v0.28.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
47 changes: 24 additions & 23 deletions nanoid.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import (
)

var (
// DefaultGenerator is a global, shared instance of a Nano ID generator. It is safe for concurrent use.
DefaultGenerator Generator
// Generator is a global, shared instance of a Nano ID generator. It is safe for concurrent use.
Generator Interface

// DefaultRandReader is the default random number generator used for generating IDs.
DefaultRandReader = prng.Reader
// RandReader is the default random number generator used for generating IDs.
RandReader = prng.Reader
)

const (
Expand Down Expand Up @@ -60,16 +60,17 @@ const (

func init() {
var err error
DefaultGenerator, err = NewGenerator()
Generator, err = NewGenerator()
if err != nil {
panic(fmt.Sprintf("failed to initialize DefaultGenerator: %v", err))
panic(fmt.Sprintf("failed to initialize Generator: %v", err))
}
}

// Generator defines the interface for generating Nano IDs.
// Interface defines the contract for generating Nano IDs.
//
// Implementations of this interface provide methods to create new IDs
// and to read random data, supporting both ID generation and direct random byte access.
type Generator interface {
type Interface interface {
// New generates and returns a new Nano ID as a string with the specified length.
// The 'length' parameter determines the number of characters in the generated ID.
// Returns an error if the ID generation fails due to issues like insufficient randomness.
Expand All @@ -85,7 +86,7 @@ type Generator interface {
// Read fills the provided byte slice 'p' with random data, reading up to len(p) bytes.
// Returns the number of bytes read and any error encountered during the read operation.
//
// Implements the io.Reader interface, allowing the Generator to be used wherever an io.Reader is accepted.
// Implements the io.Reader interface, allowing the Interface to be used wherever an io.Reader is accepted.
// This can be useful for directly obtaining random bytes or integrating with other components that consume random data.
//
// Usage:
Expand All @@ -95,7 +96,7 @@ type Generator interface {
// // handle error
// }
// fmt.Printf("Read %d random bytes\n", n)
Read(p []byte) (n int, err error)
Read(b []byte) (n int, err error)
}

type generator struct {
Expand Down Expand Up @@ -132,7 +133,7 @@ func New() (ID, error) {
// }
// fmt.Println("Generated ID:", id)
func NewWithLength(length int) (ID, error) {
return DefaultGenerator.New(length)
return Generator.New(length)
}

// Must generates a new Nano ID using the default length specified by `DefaultLength`.
Expand Down Expand Up @@ -201,36 +202,36 @@ func MustWithLength(length int) ID {
// nothing happened; in particular it does not indicate EOF.
//
// Implementations must not retain p.
func Read(p []byte) (n int, err error) {
return DefaultGenerator.Read(p)
func Read(b []byte) (n int, err error) {
return Generator.Read(b)
}

// NewGenerator creates a new Generator with buffer pooling enabled.
// It accepts variadic Option parameters to configure the Generator's behavior.
// NewGenerator creates a new Interface with buffer pooling enabled.
// It accepts variadic Option parameters to configure the Interface's behavior.
// The function initializes the configuration with default values, applies any provided options,
// validates the configuration, constructs the runtime configuration, initializes buffer pools,
// and returns a configured Generator or an error if the configuration is invalid.
// and returns a configured Interface or an error if the configuration is invalid.
//
// Parameters:
// - options ...Option: A variadic list of Option functions to customize the Generator's configuration.
// - options ...Option: A variadic list of Option functions to customize the Interface's configuration.
//
// Returns:
// - Generator: An instance of the Generator interface configured with the specified options.
// - error: An error object if the Generator could not be created due to invalid configuration.
// - Interface: An instance of the Interface interface configured with the specified options.
// - error: An error object if the Interface could not be created due to invalid configuration.
//
// Error Conditions:
// - ErrInvalidLength: Returned if the provided LengthHint is less than 1.
// - ErrNilRandReader: Returned if the provided RandReader is nil.
// - ErrInvalidAlphabet: Returned if the alphabet is invalid or contains invalid UTF-8 characters.
// - ErrNonUTF8Alphabet: Returned if the alphabet contains non-UTF-8 characters.
// - ErrDuplicateCharacters: Returned if the alphabet contains duplicate characters.
func NewGenerator(options ...Option) (Generator, error) {
func NewGenerator(options ...Option) (Interface, error) {
// Initialize ConfigOptions with default values.
// These defaults include the default alphabet, the default random reader,
// and the default length hint for ID generation.
configOpts := &ConfigOptions{
Alphabet: DefaultAlphabet,
RandReader: DefaultRandReader,
RandReader: RandReader,
LengthHint: DefaultLength,
}

Expand Down Expand Up @@ -286,7 +287,7 @@ func NewGenerator(options ...Option) (Generator, error) {
}
}

// Return the configured Generator instance.
// Return the configured Interface instance.
// The generator holds references to the runtime configuration and buffer pools,
// facilitating efficient and thread-safe ID generation.
return &generator{
Expand All @@ -313,7 +314,7 @@ func NewGenerator(options ...Option) (Generator, error) {
//
// Usage Example:
//
// id, err := DefaultGenerator.New(21)
// id, err := Generator.New(21)
// if err != nil {
// // handle error
// }
Expand Down
6 changes: 3 additions & 3 deletions nanoid_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func BenchmarkGenerator_Read_DefaultLength(b *testing.B) {

b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := DefaultGenerator.Read(buffer)
_, err := Generator.Read(buffer)
if err != nil {
b.Fatalf("Read returned an unexpected error: %v", err)
}
Expand Down Expand Up @@ -187,7 +187,7 @@ func BenchmarkGenerator_Read_ZeroLengthBuffer(b *testing.B) {

b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := DefaultGenerator.Read(buffer)
_, err := Generator.Read(buffer)
if err != nil {
b.Fatalf("Read returned an unexpected error: %v", err)
}
Expand All @@ -211,7 +211,7 @@ func BenchmarkGenerator_Read_Concurrent(b *testing.B) {
defer wg.Done()
buffer := make([]byte, bufferSize)
for j := 0; j < b.N/concurrency; j++ {
_, err := DefaultGenerator.Read(buffer)
_, err := Generator.Read(buffer)
if err != nil {
b.Errorf("Read returned an unexpected error: %v", err)
return
Expand Down
14 changes: 7 additions & 7 deletions nanoid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func TestGenerateWithDuplicateAlphabet(t *testing.T) {
WithAlphabet(alphabet),
)
is.Error(err, "NewGenerator() should return an error with duplicate characters in the alphabet")
is.Nil(gen, "Generator should be nil when initialization fails")
is.Nil(gen, "Interface should be nil when initialization fails")
is.Equal(ErrDuplicateCharacters, err, "Expected ErrDuplicateCharacters")
}

Expand Down Expand Up @@ -164,11 +164,11 @@ func TestNewGeneratorWithInvalidAlphabet(t *testing.T) {
switch true {
case l < MinAlphabetLength:
is.Error(err, "NewGenerator() should return an error with an invalid alphabet length")
is.Nil(gen, "Generator should be nil when initialization fails")
is.Nil(gen, "Interface should be nil when initialization fails")
is.Equal(ErrAlphabetTooShort, err, "Expected ErrAlphabetTooShort")
case l > MaxAlphabetLength:
is.Error(err, "NewGenerator() should return an error with an invalid alphabet length")
is.Nil(gen, "Generator should be nil when initialization fails")
is.Nil(gen, "Interface should be nil when initialization fails")
is.Equal(ErrAlphabetTooLong, err, "Expected ErrAlphabetTooLong")
default:
is.NoError(err, "NewGenerator() should not return an error when initialization succeeds")
Expand All @@ -191,7 +191,7 @@ func TestInvalidUTF8Alphabet(t *testing.T) {
)

is.Error(err, "NewGenerator() should return an error with an invalid alphabet")
is.Nil(gen, "Generator should be nil when initialization fails")
is.Nil(gen, "Interface should be nil when initialization fails")
is.Equal(ErrNonUTF8Alphabet, err, "Expected ErrNonUTF8Alphabet")
}

Expand Down Expand Up @@ -662,7 +662,7 @@ func TestNewWithZeroLengthHintAndMaxAlphabet(t *testing.T) {
WithLengthHint(lengthHint),
)
is.Error(err, "NewGenerator() should return an error with LengthHint=0 and maximum alphabet size")
is.Nil(gen, "Generator should be nil when LengthHint is zero")
is.Nil(gen, "Interface should be nil when LengthHint is zero")
}

// TestGenerateWithCustomRandReaderReturningNoBytes tests generator behavior when the custom reader returns no bytes.
Expand Down Expand Up @@ -974,8 +974,8 @@ func TestGenerator_Read_Concurrent(t *testing.T) {
t.Parallel()
is := assert.New(t)

gen, ok := DefaultGenerator.(*generator)
is.True(ok, "DefaultGenerator should be of type *generator")
gen, ok := Generator.(*generator)
is.True(ok, "Generator should be of type *generator")

numGoroutines := 10
readsPerGoroutine := 100
Expand Down
4 changes: 2 additions & 2 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ github.com/pmezard/go-difflib/difflib
## explicit; go 1.17
github.com/stretchr/testify/assert
github.com/stretchr/testify/assert/yaml
# golang.org/x/crypto v0.29.0
# golang.org/x/crypto v0.30.0
## explicit; go 1.20
golang.org/x/crypto/chacha20
golang.org/x/crypto/internal/alias
# golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
## explicit; go 1.22.0
golang.org/x/exp/constraints
# golang.org/x/sys v0.27.0
# golang.org/x/sys v0.28.0
## explicit; go 1.18
golang.org/x/sys/cpu
# gopkg.in/yaml.v3 v3.0.1
Expand Down

0 comments on commit 40e0f1c

Please sign in to comment.